Extending Rotor with Structural Reflection to support Reflective Languages


Published on

Presentation of the results of the project "Extending Rotor with Structural Reflection to support Reflective Languages" at Microsoft Research, Redmond, Washington (USA)

Published in: Education, Technology
  • Be the first to comment

  • Be the first to like this

Extending Rotor with Structural Reflection to support Reflective Languages

  1. 1. Extending Rotor with Structural Reflection to support Reflective Languages
  2. 2. Adaptiveness and Adaptability <ul><li>The dynamic manipulation (evolution) of system behavior and structure is becoming increasingly important to develop adaptive and adaptable applications </li></ul><ul><ul><li>A system is adaptive if it is able to change its behavior ( by itself ) according to the changes in its environment, or within itself </li></ul></ul><ul><ul><li>A system is adaptable if the user could dynamically produce a new system behavior </li></ul></ul><ul><li>There are different approaches to construct adaptable(ive) software </li></ul><ul><ul><li>Adaptive (Dynamic) Languages </li></ul></ul><ul><ul><ul><li>Python, Dylan, Ruby, Smalltalk, Self or CLOS) </li></ul></ul></ul><ul><ul><li>Adaptive Paradigms </li></ul></ul><ul><ul><li>Agile and Adaptive Methodologies </li></ul></ul><ul><ul><li>A lot of Domain Specific Adaptive Frameworks </li></ul></ul>Introduction
  3. 3. Dynamic Languages <ul><li>Programming languages that support reasoning about / customizing their own structure , behavior and environment , supporting self-modifying features and dynamic code generation </li></ul><ul><li>As a side effect of this dynamism, dynamic programming languages are dynamically typed </li></ul><ul><li>For example, it is possible to dynamically </li></ul><ul><ul><li>Change the interface of objects and classes </li></ul></ul><ul><ul><li>Modify the implementation of specific methods </li></ul></ul><ul><ul><li>Adapt the structure of objects </li></ul></ul><ul><ul><li>Generate new code </li></ul></ul><ul><ul><li>Modify an object’s type </li></ul></ul><ul><ul><li>Customize the behavior of a set of classes ( meta-classes ) </li></ul></ul>Introduction
  4. 4. Pros and Cons <ul><ul><li>Facilitate the development of adaptive and adaptable software </li></ul></ul><ul><ul><li>Design -time and runtime integration </li></ul></ul><ul><ul><li>Making new software entities first-class objects (modules, classes, meta-classes, objects, methods, fields and types) increases behavior parameterization (factorization) </li></ul></ul><ul><li>Due to these benefits, static languages (Java or C#) are incorporating more and more dynamic features </li></ul><ul><li>However, static type-checking has important benefits </li></ul><ul><ul><li>The lack of static type-checking may cause a loss of safety </li></ul></ul><ul><ul><ul><li>Test-driven development (PyUnit, JUnit or NUnit) could be used in some scenarios </li></ul></ul></ul><ul><ul><ul><li>Mixing static and dynamic type-checking could be interesting, when developing adaptable software </li></ul></ul></ul><ul><ul><li>Performance caused by inferring types (and checking) at runtime </li></ul></ul>Introduction
  5. 5. <ul><li>Our Project, Extending Rotor with Structural Reflection to support Reflective Languages </li></ul><ul><li>has tried to response these questions </li></ul><ul><ul><li>Is it possible to improve runtime performance of reflective languages? </li></ul></ul><ul><ul><li>Is it possible to make static and dynamic languages interoperate? </li></ul></ul><ul><ul><li>Is it possible to combine the best of both worlds ( static typing where possible, dynamic typing when needed )? </li></ul></ul><ul><li>The main objective is to enhance Rotor with structural reflective primitives offered by dynamic languages, in order to evaluate </li></ul><ul><ul><li>feasibility of making the CLI a runtime reflective platform (combining static and dynamic languages) </li></ul></ul><ul><ul><li>performance cost (vs. static rotor) and performance benefits (vs. interpreted counterparts) </li></ul></ul>Я Rotor Introduction
  6. 6. Contents <ul><li>Introduction </li></ul><ul><li>Reflection </li></ul><ul><li>Structural Reflection in Rotor </li></ul><ul><li>Implementation </li></ul><ul><li>Assessment </li></ul><ul><li>Conclusions </li></ul>
  7. 7. Reflection <ul><li>Reflection is the capability of a computational system to reason about/act upon itself, adjusting itself to changing conditions </li></ul><ul><ul><li>Its computational domain is enhanced by its own representation , offering its semantics and structure as if they were computable data </li></ul></ul><ul><li>Runtime reflection offers dynamic adaptation of running systems ( dynamic languages ) </li></ul><ul><li>Regarding to what can be reflected, reflection can be classified into </li></ul><ul><ul><li>Introspection : program structure may be consulted, but not modified (e.g. Java and C# reflective capabilities) </li></ul></ul><ul><ul><li>Structural Reflection: program structure can be modified and those changes should be reflected (e.g. modifying attributes and methods of Python classes) </li></ul></ul><ul><ul><li>Computational Reflection: modifying program behavior (e.g. extending the message passing mechanism to develop a trace log with a MOP) </li></ul></ul>Reflection
  8. 8. Extending Rotor’s Reflection <ul><li>Runtime adaptiveness has been an important issue in .Net’s design </li></ul><ul><ul><li>Introspection services of the System.Reflection namespace </li></ul></ul><ul><ul><li>Generative programming with the Reflection.Emit namespace </li></ul></ul><ul><ul><li>Dynamic inspection of the declarative information offered by attributes </li></ul></ul><ul><li>Structural Reflection is a step forward to adaptiveness, permitting the modification of program’s structure at runtime </li></ul><ul><li>There are languages that offer this level of reflection: Python, Ruby, Dylan, Smalltalk or CLOS </li></ul><ul><li>Extending Rotor with structural reflection has </li></ul><ul><ul><li>Made the CLI a platform to directly support reflective features of dynamic languages </li></ul></ul><ul><ul><li>Made the most of its introspective , attribute and generative programming features </li></ul></ul><ul><ul><li>Improved runtime performance of existing implementations, using its JIT compiler </li></ul></ul><ul><ul><li>Offered direct interoperability between X.Net and dynamic languages </li></ul></ul>Reflection
  9. 9. Contents <ul><li>Introduction </li></ul><ul><li>Reflection </li></ul><ul><li>Structural Reflection in Rotor </li></ul><ul><li>Implementation </li></ul><ul><li>Assessment </li></ul><ul><li>Conclusions </li></ul>
  10. 10. Structural Reflective Facilities <ul><li>We have extended Rotor with the following summary of structural reflective capabilities </li></ul><ul><ul><li>Fields Manipulation . Dynamic addition, deletion and updating of </li></ul></ul><ul><ul><ul><li>The structure of classes (static and non-static fields) </li></ul></ul></ul><ul><ul><ul><li>The structure of a single object </li></ul></ul></ul><ul><ul><li>Methods manipulation . Dynamic addition, deletion and updating of </li></ul></ul><ul><ul><ul><li>Methods of classes (static and instance methods) </li></ul></ul></ul><ul><ul><ul><li>Methods of a specific object </li></ul></ul></ul><ul><ul><li>The implementation of new methods can be </li></ul></ul><ul><ul><ul><li>obtained as copies of existing ones </li></ul></ul></ul><ul><ul><ul><li>dynamically generated by means of the System.Reflection.Emit namespace </li></ul></ul></ul><ul><li>The programmer may combine these facilities with .Net introspective features to create adaptive(able) software in an easier way </li></ul>Structural Reflection in Rotor
  11. 11. Python Example class Point : &quot;Constructor&quot; def __init__ (self, x, y): self.x=x self.y=y &quot;Move Method&quot; def move (self, relx, rely): self.x=self.x+relx self.y=self.y+rely &quot;Draw Method&quot; def draw (self): print &quot;(&quot; +str(self.x)+ &quot;,&quot; +str(self.y)+ &quot;)&quot; point=Point(1,2) point.draw() # (1,2) # Modify attributes of # a single object point.z=3 print point.z # 3 # Modify methods of # a single object def draw3D (self): print &quot;(&quot; +str(self.x)+ &quot;,&quot; +str(self.y)+ &quot;,&quot; +str(self.z)+ &quot;)&quot; point.draw3D=draw3D point.draw3D() # (1,2,3) # Modify methods of a class def getX (self): return self.x Point.getX=getX print point.getX() # 1 Structural Reflection in Rotor
  12. 12. Conceptual Problems <ul><li>There are conceptual issues to tackle when adding structural reflective capabilities to class-based object-oriented systems </li></ul><ul><ul><li>Modifying classes structure  Schema evolution </li></ul></ul><ul><ul><ul><li>Default values to new fields </li></ul></ul></ul><ul><ul><ul><li>Runtime exceptions to manage obsolete code </li></ul></ul></ul><ul><ul><li>Modifying the structure of a single object  Schema versioning (new class for that object) </li></ul></ul><ul><ul><ul><li>Class identity (different classes, same type) </li></ul></ul></ul><ul><ul><ul><li>Memory consumption </li></ul></ul></ul><ul><ul><ul><li>Class structure consistency (future modifications of “first” class should imply modifications of “second” class) </li></ul></ul></ul><ul><ul><li>… Imply a complex implementation of an incoherent computational model (e.g. MetaXa) </li></ul></ul>Structural Reflection in Rotor
  13. 13. Prototype-Based OO Comp. Model <ul><li>The prototype-based object-oriented computational model (e.g. Self or Mootstrap) </li></ul><ul><ul><li>Does not use classes ( only objects ) </li></ul></ul>Point x,y:Integer draw() move(x,y:Integer) p:Point x=245 y=-23 Class-based model Prototype-based model inheritance Prototype Cloning Point pointPrototype p Trait object Prototype object Structural Reflection in Rotor <ul><ul><li>Shared behavior could be defined in objects called trait objects </li></ul></ul><ul><ul><li>Common structure is defined with prototype objects </li></ul></ul><ul><ul><li>Object’s instantiation is performed by cloning prototypes </li></ul></ul>Method implementation move Method implementation draw 0 y 0 x -23 y 245 x
  14. 14. Overcoming to Schema Evolution <ul><li>Prototype-based OO model overcomes the schema versioning problem detected with classes </li></ul><ul><li>It is possible to modify the structure of a single object in a coherent way </li></ul>draw method implementation move method implementation x 12 y 0 x 0 y 0 x 1 y 2 p1 p2 Point pointPrototype Structural Reflection in Rotor z 3 <ul><li>Modify attributes of a single object </li></ul>distance method <ul><li>Modify methods of a single object </li></ul>rotate method implementation <ul><li>Modify behavior and structure of a class </li></ul>
  15. 15. Structural Reflection in Rotor <ul><li>But, Rotor uses a class-based object-oriented computational model !!! </li></ul><ul><li>It is necessary to maintain classes because of </li></ul><ul><ul><li>Existing (class-based) legacy code </li></ul></ul><ul><ul><li>Languages and applications interoperability </li></ul></ul><ul><li>The programmer will continue using classes , but when using new structural reflective capabilities </li></ul><ul><ul><li>Classes will be treated as trait objects (shared behavior and lazy schema evolution for fields) </li></ul></ul><ul><ul><li>Objects will be capable of grouping both attributes and methods (slots)  No schema versioning </li></ul></ul><ul><li>Internally we use a prototype-based reflective model (module object of rotor) </li></ul>Structural Reflection in Rotor
  16. 16. Architecture <ul><li>Supporting both class-based </li></ul><ul><li>and prototype-based OO models </li></ul><ul><li>Manipulation of methods : </li></ul><ul><ul><li>Classes : Shared behavior (both models) </li></ul></ul><ul><ul><li>Objects : Specific behavior (mainly prototype-based model) </li></ul></ul><ul><li>Manipulation of fields : </li></ul><ul><ul><li>Classes : Lazy schema evolution ( class-based model) </li></ul></ul><ul><ul><li>Objects : Specific instance modification (mainly prototype-based model) </li></ul></ul><ul><li>“ Static typing where possible, dynamic typing when needed ” </li></ul>Structural Reflection in Rotor Compilation MSIL Я Rotor Operating System Execution Interaction Interaction C# Python Reflective C# Statically typed language (legacy code) Statically and Dynamically typed language Dynamically typed language
  17. 17. Contents <ul><li>Introduction </li></ul><ul><li>Reflection </li></ul><ul><li>Structural Reflection in Rotor </li></ul><ul><li>Implementation </li></ul><ul><li>Assessment </li></ul><ul><li>Conclusions </li></ul>
  18. 18. BCL Interface <ul><li>The final implementation consists of </li></ul><ul><ul><li>A set of new BCL reflective primitives </li></ul></ul><ul><ul><li>The extension of appropriate IL instruction semantics (code generated by the JITter) </li></ul></ul><ul><li>The BCL has been extended with a System.Reflection.Structural namespace </li></ul><ul><li>A summary of the most significant primitives (static methods of the Structural utility class) </li></ul><ul><ul><li>[ add , get , remove , alter , exist ] Field : Modify (inspect) the field structure of classes and single objects </li></ul></ul><ul><ul><li>[ add , get , remove , alter , exist ] Method : work with both classes ( Sytem.Type ) and objects using method descriptions ( MethodInfo ) </li></ul></ul><ul><ul><ul><li>Methods could be cloned from existing ones or dynamically generated with System.Reflection.Emit </li></ul></ul></ul><ul><ul><li>invoke : executes a class or object method taking into account the prototype-based semantics (and inheritance) </li></ul></ul><ul><ul><li>[ get , set ] Value : statically-typed field access </li></ul></ul>Implementation
  19. 19. Sample Code Fragment (BCL) <ul><li>A fragment of C# program that only uses the BCL interface of Я Rotor: </li></ul>Implementation RuntimeStructuralFieldInfo rsfi= new RuntimeStructuralFieldInfo( &quot;z&quot;, typeof ( int ),3, FieldAttributes.Public); Structural.addField(point,rsfi); // field addition (object) // * Draw3D is the MethodInfo of a new method generated by // means of the System.Reflection.Emit namespace Structural.addMethod(point,draw3D); // method addition (object) Object[] pars={}; // method invocation (object method) Structural.invoke(point,draw3D.ReturnType, &quot;draw3D&quot;,pars); // * getX is another MethodInfo Structural.addMethod( typeof (Point),getX); // add class method Console.WriteLine(Structural.invoke( point, getX.ReturnType, &quot;getX&quot;, pars ); rsfi = new RuntimeStructuralFieldInfo( &quot;isShowing&quot;, typeof ( bool ), false , FieldAttributes.Public); Structural.addField( typeof (Point), rsfi); // add class field
  20. 20. Extension of IL Semantics <ul><li>The new reflective model must be supported by the IL instructions , offering the benefits: </li></ul><ul><ul><li>Making existing (legacy) .Net applications reflective </li></ul></ul><ul><ul><li>Programmers should make no distinction between static and dynamic (reflective) code </li></ul></ul><ul><ul><li>Applications needn’t to be recompiled to be adapted </li></ul></ul><ul><li>We generate new native code, modifying the JIT compiler </li></ul><ul><li>This IL statements support dynamic type-checking </li></ul><ul><ul><li>ldfld , ldsfld , ldflda : Load into the stack the field value (or address) following the prototype-based model </li></ul></ul><ul><ul><li>stfld , stsfld : Store a value into a field, deciding its memory location at runtime </li></ul></ul><ul><ul><li>call , callvirt : Execute methods following the prototype-based model </li></ul></ul>Implementation
  21. 21. Implementation Details <ul><li>Inside of Rotor, both classes and objects are instances of the Object class ( object.h ) </li></ul><ul><li>These instances have fixed-size data </li></ul><ul><ul><li>we couldn’t make objects variable size </li></ul></ul><ul><li>We placed reflective information of each object inside their SyncBlock ( syncblk.h ) </li></ul><ul><ul><li>Two hash tables were added to dynamically collect reflective members (methods and fields) </li></ul></ul><ul><li>Reflective primitives manipulate this reflective information </li></ul><ul><ul><li>New semantics of IL instructions was added modifying the JITter functions ( fjit.cpp ): </li></ul></ul><ul><ul><ul><li>compileCEE_ { LDFLD , LDFLDA , STFLD , CALL , CALLVIRT } </li></ul></ul></ul><ul><ul><li>The reflective information is manipulated at runtime by the runtime helper functions ( fjitdef.h ): </li></ul></ul><ul><ul><li>JIT_ {{ Set , Get } Field { 32 , 64 , Obj }, GetFieldAddr , GetStaticFieldAddr , Test { Method , VirtualMethod }} </li></ul></ul><ul><ul><li>The rest of the functionality was placed in the BCL </li></ul></ul>Implementation
  22. 22. Contents <ul><li>Introduction </li></ul><ul><li>Reflection </li></ul><ul><li>Structural Reflection in Rotor </li></ul><ul><li>Implementation </li></ul><ul><li>Assessment </li></ul><ul><li>Conclusions </li></ul>
  23. 23. Reflective Primitives Assessment <ul><li>Three performance assessments </li></ul><ul><ul><li>Reflective primitives </li></ul></ul><ul><ul><li>The cost of adaptiveness (no reflection) </li></ul></ul><ul><ul><li>Benefits of JIT compilation (vs. existing implementations) </li></ul></ul><ul><li>We have evaluated the performance of the following reflective primitives </li></ul><ul><ul><li>[ add , delete ][ method , attribute ] </li></ul></ul><ul><ul><li>invoke , accessField </li></ul></ul><ul><ul><li>compared with </li></ul></ul><ul><ul><li>CPython 2.4. The most widely used interpreted implementation –developed in C </li></ul></ul><ul><ul><li>ActivePython 2.4 from ActiveState (C) </li></ul></ul><ul><ul><li>Jython 2.1. Compiles into 100% pure JVM code </li></ul></ul><ul><ul><li>IronPython 0.6. Generates CLR IL code </li></ul></ul><ul><li>Reflective primitives have been measured using different scenarios (10,000 iterations each) </li></ul>Assessment
  24. 24. Reflective Primitives Assessment <ul><ul><li>Я Rotor uses 23.18% average time ( 5.74 times faster) to execute reflective primitives in comparison with CPython </li></ul></ul><ul><ul><li>Notice that we do not support the whole Python programming language computational model </li></ul></ul>Assessment 0 200 400 600 800 1000 1200 1 3 5 7 9 11 13 15 17 19 ActivePython CPython Я Rotor 0 20000 40000 IronPython 1,2 Object attribute addition 3,4 Class attribute addition 5,6 Object attribute deletion 7,8 Class attribute deletion 9,10 Object attribute access 11,12 Class attribute access 13 Object method addition 14 Class method addition 15,16 Object method invocation 17 Class method invocation 18 Object method deletion 19 Class method deletion Jython
  25. 25. The cost of Adaptiveness <ul><li>Static ( non-reflective ) operations should also be measured against original Rotor </li></ul><ul><li>The current cost of flexibility has been measured with the Tommti benchmark that measures: </li></ul><ul><ul><li>{int,double,long} Arithmetic, trigonometric, input/output, array, exception handling, hash table(s), heap sort, vector, matrix, loops and string operations </li></ul></ul><ul><li>A performance penalty was only detected in member accesses </li></ul>Assessment Rotor Я Rotor 0% 20% 40% 60% 80% 100% int arithmetic double arithmetic long arithmetic trigonometric io array exception hashmap hashmaps heapsort vector matrix loops StringBuilder
  26. 26. The cost of Adaptiveness (II) <ul><li>After many optimizations , we have measured ( Я Rotor vs. Rotor) </li></ul><ul><ul><li>the cost of static ( non-reflective ) primitives </li></ul></ul><ul><ul><ul><li>Instance field access ( ldfld ): 0.6 times slower </li></ul></ul></ul><ul><ul><ul><li>Instance method invocation ( call ): 0.6 times slower </li></ul></ul></ul><ul><ul><li>the execution of real C# application benchmarks </li></ul></ul><ul><ul><ul><li>LCSCBench (LR parser): 0.81 times slower </li></ul></ul></ul><ul><ul><ul><li>AHCBench (Compression Algorithm): 2.14 times slower </li></ul></ul></ul>Assessment
  27. 27. Benefits of JIT Compilation <ul><li>What has been the performance benefit when executing non-reflective code ? </li></ul><ul><li>We have compared C# Tommti benchmark executed on Я Rotor and CPython </li></ul><ul><li>Average runtime performance is 9.01 times faster </li></ul><ul><ul><li>We do not support the whole Python computational model </li></ul></ul><ul><li>Differences with maps , vectors and files : </li></ul><ul><ul><li>in .Net, they belong to the BCL (performance overhead) </li></ul></ul><ul><ul><li>in Python, they are part of the language </li></ul></ul><ul><li>In both Python and .Net, arrays (matrix) are part of the language </li></ul>Assessment 0% 20% 40% 60% 80% 100% int arith. double arith. long arith. trigonometric io array exception hashmap hashmaps heapsort vector matrix loops StringBuilder CPython Features included in the Python PL Я Rotor
  28. 28. Contents <ul><li>Introduction </li></ul><ul><li>Reflection </li></ul><ul><li>Structural Reflection in Rotor </li></ul><ul><li>Implementation </li></ul><ul><li>Assessment </li></ul><ul><li>Conclusions </li></ul>
  29. 29. Major Conclusions <ul><li>JIT compilation is a suitable technique to optimize reflective primitives of dynamic languages </li></ul><ul><ul><li>9 times faster when executing non-reflective code </li></ul></ul><ul><ul><li>5.74 times faster when executing reflective code </li></ul></ul><ul><li>To make the CLI a platform to directly support reflection </li></ul><ul><ul><li>Semantics of the abstract machine should support reflective primitives </li></ul></ul><ul><ul><li>Extra code generation produces performance overhead (e.g., Jython and IronPython) </li></ul></ul><ul><li>Structural Reflection is properly represented by an internal prototype-based model </li></ul><ul><ul><li>plus a lazy schema evolution for classes </li></ul></ul><ul><ul><li>Both models could be supported (interaction) </li></ul></ul><ul><li>Statically typed programs ( legacy code ) could be dynamically adapted </li></ul><ul><li>After many optimizations, static (non-reflective) member accesses performance cost has been reduced from 350% to 60% </li></ul><ul><ul><li>Probably they can be reduced even more </li></ul></ul>Conclusions
  30. 30. Extending Rotor with Structural Reflection to support Reflective Languages