DEADSOFTWARE

return Kernel.Call implementation for native 486
[cpc.git] / src / native / posix / 486 / System / Mod / Kernel.cp
1 MODULE Kernel;
3 IMPORT S := SYSTEM, stdlib := PosixCstdlib, stdio := PosixCstdio,
4 time := PosixCtime, wctype := PosixCwctype, sysmman := PosixCsys_mman,
5 dlfcn := PosixCdlfcn, types := PosixCtypes, fcntl := PosixCfcntl,
6 unistd := PosixCunistd, signal := PosixCsignal, setjmp := PosixCsetjmp;
8 (* init fpu? *)
9 (* add signal blocking to avoid race conditions in Try/Trap/TrapHandler *)
10 (* add BeepHook for Beep *)
12 CONST
13 nameLen* = 256;
15 littleEndian* = TRUE;
16 timeResolution* = 1000; (* ticks per second *)
18 processor* = 1; (* generic c *)
20 objType* = "ocf"; (* file types *)
21 symType* = "osf";
22 docType* = "odc";
24 (* loader constants *)
25 done* = 0;
26 fileNotFound* = 1;
27 syntaxError* = 2;
28 objNotFound* = 3;
29 illegalFPrint* = 4;
30 cyclicImport* = 5;
31 noMem* = 6;
32 commNotFound* = 7;
33 commSyntaxError* = 8;
34 moduleNotFound* = 9;
36 any = 1000000;
38 CX = 1;
39 SP = 4; (* register number of stack pointer *)
40 FP = 5; (* register number of frame pointer *)
41 ML = 3; (* register which holds the module list at program start *)
43 strictStackSweep = FALSE;
44 N = 128 DIV 16; (* free lists *)
46 (* kernel flags in module desc *)
47 init = 16; dyn = 17; dll = 24; iptrs = 30;
49 (* meta interface consts *)
50 mConst = 1; mTyp = 2; mVar = 3; mProc = 4; mField = 5;
52 TYPE
53 Name* = ARRAY nameLen OF CHAR;
54 Utf8Name* = ARRAY nameLen OF SHORTCHAR;
55 Command* = PROCEDURE;
57 Module* = POINTER TO RECORD [untagged]
58 next-: Module;
59 opts-: SET; (* 0..15: compiler opts, 16..31: kernel flags *)
60 refcnt-: INTEGER; (* <0: module invalidated *)
61 compTime-, loadTime-: ARRAY 6 OF SHORTINT;
62 ext-: INTEGER; (* currently not used *)
63 term-: Command; (* terminator *)
64 nofimps-, nofptrs-: INTEGER;
65 csize-, dsize-, rsize-: INTEGER;
66 code-, data-, refs-: INTEGER;
67 procBase-, varBase-: INTEGER; (* meta base addresses *)
68 names-: POINTER TO ARRAY [untagged] OF SHORTCHAR; (* names[0] = 0X *)
69 ptrs-: POINTER TO ARRAY [untagged] OF INTEGER;
70 imports-: POINTER TO ARRAY [untagged] OF Module;
71 export-: Directory; (* exported objects (name sorted) *)
72 name-: Utf8Name
73 END;
75 Type* = POINTER TO RECORD [untagged]
76 (* record: ptr to method n at offset - 4 * (n+1) *)
77 size-: INTEGER; (* record: size, array: #elem, dyn array: 0, proc: sigfp *)
78 mod-: Module;
79 id-: INTEGER; (* name idx * 256 + lev * 16 + attr * 4 + form *)
80 base-: ARRAY 16 OF Type; (* signature if form = ProcTyp *)
81 fields-: Directory; (* new fields (declaration order) *)
82 ptroffs-: ARRAY any OF INTEGER (* array of any length *)
83 END;
85 Object* = POINTER TO ObjDesc;
87 ObjDesc* = RECORD [untagged]
88 fprint-: INTEGER;
89 offs-: INTEGER; (* pvfprint for record types *)
90 id-: INTEGER; (* name idx * 256 + vis * 16 + mode *)
91 struct-: Type (* id of basic type or pointer to typedesc/signature *)
92 END;
94 Directory* = POINTER TO RECORD [untagged]
95 num-: INTEGER; (* number of entries *)
96 obj-: ARRAY any OF ObjDesc (* array of any length *)
97 END;
99 Signature* = POINTER TO RECORD [untagged]
100 retStruct-: Type; (* id of basic type or pointer to typedesc or 0 *)
101 num-: INTEGER; (* number of parameters *)
102 par-: ARRAY any OF RECORD [untagged] (* parameters *)
103 id-: INTEGER; (* name idx * 256 + kind *)
104 struct-: Type (* id of basic type or pointer to typedesc *)
105 END
106 END;
108 Handler* = PROCEDURE;
110 Reducer* = POINTER TO ABSTRACT RECORD
111 next: Reducer
112 END;
114 Identifier* = ABSTRACT RECORD
115 typ*: INTEGER;
116 obj-: ANYPTR
117 END;
119 TrapCleaner* = POINTER TO ABSTRACT RECORD
120 next: TrapCleaner
121 END;
123 TryHandler* = PROCEDURE (a, b, c: INTEGER);
125 (* meta extension suport *)
127 ItemExt* = POINTER TO ABSTRACT RECORD END;
129 ItemAttr* = RECORD
130 obj*, vis*, typ*, adr*: INTEGER;
131 mod*: Module;
132 desc*: Type;
133 ptr*: S.PTR;
134 ext*: ItemExt
135 END;
137 Hook* = POINTER TO ABSTRACT RECORD END;
139 LoaderHook* = POINTER TO ABSTRACT RECORD (Hook)
140 res*: INTEGER;
141 importing*, imported*, object*: ARRAY 256 OF CHAR
142 END;
144 Block = POINTER TO RECORD [untagged]
145 tag: Type;
146 last: INTEGER; (* arrays: last element *)
147 actual: INTEGER; (* arrays: used during mark phase *)
148 first: INTEGER (* arrays: first element *)
149 END;
151 FreeBlock = POINTER TO FreeDesc;
153 FreeDesc = RECORD [untagged]
154 tag: Type; (* f.tag = ADR(f.size) *)
155 size: INTEGER;
156 next: FreeBlock
157 END;
159 Cluster = POINTER TO RECORD [untagged]
160 size: INTEGER; (* total size *)
161 next: Cluster;
162 max: INTEGER (* exe: reserved size, dll: original address *)
163 (* start of first block *)
164 END;
166 FList = POINTER TO RECORD
167 next: FList;
168 blk: Block;
169 iptr, aiptr: BOOLEAN
170 END;
172 CList = POINTER TO RECORD
173 next: CList;
174 do: Command;
175 trapped: BOOLEAN
176 END;
179 PtrType = RECORD v: S.PTR END; (* used for array of pointer *)
180 Char8Type = RECORD v: SHORTCHAR END;
181 Char16Type = RECORD v: CHAR END;
182 Int8Type = RECORD v: BYTE END;
183 Int16Type = RECORD v: SHORTINT END;
184 Int32Type = RECORD v: INTEGER END;
185 Int64Type = RECORD v: LONGINT END;
186 BoolType = RECORD v: BOOLEAN END;
187 SetType = RECORD v: SET END;
188 Real32Type = RECORD v: SHORTREAL END;
189 Real64Type = RECORD v: REAL END;
190 ProcType = RECORD v: PROCEDURE END;
191 UPtrType = RECORD v: INTEGER END;
192 StrPtr = POINTER TO ARRAY [untagged] OF SHORTCHAR;
194 ArrStrPtr = POINTER TO ARRAY [untagged] OF StrPtr;
196 ADDRESS* = types.Pvoid;
198 VAR
199 baseStack: INTEGER;
200 root: Cluster;
201 modList-: Module;
202 trapCount-: INTEGER;
203 err-, pc-, sp-, fp-, stack-, val-: INTEGER;
205 isTry: BOOLEAN;
206 startEnv: setjmp.sigjmp_buf;
207 tryEnv: setjmp.jmp_buf;
209 argc-: INTEGER;
210 argv-: ArrStrPtr;
211 pagesize: unistd.long;
213 free: ARRAY N OF FreeBlock; (* free list *)
214 sentinelBlock: FreeDesc;
215 sentinel: FreeBlock;
216 candidates: ARRAY 1024 OF INTEGER;
217 nofcand: INTEGER;
218 allocated: INTEGER; (* bytes allocated on BlackBox heap *)
219 total: INTEGER; (* current total size of BlackBox heap *)
220 used: INTEGER; (* bytes allocated on system heap *)
221 finalizers: FList;
222 hotFinalizers: FList;
223 cleaners: CList;
224 reducers: Reducer;
225 trapStack: TrapCleaner;
226 actual: Module; (* valid during module initialization *)
228 trapViewer, trapChecker: Handler;
229 trapped, guarded, secondTrap: BOOLEAN;
230 interrupted: BOOLEAN;
231 static, inDll, terminating: BOOLEAN;
232 restart: Command;
234 loader: LoaderHook;
235 loadres: INTEGER;
237 wouldFinalize: BOOLEAN;
239 watcher*: PROCEDURE (event: INTEGER); (* for debugging *)
241 intTrap*: BOOLEAN;
243 PROCEDURE Erase (adr, words: INTEGER);
244 BEGIN
245 ASSERT(words >= 0, 20);
246 WHILE words > 0 DO
247 S.PUT(adr, 0);
248 INC(adr, 4);
249 DEC(words)
250 END
251 END Erase;
254 PROCEDURE (VAR id: Identifier) Identified* (): BOOLEAN, NEW, ABSTRACT;
255 PROCEDURE (r: Reducer) Reduce* (full: BOOLEAN), NEW, ABSTRACT;
256 PROCEDURE (c: TrapCleaner) Cleanup*, NEW, EMPTY;
258 (* meta extension suport *)
260 PROCEDURE (e: ItemExt) Lookup* (name: ARRAY OF CHAR; VAR i: ANYREC), NEW, ABSTRACT;
261 PROCEDURE (e: ItemExt) Index* (index: INTEGER; VAR elem: ANYREC), NEW, ABSTRACT;
262 PROCEDURE (e: ItemExt) Deref* (VAR ref: ANYREC), NEW, ABSTRACT;
264 PROCEDURE (e: ItemExt) Valid* (): BOOLEAN, NEW, ABSTRACT;
265 PROCEDURE (e: ItemExt) Size* (): INTEGER, NEW, ABSTRACT;
266 PROCEDURE (e: ItemExt) BaseTyp* (): INTEGER, NEW, ABSTRACT;
267 PROCEDURE (e: ItemExt) Len* (): INTEGER, NEW, ABSTRACT;
269 PROCEDURE (e: ItemExt) Call* (OUT ok: BOOLEAN), NEW, ABSTRACT;
270 PROCEDURE (e: ItemExt) BoolVal* (): BOOLEAN, NEW, ABSTRACT;
271 PROCEDURE (e: ItemExt) PutBoolVal* (x: BOOLEAN), NEW, ABSTRACT;
272 PROCEDURE (e: ItemExt) CharVal* (): CHAR, NEW, ABSTRACT;
273 PROCEDURE (e: ItemExt) PutCharVal* (x: CHAR), NEW, ABSTRACT;
274 PROCEDURE (e: ItemExt) IntVal* (): INTEGER, NEW, ABSTRACT;
275 PROCEDURE (e: ItemExt) PutIntVal* (x: INTEGER), NEW, ABSTRACT;
276 PROCEDURE (e: ItemExt) LongVal* (): LONGINT, NEW, ABSTRACT;
277 PROCEDURE (e: ItemExt) PutLongVal* (x: LONGINT), NEW, ABSTRACT;
278 PROCEDURE (e: ItemExt) RealVal* (): REAL, NEW, ABSTRACT;
279 PROCEDURE (e: ItemExt) PutRealVal* (x: REAL), NEW, ABSTRACT;
280 PROCEDURE (e: ItemExt) SetVal* (): SET, NEW, ABSTRACT;
281 PROCEDURE (e: ItemExt) PutSetVal* (x: SET), NEW, ABSTRACT;
282 PROCEDURE (e: ItemExt) PtrVal* (): ANYPTR, NEW, ABSTRACT;
283 PROCEDURE (e: ItemExt) PutPtrVal* (x: ANYPTR), NEW, ABSTRACT;
284 PROCEDURE (e: ItemExt) GetSStringVal* (OUT x: ARRAY OF SHORTCHAR;
285 OUT ok: BOOLEAN), NEW, ABSTRACT;
286 PROCEDURE (e: ItemExt) PutSStringVal* (IN x: ARRAY OF SHORTCHAR;
287 OUT ok: BOOLEAN), NEW, ABSTRACT;
288 PROCEDURE (e: ItemExt) GetStringVal* (OUT x: ARRAY OF CHAR; OUT ok: BOOLEAN), NEW, ABSTRACT;
289 PROCEDURE (e: ItemExt) PutStringVal* (IN x: ARRAY OF CHAR; OUT ok: BOOLEAN), NEW, ABSTRACT;
291 (* -------------------- miscellaneous tools -------------------- *)
293 PROCEDURE IsUpper* (ch: CHAR): BOOLEAN;
294 BEGIN
295 RETURN wctype.iswupper(ORD(ch)) # 0
296 END IsUpper;
298 PROCEDURE Upper* (ch: CHAR): CHAR;
299 BEGIN
300 RETURN CHR(wctype.towupper(ORD(ch)))
301 END Upper;
303 PROCEDURE IsLower* (ch: CHAR): BOOLEAN;
304 BEGIN
305 RETURN wctype.iswlower(ORD(ch)) # 0
306 END IsLower;
308 PROCEDURE Lower* (ch: CHAR): CHAR;
309 BEGIN
310 RETURN CHR(wctype.towlower(ORD(ch)))
311 END Lower;
313 PROCEDURE IsAlpha* (ch: CHAR): BOOLEAN;
314 BEGIN
315 RETURN wctype.iswalpha(ORD(ch)) # 0
316 END IsAlpha;
318 PROCEDURE Utf8ToString* (IN in: ARRAY OF SHORTCHAR; OUT out: ARRAY OF CHAR; OUT res: INTEGER);
319 VAR i, j, val, max: INTEGER; ch: SHORTCHAR;
321 PROCEDURE FormatError();
322 BEGIN out := in$; res := 2 (*format error*)
323 END FormatError;
325 BEGIN
326 ch := in[0]; i := 1; j := 0; max := LEN(out) - 1;
327 WHILE (ch # 0X) & (j < max) DO
328 IF ch < 80X THEN
329 out[j] := ch; INC(j)
330 ELSIF ch < 0E0X THEN
331 val := ORD(ch) - 192;
332 IF val < 0 THEN FormatError; RETURN END ;
333 ch := in[i]; INC(i); val := val * 64 + ORD(ch) - 128;
334 IF (ch < 80X) OR (ch >= 0E0X) THEN FormatError; RETURN END ;
335 out[j] := CHR(val); INC(j)
336 ELSIF ch < 0F0X THEN
337 val := ORD(ch) - 224;
338 ch := in[i]; INC(i); val := val * 64 + ORD(ch) - 128;
339 IF (ch < 80X) OR (ch >= 0E0X) THEN FormatError; RETURN END ;
340 ch := in[i]; INC(i); val := val * 64 + ORD(ch) - 128;
341 IF (ch < 80X) OR (ch >= 0E0X) THEN FormatError; RETURN END ;
342 out[j] := CHR(val); INC(j)
343 ELSE
344 FormatError; RETURN
345 END ;
346 ch := in[i]; INC(i)
347 END;
348 out[j] := 0X;
349 IF ch = 0X THEN res := 0 (*ok*) ELSE res := 1 (*truncated*) END
350 END Utf8ToString;
352 PROCEDURE StringToUtf8* (IN in: ARRAY OF CHAR; OUT out: ARRAY OF SHORTCHAR; OUT res: INTEGER);
353 VAR i, j, val, max: INTEGER;
354 BEGIN
355 i := 0; j := 0; max := LEN(out) - 3;
356 WHILE (in[i] # 0X) & (j < max) DO
357 val := ORD(in[i]); INC(i);
358 IF val < 128 THEN
359 out[j] := SHORT(CHR(val)); INC(j)
360 ELSIF val < 2048 THEN
361 out[j] := SHORT(CHR(val DIV 64 + 192)); INC(j);
362 out[j] := SHORT(CHR(val MOD 64 + 128)); INC(j)
363 ELSE
364 out[j] := SHORT(CHR(val DIV 4096 + 224)); INC(j);
365 out[j] := SHORT(CHR(val DIV 64 MOD 64 + 128)); INC(j);
366 out[j] := SHORT(CHR(val MOD 64 + 128)); INC(j)
367 END;
368 END;
369 out[j] := 0X;
370 IF in[i] = 0X THEN res := 0 (*ok*) ELSE res := 1 (*truncated*) END
371 END StringToUtf8;
373 PROCEDURE SplitName* (name: ARRAY OF CHAR; VAR head, tail: ARRAY OF CHAR);
374 (* portable *)
375 VAR i, j: INTEGER; ch, lch: CHAR;
376 BEGIN
377 i := 0; ch := name[0];
378 IF ch # 0X THEN
379 REPEAT
380 head[i] := ch; lch := ch; INC(i); ch := name[i]
381 UNTIL (ch = 0X) OR (ch = ".") OR IsUpper(ch) & ~IsUpper(lch);
382 IF ch = "." THEN i := 0; ch := name[0] END;
383 head[i] := 0X; j := 0;
384 WHILE ch # 0X DO tail[j] := ch; INC(i); INC(j); ch := name[i] END;
385 tail[j] := 0X;
386 IF tail = "" THEN tail := head$; head := "" END
387 ELSE head := ""; tail := ""
388 END
389 END SplitName;
391 PROCEDURE MakeFileName* (VAR name: ARRAY OF CHAR; type: ARRAY OF CHAR);
392 VAR i, j: INTEGER; ext: ARRAY 8 OF CHAR; ch: CHAR;
393 BEGIN
394 i := 0;
395 WHILE (name[i] # 0X) & (name[i] # ".") DO INC(i) END;
396 IF name[i] = "." THEN
397 IF name[i + 1] = 0X THEN name[i] := 0X END
398 ELSE
399 IF type = "" THEN ext := docType ELSE ext := type$ END;
400 IF i < LEN(name) - LEN(ext$) - 1 THEN
401 name[i] := "."; INC(i); j := 0; ch := ext[0];
402 WHILE ch # 0X DO
403 name[i] := Lower(ch); INC(i); INC(j); ch := ext[j]
404 END;
405 name[i] := 0X
406 END
407 END
408 END MakeFileName;
410 PROCEDURE Time* (): LONGINT;
411 VAR res: time.int; tp: time.struct_timespec;
412 BEGIN
413 ASSERT(timeResolution >= 1);
414 ASSERT(timeResolution <= 1000000000);
415 res := time.clock_gettime(time.CLOCK_MONOTONIC, tp);
416 ASSERT(res = 0, 100);
417 RETURN tp.tv_sec * LONG(timeResolution) + tp.tv_nsec DIV LONG(1000000000 DIV timeResolution)
418 END Time;
420 PROCEDURE Beep*;
421 (* !!! *)
422 END Beep;
424 PROCEDURE SearchProcVar* (var: INTEGER; VAR m: Module; VAR adr: INTEGER);
425 BEGIN
426 adr := var; m := NIL;
427 IF var # 0 THEN
428 m := modList;
429 WHILE (m # NIL) & ((var < m.code) OR (var >= m.code + m.csize)) DO m := m.next END;
430 IF m # NIL THEN DEC(adr, m.code) END
431 END
432 END SearchProcVar;
434 (* -------------------- system memory management --------------------- *)
436 PROCEDURE AllocMem (size: sysmman.size_t; VAR max: sysmman.size_t): ADDRESS;
437 VAR fd, flags, res: fcntl.int; ptr: ADDRESS;
438 BEGIN
439 max := (size + pagesize - 1) DIV pagesize * pagesize;
440 fd := fcntl.open("/dev/zero", fcntl.O_RDWR, 0);
441 IF fd # -1 THEN
442 flags := sysmman.PROT_READ + sysmman.PROT_WRITE;
443 ptr := sysmman.mmap(0, max, flags, sysmman.MAP_PRIVATE, fd, 0);
444 IF ptr = sysmman.MAP_FAILED THEN ptr := 0 END;
445 res := unistd.close(fd);
446 ASSERT(res = 0, 100)
447 ELSE
448 ptr := 0
449 END;
450 RETURN ptr
451 END AllocMem;
453 PROCEDURE FreeMem (adr: ADDRESS; size: sysmman.size_t);
454 VAR res: types.int;
455 BEGIN
456 size := (size + pagesize - 1) DIV pagesize * pagesize;
457 res := sysmman.munmap(adr, size);
458 ASSERT(res = 0, 100)
459 END FreeMem;
461 PROCEDURE AllocHeapMem (size: INTEGER; VAR c: Cluster);
462 CONST N = 65536; (* cluster size for dll *)
463 VAR adr, allocated, newsize: INTEGER;
464 BEGIN
465 INC(size, 16);
466 ASSERT(size > 0, 100); adr := 0;
467 IF size < N THEN
468 adr := AllocMem(N, newsize);
469 allocated := newsize
470 END;
471 IF adr = 0 THEN
472 adr := AllocMem(size, newsize);
473 allocated := newsize
474 END;
475 IF adr = 0 THEN c := NIL
476 ELSE
477 c := S.VAL(Cluster, (adr + 15) DIV 16 * 16); c.max := adr;
478 c.size := allocated - (S.VAL(INTEGER, c) - adr);
479 INC(used, c.size); INC(total, c.size)
480 END;
481 ASSERT((adr = 0) OR (adr MOD 16 = 0) & (c.size >= size), 101);
482 (* post: (c = NIL) OR (c MOD 16 = 0) & (c.size >= size) *)
483 END AllocHeapMem;
485 PROCEDURE FreeHeapMem (c: Cluster);
486 BEGIN
487 DEC(used, c.size); DEC(total, c.size);
488 FreeMem(S.VAL(ADDRESS, c.max), c.size)
489 END FreeHeapMem;
491 PROCEDURE HeapFull (size: INTEGER): BOOLEAN;
492 BEGIN
493 RETURN TRUE
494 END HeapFull;
496 PROCEDURE AllocModMem* (descSize, modSize: INTEGER; VAR descAdr, modAdr: INTEGER);
497 BEGIN
498 descAdr := 0; modAdr := 0;
499 descAdr := AllocMem(descSize, descSize);
500 IF descAdr # 0 THEN
501 modAdr := AllocMem(modSize, modSize);
502 IF modAdr = 0 THEN
503 FreeMem(descAdr, descSize)
504 ELSE
505 INC(used, descSize + modSize)
506 END
507 END
508 END AllocModMem;
510 PROCEDURE DeallocModMem* (descSize, modSize, descAdr, modAdr: INTEGER);
511 BEGIN
512 FreeMem(descAdr, descSize);
513 FreeMem(modAdr, modSize);
514 DEC(used, descSize + modSize)
515 END DeallocModMem;
517 PROCEDURE InvalModMem (modSize, modAdr: INTEGER);
518 BEGIN
519 FreeMem(modAdr, modSize)
520 END InvalModMem;
522 PROCEDURE TryRead (from, to, c: INTEGER);
523 VAR i: INTEGER; x: BYTE;
524 BEGIN
525 IF from <= to THEN
526 FOR i := from TO to DO
527 S.GET(i, x)
528 END
529 ELSE
530 FOR i := to TO from BY -1 DO
531 S.GET(i, x)
532 END
533 END;
534 END TryRead;
536 PROCEDURE^ Try* (h: TryHandler; a, b, c: INTEGER);
538 PROCEDURE IsReadable* (from, to: INTEGER): BOOLEAN;
539 VAR i: INTEGER;
540 BEGIN
541 i := trapCount;
542 Try(TryRead, from, to, 0);
543 RETURN trapCount = i
544 END IsReadable;
546 (* --------------------- NEW implementation (portable) -------------------- *)
548 PROCEDURE^ NewBlock (size: INTEGER): Block;
550 PROCEDURE NewRec* (typ: INTEGER): INTEGER; (* implementation of NEW(ptr) *)
551 VAR size, adr: INTEGER; b: Block; tag: Type; l: FList;
552 BEGIN
553 IF ~ODD(typ) THEN
554 tag := S.VAL(Type, typ);
555 b := NewBlock(tag.size);
556 IF b # NIL THEN
557 b.tag := tag;
558 S.GET(typ - 4, size);
559 IF size # 0 THEN (* record uses a finalizer *)
560 l := S.VAL(FList, S.ADR(b.last)); (* anchor new object! *)
561 l := S.VAL(FList, NewRec(S.TYP(FList))); (* NEW(l) *)
562 l.blk := b; l.next := finalizers; finalizers := l
563 END;
564 adr := S.ADR(b.last)
565 ELSE
566 adr := 0
567 END
568 ELSE
569 HALT(100) (* COM interface pointers not supported *)
570 END;
571 RETURN adr
572 END NewRec;
574 PROCEDURE NewArr* (eltyp, nofelem, nofdim: INTEGER): INTEGER; (* impl. of NEW(ptr, dim0, dim1, ...) *)
575 VAR b: Block; size, headSize: INTEGER; t: Type;
576 BEGIN
577 CASE eltyp OF
578 | -1: HALT(100) (* COM interface pointers not supported *)
579 | 0: eltyp := S.ADR(PtrType)
580 | 1: eltyp := S.ADR(Char8Type)
581 | 2: eltyp := S.ADR(Int16Type)
582 | 3: eltyp := S.ADR(Int8Type)
583 | 4: eltyp := S.ADR(Int32Type)
584 | 5: eltyp := S.ADR(BoolType)
585 | 6: eltyp := S.ADR(SetType)
586 | 7: eltyp := S.ADR(Real32Type)
587 | 8: eltyp := S.ADR(Real64Type)
588 | 9: eltyp := S.ADR(Char16Type)
589 | 10: eltyp := S.ADR(Int64Type)
590 | 11: eltyp := S.ADR(ProcType)
591 | 12: HALT(101) (* COM interface pointers not supported *)
592 ELSE
593 ASSERT(~ODD(eltyp), 102) (* COM interface pointers not supported *)
594 END;
595 t := S.VAL(Type, eltyp);
596 headSize := 4 * nofdim + 12;
597 size := headSize + nofelem * t.size;
598 b := NewBlock(size);
599 IF b # NIL THEN
600 b.tag := S.VAL(Type, eltyp + 2); (* tag + array mark *)
601 b.last := S.ADR(b.last) + size - t.size; (* pointer to last elem *)
602 b.first := S.ADR(b.last) + headSize; (* pointer to first elem *)
603 RETURN S.ADR(b.last)
604 ELSE
605 RETURN 0
606 END;
607 END NewArr;
609 (* -------------------- handler installation (portable) --------------------- *)
611 PROCEDURE ThisFinObj* (VAR id: Identifier): ANYPTR;
612 VAR l: FList;
613 BEGIN
614 ASSERT(id.typ # 0, 100);
615 l := finalizers;
616 WHILE l # NIL DO
617 IF S.VAL(INTEGER, l.blk.tag) = id.typ THEN
618 id.obj := S.VAL(ANYPTR, S.ADR(l.blk.last));
619 IF id.Identified() THEN RETURN id.obj END
620 END;
621 l := l.next
622 END;
623 RETURN NIL
624 END ThisFinObj;
626 PROCEDURE InstallReducer* (r: Reducer);
627 BEGIN
628 r.next := reducers; reducers := r
629 END InstallReducer;
631 PROCEDURE InstallTrapViewer* (h: Handler);
632 BEGIN
633 trapViewer := h
634 END InstallTrapViewer;
636 PROCEDURE InstallTrapChecker* (h: Handler);
637 BEGIN
638 trapChecker := h
639 END InstallTrapChecker;
641 PROCEDURE PushTrapCleaner* (c: TrapCleaner);
642 VAR t: TrapCleaner;
643 BEGIN
644 t := trapStack; WHILE (t # NIL) & (t # c) DO t := t.next END;
645 ASSERT(t = NIL, 20);
646 c.next := trapStack; trapStack := c
647 END PushTrapCleaner;
649 PROCEDURE PopTrapCleaner* (c: TrapCleaner);
650 VAR t: TrapCleaner;
651 BEGIN
652 t := NIL;
653 WHILE (trapStack # NIL) & (t # c) DO
654 t := trapStack; trapStack := trapStack.next
655 END
656 END PopTrapCleaner;
658 PROCEDURE InstallCleaner* (p: Command);
659 VAR c: CList;
660 BEGIN
661 c := S.VAL(CList, NewRec(S.TYP(CList))); (* NEW(c) *)
662 c.do := p; c.trapped := FALSE; c.next := cleaners; cleaners := c
663 END InstallCleaner;
665 PROCEDURE RemoveCleaner* (p: Command);
666 VAR c0, c: CList;
667 BEGIN
668 c := cleaners; c0 := NIL;
669 WHILE (c # NIL) & (c.do # p) DO c0 := c; c := c.next END;
670 IF c # NIL THEN
671 IF c0 = NIL THEN cleaners := cleaners.next ELSE c0.next := c.next END
672 END
673 END RemoveCleaner;
675 PROCEDURE Cleanup*;
676 VAR c, c0: CList;
677 BEGIN
678 c := cleaners; c0 := NIL;
679 WHILE c # NIL DO
680 IF ~c.trapped THEN
681 c.trapped := TRUE; c.do; c.trapped := FALSE; c0 := c
682 ELSE
683 IF c0 = NIL THEN cleaners := cleaners.next
684 ELSE c0.next := c.next
685 END
686 END;
687 c := c.next
688 END
689 END Cleanup;
691 (* -------------------- meta information (portable) --------------------- *)
693 PROCEDURE (h: LoaderHook) ThisMod* (IN name: ARRAY OF CHAR): Module, NEW, ABSTRACT;
695 PROCEDURE SetLoaderHook*(h: LoaderHook);
696 BEGIN
697 loader := h
698 END SetLoaderHook;
700 PROCEDURE InitModule (mod: Module); (* initialize linked modules *)
701 VAR body: Command;
702 BEGIN
703 IF ~(dyn IN mod.opts) & (mod.next # NIL) & ~(init IN mod.next.opts) THEN InitModule(mod.next) END;
704 IF ~(init IN mod.opts) THEN
705 body := S.VAL(Command, mod.code);
706 INCL(mod.opts, init);
707 actual := mod;
708 body(); actual := NIL
709 END
710 END InitModule;
712 PROCEDURE ThisLoadedMod* (IN name: ARRAY OF CHAR): Module; (* loaded modules only *)
713 VAR m: Module; res: INTEGER; n: Utf8Name;
714 BEGIN
715 StringToUtf8(name, n, res); ASSERT(res = 0);
716 loadres := done;
717 m := modList;
718 WHILE (m # NIL) & ((m.name # n) OR (m.refcnt < 0)) DO m := m.next END;
719 IF (m # NIL) & ~(init IN m.opts) THEN InitModule(m) END;
720 IF m = NIL THEN loadres := moduleNotFound END;
721 RETURN m
722 END ThisLoadedMod;
724 PROCEDURE ThisMod* (IN name: ARRAY OF CHAR): Module;
725 BEGIN
726 IF loader # NIL THEN
727 loader.res := done;
728 RETURN loader.ThisMod(name)
729 ELSE
730 RETURN ThisLoadedMod(name)
731 END
732 END ThisMod;
734 PROCEDURE LoadMod* (IN name: ARRAY OF CHAR);
735 VAR m: Module;
736 BEGIN
737 m := ThisMod(name)
738 END LoadMod;
740 PROCEDURE GetLoaderResult* (OUT res: INTEGER; OUT importing, imported, object: ARRAY OF CHAR);
741 BEGIN
742 IF loader # NIL THEN
743 res := loader.res;
744 importing := loader.importing$;
745 imported := loader.imported$;
746 object := loader.object$
747 ELSE
748 res := loadres;
749 importing := "";
750 imported := "";
751 object := ""
752 END
753 END GetLoaderResult;
755 PROCEDURE ThisObject* (mod: Module; IN name: ARRAY OF CHAR): Object;
756 VAR l, r, m, res: INTEGER; p: StrPtr; n: Utf8Name;
757 BEGIN
758 StringToUtf8(name, n, res); ASSERT(res = 0);
759 l := 0; r := mod.export.num;
760 WHILE l < r DO (* binary search *)
761 m := (l + r) DIV 2;
762 p := S.VAL(StrPtr, S.ADR(mod.names[mod.export.obj[m].id DIV 256]));
763 IF p^ = n THEN RETURN S.VAL(Object, S.ADR(mod.export.obj[m])) END;
764 IF p^ < n THEN l := m + 1 ELSE r := m END
765 END;
766 RETURN NIL
767 END ThisObject;
769 PROCEDURE ThisDesc* (mod: Module; fprint: INTEGER): Object;
770 VAR i, n: INTEGER;
771 BEGIN
772 i := 0; n := mod.export.num;
773 WHILE (i < n) & (mod.export.obj[i].id DIV 256 = 0) DO
774 IF mod.export.obj[i].offs = fprint THEN RETURN S.VAL(Object, S.ADR(mod.export.obj[i])) END;
775 INC(i)
776 END;
777 RETURN NIL
778 END ThisDesc;
780 PROCEDURE ThisField* (rec: Type; IN name: ARRAY OF CHAR): Object;
781 VAR n, res: INTEGER; p: StrPtr; obj: Object; m: Module; nn: Utf8Name;
782 BEGIN
783 StringToUtf8(name, nn, res); ASSERT(res = 0);
784 m := rec.mod;
785 obj := S.VAL(Object, S.ADR(rec.fields.obj[0])); n := rec.fields.num;
786 WHILE n > 0 DO
787 p := S.VAL(StrPtr, S.ADR(m.names[obj.id DIV 256]));
788 IF p^ = nn THEN RETURN obj END;
789 DEC(n); INC(S.VAL(INTEGER, obj), 16)
790 END;
791 RETURN NIL
792 END ThisField;
794 PROCEDURE ThisCommand* (mod: Module; IN name: ARRAY OF CHAR): Command;
795 VAR x: Object; sig: Signature;
796 BEGIN
797 x := ThisObject(mod, name);
798 IF (x # NIL) & (x.id MOD 16 = mProc) THEN
799 sig := S.VAL(Signature, x.struct);
800 IF (sig.retStruct = NIL) & (sig.num = 0) THEN RETURN S.VAL(Command, mod.procBase + x.offs) END
801 END;
802 RETURN NIL
803 END ThisCommand;
805 PROCEDURE ThisType* (mod: Module; IN name: ARRAY OF CHAR): Type;
806 VAR x: Object;
807 BEGIN
808 x := ThisObject(mod, name);
809 IF (x # NIL) & (x.id MOD 16 = mTyp) & (S.VAL(INTEGER, x.struct) DIV 256 # 0) THEN
810 RETURN x.struct
811 ELSE
812 RETURN NIL
813 END
814 END ThisType;
816 PROCEDURE TypeOf* (IN rec: ANYREC): Type;
817 BEGIN
818 RETURN S.VAL(Type, S.TYP(rec))
819 END TypeOf;
821 PROCEDURE LevelOf* (t: Type): SHORTINT;
822 BEGIN
823 RETURN SHORT(t.id DIV 16 MOD 16)
824 END LevelOf;
826 PROCEDURE NewObj* (VAR o: S.PTR; t: Type);
827 VAR i: INTEGER;
828 BEGIN
829 IF t.size = -1 THEN o := NIL
830 ELSE
831 i := 0; WHILE t.ptroffs[i] >= 0 DO INC(i) END;
832 IF t.ptroffs[i+1] >= 0 THEN INC(S.VAL(INTEGER, t)) END; (* with interface pointers *)
833 o := S.VAL(S.PTR, NewRec(S.VAL(INTEGER, t))) (* generic NEW *)
834 END
835 END NewObj;
837 PROCEDURE GetModName* (mod: Module; OUT name: Name);
838 VAR res: INTEGER;
839 BEGIN
840 Utf8ToString(mod.name, name, res); ASSERT(res = 0)
841 END GetModName;
843 PROCEDURE GetObjName* (mod: Module; obj: Object; OUT name: Name);
844 VAR p: StrPtr; res: INTEGER;
845 BEGIN
846 p := S.VAL(StrPtr, S.ADR(mod.names[obj.id DIV 256]));
847 Utf8ToString(p^$, name, res); ASSERT(res = 0)
848 END GetObjName;
850 PROCEDURE GetTypeName* (t: Type; OUT name: Name);
851 VAR p: StrPtr; res: INTEGER;
852 BEGIN
853 p := S.VAL(StrPtr, S.ADR(t.mod.names[t.id DIV 256]));
854 Utf8ToString(p^$, name, res); ASSERT(res = 0)
855 END GetTypeName;
857 PROCEDURE RegisterMod* (mod: Module);
858 VAR i: INTEGER; epoch: time.time_t; tm: time.struct_tm; ptm: time.Pstruct_tm;
859 BEGIN
860 mod.next := modList; modList := mod; mod.refcnt := 0; INCL(mod.opts, dyn); i := 0;
861 WHILE i < mod.nofimps DO
862 IF mod.imports[i] # NIL THEN INC(mod.imports[i].refcnt) END;
863 INC(i)
864 END;
865 epoch := time.time(NIL);
866 ptm := time.localtime_r(epoch, tm);
867 IF ptm # NIL THEN
868 mod.loadTime[0] := SHORT(tm.tm_year + 1900);
869 mod.loadTime[1] := SHORT(tm.tm_mon + 1);
870 mod.loadTime[2] := SHORT(tm.tm_mday);
871 mod.loadTime[3] := SHORT(tm.tm_hour);
872 mod.loadTime[4] := SHORT(tm.tm_min);
873 mod.loadTime[5] := SHORT(tm.tm_sec)
874 ELSE
875 mod.loadTime[0] := 0;
876 mod.loadTime[1] := 0;
877 mod.loadTime[2] := 0;
878 mod.loadTime[3] := 0;
879 mod.loadTime[4] := 0;
880 mod.loadTime[5] := 0
881 END;
882 IF ~(init IN mod.opts) THEN InitModule(mod) END
883 END RegisterMod;
885 PROCEDURE^ Collect*;
887 PROCEDURE UnloadMod* (mod: Module);
888 VAR i: INTEGER; t: Command;
889 BEGIN
890 IF mod.refcnt = 0 THEN
891 t := mod.term; mod.term := NIL;
892 IF t # NIL THEN t() END; (* terminate module *)
893 i := 0;
894 WHILE i < mod.nofptrs DO (* release global pointers *)
895 S.PUT(mod.varBase + mod.ptrs[i], 0); INC(i)
896 END;
897 Collect; (* call finalizers *)
898 i := 0;
899 WHILE i < mod.nofimps DO (* release imported modules *)
900 IF mod.imports[i] # NIL THEN DEC(mod.imports[i].refcnt) END;
901 INC(i)
902 END;
903 mod.refcnt := -1;
904 IF dyn IN mod.opts THEN (* release memory *)
905 InvalModMem(mod.data + mod.dsize - mod.refs, mod.refs)
906 END
907 END
908 END UnloadMod;
910 (* -------------------- dynamic procedure call --------------------- *)
912 PROCEDURE [code] PUSH (p: INTEGER) 050H; (* push AX *)
913 PROCEDURE [code] CALL (a: INTEGER) 0FFH, 0D0H; (* call AX *)
914 PROCEDURE [code] RETI (): LONGINT;
915 PROCEDURE [code] RETR (): REAL;
917 (*
918 type par
919 32 bit scalar value
920 64 bit scalar low hi
921 var scalar address
922 record address tag
923 array address size
924 open array length_N-1 .. length_0
925 *)
927 PROCEDURE Call* (adr: INTEGER; sig: Signature; IN par: ARRAY OF INTEGER; n: INTEGER): LONGINT;
928 VAR p, kind, sp, size: INTEGER; typ: Type; r: REAL;
929 BEGIN
930 p := sig.num;
931 WHILE p > 0 DO (* push parameters from right to left *)
932 DEC(p);
933 typ := sig.par[p].struct;
934 kind := sig.par[p].id MOD 16;
935 IF (S.VAL(INTEGER, typ) DIV 256 = 0) OR (typ.id MOD 4 IN {0, 3}) THEN (* scalar, ANYREC *)
936 IF (kind = 10) & ((S.VAL(INTEGER, typ) = 8) OR (S.VAL(INTEGER, typ) = 10)) THEN (* 64 bit *)
937 DEC(n); PUSH(par[n]) (* push hi word *)
938 ELSIF S.VAL(INTEGER, typ) = 11 THEN (* ANYREC *)
939 ASSERT(kind # 10); (* not a value par, also checked by compiler *)
940 DEC(n); PUSH(par[n]) (* push tag *)
941 END;
942 DEC(n); PUSH(par[n]) (* push value/address *)
943 ELSIF typ.id MOD 4 = 1 THEN (* record *)
944 IF kind # 10 THEN (* var par *)
945 DEC(n); PUSH(par[n]); (* push tag *)
946 DEC(n); PUSH(par[n]) (* push address *)
947 ELSE
948 DEC(n, 2); (* skip tag *)
949 S.GETREG(SP, sp); sp := (sp - typ.size) DIV 4 * 4; S.PUTREG(SP, sp); (* allocate space *)
950 S.MOVE(par[n], sp, typ.size) (* copy to stack *)
951 END
952 ELSIF typ.size = 0 THEN (* open array *)
953 size := typ.id DIV 16 MOD 16; (* number of open dimensions *)
954 WHILE size > 0 DO
955 DEC(size); DEC(n); PUSH(par[n]) (* push length *)
956 END;
957 DEC(n); PUSH(par[n]) (* push address *)
958 ELSE (* fix array *)
959 IF kind # 10 THEN (* var par *)
960 DEC(n, 2); PUSH(par[n]) (* push address *)
961 ELSE
962 DEC(n); size := par[n]; DEC(n);
963 S.GETREG(SP, sp); sp := (sp - size) DIV 4 * 4; S.PUTREG(SP, sp); (* allocate space *)
964 S.MOVE(par[n], sp, size) (* copy to stack *)
965 END
966 END
967 END;
968 ASSERT(n = 0);
969 IF S.VAL(INTEGER, sig.retStruct) = 7 THEN (* shortreal *)
970 CALL(adr);
971 RETURN S.VAL(INTEGER, SHORT(RETR())) (* return value in fpu register *)
972 ELSIF S.VAL(INTEGER, sig.retStruct) = 8 THEN (* real *)
973 CALL(adr); r := RETR();
974 RETURN S.VAL(LONGINT, r) (* return value in fpu register *)
975 ELSE
976 CALL(adr);
977 RETURN RETI() (* return value in integer registers *)
978 END
979 END Call;
981 (* -------------------- reference information (portable) --------------------- *)
983 PROCEDURE RefCh (VAR ref: INTEGER; OUT ch: SHORTCHAR);
984 BEGIN
985 S.GET(ref, ch); INC(ref)
986 END RefCh;
988 PROCEDURE RefNum (VAR ref: INTEGER; OUT x: INTEGER);
989 VAR s, n: INTEGER; ch: SHORTCHAR;
990 BEGIN
991 s := 0; n := 0; RefCh(ref, ch);
992 WHILE ORD(ch) >= 128 DO INC(n, ASH(ORD(ch) - 128, s) ); INC(s, 7); RefCh(ref, ch) END;
993 x := n + ASH(ORD(ch) MOD 64 - ORD(ch) DIV 64 * 64, s)
994 END RefNum;
996 PROCEDURE RefName (VAR ref: INTEGER; OUT n: Utf8Name);
997 VAR i: INTEGER; ch: SHORTCHAR;
998 BEGIN
999 i := 0; RefCh(ref, ch);
1000 WHILE ch # 0X DO n[i] := ch; INC(i); RefCh(ref, ch) END;
1001 n[i] := 0X
1002 END RefName;
1004 PROCEDURE GetRefProc* (VAR ref: INTEGER; OUT adr: INTEGER; OUT name: Utf8Name);
1005 VAR ch: SHORTCHAR;
1006 BEGIN
1007 S.GET(ref, ch);
1008 WHILE ch >= 0FDX DO (* skip variables *)
1009 INC(ref); RefCh(ref, ch);
1010 IF ch = 10X THEN INC(ref, 4) END;
1011 RefNum(ref, adr); RefName(ref, name); S.GET(ref, ch)
1012 END;
1013 WHILE (ch > 0X) & (ch < 0FCX) DO (* skip source refs *)
1014 INC(ref); RefNum(ref, adr); S.GET(ref, ch)
1015 END;
1016 IF ch = 0FCX THEN INC(ref); RefNum(ref, adr); RefName(ref, name)
1017 ELSE adr := 0
1018 END
1019 END GetRefProc;
1021 PROCEDURE GetRefVar* (VAR ref: INTEGER; OUT mode, form: SHORTCHAR; OUT desc: Type; OUT adr: INTEGER; OUT name: Utf8Name);
1022 BEGIN
1023 S.GET(ref, mode); desc := NIL;
1024 IF mode >= 0FDX THEN
1025 mode := SHORT(CHR(ORD(mode) - 0FCH));
1026 INC(ref); RefCh(ref, form);
1027 IF form = 10X THEN
1028 S.GET(ref, desc); INC(ref, 4); form := SHORT(CHR(16 + desc.id MOD 4))
1029 END;
1030 RefNum(ref, adr); RefName(ref, name)
1031 ELSE
1032 mode := 0X; form := 0X; adr := 0
1033 END
1034 END GetRefVar;
1036 PROCEDURE SourcePos* (mod: Module; codePos: INTEGER): INTEGER;
1037 VAR ref, pos, ad, d: INTEGER; ch: SHORTCHAR; name: Utf8Name;
1038 BEGIN
1039 IF mod # NIL THEN (* mf, 12.02.04 *)
1040 ref := mod.refs; pos := 0; ad := 0; S.GET(ref, ch);
1041 WHILE ch # 0X DO
1042 WHILE (ch > 0X) & (ch < 0FCX) DO (* srcref: {dAdr,dPos} *)
1043 INC(ad, ORD(ch)); INC(ref); RefNum(ref, d);
1044 IF ad > codePos THEN RETURN pos END;
1045 INC(pos, d); S.GET(ref, ch)
1046 END;
1047 IF ch = 0FCX THEN (* proc: 0FCX,Adr,Name *)
1048 INC(ref); RefNum(ref, d); RefName(ref, name); S.GET(ref, ch);
1049 IF (d > codePos) & (pos > 0) THEN RETURN pos END
1050 END;
1051 WHILE ch >= 0FDX DO (* skip variables: Mode, Form, adr, Name *)
1052 INC(ref); RefCh(ref, ch);
1053 IF ch = 10X THEN INC(ref, 4) END;
1054 RefNum(ref, d); RefName(ref, name); S.GET(ref, ch)
1055 END
1056 END;
1057 END;
1058 RETURN -1
1059 END SourcePos;
1061 PROCEDURE LoadDll* (IN name: ARRAY OF CHAR; VAR ok: BOOLEAN);
1062 VAR h: ADDRESS; file: Utf8Name; res: INTEGER;
1063 BEGIN
1064 StringToUtf8(name, file, res);
1065 IF res = 0 THEN
1066 h := dlfcn.dlopen(file, dlfcn.RTLD_LAZY + dlfcn.RTLD_GLOBAL);
1067 ok := h # 0
1068 ELSE
1069 ok := FALSE
1070 END
1071 END LoadDll;
1073 PROCEDURE ThisDllObj* (mode, fprint: INTEGER; IN dll, name: ARRAY OF CHAR): INTEGER;
1074 VAR h, p: ADDRESS; file, sym: Utf8Name; res: INTEGER; err: dlfcn.int;
1075 BEGIN
1076 StringToUtf8(dll, file, res);
1077 IF res = 0 THEN
1078 h := dlfcn.dlopen(file, dlfcn.RTLD_LAZY + dlfcn.RTLD_GLOBAL);
1079 IF h # 0 THEN
1080 StringToUtf8(name, sym, res);
1081 IF res = 0 THEN
1082 p := dlfcn.dlsym(h, sym)
1083 ELSE
1084 p := 0
1085 END;
1086 err := dlfcn.dlclose(h);
1087 ASSERT(err = 0, 100)
1088 ELSE
1089 p := 0
1090 END
1091 ELSE
1092 p := 0
1093 END;
1094 RETURN p
1095 END ThisDllObj;
1097 (* -------------------- garbage collector (portable) --------------------- *)
1099 PROCEDURE Mark (this: Block);
1100 VAR father, son: Block; tag: Type; flag, offset, actual: INTEGER;
1101 BEGIN
1102 IF ~ODD(S.VAL(INTEGER, this.tag)) THEN
1103 father := NIL;
1104 LOOP
1105 INC(S.VAL(INTEGER, this.tag));
1106 flag := S.VAL(INTEGER, this.tag) MOD 4;
1107 tag := S.VAL(Type, S.VAL(INTEGER, this.tag) - flag);
1108 IF flag >= 2 THEN actual := this.first; this.actual := actual
1109 ELSE actual := S.ADR(this.last)
1110 END;
1111 LOOP
1112 offset := tag.ptroffs[0];
1113 IF offset < 0 THEN
1114 INC(S.VAL(INTEGER, tag), offset + 4); (* restore tag *)
1115 IF (flag >= 2) & (actual < this.last) & (offset < -4) THEN (* next array element *)
1116 INC(actual, tag.size); this.actual := actual
1117 ELSE (* up *)
1118 this.tag := S.VAL(Type, S.VAL(INTEGER, tag) + flag);
1119 IF father = NIL THEN RETURN END;
1120 son := this; this := father;
1121 flag := S.VAL(INTEGER, this.tag) MOD 4;
1122 tag := S.VAL(Type, S.VAL(INTEGER, this.tag) - flag);
1123 offset := tag.ptroffs[0];
1124 IF flag >= 2 THEN actual := this.actual ELSE actual := S.ADR(this.last) END;
1125 S.GET(actual + offset, father); S.PUT(actual + offset, S.ADR(son.last));
1126 INC(S.VAL(INTEGER, tag), 4)
1127 END
1128 ELSE
1129 S.GET(actual + offset, son);
1130 IF son # NIL THEN
1131 DEC(S.VAL(INTEGER, son), 4);
1132 IF ~ODD(S.VAL(INTEGER, son.tag)) THEN (* down *)
1133 this.tag := S.VAL(Type, S.VAL(INTEGER, tag) + flag);
1134 S.PUT(actual + offset, father); father := this; this := son;
1135 EXIT
1136 END
1137 END;
1138 INC(S.VAL(INTEGER, tag), 4)
1139 END
1140 END
1141 END
1142 END
1143 END Mark;
1145 PROCEDURE MarkGlobals;
1146 VAR m: Module; i, p: INTEGER;
1147 BEGIN
1148 m := modList;
1149 WHILE m # NIL DO
1150 IF m.refcnt >= 0 THEN
1151 i := 0;
1152 WHILE i < m.nofptrs DO
1153 S.GET(m.varBase + m.ptrs[i], p); INC(i);
1154 IF p # 0 THEN Mark(S.VAL(Block, p - 4)) END
1155 END
1156 END;
1157 m := m.next
1158 END
1159 END MarkGlobals;
1161 PROCEDURE Next (b: Block): Block; (* next block in same cluster *)
1162 VAR size: INTEGER;
1163 BEGIN
1164 S.GET(S.VAL(INTEGER, b.tag) DIV 4 * 4, size);
1165 IF ODD(S.VAL(INTEGER, b.tag) DIV 2) THEN INC(size, b.last - S.ADR(b.last)) END;
1166 RETURN S.VAL(Block, S.VAL(INTEGER, b) + (size + 19) DIV 16 * 16)
1167 END Next;
1169 PROCEDURE CheckCandidates;
1170 (* pre: nofcand > 0 *)
1171 VAR i, j, h, p, end: INTEGER; c: Cluster; blk, next: Block;
1172 BEGIN
1173 (* sort candidates (shellsort) *)
1174 h := 1; REPEAT h := h*3 + 1 UNTIL h > nofcand;
1175 REPEAT h := h DIV 3; i := h;
1176 WHILE i < nofcand DO p := candidates[i]; j := i;
1177 WHILE (j >= h) & (candidates[j-h] > p) DO
1178 candidates[j] := candidates[j-h]; j := j-h
1179 END;
1180 candidates[j] := p; INC(i)
1181 END
1182 UNTIL h = 1;
1183 (* sweep *)
1184 c := root; i := 0;
1185 WHILE c # NIL DO
1186 blk := S.VAL(Block, S.VAL(INTEGER, c) + 12);
1187 end := S.VAL(INTEGER, blk) + (c.size - 12) DIV 16 * 16;
1188 WHILE candidates[i] < S.VAL(INTEGER, blk) DO
1189 INC(i);
1190 IF i = nofcand THEN RETURN END
1191 END;
1192 WHILE S.VAL(INTEGER, blk) < end DO
1193 next := Next(blk);
1194 IF candidates[i] < S.VAL(INTEGER, next) THEN
1195 IF (S.VAL(INTEGER, blk.tag) # S.ADR(blk.last)) (* not a free block *)
1196 & (~strictStackSweep OR (candidates[i] = S.ADR(blk.last))) THEN
1197 Mark(blk)
1198 END;
1199 REPEAT
1200 INC(i);
1201 IF i = nofcand THEN RETURN END
1202 UNTIL candidates[i] >= S.VAL(INTEGER, next)
1203 END;
1204 IF (S.VAL(INTEGER, blk.tag) MOD 4 = 0) & (S.VAL(INTEGER, blk.tag) # S.ADR(blk.last))
1205 & (blk.tag.base[0] = NIL) & (blk.actual > 0) THEN (* referenced interface record *)
1206 Mark(blk)
1207 END;
1208 blk := next
1209 END;
1210 c := c.next
1211 END
1212 END CheckCandidates;
1214 PROCEDURE MarkLocals;
1215 VAR sp, p, min, max: INTEGER; c: Cluster;
1216 BEGIN
1217 sp := S.ADR(sp); nofcand := 0; c := root;
1218 WHILE c.next # NIL DO c := c.next END;
1219 min := S.VAL(INTEGER, root); max := S.VAL(INTEGER, c) + c.size;
1220 WHILE sp < baseStack DO
1221 S.GET(sp, p);
1222 IF (p > min) & (p < max) & (~strictStackSweep OR (p MOD 16 = 0)) THEN
1223 candidates[nofcand] := p; INC(nofcand);
1224 IF nofcand = LEN(candidates) - 1 THEN CheckCandidates; nofcand := 0 END
1225 END;
1226 INC(sp, 4)
1227 END;
1228 candidates[nofcand] := max; INC(nofcand); (* ensure complete scan for interface mark*)
1229 IF nofcand > 0 THEN CheckCandidates END
1230 END MarkLocals;
1232 PROCEDURE MarkFinObj;
1233 VAR f: FList;
1234 BEGIN
1235 wouldFinalize := FALSE;
1236 f := finalizers;
1237 WHILE f # NIL DO
1238 IF ~ODD(S.VAL(INTEGER, f.blk.tag)) THEN wouldFinalize := TRUE END;
1239 Mark(f.blk);
1240 f := f.next
1241 END;
1242 f := hotFinalizers;
1243 WHILE f # NIL DO IF ~ODD(S.VAL(INTEGER, f.blk.tag)) THEN wouldFinalize := TRUE END;
1244 Mark(f.blk);
1245 f := f.next
1246 END
1247 END MarkFinObj;
1249 PROCEDURE CheckFinalizers;
1250 VAR f, g, h, k: FList;
1251 BEGIN
1252 f := finalizers; g := NIL;
1253 IF hotFinalizers = NIL THEN k := NIL
1254 ELSE
1255 k := hotFinalizers;
1256 WHILE k.next # NIL DO k := k.next END
1257 END;
1258 WHILE f # NIL DO
1259 h := f; f := f.next;
1260 IF ~ODD(S.VAL(INTEGER, h.blk.tag)) THEN
1261 IF g = NIL THEN finalizers := f ELSE g.next := f END;
1262 IF k = NIL THEN hotFinalizers := h ELSE k.next := h END;
1263 k := h; h.next := NIL
1264 ELSE g := h
1265 END
1266 END;
1267 h := hotFinalizers;
1268 WHILE h # NIL DO Mark(h.blk); h := h.next END
1269 END CheckFinalizers;
1271 PROCEDURE ExecFinalizer (a, b, c: INTEGER);
1272 VAR f: FList; fin: PROCEDURE(this: ANYPTR);
1273 BEGIN
1274 f := S.VAL(FList, a);
1275 S.GET(S.VAL(INTEGER, f.blk.tag) - 4, fin); (* method 0 *)
1276 IF (fin # NIL) & (f.blk.tag.mod.refcnt >= 0) THEN fin(S.VAL(ANYPTR, S.ADR(f.blk.last))) END;
1277 END ExecFinalizer;
1279 PROCEDURE^ Try* (h: TryHandler; a, b, c: INTEGER); (* COMPILER DEPENDENT *)
1281 PROCEDURE CallFinalizers;
1282 VAR f: FList;
1283 BEGIN
1284 WHILE hotFinalizers # NIL DO
1285 f := hotFinalizers; hotFinalizers := hotFinalizers.next;
1286 Try(ExecFinalizer, S.VAL(INTEGER, f), 0, 0)
1287 END;
1288 wouldFinalize := FALSE
1289 END CallFinalizers;
1291 PROCEDURE Insert (blk: FreeBlock; size: INTEGER); (* insert block in free list *)
1292 VAR i: INTEGER;
1293 BEGIN
1294 blk.size := size - 4; blk.tag := S.VAL(Type, S.ADR(blk.size));
1295 i := MIN(N - 1, (blk.size DIV 16));
1296 blk.next := free[i]; free[i] := blk
1297 END Insert;
1299 PROCEDURE Sweep (dealloc: BOOLEAN);
1300 VAR cluster, last, c: Cluster; blk, next: Block; fblk, b, t: FreeBlock; end, i: INTEGER;
1301 BEGIN
1302 cluster := root; last := NIL; allocated := 0;
1303 i := N;
1304 REPEAT DEC(i); free[i] := sentinel UNTIL i = 0;
1305 WHILE cluster # NIL DO
1306 blk := S.VAL(Block, S.VAL(INTEGER, cluster) + 12);
1307 end := S.VAL(INTEGER, blk) + (cluster.size - 12) DIV 16 * 16;
1308 fblk := NIL;
1309 WHILE S.VAL(INTEGER, blk) < end DO
1310 next := Next(blk);
1311 IF ODD(S.VAL(INTEGER, blk.tag)) THEN
1312 IF fblk # NIL THEN
1313 Insert(fblk, S.VAL(INTEGER, blk) - S.VAL(INTEGER, fblk));
1314 fblk := NIL
1315 END;
1316 DEC(S.VAL(INTEGER, blk.tag)); (* unmark *)
1317 INC(allocated, S.VAL(INTEGER, next) - S.VAL(INTEGER, blk))
1318 ELSIF fblk = NIL THEN
1319 fblk := S.VAL(FreeBlock, blk)
1320 END;
1321 blk := next
1322 END;
1323 IF dealloc & (S.VAL(INTEGER, fblk) = S.VAL(INTEGER, cluster) + 12) THEN (* deallocate cluster *)
1324 c := cluster; cluster := cluster.next;
1325 IF last = NIL THEN root := cluster ELSE last.next := cluster END;
1326 FreeHeapMem(c)
1327 ELSE
1328 IF fblk # NIL THEN Insert(fblk, end - S.VAL(INTEGER, fblk)) END;
1329 last := cluster; cluster := cluster.next
1330 END
1331 END;
1332 (* reverse free list *)
1333 i := N;
1334 REPEAT
1335 DEC(i);
1336 b := free[i]; fblk := sentinel;
1337 WHILE b # sentinel DO t := b; b := t.next; t.next := fblk; fblk := t END;
1338 free[i] := fblk
1339 UNTIL i = 0
1340 END Sweep;
1342 PROCEDURE Collect*;
1343 BEGIN
1344 IF root # NIL THEN
1345 CallFinalizers; (* trap cleanup *)
1346 MarkGlobals;
1347 MarkLocals;
1348 CheckFinalizers;
1349 Sweep(TRUE);
1350 CallFinalizers
1351 END
1352 END Collect;
1354 PROCEDURE FastCollect*;
1355 BEGIN
1356 IF root # NIL THEN
1357 MarkGlobals;
1358 MarkLocals;
1359 MarkFinObj;
1360 Sweep(FALSE)
1361 END
1362 END FastCollect;
1364 PROCEDURE WouldFinalize* (): BOOLEAN;
1365 BEGIN
1366 RETURN wouldFinalize
1367 END WouldFinalize;
1369 (* --------------------- memory allocation (portable) -------------------- *)
1371 PROCEDURE OldBlock (size: INTEGER): FreeBlock; (* size MOD 16 = 0 *)
1372 VAR b, l: FreeBlock; s, i: INTEGER;
1373 BEGIN
1374 s := size - 4;
1375 i := MIN(N - 1, s DIV 16);
1376 WHILE (i # N - 1) & (free[i] = sentinel) DO INC(i) END;
1377 b := free[i]; l := NIL;
1378 WHILE b.size < s DO l := b; b := b.next END;
1379 IF b # sentinel THEN
1380 IF l = NIL THEN free[i] := b.next ELSE l.next := b.next END
1381 ELSE b := NIL
1382 END;
1383 RETURN b
1384 END OldBlock;
1386 PROCEDURE LastBlock (limit: INTEGER): FreeBlock; (* size MOD 16 = 0 *)
1387 VAR b, l: FreeBlock; s, i: INTEGER;
1388 BEGIN
1389 s := limit - 4;
1390 i := 0;
1391 REPEAT
1392 b := free[i]; l := NIL;
1393 WHILE (b # sentinel) & (S.VAL(INTEGER, b) + b.size # s) DO l := b; b := b.next END;
1394 IF b # sentinel THEN
1395 IF l = NIL THEN free[i] := b.next ELSE l.next := b.next END
1396 ELSE b := NIL
1397 END;
1398 INC(i)
1399 UNTIL (b # NIL) OR (i = N);
1400 RETURN b
1401 END LastBlock;
1403 PROCEDURE NewBlock (size: INTEGER): Block;
1404 VAR tsize, a, s: INTEGER; b: FreeBlock; new, c: Cluster; r: Reducer;
1405 BEGIN
1406 ASSERT(size >= 0, 20);
1407 IF size > MAX(INTEGER) - 19 THEN RETURN NIL END;
1408 tsize := (size + 19) DIV 16 * 16;
1409 b := OldBlock(tsize); (* 1) search for free block *)
1410 IF b = NIL THEN
1411 FastCollect; b := OldBlock(tsize); (* 2) collect *)
1412 IF b = NIL THEN
1413 Collect; b := OldBlock(tsize); (* 2a) fully collect *)
1414 END;
1415 IF b = NIL THEN
1416 AllocHeapMem(tsize + 12, new); (* 3) allocate new cluster *)
1417 IF new # NIL THEN
1418 IF (root = NIL) OR (S.VAL(INTEGER, new) < S.VAL(INTEGER, root)) THEN
1419 new.next := root; root := new
1420 ELSE
1421 c := root;
1422 WHILE (c.next # NIL) & (S.VAL(INTEGER, new) > S.VAL(INTEGER, c.next)) DO c := c.next END;
1423 new.next := c.next; c.next := new
1424 END;
1425 b := S.VAL(FreeBlock, S.VAL(INTEGER, new) + 12);
1426 b.size := (new.size - 12) DIV 16 * 16 - 4
1427 ELSE
1428 RETURN NIL (* 4) give up *)
1429 END
1430 END
1431 END;
1432 (* b # NIL *)
1433 a := b.size + 4 - tsize;
1434 IF a > 0 THEN Insert(S.VAL(FreeBlock, S.VAL(INTEGER, b) + tsize), a) END;
1435 IF size > 0 THEN Erase(S.ADR(b.size), (size + 3) DIV 4) END;
1436 INC(allocated, tsize);
1437 RETURN S.VAL(Block, b)
1438 END NewBlock;
1440 PROCEDURE Allocated* (): INTEGER;
1441 BEGIN
1442 RETURN allocated
1443 END Allocated;
1445 PROCEDURE Used* (): INTEGER;
1446 BEGIN
1447 RETURN used
1448 END Used;
1450 PROCEDURE Root* (): INTEGER;
1451 BEGIN
1452 RETURN S.VAL(INTEGER, root)
1453 END Root;
1455 (* -------------------- Trap Handling --------------------- *)
1457 PROCEDURE Start* (code: Command);
1458 VAR res: setjmp.int;
1459 BEGIN
1460 restart := code;
1461 S.GETREG(SP, baseStack);
1462 res := setjmp.sigsetjmp(startEnv, 1);
1463 restart
1464 END Start;
1466 PROCEDURE Quit* (exitCode: INTEGER);
1467 VAR m: Module; term: Command; t: BOOLEAN;
1468 BEGIN
1469 trapViewer := NIL; trapChecker := NIL; restart := NIL;
1470 t := terminating; terminating := TRUE; m := modList;
1471 WHILE m # NIL DO (* call terminators *)
1472 IF ~static OR ~t THEN
1473 term := m.term; m.term := NIL;
1474 IF term # NIL THEN term() END
1475 END;
1476 m := m.next
1477 END;
1478 CallFinalizers;
1479 hotFinalizers := finalizers; finalizers := NIL;
1480 CallFinalizers;
1481 stdlib.exit(exitCode)
1482 END Quit;
1484 PROCEDURE FatalError* (id: INTEGER; str: ARRAY OF CHAR);
1485 VAR res: stdio.int; title: ARRAY 16 OF CHAR; text: ARRAY 256 OF SHORTCHAR;
1486 BEGIN
1487 title := "Error xy";
1488 title[6] := CHR(id DIV 10 + ORD("0"));
1489 title[7] := CHR(id MOD 10 + ORD("0"));
1490 res := unistd.write(2, S.ADR(title), 8);
1491 stdlib.abort
1492 END FatalError;
1494 PROCEDURE DefaultTrapViewer;
1495 VAR out: ARRAY 2048 OF SHORTCHAR; a, b, c, len, ref, end: INTEGER; mod: Module;
1496 modName, name: Name; n: Utf8Name; res: unistd.int;
1498 PROCEDURE WriteString (IN s: ARRAY OF SHORTCHAR);
1499 VAR i: INTEGER;
1500 BEGIN
1501 i := 0;
1502 WHILE (len < LEN(out) - 1) & (s[i] # 0X) DO out[len] := s[i]; INC(i); INC(len) END
1503 END WriteString;
1505 PROCEDURE WriteHex (x, n: INTEGER);
1506 VAR i, y: INTEGER;
1507 BEGIN
1508 IF len + n < LEN(out) THEN
1509 i := len + n - 1;
1510 WHILE i >= len DO
1511 y := x MOD 16; x := x DIV 16;
1512 IF y > 9 THEN y := y + (ORD("A") - ORD("0") - 10) END;
1513 out[i] := SHORT(CHR(y + ORD("0"))); DEC(i)
1514 END;
1515 INC(len, n)
1516 END
1517 END WriteHex;
1519 PROCEDURE WriteLn;
1520 BEGIN
1521 IF len < LEN(out) - 1 THEN out[len] := 0AX; INC(len) END
1522 END WriteLn;
1524 BEGIN
1525 len := 0;
1526 WriteString("====== ");
1527 IF err = 129 THEN WriteString("invalid with")
1528 ELSIF err = 130 THEN WriteString("invalid case")
1529 ELSIF err = 131 THEN WriteString("function without return")
1530 ELSIF err = 132 THEN WriteString("type guard")
1531 ELSIF err = 133 THEN WriteString("implied type guard")
1532 ELSIF err = 134 THEN WriteString("value out of range")
1533 ELSIF err = 135 THEN WriteString("index out of range")
1534 ELSIF err = 136 THEN WriteString("string too long")
1535 ELSIF err = 137 THEN WriteString("stack overflow")
1536 ELSIF err = 138 THEN WriteString("integer overflow")
1537 ELSIF err = 139 THEN WriteString("division by zero")
1538 ELSIF err = 140 THEN WriteString("infinite real result")
1539 ELSIF err = 141 THEN WriteString("real underflow")
1540 ELSIF err = 142 THEN WriteString("real overflow")
1541 ELSIF err = 143 THEN WriteString("undefined real result")
1542 ELSIF err = 144 THEN WriteString("not a number")
1543 ELSIF err = 200 THEN WriteString("keyboard interrupt")
1544 ELSIF err = 201 THEN WriteString("NIL dereference")
1545 ELSIF err = 202 THEN WriteString("illegal instruction: ");
1546 WriteHex(val, 4)
1547 ELSIF err = 203 THEN WriteString("illegal memory read [ad = ");
1548 WriteHex(val, 8); WriteString("]")
1549 ELSIF err = 204 THEN WriteString("illegal memory write [ad = ");
1550 WriteHex(val, 8); WriteString("]")
1551 ELSIF err = 205 THEN WriteString("illegal execution [ad = ");
1552 WriteHex(val, 8); WriteString("]")
1553 ELSIF err = 257 THEN WriteString("out of memory")
1554 ELSIF err = 10001H THEN WriteString("bus error")
1555 ELSIF err = 10002H THEN WriteString("address error")
1556 ELSIF err = 10007H THEN WriteString("fpu error")
1557 ELSIF err < 0 THEN WriteString("exception #"); WriteHex(-err, 2)
1558 ELSE err := err DIV 100 * 256 + err DIV 10 MOD 10 * 16 + err MOD 10;
1559 WriteString("trap #"); WriteHex(err, 3)
1560 END;
1561 WriteString(" ======");
1562 a := pc; b := fp; c := 12;
1563 REPEAT
1564 WriteLn; WriteString("- ");
1565 mod := modList;
1566 WHILE (mod # NIL) & ((a < mod.code) OR (a >= mod.code + mod.csize)) DO mod := mod.next END;
1567 IF mod # NIL THEN
1568 DEC(a, mod.code);
1569 IF mod.refcnt >= 0 THEN
1570 GetModName(mod, modName); WriteString(SHORT(modName)); ref := mod.refs;
1571 REPEAT GetRefProc(ref, end, n) UNTIL (end = 0) OR (a < end);
1572 IF a < end THEN
1573 Utf8ToString(n, name, res); WriteString("."); WriteString(SHORT(name))
1574 END
1575 ELSE
1576 GetModName(mod, modName); WriteString("("); WriteString(SHORT(modName)); WriteString(")")
1577 END;
1578 WriteString(" ")
1579 END;
1580 WriteString("(pc="); WriteHex(a, 8);
1581 WriteString(", fp="); WriteHex(b, 8); WriteString(")");
1582 IF (b >= sp) & (b < stack) THEN
1583 S.GET(b+4, a); (* stacked pc *)
1584 S.GET(b, b); (* dynamic link *)
1585 DEC(c)
1586 ELSE c := 0
1587 END
1588 UNTIL c = 0;
1589 out[len] := 0X;
1590 res := unistd.write(2, S.ADR(out), len)
1591 END DefaultTrapViewer;
1593 PROCEDURE TrapCleanup;
1594 VAR t: TrapCleaner;
1595 BEGIN
1596 WHILE trapStack # NIL DO
1597 t := trapStack; trapStack := trapStack.next; t.Cleanup
1598 END;
1599 IF (trapChecker # NIL) & (err # 128) THEN trapChecker END
1600 END TrapCleanup;
1602 PROCEDURE SetTrapGuard* (on: BOOLEAN);
1603 BEGIN
1604 guarded := on
1605 END SetTrapGuard;
1607 PROCEDURE Try* (h: TryHandler; a, b, c: INTEGER);
1608 VAR oldIsTry: BOOLEAN; oldTryEnv: setjmp.jmp_buf; res: setjmp.int;
1609 BEGIN
1610 oldIsTry := isTry; oldTryEnv := tryEnv;
1611 isTry := TRUE;
1612 res := setjmp._setjmp(tryEnv);
1613 IF res = 0 THEN h(a, b, c) END;
1614 isTry := oldIsTry; tryEnv := oldTryEnv
1615 END Try;
1617 PROCEDURE Trap* (n: INTEGER);
1618 BEGIN
1619 IF trapped THEN
1620 DefaultTrapViewer;
1621 IF ~secondTrap THEN trapped := FALSE; secondTrap := TRUE END
1622 END;
1623 IF n >= 0 THEN err := n
1624 ELSE err := -n + 128
1625 END;
1626 pc := 0; sp := 0; fp := 0; stack := 0; val := 0;
1627 INC(trapCount);
1628 (* !!! InitFPU *)
1629 TrapCleanup;
1630 IF isTry THEN
1631 setjmp._longjmp(tryEnv, 1)
1632 END;
1633 IF (err = 128) OR (err = 200) & ~intTrap THEN (* do nothing *)
1634 ELSIF (trapViewer # NIL) & (restart # NIL) & ~trapped & ~guarded THEN
1635 trapped := TRUE; trapViewer()
1636 ELSE DefaultTrapViewer
1637 END;
1638 trapped := FALSE; secondTrap := FALSE;
1639 IF restart # NIL THEN
1640 setjmp.siglongjmp(startEnv, 1)
1641 END;
1642 stdlib.abort
1643 END Trap;
1645 PROCEDURE [ccall] TrapHandler (signo: signal.int; IN info: signal.siginfo_t; context: ADDRESS);
1646 VAR res: signal.int;
1647 BEGIN
1648 IF trapped THEN
1649 DefaultTrapViewer;
1650 IF ~secondTrap THEN trapped := FALSE; secondTrap := TRUE END
1651 END;
1652 err := -signo; pc := 0; sp := 0; fp := 0; stack := baseStack; val := 0;
1653 CASE signo OF
1654 | signal.SIGFPE:
1655 val := info.si_code;
1656 pc := info.info.sigfpe.si_addr;
1657 CASE info.si_code OF
1658 | signal.FPE_INTDIV: err := 139 (* division by zero *)
1659 | signal.FPE_INTOVF: err := 138 (* integer overflow *)
1660 | signal.FPE_FLTDIV: err := 140 (* fpu: division by zero *)
1661 | signal.FPE_FLTOVF: err := 142 (* fpu: overflow *)
1662 | signal.FPE_FLTUND: err := 141 (* fpu: underflow *)
1663 (* !!! | signal.FPE_FLTRES: err := ??? (* fpu: *) *)
1664 | signal.FPE_FLTINV: err := 143 (* val := opcode *) (* fpu: invalid op *)
1665 (* !!! | signal.FPE_FLTSUB: err := ??? (* fpu: *) *)
1666 ELSE (* unknown *)
1667 END
1668 | signal.SIGINT:
1669 val := info.si_code;
1670 err := 200 (* keyboard interrupt *)
1671 | signal.SIGSEGV:
1672 val := info.info.sigsegv.si_addr;
1673 err := 203 (* illigal read *)
1674 | signal.SIGBUS:
1675 val := info.info.sigbus.si_addr;
1676 err := 10001H (* bus error *)
1677 | signal.SIGILL:
1678 pc := info.info.sigill.si_addr;
1679 err := 202; (* illigal instruction *)
1680 IF IsReadable(pc, pc + 4) THEN
1681 S.GET(pc, val)
1682 (* !!! err := halt code *)
1683 END;
1684 ELSE (* unknown *)
1685 END;
1686 INC(trapCount);
1687 (* !!! InitFPU *)
1688 TrapCleanup;
1689 IF isTry THEN
1690 setjmp._longjmp(tryEnv, 1)
1691 END;
1692 IF (err = 128) OR (err = 200) & ~intTrap THEN (* do nothing *)
1693 ELSIF (trapViewer # NIL) & (restart # NIL) & ~trapped & ~guarded THEN
1694 trapped := TRUE; trapViewer()
1695 ELSE DefaultTrapViewer
1696 END;
1697 trapped := FALSE; secondTrap := FALSE;
1698 IF restart # NIL THEN
1699 setjmp.siglongjmp(startEnv, 1)
1700 END;
1701 stdlib.abort
1702 END TrapHandler;
1704 (* -------------------- Initialization --------------------- *)
1706 PROCEDURE InstallTrap (signo: signal.int);
1707 VAR act: signal.struct_sigaction; res: signal.int;
1708 BEGIN
1709 act.handler.sa_handler := NIL;
1710 res := signal.sigemptyset(act.sa_mask);
1711 act.sa_flags := signal.SA_NODEFER + signal.SA_SIGINFO;
1712 act.handler.sa_sigaction := TrapHandler;
1713 res := signal.sigaction(signo, act, NIL);
1714 END InstallTrap;
1716 PROCEDURE InstallTrapVectors;
1717 BEGIN
1718 InstallTrap(signal.SIGFPE);
1719 InstallTrap(signal.SIGINT);
1720 InstallTrap(signal.SIGSEGV);
1721 InstallTrap(signal.SIGBUS);
1722 InstallTrap(signal.SIGILL)
1723 END InstallTrapVectors;
1725 PROCEDURE RemoveTrapVectors;
1726 END RemoveTrapVectors;
1728 PROCEDURE Init;
1729 VAR i: INTEGER;
1730 BEGIN
1731 intTrap := TRUE;
1732 pagesize := unistd.sysconf(unistd._SC_PAGESIZE);
1734 (* init heap *)
1735 allocated := 0; total := 0; used := 0;
1736 sentinelBlock.size := MAX(INTEGER);
1737 sentinel := S.ADR(sentinelBlock);
1738 i := N;
1739 REPEAT DEC(i); free[i] := sentinel UNTIL i = 0;
1741 IF ~inDll THEN
1742 InstallTrapVectors
1743 END;
1745 (* !!! InitFPU *)
1746 IF ~static THEN
1747 InitModule(modList);
1748 IF ~inDll THEN Quit(1) END
1749 END
1750 END Init;
1752 BEGIN
1753 IF modList = NIL THEN (* only once *)
1754 S.GETREG(SP, baseStack);
1755 S.GET(baseStack + 16, argc);
1756 argv := S.VAL(ArrStrPtr, baseStack + 20);
1757 S.GETREG(ML, modList); (* linker loads module list to BX *)
1758 static := init IN modList.opts;
1759 inDll := dll IN modList.opts;
1760 Init
1761 END
1762 CLOSE
1763 IF ~terminating THEN
1764 terminating := TRUE;
1765 Quit(0)
1766 END
1767 END Kernel.