200 likes | 1.28k Views
Revealing the Man Behind the Curtain Designing a Runtime Library for D The Language High-level programming Dynamic and associative arrays Garbage collection Unicode-aware Systems programming Pointers Inline assembly Direct calling of C code User Requirements High-level
E N D
Revealing the Man Behind the Curtain Designing a Runtime Library for D
The Language • High-level programming • Dynamic and associative arrays • Garbage collection • Unicode-aware • Systems programming • Pointers • Inline assembly • Direct calling of C code
User Requirements • High-level • Low barrier for entry / ease of use • It should be trivial to write a simple application • Applications should behave in a safe and predictable manner by default • Systems-oriented • Specialized information or access • Systems applications can often benefit from access to low-level information about the program or control over program behavior • Only get what you pay for • Systems programmers may have very explicit requirements regarding code size, so hidden dependencies must be avoided
Designer Requirements:The Compiler Writer • Language support routines • Dynamic array manipulation • Concatenation • Resizing • Sorting • Associative arrays • UTF conversions • Memory allocation / garbage collection
Designer Requirements:The Library Developer • User-accessible code • Thread management • Error handling • Input/output • Text processing
First Cut: Monolithic • Resources • Compiler team and library team • Team Interaction • Close collaboration for integrated features • Multithreading • Language / system exceptions • User control of garbage collection • Synchronized / inclusive releases
Second Cut: A Binary Design • Must formalize the interaction between components to decouple development effort • Language support component • Standard library component • Design limitations to eliminate compile-time dependencies • Functions • Structs • Simple data types
Standard Library Interface: Threads The garbage collector must interact with thread code to coordinate collection: void thread_suspendAll(); void thread_scanAll( void delegate( void*, void* ) scan, void* curStackTop = null ); void thread_resumeAll();
Standard Library Interface: Exceptions Expose a means of signaling system errors to decouple exception hierarchy from language support component: void onArrayBoundsError( char[] file, size_t line ); void onAssertError( char[] file, uint line ); void onOutOfMemoryError();
Third Cut: A Modular Design • Garbage collector research • Team skills: memory allocator and garbage collector design is a specialized field • Utilize externally developed garbage collectors to minimize team effort and obtain “best of breed” implementation • Varying needs of the users • Specialized garbage collectors • Typical vs. real-time
Language Support Interface: Platform-Specific Functionality The compiler is most suited for providing information about the target architecture: void* rt_stackTop(); void* rt_stackBottom(); void rt_scanStaticData( void delegate( void*, void* ) ); void rt_finalize( void* p, bool det = true );
Memory Management Interface void gc_enable(); void gc_disable(); void gc_collect(); uint gc_getAttr( void* p ); uint gc_setAttr( void* p, uint a ); uint gc_clrAttr( void* p, uint a ); void* gc_malloc( size_t sz, uint ba = 0 ); void* gc_calloc( size_t sz, uint ba = 0 ); void* gc_realloc( void* p, size_t sz, uint ba = 0 ); void gc_free( void* p ); size_t gc_sizeOf( void* p );
The Design Realized • Three components: • Language support • Garbage collector • Standard library • Proof of concept: Replaceable GC • Mark / sweep vs. C malloc • Link-time selection
private import tango.stdc.stdlib; private extern (C) void thread_init(); private extern (C) void onOutOfMemoryError(); extern (C) void* gc_malloc( size_t sz, uint ba = 0 ) { void* p = malloc( sz ); if( sz && p is null ) onOutOfMemoryError(); return p; } extern (C) void* gc_calloc( size_t sz, uint ba = 0 ) { void* p = calloc( 1, sz ); if( sz && p is null ) onOutOfMemoryError(); return p; } extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 ) { p = realloc( p, sz ); if( sz && p is null ) onOutOfMemoryError(); return p; } extern (C) void gc_free( void* p ) { free( p ); }
import tango.core.Memory; import tango.stdc.stdio; class C { this( char[] n ) { printf( "ctor: %.*s\n", name = n ); } ~this() { printf( "dtor: %.*s\n", name ); } char[] name; } void main() { auto autoVal = new C( "autoVal" ); scope scopeVal = new C( "scopeVal" ); autoVal = null; GC.collect(); }
31,744 gcbasic.lib 1,517 gcmalloc.d 383 Main.d 199,680 phobos.lib 66,048 tango.lib > dmd -release Main gcbasic.lib tango.lib > Main ctor: autoVal ctor: scopeVal dtor: autoVal dtor: scopeVal > dmd -release Main gcmalloc.d tango.lib > Main ctor: autoVal ctor: scopeVal dtor: scopeVal 104,476 Main.exe - using gcbasic.lib 91,164 Main.exe - using gcmalloc.d ------- 13,312
“Leak Detection” and Disposable • Validate program behavior • Specialized clean-up void rt_finalize( void* p, bool det = true ); bool onCollectResource( Object obj );
class Disposable { ~this() { printf( "dtor: Disposable\n" ); } void dispose() { printf( "dispose: Disposable\n" ); } } static this() { GC.collectHandler = &onCollect; } bool onCollect( Object o ) { if( auto d = cast(Disposable) o ) { d.dispose(); return false; } return true; } void discardDisposable() { auto d = new Disposable; } void main() { auto d = new Disposable; printf( "\n***** delete *****\n" ); d = new Disposable; delete d; printf( "\n*** GC.collect ***\n" ); GC.collect(); } > Main ***** delete ***** dtor: Disposable *** GC.collect *** dispose: Disposable
Overridable Object Monitors • Given the following interface: class Object { interface Monitor { void lock(); void unlock(); } } • Object monitors must be strucutred as: alias Object.Monitor IMonitor; struct Monitor { IMonitor impl; /* data */ }
Library Mutexes as Object Monitors auto mutex = new Mutex; auto cond = new Condition; bool ready = false; synchronized( mutex ) { while( !ready ) cond.wait(); // mutex released / acquired } synchronized( mutex ) { ready = true; cond.notify(); }