320 likes | 396 Views
Phx.Morph Can Aspect-Oriented Programming solve Microsoft’s growing software problem?. Marc Eaddy Columbia University. Background. The Phoenix Project Microsoft’s production-grade compiler, analysis, and tools infrastructure Will become backend for all Microsoft compilers
E N D
Phx.MorphCan Aspect-OrientedProgramming solve Microsoft’s growing software problem? Marc Eaddy Columbia University
Background • The Phoenix Project • Microsoft’s production-grade compiler, analysis,and tools infrastructure • Will become backend for all Microsoft compilers • Massive software project • Currently 1.8M LOC (318K hand-written)
Problem • Many Phoenix requirements cannot be cleanly separated using traditional OO techniques (inheritance and aggregation) • Unanticipated requirements • Requirements to satisfy multiple clients and scenarios • “Operational” (orthogonal) requirements • Traditional OO solutions resulted in increased software complexity • Designs are complex and highly coupled • Code is cluttered and difficult to write and maintain • Many other groups at Microsoft are also struggling with this problem
Our goal Phx.Morph Determine if Aspect-Oriented Programming (AOP) can improve Phoenix development Our approach • Use Phoenix to develop an AOP solution • Then turn around and use the AOP solution to help develop Phoenix
Aspect-Oriented Programming • Promise of greater “separation of concerns” • AOP = Open Classes + Advice • Open Classes (type changes) • Advice (code changes) • AspectJ™ is the canonical AOP specification and implementation
AOP buzzwords • joinpoint – an execution event • function call, function execution, field access, exception, etc. • advice – code that the programmer wants to be called before, after, or instead of (around), some joinpoint • pointcut – a pattern for matching joinpoints • e.g., “System.Output.*” • weaving – transforming a program to call advice code
Weaving using Phx.Morph Post-Link Step Normal assemblies containing custom AOP attributes Aspect Assemblies Source Files Original Program WeavedProgram Phx.Morph Compiler Original developer can be oblivious
Open Classes (OC) Ability to split a class definition into separate modules • Similar to Partial Classes in C# except • post-link time; can extend a class at any time • works on assemblies; no source req’d • language agnostic • We support adding fields, properties, methods, base interfaces, and base classes
Demo: Adding foreach sugar using System.Collections; using Phx.Morph.Attributes; [Extends("Node")] class NodeEnumeratorAspect:Node, IEnumerable { [Add] public IEnumerator GetEnumerator() { return new NodeEnumerator(this); } } Class to extend “Add this iface” “Add this method”
NodeEnumerator public classNodeEnumerator : IEnumerator { Node node; int index = -1; publicNodeEnumerator(Node node){ this.node = node; } public object Current{ get{return node.GetChild(index);} } public bool MoveNext(){ return ++index < node.ChildCount; } public void Reset() { index = -1;} }
foreach client static void DumpNode(Noderoot, string indent) { if (root == null) return; System.Console.WriteLine(indent + root); foreach (Node child in root) { DumpNode(child, indent + " "); } } New capability!
Adding the Visitor pattern:Traditional OO Depends On Depends On Depends On Depends On OO design is tightly coupled and hard to maintain
Adding the Visitor pattern:Open Classes Open Classes design breaks the circular dependency and centralizes the code Depends On
Phoenix client extensibility:Traditional OO • Client wants to attach custom data to an object • Example: IR-Longevity plug-in tracks compiler phase when an instruction is created Client’s extension object
Phoenix client extensibility:Open Classes • Empowers clients • High performance • Type safe • Don’t have to wait for RDK drop • Don’t require help from Phoenix team • Weave Phx.dll • To add BirthPhase field directly to Instr Client’s extension object
Advice Ability to inject code at specific points in a program • profiling • logging/tracing • log field get/set • dirty bit (persistence, synchronization) • change notification (undo/redo/rollback) • enforce invariants (non-null, const, data flow, Design by Contract) • error checking/handling • fault injection • caching/memoization • proxies/delegation • etc. etc.
Demo: Logging reflection usage • Want to log a message whenever we use the Reflection API • Self-weave Phx.Morph.dll
Logging advice using Phx.Morph.Aop; using Phx.Morph.Attributes; public classLogReflectionAspect { [Advice(AdviceType.before, "call(System.Reflection..)")] static public void LogReflection([Signature] string signature, [SourceLocation.WithinSignature] string withinSignature, [SourceLocation.FilePath] string filePath, [SourceLocation.Line] uint line) { System.Console.WriteLine(); System.Console.WriteLine("Called {0}()", signature); System.Console.WriteLine(" inside {0}()", withinSignature); System.Console.WriteLine(" [File: {0}, Line: {1}]", System.IO.Path.GetFileName(filePath), line); } }
Weaved result IL_0065: ldarg.0 IL_0066: call class System.Reflection.Assembly System.Reflection.Assembly::Load(string)
Weaved result Injected code IL_0065: ldarg.0 IL_0066: ldstr "System.Reflection.Assembly.Load" IL_006b: ldstr "Phx.Morph.ReflectionHelpers.LoadAssembly" IL_0070: ldstr "c:\\phx\\rdk\\samples\\Morpher\\Phx.Morph\\ReflectionHelpers.cs" IL_0075: ldc.i4 0xfb IL_007a: call void LogReflectionExt::LogReflection( string, string, string, uint32) IL_007f: call class System.Reflection.Assembly System.Reflection.Assembly::Load(string)
Logging output Called System.Reflection.Assembly.Load() inside Phx.Morph.ReflectionHelpers.LoadAssembly() [File: ReflectionHelpers.cs, Line: 251] Called System.Reflection.Emit.AssemblyBuilder.DefineDynamicModule() inside Phx.Morph.Attributes.AttributeHelper.CreateTypeBuilder() [File: AttributeHelper.cs, Line: 499] Called System.Reflection.Emit.ModuleBuilder.DefineType() inside Phx.Morph.Attributes.AttributeHelper.CreateTypeBuilder() [File: AttributeHelper.cs, Line: 504] …etc…
Demo: Enforcing invariants • Supporting const-ness at runtime Person teacher = new Person(); teacher.Salary = 25000; teacher.IsConst = true; teacher.Salary = 1000000; • Caveat: Must weave all clients New! Invariant violated!
Invariant aspect [Extends("Person")] classInvariantAspect { [Add] public bool IsConst; [Advice(AdviceType.before, "set(Person.*)")] void CheckIsConst( [SourceLocation.WithinSignature] string withinSignature, [This] object This) { if (IsConst) { System.Console.WriteLine( "Person '{0}' violated IsConst constraint inside {1}", This, withinSignature); } } }
Phx.Morph implementation • Built using Phoenix • MorphPlugin plugs into PEREW and uses Phx.Morph to perform weaving Phx.Morph Editors Open Classes, weaving AOP Joinpoints, pointcuts, … PEREW Assembly Re-Writer Attributes Custom AOP attributes MorphPlugin Phoenix Core API
Current limitations • Managed-code only • Cannot access private members • Limited aspect instantiation model • Instance advice methods are imported • Static advice methods are referenced • Not yet implemented • Can’t import a method with multiple return statements • Around advice • Many pointcuts not implemented (including cflow) • Aspect composition and precedence • Access to some joinpoint context (Args, Target, thisJoinPoint)
Related work “Real” (shipped) products IBM WebSphere HyperProbes AspectJ™ BEA JRockit JVM JAsCo PROSE IBM Eclipse JBoss (J2EE) JMangler DynAOP Products EAOP Steamloom Spring (J2EE) CeaserJ Jakarta Hivemind JAML Java .NET Phx.Morph AspectC Rapier.NET Aspect# C++ No real products Loom.NET AspectC++ AspectDNG FeatureC++ Meta.NET Weave.NET Wool Other XWeaver Eos Aspect.NET Aspects PostSharp AspectS SetPoint CLAW AOPHP ComposeStar Apostle Hyper/J SourceWeave.NET PHPaspect Pythius DemeterJ AopDotNetAddin PEAK AOP.NET Encase Composition Filters AspectScheme AspectL AOP-Engine AspectCocoa Concern Manipulation Environment AspectR Italics = Microsoft-sponsored (although none are shipped)
Why our work is interesting • Built using Phoenix – Microsoft’s production-grade compiler, analysis and tools infrastructure • Capable of weaving very large programs (e.g., Phoenix itself, which is 1.8M LOC) • Evolves in parallel with Phoenix and the Common Language Runtime (performance improvements, bug fixes, API evolution, etc.) • Used by Phoenix to solve real business requirements • Phoenix is real software • Hampered by traditional OO techniques • We’ve started using AOP to develop Phoenix
Conclusions • Our goal was to determine if AOP would improve Phoenix development • Re-implemented a Phoenix plug-in to use Open Classes instead of the OO extension API • Began prototyping grafting adapter interfaces onto Phoenix classes to integrate with another library • We validated the feasibility of using Phx.Morph on Phoenix itself
Future work • Work on Microsoft’s key blocking issues • Debugability • Maintainability • Performance • Versioning • Serviceability • Explore more AOP scenarios • compile-time (ala Partial Classes for C++) • Makes it easier for Phoenix to use their own extensions • Easily separate hand-written code from generated code (code behind) • load-time • Needed to fully support compile-time weaving • runtime (dynamic weaving) • Useful for on-the-fly debugging and rapid prototyping • Improve ease-of-use • IDE integration, projecting aspects into source code
Acks • Many thanks to the Phoenix team! • Mentor: Weiping Hu • Andy Ayers • Julian Burger • Jan Gray • John Lefor • Paddy McDonald • Chuck Mitchell
Contact Marc Eaddy – me133@columbia.edu