Generic.Modules.Mod 28 KB

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