Generic.Modules.Mod 31 KB

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