Generic.Modules.Mod 27 KB

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