faslout.red 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. %
  2. % FASLOUT.RED - Top level of fasl file writer
  3. %
  4. % Author: Eric Benson
  5. % Symbolic Computation Group
  6. % Computer Science Dept.
  7. % University of Utah
  8. % Date: 16 February 1982
  9. % Copyright (c) 1982 University of Utah
  10. %
  11. % <PSL.COMP>FASLOUT.RED.8, 19-Apr-83 07:54:22, Edit by KESSLER
  12. % Flat Faslabort as Ignore, so you need not type compiletime faslabort.
  13. % <PSL.COMP>FASLOUT.RED.7, 28-Mar-83 07:49:53, Edit by KESSLER
  14. % Added FaslAbort Command to Terminate Faslout Gracefully.
  15. % <PSL.COMP>FASLOUT.RED.6, 16-Dec-82 12:49:59, Edit by KESSLER
  16. % Take out Semic!* as a fluid. Not used by anyone that I can see
  17. % and is already a global in RLISP.
  18. % <PSL.COMP>FASLOUT.RED.35, 10-Jun-82 10:41:18, Edit by GRISS
  19. % Made CompileUncompiledExpressions regular func
  20. % <PSL.COMP>FASLOUT.RED.12, 30-Apr-82 14:45:59, Edit by BENSON
  21. % Removed EVAL and IGNORE processing
  22. % <PSL.COMP>FASLOUT.RED.8, 29-Apr-82 06:23:18, Edit by GRISS
  23. % moved DEFINEROP call to RLISP-PARSER
  24. CompileTime <<
  25. flag('(CodeFileHeader CodeFileTrailer AllocateFaslSpaces),
  26. 'InternalFunction);
  27. load Fast!-Vector;
  28. >>;
  29. fluid '(!*WritingFaslFile
  30. !*Lower
  31. !*quiet_faslout
  32. DfPrint!*
  33. UncompiledExpressions!*
  34. ModuleName!*
  35. CodeOut!*
  36. InitOffset!*
  37. CurrentOffset!*
  38. FaslBlockEnd!*
  39. MaxFaslOffset!*
  40. BitTableOffset!*
  41. FaslFilenameFormat!*);
  42. FaslFilenameFormat!* := "%w.b";
  43. lisp procedure DfPrintFasl U; %. Called by TOP-loop, DFPRINT!*
  44. begin scalar Nam, Ty, Fn, !*WritingFaslFile;
  45. !*WritingFaslFile := T;
  46. if atom U then return NIL;
  47. Fn := car U;
  48. IF FN = 'PUTD THEN GOTO DB2;
  49. IF NOT (FN MEMQ '(DE DF DM DN)) THEN GOTO DB1;
  50. NAM:=CADR U;
  51. U:='LAMBDA . CDDR U;
  52. TY:=CDR ASSOC(FN, '((DE . EXPR)
  53. (DF . FEXPR)
  54. (DM . MACRO)
  55. (DN . NEXPR)));
  56. DB3: if Ty = 'MACRO then begin scalar !*Comp;
  57. PutD(Nam, Ty, U); % Macros get defined now
  58. end;
  59. if FlagP(Nam, 'Lose) then <<
  60. ErrorPrintF("*** %r has not been defined, because it is flagged LOSE",
  61. Nam);
  62. return NIL >>;
  63. IF FLAGP(TY,'COMPILE) THEN
  64. << PUT(NAM,'CFNTYPE,LIST TY);
  65. U := LIST('!*ENTRY,NAM,TY,LENGTH CADR U)
  66. . !&COMPROC(U, NAM);
  67. LAP U >>
  68. ELSE % should never happen
  69. SaveUncompiledExpression LIST('PUTD, MKQUOTE NAM,
  70. MKQUOTE TY,
  71. MKQUOTE U);
  72. if IGreaterP(Posn(), 0) then WriteChar char BLANK;
  73. Prin1 NAM;
  74. RETURN NIL;
  75. DB1: % Simple S-EXPRESSION, maybe EVAL it;
  76. IF NOT PAIRP U THEN RETURN NIL;
  77. if (Fn := get(car U, 'FaslPreEval)) then return Apply(Fn, list U)
  78. else if (Fn := GetD car U) and car Fn = 'MACRO then
  79. return DFPRINTFasl Apply(cdr Fn, list U);
  80. SaveUncompiledExpression U;
  81. RETURN NIL;
  82. DB2: NAM:=CADR U;
  83. TY:=CADDR U;
  84. FN:=CADDDR U;
  85. IF EQCAR(NAM,'QUOTE) THEN << NAM:=CADR NAM;
  86. IF EQCAR(TY,'QUOTE) THEN << TY:=CADR TY;
  87. IF PAIRP FN AND CAR FN MEMBER '(FUNCTION QUOTE) THEN << FN:=CADR FN;
  88. IF TY MEMQ '(EXPR FEXPR MACRO NEXPR) THEN
  89. << U:=FN; GOTO DB3 >> >> >> >>;
  90. GOTO DB1;
  91. END;
  92. FLAG ('(DEFLIST FLAG FLUID GLOBAL REMFLAG REMPROP UNFLUID),'EVAL);
  93. lisp procedure FaslPreEvalLoadTime U;
  94. DFPrintFasl cadr U; % remove LOADTIME
  95. put('LoadTime, 'FaslPreEval, 'FaslPreEvalLoadTime);
  96. put('BothTimes, 'FaslPreEval, 'FaslPreEvalLoadTime);
  97. put('StartupTime, 'FaslPreEval, 'FaslPreEvalLoadTime); % used in kernel
  98. % A few things to save space when loading
  99. put('Flag,
  100. 'FaslPreEval,
  101. function lambda U;
  102. if EqCar(second U, 'QUOTE) then
  103. DFPrintFasl('progn . for each X in second second U collect
  104. list('Flag1, MkQuote X, third U))
  105. else SaveUncompiledExpression U);
  106. put('fluid,
  107. 'FaslPreEval,
  108. function lambda U;
  109. if EqCar(second U, 'QUOTE) then
  110. DFPrintFasl('progn . for each X in second second U collect
  111. list('Fluid1, MkQuote X))
  112. else SaveUncompiledExpression U);
  113. put('global,
  114. 'FaslPreEval,
  115. function lambda U;
  116. if EqCar(second U, 'QUOTE) then
  117. DFPrintFasl('progn . for each X in second second U collect
  118. list('Global1, MkQuote X))
  119. else SaveUncompiledExpression U);
  120. put('DefList,
  121. 'FaslPreEval,
  122. function lambda U;
  123. if EqCar(second U, 'QUOTE) then
  124. DFPrintFasl('progn . for each X in second second U collect
  125. list('put, MkQuote first X,
  126. third U,
  127. MkQuote second X))
  128. else SaveUncompiledExpression U);
  129. put('ProgN,
  130. 'FaslPreEval,
  131. function lambda U;
  132. for each X in cdr U do
  133. DFPrintFasl X);
  134. put('LAP,
  135. 'FaslPreEval,
  136. function lambda U;
  137. if EqCar(cadr U, 'QUOTE) then Lap cadr cadr U
  138. else SaveUncompiledExpression U);
  139. UncompiledExpressions!* := NIL . NIL;
  140. lisp procedure SaveUncompiledExpression U;
  141. << if atom U then NIL
  142. else TConc(UncompiledExpressions!*, U);
  143. NIL >>;
  144. lisp procedure FaslOut FIL;
  145. << ModuleName!* := FIL;
  146. if not !*quiet_faslout then
  147. << if not FUnBoundP 'Begin1 then
  148. << Prin2T "FASLOUT: IN files; or type in expressions";
  149. Prin2T "When all done execute FASLEND;" >>
  150. else
  151. << Prin2T "FASLOUT: (DSKIN files) or type in expressions";
  152. Prin2T "When all done execute (FASLEND)" >> >>;
  153. CodeOut!* := BinaryOpenWrite BldMsg(FaslFilenameFormat!*, ModuleName!*);
  154. CodeFileHeader();
  155. DFPRINT!* := 'DFPRINTFasl;
  156. !*WritingFaslFile := T;
  157. !*DEFN := T >>;
  158. lisp procedure FaslEnd;
  159. if not !*WritingFaslFile then
  160. StdError "FASLEND not within FASLOUT"
  161. else
  162. << CompileUncompiledExpressions();
  163. UncompiledExpressions!* := NIL . NIL;
  164. CodeFileTrailer();
  165. BinaryClose CodeOut!*;
  166. DFPRINT!* := NIL;
  167. !*WritingFaslFile := NIL;
  168. !*DEFN := NIL >>;
  169. FLAG('(FaslEND), 'IGNORE);
  170. % FaslAbort. Abort the Fasl process cleanly. The code file will be closed
  171. % and the various flags will be reset.
  172. lisp procedure FaslAbort;
  173. if not !*WritingFaslFile then
  174. StdError "FASLAbort not within FASLOUT"
  175. else
  176. << UncompiledExpressions!* := NIL . NIL;
  177. BinaryClose CodeOut!*;
  178. DFPRINT!* := NIL;
  179. !*WritingFaslFile := NIL;
  180. !*DEFN := NIL >>;
  181. Flag('(FaslAbort), 'Ignore);
  182. lisp procedure ComFile Filename;
  183. begin scalar !*Defn, !*WritingFaslFile, TestFile, FileBase, FileExt,
  184. I, N, DotFound, TestExts, !*quiet_faslout;
  185. if IDP Filename then
  186. (lambda (!*Lower); Filename := BldMsg("%w", Filename))(T);
  187. if not StringP Filename then return
  188. NonStringError(Filename, 'ComFile);
  189. N := ISizeS Filename;
  190. I := 0;
  191. while not DotFound and ILEQ(I, N) do
  192. << if IGetS(Filename, I) = char '!. then DotFound := T;
  193. I := IAdd1 I >>;
  194. if DotFound then
  195. << if not FileP Filename then return ContError(99, "Couldn't find file",
  196. ComFile Filename)
  197. else
  198. << FileBase := SubSeq(Filename, 0, I);
  199. FileExt := SubSeq(Filename, ISub1 I, IAdd1 N) >> >>
  200. else
  201. << TestExts := '(".build" ".sl" ".red");
  202. while not null TestExts
  203. and not FileP(TestFile := Concat(Filename, first TestExts)) do
  204. TestExts := rest TestExts;
  205. if null TestExts then return ContError(99,
  206. "Couldn't find file",
  207. ComFile Filename)
  208. else
  209. << FileExt := first TestExts;
  210. FileBase := Filename;
  211. Filename := TestFile >> >>;
  212. ErrorPrintF("*** Compiling %w", Filename);
  213. !*quiet_faslout := T;
  214. Faslout FileBase;
  215. if FileExt member '(".build" ".red") then
  216. EvIn list Filename
  217. else DskIn Filename;
  218. Faslend;
  219. return T;
  220. end;
  221. lisp procedure CompileUncompiledExpressions();
  222. << ErrorPrintF("*** Init code length is %w",
  223. length car UncompiledExpressions!*);
  224. DFPRINTFasl list('DE, '!*!*Fasl!*!*InitCode!*!*, '(),
  225. 'PROGN . car UncompiledExpressions!*) >>;
  226. lisp procedure CodeFileHeader();
  227. << BinaryWrite(CodeOut!*, const FASL_MAGIC_NUMBER);
  228. AllocateFaslSpaces() >>;
  229. fluid '(CodeBase!* BitTableBase!* OrderedIDList!* NextIDNumber!*);
  230. lisp procedure FindIDNumber U;
  231. begin scalar I;
  232. return if ILEQ(I := IDInf U, 128) then I
  233. else if (I := get(U, 'IDNumber)) then I
  234. else
  235. << put(U, 'IDNumber, I := NextIDNumber!*);
  236. OrderedIDList!* := TConc(OrderedIDList!*, U);
  237. NextIDNumber!* := IAdd1 NextIDNumber!*;
  238. I >>;
  239. end;
  240. lisp procedure CodeFileTrailer();
  241. begin scalar S;
  242. SystemFaslFixup();
  243. BinaryWrite(CodeOut!*, IDifference(ISub1 NextIDNumber!*, 2048));
  244. % Number of local IDs
  245. for each X in car OrderedIDList!* do
  246. << RemProp(X, 'IDNumber);
  247. X := StrInf ID2String X;
  248. S := StrLen X;
  249. BinaryWriteBlock(CodeOut!*, X, IAdd1 StrPack S) >>;
  250. BinaryWrite(CodeOut!*, % S is size in words
  251. S := IQuotient(IPlus2(CurrentOffset!*,
  252. ISub1 const AddressingUnitsPerItem),
  253. const AddressingUnitsPerItem));
  254. BinaryWrite(CodeOut!*, InitOffset!*);
  255. BinaryWriteBlock(CodeOut!*, CodeBase!*, S);
  256. BinaryWrite(CodeOut!*, S := IQuotient(IPlus2(BitTableOffset!*,
  257. ISub1 const BitTableEntriesPerWord),
  258. const BitTableEntriesPerWord));
  259. BinaryWriteBlock(CodeOut!*, BitTableBase!*, S);
  260. DelWArray(BitTableBase!*, FaslBlockEnd!*);
  261. end;
  262. lisp procedure UpdateBitTable(NumberOfEntries, FirstEntry);
  263. if !*WritingFaslFile then
  264. << PutBitTable(BitTableBase!*, BitTableOffset!*, FirstEntry);
  265. BitTableOffset!* := IAdd1 BitTableOffset!*;
  266. for I := 2 step 1 until NumberOfEntries do
  267. << PutBitTable(BitTableBase!*, BitTableOffset!*, 0);
  268. BitTableOffset!* := IAdd1 BitTableOffset!* >>;
  269. if IGreaterP(BitTableOffset!*, MaxFaslOffset!*) then
  270. FatalError "BPS exhausted during FaslOut; output file too large" >>;
  271. lisp procedure AllocateFaslSpaces();
  272. begin scalar B;
  273. B := GTWarray NIL; % how much is left?
  274. B := IDifference(B, IQuotient(B, 3));
  275. FaslBlockEnd!* := GTWArray 0; % pointer to top of space
  276. BitTableBase!* := GTWarray B; % take 2/3 of whatever's left
  277. CurrentOffset!* := 0;
  278. BitTableOffset!* := 0;
  279. CodeBase!*
  280. := Loc WGetV(BitTableBase!*, % split the space between
  281. IQuotient(B, % bit table and code
  282. IQuotient(const BitTableEntriesPerWord,
  283. const AddressingUnitsPerItem)));
  284. MaxFaslOffset!* := IDifference(FaslBlockEnd!*, CodeBase!*);
  285. OrderedIDList!* := NIL . NIL;
  286. NextIDNumber!* := 2048; % local IDs start at 2048
  287. end;
  288. END;