1 #include <RT0.d>
2 
3 #include <stdarg.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <stdio.h>
7 
8 #include <__oo2c.c>
9 #include <__config.h>
10 
11 #if HAVE_BACKTRACE_SYMBOLS
12 #  include <execinfo.h>
13 #endif
14 #define MAX_BACKTRACE_LEVELS 20  /* max number of backtraced procedure calls */
15 
16 /* note: __config.h might set defines for gc.h, like GC_PTHREADS */
17 #if defined(HAVE_LIBGC) && defined(HAVE_GC_GC_H)
18 #  define USE_BOEHM_GC
19 #  include <gc/gc.h>
20 #else
21 #  define GC_MALLOC malloc
22 #  define GC_MALLOC_ATOMIC malloc
23 #  define GC_FREE free
24 #endif
25 
26 OOC_INT32 RT0__poisonHeap = -1;  /* default: disabled */
27 static RT0__Module* modules = NULL;
28 static int moduleCount = 0, sizeModules = 32;
29 
30 
31 #define ROUND_SIZE(s) ((s+7) & ~((size_t)7))
32 
33 #define PS(_str,_name,_form,_size) \
34   _str.baseTypes = NULL; _str.tbProcs = NULL; \
35   _str.module = &_mid; _str.name = (OOC_CHAR8*)_name; \
36   _str.size = _size; _str.len = -1; _str.form = _form; \
37   _str.typeArgs = NULL;
38 
39 
write_backtrace()40 static void write_backtrace () {
41 #if HAVE_BACKTRACE_SYMBOLS
42 #define BACKTRACE_OFFSET 1
43   void* farray[MAX_BACKTRACE_LEVELS+BACKTRACE_OFFSET];
44   int i, size;
45   char** names;
46 
47   size = backtrace(farray, MAX_BACKTRACE_LEVELS+BACKTRACE_OFFSET);
48   names = backtrace_symbols(farray, size);
49   for (i=0; i<size; i++) {
50     (void)fprintf(stderr, "%d: %s\n", i, names[i]);
51   }
52 #endif
53 }
54 
55 #define PREFIX "## "
56 #define EXIT_CODE 127
57 void NORETURN _runtime_error(const char* msg, RT0__Module mid, OOC_INT32 pos) NORETURN2;
_runtime_error(const char * msg,RT0__Module mid,OOC_INT32 pos)58 void _runtime_error(const char* msg, RT0__Module mid, OOC_INT32 pos) {
59   (void)fprintf(stderr, "\n" PREFIX "\n" PREFIX
60 		"Runtime error in module %s at pos " OOC_INT32_FORMAT
61 		"\n" PREFIX "%s\n" PREFIX "\n",
62 		mid->name, pos, msg);
63   write_backtrace();
64   exit(EXIT_CODE);
65 }
66 
67 static NORETURN void _out_of_memory(int size) NORETURN2;
_out_of_memory(int size)68 static void _out_of_memory(int size) {
69   (void)fprintf(stderr, "\n" PREFIX "\n" PREFIX
70 		"Out of memory, failed to allocate %i bytes\n" PREFIX "\n",
71 		size);
72   write_backtrace();
73   exit(EXIT_CODE);
74 }
75 
76 static NORETURN void _negative_length(OOC_LEN len) NORETURN2;
_negative_length(OOC_LEN len)77 static void _negative_length(OOC_LEN len) {
78   (void)fprintf(stderr, "\n" PREFIX "\n" PREFIX
79 		"NewObject: Negative array length %i\n" PREFIX "\n",
80 		len);
81   write_backtrace();
82   exit(EXIT_CODE);
83 }
84 
85 #ifdef USE_BOEHM_GC
HandleFinalize(GC_PTR ptr,GC_PTR client_data)86 void HandleFinalize(GC_PTR ptr, GC_PTR client_data) {
87   int prefix = ROUND_SIZE(sizeof(RT0__Struct));
88   RT0__Object obj = (RT0__Object) (ptr + prefix);
89 
90   DYN_TBCALL(RT0,ObjectDesc,Finalize,(RT0__Object)obj,(obj));
91 }
92 #endif
93 
RT0__NewObject(RT0__Struct td,...)94 OOC_PTR RT0__NewObject(RT0__Struct td, ...) {
95   void *var, *ptr;
96   OOC_INT8 form = td->form;
97   int flags = td->flags;
98 
99   if (form == RT0__strQualType) { /* get to base type of qualified type */
100     form = td->typeArgs[0]->form;
101   }
102 
103   if (form == RT0__strRecord) { /* record */
104     int allocate;
105     int prefix;
106     int size = td->size;
107 
108     if (size == 0) size++;
109     prefix = ROUND_SIZE(sizeof(RT0__Struct));
110 
111     allocate = prefix + size;
112     if (flags & (1<<RT0__flagAtomic)) {
113       ptr = GC_MALLOC_ATOMIC(allocate);
114     } else {
115       ptr = GC_MALLOC(allocate);
116     }
117     if (ptr == NULL) {
118       _out_of_memory(allocate);
119     } else if (RT0__poisonHeap >= 0) {
120       memset(ptr, RT0__poisonHeap, allocate);
121     }
122     var = (char*)ptr+prefix;
123     OOC_TYPE_TAG(var) = td;
124     if (flags & (1<<RT0__flagVTable)) {
125       ((void **) var)[0] = td->tbProcs;
126     }
127 #ifdef USE_BOEHM_GC
128     if (flags & (1<<RT0__flagFinalize)) {
129       GC_register_finalizer(ptr,
130         HandleFinalize, 0, (GC_finalization_proc *) 0, (GC_PTR *) 0);
131     }
132 #endif
133   } else if (form == RT0__strArray) { /* fixed size array */
134     int size = td->size;
135     if (size == 0) size++;
136     if (flags & (1<<RT0__flagAtomic)) {
137       var = GC_MALLOC_ATOMIC(size);
138     } else {
139       var = GC_MALLOC(size);
140     }
141     if (var == NULL) {
142       _out_of_memory(size);
143     } else if (RT0__poisonHeap >= 0) {
144       memset(var, RT0__poisonHeap, size);
145     }
146 
147   } else {			/* dynamic array */
148     int allocate;
149     va_list ap;
150     int i;
151     size_t size, prefix;
152     void* ptr;
153     OOC_LEN *dim;
154 
155     /* calculate size of the block in bytes */
156     size = td->size;
157     va_start(ap, td);
158     for (i=0; i != td->len; i++) {
159       OOC_LEN len = va_arg(ap, OOC_LEN);
160       if (len < 0) {
161 	_negative_length(len);
162       }
163       size *= len;
164     }
165     va_end(ap);
166     if (size == 0) size++;
167 
168     /* calculate length of type tag prefix; round to maximum required alignment
169        of any basic type */
170     prefix = ROUND_SIZE(td->len*sizeof(OOC_LEN));
171 
172     allocate = prefix + size;
173     if (flags & (1<<RT0__flagAtomic)) {
174       ptr = GC_MALLOC_ATOMIC(allocate);
175     } else {
176       ptr = GC_MALLOC(allocate);
177     }
178     if (ptr == NULL) {
179       _out_of_memory(allocate);
180     } else if (RT0__poisonHeap >= 0) {
181       memset(ptr, RT0__poisonHeap, allocate);
182     }
183     var = (char*)ptr+prefix;
184 
185     /* set length of dimensions */
186     dim = (OOC_LEN*)var;
187     va_start(ap, td);
188     for (i=0; i != td->len; i++) {
189       *(--dim) = va_arg(ap, OOC_LEN);
190     }
191     va_end(ap);
192   }
193 
194   return (OOC_PTR)var;
195 }
196 
RT0__TypeOf(OOC_PTR ptr)197 RT0__Struct RT0__TypeOf(OOC_PTR ptr) {
198   return OOC_TYPE_TAG(ptr);
199 }
200 
201 /* Note: Type arguments are always of pointer type, but the type descriptor
202          stored in the typeArgs array is of the underlying record type. */
203 #define RESOLVE_TYPE_VAR(t,r) \
204   if (t->form == RT0__strTypeVar) t = r->typeArgs[t->len + 1]
205 
SameType(RT0__Struct t1,RT0__Struct t2,RT0__Struct receiverTag)206 static OOC_BOOLEAN SameType(RT0__Struct t1, RT0__Struct t2,
207 			    RT0__Struct receiverTag) {
208   RESOLVE_TYPE_VAR(t1, receiverTag);
209   RESOLVE_TYPE_VAR(t2, receiverTag);
210 
211   if (t1 == t2) {
212     return OOC_TRUE;
213   } else if ((t1->form == RT0__strQualType) &&
214 	     (t2->form == RT0__strQualType) &&
215 	     (t1->typeArgs[0] == t2->typeArgs[0])) {
216     int i=1;
217     while ((t1->typeArgs[i] != NULL) &&
218 	   SameType(t1->typeArgs[i], t2->typeArgs[i], receiverTag)) {
219       i++;
220     }
221     return (t1->typeArgs[i] == NULL);
222   } else {
223     return OOC_FALSE;
224   }
225 }
226 
RT0__TypeTest(RT0__Struct tag,RT0__Struct td,RT0__Struct receiverTag)227 OOC_BOOLEAN RT0__TypeTest(RT0__Struct tag, RT0__Struct td,
228                           RT0__Struct receiverTag) {
229   RESOLVE_TYPE_VAR(td, receiverTag);
230   return (tag->len >= td->len) &&
231     SameType(tag->baseTypes[td->len], td, receiverTag);
232 }
233 
RT0__NewBlock(OOC_INT32 bytes)234 OOC_PTR RT0__NewBlock(OOC_INT32 bytes) {
235   void *ptr;
236 
237   ptr = GC_MALLOC_ATOMIC(bytes);
238   if (ptr == NULL) {
239     _out_of_memory(bytes);
240   } else if (RT0__poisonHeap >= 0) {
241     memset(ptr, RT0__poisonHeap, bytes);
242   }
243   return (OOC_PTR)ptr;
244 }
245 
RT0__FreeBlock(OOC_PTR ptr)246 void RT0__FreeBlock(OOC_PTR ptr) {
247   GC_FREE(ptr);			/* inverse to RT0__NewBlock */
248 }
249 
RT0__CollectGarbage()250 void RT0__CollectGarbage() {
251 #ifdef USE_BOEHM_GC
252   GC_gcollect();
253 #endif
254 }
255 
RT0__RegisterDisappearingLink(OOC_PTR * ptr)256 void RT0__RegisterDisappearingLink(OOC_PTR * ptr) {
257 #ifdef USE_BOEHM_GC
258 /* CHECKME: What if ptr is not in a heap object? */
259   GC_general_register_disappearing_link(ptr, GC_base(*ptr));
260 #endif
261 }
262 
RT0__UnregisterDisappearingLink(OOC_PTR * ptr)263 void RT0__UnregisterDisappearingLink(OOC_PTR * ptr) {
264 #ifdef USE_BOEHM_GC
265 /* CHECKME: What if ptr is not in a heap object? */
266   GC_unregister_disappearing_link(ptr);
267 #endif
268 }
269 
RT0__ErrorIndexOutOfRange(RT0__Module mid,OOC_CHARPOS pos,OOC_LEN index,OOC_LEN length)270 void RT0__ErrorIndexOutOfRange (RT0__Module mid, OOC_CHARPOS pos,
271 				OOC_LEN index, OOC_LEN length) {
272   char s[128];
273   (void)sprintf(s, "Array index out of range, " OOC_LEN_FORMAT
274 		" not in 0 <= x < " OOC_LEN_FORMAT, index, length);
275   _runtime_error(s, mid, pos);
276 }
277 
RT0__ErrorDerefOfNil(RT0__Module mid,OOC_CHARPOS pos)278 void RT0__ErrorDerefOfNil (RT0__Module mid, OOC_CHARPOS pos) {
279   _runtime_error("Dereference of NIL", mid, pos);
280 }
281 
RT0__ErrorFailedTypeGuard(RT0__Module mid,OOC_CHARPOS pos,RT0__Struct typeTag)282 void RT0__ErrorFailedTypeGuard (RT0__Module mid, OOC_CHARPOS pos,
283 				RT0__Struct typeTag) {
284   char s[1024];
285 
286   (void)sprintf(s, "Type guard failed, actual type is %s.%s",
287 		(const char*)typeTag->module->name,
288 		(const char*)typeTag->name);
289   _runtime_error(s, mid, pos);
290 }
291 
RT0__ErrorFailedCase(RT0__Module mid,OOC_CHARPOS pos,OOC_INT32 select)292 void RT0__ErrorFailedCase (RT0__Module mid, OOC_CHARPOS pos, OOC_INT32 select) {
293   char s[128];
294   (void)sprintf(s, "CASE error, `" OOC_INT32_FORMAT
295 		"' does not match any label", select);
296   _runtime_error(s, mid, pos);
297 }
298 
RT0__ErrorFailedWith(RT0__Module mid,OOC_CHARPOS pos,RT0__Struct typeTag)299 void RT0__ErrorFailedWith (RT0__Module mid, OOC_CHARPOS pos,
300 			   RT0__Struct typeTag) {
301   char s[1024];
302 
303   (void)sprintf(s, "No WITH guard matches, last type is %s.%s",
304 		(const char*)typeTag->module->name,
305 		(const char*)typeTag->name);
306   _runtime_error(s, mid, pos);
307 }
308 
RT0__ErrorFailedTypeAssert(RT0__Module mid,OOC_CHARPOS pos)309 void RT0__ErrorFailedTypeAssert (RT0__Module mid, OOC_CHARPOS pos) {
310   _runtime_error("Dynamic type differs from static type", mid, pos);
311 }
312 
RT0__ErrorFailedFunction(RT0__Module mid,OOC_CHARPOS pos)313 void RT0__ErrorFailedFunction (RT0__Module mid, OOC_CHARPOS pos) {
314   _runtime_error("Control reaches end of function procedure", mid, pos);
315 }
316 
RT0__ErrorAssertionFailed(RT0__Module mid,OOC_CHARPOS pos,OOC_INT32 code)317 void RT0__ErrorAssertionFailed (RT0__Module mid, OOC_CHARPOS pos,
318 				OOC_INT32 code) {
319   char s[128];
320   (void)sprintf(s, "Assertion failed, code " OOC_INT32_FORMAT, code);
321   _runtime_error(s, mid, pos);
322 }
323 
RT0__Halt(OOC_INT32 code)324 void RT0__Halt (OOC_INT32 code) {
325   exit(code);
326 }
327 
328 
329 
RT0__RegisterModule(RT0__Module mid)330 void RT0__RegisterModule(RT0__Module mid) {
331   if (moduleCount == sizeModules) {
332     RT0__Module* newModules;
333     int i;
334 
335     sizeModules = sizeModules*2;
336     newModules = RT0__NewBlock(sizeModules*sizeof(RT0__Module));
337     for (i=0; i != moduleCount; i++) {
338       newModules[i] = modules[i];
339     }
340     RT0__FreeBlock(modules);
341     modules = newModules;
342   }
343 
344   modules[moduleCount] = mid;
345   moduleCount++;
346 }
347 
RT0__UnregisterModule(RT0__Module mid)348 void RT0__UnregisterModule(RT0__Module mid) {
349   /* until we have dynamic unloading, there is no need to do anything
350      fancy here */
351 }
352 
RT0__ThisModule(const OOC_CHAR8 name__ref[],OOC_LEN name_0d)353 RT0__Module RT0__ThisModule(const OOC_CHAR8 name__ref[], OOC_LEN name_0d) {
354   int i=0;
355   while ((i != moduleCount) && strcmp((char*)name__ref,
356 				      (char*)modules[i]->name)) {
357     i++;
358   }
359   if (i == moduleCount) {
360     return NULL;
361   } else {
362     return modules[i];
363   }
364 }
365 
RT0__ThisType(RT0__Module mid,const OOC_CHAR8 name__ref[],OOC_LEN name_0d)366 RT0__Struct RT0__ThisType(RT0__Module mid, const OOC_CHAR8 name__ref[], OOC_LEN name_0d) {
367   RT0__Struct* td;
368 
369   td = mid->typeDescriptors;
370   while (*td) {
371     if (!strcmp((char*)name__ref, (char*)(*td)->name)) {
372       return *td;
373     } else {
374       td++;
375     }
376   }
377 
378   if (strchr((char*)name__ref, '(')) {
379     /* name of qualified type: search _all_ modules for a match */
380     int i=0;
381     while (i != moduleCount) {
382       td = modules[i]->typeDescriptors;
383       while (*td) {
384 	if (!strcmp((char*)name__ref, (char*)(*td)->name)) {
385 	  return *td;
386 	} else {
387 	  td++;
388 	}
389       }
390       i++;
391     }
392   }
393   return NULL;
394 }
395 
396 /* Objects of type RT0.Object are not registered for finalisation, so this
397  * procedure is never directly called by the GC. However, it may be called via
398  * a super-call. */
399 
RT0__ObjectDesc_Finalize(RT0__Object o)400 void RT0__ObjectDesc_Finalize(RT0__Object o) {
401 }
402 
403 
RT0__ScanCaseRanges(const struct RT0__CaseRange table[],OOC_INT32 value)404 void* RT0__ScanCaseRanges(const struct RT0__CaseRange table[],
405 			  OOC_INT32 value) {
406   int i=0;
407   while (1) {			/* simple and slow, but correct... */
408     if ((table[i].low <= value) && (value <= table[i].high)) {
409       return table[i].jmp;
410     } else {
411       i++;
412     }
413   }
414 }
415 
416 
OOC_RT0_init()417 void OOC_RT0_init() {
418 #ifdef USE_BOEHM_GC
419   GC_all_interior_pointers = 0;
420   GC_INIT();
421   /* tell GC to accept pointers with an offset of 8/16/24 as references to
422      a given object; this is necessary if the GC is running with the
423      ALL_INTERIOR_POINTERS option; the offsets cover records and open
424      arrays with up to 5 free dimensions on 32 bit architectures */
425   GC_REGISTER_DISPLACEMENT(8);
426   GC_REGISTER_DISPLACEMENT(16);
427   GC_REGISTER_DISPLACEMENT(24);
428 #endif
429 
430   modules = RT0__NewBlock(sizeModules*sizeof(RT0__Module));
431 
432   PS(RT0__boolean  , "BOOLEAN",  RT0__strBoolean  , sizeof(OOC_BOOLEAN));
433   PS(RT0__char     , "CHAR",     RT0__strChar     , sizeof(OOC_CHAR8));
434   PS(RT0__longchar , "LONGCHAR", RT0__strLongchar , sizeof(OOC_CHAR16));
435   PS(RT0__ucs4char , "UCS4CHAR", RT0__strUCS4Char , sizeof(OOC_CHAR32));
436   PS(RT0__shortint , "SHORTINT", RT0__strShortint , sizeof(OOC_INT8));
437   PS(RT0__integer  , "INTEGER",  RT0__strInteger  , sizeof(OOC_INT16));
438   PS(RT0__longint  , "LONGINT",  RT0__strLongint  , sizeof(OOC_INT32));
439   PS(RT0__real     , "REAL",     RT0__strReal     , sizeof(OOC_REAL32));
440   PS(RT0__longreal , "LONGREAL", RT0__strLongreal , sizeof(OOC_REAL64));
441   PS(RT0__set32    , "SET",      RT0__strSet32    , sizeof(OOC_UINT32));
442   PS(RT0__byte     , "BYTE",     RT0__strByte     , sizeof(OOC_BYTE));
443   PS(RT0__ptr      , "PTR",      RT0__strPtr      , sizeof(OOC_PTR));
444   PS(RT0__procedure, "$PROC",    RT0__strProcedure, sizeof(OOC_PTR));
445 }
446 
OOC_RT0_destroy()447 void OOC_RT0_destroy() {
448 }
449