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