" -*- Smalltalk -*- Copyright (c) 2005, 2006 Ian Piumarta All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation. THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK. Last edited: 2008-06-20 15:13:06 by piumarta on emilia.local " { import: CodeGenerator } "I am a managed code generator for target machines that understand C program source." CManagedCodeGenerator : CodeGenerator ( output "WriteStream on the output program text" ) [ CodeGenerators at: #managed put: CManagedCodeGenerator ] CManagedCodeGenerator new [ '*** GENERATING MANAGED CODE ***' putln. ^super new. ] CManagedCodeGenerator generate: program on: aStream for: aCompiler outputType: outputType fileName: fileName [ "Generate an entire program on aStream within aCompiler's global context. If outputType is #program then generate global program entry point and initialisation. If outputType is #object then append fileName to global initialiser." self := self withCompiler: aCompiler encoder: (Encoder withGlobalContext: aCompiler). output := aStream. program do: [:node | node encode: encoder]. self genl: (self headerTextType: outputType). encoder selectors do: [:var | self gen: 'static oop s_'; gen: var; genl: '= 0;']. "declare selector" self genl: 'static struct _Selector { const char *name; oop *addr; } _Selectors[]= {'. "selector table" encoder selectors keysAndValuesDo: [:string :var | self gen: ' { "'; genString: string ; gen: '", &s_'; gen: var; genl: ' },']. self genl: ' { 0, 0 }'; genl: '};'. program do: [:node | node genDeclaration: self]. program do: [:node | node genDefinition: self]. program do: [:node | node genImplementation: self]. self genl: (self initTextType: outputType fileName: fileName). program do: [:node | node genInitialisation: self]. self genl: '}'. outputType == #program ifTrue: [self genl: self mainText]. ^output ] CManagedCodeGenerator headerTextType: outputType [ ^ '/* generated by Id 1.0 at ', String dateAndTimeZuluStamp, ' */ /* with the command:', (Smalltalk arguments inject: '' into: [:s :a | s,' ',a]), ' */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define GC_DLL 1 #include #if defined(WIN32) # include # include typedef HINSTANCE dlhandle_t; # define dlopen(path, mode) LoadLibrary(path) # define dlsym(handle, name) ((void *)GetProcAddress(handle, name)) # define dlclose(handle) FreeLibrary(handle) # include inline int gettimeofday(struct timeval *tp, void *tzp) { union { long long ns100; FILETIME ft; } _now; GetSystemTimeAsFileTime(&_now.ft); tp->tv_usec= (long)((_now.ns100 / 10LL) % 1000000LL); tp->tv_sec= (long)((_now.ns100 - (116444736000000000LL)) / 10000000LL); return 0; } #else # include typedef void *dlhandle_t; #endif #ifndef O_BINARY # define O_BINARY 0 #endif typedef struct t__object *oop; typedef oop (*_imp_t)(oop _thunk, oop receiver, ...); struct __closure { _imp_t method; oop data; }; static void *(*_local_param )(int index)= 0; static oop (*_local_intern )(const char *string)= 0; static oop (*_local_proto )(oop base)= 0; static oop (*_local_import )(const char *name)= 0; static oop (*_local_export )(const char *name, oop value)= 0; static void (*_local_method )(oop type, oop selector, _imp_t method)= 0; static oop (*_local_alloc )(oop type, size_t size)= 0; static oop *(*_local_palloc )(size_t size)= 0; static void *(*_local_balloc )(size_t size)= 0; static struct __closure *(*_local_bind )(oop selector, oop receiver)= 0; static oop (*_local_nlreturn)(oop nlr, oop result)= 0; static oop (*_local_nlresult)(void)= 0; static oop _local_object= 0; static oop *_local_tag_vtable= 0; static oop *_local_nil_vtable= 0; static void (*_local_gc_addRoots)(char *lo, char *hi)= 0; #define _param(INDEX) _local_param(INDEX) #define _selector(NAME) _local_intern(NAME) #define _proto(BASE) _local_proto(BASE) #define _id_import(NAME) _local_import(NAME) #define _id_export(NAME, VAL) _local_export((NAME), (VAL)) #define _method(TYPE, SEL, IMP) _local_method((TYPE), (SEL), (_imp_t)(IMP)) #define _alloc(RCV, LBS) _local_alloc((RCV), (LBS)) #define _palloc(LBS) _local_palloc((LBS)) #define _balloc(LBS) _local_balloc((LBS)) #define _nlreturn(NLR, ARG) _local_nlreturn((NLR), (ARG)) #define _nlresult() _local_nlresult() ', self sendText, ' #define _super(TYP, MSG, RCV, ARG...) ({ \\ struct __closure *_c= (struct __closure *)_local_bind((MSG), (TYP)); \\ (_c->method)((oop)_c, (RCV), ##ARG); \\ }) '] CManagedCodeGenerator sendText [ compiler cacheLevel == 0 ifTrue: [^self sendNoCacheText]. compiler cacheLevel == 1 ifTrue: [^self sendInlineCacheText]. compiler error: 'unsupported cache level: ', compiler cacheLevel printString ] CManagedCodeGenerator sendNoCacheText [ ^' #define _send(MSG, RCV, ARG...) ({ \\ register oop _r= (RCV); \\ struct __closure *_c= (struct __closure *)_local_bind((MSG), _r); \\ (_c->method)((oop)_c, _r, ##ARG); \\ }) '] CManagedCodeGenerator sendInlineCacheText [ ^' struct __entry { oop vtable; struct __closure *closure; }; #define _send(MSG, RCV, ARG...) ({ \\ static struct __entry _e; \\ register oop _r= (RCV); \\ register oop _v= _r ? (((unsigned)_r & 1) ? *_local_tag_vtable : ((oop *)_r)[-1]) : *_local_nil_vtable; \\ if (_v != _e.vtable) { _e.vtable= _v; _e.closure= _local_bind((MSG), _r); } \\ (_e.closure->method)((oop)_e.closure, _r, ##ARG); \\ }) '] CManagedCodeGenerator initTextType: outputType fileName: fileName [ ^' void __id__init__', (outputType == #object ifTrue: [encoder mangleSelector: (fileName withoutSuffix: '.st')] ifFalse: ['']), '(void) { if (_local_object) return; { dlhandle_t global= dlopen(0, RTLD_LAZY); _local_object= *(oop *)dlsym(global, "_libid_object"); _local_param= dlsym(global, "_libid_param"); _local_intern= dlsym(global, "_libid_intern"); _local_proto= dlsym(global, "_libid_proto"); _local_import= dlsym(global, "_libid_import"); _local_export= dlsym(global, "_libid_export"); _local_method= dlsym(global, "_libid_method"); _local_alloc= dlsym(global, "_libid_alloc"); _local_palloc= dlsym(global, "_libid_palloc"); _local_balloc= dlsym(global, "_libid_balloc"); _local_bind= dlsym(global, "_libid_bind"); _local_nlreturn= dlsym(global, "_libid_nlreturn"); _local_nlresult= dlsym(global, "_libid_nlresult"); _local_tag_vtable= dlsym(global, "_libid_tag_vtable"); _local_nil_vtable= dlsym(global, "_libid_nil_vtable"); _local_gc_addRoots= dlsym(global, "GC_add_roots"); dlclose(global); }', (outputType == #program ifTrue: [''] ifFalse: [' # define GC_add_roots _local_gc_addRoots GC_INIT();']), ' { struct _Selector *s= 0; for (s= _Selectors; s->name; ++s) *s->addr= _selector(s->name); } '] CManagedCodeGenerator mainText [ ^' int main(int argc, char **argv, char **envp) { dlhandle_t global= dlopen(0, RTLD_LAZY); void *_local_init= dlsym(global, "_libid_init"); if (!_local_init) { fprintf(stderr, "id runtime not found\\n"); abort(); } ((void (*)(int *, char ***, char ***))_local_init)(&argc, &argv, &envp); __id__init__(); dlclose(global); return 0; }'] "writing to the output stream" CManagedCodeGenerator put: aCharacter [ output nextPut: aCharacter ] CManagedCodeGenerator print: anObject [ output print: anObject ] CManagedCodeGenerator gen: aString [ output nextPutAll: aString ] CManagedCodeGenerator genl: aString [ output nextPutAll: aString; nl ] CManagedCodeGenerator comment: aString [ output nextPutAll: ' '; nextPutAll: '/* '; nextPutAll: aString; nextPutAll: ' */'; nl ] "writing specific types of information, with a type-specific prefix" CManagedCodeGenerator genSelector: aSelector [ output nextPutAll: 's_'; nextPutAll: (encoder selectors at: aSelector ifAbsent: [self error: 'internal compiler error #2 (', aSelector printString, ')']). ] CManagedCodeGenerator genLocation: aLocation [ output nextPut: $_; print: aLocation ] CManagedCodeGenerator genStruct: name [ output nextPutAll: 'struct t_'; nextPutAll: name ] CManagedCodeGenerator genVariable: name [ output nextPutAll: 'v_'; nextPutAll: name ] CManagedCodeGenerator genLiteral: tag [ output nextPutAll: 'l_'; print: tag ] CManagedCodeGenerator genBlock: tag [ output nextPutAll: 'b_'; print: tag ] CManagedCodeGenerator genLabel: tag [ output nextPutAll: '_l'; print: tag ] CManagedCodeGenerator genString: string [ string do: [:c | c == $\\ ifTrue: [output nextPut: c]. output nextPut: c] ] CManagedCodeGenerator genType: name method: selector [ output nextPutAll: name; nextPutAll: '__'; nextPutAll: (encoder selectors at: selector ifAbsent: [self error: 'internal compiler error #3 (', selector printString, ')']). ] CManagedCodeGenerator genType: name sequence: sequenceNumber method: selector [ output nextPutAll: name. sequenceNumber > 0 ifTrue: [output nextPutAll: '__'; print: sequenceNumber]. output nextPutAll: '__'; nextPutAll: (encoder selectors at: selector ifAbsent: [self error: 'internal compiler error #3 (', selector printString, ')']). ] "unparsed code: external code and primitives" CManagedCodeGenerator genExtern: code [ self genl: ' {'; gen: code; genl: ' ;'; genl: ' }'. ] CManagedCodeGenerator genInclude: name [ self gen: '#include '; genl: name. ] CManagedCodeGenerator genPrimitive: code in: mtype [ self genl: ' {'. mtype isNil ifFalse: [self gen: '# define self (('; genStruct: mtype name; genl: ' *)v_self)']. self genl: code. mtype isNil ifFalse: [self genl: '# undef self']. self genl: ' }'. ] "stack: loading constants and literals" CManagedCodeGenerator loadNil: loc [ self gen: ' '; genLocation: loc; genl: '= 0;'. ] CManagedCodeGenerator declareLiteral: tag [ self gen: 'static oop '; genLiteral: tag; genl: '= 0;'. ] CManagedCodeGenerator defineLiteral: tag [] CManagedCodeGenerator loadLiteral: tag to: loc [ self gen: ' '; genLocation: loc; gen: '= '; genLiteral: tag; genl: ';'. ] CManagedCodeGenerator initialiseInteger: tag constructor: constructor with: anInteger [ self gen: ' '; genLiteral: tag; gen: '= _send('; genSelector: constructor value; gen: ', '; genVariable: constructor key; gen: ', '; print: anInteger; genl: ');'. ] CManagedCodeGenerator defineFloat: tag withValue: aString [ | first | self gen: 'static double d_'; print: tag; gen: '= '; gen: aString; genl: ';'. ] CManagedCodeGenerator initialiseFloat: tag constructor: constructor with: aString [ self gen: ' '; genLiteral: tag; gen: '= _send('; genSelector: constructor value; gen: ', '; genVariable: constructor key; gen: ', &d_'; print: tag; genl: ');'. ] CManagedCodeGenerator initialiseCharacter: tag constructor: constructor with: aCharacter [ self gen: ' '; genLiteral: tag; gen: '= _send('; genSelector: constructor value; gen: ', '; genVariable: constructor key; gen: ', '; print: aCharacter value; genl: ');'. ] CManagedCodeGenerator initialiseString: tag constructor: constructor with: aString [ self gen: ' '; genLiteral: tag; gen: '= _send('; genSelector: constructor value; gen: ', '; genVariable: constructor key; gen: ', '; print: aString size; gen: ', "'. aString do: [:char | char = $" ifTrue: [self gen: '\\"'] ifFalse: [| ascii | ascii := char asciiValue. (ascii >= 32 and: [ascii < 127 and: [char ~~ $" and: [char ~~ $\\]]]) ifTrue: [self put: char] ifFalse: [self put: $\\; put: (Character digitValue: ascii // 64 \\ 8); put: (Character digitValue: ascii // 8 \\ 8); put: (Character digitValue: ascii \\ 8)]]]. self genl: '");'. ] CManagedCodeGenerator initialiseByteArray: tag constructor: constructor with: aByteArray [ self gen: ' '; genLiteral: tag; gen: '= _send('; genSelector: constructor value; gen: ', '; genVariable: constructor key; gen: ', '; print: aByteArray size; gen: ', "'. aByteArray do: [:byte | self put: $\\; put: (Character digitValue: byte // 64 \\ 8); put: (Character digitValue: byte // 8 \\ 8); put: (Character digitValue: byte \\ 8)]. self genl: '");'. ] CManagedCodeGenerator defineWordArray: tag withElements: aWordArray [ | first | self gen: 'static int w'; genLiteral: tag; gen: '['; print: aWordArray size; genl: ']= {'. first := true. aWordArray do: [:word | first ifTrue: [first := false] ifFalse: [self genl: ',']. self genl: ' '; print: word]. self genl: ''; genl: '};'. ] CManagedCodeGenerator initialiseWordArray: tag constructor: constructor with: aWordArray [ self gen: ' '; genLiteral: tag; gen: '= _send('; genSelector: constructor value; gen: ', '; genVariable: constructor key; gen: ', '; print: aWordArray size; gen: ', '; gen: 'w'; genLiteral: tag; genl: ');'. ] CManagedCodeGenerator defineArray: tag withElements: anArray [ | first | self gen: 'static oop a'; genLiteral: tag; gen: '['; print: anArray size; genl: ']= {'. first := true. anArray do: [:element | first ifTrue: [first := false] ifFalse: [self genl: ',']. self genl: ' '; gen: '(oop)&'; genLiteral: element tag]. self genl: ''; genl: '};'. ] CManagedCodeGenerator initialiseArray: tag constructor: constructor with: anArray [ self gen: ' '; genLiteral: tag; gen: '= _send('; genSelector: constructor value; gen: ', '; genVariable: constructor key; gen: ', '; print: anArray size; gen: ', '; gen: 'a'; genLiteral: tag; genl: ');'. ] "blocks" CManagedCodeGenerator initialiseBlock: blockTag function: functionTag arity: arity constructor: constructor [ self gen: ' '; genLiteral: blockTag; gen: '= _send('; genSelector: constructor value; gen: ', '; genVariable: constructor key; gen: ', '; genBlock: functionTag; gen: ', '; "function" print: arity; "arity" genl: ');'. ] CManagedCodeGenerator loadBlock: tag location: loc [ self gen: ' '; genLocation: loc; gen: '= '; genLiteral: tag; genl: ';'. ] CManagedCodeGenerator makeBlock: tag constructor: constructor outerFlag: outerFlag function: functionTag arity: arity state: scopeTagOrNil nlrFlag: nlrFlag location: location [ self gen: ' '; genLocation: location; gen: '= _send('; genSelector: constructor value; gen: ', '; genVariable: constructor key; gen: ', '; gen: '(oop)'; genBlock: functionTag; "function" gen: ', '; print: arity; "arity" gen: ', '; gen: (outerFlag ifTrue: ['v__self'] ifFalse: ['0']). "outer" scopeTagOrNil isNil ifTrue: [self gen: ', 0'] "state" ifFalse: [self gen: ', '; genState: scopeTagOrNil]. self gen: ', '; gen: (nlrFlag "nlr" ifTrue: [outerFlag ifTrue: ['((struct t_BlockClosure *)v__self)->v__nlr'] ifFalse: ['_nlr']] ifFalse: ['0']); genl: ');'. ] "stack: loading and storing variables" CManagedCodeGenerator loadGlobal: var location: loc [ self gen: ' '; genLocation: loc; gen: '= '; genVariable: var name; genl: ';'. ] CManagedCodeGenerator storeGlobal: var location: loc [ self gen: ' '; genVariable: var name; gen: '= '; genLocation: loc; genl: ';'; gen: ' '; gen: '_id_export("'; gen: var name; gen: '", '; genVariable: var name; genl: ');'. ] CManagedCodeGenerator loadSlot: slot type: type location: loc [ self gen: ' '; genLocation: loc; gen: '= (('; genStruct: type name; gen: ' *)v_self)->'; genVariable: slot name; genl: ';'. ] CManagedCodeGenerator storeSlot: slot type: type location: loc [ self gen: ' (('; genStruct: type name; gen: ' *)v_self)->'; genVariable: slot name; gen: '= '; genLocation: loc; genl: ';'. ] CManagedCodeGenerator loadArgument: arg location: loc [ self gen: ' '; genLocation: loc; gen: '= '; genVariable: arg name; genl: ';'. ] CManagedCodeGenerator storeArgument: arg location: loc [ self gen: ' '; genVariable: arg name; gen: '= '; genLocation: loc; genl: ';'. ] CManagedCodeGenerator loadTemporary: tmp location: loc [ self gen: ' '; genLocation: loc; gen: '= '; genVariable: tmp name; genl: ';'. ] CManagedCodeGenerator storeTemporary: tmp location: loc [ self gen: ' '; genVariable: tmp name; gen: '= '; genLocation: loc; genl: ';'. ] CManagedCodeGenerator storeTemporary: tmp withPrototype: proto [ self gen: ' '; genVariable: tmp name; gen: '= '; genVariable: proto name; genl: ';'. ] CManagedCodeGenerator storePrototype: proto withTemporary: tmp [ self gen: ' '; genVariable: proto name; gen: '= '; genVariable: tmp name; genl: ';'. ] CManagedCodeGenerator loadFree: name scope: scopeTag outer: indir offset: offset location: loc [ self gen: ' '; genLocation: loc; gen: '= '; genFreeState: scopeTag outer: indir offset: offset; gen: ';'; comment: name. ] CManagedCodeGenerator storeFree: name scope: scopeTag outer: indir offset: offset location: loc [ self gen: ' '; genFreeState: scopeTag outer: indir offset: offset; gen: '= '; genLocation: loc; gen: ';'; comment: name. ] CManagedCodeGenerator loadFreeSlot: name type: type scope: scopeTag outer: indir offset: offset location: loc [ self gen: ' '; genLocation: loc; gen: '= (('; genStruct: type; gen: ' *)'; genFreeState: scopeTag outer: indir offset: offset; gen: ')->'; genVariable: name; gen: ';'; comment: name. ] CManagedCodeGenerator storeFreeSlot: name type: type scope: scopeTag outer: indir offset: offset location: loc [ self gen: ' '; gen: '(('; genStruct: type; gen: ' *)'; genFreeState: scopeTag outer: indir offset: offset; gen: ')->'; genVariable: name; gen: '= '; genLocation: loc; gen: ';'; comment: name. ] CManagedCodeGenerator genFreeState: scopeTag outer: indir offset: offset [ "If INDIR > 0 then the reference is non local: climb up through INDIR outer contexts to find a state vector in which the var is stored at OFFSET. If INDIR = 0 then SCOPETAG is the tag of a locally-visible state vector in which the var is stored at OFFSET." indir = 0 ifTrue: [self genState: scopeTag at: offset] ifFalse: [self gen: '((oop *)((struct t_BlockClosure *)'. indir - 1 timesRepeat: [self gen: '((struct t_BlockClosure *)']. self gen: '((struct t_BlockClosure *)v__self)'. indir - 1 timesRepeat: [self gen: '->v_outer)']. self gen: '->v_state))['; print: offset; gen: ']'.]. ] "messaging: send and return" CManagedCodeGenerator genReturn: node [ self gen: ' '; gen: 'return '; genLocation: node location; genl: ';'. ] CManagedCodeGenerator genNonLocalReturn: node [ self gen: ' '; gen: 'return _nlreturn(((struct t_BlockClosure *)v__self)->v__nlr, '; genLocation: node location; genl: ');'. ] CManagedCodeGenerator send: selector to: receiver withArguments: arguments forValue: valueFlag supered: superedType [ self gen: ' '. valueFlag ifTrue: [self genLocation: receiver location; gen: '=']. superedType isNil ifTrue: [self gen: '_send('; genSelector: selector; gen: ', '; genLocation: receiver location] ifFalse: [self gen: '_super('; genVariable: superedType; gen: ', '; genSelector: selector; gen: ', '; genLocation: receiver location]. arguments do: [:arg | self gen: ', '; genLocation: arg location]. self genl: ');'. ] "runtime support" CManagedCodeGenerator import: name [ self gen: ' '; gen: '_send('; genSelector: '_import:'; gen: ', '; gen: '_local_object'; gen: ', "'; gen: name; gen: '", "'; gen: '__id__init__'; gen: (encoder mangleSelector: name); genl: '");'. ] "types" CManagedCodeGenerator declareType: typeNode [ self genStruct: typeNode name; genl: ' {'; genl: ' struct _vtable *_vtable[0];'. typeNode slots do: [:slot | self gen: ' oop '; genVariable: slot; genl: ';']. self genl: '};'. ] CManagedCodeGenerator defineType: typeNode [ self gen: 'static oop '; genVariable: typeNode name; genl: '= 0;'. ] CManagedCodeGenerator implementType: typeNode [ | name | name := typeNode name. self gen: 'static size_t '; genType: name method: '_sizeof'; gen: '(oop '; genVariable: 'self'; gen: ') {'; gen: ' return sizeof('; genStruct: name; genl: '); }'; gen: 'static char *'; genType: name method: '_debugName'; gen: '(oop '; genVariable: 'self'; gen: ') {'; gen: ' return "'; gen: name; genl: '"; }'. ] CManagedCodeGenerator initialiseExternal: typeName [ self gen: ' '; genVariable: typeName; gen: '= _id_import("'; gen: typeName; genl: '");'. ] CManagedCodeGenerator initialiseType: typeName in: baseName [ self gen: ' '; genVariable: typeName; gen: '= _proto('. baseName isNil ifTrue: [self gen: '0'] ifFalse: [self genVariable: baseName]. self genl: ');'. self gen: ' _method('; genVariable: typeName; gen: ', '; genSelector: '_sizeof'; gen: ', '; genType: typeName method: '_sizeof'; genl: ');'; gen: ' _method('; genVariable: typeName; gen: ', '; genSelector: '_debugName'; gen: ', '; genType: typeName method: '_debugName'; genl: ');'; gen: ' _id_export("'; gen: typeName; gen: '", '; genVariable: typeName; genl: ');'. ] "globals" CManagedCodeGenerator defineVariable: definitionNode [ self gen: 'static oop '; genVariable: definitionNode name; genl: '= 0;'. ] CManagedCodeGenerator initialiseVariable: varName [ self gen: ' '; genVariable: varName; genl: '= 0;'; gen: ' _id_export("'; gen: varName; gen: '", '; genVariable: varName; genl: ');'. ] CManagedCodeGenerator initialiseVariable: varName location: loc [ self gen: ' '; genVariable: varName; gen: '= '; genLocation: loc; genl: ';'; gen: ' _id_export("'; gen: varName; gen: '", '; genVariable: varName; genl: ');'. ] "sequences: methods and blocks" CManagedCodeGenerator beginBlock: blockNode arguments: arguments variadic: variadic [ self gen: 'static oop '; genBlock: blockNode tag; gen: '(oop v__closure, oop v__self'. arguments do: [:arg | self gen: ', oop '; genVariable: arg name]. variadic ifTrue: [self gen: ', ...']. self genl: ')'. ] CManagedCodeGenerator beginMethod: methodNode in: typeNode arguments: arguments variadic: variadic sequence: sequenceNumber [ self gen: 'static oop '; genType: typeNode name sequence: sequenceNumber method: methodNode selector; gen: '(oop v__closure'. arguments do: [:arg | self gen: ', oop '; genVariable: arg name]. variadic ifTrue: [self gen: ', ...']. self genl: ')'. ] CManagedCodeGenerator beginSequence: sequenceNode [ self genl: ' {' ] CManagedCodeGenerator endSequence: sequenceNode [ self genl: ' }' ] CManagedCodeGenerator createStateVector: size inScope: scopeTag constructor: constructor [ self gen: ' '; gen: 'oop _state'; print: scopeTag; gen: '= _send('; genSelector: constructor value; gen: ', '; genVariable: constructor key; gen: ', '; print: size + 1; genl: ');'. ] CManagedCodeGenerator genState: scopeTag [ self gen: '((oop *)_state'; print: scopeTag; gen: ')' ] CManagedCodeGenerator genState: scopeTag at: offset [ self genState: scopeTag; gen: '['; print: offset; gen: ']' ] CManagedCodeGenerator declareVariadic: arg [ self gen: ' '; genl: 'va_list ap;'. ] CManagedCodeGenerator declareTemporary: tmp [ self gen: ' '; gen: 'oop '; genVariable: tmp name; genl: '= 0;'. ] CManagedCodeGenerator declareStack: size [ 1 to: size do: [:index | self gen: ' oop '; genLocation: index; genl: '= 0;']. ] CManagedCodeGenerator declareNonLocalReturn [ self gen: ' '; genl: 'jmp_buf __nlr;'. self gen: ' '; genl: 'oop _nlr;'. ] CManagedCodeGenerator defineTemporary: tmp [ self gen: ' '; gen: '(void)'; genVariable: tmp name; genl: ';'. ] CManagedCodeGenerator defineVariadic: arg [ self gen: ' '; genVariable: 'nextArgument'; genl: '= (oop)≈'. self gen: ' '; gen: 'va_start(ap, '; genVariable: arg name; genl: ');'. ] CManagedCodeGenerator defineNonLocalReturn [ self gen: ' '; genl: '_nlr= (oop)&__nlr;'. self gen: ' '; genl: 'if (setjmp(__nlr)) { return _nlresult(); }'. ] CManagedCodeGenerator defineStack: size [] CManagedCodeGenerator saveArgument: var [ self gen: ' '; genState: var scope tag at: var offset; gen: '= '; genVariable: var name; genl: ';'. ] CManagedCodeGenerator initialiseMethod: selector in: typeNode sequence: sequenceNumber [ self gen: ' _method('; genVariable: typeNode name; gen: ', '; genSelector: selector; gen: ', '; genType: typeNode name sequence: sequenceNumber method: selector; genl: ');'. ] "control flow: labels and jumps" CManagedCodeGenerator pushLabel [ ^nextLabel := nextLabel + 1 ] CManagedCodeGenerator defineLabel: label [ self gen: ' '; genLabel: label; genl: ':;' ] CManagedCodeGenerator popLabel [] CManagedCodeGenerator popLabels: count [] CManagedCodeGenerator jumpTo: label [ self gen: ' '; gen: 'goto '; genLabel: label; genl: ';' ] CManagedCodeGenerator jumpFalse: loc to: label [ self gen: ' '; gen: 'if (!'; genLocation: loc; gen: ') goto '; genLabel: label; genl: ';' ] CManagedCodeGenerator jumpTrue: loc to: label [ self gen: ' '; gen: 'if (' ; genLocation: loc; gen: ') goto '; genLabel: label; genl: ';' ] "special and tagged arithmetic operations" CManagedCodeGenerator compare: loc1 identical: loc2 location: loc [ self gen: ' '; genLocation: loc; gen: '= ('; genLocation: loc1; gen: ' == '; genLocation: loc2; genl: ') ? v_true : v_false;'. ] CManagedCodeGenerator compare: loc1 notIdentical: loc2 location: loc [ self gen: ' '; genLocation: loc; gen: '= ('; genLocation: loc1; gen: ' != '; genLocation: loc2; genl: ') ? v_true : v_false;'. ] CManagedCodeGenerator checkTags: check with: lhs with: rhs [ self gen: '(1'. (check == #left or: [check == #both]) ifTrue: [self gen: ' & (long)'; genLocation: lhs]. (check == #right or: [check == #both]) ifTrue: [self gen: ' & (long)'; genLocation: rhs]. self gen: ')'. ] CManagedCodeGenerator tagged: rcv add: arg location: loc checking: tagCheck [ " self gen: ' '; gen: 'if '; checkTags: tagCheck with: rcv with: arg; genl: ' {'; gen: ' '; gen: ' '; genLocation: loc; gen: '= (oop)(((long)'; genLocation: rcv; gen: ' + (long)'; genLocation: arg; genl: ') - 1L);'; gen: ' '; gen: '} else '; genLocation: loc; gen: '= _send('; genSelector: '+'; gen: ', '; genLocation: rcv; gen: ', '; genLocation: arg; genl: ');'. " self genl: ' {'; gen: ' int _l= (long)'; genLocation: rcv; genl: ' >> 1;'; gen: ' int _r= (long)'; genLocation: arg; genl: ' >> 1;'; genl: ' int _s= _l + _r;'; gen: ' if ('; checkTags: tagCheck with: rcv with: arg; gen: ' && ((_s ^ (_s << 1)) >= 0))'; gen: ' '; genLocation: loc; gen: '= (oop)(long)(_s << 1 | 1);'; gen: ' else '; genLocation: loc; gen: '= '; gen: '_send('; genSelector: '+'; gen: ', '; genLocation: rcv; gen: ', '; genLocation: arg; genl: ');'; genl: ' }' ] CManagedCodeGenerator tagged: rcv sub: arg location: loc checking: tagCheck [ " self gen: ' '; gen: 'if '; checkTags: tagCheck with: rcv with: arg; genl: ' {'; gen: ' '; gen: ' '; genLocation: loc; gen: '= (oop)(((long)'; genLocation: rcv; gen: ' - (long)'; genLocation: arg; genl: ') + 1L);'; gen: ' '; gen: '} else '; genLocation: loc; gen: '= _send('; genSelector: '-'; gen: ', '; genLocation: rcv; gen: ', '; genLocation: arg; genl: ');'. " self genl: ' {'; gen: ' int _l= (long)'; genLocation: rcv; genl: ' >> 1;'; gen: ' int _r= (long)'; genLocation: arg; genl: ' >> 1;'; genl: ' int _s= (_l - _r);'; gen: ' if ('; checkTags: tagCheck with: rcv with: arg; gen: ' && ((_s ^ (_s << 1)) >= 0))'; gen: ' '; genLocation: loc; gen: '= (oop)(long)(_s << 1 | 1);'; gen: ' else '; genLocation: loc; gen: '= '; gen: '_send('; genSelector: '-'; gen: ', '; genLocation: rcv; gen: ', '; genLocation: arg; genl: ');'; genl: ' }' ] CManagedCodeGenerator tagged: rcv op: operator selector: sel with: arg location: loc checking: tagCheck [ self gen: ' '; gen: 'if '; checkTags: tagCheck with: rcv with: arg; genl: ' {'; gen: ' '; gen: ' '; genLocation: loc; gen: '= (oop)(((((long)'; genLocation: rcv; gen: '>> 1) '; gen: operator; gen: ' ((long)'; genLocation: arg; genl: '>> 1)) << 1) | 1);'; gen: ' '; gen: '} else '; genLocation: loc; gen: '= _send('; genSelector: sel; gen: ', '; genLocation: rcv; gen: ', '; genLocation: arg; genl: ');'. ] CManagedCodeGenerator tagged: rcv mul: arg location: loc checking: tagCheck [ " self tagged: rcv op: '*' selector: '*' with: arg location: loc checking: tagCheck " self genl: ' {'; gen: ' int _l= (long)'; genLocation: rcv; genl: ' >> 1;'; gen: ' int _r= (long)'; genLocation: arg; genl: ' >> 1;'; genl: ' int _s= (_l * _r);'; gen: ' if ('; checkTags: tagCheck with: rcv with: arg; gen: ' && ((_r == 0) || (_s / _r == _l))'; gen: ' && ((_s ^ (_s << 1)) >= 0))'; gen: ' '; genLocation: loc; gen: '= (oop)(long)(_s << 1 | 1);'; gen: ' else '; genLocation: loc; gen: '= '; gen: '_send('; genSelector: '*'; gen: ', '; genLocation: rcv; gen: ', '; genLocation: arg; genl: ');'; genl: ' }' ] CManagedCodeGenerator tagged: rcv div: arg location: loc checking: tagCheck [ " self tagged: rcv op: '/' selector: '//' with: arg location: loc checking: tagCheck " self gen: ' '; genLocation: loc; gen: '= '; gen: '_send('; genSelector: '//'; gen: ', '; genLocation: rcv; gen: ', '; genLocation: arg; genl: ');' ] CManagedCodeGenerator tagged: rcv mod: arg location: loc checking: tagCheck [ " self tagged: rcv op: '%' selector: '\\\\' with: arg location: loc checking: tagCheck " self gen: ' '; genLocation: loc; gen: '= '; gen: '_send('; genSelector: '\\\\'; gen: ', '; genLocation: rcv; gen: ', '; genLocation: arg; genl: ');' ] CManagedCodeGenerator tagged: rcv and: arg location: loc checking: tagCheck [ self gen: ' '; gen: 'if ('; checkTags: tagCheck with: rcv with: arg; gen: ' && ('; genLocation: rcv; gen: ' > 0)'; gen: ' && ('; genLocation: arg; genl: ' > 0)) {'; gen: ' '; gen: ' '; genLocation: loc; gen: '= (oop)((long)'; genLocation: rcv; gen: ' & (long)'; genLocation: arg; genl: ');'; gen: ' '; gen: '} else '; genLocation: loc; gen: '= _send('; genSelector: 'bitAnd:'; gen: ', '; genLocation: rcv; gen: ', '; genLocation: arg; genl: ');'. ] CManagedCodeGenerator tagged: rcv or: arg location: loc checking: tagCheck [ self gen: ' '; gen: 'if ('; checkTags: tagCheck with: rcv with: arg; gen: ' && ('; genLocation: rcv; gen: ' > 0)'; gen: ' && ('; genLocation: arg; genl: ' > 0)) {'; gen: ' '; gen: ' '; genLocation: loc; gen: '= (oop)((long)'; genLocation: rcv; gen: ' | (long)'; genLocation: arg; genl: ');'; gen: ' '; gen: '} else '; genLocation: loc; gen: '= _send('; genSelector: 'bitOr:'; gen: ', '; genLocation: rcv; gen: ', '; genLocation: arg; genl: ');'. ] CManagedCodeGenerator tagged: rcv xor: arg location: loc checking: tagCheck [ self gen: ' '; gen: 'if ('; checkTags: tagCheck with: rcv with: arg; gen: ' && ('; genLocation: rcv; gen: ' > 0)'; gen: ' && ('; genLocation: arg; genl: ' > 0)) {'; gen: ' '; gen: ' '; genLocation: loc; gen: '= (oop)(((long)'; genLocation: rcv; gen: ' ^ (long)'; genLocation: arg; genl: ') | 1);'; gen: ' '; gen: '} else '; genLocation: loc; gen: '= _send('; genSelector: 'bitXor:'; gen: ', '; genLocation: rcv; gen: ', '; genLocation: arg; genl: ');'. ] CManagedCodeGenerator tagged: rcv shift: arg location: loc checking: tagCheck [ self gen: ' { int _l= (long)'; genLocation: rcv; gen: ' >> 1, '; gen: ' _r= (long)'; genLocation: arg; gen: ' >> 1, '; genl: ' _s= ((_r < 0) ? (_l >> -_r) : (_l << _r));'; gen: ' if ('; checkTags: tagCheck with: rcv with: arg; gen: ' && ( ( (_r >= 0) && (_r <= 31) '; gen: ' && (_l == (_s >> _r))'; gen: ' && ((_s ^ (_s << 1)) >= 0) )'; gen: ' || ((_r < 0) && (_r >= -31)) )'; gen: ') '; genLocation: loc; gen: '= (oop)(long)(_s << 1 | 1);'; gen: ' else '; genLocation: loc; gen: '= '; gen: '_send('; genSelector: 'bitShift:'; gen: ', '; genLocation: rcv; gen: ', '; genLocation: arg; genl: ');'; genl: ' }' ] CManagedCodeGenerator tagged: rcv left: arg location: loc checking: tagCheck [ self genl: '{'; gen: ' int _l= (long)'; genLocation: rcv; gen: ' >> 1,'; gen: ' _r= (long)'; genLocation: arg; gen: ' >> 1,'; genl: ' _s= (_l << _r);'; gen: ' if ('; checkTags: tagCheck with: rcv with: arg; gen: ' && (_r >= 0) && (_r <= 31)'; gen: ' && (_l == (_s >> _r))'; gen: ' && ((_s ^ (_s << 1)) >= 0)'; gen: ') '; genLocation: loc; gen: '= (oop)(long)(_s << 1 | 1);'; gen: ' else '; genLocation: loc; gen: '= '; gen: '_send('; genSelector: '<<'; gen: ', '; genLocation: rcv; gen: ', '; genLocation: arg; genl: ');'; genl: ' }' ] CManagedCodeGenerator tagged: rcv right: arg location: loc checking: tagCheck [ self genl: ' {'; gen: ' int _l= (long)'; genLocation: rcv; gen: ' >> 1,'; gen: ' _r= (long)'; genLocation: arg; gen: ' >> 1,'; genl: ' _s= (_l >> _r);'; gen: ' if ('; checkTags: tagCheck with: rcv with: arg; gen: ' && (_r >= 0) && (_r <= 31)'; gen: ') '; genLocation: loc; gen: '= (oop)(long)(_s << 1 | 1);'; gen: ' else '; genLocation: loc; gen: '= '; gen: '_send('; genSelector: '>>'; gen: ', '; genLocation: rcv; gen: ', '; genLocation: arg; genl: ');'; genl: ' }' ] CManagedCodeGenerator tagged: rcv rel: operator selector: sel with: arg location: loc checking: tagCheck [ self gen: ' '; gen: 'if '; checkTags: tagCheck with: rcv with: arg; genl: ' {'; gen: ' '; gen: ' '; genLocation: loc; gen: '= (((long)'; genLocation: rcv; gen: ' '; gen: operator; gen: ' (long)'; genLocation: arg; gen: ') ? '; genVariable: 'true'; gen: ' : '; genVariable: 'false'; genl: ');'; gen: ' '; gen: '} else '; genLocation: loc; gen: '= _send('; genSelector: sel; gen: ', '; genLocation: rcv; gen: ', '; genLocation: arg; genl: ');'. ] CManagedCodeGenerator tagged: rcv lt: arg location: loc checking: tagCheck [ self tagged: rcv rel: '<' selector: '<' with: arg location: loc checking: tagCheck ] CManagedCodeGenerator tagged: rcv le: arg location: loc checking: tagCheck [ self tagged: rcv rel: '<=' selector: '<=' with: arg location: loc checking: tagCheck ] CManagedCodeGenerator tagged: rcv eq: arg location: loc checking: tagCheck [ self tagged: rcv rel: '==' selector: '=' with: arg location: loc checking: tagCheck ] CManagedCodeGenerator tagged: rcv ne: arg location: loc checking: tagCheck [ self tagged: rcv rel: '!=' selector: '~=' with: arg location: loc checking: tagCheck ] CManagedCodeGenerator tagged: rcv ge: arg location: loc checking: tagCheck [ self tagged: rcv rel: '>=' selector: '>=' with: arg location: loc checking: tagCheck ] CManagedCodeGenerator tagged: rcv gt: arg location: loc checking: tagCheck [ self tagged: rcv rel: '>' selector: '>' with: arg location: loc checking: tagCheck ]