Coop.Modules.Mod 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. MODULE Modules; (** AUTHOR "pjm"; PURPOSE "Modules and types"; *)
  2. IMPORT SYSTEM, Trace, Machine, Heaps, Environment, Activities, Processors, Queues;
  3. CONST
  4. Ok* = 0;
  5. AddressSize = SIZEOF (ADDRESS); (* architecture dependent size of addresses in bytes *)
  6. MaxTags* = 16; (* in type descriptor *)
  7. (** type descriptor field offsets relative to root (middle) *)
  8. Tag0Ofs* = -AddressSize * 2; (** first tag *)
  9. Mth0Ofs* = Tag0Ofs - AddressSize*MaxTags; (** first method *)
  10. Ptr0Ofs* = AddressSize; (** first pointer offset *)
  11. MaxObjFormats = 5; (* maximum number of object file formats installed *)
  12. (** flags in TypeDesc, RoundUp(log2(MaxTags)) low bits reserved for extLevel *)
  13. ProtTypeBit* = Heaps.ProtTypeBit;
  14. None* = 0; PowerDown* = 1; Reboot* = 2;
  15. ClearCode = TRUE;
  16. DefaultContext* = "A2";
  17. NoLoader=3400;
  18. TraceBoot=TRUE;
  19. TYPE
  20. (* definitions for object-model loader support *)
  21. Name* = ARRAY 32 OF CHAR;
  22. (* the correponding name array is protected from being GCed via module's internal pointer arrray
  23. compiler generated!
  24. *)
  25. DynamicName* = POINTER {UNSAFE} TO ARRAY 256 OF CHAR;
  26. Command* = RECORD
  27. (* Fields exported for initialization by loader/linker only! Consider read-only! *)
  28. name*: Name; (* name of the procedure *)
  29. argTdAdr*, retTdAdr* : ADDRESS; (* address of type descriptors of argument and return type, 0 if no type *)
  30. entryAdr* : ADDRESS; (* entry address of procedure *)
  31. END;
  32. ExportDesc* = RECORD
  33. fp*: ADDRESS;
  34. name* {UNTRACED}: DynamicName;
  35. adr*: ADDRESS;
  36. exports*: LONGINT; (* number of exports referenced by ExportArray *)
  37. dsc* {UNTRACED}: ExportArray; (* pointer to memory containing a raw array with "exports" entries *)
  38. END;
  39. ExportArray* = POINTER {UNSAFE} TO ARRAY OF ExportDesc;
  40. Bytes* = POINTER TO ARRAY OF CHAR;
  41. TerminationHandler* = PROCEDURE;
  42. (* all implicit or explicit pointers in the subsequent data structures are protected with one pointer array
  43. *)
  44. TypeDesc* = POINTER TO RECORD
  45. descSize-: SIZE;
  46. sentinel-: LONGINT; (* = MPO-4 *)
  47. tag-: ADDRESS; (* pointer to static type descriptor, only used by linker and loader *)
  48. flags-: SET;
  49. mod- {UNTRACED}: Module; (* hint only, because module may have been freed (at Heaps.ModOfs) *)
  50. name-: Name;
  51. refsOffset-: SIZE;
  52. END;
  53. ExceptionTableEntry* = RECORD
  54. pcFrom*: ADDRESS;
  55. pcTo*: ADDRESS;
  56. pcHandler*: ADDRESS;
  57. END;
  58. ExceptionTable* = POINTER TO ARRAY OF ExceptionTableEntry;
  59. ProcedureDescPointer* = POINTER TO ProcedureDesc;
  60. ProcedureDesc*= RECORD
  61. pcFrom-, pcLimit-: ADDRESS;
  62. offsets- {UNTRACED}: POINTER TO ARRAY OF ADDRESS;
  63. END;
  64. ProcedureDescs* = POINTER TO ARRAY OF ProcedureDescPointer;
  65. Module* = OBJECT (Heaps.RootObject) (* cf. Linker0 & Heaps.WriteType *)
  66. VAR
  67. next*: Module; (** once a module is published, all fields are read-only *)
  68. name*: Name;
  69. init, published: BOOLEAN;
  70. refcnt*: LONGINT; (* counts loaded modules that import this module *)
  71. sb*: ADDRESS; (* reference address between constants and local variables *)
  72. entry*: POINTER TO ARRAY OF ADDRESS;
  73. command*: POINTER TO ARRAY OF Command;
  74. ptrAdr*: POINTER TO ARRAY OF ADDRESS; (* traced explicitly in FindRoots *)
  75. typeInfo*: POINTER TO ARRAY OF TypeDesc;
  76. module*: POINTER TO ARRAY OF Module; (* imported modules: for reference counting *)
  77. procTable*: ProcedureDescs; (* information inserted by loader, sorted by pc after loading *)
  78. data*, code*, staticTypeDescs* (* ug *), refs*: Bytes;
  79. export*: ExportDesc;
  80. term*: TerminationHandler;
  81. exTable*: ExceptionTable;
  82. (* internal pointer array: to protect internal data structures from being GCed *)
  83. internal-: POINTER TO ARRAY OF ANY;
  84. crc*: LONGINT;
  85. body*: PROCEDURE;
  86. flags*: SET; (* e.g. compilation flags *)
  87. END Module;
  88. LoaderProc* = PROCEDURE (CONST name, fileName: ARRAY OF CHAR; VAR res: WORD;
  89. VAR msg: ARRAY OF CHAR): Module; (** load an object file *)
  90. VAR
  91. extension-: ARRAY MaxObjFormats, 8 OF CHAR;
  92. loader: ARRAY MaxObjFormats OF LoaderProc;
  93. numLoaders: LONGINT;
  94. freeRoot*: Module; (** list of freed modules (temporary) *)
  95. root-: Module; (** list of modules (read-only) *)
  96. shutdown*: LONGINT; (** None, Reboot, PowerDown *)
  97. trace: BOOLEAN;
  98. register: RECORD
  99. first {UNTRACED}, last {UNTRACED}: Module;
  100. END;
  101. (* global sorted table of all procedures , basically for GC *)
  102. procedureDescriptors-: ProcedureDescs;
  103. (** Register a module loader. *)
  104. PROCEDURE Halt(CONST reason: ARRAY OF CHAR);
  105. BEGIN
  106. HALT(999);
  107. END Halt;
  108. PROCEDURE AddLoader*(CONST ext: ARRAY OF CHAR; proc: LoaderProc);
  109. BEGIN
  110. Machine.Acquire(Machine.Modules);
  111. ASSERT(numLoaders < MaxObjFormats);
  112. loader[numLoaders] := proc;
  113. COPY(ext, extension[numLoaders]);
  114. ASSERT(ext = extension[numLoaders]); (* no overflow *)
  115. INC(numLoaders);
  116. Machine.Release(Machine.Modules)
  117. END AddLoader;
  118. (** Remove a module loader. *)
  119. PROCEDURE RemoveLoader*(CONST ext: ARRAY OF CHAR; proc: LoaderProc);
  120. VAR i, j: LONGINT;
  121. BEGIN
  122. Machine.Acquire(Machine.Modules);
  123. i := 0;
  124. WHILE (i # numLoaders) & ((loader[i] # proc) OR (extension[i] # ext)) DO INC(i) END;
  125. IF i # numLoaders THEN
  126. FOR j := i TO numLoaders - 2 DO
  127. loader[j] := loader[j + 1]; extension[j] := extension[j + 1];
  128. END;
  129. loader[numLoaders - 1] := NIL; extension[numLoaders - 1] := "";
  130. DEC(numLoaders)
  131. END;
  132. Machine.Release(Machine.Modules)
  133. END RemoveLoader;
  134. (** Append string from to to, truncating on overflow. *)
  135. PROCEDURE Append*(CONST from: ARRAY OF CHAR; VAR to: ARRAY OF CHAR);
  136. VAR i, j, m: LONGINT;
  137. BEGIN
  138. j := 0; WHILE to[j] # 0X DO INC(j) END;
  139. m := LEN(to)-1;
  140. i := 0; WHILE (from[i] # 0X) & (j # m) DO to[j] := from[i]; INC(i); INC(j) END;
  141. to[j] := 0X
  142. END Append;
  143. (** Add a module to the pool of accessible modules, or return named module. *)
  144. PROCEDURE Publish*(VAR m: Module; VAR new: BOOLEAN);
  145. VAR n: Module; i: LONGINT; name: Name;
  146. BEGIN
  147. Machine.Acquire(Machine.Modules);
  148. n := root; WHILE (n # NIL) & (n.name # m.name) DO n := n.next END;
  149. IF n # NIL THEN (* module with same name exists, return it and ignore new m *)
  150. m := n; new := FALSE
  151. ELSE
  152. IF TraceBoot OR trace THEN
  153. Machine.Acquire(Machine.TraceOutput);
  154. Trace.String("publish "); Trace.String(m.name);
  155. Trace.Ln;
  156. Machine.Release(Machine.TraceOutput);
  157. END;
  158. Unregister(m);
  159. m.published := TRUE;
  160. m.next := root; root := m;
  161. m.refcnt := 0;
  162. SortExceptionTable(m.exTable);
  163. SortProcedureDescs(m.procTable);
  164. IF m.module # NIL THEN
  165. FOR i := 0 TO LEN(m.module)-1 DO INC(m.module[i].refcnt) END;
  166. END;
  167. new := TRUE;
  168. END;
  169. Machine.Release(Machine.Modules);
  170. END Publish;
  171. PROCEDURE Initialize*(VAR module: Module);
  172. VAR new: BOOLEAN; import: LONGINT;
  173. BEGIN
  174. IF (module = NIL) THEN RETURN END;
  175. Publish (module, new);
  176. IF new THEN
  177. FOR import := 0 TO LEN (module.module) - 1 DO
  178. IF ~module.module[import].published THEN
  179. ASSERT(register.first # NIL);
  180. Initialize(module.module[import]);
  181. END
  182. END;
  183. IF (module.code # NIL) & (LEN(module.code) > 0) THEN
  184. Machine.FlushDCacheRange(ADDRESSOF(module.code[0]), LEN(module.code));
  185. END;
  186. IF module.body # NIL THEN
  187. module.body
  188. END;
  189. module.init := TRUE;
  190. END;
  191. END Initialize;
  192. VAR callagain: BOOLEAN;
  193. PROCEDURE Initialize0*(module: Module);
  194. VAR new: BOOLEAN;
  195. BEGIN
  196. (*TRACE(module.name);*)
  197. (* module MUST have been removed from register list and must not have been initialized yet *)
  198. (* ASSERT(module.next = NIL); *)
  199. Publish (module, new);
  200. callagain := FALSE;
  201. IF new THEN
  202. IF module.name = "Objects" THEN
  203. callagain := TRUE;
  204. module.init := TRUE;
  205. END;
  206. (*
  207. Trace.Memory(SYSTEM.VAL(ADDRESS, module), 256);
  208. TRACE(module, module.name, module.body);
  209. TRACE(module);
  210. TRACE(ADDRESS OF module.next);
  211. TRACE(ADDRESS OF module.name);
  212. TRACE(ADDRESS OF module.init);
  213. TRACE(ADDRESS OF module.published);
  214. TRACE(ADDRESS OF module.body);
  215. TRACE(ADDRESS OF module.refcnt);
  216. TRACE(ADDRESS OF module.sb);
  217. TRACE(ADDRESS OF module.entry);
  218. TRACE(ADDRESS OF module.command);
  219. TRACE(ADDRESS OF module.ptrAdr);
  220. TRACE(ADDRESS OF module.typeInfo);
  221. TRACE(ADDRESS OF module.module);
  222. TRACE(ADDRESS OF module.procTable);
  223. TRACE(ADDRESS OF module.ptrTable);
  224. TRACE(ADDRESS OF module.data);
  225. TRACE(ADDRESS OF module.code);
  226. TRACE(ADDRESS OF module.staticTypeDescs);
  227. TRACE(ADDRESS OF module.refs);
  228. TRACE(ADDRESS OF module.export);
  229. TRACE(ADDRESS OF module.term);
  230. TRACE(ADDRESS OF module.exTable);
  231. TRACE(ADDRESS OF module.noProcs);
  232. TRACE(ADDRESS OF module.firstProc);
  233. TRACE(ADDRESS OF module.maxPtrs);
  234. TRACE(ADDRESS OF module.crc);
  235. TRACE(ADDRESS OF module.body);
  236. *)
  237. IF module.body # NIL THEN module.body END;
  238. IF callagain THEN
  239. PublishRegisteredModules (* does not return on intel architecture. Returns on ARM but looses procedure stack frame: we are not allowed to refer to local variables after this *)
  240. ELSE
  241. module.init := TRUE;
  242. END;
  243. END;
  244. END Initialize0;
  245. (** Return the named module or NIL if it is not loaded yet. *)
  246. PROCEDURE ModuleByName*(CONST name: ARRAY OF CHAR): Module;
  247. VAR m: Module;
  248. BEGIN
  249. Machine.Acquire(Machine.Modules);
  250. m := root; WHILE (m # NIL) & (m.name # name) DO m := m.next END;
  251. Machine.Release(Machine.Modules);
  252. RETURN m
  253. END ModuleByName;
  254. PROCEDURE ByName(CONST name: ARRAY OF CHAR; VAR referenced: BOOLEAN): Module;
  255. VAR m: Module;
  256. BEGIN
  257. Machine.Acquire(Machine.Modules);
  258. referenced := FALSE;
  259. m := root; WHILE (m # NIL) & (m.name # name) DO m := m.next END;
  260. IF m = NIL THEN
  261. referenced := TRUE;
  262. m := register.first; WHILE (m#NIL) & (m.name # name) DO m := m.next END;
  263. END;
  264. Machine.Release(Machine.Modules);
  265. RETURN m
  266. END ByName;
  267. (* Generate a module file name. *)
  268. PROCEDURE GetFileName(CONST name, extension: ARRAY OF CHAR; VAR fileName: ARRAY OF CHAR);
  269. VAR i, j: LONGINT;
  270. BEGIN
  271. i := 0; WHILE name[i] # 0X DO fileName[i] := name[i]; INC(i) END;
  272. j := 0; WHILE extension[j] # 0X DO fileName[i] := extension[j]; INC(i); INC(j) END;
  273. fileName[i] := 0X
  274. END GetFileName;
  275. (* sort procedure descriptors by firstPC in ascending order *)
  276. PROCEDURE SortProcedureDescs(p: ProcedureDescs);
  277. PROCEDURE Less(i,j: LONGINT): BOOLEAN;
  278. BEGIN
  279. RETURN p[i].pcFrom < p[j].pcFrom;
  280. END Less;
  281. PROCEDURE Swap(i,j: LONGINT);
  282. VAR tmp: ProcedureDescPointer;
  283. BEGIN
  284. tmp := p[i];
  285. p[i] := p[j];
  286. p[j] := tmp;
  287. END Swap;
  288. PROCEDURE Quick( lo, hi: LONGINT);
  289. VAR i, j, m: LONGINT;
  290. BEGIN
  291. IF lo < hi THEN
  292. i := lo; j := hi; m := (lo + hi) DIV 2;
  293. REPEAT
  294. WHILE Less( i, m ) DO INC( i ) END;
  295. WHILE Less( m, j ) DO DEC( j ) END;
  296. IF i <= j THEN
  297. IF m = i THEN m := j
  298. ELSIF m = j THEN m := i
  299. END;
  300. Swap( i, j ); INC( i ); DEC( j )
  301. END
  302. UNTIL i > j;
  303. Quick( lo, j); Quick( i, hi)
  304. END;
  305. END Quick;
  306. BEGIN
  307. Quick(0, LEN(p)-1);
  308. END SortProcedureDescs;
  309. (* sort procedure descriptors by firstPC in ascending order *)
  310. PROCEDURE SortExceptionTable(p: ExceptionTable);
  311. PROCEDURE Less(i,j: LONGINT): BOOLEAN;
  312. BEGIN
  313. RETURN p[i].pcFrom < p[j].pcFrom;
  314. END Less;
  315. PROCEDURE Swap(i,j: LONGINT);
  316. VAR tmp: ExceptionTableEntry;
  317. BEGIN
  318. tmp := p[i];
  319. p[i] := p[j];
  320. p[j] := tmp;
  321. END Swap;
  322. PROCEDURE Quick( lo, hi: LONGINT);
  323. VAR i, j, m: LONGINT;
  324. BEGIN
  325. IF lo < hi THEN
  326. i := lo; j := hi; m := (lo + hi) DIV 2;
  327. REPEAT
  328. WHILE Less( i, m ) DO INC( i ) END;
  329. WHILE Less( m, j ) DO DEC( j ) END;
  330. IF i <= j THEN
  331. IF m = i THEN m := j
  332. ELSIF m = j THEN m := i
  333. END;
  334. Swap( i, j ); INC( i ); DEC( j )
  335. END
  336. UNTIL i > j;
  337. Quick( lo, j); Quick( i, hi)
  338. END;
  339. END Quick;
  340. BEGIN
  341. Quick(0, LEN(p)-1);
  342. END SortExceptionTable;
  343. (** Load the module if it is not already loaded. *) (* Algorithm J. Templ, ETHZ, 1994 *)
  344. PROCEDURE ThisModule*(CONST name: ARRAY OF CHAR; VAR res: WORD; VAR msg: ARRAY OF CHAR): Module;
  345. VAR m: Module; fileName: ARRAY 64 OF CHAR; i: LONGINT; registered: BOOLEAN;
  346. BEGIN
  347. res := Ok; msg[0] := 0X; m := ByName(name, registered);
  348. IF (m#NIL) & (registered) THEN
  349. IF trace THEN
  350. Machine.Acquire (Machine.TraceOutput);
  351. Trace.String(">R>"); Trace.StringLn (name);
  352. Machine.Release (Machine.TraceOutput);
  353. END;
  354. IF ~m.published THEN (* no race on m.published, as update is done in Publish *)
  355. Initialize(m);
  356. END;
  357. IF trace THEN
  358. Machine.Acquire (Machine.TraceOutput);
  359. Trace.String("<R<"); Trace.StringLn (name);
  360. Machine.Release (Machine.TraceOutput);
  361. END;
  362. ELSIF m = NIL THEN
  363. IF trace THEN
  364. Machine.Acquire (Machine.TraceOutput);
  365. Trace.String(">L>"); Trace.StringLn (name);
  366. Machine.Release (Machine.TraceOutput);
  367. END;
  368. IF numLoaders = 0 THEN
  369. res := NoLoader; m := NIL;
  370. ELSE
  371. i:= 0;
  372. REPEAT
  373. GetFileName(name, extension[i], fileName);
  374. m := loader[i](name, fileName, res, msg);
  375. INC(i);
  376. UNTIL (m # NIL) OR (i=numLoaders);
  377. END;
  378. IF trace THEN
  379. Machine.Acquire (Machine.TraceOutput);
  380. Trace.String("?"); Trace.StringLn (name);
  381. Machine.Release (Machine.TraceOutput);
  382. END;
  383. IF (m # NIL) & ~m.published THEN (* no race on m.published, as update is done below in Publish *)
  384. Initialize(m);
  385. END;
  386. IF trace THEN
  387. Machine.Acquire (Machine.TraceOutput);
  388. IF m = NIL THEN
  389. Trace.String("could not load "); Trace.StringLn(name)
  390. ELSIF ~m.published THEN
  391. Trace.String("not published "); Trace.StringLn(name)
  392. ELSE
  393. Trace.String("<L<"); Trace.StringLn (name);
  394. END;
  395. Machine.Release (Machine.TraceOutput);
  396. END;
  397. END;
  398. RETURN m
  399. END ThisModule;
  400. (** Return the module that contains code address pc or NIL if not found. Can also return freed modules. Non-blocking version for reflection *)
  401. PROCEDURE ThisModuleByAdr0*(pc: ADDRESS): Module;
  402. VAR m: Module; found: BOOLEAN; list: LONGINT;
  403. BEGIN
  404. list := 0; found := FALSE;
  405. REPEAT
  406. CASE list OF
  407. 0: m := root
  408. |1: m := freeRoot
  409. END;
  410. WHILE (m # NIL) & ~found DO
  411. found := FindProc(pc, m.procTable) # NIL;
  412. IF ~found THEN m := m.next END;
  413. END;
  414. INC(list)
  415. UNTIL found OR (list=2);
  416. RETURN m
  417. END ThisModuleByAdr0;
  418. (** Return the module that contains code address pc or NIL if not found. Can also return freed modules. *)
  419. PROCEDURE ThisModuleByAdr*(pc: ADDRESS): Module;
  420. VAR m: Module;
  421. BEGIN
  422. Machine.Acquire(Machine.Modules);
  423. m := ThisModuleByAdr0(pc);
  424. Machine.Release(Machine.Modules);
  425. RETURN m
  426. END ThisModuleByAdr;
  427. (* Retrieve a procedure given a module name, the procedure name and some type information (kernel call) *)
  428. PROCEDURE GetProcedure*(CONST moduleName, procedureName : ARRAY OF CHAR; argTdAdr, retTdAdr : ADDRESS; VAR entryAdr : ADDRESS);
  429. VAR module : Module; ignoreMsg : ARRAY 32 OF CHAR; i, res : LONGINT;
  430. BEGIN
  431. module := ThisModule(moduleName, res, ignoreMsg);
  432. IF (res = Ok) THEN
  433. ASSERT(module.init); (* module body must have been called (see note at end of module) *)
  434. IF module.init THEN
  435. Machine.Acquire(Machine.Modules);
  436. i := 0; entryAdr := Heaps.NilVal;
  437. WHILE (entryAdr = Heaps.NilVal) & (i # LEN(module.command^)) DO
  438. IF (module.command[i].name = procedureName) & (module.command[i].argTdAdr = argTdAdr) & (module.command[i].retTdAdr = retTdAdr) THEN
  439. entryAdr := module.command[i].entryAdr;
  440. END;
  441. INC(i)
  442. END;
  443. Machine.Release(Machine.Modules);
  444. END;
  445. END;
  446. END GetProcedure;
  447. (** Return the named type *)
  448. PROCEDURE ThisType*(m: Module; CONST name: ARRAY OF CHAR): TypeDesc;
  449. VAR i: LONGINT; type: TypeDesc;
  450. BEGIN
  451. Machine.Acquire(Machine.Modules);
  452. i := 0;
  453. WHILE (i < LEN(m.typeInfo)) & (m.typeInfo[i].name # name) DO INC(i) END;
  454. IF i = LEN(m.typeInfo) THEN
  455. type := NIL
  456. ELSE
  457. type := m.typeInfo[i]
  458. END;
  459. Machine.Release(Machine.Modules);
  460. RETURN type
  461. END ThisType;
  462. PROCEDURE ThisTypeByAdr*(adr: ADDRESS; VAR m: Module; VAR t: TypeDesc);
  463. BEGIN
  464. IF adr # 0 THEN
  465. Machine.Acquire(Machine.Modules);
  466. SYSTEM.GET (adr + Heaps.TypeDescOffset, adr);
  467. t := SYSTEM.VAL(TypeDesc, adr);
  468. m := t.mod;
  469. Machine.Release(Machine.Modules)
  470. ELSE
  471. m := NIL; t := NIL
  472. END
  473. END ThisTypeByAdr;
  474. (** create a new object given its type descriptor *)
  475. PROCEDURE NewObj*(t : TypeDesc; isRealtime: BOOLEAN) : ANY;
  476. VAR x : ANY;
  477. BEGIN
  478. Heaps.NewRec(x, SYSTEM.VAL (ADDRESS, t.tag), isRealtime);
  479. RETURN x;
  480. END NewObj;
  481. (** return the type descriptor of an object *)
  482. PROCEDURE TypeOf*(obj : ANY): TypeDesc;
  483. VAR
  484. m : Module;
  485. t : TypeDesc;
  486. adr : ADDRESS;
  487. BEGIN
  488. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.TypeDescOffset, adr);
  489. ThisTypeByAdr(adr, m, t);
  490. RETURN t;
  491. END TypeOf;
  492. (** searches for the given pc in the global ProcKeyTable, if found it returns the corresponding data element *)
  493. PROCEDURE FindProc*(pc: ADDRESS; p: ProcedureDescs): ProcedureDescPointer;
  494. VAR l,r,x: LONGINT; isHit: BOOLEAN;
  495. BEGIN
  496. IF p # NIL THEN
  497. l := 0; r := LEN(p)-1;
  498. REPEAT
  499. x := (l + r) DIV 2;
  500. IF pc < p[x].pcFrom THEN r := x - 1 ELSE l := x + 1 END;
  501. isHit := ((p[x].pcFrom <= pc) & (pc < p[x].pcLimit));
  502. UNTIL isHit OR (l > r);
  503. IF isHit THEN
  504. RETURN p[x];
  505. END;
  506. END;
  507. RETURN NIL;
  508. END FindProc;
  509. (** Install procedure to execute when module is freed or shut down. The handler can distinguish the two cases by checking Modules.shutdown. If it is None, the module is being freed, otherwise the system is being shut down or rebooted. Only one handler may be installed per module. The last handler installed is active. *)
  510. PROCEDURE InstallTermHandler*(h: TerminationHandler);
  511. VAR m: Module;
  512. BEGIN
  513. m := ThisModuleByAdr(SYSTEM.VAL (ADDRESS, h));
  514. IF m # NIL THEN
  515. m.term := h (* overwrite existing handler, if any *)
  516. END
  517. END InstallTermHandler;
  518. (** Free a module. The module's termination handler, if any, is called first. Then all objects that have finalizers in this module are finalized (even if they are still reachable). Then the module's data and code are invalidated. *)
  519. PROCEDURE FreeModule*(CONST name: ARRAY OF CHAR; VAR res: WORD; VAR msg: ARRAY OF CHAR);
  520. VAR p, m: Module; term: TerminationHandler; i: LONGINT;
  521. BEGIN
  522. m := ModuleByName(name);
  523. IF (m # NIL) & (m.refcnt = 0) THEN (* will be freed below *)
  524. IF m.term # NIL THEN (* call termination handler *)
  525. term := m.term; m.term := NIL; term (* may trap *)
  526. END;
  527. IF m.code # NIL THEN
  528. Heaps.CleanupModuleFinalizers(ADDRESSOF(m.code[0]), LEN(m.code), m.name)
  529. END;
  530. END;
  531. res := Ok; msg[0] := 0X;
  532. Machine.Acquire(Machine.Modules);
  533. p := NIL; m := root;
  534. WHILE (m # NIL) & (m.name # name) DO p := m; m := m.next END;
  535. IF m # NIL THEN
  536. IF m.refcnt = 0 THEN (* free the module *)
  537. FOR i := 0 TO LEN(m.module)-1 DO DEC(m.module[i].refcnt) END;
  538. m.init := FALSE; (* disallow ThisCommand *)
  539. Append("?", m.name);
  540. (* move module to free list *)
  541. IF p = NIL THEN root := root.next ELSE p.next := m.next END;
  542. m.next := freeRoot; freeRoot := m;
  543. (* clear global pointers and code *)
  544. IF m.ptrAdr # NIL THEN
  545. Trace.String("ptradr del"); Trace.Ln;
  546. FOR i := 0 TO LEN(m.ptrAdr)-1 DO SYSTEM.PUT (m.ptrAdr[i], NIL) END;
  547. END;
  548. IF ClearCode & (m.code # NIL) THEN
  549. Trace.String("clear code"); Trace.Ln;
  550. FOR i := 0 TO LEN(m.code)-1 DO m.code[i] := 0CCX END
  551. END;
  552. Trace.String("clear code f"); Trace.Ln;
  553. (* remove references to module data *)
  554. m.published := FALSE;
  555. m.entry := NIL; m.command := NIL; m.ptrAdr := NIL;
  556. (* do not clear m.type or m.module, as old heap block tags might reference type descs indirectly. *) (* m.staticTypeDescs, m.typeInfo ??? *)
  557. (* do not clear m.data or m.code, as they are used in ThisModuleByAdr (for debugging). *)
  558. (* do not clear m.refs, as they are used in Traps (for debugging). *)
  559. m.export.dsc := NIL; m.exTable := NIL;
  560. ELSE
  561. res := 1901; (* can not free module in use *)
  562. COPY(name, msg); Append(" reference count not zero", msg)
  563. END
  564. ELSE
  565. res := 1902; (* module not found *)
  566. COPY(name, msg); Append(" not found", msg)
  567. END;
  568. Machine.Release(Machine.Modules)
  569. END FreeModule;
  570. (** Shut down all modules by calling their termination handlers and then call Machine.Shutdown. *)
  571. PROCEDURE Shutdown*(code: LONGINT);
  572. VAR m: Module; term: TerminationHandler;
  573. BEGIN
  574. IF code # None THEN
  575. LOOP
  576. Machine.Acquire(Machine.Modules);
  577. m := root; WHILE (m # NIL) & (m.term = NIL) DO m := m.next END;
  578. IF m # NIL THEN term := m.term; m.term := NIL END; (* finalizer only called once *)
  579. Machine.Release(Machine.Modules);
  580. IF m = NIL THEN EXIT END;
  581. IF trace THEN
  582. Machine.Acquire (Machine.TraceOutput);
  583. Trace.String("TermHandler "); Trace.StringLn (m.name);
  584. Machine.Release (Machine.TraceOutput);
  585. END;
  586. term (* if this causes exception or hangs, another shutdown call will retry *)
  587. END;
  588. (* clean up finalizers *)
  589. m := root;
  590. WHILE m # NIL DO
  591. IF (m.code # NIL) & (LEN(m.code)>0) THEN
  592. Heaps.CleanupModuleFinalizers(ADDRESSOF(m.code[0]), LEN(m.code), m.name)
  593. END;
  594. m := m.next
  595. END;
  596. IF trace THEN
  597. Machine.Acquire (Machine.TraceOutput);
  598. Trace.StringLn ("Modules.Shutdown finished");
  599. Machine.Release (Machine.TraceOutput);
  600. END;
  601. Machine.Shutdown(code = Reboot) (* does not return *)
  602. END
  603. END Shutdown;
  604. (* Is this PC handled in the corresponding module. deep = scan the whole stack. *)
  605. PROCEDURE IsExceptionHandled*(VAR pc, fp: ADDRESS; deep: BOOLEAN): BOOLEAN;
  606. VAR
  607. handler: ADDRESS;
  608. BEGIN
  609. IF deep THEN
  610. handler := GetExceptionHandler(pc);
  611. IF handler # -1 THEN (* Handler in the current PAF *)
  612. RETURN TRUE
  613. ELSE
  614. WHILE (fp # 0) & (handler = -1) DO
  615. SYSTEM.GET (fp + 4, pc);
  616. pc := pc - 1; (* CALL instruction, machine dependant!!! *)
  617. handler := GetExceptionHandler(pc);
  618. SYSTEM.GET (fp, fp) (* Unwind PAF *)
  619. END;
  620. IF handler = -1 THEN RETURN FALSE ELSE pc := handler; RETURN TRUE END
  621. END
  622. ELSE
  623. RETURN GetExceptionHandler(pc) # -1
  624. END
  625. END IsExceptionHandled;
  626. (* Is this PC handled in the corresponding module. If the PC is handled the PC of the
  627. handler is return else -1 is return. There is no problem concurrently accessing this
  628. procedure, there is only reading work. *)
  629. PROCEDURE GetExceptionHandler*(pc: ADDRESS): ADDRESS;
  630. VAR
  631. m: Module;
  632. PROCEDURE BinSearch(exTable: ExceptionTable; key: ADDRESS): ADDRESS;
  633. VAR
  634. x, l, r: LONGINT;
  635. BEGIN
  636. l := 0; r:=LEN(exTable) - 1;
  637. REPEAT
  638. x := (l + r) DIV 2;
  639. IF key < exTable[x].pcFrom THEN r := x - 1 ELSE l := x + 1 END;
  640. UNTIL ((key >= exTable[x].pcFrom) & (key < exTable[x].pcTo) ) OR (l > r);
  641. IF (key >= exTable[x].pcFrom) & (key < exTable[x].pcTo) THEN
  642. RETURN exTable[x].pcHandler;
  643. ELSE
  644. RETURN -1;
  645. END
  646. END BinSearch;
  647. BEGIN
  648. m := ThisModuleByAdr(pc);
  649. IF (m # NIL) & (m.exTable # NIL) & (LEN(m.exTable) > 0) THEN
  650. RETURN BinSearch(m.exTable, pc);
  651. END;
  652. RETURN -1;
  653. END GetExceptionHandler;
  654. (** fof: to make custom solutions to the race process, described below, possible. This is not a solution to the generic problem !! *)
  655. PROCEDURE Initialized*(m: Module): BOOLEAN;
  656. BEGIN
  657. RETURN m.init;
  658. END Initialized;
  659. PROCEDURE Register- (module {UNTRACED}: Module);
  660. BEGIN {UNCOOPERATIVE, UNCHECKED}
  661. IF register.first = NIL THEN
  662. register.first := module;
  663. ELSE
  664. register.last.next := module; (* transitively unsafe access via register.last *)
  665. END;
  666. register.last := module;
  667. END Register;
  668. PROCEDURE Unregister(m: Module);
  669. VAR prev: Module;
  670. BEGIN
  671. ASSERT(m#NIL);
  672. IF register.first = NIL THEN RETURN
  673. ELSIF m = register.first THEN
  674. register.first := m.next;
  675. IF register.first = NIL THEN register.last := NIL END;
  676. ELSE
  677. prev := register.first;
  678. WHILE (prev.next # NIL) & (prev.next # m) DO
  679. prev := prev.next;
  680. END;
  681. IF prev.next = m THEN
  682. prev.next := prev.next.next;
  683. IF prev.next = NIL THEN register.last := prev END;
  684. END;
  685. END;
  686. m.next := NIL;
  687. END Unregister;
  688. PROCEDURE PublishRegisteredModules;
  689. VAR m {UNTRACED}: Module; module, import: SIZE;
  690. BEGIN
  691. Activities.Call (Activities.Idle);
  692. WHILE register.first # NIL DO
  693. m := register.first;
  694. IF m.module # NIL THEN
  695. FOR import := 0 TO LEN (m.module) - 1 DO
  696. IF ~m.module[import].published THEN
  697. ASSERT(register.first # NIL);
  698. (*prev := NIL;
  699. cur := register.first;
  700. WHILE (cur # NIL) & (cur # m.module[import]) DO
  701. prev := cur;
  702. cur := cur.next
  703. END;
  704. (*ASSERT(cur = m.module[import]);*)
  705. ASSERT(cur = m.module[import]);
  706. IF prev = NIL THEN
  707. register.first := cur.next
  708. ELSE
  709. prev.next := cur.next;
  710. END;
  711. cur.next := NIL;
  712. *)
  713. Initialize0 (m.module[import]);
  714. END
  715. END;
  716. END;
  717. Initialize0 (m);
  718. END;
  719. END PublishRegisteredModules;
  720. PROCEDURE FinalizeModules;
  721. VAR module {UNTRACED}: Module;
  722. PROCEDURE Finalize EXTERN "BaseTypes.Object.Finalize" (module {UNTRACED}: Module);
  723. BEGIN {UNCOOPERATIVE, UNCHECKED}
  724. module := root;
  725. WHILE module # NIL DO
  726. Finalize (module);
  727. module := module.next;
  728. END;
  729. END FinalizeModules;
  730. PROCEDURE {FINAL} Main;
  731. PROCEDURE InitializeGC EXTERN "GarbageCollector.Initialize";
  732. PROCEDURE TerminateGC EXTERN "GarbageCollector.Terminate";
  733. BEGIN {UNCOOPERATIVE, UNCHECKED}
  734. SYSTEM.SetActivity (NIL);
  735. SYSTEM.SetFramePointer (NIL);
  736. Environment.Initialize;
  737. InitializeGC;
  738. Processors.Initialize;
  739. Activities.Execute (PublishRegisteredModules);
  740. Processors.Terminate;
  741. FinalizeModules;
  742. Activities.Terminate;
  743. Queues.Terminate;
  744. Environment.Terminate;
  745. TerminateGC;
  746. Environment.Exit (Environment.status);
  747. END Main;
  748. PROCEDURE Init;
  749. VAR
  750. s: ARRAY 4 OF CHAR;
  751. BEGIN
  752. (* root and initBlock are initialized by the linker *)
  753. shutdown := None;
  754. numLoaders := 0;
  755. freeRoot := NIL;
  756. Machine.GetConfig("TraceModules", s);
  757. trace := (s[0] = "1");
  758. END Init;
  759. BEGIN
  760. Init
  761. END Modules.