1 / 64

Virgil Objects on the Head of a Pin

Virgil Objects on the Head of a Pin. Ben L. Titzer UCLA Compilers Group titzer@cs.ucla.edu. The Microcontroller Challenge. ~6 billion MCUs produced annually In everything from microwaves to sensor nets Goal: Build robust and efficient systems software for very small devices

Download Presentation

Virgil Objects on the Head of a Pin

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. VirgilObjects on the Head of a Pin Ben L. Titzer UCLA Compilers Group titzer@cs.ucla.edu

  2. The Microcontroller Challenge • ~6 billion MCUs produced annually • In everything from microwaves to sensor nets • Goal: Build robust and efficient systems software for very small devices • Robust: language-level safety • Efficient: fit in tiny memories, run fast • On the bare metal: device drivers + OS MCU: Atmel Atmega128 Flash: 128KB RAM: 4KB Devices: Timers, EEPROM, ADC, UART Node: Mica2 Dot Radio: CC1000 External Flash: 512KB Sensors: light, temp, acoustic 3 LEDs, serial port http://compilers.cs.ucla.edu/virgil

  3. Difficulties • Domain constraints • Severe resource limitations • Low-level hardware details • Often lacks hardware protection • Events, interrupts, reentrancy • Energy, real-time requirements • Heavyweight runtime systems • Complex language services • Metadata requirements of language features http://compilers.cs.ucla.edu/virgil

  4. 104 101 102 103 105 106 107 108 109 The Size Gap data Most runtime Java data runtime C++ data libraries data C code microcontrollers embedded desktop http://compilers.cs.ucla.edu/virgil

  5. 104 101 102 103 105 106 107 108 109 The Size Gap data Most Virgil runtime Java C++ data libraries data C code microcontrollers embedded desktop http://compilers.cs.ucla.edu/virgil

  6. IR IR Heap Heap Virgil Contributions Heap-specific optimization: RMA + RC + ROM Lightweight features Source Code IR optimization initialization Compiler Program initialization phase exe http://compilers.cs.ucla.edu/virgil

  7. Virgil Basics • Overall goal: strong type safety • Familiar, well-defined primitives: int, boolean, char • Bounds-checked arrays of any type T as T[] • Dynamically safety checks for null and casts • With expressive features • Objects, components, arrays and delegates • Raw types 1…64 and operators for bit twiddling • Support for hardware access and interrupt handlers • But efficient implementation • No heavyweight runtime system • Straightforward object implementation • Sophisticated compiler optimizations http://compilers.cs.ucla.edu/virgil

  8. Components • Components encapsulate global state • Those members that would be static in Java • Require no metadata • Like a TinyOS component, but without wiring • Serve as the unit of compile-time initialization • Can define hardware interrupt handlers componentTimer { fielddivider: int; methodstart() { . . . } methodstop() { . . . } methodinterrupt() { if (count % divider == 0) { LED.toggle(); count = 0; } } } http://compilers.cs.ucla.edu/virgil

  9. Lightweight Objects • Virgil has classes similar to Java • Pass by reference semantics • Static types, dynamic safety checks • Single inheritance between classes • No interfaces • No java.lang.Object equivalent • Reduces size of metaobjects and object headers • Affords more programmer control • Complicates code reuse http://compilers.cs.ucla.edu/virgil

  10. Delegates (C#) • Delegates are typed method references • Bound to a method and its object • Approximates a closure • Syntax generalizes expr.method() • Anonymous type: function(Ta): Tb • Precludes method overloading • Implemented as <object, method> tuple • No memory allocation (unlike C#) • Efficient dispatch strategy • Can be represented as scalars locally http://compilers.cs.ucla.edu/virgil

  11. Delegate Example classList { fieldhead: Link; methodadd(i: Item) { . . . } methodapply(f: function(Item)) { local pos = head; while ( pos != null ) { f(pos.item); pos = pos.next; } } } componentClient { methodprintAll(l: List) { l.apply(print); } methodcopy(a: List, b: List) { a.apply(b.add); } methodprint(i: Item) { . . . } } Delegate type Invocation Delegates http://compilers.cs.ucla.edu/virgil

  12. Raw Types and Operators • Bit twiddling is tedious • Unnaturally sized fields, bit layouts • Masking and shifting is error prone • Raw types model bit-level values • The type k in { 1…64 } is a k-bit value • Bitwise operators & ^ | << >> model width • The [] operator accesses bits like an array • 0x0FF and 0b01110 literals have width • Can convert integers, characters, booleans • Hardware registers have raw types http://compilers.cs.ucla.edu/virgil

  13. Initialization Phase http://compilers.cs.ucla.edu/virgil

  14. Initialization Phase • Virgil has no dynamic memory allocation • Compile-time application constructors • Application allocates objects, arrays • Configure parameters, initialize data structures • Turing-complete computation • Heap compiled into program binary • Available immediately at runtime • Further allocation disallowed • Sophisticated space optimizations http://compilers.cs.ucla.edu/virgil

  15. Initialization Example programExample { components {Strobe,Timer,LED}; entrypoint main = Strobe.entry; entrypoint timer0_int = Timer.interrupt; } componentStrobe { fieldtree: Tree = new Tree(); constructor() { tree.add(6, 9, 11, 300); . . .; tree.balance(); } methodentry() { Timer.start(); } } componentTimer { fieldcount: int; methodstart() { . . . } methodinterrupt() { if ( Main.tree.find(count++) ) LED.toggle(); } } Main program declares included components and entrypoints Components contain initialization code for the program http://compilers.cs.ucla.edu/virgil

  16. Optimization http://compilers.cs.ucla.edu/virgil

  17. Compilation Techniques • Standard optimizations • Devirtualization, inlining, constant propagation • Orphan classes: require no metadata • Reachable Members Analysis: remove dead code, data, and fields • Reference Compression: compress objects by exploiting type safety http://compilers.cs.ucla.edu/virgil

  18. Code Reuse or Code Refuse? • Drivers, libraries, kernels are general • Unused states and modes • Unused data structures, methods, fields • Examples: timer, doubly linked list • RAM extremely precious on MCU • Goal: include only used code+data • Remove dead code, fields, objects • Minimize overall footprint for program • Reduce program and heap http://compilers.cs.ucla.edu/virgil

  19. Traditional Approach • Compiler explores call graph • Start at entrypoint method(s) • Transitively include called methods • Find dead fields by analyzing code • Remove dead fields from objects • Requires call site approximation • CHA, RTA, flow analysis • Do not leverage heap-specific information • Liveness cycle problem http://compilers.cs.ucla.edu/virgil

  20. Example Program program heap componentMain { fieldf: A = new A(); fieldg: A = new B(); fieldh: A = new C(); methodentry() { while ( true ) f = f.m(); } } classA { fieldz: int = 19; methodm(): A { return this; } } classB extends A { methodm(): A { return Main.g; } } classC extends A { methodm(): A { z++; return this; } } Main: Main { fieldf: A = A1; fieldg: A = B1; fieldh: A = C1; } A1: A { fieldz: int = 19; } B1: B { fieldz: int = 19; } C1: C { fieldz: int = 19; } http://compilers.cs.ucla.edu/virgil

  21. Reachable Members Analysis • Given: entrypoint methods and live heap • Assume everything is dead until used • Call graph approx. considers only live objects • Can assume no dynamic memory allocation, or conservatively include allocation sites • More precise than CHA, RTA analyses • Objects and types considered on demand • Avoids liveness cycle http://compilers.cs.ucla.edu/virgil

  22. RMA Illustration heap program component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } class A { field z: int = 19; method m(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { field f: A = A1; field g: A = B1; field h: A = C1; } A1: A { field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  23. current RMA Illustration (1) heap program componentMain { field f: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } class A { field z: int = 19; method m(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { field f: A = A1; field g: A = B1; field h: A = C1; } A1: A { field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  24. current RMA Illustration (2) heap program componentMain { field f: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } class A { field z: int = 19; method m(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { field f: A = A1; field g: A = B1; field h: A = C1; } A1: A { field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  25. current RMA Illustration (3) heap program componentMain { field f: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } class A { field z: int = 19; method m(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { field f: A = A1; field g: A = B1; field h: A = C1; } A1: A { field z: int = 19; } Use of Main.f B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  26. current RMA Illustration (4) heap program componentMain { field f: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } class A { field z: int = 19; method m(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { field f: A = A1; field g: A = B1; field h: A = C1; } A1: A { field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  27. current RMA Illustration (5) heap program componentMain { field f: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } class A { field z: int = 19; method m(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { field f: A = A1; field g: A = B1; field h: A = C1; } A1: A { field z: int = 19; } Use of A.m B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  28. current RMA Illustration (6) heap program componentMain { field f: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } class A { field z: int = 19; method m(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { field f: A = A1; field g: A = B1; field h: A = C1; } A1: A { field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  29. current RMA Illustration (7) heap program componentMain { field f: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } class A { field z: int = 19; method m(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { field f: A = A1; field g: A = B1; field h: A = C1; } A1: A { field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  30. current RMA Illustration (8) heap program componentMain { fieldf: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } class A { field z: int = 19; method m(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { field f: A = A1; field g: A = B1; field h: A = C1; } A1: A { field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  31. current RMA Illustration (9) heap program componentMain { fieldf: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } class A { field z: int = 19; method m(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { field f: A = A1; field g: A = B1; field h: A = C1; } A1: A { field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  32. current RMA Illustration (10) heap program componentMain { fieldf: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } class A { field z: int = 19; method m(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { field f: A = A1; field g: A = B1; field h: A = C1; } A1: A { field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  33. current RMA Illustration (11) heap program componentMain { fieldf: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } classA{ field z: int = 19; methodm(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { field f: A = A1; field g: A = B1; field h: A = C1; } A1: A { field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  34. current RMA Illustration (12) heap program componentMain { fieldf: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } classA{ field z: int = 19; methodm(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { fieldf: A = A1; field g: A = B1; field h: A = C1; } A1: A { field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  35. current RMA Illustration (13) heap program componentMain { fieldf: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } classA{ field z: int = 19; methodm(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { fieldf: A = A1; field g: A = B1; field h: A = C1; } A1: A { field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  36. current RMA Illustration (14) heap program componentMain { fieldf: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } classA{ field z: int = 19; methodm(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { fieldf: A = A1; field g: A = B1; field h: A = C1; } A1: A { field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  37. current RMA Illustration (15) heap program componentMain { fieldf: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } classA{ field z: int = 19; methodm(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { fieldf: A = A1; field g: A = B1; field h: A = C1; } A1:A{ field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  38. current RMA Illustration (16) heap program componentMain { fieldf: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } classA{ field z: int = 19; methodm(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { fieldf: A = A1; field g: A = B1; field h: A = C1; } A1:A{ field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  39. current RMA Illustration (17) heap program componentMain { fieldf: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } classA{ field z: int = 19; methodm(): A { return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { fieldf: A = A1; field g: A = B1; field h: A = C1; } A1:A{ field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  40. current RMA Illustration (18) heap program componentMain { fieldf: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } classA{ field z: int = 19; methodm(): A{ return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { fieldf: A = A1; field g: A = B1; field h: A = C1; } A1:A{ field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  41. current RMA Illustration (19) heap program componentMain { fieldf: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } classA{ field z: int = 19; methodm(): A{ return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { fieldf: A = A1; field g: A = B1; field h: A = C1; } A1:A{ field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  42. RMA Result heap program componentMain { fieldf: A = new A(); field g: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } classA{ field z: int = 19; methodm(): A{ return this; } } class B extends A { method m(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { fieldf: A = A1; field g: A = B1; field h: A = C1; } A1:A{ field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  43. CHA Result heap program componentMain { fieldf:A = new A(); fieldg: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } classA{ fieldz: int = 19; methodm(): A { return this; } } classBextends A { methodm(): A { return Main.g; } } classCextends A { methodm(): A { z++; return this; } } Main: Main { fieldf: A = A1; fieldg: A = B1; field h: A = C1; } A1: A { fieldz: int = 19; } B1: B { fieldz: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  44. RTA Result heap = { A, B, C } program componentMain { fieldf:A = new A(); fieldg: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } classA{ fieldz: int = 19; methodm(): A { return this; } } classBextends A { methodm(): A { return Main.g; } } classCextends A { methodm(): A { z++; return this; } } Main: Main { fieldf: A = A1; fieldg: A = B1; field h: A = C1; } A1: A { fieldz: int = 19; } B1: B { fieldz: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  45. Final RTA Result heap = { A, B } program componentMain { fieldf:A = new A(); fieldg: A = new B(); field h: A = new C(); methodentry() { while ( true ) f = f.m(); } } classA{ field z: int = 19; methodm(): A { return this; } } classBextends A { methodm(): A { return Main.g; } } class C extends A { method m(): A { z++; return this; } } Main: Main { fieldf: A = A1; fieldg: A = B1; field h: A = C1; } A1: A { field z: int = 19; } B1: B { field z: int = 19; } C1: C { field z: int = 19; } http://compilers.cs.ucla.edu/virgil

  46. Reference Compression • Pointers normally 16-bit integers • Types restrict referencible sets • Reference of type A can only point to A objects • Complete heap available after initialization • Represent references specially • Compression table approach • Use object handles instead of direct pointers • Handle tables can be stored in ROM http://compilers.cs.ucla.edu/virgil

  47. A X B C Y Z M D E N P Q Referencible Sets Object Virgil has no universal superclass http://compilers.cs.ucla.edu/virgil

  48. A X B C Y Z M D E N P Q Referencible Sets Disjoint hierarchies completed unrelated http://compilers.cs.ucla.edu/virgil

  49. A X B C Y Z M D E N P Q Referencible Sets Each can be considered independently http://compilers.cs.ucla.edu/virgil

  50. A X B C Y Z M D E N P Q Referencible Sets Type system restricts referencible sets http://compilers.cs.ucla.edu/virgil

More Related