GenericLoader.Mod 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. MODULE GenericLoader; (** AUTHOR "fof"; PURPOSE "Active Oberon Generic Object File Loader"; *)
  2. (* cf. Linker *)
  3. IMPORT SYSTEM, KernelLog, Modules, Streams, Files, D := KernelLog, GenericLinker, ObjectFile, Diagnostics, Strings, StringPool, Trace, Machine;
  4. CONST
  5. Ok = 0;
  6. LinkerError=3400;
  7. FileNotFound = 3401;
  8. CommandTrapped* = 3904; (* cf module Commands *)
  9. SupportOldObjectFileFormat = FALSE;
  10. TraceLoading = FALSE;
  11. TYPE
  12. HashEntryIntInt = RECORD
  13. key,value: LONGINT;
  14. END;
  15. HashIntArray = POINTER TO ARRAY OF HashEntryIntInt;
  16. HashEntryIntAny = RECORD
  17. key: LONGINT; value: ANY;
  18. END;
  19. HashIntAnyArray = POINTER TO ARRAY OF HashEntryIntAny;
  20. HashTableInt = OBJECT
  21. VAR
  22. table: HashIntArray;
  23. size: LONGINT;
  24. used-: LONGINT;
  25. maxLoadFactor: REAL;
  26. (* Interface *)
  27. PROCEDURE & Init* (initialSize: LONGINT);
  28. BEGIN
  29. ASSERT(initialSize > 2);
  30. NEW(table, initialSize);
  31. size := initialSize;
  32. used := 0;
  33. maxLoadFactor := 0.75;
  34. END Init;
  35. PROCEDURE Put*(key: LONGINT; value: LONGINT);
  36. VAR hash: LONGINT;
  37. BEGIN
  38. ASSERT(key # 0);
  39. ASSERT(used < size);
  40. hash := HashValue(key);
  41. IF table[hash].key = 0 THEN
  42. INC(used, 1);
  43. END;
  44. table[hash].key := key;
  45. table[hash].value := value;
  46. IF (used / size) > maxLoadFactor THEN Grow END;
  47. END Put;
  48. PROCEDURE Get*(key: LONGINT):LONGINT;
  49. BEGIN
  50. RETURN table[HashValue(key)].value;
  51. END Get;
  52. PROCEDURE Has*(key: LONGINT):BOOLEAN;
  53. BEGIN
  54. RETURN table[HashValue(key)].key = key;
  55. END Has;
  56. PROCEDURE Length*():LONGINT;
  57. BEGIN RETURN used; END Length;
  58. PROCEDURE Clear*;
  59. VAR i: LONGINT;
  60. BEGIN FOR i := 0 TO size - 1 DO table[i].key := 0; END; END Clear;
  61. (* Internals *)
  62. PROCEDURE HashValue(key: LONGINT):LONGINT;
  63. VAR value, h1, h2, i: LONGINT;
  64. BEGIN
  65. i := 0;
  66. value := key;
  67. h1 := key MOD size;
  68. h2 := 1; (* Linear probing *)
  69. REPEAT
  70. value := (h1 + i*h2) MOD size;
  71. INC(i);
  72. UNTIL((table[value].key = 0) OR (table[value].key = key) OR (i > size));
  73. ASSERT((table[value].key = 0) OR (table[value].key = key));
  74. RETURN value;
  75. END HashValue;
  76. PROCEDURE Grow;
  77. VAR oldTable: HashIntArray; oldSize, i, key: LONGINT;
  78. BEGIN
  79. oldSize := size;
  80. oldTable := table;
  81. Init(size*2);
  82. FOR i := 0 TO oldSize-1 DO
  83. key := oldTable[i].key;
  84. IF key # 0 THEN
  85. Put(key, oldTable[i].value);
  86. END;
  87. END;
  88. END Grow;
  89. END HashTableInt;
  90. HashTableIntAny* = OBJECT
  91. VAR
  92. table: HashIntAnyArray;
  93. size: LONGINT;
  94. used-: LONGINT;
  95. maxLoadFactor: REAL;
  96. (* Interface *)
  97. PROCEDURE & Init* (initialSize: LONGINT);
  98. BEGIN
  99. ASSERT(initialSize > 2);
  100. NEW(table, initialSize);
  101. size := initialSize;
  102. used := 0;
  103. maxLoadFactor := 0.75;
  104. END Init;
  105. PROCEDURE Put*(key: LONGINT; value: ANY);
  106. VAR hash: LONGINT;
  107. BEGIN
  108. ASSERT(key # 0);
  109. ASSERT(used < size);
  110. hash := HashValue(key);
  111. IF table[hash].key = 0 THEN
  112. INC(used, 1);
  113. END;
  114. table[hash].key := key;
  115. table[hash].value := value;
  116. IF (used / size) > maxLoadFactor THEN Grow END;
  117. END Put;
  118. PROCEDURE Get*(key: LONGINT):ANY;
  119. BEGIN
  120. RETURN table[HashValue(key)].value;
  121. END Get;
  122. PROCEDURE Has*(key: LONGINT):BOOLEAN;
  123. BEGIN
  124. RETURN table[HashValue(key)].key = key;
  125. END Has;
  126. PROCEDURE Length*():LONGINT;
  127. BEGIN RETURN used; END Length;
  128. PROCEDURE Clear*;
  129. VAR i: LONGINT;
  130. BEGIN FOR i := 0 TO size - 1 DO table[i].key := 0; END; END Clear;
  131. (* Interface for integer values *)
  132. (* Internals *)
  133. PROCEDURE HashValue(key: LONGINT):LONGINT;
  134. VAR value, h1, h2, i: LONGINT;
  135. BEGIN
  136. i := 0;
  137. value := key;
  138. h1 := key MOD size;
  139. h2 := 1; (* Linear probing *)
  140. REPEAT
  141. value := (h1 + i*h2) MOD size;
  142. INC(i);
  143. UNTIL((table[value].key = 0) OR (table[value].key = key) OR (i > size));
  144. ASSERT((table[value].key = 0) OR (table[value].key = key));
  145. RETURN value;
  146. END HashValue;
  147. PROCEDURE Grow;
  148. VAR oldTable: HashIntAnyArray; oldSize, i, key: LONGINT;
  149. BEGIN
  150. oldSize := size;
  151. oldTable := table;
  152. Init(size*2);
  153. FOR i := 0 TO oldSize-1 DO
  154. key := oldTable[i].key;
  155. IF key # 0 THEN
  156. Put(key, oldTable[i].value);
  157. END;
  158. END;
  159. END Grow;
  160. END HashTableIntAny;
  161. Data=RECORD size, pos: LONGINT; bytes: Modules.Bytes; firstAddress: LONGINT; END;
  162. Arrangement* = OBJECT (GenericLinker.Arrangement);
  163. VAR
  164. code, data: Data;
  165. (*moduleAdr: LONGINT;*)
  166. hasBody: BOOLEAN;
  167. bodyAddress : LONGINT;
  168. PROCEDURE & InitArrangement;
  169. BEGIN InitData(code); InitData(data); hasBody := FALSE;
  170. END InitArrangement;
  171. PROCEDURE Preallocate*(CONST section: ObjectFile.Section);
  172. BEGIN
  173. ASSERT(section.unit = 8);
  174. ASSERT(section.bits.GetSize() MOD 8 = 0);
  175. ASSERT(section.type # ObjectFile.InitCode);
  176. IF section.type IN {ObjectFile.Code, ObjectFile.BodyCode} THEN
  177. DoPreallocate(section, code);
  178. ELSE ASSERT (section.type IN {ObjectFile.Const, ObjectFile.Data});
  179. DoPreallocate(section, data);
  180. END;
  181. END Preallocate;
  182. PROCEDURE Allocate* (CONST section: ObjectFile.Section): GenericLinker.Address;
  183. VAR adr: GenericLinker.Address;
  184. BEGIN
  185. IF section.type IN {ObjectFile.Code, ObjectFile.BodyCode} THEN
  186. adr := DoAllocate(section, code);
  187. ELSE ASSERT(section.type IN {ObjectFile.Const, ObjectFile.Data});
  188. adr := DoAllocate(section, data);
  189. END;
  190. IF section.type = ObjectFile.BodyCode THEN
  191. hasBody := TRUE; bodyAddress := adr;
  192. END;
  193. (*
  194. IF (section.identifier.name[0] >= 0) & (section.identifier.name[1] >= 0) THEN
  195. IF (section.identifier.name[1] = InternalModuleName) OR (section.identifier.name[2] = InternalModuleName) THEN
  196. moduleAdr := adr
  197. END;
  198. END;
  199. *)
  200. RETURN adr;
  201. END Allocate;
  202. PROCEDURE Patch* (pos, value: GenericLinker.Address; offset, bits, unit: ObjectFile.Bits);
  203. VAR char: CHAR;
  204. BEGIN
  205. ASSERT(bits MOD 8 = 0);
  206. ASSERT(unit = 8);
  207. WHILE bits > 0 DO
  208. char := CHR(value);
  209. SYSTEM.PUT(pos, char);
  210. value := value DIV 256;
  211. DEC(bits,8); INC(pos,1);
  212. END;
  213. END Patch;
  214. END Arrangement;
  215. ModuleList=OBJECT
  216. VAR
  217. hash: HashTableIntAny;
  218. PROCEDURE &Init;
  219. BEGIN
  220. NEW(hash,128);
  221. END Init;
  222. PROCEDURE ThisModule(module: Modules.Module): HashTableInt;
  223. VAR modList: HashTableInt;
  224. any: ANY;
  225. PROCEDURE TraverseScopes(CONST scope: Modules.ExportDesc; level: LONGINT);
  226. VAR adr,i: LONGINT;
  227. BEGIN
  228. IF (level > 2) THEN RETURN END;
  229. IF (scope.fp # 0) THEN
  230. adr := scope.adr;
  231. IF SupportOldObjectFileFormat THEN
  232. IF module.staticTypeDescs # testTypeDescs THEN (* old object file format *)
  233. IF (adr = 0) & (scope.exports > 0) THEN (* type in old object file format *)
  234. adr := scope.dsc[0].adr;
  235. SYSTEM.GET(module.sb + adr, adr);
  236. ELSIF adr # 0 THEN
  237. INC(adr,ADDRESSOF(module.code[0]));
  238. END;
  239. END;
  240. END;
  241. modList.Put(scope.fp, adr)
  242. END;
  243. FOR i := 0 TO scope.exports-1 DO
  244. IF scope.dsc # NIL THEN TraverseScopes(scope.dsc[i],level+1) END;
  245. END;
  246. adr := 0;
  247. END TraverseScopes;
  248. BEGIN{EXCLUSIVE}
  249. IF hash.Has(SYSTEM.VAL(LONGINT, module)) THEN
  250. any := hash.Get(SYSTEM.VAL(LONGINT,module));
  251. modList := any(HashTableInt);
  252. ELSE
  253. NEW(modList,256); TraverseScopes(module.export,0);
  254. hash.Put(SYSTEM.VAL(LONGINT,module), modList);
  255. RETURN modList
  256. END;
  257. RETURN modList;
  258. END ThisModule;
  259. END ModuleList;
  260. Linker = OBJECT (GenericLinker.Linker)
  261. VAR
  262. moduleName: ObjectFile.SegmentedName;
  263. importBlock: GenericLinker.Block;
  264. hash: HashTableIntAny;
  265. moduleBlock: GenericLinker.Block;
  266. PROCEDURE &InitLinkerX* (diagnostics: Diagnostics.Diagnostics; log: Streams.Writer; code, data: GenericLinker.Arrangement; CONST name: ARRAY OF CHAR);
  267. BEGIN
  268. ObjectFile.StringToSegmentedName(name, moduleName);
  269. InitLinker(diagnostics, log, GenericLinker.UseAllButInitCode (* strip init code *), code, data);
  270. NEW(importBlock);
  271. NEW(hash,256); (* hash for blocks *)
  272. END InitLinkerX;
  273. (* oerwritten functionality of generic linker *)
  274. PROCEDURE FindBlock(CONST identifier: ObjectFile.Identifier): GenericLinker.Block;
  275. VAR block: GenericLinker.Block; any: ANY;
  276. BEGIN
  277. block := NIL;
  278. IF IsPrefix(moduleName, identifier.name) THEN (* local block *)
  279. IF identifier.fingerprint = 0 THEN (* not identifiable via fingerprint *)
  280. block := FindBlock^(identifier);
  281. ELSE
  282. any := hash.Get(identifier.fingerprint);
  283. IF any # NIL THEN block := any(GenericLinker.Block) (* local block *) END;
  284. IF (block # NIL) & (block.identifier.name # identifier.name) THEN (* local block, false or duplicate fingerprint *)
  285. block := FindBlock^(identifier)
  286. END;
  287. END;
  288. END;
  289. RETURN block;
  290. END FindBlock;
  291. PROCEDURE ExportBlock(block: GenericLinker.Block);
  292. BEGIN
  293. IF block.identifier.fingerprint # 0 THEN
  294. hash.Put(block.identifier.fingerprint, block)
  295. END;
  296. IF (block.identifier.name[0] >= 0) & (block.identifier.name[1] >= 0) THEN
  297. IF (block.identifier.name[1] = InternalModuleName) & (block.identifier.name[2]<0) OR (block.identifier.name[2] = InternalModuleName) & (block.identifier.name[3] < 0) THEN
  298. moduleBlock := block;
  299. END;
  300. END;
  301. END ExportBlock;
  302. PROCEDURE ImportBlock(CONST fixup: ObjectFile.Fixup): GenericLinker.Block;
  303. VAR name: Modules.Name; res: LONGINT;
  304. msg: ARRAY 128 OF CHAR; module: Modules.Module; adr: LONGINT; m: HashTableInt;
  305. s: ObjectFile.SectionName; isModule: BOOLEAN; identifier: ObjectFile.Identifier;
  306. PROCEDURE CheckName(n: StringPool.Index; name {UNTRACED}: Modules.DynamicName): LONGINT;
  307. VAR s: ObjectFile.SectionName; i: LONGINT;
  308. BEGIN
  309. IF name = NIL THEN RETURN -1 END;
  310. StringPool.GetString(n, s);
  311. i := 0;
  312. WHILE (s[i] # 0X) & (name[i] # 0X) & (s[i] = name[i]) DO
  313. INC(i);
  314. END;
  315. RETURN ORD(s[i]) - ORD(name[i]);
  316. END CheckName;
  317. (* stupid implementation: just search for fp in all exports *)
  318. PROCEDURE CheckScope(CONST scope: Modules.ExportDesc; level: LONGINT): LONGINT;
  319. VAR adr,lo,hi,m,res: LONGINT;
  320. BEGIN
  321. adr := 0;
  322. (* export names are sorted, binary search: *)
  323. lo := 0; hi := scope.exports-1;
  324. WHILE (lo <= hi) DO
  325. m := (lo + hi) DIV 2;
  326. res := CheckName(identifier.name[level], scope.dsc[m].name);
  327. IF res = 0 THEN
  328. IF (level = LEN(identifier.name)-1) OR (identifier.name[level+1] <= 0) THEN
  329. IF (scope.dsc[m].fp # identifier.fingerprint) & (scope.dsc[m].fp # 0) & (identifier.fingerprint # 0) THEN
  330. TRACE("fingerprints don't match");
  331. END;
  332. RETURN scope.dsc[m].adr
  333. ELSE
  334. RETURN CheckScope(scope.dsc[m], level+1);
  335. END;
  336. ELSIF res > 0 THEN lo := m+1;
  337. ELSE hi := m-1;
  338. END;
  339. END;
  340. RETURN 0;
  341. END CheckScope;
  342. BEGIN
  343. identifier := fixup.identifier;
  344. IF IsPrefix(moduleName, identifier.name) THEN
  345. D.String("circular import while trying to fetch ");
  346. s := identifier.name; D.String(s);
  347. D.Ln;
  348. RETURN NIL
  349. END;
  350. StringPool.GetString(identifier.name[0], name);
  351. isModule := identifier.name[1] = InternalModuleName;
  352. IF (identifier.name[0] = OberonName) & (identifier.name[2] >= 0) THEN (* in Oberon name space *)
  353. StringPool.GetString(identifier.name[1], s);
  354. Strings.Append(name, ".");
  355. Strings.Append(name, s);
  356. isModule := identifier.name[2] = InternalModuleName;
  357. END;
  358. (*
  359. IF ~isModule & (identifier.fingerprint = 0) THEN
  360. D.String("Invalid attempt to import symbol without fingerprint ");
  361. s := identifier.name; D.String(s);
  362. D.Ln;
  363. RETURN NIL
  364. END;
  365. *)
  366. module := Modules.ThisModule(name,res,msg);
  367. IF module = NIL THEN
  368. D.String("could not get module while importing "); D.String(name); D.Ln;
  369. RETURN NIL
  370. END;
  371. IF isModule THEN
  372. adr := SYSTEM.VAL(ADDRESS, module) - fixup.patch[0].displacement;
  373. ELSE
  374. m := moduleList.ThisModule(module);
  375. ASSERT(module # NIL);
  376. (* first try via hash-table *)
  377. (* disabled -- might be able to remove hash table completely, needs some testing
  378. IF identifier.fingerprint # 0 THEN
  379. adr := m.Get(identifier.fingerprint);
  380. END;
  381. *)
  382. (* if it does not work, then try export table directly *)
  383. IF adr = 0 THEN
  384. adr := CheckScope(module.export,1(*level*) );
  385. END;
  386. END;
  387. IF adr = 0 THEN
  388. D.String("GenericLoader Fatal error: did not find block "); s := identifier.name; D.String(s); D.Ln;
  389. RETURN NIL;
  390. ELSE (* found *)
  391. importBlock.identifier.fingerprint := identifier.fingerprint; importBlock.address := adr
  392. END;
  393. RETURN importBlock
  394. END ImportBlock;
  395. END Linker;
  396. VAR
  397. moduleList: ModuleList;
  398. testTypeDescs: Modules.Bytes;
  399. InternalModuleName, OberonName: StringPool.Index;
  400. PROCEDURE InitData(VAR data: Data);
  401. BEGIN
  402. data.pos := 0; data.size := 0; data.bytes := NIL; data.firstAddress := 0;
  403. END InitData;
  404. PROCEDURE IsPrefix(CONST prefix, of: ObjectFile.SegmentedName): BOOLEAN;
  405. VAR prefixS, ofS: ObjectFile.SectionName; i: LONGINT;
  406. BEGIN
  407. i := 0;
  408. WHILE (i< LEN(prefix)) & (prefix[i] = of[i]) DO INC(i) END;
  409. IF i = LEN(prefix) THEN RETURN TRUE (* identical *)
  410. ELSE (* prefix[i] # of[i] *)
  411. IF prefix[i] < 0 THEN RETURN TRUE (* name longer than prefix *)
  412. ELSIF of[i] < 0 THEN RETURN FALSE (* prefix longer than name *)
  413. ELSIF (i<LEN(prefix)-1) THEN RETURN FALSE (* prefix and name differ but not at the tail *)
  414. ELSE
  415. (* check tail *)
  416. StringPool.GetString(prefix[i], prefixS);
  417. StringPool.GetString(of[i], ofS);
  418. RETURN Strings.StartsWith(prefixS, 0, ofS)
  419. END
  420. END;
  421. END IsPrefix;
  422. PROCEDURE DoPreallocate(CONST section: ObjectFile.Section; VAR data: Data);
  423. BEGIN
  424. ASSERT(section.bits.GetSize() MOD 8 = 0);
  425. IF section.alignment > 0 THEN
  426. INC(data.size, (-data.size) MOD section.alignment); (* here we assume that base-alignment is ok *)
  427. END;
  428. INC(data.size, section.bits.GetSize() DIV 8);
  429. END DoPreallocate;
  430. PROCEDURE DoAllocate(CONST section: ObjectFile.Section; VAR data: Data): GenericLinker.Address;
  431. VAR address: ObjectFile.Bits; size: SIZE;
  432. BEGIN
  433. IF (data.bytes = NIL) OR (LEN(data.bytes) # data.size) THEN NEW(data.bytes, data.size) END;
  434. IF section.alignment > 0 THEN
  435. INC(data.pos, (-data.pos) MOD section.alignment); (* here we assume that base-alignment is ok *)
  436. END;
  437. address := ADDRESSOF(data.bytes[0])+data.pos; (* to account for potentially empty variable at end of data ... *)
  438. size := section.bits.GetSize();
  439. section.bits.CopyTo(address, size);
  440. INC(data.pos, size DIV 8);
  441. (*
  442. bitPos:= 0;
  443. WHILE size > 0 DO
  444. value := section.bits.GetBits(bitPos,8);
  445. data.bytes[data.pos] := CHR(value);
  446. DEC(size,8); INC(data.pos); INC(bitPos,8);
  447. END;
  448. *)
  449. IF data.firstAddress = 0 THEN data.firstAddress := address END;
  450. RETURN address
  451. END DoAllocate;
  452. PROCEDURE LoadObj*(CONST name, fileName: ARRAY OF CHAR; VAR res: LONGINT; VAR msg: ARRAY OF CHAR): Modules.Module;
  453. TYPE Body=PROCEDURE;
  454. VAR
  455. file: Files.File; reader: Files.Reader; linker: Linker;
  456. arrangement: Arrangement; diagnostics: Diagnostics.StreamDiagnostics; stringWriter: Streams.StringWriter;
  457. module: Modules.Module; heapBlockAdr,moduleAdr: LONGINT;
  458. Log: Streams.Writer;
  459. BEGIN
  460. file := Files.Old(fileName);
  461. IF file # NIL THEN
  462. IF TraceLoading THEN Trace.String("loading"); Trace.String(fileName); Trace.Ln END;
  463. res := Ok; msg[0] := 0X;
  464. Files.OpenReader(reader, file, 0);
  465. NEW(arrangement); NEW(stringWriter,256);
  466. Streams.OpenWriter( Log, KernelLog.Send );
  467. NEW(diagnostics,Log);
  468. NEW(linker, diagnostics, NIL, arrangement, arrangement,name);
  469. IF TraceLoading THEN Trace.String("before linking"); Trace.Ln END;
  470. GenericLinker.Process (reader, linker);
  471. IF ~linker.error THEN linker.Resolve END;
  472. IF ~linker.error THEN linker.Link END;
  473. (*D.Update;*)
  474. IF ~linker.error THEN
  475. IF TraceLoading THEN Trace.String("linking done"); Trace.Ln END;
  476. moduleAdr := linker.moduleBlock.address;
  477. IF ~Machine.IsCooperative THEN
  478. SYSTEM.GET(moduleAdr+3*SIZEOF(ADDRESS), moduleAdr);
  479. SYSTEM.GET(moduleAdr-2*SIZEOF(ADDRESS), heapBlockAdr);
  480. ASSERT(heapBlockAdr = linker.moduleBlock.address+2*SIZEOF(ADDRESS));
  481. END;
  482. module := SYSTEM.VAL(Modules.Module,moduleAdr);
  483. module.staticTypeDescs := testTypeDescs; (* trick to identify new object file loaded modules *)
  484. module.data := arrangement.data.bytes;
  485. module.code := arrangement.code.bytes;
  486. module.sb := 0 (*arrangement.data.firstAddress*); (* zero is correct ! *)
  487. module.body := SYSTEM.VAL(Body, arrangement.bodyAddress);
  488. (*
  489. SortProcTable(module);
  490. SelectionSort(module.exTable);
  491. *)
  492. (*
  493. careful: when GC uses a heuristic for pointer detection on the stack, it will not
  494. trace the module because the module is not reachable as a heap block in a sweep
  495. Therefore the code and data array has to be secured in addition.
  496. Here this is made sure to enter the module in the data structure before returning it.
  497. *)
  498. Modules.Initialize(module);
  499. ELSE module := NIL; res := LinkerError; stringWriter.Update; stringWriter.Get(msg);
  500. END;
  501. ELSE
  502. res := FileNotFound; COPY(fileName, msg); Modules.Append(" not found", msg)
  503. END;
  504. IF res # Ok THEN module := NIL END;
  505. IF (res # Ok) & (res # FileNotFound) THEN D.String(msg);D.Ln END;
  506. RETURN module
  507. FINALLY
  508. res := CommandTrapped;
  509. RETURN NIL
  510. END LoadObj;
  511. PROCEDURE Install*;
  512. VAR extension: ARRAY 32 OF CHAR;
  513. BEGIN
  514. Machine.GetConfig("ObjectFileExtension", extension);
  515. IF extension = "" THEN
  516. COPY(".Gof", extension)
  517. END;
  518. Modules.AddLoader(extension, LoadObj);
  519. END Install;
  520. PROCEDURE Remove*;
  521. BEGIN
  522. Modules.RemoveLoader(".Gof",LoadObj);
  523. END Remove;
  524. BEGIN
  525. NEW(testTypeDescs,1);
  526. Modules.InstallTermHandler(Remove);
  527. StringPool.GetIndex("Oberon",OberonName);
  528. StringPool.GetIndex("@Module",InternalModuleName);
  529. NEW(moduleList);
  530. Install;
  531. END GenericLoader.
  532. (* concurrent load test:
  533. VAR
  534. startConcurrentLoad: BOOLEAN;
  535. PROCEDURE ConcurrentLoad*;
  536. VAR i: LONGINT;
  537. o: OBJECT VAR
  538. mod: Modules.Module; res: LONGINT; msg: ARRAY 32 OF CHAR;
  539. BEGIN{ACTIVE}
  540. WHILE(~startConcurrentLoad) DO END;
  541. mod := Modules.ThisModule("Test",res,msg);
  542. END;
  543. BEGIN
  544. startConcurrentLoad := FALSE;
  545. FOR i := 0 TO 128 DO
  546. NEW(o);
  547. END;
  548. startConcurrentLoad := TRUE;
  549. END ConcurrentLoad;
  550. *)