VirgilObjects on the Head of a Pin
Ben L. TitzerUCLA Compilers [email protected]
http://compilers.cs.ucla.edu/virgil 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
QuickTime™ and aTIFF (Uncompressed) decompressor
are needed to see this picture.
MCU: Atmel Atmega128Flash: 128KBRAM: 4KBDevices: Timers, EEPROM, ADC, UART
Node: Mica2 DotRadio: CC1000External Flash: 512KBSensors: light, temp, acoustic3 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
The Size Gap
101 102 103 104 105 106 107 108 109
Javaruntime
data
C++librarie
s
data
C
microcontrollers embedded desktop
Mostruntime
data
data
code
http://compilers.cs.ucla.edu/virgil 5
The Size Gap
101 102 103 104 105 106 107 108 109
Java
C++librarie
s
data
C
microcontrollers embedded desktop
Mostruntime
data
Virgil
data
code
http://compilers.cs.ucla.edu/virgil 6
Virgil Contributions
exe
initialization
Heap
IR
Heap
IRIR
SourceCode
optimization
Program initialization phase
Heap-specific optimization:RMA + RC +
ROM
Lightweight features
Compiler
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
component Timer { field divider: int; method start() { . . . } method stop() { . . . } method interrupt() { if (count % divider == 0) { LED.toggle(); count = 0; } }}
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
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 Exampleclass List {
field head: Link;
method add(i: Item) { . . . }
method apply(f: function(Item)) {
local pos = head;
while ( pos != null ) {
f(pos.item);
pos = pos.next;
}
}
}
component Client {
method printAll(l: List) { l.apply(print); }
method copy(a: List, b: List) { a.apply(b.add); }
method print(i: Item) { . . . }
}
Delegates
Delegate type
Invocation
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
component Strobe { field tree: Tree = new Tree(); constructor() { tree.add(6, 9, 11, 300); . . .; tree.balance(); } method entry() { Timer.start(); }}
component Timer { field count: int; method start() { . . . } method interrupt() { if ( Main.tree.find(count++) ) LED.toggle(); }}
program Example { components {Strobe,Timer,LED}; entrypoint main = Strobe.entry; entrypoint timer0_int = Timer.interrupt;}
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
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
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
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
http://compilers.cs.ucla.edu/virgil 23
RMA Illustration (1)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 24
RMA Illustration (2)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 25
RMA Illustration (3)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
Use of Main.f
http://compilers.cs.ucla.edu/virgil 26
RMA Illustration (4)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 27
RMA Illustration (5)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
Use of A.m
http://compilers.cs.ucla.edu/virgil 28
RMA Illustration (6)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 29
RMA Illustration (7)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 30
RMA Illustration (8)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 31
RMA Illustration (9)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 32
RMA Illustration (10)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 33
RMA Illustration (11)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 34
RMA Illustration (12)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 35
RMA Illustration (13)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 36
RMA Illustration (14)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 37
RMA Illustration (15)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 38
RMA Illustration (16)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 39
RMA Illustration (17)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 40
RMA Illustration (18)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 41
RMA Illustration (19)
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
current
http://compilers.cs.ucla.edu/virgil 42
RMA Result
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
http://compilers.cs.ucla.edu/virgil 43
CHA Result
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap
http://compilers.cs.ucla.edu/virgil 44
RTA Result
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap = { A, B, C }
http://compilers.cs.ucla.edu/virgil 45
Final RTA Result
component Main { field f: A = new A(); field g: A = new B(); field h: A = new C(); method entry() { 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;}
program heap = { A, B }
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
Referencible Sets
A
B C
D E
M
N P
Q
X
Y Z
Virgil has no universal superclass
Object
http://compilers.cs.ucla.edu/virgil 48
Referencible Sets
A
B C
D E
M
N P
Q
X
Y Z
Disjoint hierarchies completed unrelated
http://compilers.cs.ucla.edu/virgil 49
Referencible Sets
A
B C
D E
M
N P
Q
X
Y Z
Each can be considered independently
http://compilers.cs.ucla.edu/virgil 50
Referencible Sets
M
N P
Q
Type system restricts referencible sets
X
Y ZA
B C
D E
http://compilers.cs.ucla.edu/virgil 51
Referencible Sets
M
N P
Q
Approximate by merging inheritance tree
X
Y ZA
B C
D E
http://compilers.cs.ucla.edu/virgil 52
Referencible Sets
M
N P
Q
Count number of live objects in program heap
X
Y ZA
B C
D E
15
1
133
http://compilers.cs.ucla.edu/virgil 53
Table-based Compression
M
Introduce handle table in ROM
XA
15 1 133
log2(15+1) = 4 bits log2(1+1) = 1 bit log2(133+1) = 8 bits
… …
ROM
http://compilers.cs.ucla.edu/virgil 54
Table-based Compression
M
Stores actual addresses of objects
XA
15 1 133
log2(15+1) = 4 bits log2(1+1) = 1 bit log2(133+1) = 8 bits
… …
RAM
ROM
http://compilers.cs.ucla.edu/virgil 55
Experiments
http://compilers.cs.ucla.edu/virgil 56
Experiments
5 Demo Applications Blink: flip LEDs on / off periodically CntToLeds: rotate LEDs List: Manipulates linked lists Decoder: decoder tree builder MPK: message passing kernel (SOS excerpt)
Share common device drivers GPIO ports, Timer No native code
http://compilers.cs.ucla.edu/virgil 57
Baseline Compilation
Code* ROM RAM
Blink 1674 / 704 8 50
CntToLeds 1930 / 828 8 52
List 1012 / 582 14 164
Decoder 6600 / 3088 72 320
MPK 4396 / 1898 50 336
numbers in bytes
* gcc 3.3 / -O2
http://compilers.cs.ucla.edu/virgil 58
Results: Code Reduction
1674
1930
1012
6600
4396
704
828
578
3052
2004
704
828
582
3088
1908
696
814
578
3038
1898
1036
1376
560
1364
2868
546
688
354
566
1428
548
688
356
570
1360
540
674
354
570
1360
0 1000 2000 3000 4000 5000 6000 7000
Blink
CntToLeds
LinkedList
Decoder
MPK
RMA+Os
RMA+O2
RMA+O1
RMA
none+Os
none+O2
none+O1
none
http://compilers.cs.ucla.edu/virgil 59
Results: RAM Reduction
0 10 20 30 40 50 60
base
RMA
RMA+RC
primitives
references
metadata
alignment
0 50 100 150 200 250 300 350 400
base
RMA
RMA+RC
primitives
references
metadata
alignment
Blink
MPK 41%
74%
http://compilers.cs.ucla.edu/virgil 60
Results: RAM / ROM
50
52
164
320
336
14
30
110
316
296
13
23
41
190
198
8
8
14
72
50
2
6
8
20
30
8
16
74
118
94
0 50 100 150 200 250 300 350 400
Blink
CntToLeds
LinkedList
Decoder
MPK
ROM RMA+RCROM RMAROM baseRAM RMA+RCRAM RMARAM base
http://compilers.cs.ucla.edu/virgil 61
Conclusion
Objects can fit in the space gap Virgil solutions draw on
Language design New compilation model Minimal language runtime Aggressive compiler optimization
Practical results demonstrated Applications running on hardware simulator Significant resource reduction
http://compilers.cs.ucla.edu/virgil 62
Current and Future Work Virgil B-01 released January 9th, 2007 Language and runtime features
Parametric types (i.e. generics) Module system, dynamic loading DMA support Dynamic memory allocation
Applied ideas to Java PLDI 2007, with David Bacon at IBM
Tools: development, debugging, testing Code: drivers, applications, OS services
With undergrads Akop Palyan and Ryan Hall
http://compilers.cs.ucla.edu/virgil 63
Questions?
http://compilers.cs.ucla.edu/virgil 64
Anti-Features Locks: queues, atomicity, threads Interfaces: complex dispatch, tables Universal superclass: metaobjects Reflection: large metadata Dynamic allocation: allocator, GC Class loading: verifier, metadata Closures: dynamic allocation Intrinsics: built-ins
Top Related