Generic.Modules.Mod 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014
  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=FALSE;
  19. (* flags *)
  20. PreciseGC* = 0;
  21. TYPE
  22. (* definitions for object-model loader support *)
  23. Name* = ARRAY 32 OF CHAR;
  24. (* the correponding name array is protected from being GCed via module's internal pointer arrray
  25. compiler generated!
  26. *)
  27. DynamicName* = POINTER {UNSAFE} TO ARRAY 256 OF CHAR;
  28. Command* = RECORD
  29. (* Fields exported for initialization by loader/linker only! Consider read-only! *)
  30. name*: Name; (* name of the procedure *)
  31. argTdAdr*, retTdAdr* : ADDRESS; (* address of type descriptors of argument and return type, 0 if no type *)
  32. entryAdr* : ADDRESS; (* entry address of procedure *)
  33. END;
  34. ExportDesc* = RECORD
  35. fp*: ADDRESS;
  36. name* {UNTRACED}: DynamicName;
  37. adr*: ADDRESS;
  38. exports*: LONGINT; (* number of exports referenced by ExportArray *)
  39. dsc* {UNTRACED}: ExportArray; (* pointer to memory containing a raw array with "exports" entries *)
  40. END;
  41. ExportArray* = POINTER {UNSAFE} TO ARRAY OF ExportDesc;
  42. Bytes* = POINTER TO ARRAY OF CHAR;
  43. TerminationHandler* = PROCEDURE;
  44. (* all implicit or explicit pointers in the subsequent data structures are protected with one pointer array
  45. *)
  46. TypeDesc* = POINTER TO RECORD
  47. descSize-: SIZE;
  48. sentinel-: LONGINT; (* = MPO-4 *)
  49. tag-: ADDRESS; (* pointer to static type descriptor, only used by linker and loader *)
  50. flags-: SET;
  51. mod- {UNTRACED}: Module; (* hint only, because module may have been freed (at Heaps.ModOfs) *)
  52. name-: Name;
  53. refsOffset-: SIZE;
  54. END;
  55. ExceptionTableEntry* = RECORD
  56. pcFrom*: ADDRESS;
  57. pcTo*: ADDRESS;
  58. pcHandler*: ADDRESS;
  59. END;
  60. ExceptionTable* = POINTER TO ARRAY OF ExceptionTableEntry;
  61. ProcedureDescPointer* = POINTER TO ProcedureDesc;
  62. ProcedureDesc*= RECORD
  63. pcFrom-, pcLimit-: ADDRESS;
  64. offsets- {UNTRACED}: POINTER TO ARRAY OF ADDRESS;
  65. END;
  66. ProcedureDescs* = POINTER TO ARRAY OF ProcedureDescPointer;
  67. Module* = OBJECT (Heaps.RootObject) (* cf. Linker0 & Heaps.WriteType *)
  68. VAR
  69. next*: Module; (** once a module is published, all fields are read-only *)
  70. name*: Name;
  71. init, published: BOOLEAN;
  72. refcnt*: LONGINT; (* counts loaded modules that import this module *)
  73. sb*: ADDRESS; (* reference address between constants and local variables *)
  74. entry*: POINTER TO ARRAY OF ADDRESS;
  75. command*: POINTER TO ARRAY OF Command;
  76. ptrAdr*: POINTER TO ARRAY OF ADDRESS; (* traced explicitly in FindRoots *)
  77. typeInfo*: POINTER TO ARRAY OF TypeDesc;
  78. module*: POINTER TO ARRAY OF Module; (* imported modules: for reference counting *)
  79. procTable*: ProcedureDescs; (* information inserted by loader, sorted by pc after loading *)
  80. data*, code*, staticTypeDescs* (* ug *), refs*: Bytes;
  81. export*: ExportDesc;
  82. term*: TerminationHandler;
  83. exTable*: ExceptionTable;
  84. (* internal pointer array: to protect internal data structures from being GCed *)
  85. internal-: POINTER TO ARRAY OF ANY;
  86. crc*: LONGINT;
  87. body*: PROCEDURE;
  88. flags*: SET; (* e.g. compilation flags *)
  89. PROCEDURE FindRoots; (* override *)
  90. VAR i: LONGINT; ptr: ANY; false: BOOLEAN;
  91. VAR name: Name;
  92. BEGIN
  93. name := SELF.name;
  94. false := FALSE; IF false THEN BEGIN{EXCLUSIVE} END END; (* trick to make a module a protected record ... *)
  95. IF published THEN (* mark global pointers *)
  96. FOR i := 0 TO LEN(ptrAdr) - 1 DO
  97. SYSTEM.GET (ptrAdr[i], ptr);
  98. IF ptr # NIL THEN Heaps.Mark(ptr) END
  99. END;
  100. Heaps.AddRootObject(next);
  101. (* all other fields are being traversed by Mark of the Garbage Collector *)
  102. END;
  103. END FindRoots;
  104. END Module;
  105. LoaderProc* = PROCEDURE (CONST name, fileName: ARRAY OF CHAR; VAR res: LONGINT;
  106. VAR msg: ARRAY OF CHAR): Module; (** load an object file *)
  107. VAR
  108. extension-: ARRAY MaxObjFormats, 8 OF CHAR;
  109. loader: ARRAY MaxObjFormats OF LoaderProc;
  110. numLoaders: LONGINT;
  111. freeRoot*: Module; (** list of freed modules (temporary) *)
  112. root-: Module; (** list of modules (read-only) *)
  113. shutdown*: LONGINT; (** None, Reboot, PowerDown *)
  114. trace: BOOLEAN;
  115. register: RECORD
  116. first, last: Module;
  117. END;
  118. (* global sorted table of all procedures , basically for GC *)
  119. procedureDescriptors-: ProcedureDescs;
  120. (** Register a module loader. *)
  121. PROCEDURE AddLoader*(CONST ext: ARRAY OF CHAR; proc: LoaderProc);
  122. BEGIN
  123. Machine.Acquire(Machine.Modules);
  124. ASSERT(numLoaders < MaxObjFormats);
  125. loader[numLoaders] := proc;
  126. COPY(ext, extension[numLoaders]);
  127. ASSERT(ext = extension[numLoaders]); (* no overflow *)
  128. INC(numLoaders);
  129. Machine.Release(Machine.Modules)
  130. END AddLoader;
  131. (** Remove a module loader. *)
  132. PROCEDURE RemoveLoader*(CONST ext: ARRAY OF CHAR; proc: LoaderProc);
  133. VAR i, j: LONGINT;
  134. BEGIN
  135. Machine.Acquire(Machine.Modules);
  136. i := 0;
  137. WHILE (i # numLoaders) & ((loader[i] # proc) OR (extension[i] # ext)) DO INC(i) END;
  138. IF i # numLoaders THEN
  139. FOR j := i TO numLoaders - 2 DO
  140. loader[j] := loader[j + 1]; extension[j] := extension[j + 1];
  141. END;
  142. loader[numLoaders - 1] := NIL; extension[numLoaders - 1] := "";
  143. DEC(numLoaders)
  144. END;
  145. Machine.Release(Machine.Modules)
  146. END RemoveLoader;
  147. (** Append string from to to, truncating on overflow. *)
  148. PROCEDURE Append*(CONST from: ARRAY OF CHAR; VAR to: ARRAY OF CHAR);
  149. VAR i, j, m: LONGINT;
  150. BEGIN
  151. j := 0; WHILE to[j] # 0X DO INC(j) END;
  152. m := LEN(to)-1;
  153. i := 0; WHILE (from[i] # 0X) & (j # m) DO to[j] := from[i]; INC(i); INC(j) END;
  154. to[j] := 0X
  155. END Append;
  156. (** Add a module to the pool of accessible modules, or return named module. *)
  157. PROCEDURE Publish*(VAR m: Module; VAR new: BOOLEAN);
  158. VAR n: Module; i: LONGINT; name: Name;
  159. BEGIN
  160. Machine.Acquire(Machine.Modules);
  161. n := root; WHILE (n # NIL) & (n.name # m.name) DO n := n.next END;
  162. IF n # NIL THEN (* module with same name exists, return it and ignore new m *)
  163. m := n; new := FALSE
  164. ELSE
  165. IF TraceBoot OR trace THEN
  166. Machine.Acquire(Machine.TraceOutput);
  167. Trace.String("publish "); Trace.String(m.name);
  168. Trace.Ln;
  169. Machine.Release(Machine.TraceOutput);
  170. END;
  171. Unregister(m);
  172. m.published := TRUE;
  173. m.next := root; root := m;
  174. m.refcnt := 0;
  175. SortExceptionTable(m.exTable);
  176. SortProcedureDescs(m.procTable);
  177. IF m.module # NIL THEN
  178. FOR i := 0 TO LEN(m.module)-1 DO INC(m.module[i].refcnt) END;
  179. END;
  180. new := TRUE;
  181. END;
  182. Machine.Release(Machine.Modules);
  183. IF (Heaps.GCType = Heaps.MetaDataForStackGC) & ~(PreciseGC IN m.flags) THEN
  184. name := m.name;
  185. HALT(100);
  186. END;
  187. END Publish;
  188. PROCEDURE Initialize*(VAR module: Module);
  189. VAR new: BOOLEAN; import: LONGINT;
  190. BEGIN
  191. IF (module = NIL) THEN RETURN END;
  192. Publish (module, new);
  193. IF new THEN
  194. FOR import := 0 TO LEN (module.module) - 1 DO
  195. IF ~module.module[import].published THEN
  196. ASSERT(register.first # NIL);
  197. Initialize(module.module[import]);
  198. END
  199. END;
  200. IF (module.code # NIL) & (LEN(module.code) > 0) THEN
  201. Machine.FlushDCacheRange(ADDRESSOF(module.code[0]), LEN(module.code));
  202. END;
  203. IF module.body # NIL THEN
  204. module.body
  205. END;
  206. module.init := TRUE;
  207. END;
  208. END Initialize;
  209. VAR callagain: BOOLEAN;
  210. PROCEDURE Initialize0*(module: Module);
  211. VAR new: BOOLEAN;
  212. BEGIN
  213. (*TRACE(module.name);*)
  214. (* module MUST have been removed from register list and must not have been initialized yet *)
  215. (* ASSERT(module.next = NIL); *)
  216. Publish (module, new);
  217. callagain := FALSE;
  218. IF new THEN
  219. IF module.name = "Objects" THEN
  220. callagain := TRUE;
  221. module.init := TRUE;
  222. END;
  223. (*
  224. Trace.Memory(SYSTEM.VAL(ADDRESS, module), 256);
  225. TRACE(module, module.name, module.body);
  226. TRACE(module);
  227. TRACE(ADDRESS OF module.next);
  228. TRACE(ADDRESS OF module.name);
  229. TRACE(ADDRESS OF module.init);
  230. TRACE(ADDRESS OF module.published);
  231. TRACE(ADDRESS OF module.body);
  232. TRACE(ADDRESS OF module.refcnt);
  233. TRACE(ADDRESS OF module.sb);
  234. TRACE(ADDRESS OF module.entry);
  235. TRACE(ADDRESS OF module.command);
  236. TRACE(ADDRESS OF module.ptrAdr);
  237. TRACE(ADDRESS OF module.typeInfo);
  238. TRACE(ADDRESS OF module.module);
  239. TRACE(ADDRESS OF module.procTable);
  240. TRACE(ADDRESS OF module.ptrTable);
  241. TRACE(ADDRESS OF module.data);
  242. TRACE(ADDRESS OF module.code);
  243. TRACE(ADDRESS OF module.staticTypeDescs);
  244. TRACE(ADDRESS OF module.refs);
  245. TRACE(ADDRESS OF module.export);
  246. TRACE(ADDRESS OF module.term);
  247. TRACE(ADDRESS OF module.exTable);
  248. TRACE(ADDRESS OF module.noProcs);
  249. TRACE(ADDRESS OF module.firstProc);
  250. TRACE(ADDRESS OF module.maxPtrs);
  251. TRACE(ADDRESS OF module.crc);
  252. TRACE(ADDRESS OF module.body);
  253. *)
  254. IF module.body # NIL THEN module.body END;
  255. IF callagain THEN
  256. 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 *)
  257. ELSE
  258. module.init := TRUE;
  259. END;
  260. END;
  261. END Initialize0;
  262. (** Return the named module or NIL if it is not loaded yet. *)
  263. PROCEDURE ModuleByName*(CONST name: ARRAY OF CHAR): Module;
  264. VAR m: Module;
  265. BEGIN
  266. Machine.Acquire(Machine.Modules);
  267. m := root; WHILE (m # NIL) & (m.name # name) DO m := m.next END;
  268. Machine.Release(Machine.Modules);
  269. RETURN m
  270. END ModuleByName;
  271. PROCEDURE ByName(CONST name: ARRAY OF CHAR; VAR referenced: BOOLEAN): Module;
  272. VAR m: Module;
  273. BEGIN
  274. Machine.Acquire(Machine.Modules);
  275. referenced := FALSE;
  276. m := root; WHILE (m # NIL) & (m.name # name) DO m := m.next END;
  277. IF m = NIL THEN
  278. referenced := TRUE;
  279. m := register.first; WHILE (m#NIL) & (m.name # name) DO m := m.next END;
  280. END;
  281. Machine.Release(Machine.Modules);
  282. RETURN m
  283. END ByName;
  284. (* Generate a module file name. *)
  285. PROCEDURE GetFileName(CONST name, extension: ARRAY OF CHAR; VAR fileName: ARRAY OF CHAR);
  286. VAR i, j: LONGINT;
  287. BEGIN
  288. i := 0; WHILE name[i] # 0X DO fileName[i] := name[i]; INC(i) END;
  289. j := 0; WHILE extension[j] # 0X DO fileName[i] := extension[j]; INC(i); INC(j) END;
  290. fileName[i] := 0X
  291. END GetFileName;
  292. (* sort procedure descriptors by firstPC in ascending order *)
  293. PROCEDURE SortProcedureDescs(p: ProcedureDescs);
  294. PROCEDURE Less(i,j: LONGINT): BOOLEAN;
  295. BEGIN
  296. RETURN p[i].pcFrom < p[j].pcFrom;
  297. END Less;
  298. PROCEDURE Swap(i,j: LONGINT);
  299. VAR tmp: ProcedureDescPointer;
  300. BEGIN
  301. tmp := p[i];
  302. p[i] := p[j];
  303. p[j] := tmp;
  304. END Swap;
  305. PROCEDURE Quick( lo, hi: LONGINT);
  306. VAR i, j, m: LONGINT;
  307. BEGIN
  308. IF lo < hi THEN
  309. i := lo; j := hi; m := (lo + hi) DIV 2;
  310. REPEAT
  311. WHILE Less( i, m ) DO INC( i ) END;
  312. WHILE Less( m, j ) DO DEC( j ) END;
  313. IF i <= j THEN
  314. IF m = i THEN m := j
  315. ELSIF m = j THEN m := i
  316. END;
  317. Swap( i, j ); INC( i ); DEC( j )
  318. END
  319. UNTIL i > j;
  320. Quick( lo, j); Quick( i, hi)
  321. END;
  322. END Quick;
  323. BEGIN
  324. Quick(0, LEN(p)-1);
  325. END SortProcedureDescs;
  326. (* sort procedure descriptors by firstPC in ascending order *)
  327. PROCEDURE SortExceptionTable(p: ExceptionTable);
  328. PROCEDURE Less(i,j: LONGINT): BOOLEAN;
  329. BEGIN
  330. RETURN p[i].pcFrom < p[j].pcFrom;
  331. END Less;
  332. PROCEDURE Swap(i,j: LONGINT);
  333. VAR tmp: ExceptionTableEntry;
  334. BEGIN
  335. tmp := p[i];
  336. p[i] := p[j];
  337. p[j] := tmp;
  338. END Swap;
  339. PROCEDURE Quick( lo, hi: LONGINT);
  340. VAR i, j, m: LONGINT;
  341. BEGIN
  342. IF lo < hi THEN
  343. i := lo; j := hi; m := (lo + hi) DIV 2;
  344. REPEAT
  345. WHILE Less( i, m ) DO INC( i ) END;
  346. WHILE Less( m, j ) DO DEC( j ) END;
  347. IF i <= j THEN
  348. IF m = i THEN m := j
  349. ELSIF m = j THEN m := i
  350. END;
  351. Swap( i, j ); INC( i ); DEC( j )
  352. END
  353. UNTIL i > j;
  354. Quick( lo, j); Quick( i, hi)
  355. END;
  356. END Quick;
  357. BEGIN
  358. Quick(0, LEN(p)-1);
  359. END SortExceptionTable;
  360. (** Load the module if it is not already loaded. *) (* Algorithm J. Templ, ETHZ, 1994 *)
  361. PROCEDURE ThisModule*(CONST name: ARRAY OF CHAR; VAR res: LONGINT; VAR msg: ARRAY OF CHAR): Module;
  362. VAR m: Module; fileName: ARRAY 64 OF CHAR; i: LONGINT; registered: BOOLEAN;
  363. BEGIN
  364. res := Ok; msg[0] := 0X; m := ByName(name, registered);
  365. IF (m#NIL) & (registered) THEN
  366. IF trace THEN
  367. Machine.Acquire (Machine.TraceOutput);
  368. Trace.String(">R>"); Trace.StringLn (name);
  369. Machine.Release (Machine.TraceOutput);
  370. END;
  371. IF ~m.published THEN (* no race on m.published, as update is done in Publish *)
  372. Initialize(m);
  373. END;
  374. IF trace THEN
  375. Machine.Acquire (Machine.TraceOutput);
  376. Trace.String("<R<"); Trace.StringLn (name);
  377. Machine.Release (Machine.TraceOutput);
  378. END;
  379. ELSIF m = NIL THEN
  380. IF trace THEN
  381. Machine.Acquire (Machine.TraceOutput);
  382. Trace.String(">L>"); Trace.StringLn (name);
  383. Machine.Release (Machine.TraceOutput);
  384. END;
  385. IF numLoaders = 0 THEN
  386. res := NoLoader; m := NIL;
  387. ELSE
  388. i:= 0;
  389. REPEAT
  390. GetFileName(name, extension[i], fileName);
  391. m := loader[i](name, fileName, res, msg);
  392. INC(i);
  393. UNTIL (m # NIL) OR (i=numLoaders);
  394. END;
  395. IF trace THEN
  396. Machine.Acquire (Machine.TraceOutput);
  397. Trace.String("?"); Trace.StringLn (name);
  398. Machine.Release (Machine.TraceOutput);
  399. END;
  400. IF (m # NIL) & ~m.published THEN (* no race on m.published, as update is done below in Publish *)
  401. Initialize(m);
  402. END;
  403. IF trace THEN
  404. Machine.Acquire (Machine.TraceOutput);
  405. IF m = NIL THEN
  406. Trace.String("could not load "); Trace.StringLn(name)
  407. ELSIF ~m.published THEN
  408. Trace.String("not published "); Trace.StringLn(name)
  409. ELSE
  410. Trace.String("<L<"); Trace.StringLn (name);
  411. END;
  412. Machine.Release (Machine.TraceOutput);
  413. END;
  414. END;
  415. RETURN m
  416. END ThisModule;
  417. (** Return the module that contains code address pc or NIL if not found. Can also return freed modules. Non-blocking version for reflection *)
  418. PROCEDURE ThisModuleByAdr0*(pc: ADDRESS): Module;
  419. VAR m: Module; found: BOOLEAN; list: LONGINT;
  420. BEGIN
  421. list := 0; found := FALSE;
  422. REPEAT
  423. CASE list OF
  424. 0: m := root
  425. |1: m := freeRoot
  426. END;
  427. WHILE (m # NIL) & ~found DO
  428. found := FindProc(pc, m.procTable) # NIL;
  429. IF ~found THEN m := m.next END;
  430. END;
  431. INC(list)
  432. UNTIL found OR (list=2);
  433. RETURN m
  434. END ThisModuleByAdr0;
  435. (** Return the module that contains code address pc or NIL if not found. Can also return freed modules. *)
  436. PROCEDURE ThisModuleByAdr*(pc: ADDRESS): Module;
  437. VAR m: Module;
  438. BEGIN
  439. Machine.Acquire(Machine.Modules);
  440. m := ThisModuleByAdr0(pc);
  441. Machine.Release(Machine.Modules);
  442. RETURN m
  443. END ThisModuleByAdr;
  444. CONST ModuleInitTimeout = HUGEINT(3000000000); (* Timeout for waiting until a module get initialized, 3 seconds for 1 GHz CPU *)
  445. (* Retrieve a procedure given a module name, the procedure name and some type information (kernel call) *)
  446. PROCEDURE GetProcedure*(CONST moduleName, procedureName : ARRAY OF CHAR; argTdAdr, retTdAdr : ADDRESS; VAR entryAdr : ADDRESS);
  447. VAR module : Module; ignoreMsg : ARRAY 32 OF CHAR; i, res : LONGINT; t: HUGEINT;
  448. BEGIN
  449. module := ThisModule(moduleName, res, ignoreMsg);
  450. IF (res = Ok) THEN
  451. (*!
  452. module body must have been called (see note at the end of this module);
  453. return NIL if the module does not get initialized within the specified timeout
  454. *)
  455. IF ~module.init THEN
  456. t := Machine.GetTimer();
  457. WHILE ~module.init & (Machine.GetTimer() - t < ModuleInitTimeout) DO END;
  458. IF ~module.init THEN (* timeout has expired *)
  459. RETURN;
  460. END;
  461. END;
  462. Machine.Acquire(Machine.Modules);
  463. i := 0; entryAdr := Heaps.NilVal;
  464. WHILE (entryAdr = Heaps.NilVal) & (i # LEN(module.command^)) DO
  465. IF (module.command[i].name = procedureName) & (module.command[i].argTdAdr = argTdAdr) & (module.command[i].retTdAdr = retTdAdr) THEN
  466. entryAdr := module.command[i].entryAdr;
  467. END;
  468. INC(i)
  469. END;
  470. Machine.Release(Machine.Modules);
  471. END;
  472. END GetProcedure;
  473. (** Return the named type *)
  474. PROCEDURE ThisType*(m: Module; CONST name: ARRAY OF CHAR): TypeDesc;
  475. VAR i: LONGINT; type: TypeDesc;
  476. BEGIN
  477. Machine.Acquire(Machine.Modules);
  478. i := 0;
  479. WHILE (i < LEN(m.typeInfo)) & (m.typeInfo[i].name # name) DO INC(i) END;
  480. IF i = LEN(m.typeInfo) THEN
  481. type := NIL
  482. ELSE
  483. type := m.typeInfo[i]
  484. END;
  485. Machine.Release(Machine.Modules);
  486. RETURN type
  487. END ThisType;
  488. PROCEDURE ThisTypeByAdr*(adr: ADDRESS; VAR m: Module; VAR t: TypeDesc);
  489. BEGIN
  490. IF adr # 0 THEN
  491. Machine.Acquire(Machine.Modules);
  492. SYSTEM.GET (adr + Heaps.TypeDescOffset, adr);
  493. t := SYSTEM.VAL(TypeDesc, adr);
  494. m := t.mod;
  495. Machine.Release(Machine.Modules)
  496. ELSE
  497. m := NIL; t := NIL
  498. END
  499. END ThisTypeByAdr;
  500. (** create a new object given its type descriptor *)
  501. PROCEDURE NewObj*(t : TypeDesc; isRealtime: BOOLEAN) : ANY;
  502. VAR x : ANY;
  503. BEGIN
  504. Heaps.NewRec(x, SYSTEM.VAL (ADDRESS, t.tag), isRealtime);
  505. RETURN x;
  506. END NewObj;
  507. (** return the type descriptor of an object *)
  508. PROCEDURE TypeOf*(obj : ANY): TypeDesc;
  509. VAR
  510. m : Module;
  511. t : TypeDesc;
  512. adr : ADDRESS;
  513. BEGIN
  514. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.TypeDescOffset, adr);
  515. ThisTypeByAdr(adr, m, t);
  516. RETURN t;
  517. END TypeOf;
  518. (** searches for the given pc in the global ProcKeyTable, if found it returns the corresponding data element *)
  519. PROCEDURE FindProc*(pc: ADDRESS; p: ProcedureDescs): ProcedureDescPointer;
  520. VAR l,r,x: LONGINT; isHit: BOOLEAN;
  521. BEGIN
  522. IF p # NIL THEN
  523. l := 0; r := LEN(p)-1;
  524. REPEAT
  525. x := (l + r) DIV 2;
  526. IF pc < p[x].pcFrom THEN r := x - 1 ELSE l := x + 1 END;
  527. isHit := ((p[x].pcFrom <= pc) & (pc < p[x].pcLimit));
  528. UNTIL isHit OR (l > r);
  529. IF isHit THEN
  530. RETURN p[x];
  531. END;
  532. END;
  533. RETURN NIL;
  534. END FindProc;
  535. (** 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. *)
  536. PROCEDURE InstallTermHandler*(h: TerminationHandler);
  537. VAR m: Module;
  538. BEGIN
  539. m := ThisModuleByAdr(SYSTEM.VAL (ADDRESS, h));
  540. IF m # NIL THEN
  541. m.term := h (* overwrite existing handler, if any *)
  542. END
  543. END InstallTermHandler;
  544. (** 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. *)
  545. PROCEDURE FreeModule*(CONST name: ARRAY OF CHAR; VAR res: LONGINT; VAR msg: ARRAY OF CHAR);
  546. VAR p, m: Module; term: TerminationHandler; i: LONGINT;
  547. BEGIN
  548. m := ModuleByName(name);
  549. IF (m # NIL) & (m.refcnt = 0) THEN (* will be freed below *)
  550. IF m.term # NIL THEN (* call termination handler *)
  551. term := m.term; m.term := NIL; term (* may trap *)
  552. END;
  553. IF m.code # NIL THEN
  554. Heaps.CleanupModuleFinalizers(ADDRESSOF(m.code[0]), LEN(m.code), m.name)
  555. END;
  556. END;
  557. res := Ok; msg[0] := 0X;
  558. Machine.Acquire(Machine.Modules);
  559. p := NIL; m := root;
  560. WHILE (m # NIL) & (m.name # name) DO p := m; m := m.next END;
  561. IF m # NIL THEN
  562. IF m.refcnt = 0 THEN (* free the module *)
  563. FOR i := 0 TO LEN(m.module)-1 DO DEC(m.module[i].refcnt) END;
  564. m.init := FALSE; (* disallow ThisCommand *)
  565. Append("?", m.name);
  566. (* move module to free list *)
  567. IF p = NIL THEN root := root.next ELSE p.next := m.next END;
  568. m.next := freeRoot; freeRoot := m;
  569. (* clear global pointers and code *)
  570. IF m.ptrAdr # NIL THEN
  571. Trace.String("ptradr del"); Trace.Ln;
  572. FOR i := 0 TO LEN(m.ptrAdr)-1 DO SYSTEM.PUT (m.ptrAdr[i], NIL) END;
  573. END;
  574. IF ClearCode & (m.code # NIL) THEN
  575. Trace.String("clear code"); Trace.Ln;
  576. FOR i := 0 TO LEN(m.code)-1 DO m.code[i] := 0CCX END
  577. END;
  578. Trace.String("clear code f"); Trace.Ln;
  579. (* remove references to module data *)
  580. m.published := FALSE;
  581. m.entry := NIL; m.command := NIL; m.ptrAdr := NIL;
  582. (* do not clear m.type or m.module, as old heap block tags might reference type descs indirectly. *) (* m.staticTypeDescs, m.typeInfo ??? *)
  583. (* do not clear m.data or m.code, as they are used in ThisModuleByAdr (for debugging). *)
  584. (* do not clear m.refs, as they are used in Traps (for debugging). *)
  585. m.export.dsc := NIL; m.exTable := NIL;
  586. ELSE
  587. res := 1901; (* can not free module in use *)
  588. COPY(name, msg); Append(" reference count not zero", msg)
  589. END
  590. ELSE
  591. res := 1902; (* module not found *)
  592. COPY(name, msg); Append(" not found", msg)
  593. END;
  594. Machine.Release(Machine.Modules)
  595. END FreeModule;
  596. (** Shut down all modules by calling their termination handlers and then call Machine.Shutdown. *)
  597. PROCEDURE Shutdown*(code: LONGINT);
  598. VAR m: Module; term: TerminationHandler;
  599. BEGIN
  600. IF code # None THEN
  601. LOOP
  602. Machine.Acquire(Machine.Modules);
  603. m := root; WHILE (m # NIL) & (m.term = NIL) DO m := m.next END;
  604. IF m # NIL THEN term := m.term; m.term := NIL END; (* finalizer only called once *)
  605. Machine.Release(Machine.Modules);
  606. IF m = NIL THEN EXIT END;
  607. IF trace THEN
  608. Machine.Acquire (Machine.TraceOutput);
  609. Trace.String("TermHandler "); Trace.StringLn (m.name);
  610. Machine.Release (Machine.TraceOutput);
  611. END;
  612. term (* if this causes exception or hangs, another shutdown call will retry *)
  613. END;
  614. (* clean up finalizers *)
  615. m := root;
  616. WHILE m # NIL DO
  617. IF (m.code # NIL) & (LEN(m.code)>0) THEN
  618. Heaps.CleanupModuleFinalizers(ADDRESSOF(m.code[0]), LEN(m.code), m.name)
  619. END;
  620. m := m.next
  621. END;
  622. IF trace THEN
  623. Machine.Acquire (Machine.TraceOutput);
  624. Trace.StringLn ("Modules.Shutdown finished");
  625. Machine.Release (Machine.TraceOutput);
  626. END;
  627. Machine.Shutdown(code = Reboot) (* does not return *)
  628. END
  629. END Shutdown;
  630. (* Is this PC handled in the corresponding module. deep = scan the whole stack. *)
  631. PROCEDURE IsExceptionHandled*(VAR pc, fp: ADDRESS; deep: BOOLEAN): BOOLEAN;
  632. VAR
  633. handler: ADDRESS;
  634. BEGIN
  635. IF deep THEN
  636. handler := GetExceptionHandler(pc);
  637. IF handler # -1 THEN (* Handler in the current PAF *)
  638. RETURN TRUE
  639. ELSE
  640. WHILE (fp # 0) & (handler = -1) DO
  641. SYSTEM.GET (fp + 4, pc);
  642. pc := pc - 1; (* CALL instruction, machine dependant!!! *)
  643. handler := GetExceptionHandler(pc);
  644. SYSTEM.GET (fp, fp) (* Unwind PAF *)
  645. END;
  646. IF handler = -1 THEN RETURN FALSE ELSE pc := handler; RETURN TRUE END
  647. END
  648. ELSE
  649. RETURN GetExceptionHandler(pc) # -1
  650. END
  651. END IsExceptionHandled;
  652. (* Is this PC handled in the corresponding module. If the PC is handled the PC of the
  653. handler is return else -1 is return. There is no problem concurrently accessing this
  654. procedure, there is only reading work. *)
  655. PROCEDURE GetExceptionHandler*(pc: ADDRESS): ADDRESS;
  656. VAR
  657. m: Module;
  658. PROCEDURE BinSearch(exTable: ExceptionTable; key: ADDRESS): ADDRESS;
  659. VAR
  660. x, l, r: LONGINT;
  661. BEGIN
  662. l := 0; r:=LEN(exTable) - 1;
  663. REPEAT
  664. x := (l + r) DIV 2;
  665. IF key < exTable[x].pcFrom THEN r := x - 1 ELSE l := x + 1 END;
  666. UNTIL ((key >= exTable[x].pcFrom) & (key < exTable[x].pcTo) ) OR (l > r);
  667. IF (key >= exTable[x].pcFrom) & (key < exTable[x].pcTo) THEN
  668. RETURN exTable[x].pcHandler;
  669. ELSE
  670. RETURN -1;
  671. END
  672. END BinSearch;
  673. BEGIN
  674. m := ThisModuleByAdr(pc);
  675. IF (m # NIL) & (m.exTable # NIL) & (LEN(m.exTable) > 0) THEN
  676. RETURN BinSearch(m.exTable, pc);
  677. END;
  678. RETURN -1;
  679. END GetExceptionHandler;
  680. (** fof: to make custom solutions to the race process, described below, possible. This is not a solution to the generic problem !! *)
  681. PROCEDURE Initialized*(m: Module): BOOLEAN;
  682. BEGIN
  683. RETURN m.init;
  684. END Initialized;
  685. PROCEDURE Register- (module {UNTRACED}: Module);
  686. BEGIN {UNCOOPERATIVE, UNCHECKED}
  687. (*TRACE(module.name);*)
  688. IF register.first = NIL THEN
  689. register.first := module;
  690. ELSE
  691. register.last.next := module;
  692. END;
  693. register.last := module;
  694. END Register;
  695. PROCEDURE Unregister(m: Module);
  696. VAR prev: Module;
  697. BEGIN
  698. ASSERT(m#NIL);
  699. IF register.first = NIL THEN RETURN
  700. ELSIF m = register.first THEN
  701. register.first := m.next;
  702. IF register.first = NIL THEN register.last := NIL END;
  703. ELSE
  704. prev := register.first;
  705. WHILE (prev.next # NIL) & (prev.next # m) DO
  706. prev := prev.next;
  707. END;
  708. IF prev.next = m THEN
  709. prev.next := prev.next.next;
  710. IF prev.next = NIL THEN register.last := prev END;
  711. END;
  712. END;
  713. m.next := NIL;
  714. END Unregister;
  715. PROCEDURE PublishRegisteredModules;
  716. VAR m {UNTRACED}, prev {UNTRACED}, cur {UNTRACED}: Module; import: SIZE;
  717. BEGIN
  718. WHILE register.first # NIL DO
  719. m := register.first;
  720. (*
  721. register.first := m.next;
  722. m.next := NIL;
  723. *)
  724. IF m.module # NIL THEN
  725. FOR import := 0 TO LEN (m.module) - 1 DO
  726. IF ~m.module[import].published THEN
  727. ASSERT(register.first # NIL);
  728. (*prev := NIL;
  729. cur := register.first;
  730. WHILE (cur # NIL) & (cur # m.module[import]) DO
  731. prev := cur;
  732. cur := cur.next
  733. END;
  734. (*ASSERT(cur = m.module[import]);*)
  735. ASSERT(cur = m.module[import]);
  736. IF prev = NIL THEN
  737. register.first := cur.next
  738. ELSE
  739. prev.next := cur.next;
  740. END;
  741. cur.next := NIL;
  742. *)
  743. Initialize0 (m.module[import]);
  744. END
  745. END;
  746. END;
  747. Initialize0 (m);
  748. END;
  749. END PublishRegisteredModules;
  750. (* procedure that will be called last in a linked kernel *)
  751. PROCEDURE {FINAL, NOPAF} Main-;
  752. BEGIN
  753. (*Machine.Init;*)
  754. IF TraceBoot THEN
  755. Trace.String("publish registered modules"); Trace.Ln;
  756. END;
  757. PublishRegisteredModules;
  758. END Main;
  759. PROCEDURE Init;
  760. VAR
  761. s: ARRAY 4 OF CHAR;
  762. BEGIN
  763. (* root is initialized by the linker *)
  764. shutdown := None;
  765. numLoaders := 0;
  766. freeRoot := NIL;
  767. Machine.GetConfig("TraceModules", s);
  768. trace := (s[0] = "1");
  769. END Init;
  770. BEGIN
  771. Init;
  772. END Modules.
  773. (*
  774. 19.03.1998 pjm Started
  775. 06.10.1998 pjm FreeModule
  776. Note:
  777. 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).
  778. *)
  779. StaticLinker.Link --fileFormat=PE32 --fileName=A2M.exe --extension=GofW --displacement=401000H
  780. Runtime Trace Kernel32 Machine Heaps Modules Objects Kernel KernelLog Streams Commands
  781. FIles WinFS Clock Dates Reals Strings Diagnostics BitSets StringPool ObjectFile GenericLinker Reflection
  782. GenericLoader BootConsole
  783. Traps
  784. TrapWriters
  785. SystemVersion
  786. CRC
  787. FileTrapWriter
  788. Display
  789. User32
  790. GDI32
  791. Displays
  792. Plugins
  793. Inputs
  794. Options
  795. WindowManager
  796. WMGraphics
  797. WMRectangles
  798. Raster
  799. CLUTs
  800. UTF8Strings
  801. WMRasterScale
  802. Codecs
  803. SoundDevices
  804. Configuration
  805. XMLObjects
  806. XML
  807. DynamicStrings
  808. XMLScanner
  809. XMLParser
  810. Unzip
  811. Inflate
  812. Texts
  813. WMEvents
  814. Locks
  815. FP1616
  816. Archives
  817. WMMessages
  818. Debugging
  819. WMDefaultWindows
  820. WMWindowManager
  821. WMGraphicUtilities
  822. WMFontManager
  823. WMDefaultFont
  824. WMOTFonts
  825. OpenType
  826. OpenTypeInt
  827. OpenTypeScan
  828. WMCCGFonts
  829. PNGDecoder
  830. Clipboard
  831. TextUtilities
  832. Repositories
  833. Localization
  834. UnicodeProperties
  835. HostClipboard
  836. FSTools
  837. RelativeFileSystem
  838. Autostart
  839. WMTrapWriter
  840. WMUtilities
  841. WMComponents
  842. Events
  843. WMProperties
  844. Models
  845. Types
  846. WMDropTarget
  847. WMDocumentEditor
  848. WMMacros
  849. WMTextView
  850. SyntaxHighlighter
  851. WMStandardComponents
  852. FileHandlers
  853. WMPopups
  854. WMPieMenu
  855. UnicodeBidirectionality
  856. PositionDebugging
  857. ContextualDependency
  858. WMEditors
  859. UndoManager
  860. WMInputMethods
  861. WMSearchComponents
  862. WMDialogs
  863. WMRestorable
  864. UpTime
  865. StartMenu
  866. MainMenu
  867. WMTabComponents
  868. Tar
  869. SkinEngine
  870. SkinLanguage
  871. Pipes
  872. WMFileManager
  873. WMSystemComponents
  874. WMTrees
  875. WMGrids
  876. WMStringGrids
  877. Notepad
  878. WMKernelLog
  879. KernelLogger
  880. WMClock
  881. Math
  882. WMTextTool
  883. PET
  884. CompilerInterface
  885. WhitespaceRemover
  886. WMDiagnostics
  887. WMBitmapFont
  888. PETTrees
  889. WMOberonFonts
  890. WMNavigate
  891. HotKeys
  892. Errors
  893. Zip
  894. Zlib
  895. ZlibReaders
  896. ZlibBuffers
  897. ZlibInflate
  898. ZlibWriters
  899. ZlibDeflate
  900. FoxBasic
  901. FoxA2Interface
  902. FoxScanner
  903. FoxSyntaxTree
  904. FoxGlobal
  905. FoxParser
  906. FoxPrintout
  907. FoxFormats
  908. FoxSemanticChecker
  909. FoxBackend
  910. FoxFrontend
  911. Compiler
  912. ReleaseThreadPool
  913. Release
  914. PETReleaseTree
  915. ModuleParser
  916. PETModuleTree
  917. ProcessInfo0
  918. ProcessInfo
  919. SystemTools
  920. StaticLinker
  921. ~
  922. SystemTools.ListModules -l ~