Generic.Modules.Mod 27 KB

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