Generic.Modules.Mod 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926
  1. MODULE Modules; (** AUTHOR "pjm"; PURPOSE "Modules and types"; *)
  2. IMPORT SYSTEM, Trace, Machine, Heaps;
  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*: LONGINT;
  34. name* {UNTRACED}: DynamicName;
  35. adr*: ADDRESS;
  36. exports*: LONGINT;
  37. dsc* {UNTRACED}: ExportArray
  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. EntryType*=RECORD
  45. class*: CHAR;
  46. subclass*: CHAR;
  47. (* size in bits *)
  48. size*: INTEGER;
  49. type*: ADDRESS; (* type descriptor or additional information *)
  50. END;
  51. FieldEntry* = RECORD
  52. name*: DynamicName;
  53. offset*: SIZE; (* offset of this type *)
  54. type*: EntryType;
  55. flags*: SET;
  56. END;
  57. FieldEntries*= POINTER TO ARRAY OF FieldEntry;
  58. ProcedureEntries*=POINTER TO ARRAY OF ProcedureEntry;
  59. ProcedureEntry*=RECORD
  60. name*: DynamicName;
  61. address*: ADDRESS;
  62. size*: SIZE;
  63. parameters* {UNTRACED}: FieldEntries;
  64. variables* {UNTRACED}: FieldEntries;
  65. procedures* {UNTRACED}: ProcedureEntries;
  66. returnType*: EntryType;
  67. flags*: SET;
  68. END;
  69. TypeDesc* = POINTER TO RECORD
  70. descSize: LONGINT;
  71. sentinel: LONGINT; (* = MPO-4 *)
  72. tag*: ADDRESS; (* pointer to static type descriptor, only used by linker and loader *)
  73. flags*: SET;
  74. mod* {UNTRACED}: Module; (* hint only, because module may have been freed (at Heaps.ModOfs) *)
  75. name*: Name;
  76. fields* {UNTRACED}: FieldEntries;
  77. procedures* {UNTRACED}: ProcedureEntries;
  78. END;
  79. ExceptionTableEntry* = RECORD
  80. pcFrom*: ADDRESS;
  81. pcTo*: ADDRESS;
  82. pcHandler*: ADDRESS;
  83. END;
  84. ExceptionTable* = POINTER TO ARRAY OF ExceptionTableEntry;
  85. ProcedureDescPointer* = POINTER TO ProcedureDesc;
  86. ProcedureDesc*= RECORD
  87. pcFrom-, pcLimit-, pcValid-, pcEnd-: ADDRESS;
  88. offsets- {UNTRACED}: POINTER TO ARRAY OF ADDRESS;
  89. END;
  90. ProcedureDescs* = POINTER TO ARRAY OF ProcedureDescPointer;
  91. Module* = OBJECT (Heaps.RootObject) (* cf. Linker0 & Heaps.WriteType *)
  92. VAR
  93. next*: Module; (** once a module is published, all fields are read-only *)
  94. name*: Name;
  95. init, published: BOOLEAN;
  96. refcnt*: LONGINT; (* counts loaded modules that import this module *)
  97. sb*: ADDRESS; (* reference address between constants and local variables *)
  98. entry*: POINTER TO ARRAY OF ADDRESS;
  99. command*: POINTER TO ARRAY OF Command;
  100. ptrAdr*: POINTER TO ARRAY OF ADDRESS; (* traced explicitly in FindRoots *)
  101. typeInfo*: POINTER TO ARRAY OF TypeDesc;
  102. module*: POINTER TO ARRAY OF Module; (* imported modules: for reference counting *)
  103. procTable*: ProcedureDescs; (* information inserted by loader, removed after use in Publish *)
  104. ptrTable*: ADDRESS; (*! legacy, can be removed *)
  105. data*, code*, staticTypeDescs* (* ug *), refs*: Bytes;
  106. export*: ExportDesc;
  107. term*: TerminationHandler;
  108. exTable*: ExceptionTable;
  109. noProcs*: LONGINT; (*! legacy, can be removed *)
  110. firstProc*: ADDRESS; (*! legacy, can be removed *)
  111. maxPtrs*: LONGINT; (*! legacy, can be removed *)
  112. (* internal pointer array: to protect internal data structures from being GCed *)
  113. internal: POINTER TO ARRAY OF ANY;
  114. crc*: LONGINT;
  115. body*: PROCEDURE;
  116. PROCEDURE FindRoots; (* override *)
  117. VAR i: LONGINT; ptr: ANY; false: BOOLEAN;
  118. BEGIN
  119. false := FALSE; IF false THEN BEGIN{EXCLUSIVE} END END; (* trick to make a module a protected record ... *)
  120. IF published THEN (* mark global pointers *)
  121. FOR i := 0 TO LEN(ptrAdr) - 1 DO
  122. SYSTEM.GET (ptrAdr[i], ptr);
  123. IF ptr # NIL THEN Heaps.Mark(ptr) END
  124. END;
  125. Heaps.AddRootObject(next);
  126. (* all other fields are being traversed by Mark of the Garbage Collector *)
  127. END;
  128. END FindRoots;
  129. END Module;
  130. LoaderProc* = PROCEDURE (CONST name, fileName: ARRAY OF CHAR; VAR res: LONGINT; VAR msg: ARRAY OF CHAR): Module; (** load an object file *)
  131. VAR
  132. extension-: ARRAY MaxObjFormats, 8 OF CHAR;
  133. loader: ARRAY MaxObjFormats OF LoaderProc;
  134. numLoaders: LONGINT;
  135. kernelProc*: ARRAY 11 OF ADDRESS; (** kernel call addresses for loader *)
  136. freeRoot*: Module; (** list of freed modules (temporary) *)
  137. (* the following two variables are initialized by Linker *)
  138. root-: Module; (** list of modules (read-only) *)
  139. initBlock: ANY; (* placeholder - anchor for module init code (initialized by linker) *)
  140. shutdown*: LONGINT; (** None, Reboot, PowerDown *)
  141. trace: BOOLEAN;
  142. register: RECORD
  143. first, last: Module;
  144. END;
  145. (* global sorted table of all procedures , basically for GC *)
  146. procedureDescriptors-: ProcedureDescs;
  147. mayAllocate: BOOLEAN;
  148. (** Register a module loader. *)
  149. PROCEDURE AddLoader*(CONST ext: ARRAY OF CHAR; proc: LoaderProc);
  150. BEGIN
  151. Machine.Acquire(Machine.Modules);
  152. ASSERT(numLoaders < MaxObjFormats);
  153. loader[numLoaders] := proc;
  154. COPY(ext, extension[numLoaders]);
  155. ASSERT(ext = extension[numLoaders]); (* no overflow *)
  156. INC(numLoaders);
  157. Machine.Release(Machine.Modules)
  158. END AddLoader;
  159. (** Remove a module loader. *)
  160. PROCEDURE RemoveLoader*(CONST ext: ARRAY OF CHAR; proc: LoaderProc);
  161. VAR i, j: LONGINT;
  162. BEGIN
  163. Machine.Acquire(Machine.Modules);
  164. i := 0;
  165. WHILE (i # numLoaders) & ((loader[i] # proc) OR (extension[i] # ext)) DO INC(i) END;
  166. IF i # numLoaders THEN
  167. FOR j := i TO numLoaders - 2 DO
  168. loader[j] := loader[j + 1]; extension[j] := extension[j + 1];
  169. END;
  170. loader[numLoaders - 1] := NIL; extension[numLoaders - 1] := "";
  171. DEC(numLoaders)
  172. END;
  173. Machine.Release(Machine.Modules)
  174. END RemoveLoader;
  175. (** Append string from to to, truncating on overflow. *)
  176. PROCEDURE Append*(CONST from: ARRAY OF CHAR; VAR to: ARRAY OF CHAR);
  177. VAR i, j, m: LONGINT;
  178. BEGIN
  179. j := 0; WHILE to[j] # 0X DO INC(j) END;
  180. m := LEN(to)-1;
  181. i := 0; WHILE (from[i] # 0X) & (j # m) DO to[j] := from[i]; INC(i); INC(j) END;
  182. to[j] := 0X
  183. END Append;
  184. (** Add a module to the pool of accessible modules, or return named module. *)
  185. PROCEDURE Publish*(VAR m: Module; VAR new: BOOLEAN);
  186. VAR n: Module; i: LONGINT;
  187. BEGIN
  188. (*
  189. ASSERT((m.code # NIL) & (LEN(m.code^) > 0));
  190. *)
  191. Machine.Acquire(Machine.Modules);
  192. n := root; WHILE (n # NIL) & (n.name # m.name) DO n := n.next END;
  193. IF n # NIL THEN (* module with same name exists, return it and ignore new m *)
  194. m := n; new := FALSE
  195. ELSE
  196. IF TraceBoot THEN
  197. Machine.Acquire(Machine.TraceOutput);
  198. Trace.String("publish "); Trace.String(m.name);
  199. (*
  200. a := m;
  201. IF a IS Heaps.RootObject THEN Trace.String(" IS RootObj") END;
  202. IF a IS Module THEN Trace.String(" IS Module"); END;
  203. *)
  204. Trace.Ln;
  205. Machine.Release(Machine.TraceOutput);
  206. END;
  207. m.published := TRUE;
  208. m.next := root; root := m;
  209. m.refcnt := 0;
  210. SortExceptionTable(m.exTable);
  211. SortProcedureDescs(m.procTable);
  212. MergeProcedureDescs(m.procTable);
  213. IF m.module # NIL THEN
  214. FOR i := 0 TO LEN(m.module)-1 DO INC(m.module[i].refcnt) END;
  215. END;
  216. new := TRUE;
  217. END;
  218. Machine.Release(Machine.Modules)
  219. END Publish;
  220. PROCEDURE Initialize*(VAR module: Module);
  221. VAR new: BOOLEAN;
  222. BEGIN
  223. IF (module = NIL) THEN RETURN END;
  224. Publish (module, new);
  225. IF new THEN
  226. IF module.body # NIL THEN
  227. Machine.FlushDCacheRange(ADDRESSOF(module.code[0]), LEN(module.code));
  228. module.body
  229. END;
  230. module.init := TRUE;
  231. END;
  232. END Initialize;
  233. VAR callagain: BOOLEAN;
  234. PROCEDURE Initialize0*(module: Module);
  235. VAR new: BOOLEAN;
  236. BEGIN
  237. (*TRACE(module.name);*)
  238. (* module MUST have been removed from register list and must not have been initialized yet *)
  239. ASSERT(module.next = NIL);
  240. Publish (module, new);
  241. callagain := FALSE;
  242. IF new THEN
  243. IF module.name = "Objects" THEN
  244. callagain := TRUE;
  245. module.init := TRUE;
  246. END;
  247. (*
  248. Trace.Memory(SYSTEM.VAL(ADDRESS, module), 256);
  249. TRACE(module, module.name, module.body);
  250. TRACE(module);
  251. TRACE(ADDRESS OF module.next);
  252. TRACE(ADDRESS OF module.name);
  253. TRACE(ADDRESS OF module.init);
  254. TRACE(ADDRESS OF module.published);
  255. TRACE(ADDRESS OF module.body);
  256. TRACE(ADDRESS OF module.refcnt);
  257. TRACE(ADDRESS OF module.sb);
  258. TRACE(ADDRESS OF module.entry);
  259. TRACE(ADDRESS OF module.command);
  260. TRACE(ADDRESS OF module.ptrAdr);
  261. TRACE(ADDRESS OF module.typeInfo);
  262. TRACE(ADDRESS OF module.module);
  263. TRACE(ADDRESS OF module.procTable);
  264. TRACE(ADDRESS OF module.ptrTable);
  265. TRACE(ADDRESS OF module.data);
  266. TRACE(ADDRESS OF module.code);
  267. TRACE(ADDRESS OF module.staticTypeDescs);
  268. TRACE(ADDRESS OF module.refs);
  269. TRACE(ADDRESS OF module.export);
  270. TRACE(ADDRESS OF module.term);
  271. TRACE(ADDRESS OF module.exTable);
  272. TRACE(ADDRESS OF module.noProcs);
  273. TRACE(ADDRESS OF module.firstProc);
  274. TRACE(ADDRESS OF module.maxPtrs);
  275. TRACE(ADDRESS OF module.crc);
  276. TRACE(ADDRESS OF module.body);
  277. *)
  278. IF module.body # NIL THEN module.body END;
  279. IF callagain THEN
  280. 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 *)
  281. ELSE
  282. module.init := TRUE;
  283. END;
  284. END;
  285. END Initialize0;
  286. (** Return the named module or NIL if it is not loaded yet. *)
  287. PROCEDURE ModuleByName*(CONST name: ARRAY OF CHAR): Module;
  288. VAR m: Module;
  289. BEGIN
  290. Machine.Acquire(Machine.Modules);
  291. m := root; WHILE (m # NIL) & (m.name # name) DO m := m.next END;
  292. Machine.Release(Machine.Modules);
  293. RETURN m
  294. END ModuleByName;
  295. (* Generate a module file name. *)
  296. PROCEDURE GetFileName(CONST name, extension: ARRAY OF CHAR; VAR fileName: ARRAY OF CHAR);
  297. VAR i, j: LONGINT;
  298. BEGIN
  299. i := 0; WHILE name[i] # 0X DO fileName[i] := name[i]; INC(i) END;
  300. j := 0; WHILE extension[j] # 0X DO fileName[i] := extension[j]; INC(i); INC(j) END;
  301. fileName[i] := 0X
  302. END GetFileName;
  303. (* sort procedure descriptors by firstPC in ascending order *)
  304. PROCEDURE SortProcedureDescs(p: ProcedureDescs);
  305. PROCEDURE Less(i,j: LONGINT): BOOLEAN;
  306. BEGIN
  307. RETURN p[i].pcFrom < p[j].pcFrom;
  308. END Less;
  309. PROCEDURE Swap(i,j: LONGINT);
  310. VAR tmp: ProcedureDescPointer;
  311. BEGIN
  312. tmp := p[i];
  313. p[i] := p[j];
  314. p[j] := tmp;
  315. END Swap;
  316. PROCEDURE Quick( lo, hi: LONGINT);
  317. VAR i, j, m: LONGINT;
  318. BEGIN
  319. IF lo < hi THEN
  320. i := lo; j := hi; m := (lo + hi) DIV 2;
  321. REPEAT
  322. WHILE Less( i, m ) DO INC( i ) END;
  323. WHILE Less( m, j ) DO DEC( j ) END;
  324. IF i <= j THEN
  325. IF m = i THEN m := j
  326. ELSIF m = j THEN m := i
  327. END;
  328. Swap( i, j ); INC( i ); DEC( j )
  329. END
  330. UNTIL i > j;
  331. Quick( lo, j); Quick( i, hi)
  332. END;
  333. END Quick;
  334. BEGIN
  335. Quick(0, LEN(p)-1);
  336. END SortProcedureDescs;
  337. (* sort procedure descriptors by firstPC in ascending order *)
  338. PROCEDURE SortExceptionTable(p: ExceptionTable);
  339. PROCEDURE Less(i,j: LONGINT): BOOLEAN;
  340. BEGIN
  341. RETURN p[i].pcFrom < p[j].pcFrom;
  342. END Less;
  343. PROCEDURE Swap(i,j: LONGINT);
  344. VAR tmp: ExceptionTableEntry;
  345. BEGIN
  346. tmp := p[i];
  347. p[i] := p[j];
  348. p[j] := tmp;
  349. END Swap;
  350. PROCEDURE Quick( lo, hi: LONGINT);
  351. VAR i, j, m: LONGINT;
  352. BEGIN
  353. IF lo < hi THEN
  354. i := lo; j := hi; m := (lo + hi) DIV 2;
  355. REPEAT
  356. WHILE Less( i, m ) DO INC( i ) END;
  357. WHILE Less( m, j ) DO DEC( j ) END;
  358. IF i <= j THEN
  359. IF m = i THEN m := j
  360. ELSIF m = j THEN m := i
  361. END;
  362. Swap( i, j ); INC( i ); DEC( j )
  363. END
  364. UNTIL i > j;
  365. Quick( lo, j); Quick( i, hi)
  366. END;
  367. END Quick;
  368. BEGIN
  369. Quick(0, LEN(p)-1);
  370. END SortExceptionTable;
  371. (* sort and merge procedure descriptors with the global procedure desc array, replacing the global procedure array *)
  372. PROCEDURE MergeProcedureDescs*(p: ProcedureDescs);
  373. VAR n: ProcedureDescs;
  374. i,j,k: LONGINT;
  375. BEGIN
  376. IF ~mayAllocate THEN RETURN END;
  377. IF (p = NIL) OR (LEN(p) = 0) THEN RETURN END;
  378. IF procedureDescriptors = NIL THEN
  379. procedureDescriptors := p;
  380. ELSE
  381. NEW(n, LEN(procedureDescriptors) + LEN(p));
  382. k := 0; i := 0; j := 0;
  383. FOR k := 0 TO LEN(n)-1 DO
  384. IF (i<LEN(p)) & ((j=LEN(procedureDescriptors)) OR (p[i].pcFrom < procedureDescriptors[j].pcFrom)) THEN
  385. n[k] := p[i]; INC(i);
  386. ELSE
  387. n[k] := procedureDescriptors[j]; INC(j);
  388. END;
  389. END;
  390. procedureDescriptors := n;
  391. END;
  392. END MergeProcedureDescs;
  393. (** Load the module if it is not already loaded. *) (* Algorithm J. Templ, ETHZ, 1994 *)
  394. PROCEDURE ThisModule*(CONST name: ARRAY OF CHAR; VAR res: LONGINT; VAR msg: ARRAY OF CHAR): Module;
  395. TYPE Body = PROCEDURE;
  396. VAR m, p: Module; fileName: ARRAY 64 OF CHAR; body: Body; new: BOOLEAN; i: LONGINT;
  397. BEGIN
  398. res := Ok; msg[0] := 0X; m := ModuleByName(name);
  399. IF m = NIL THEN
  400. IF trace THEN
  401. Machine.Acquire (Machine.TraceOutput);
  402. Trace.String(">"); Trace.StringLn (name);
  403. Machine.Release (Machine.TraceOutput);
  404. END;
  405. IF numLoaders = 0 THEN
  406. res := NoLoader; m := NIL;
  407. ELSE
  408. i:= 0;
  409. REPEAT
  410. GetFileName(name, extension[i], fileName);
  411. m := loader[i](name, fileName, res, msg);
  412. INC(i);
  413. UNTIL (m # NIL) OR (i=numLoaders);
  414. END;
  415. IF trace THEN
  416. Machine.Acquire (Machine.TraceOutput);
  417. Trace.String("?"); Trace.StringLn (name);
  418. Machine.Release (Machine.TraceOutput);
  419. END;
  420. p := m;
  421. IF (m # NIL) & ~m.published THEN (* no race on m.published, as update is done below in Publish *)
  422. Initialize(m);
  423. END;
  424. IF trace THEN
  425. Machine.Acquire (Machine.TraceOutput);
  426. IF m = NIL THEN
  427. Trace.String("could not load "); Trace.StringLn(name)
  428. ELSIF ~m.published THEN
  429. Trace.String("not published "); Trace.StringLn(name)
  430. ELSE
  431. Trace.String("<"); Trace.StringLn (name);
  432. END;
  433. Machine.Release (Machine.TraceOutput);
  434. END;
  435. END;
  436. RETURN m
  437. END ThisModule;
  438. (** Return the module that contains code address pc or NIL if not found. Can also return freed modules. Non-blocking version for reflection *)
  439. PROCEDURE ThisModuleByAdr0*(pc: ADDRESS): Module;
  440. VAR m: Module; found: BOOLEAN; list: LONGINT;
  441. BEGIN
  442. list := 0; found := FALSE;
  443. REPEAT
  444. CASE list OF
  445. 0: m := root
  446. |1: m := freeRoot
  447. END;
  448. WHILE (m # NIL) & ~found DO
  449. found := FindProc(pc, m.procTable) # NIL;
  450. IF ~found THEN m := m.next END;
  451. END;
  452. INC(list)
  453. UNTIL found OR (list=2);
  454. RETURN m
  455. END ThisModuleByAdr0;
  456. (** Return the module that contains code address pc or NIL if not found. Can also return freed modules. *)
  457. PROCEDURE ThisModuleByAdr*(pc: ADDRESS): Module;
  458. VAR m: Module;
  459. BEGIN
  460. Machine.Acquire(Machine.Modules);
  461. m := ThisModuleByAdr0(pc);
  462. Machine.Release(Machine.Modules);
  463. RETURN m
  464. END ThisModuleByAdr;
  465. CONST ModuleInitTimeout = HUGEINT(3000000000); (* Timeout for waiting until a module get initialized, 3 seconds for 1 GHz CPU *)
  466. (* Retrieve a procedure given a module name, the procedure name and some type information (kernel call) *)
  467. PROCEDURE GetProcedure*(CONST moduleName, procedureName : ARRAY OF CHAR; argTdAdr, retTdAdr : ADDRESS; VAR entryAdr : ADDRESS);
  468. VAR module : Module; ignoreMsg : ARRAY 32 OF CHAR; i, res : LONGINT; t: HUGEINT;
  469. BEGIN
  470. module := ThisModule(moduleName, res, ignoreMsg);
  471. IF (res = Ok) THEN
  472. (*!
  473. module body must have been called (see note at the end of this module);
  474. return NIL if the module does not get initialized within the specified timeout
  475. *)
  476. IF ~module.init THEN
  477. t := Machine.GetTimer();
  478. WHILE ~module.init & (Machine.GetTimer() - t < ModuleInitTimeout) DO END;
  479. IF ~module.init THEN (* timeout has expired *)
  480. RETURN;
  481. END;
  482. END;
  483. Machine.Acquire(Machine.Modules);
  484. i := 0; entryAdr := Heaps.NilVal;
  485. WHILE (entryAdr = Heaps.NilVal) & (i # LEN(module.command^)) DO
  486. IF (module.command[i].name = procedureName) & (module.command[i].argTdAdr = argTdAdr) & (module.command[i].retTdAdr = retTdAdr) THEN
  487. entryAdr := module.command[i].entryAdr;
  488. END;
  489. INC(i)
  490. END;
  491. Machine.Release(Machine.Modules);
  492. END;
  493. END GetProcedure;
  494. (** Return the named type *)
  495. PROCEDURE ThisType*(m: Module; CONST name: ARRAY OF CHAR): TypeDesc;
  496. VAR i: LONGINT; type: TypeDesc;
  497. BEGIN
  498. Machine.Acquire(Machine.Modules);
  499. i := 0;
  500. WHILE (i < LEN(m.typeInfo)) & (m.typeInfo[i].name # name) DO INC(i) END;
  501. IF i = LEN(m.typeInfo) THEN
  502. type := NIL
  503. ELSE
  504. type := m.typeInfo[i]
  505. END;
  506. Machine.Release(Machine.Modules);
  507. RETURN type
  508. END ThisType;
  509. PROCEDURE ThisTypeByAdr*(adr: ADDRESS; VAR m: Module; VAR t: TypeDesc);
  510. BEGIN
  511. IF adr # 0 THEN
  512. Machine.Acquire(Machine.Modules);
  513. SYSTEM.GET (adr + Heaps.TypeDescOffset, adr);
  514. t := SYSTEM.VAL(TypeDesc, adr);
  515. m := t.mod;
  516. Machine.Release(Machine.Modules)
  517. ELSE
  518. m := NIL; t := NIL
  519. END
  520. END ThisTypeByAdr;
  521. (** create a new object given its type descriptor *)
  522. PROCEDURE NewObj*(t : TypeDesc; isRealtime: BOOLEAN) : ANY;
  523. VAR x : ANY;
  524. BEGIN
  525. Heaps.NewRec(x, SYSTEM.VAL (ADDRESS, t.tag), isRealtime);
  526. RETURN x;
  527. END NewObj;
  528. (** return the type descriptor of an object *)
  529. PROCEDURE TypeOf*(obj : ANY): TypeDesc;
  530. VAR
  531. m : Module;
  532. t : TypeDesc;
  533. adr : ADDRESS;
  534. BEGIN
  535. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.TypeDescOffset, adr);
  536. ThisTypeByAdr(adr, m, t);
  537. RETURN t;
  538. END TypeOf;
  539. (** searches for the given pc in the global ProcKeyTable, if found it returns the corresponding data element *)
  540. PROCEDURE FindProc*(pc: ADDRESS; p: ProcedureDescs): ProcedureDescPointer;
  541. VAR l,r,x: LONGINT; isHit: BOOLEAN;
  542. BEGIN
  543. IF p # NIL THEN
  544. l := 0; r := LEN(p)-1;
  545. REPEAT
  546. x := (l + r) DIV 2;
  547. IF pc < p[x].pcFrom THEN r := x - 1 ELSE l := x + 1 END;
  548. isHit := ((p[x].pcFrom <= pc) & (pc < p[x].pcLimit));
  549. UNTIL isHit OR (l > r);
  550. IF isHit THEN
  551. RETURN p[x];
  552. END;
  553. END;
  554. RETURN NIL;
  555. END FindProc;
  556. (** 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. *)
  557. PROCEDURE InstallTermHandler*(h: TerminationHandler);
  558. VAR m: Module;
  559. BEGIN
  560. m := ThisModuleByAdr(SYSTEM.VAL (ADDRESS, h));
  561. IF m # NIL THEN
  562. m.term := h (* overwrite existing handler, if any *)
  563. END
  564. END InstallTermHandler;
  565. (** 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. *)
  566. PROCEDURE FreeModule*(CONST name: ARRAY OF CHAR; VAR res: LONGINT; VAR msg: ARRAY OF CHAR);
  567. VAR p, m: Module; term: TerminationHandler; i: LONGINT;
  568. BEGIN
  569. m := ModuleByName(name);
  570. IF (m # NIL) & (m.refcnt = 0) THEN (* will be freed below *)
  571. IF m.term # NIL THEN (* call termination handler *)
  572. term := m.term; m.term := NIL; term (* may trap *)
  573. END;
  574. Heaps.CleanupModuleFinalizers(ADDRESSOF(m.code[0]), LEN(m.code), m.name)
  575. END;
  576. res := Ok; msg[0] := 0X;
  577. Machine.Acquire(Machine.Modules);
  578. Trace.String("Acquired Machine.Modules x"); Trace.Ln;
  579. p := NIL; m := root;
  580. WHILE (m # NIL) & (m.name # name) DO p := m; m := m.next END;
  581. Trace.String("Acquired Machine.Modules y"); Trace.Ln;
  582. IF m # NIL THEN
  583. Trace.String("found module"); Trace.Ln;
  584. IF m.refcnt = 0 THEN (* free the module *)
  585. FOR i := 0 TO LEN(m.module)-1 DO DEC(m.module[i].refcnt) END;
  586. m.init := FALSE; (* disallow ThisCommand *)
  587. Append("?", m.name);
  588. (* move module to free list *)
  589. IF p = NIL THEN root := root.next ELSE p.next := m.next END;
  590. m.next := freeRoot; freeRoot := m;
  591. (* clear global pointers and code *)
  592. IF m.ptrAdr # NIL THEN
  593. Trace.String("ptradr del"); Trace.Ln;
  594. FOR i := 0 TO LEN(m.ptrAdr)-1 DO SYSTEM.PUT (m.ptrAdr[i], NIL) END;
  595. END;
  596. IF ClearCode & (m.code # NIL) THEN
  597. Trace.String("clear code"); Trace.Ln;
  598. FOR i := 0 TO LEN(m.code)-1 DO m.code[i] := 0CCX END
  599. END;
  600. Trace.String("clear code f"); Trace.Ln;
  601. (* remove references to module data *)
  602. m.published := FALSE;
  603. m.entry := NIL; m.command := NIL; m.ptrAdr := NIL;
  604. (* do not clear m.type or m.module, as old heap block tags might reference type descs indirectly. *) (* m.staticTypeDescs, m.typeInfo ??? *)
  605. (* do not clear m.data or m.code, as they are used in ThisModuleByAdr (for debugging). *)
  606. (* do not clear m.refs, as they are used in Traps (for debugging). *)
  607. m.export.dsc := NIL; m.exTable := NIL;
  608. (*Trace.String("delete proc offsets"); Trace.Ln;
  609. DeleteProcOffsets(m.firstProc, m.noProcs);
  610. *)
  611. RemoveProcedureDescs(m.procedureDescs);
  612. ELSE
  613. res := 1901; (* can not free module in use *)
  614. COPY(name, msg); Append(" reference count not zero", msg)
  615. END
  616. ELSE
  617. res := 1902; (* module not found *)
  618. COPY(name, msg); Append(" not found", msg)
  619. END;
  620. Machine.Release(Machine.Modules)
  621. END FreeModule;
  622. (** Shut down all modules by calling their termination handlers and then call Machine.Shutdown. *)
  623. PROCEDURE Shutdown*(code: LONGINT);
  624. VAR m: Module; term: TerminationHandler;
  625. BEGIN
  626. IF code # None THEN
  627. LOOP
  628. Machine.Acquire(Machine.Modules);
  629. m := root; WHILE (m # NIL) & (m.term = NIL) DO m := m.next END;
  630. IF m # NIL THEN term := m.term; m.term := NIL END;
  631. Machine.Release(Machine.Modules);
  632. IF m = NIL THEN EXIT END;
  633. IF trace THEN
  634. Machine.Acquire (Machine.TraceOutput);
  635. Trace.String("TermHandler "); Trace.StringLn (m.name);
  636. Machine.Release (Machine.TraceOutput);
  637. END;
  638. term (* if this causes exception or hangs, another shutdown call will retry *)
  639. END;
  640. (* clean up finalizers *)
  641. m := root;
  642. WHILE m # NIL DO
  643. IF LEN(m.code)>0 THEN
  644. Heaps.CleanupModuleFinalizers(ADDRESSOF(m.code[0]), LEN(m.code), m.name)
  645. END;
  646. m := m.next
  647. END;
  648. IF trace THEN
  649. Machine.Acquire (Machine.TraceOutput);
  650. Trace.StringLn ("Modules.Shutdown finished");
  651. Machine.Release (Machine.TraceOutput);
  652. END;
  653. Machine.Shutdown(code = Reboot) (* does not return *)
  654. END
  655. END Shutdown;
  656. (* Is this PC handled in the corresponding module. deep = scan the whole stack. *)
  657. PROCEDURE IsExceptionHandled*(VAR pc, fp: ADDRESS; deep: BOOLEAN): BOOLEAN;
  658. VAR
  659. handler: ADDRESS;
  660. BEGIN
  661. IF deep THEN
  662. handler := GetExceptionHandler(pc);
  663. IF handler # -1 THEN (* Handler in the current PAF *)
  664. RETURN TRUE
  665. ELSE
  666. WHILE (fp # 0) & (handler = -1) DO
  667. SYSTEM.GET (fp + 4, pc);
  668. pc := pc - 1; (* CALL instruction, machine dependant!!! *)
  669. handler := GetExceptionHandler(pc);
  670. SYSTEM.GET (fp, fp) (* Unwind PAF *)
  671. END;
  672. IF handler = -1 THEN RETURN FALSE ELSE pc := handler; RETURN TRUE END
  673. END
  674. ELSE
  675. RETURN GetExceptionHandler(pc) # -1
  676. END
  677. END IsExceptionHandled;
  678. (* Is this PC handled in the corresponding module. If the PC is handled the PC of the
  679. handler is return else -1 is return. There is no problem concurrently accessing this
  680. procedure, there is only reading work. *)
  681. PROCEDURE GetExceptionHandler*(pc: ADDRESS): ADDRESS;
  682. VAR
  683. m: Module;
  684. PROCEDURE BinSearch(exTable: ExceptionTable; key: ADDRESS): ADDRESS;
  685. VAR
  686. x, l, r: LONGINT;
  687. BEGIN
  688. l := 0; r:=LEN(exTable) - 1;
  689. REPEAT
  690. x := (l + r) DIV 2;
  691. IF key < exTable[x].pcFrom THEN r := x - 1 ELSE l := x + 1 END;
  692. UNTIL ((key >= exTable[x].pcFrom) & (key < exTable[x].pcTo) ) OR (l > r);
  693. IF (key >= exTable[x].pcFrom) & (key < exTable[x].pcTo) THEN
  694. RETURN exTable[x].pcHandler;
  695. ELSE
  696. RETURN -1;
  697. END
  698. END BinSearch;
  699. BEGIN
  700. m := ThisModuleByAdr(pc);
  701. IF (m # NIL) & (m.exTable # NIL) & (LEN(m.exTable) > 0) THEN
  702. RETURN BinSearch(m.exTable, pc);
  703. END;
  704. RETURN -1;
  705. END GetExceptionHandler;
  706. (** fof: to make custom solutions to the race process, described below, possible. This is not a solution to the generic problem !! *)
  707. PROCEDURE Initialized*(m: Module): BOOLEAN;
  708. BEGIN
  709. RETURN m.init;
  710. END Initialized;
  711. (** Return the specified kernel procedure address. *)
  712. PROCEDURE GetKernelProc*(num: LONGINT): ADDRESS;
  713. VAR adr: ADDRESS;
  714. BEGIN
  715. adr := kernelProc[253-num];
  716. ASSERT(adr # 0);
  717. RETURN adr
  718. END GetKernelProc;
  719. PROCEDURE Register- (module {UNTRACED}: Module);
  720. BEGIN {UNCOOPERATIVE, UNCHECKED}
  721. (*TRACE(module.name);*)
  722. IF register.first = NIL THEN
  723. register.first := module;
  724. ELSE
  725. register.last.next := module;
  726. END;
  727. register.last := module;
  728. END Register;
  729. PROCEDURE PublishRegisteredModules;
  730. VAR m {UNTRACED}, prev {UNTRACED}, cur {UNTRACED}: Module; import: SIZE;
  731. BEGIN
  732. WHILE register.first # NIL DO
  733. m := register.first;
  734. register.first := m.next;
  735. m.next := NIL;
  736. IF m.module # NIL THEN
  737. FOR import := 0 TO LEN (m.module) - 1 DO
  738. IF ~m.module[import].published THEN
  739. ASSERT(register.first # NIL);
  740. prev := NIL;
  741. cur := register.first;
  742. WHILE (cur # NIL) & (cur # m.module[import]) DO
  743. prev := cur;
  744. cur := cur.next
  745. END;
  746. (*ASSERT(cur = m.module[import]);*)
  747. ASSERT(cur = m.module[import]);
  748. IF prev = NIL THEN
  749. register.first := cur.next
  750. ELSE
  751. prev.next := cur.next;
  752. END;
  753. cur.next := NIL;
  754. Initialize0 (m.module[import]);
  755. END
  756. END;
  757. END;
  758. Initialize0 (m);
  759. END;
  760. END PublishRegisteredModules;
  761. (* procedure that will be called last in a linked kernel *)
  762. PROCEDURE {FINAL, NOPAF} Main;
  763. BEGIN
  764. (*Machine.Init;*)
  765. Trace.String("publish registered modules"); Trace.Ln;
  766. PublishRegisteredModules;
  767. END Main;
  768. PROCEDURE Init;
  769. VAR
  770. newArr: PROCEDURE (VAR p: ANY; elemTag: ADDRESS; numElems, numDims: SIZE; isRealtime: BOOLEAN);
  771. newSys: PROCEDURE (VAR p: ANY; size: SIZE; isRealtime: BOOLEAN);
  772. newRec: PROCEDURE (VAR p: ANY; tag: ADDRESS; isRealtime: BOOLEAN);
  773. getProcedure: PROCEDURE(CONST m, p : ARRAY OF CHAR; argTdAdr, retTdAdr : ADDRESS; VAR entryAdr : ADDRESS);
  774. s: ARRAY 4 OF CHAR;
  775. module: Module;
  776. BEGIN
  777. (* root and initBlock are initialized by the linker *)
  778. shutdown := None;
  779. newArr := Heaps.NewArr;
  780. newSys := Heaps.NewSys;
  781. newRec := Heaps.NewRec;
  782. getProcedure := GetProcedure;
  783. kernelProc[0] := SYSTEM.VAL (ADDRESS, newRec); (* 253 *)
  784. kernelProc[1] := SYSTEM.VAL (ADDRESS, newSys); (* 252 *)
  785. kernelProc[2] := SYSTEM.VAL (ADDRESS, newArr); (* 251 *)
  786. kernelProc[3] := 0; (* 250 *)
  787. kernelProc[4] := 0; (* 249 *)
  788. kernelProc[5] := 0; (* 248 *)
  789. kernelProc[6] := 0; (* 247 *)
  790. kernelProc[7] := 0; (* 246 *)
  791. kernelProc[8] := 0; (* 245 *)
  792. kernelProc[9] := 0; (* 244 *)
  793. kernelProc[10] := SYSTEM.VAL(ADDRESS, getProcedure); (* 243 *)
  794. numLoaders := 0;
  795. freeRoot := NIL;
  796. Machine.GetConfig("TraceModules", s);
  797. trace := (s[0] = "1");
  798. module := root;
  799. WHILE (module # NIL) DO
  800. MergeProcedureDescs(module.procTable);
  801. module := module.next;
  802. END;
  803. mayAllocate := TRUE;
  804. (*
  805. FOR i := 0 TO Runtime.modules-1 DO
  806. module := SYSTEM.VAL(Module,Runtime.kernelModule[i]);
  807. IF TraceBoot THEN
  808. Trace.String("publishing module ");
  809. Trace.String(module.name); Trace.Ln;
  810. END;
  811. Publish(module,new);
  812. ASSERT(new,112233);
  813. END;
  814. *)
  815. (*
  816. module := SYSTEM.VAL(Module,SELF);
  817. Publish(module,new);
  818. *)
  819. END Init;
  820. BEGIN
  821. Init;
  822. END Modules.
  823. (*
  824. 19.03.1998 pjm Started
  825. 06.10.1998 pjm FreeModule
  826. Note:
  827. o GetProcedure race: process A calls ThisModule, the module is published, but before its body has finished executing, process B calls GetProcedure, causing the assert (m.init) to fail. Process B should perhaps wait in this case until the body has executed, or GetProcedure should return NIL (but that will just move the race to the user).
  828. *)