home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume13 / little-st2 / part03 < prev    next >
Encoding:
Internet Message Format  |  1988-01-30  |  47.1 KB

  1. Subject:  v13i055:  New release of little smalltalk, Part03/05
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Tim Budd <budd@MIST.CS.ORST.EDU>
  7. Posting-number: Volume 13, Issue 55
  8. Archive-name: little-st2/part03
  9.  
  10. #!/bin/sh
  11. #
  12. # This is version 2.02 of Little Smalltalk, distributed in five parts.
  13. # This version is dated 12/25/87
  14. # Several bugs and many features and improvements have been made since the
  15. # first posting to comp.src.unix.  See the file ``todo'' for a partial list.
  16. # Comments, bug reports, and the like should be submitted to:
  17. #     Tim Budd
  18. #     Smalltalk Distribution
  19. #     Department of Computer Science
  20. #     Oregon State University
  21. #     Corvallis, Oregon
  22. #     97330
  23. #     budd@cs.orst.edu
  24. #     {hp-pcd, tektronix}!orstcs!budd
  25. #
  26. echo 'Start of small.v2, part 03 of 05:'
  27. echo 'x - READ_ME'
  28. sed 's/^X//' > READ_ME << '/'
  29. X
  30. X
  31. X
  32. X
  33. X
  34. X
  35. X_G_e_n_e_r_a_l _O_v_e_r_v_i_e_w
  36. X
  37. X     First, the obvious facts.  This  is  not  Smalltalk-80,
  38. Xnor  even  Smalltalk-V.   This  is the second version of the
  39. XLittle Smalltalk system,  the  first  version  of  which  is
  40. Xdescribed in the book recently published by Addison-Wesley*.
  41. XVersion  two  is smaller and faster; does more in Smalltalk,
  42. Xless in C; and is designed to be more portable  to  a  wider
  43. Xvariety  of  machines  (we  are  working on versions now for
  44. Xvarious PCs).
  45. X
  46. X     My  attitude  towards  the  language  has  been  rather
  47. Xcavalier;  what  I  liked  I  kept  and what I didn't like I
  48. Xtossed out.  This is explained in more detail in my book and
  49. Xin the end of this note.  As a consequence, individuals fam-
  50. Xiliar with ST-80 or Smalltalk-V will be struck by  how  much
  51. Xthey  are missing, and I make no apologies for this.  On the
  52. Xother  hand,  you   don't   find   Smalltalk-V   posted   to
  53. Xcomp.source.unix. Among the features you won't find here are
  54. Xmetaclasses, class methods, windows, graphics  support,  and
  55. Xmore.
  56. X
  57. X     What you will find is a small language that  does  give
  58. Xyou the flavor of object oriented programming at very little
  59. Xcost.  We are working to improve the  system,  and  hope  to
  60. Xdistribute new versions as we develop them, as well as port-
  61. Xing it to a wide  range  of  machines.   If  you  find  (and
  62. Xpreferably,  fix!) bugs let us know.  If you make nice addi-
  63. Xtions let us know.  If you want to make complements  let  us
  64. Xknow.   If  you want to make complaints let us know.  If you
  65. Xwant support you just might be out of luck.
  66. X
  67. X     This software  is  entirely  public  domain.   You  are
  68. Xencouraged  to  give  it to as many friends as you may have.
  69. XAs a courtesy, I would appreciate it if you left my name  on
  70. Xthe  code as the author, but I make no other claims to it (I
  71. Xalso, of course,  disavow  any  liability  for  any  bizarre
  72. Xthings you may choose to do with it).  Enjoy.
  73. X
  74. X_B_u_i_l_d_i_n_g _t_h_e _S_y_s_t_e_m
  75. X
  76. X     The first step in building the system is to unpack  the
  77. Xsources.   The fact that you are reading this means you have
  78. Xprobably already figured out how to do this.
  79. X
  80. X     The next step is to tailor the system to  the  type  of
  81. Xenviornment  it will be run in.  For most users, this should
  82. Xmean only changing at most three lines in  the  file  env.h.
  83. XThese  three  lines  are  near the front of the file and are
  84. Xclearly marked.  Two are hard paths; for the default initial
  85. X_________________________
  86. X* _A _L_i_t_t_l_e _S_m_a_l_l_t_a_l_k, by Timothy A. Budd.  Published by
  87. XAddison Wesley, 1987.  In better bookshops everywhere.
  88. X
  89. X
  90. X
  91. X
  92. X                      October 26, 1987
  93. X
  94. X
  95. X
  96. X
  97. X
  98. X                           - 2 -
  99. X
  100. X
  101. Xobject image and for a temporary file to be used when  edit-
  102. Xing.   The  third  line is a ``meta-define'' which indicates
  103. Xthe type of machine and/or operating system to be used.  You
  104. Xshould  examine  the  rest of the file to see the variety of
  105. Xsystems supported.  If  you  are  unable  to  find  anything
  106. Xappropriate,   you   will  have  to  look  in  the  document
  107. Xinstall.ms for further instructions.  In this  latter  case,
  108. Xif  you  are  sucessful  in  porting  the  software to a new
  109. Xmachine, I would be pleased if you could  let  me  know  the
  110. Xnature of the changes required.
  111. X
  112. X     Once you have tailored the system, there are then three
  113. Xsteps  involving  in  building the system; making the parser
  114. X(the component used to generate the initial  object  image),
  115. Xmaking  the  bytecode  interpreter,  and  making  the object
  116. Ximage.  Typing _m_a_k_e, with no arguments, will do  all  three.
  117. XFor  more detailed instructions on making the system consult
  118. Xinstall.ms.
  119. X
  120. X     Once you  have  sucessfully  created  the  parser,  the
  121. Xbytecode compiler, and an object image, type
  122. X
  123. X        st
  124. X
  125. X
  126. Xto run the system.  Now would be a very good time to go read
  127. Xexplore.ms,  which  would tell you more how to find your way
  128. Xaround.
  129. X
  130. X_C_h_a_n_g_e_s _f_r_o_m _L_i_t_t_l_e _S_m_a_l_l_t_a_l_k _v_e_r_s_i_o_n _o_n_e
  131. X
  132. X     The following changes have been made from  version  one
  133. Xto version two:
  134. X
  135. Xo+    The user interface is slightly different.  This is most
  136. X     apparent   in  the  way  new  classes  are  added  (see
  137. X     explore.ms), and in the fact that expressions will  not
  138. X     be  printed unless you explicitly request printing, and
  139. X     in the fact that new global variables cannot be created
  140. X     at the command level merely by assignment.
  141. X
  142. Xo+    Much (very much) more of the system is now  written  in
  143. X     Smalltalk, rather than C.  This allows the user to see,
  144. X     and modify it if they wish.  This also means  that  the
  145. X     virtual machine is now much smaller.
  146. X
  147. Xo+    The pseudo variable selfProcess is no longer supported.
  148. X     The  variables  true,  false and nil are now treated as
  149. X     global variables, not  pseudo  variables  (see  below).
  150. X     There  are  plans  for adding processes to version two,
  151. X     but they have not been formalized yet.
  152. X
  153. Xo+    Global variables are now supported; in fact classes are
  154. X     now simply global variables, as are the variables true,
  155. X
  156. X
  157. X
  158. X                      October 26, 1987
  159. X
  160. X
  161. X
  162. X
  163. X
  164. X                           - 3 -
  165. X
  166. X
  167. X     false, smalltalk and nil.  The global variable  global-
  168. X     Names  contains  the  dictionary of all currently known
  169. X     global variables and their values.  (Pool variables are
  170. X     still not supported).
  171. X
  172. Xo+    The internal bytecodes are slightly different.  In par-
  173. X     ticular,  the  bytecode  representing ``send to super''
  174. X     has been eliminated, and a bytecode representing ``do a
  175. X     primitive'' has been added.
  176. X
  177. Xo+    The internal representation of  objects  is  different.
  178. X     Instead  of the ``super-object'' chain, objects are now
  179. X     created big enough to hold all the  instance  variables
  180. X     for  all  their  superclasses.   (This is the way it is
  181. X     done in Smalltalk-80, and, to the best of my knowledge,
  182. X     in Smalltalk-V).
  183. X
  184. Xo+    The Collection  hierarchy  has  been  rearranged.   The
  185. X     rational for this change is explained in more detail in
  186. X     another essay.  (possibly not written yet).
  187. X
  188. Xo+    Some methods, most notably the error  message  methods,
  189. X     have  been  moved  out  of  class Object and into class
  190. X     Smalltalk.
  191. X
  192. Xo+    The syntax for primitives  is  different;  the  keyword
  193. X     primitive has been eliminated, and named primitives are
  194. X     now gone as well.  Fewer actions are performed by prim-
  195. X     itives, having been replaced by Smalltalk methods.
  196. X
  197. Xo+    Command line options, such as the  fast  load  feature,
  198. X     have been eliminated.  However, since version two reads
  199. X     in a binary object image, not a textual  file,  loading
  200. X     should be considerably faster.
  201. X
  202. X_E_l_e_c_t_r_o_n_i_c _C_o_m_m_u_n_i_c_a_t_i_o_n
  203. X
  204. X     Here is my address, various net addresses:
  205. X
  206. X        Tim Budd
  207. X        Oregon State University
  208. X        Department of Computer Science
  209. X        Corvallis, Oregon 97331 USA
  210. X        (503) 754-3273
  211. X
  212. X        budd@ cs.orst.edu
  213. X
  214. X        {tektronix, hp-pcd} !orstcs!budd
  215. X
  216. X
  217. X_C_h_a_n_g_e_s
  218. X
  219. X     I want to emphasize that this is not even  a  beta-test
  220. Xversion (does that make it an alpha or a gamma version?).  I
  221. X
  222. X
  223. X
  224. X                      October 26, 1987
  225. X
  226. X
  227. X
  228. X
  229. X
  230. X                           - 4 -
  231. X
  232. X
  233. Xwill be making a number of changes, hopefully just additions
  234. Xto  the initial image, in the next few months.  In addition,
  235. XI hope to prepare versions for other machines,  notably  the
  236. XMacintosh  and  the IBM PC.  I am also encouraging others to
  237. Xport the system to new  machines.   If  you  have  done  so,
  238. Xplease let me know.
  239. X
  240. X
  241. X
  242. X
  243. X
  244. X
  245. X
  246. X
  247. X
  248. X
  249. X
  250. X
  251. X
  252. X
  253. X
  254. X
  255. X
  256. X
  257. X
  258. X
  259. X
  260. X
  261. X
  262. X
  263. X
  264. X
  265. X
  266. X
  267. X
  268. X
  269. X
  270. X
  271. X
  272. X
  273. X
  274. X
  275. X
  276. X
  277. X
  278. X
  279. X
  280. X
  281. X
  282. X
  283. X
  284. X
  285. X
  286. X
  287. X
  288. X
  289. X
  290. X                      October 26, 1987
  291. X
  292. X
  293. /
  294. echo 'x - env.h'
  295. sed 's/^X//' > env.h << '/'
  296. X/*
  297. X    Little Smalltalk, version two
  298. X    Written by Tim Budd, Oregon State University, July 1987
  299. X
  300. X    environmental factors
  301. X
  302. X    This include file gathers together environmental factors that
  303. X    are likely to change from one C compiler to another, or from
  304. X    one system to another.  Please refer to the installation 
  305. X    notes for more information.
  306. X*/
  307. X
  308. X/* ### the following two define statements should be edit to conform
  309. Xto your specific system, and should be the only changes most installations
  310. Xneed to make ### */
  311. X
  312. X/*============= define the kind of system you are on ===========*/
  313. X
  314. X# define B42
  315. X
  316. X# define INITIALIMAGE "imageFile"
  317. X/*=============== rules for various systems ====================*/
  318. X
  319. X# ifdef B42
  320. X    /* Berkeley 4.2, 4.3 and compatible, which include: */
  321. X        /* sequent balance */
  322. X        /* Harris HCX-7 */
  323. X        /* sun workstations */
  324. X
  325. Xtypedef unsigned char byte;
  326. X
  327. X# define byteToInt(b) (b)
  328. X
  329. X# define longCanBeInt(l) (l == (l & 037777))
  330. X
  331. X# define STRINGS
  332. X# define SIGNALS
  333. X
  334. X# endif
  335. X
  336. X# ifdef SYSV
  337. X    /* system V systems including: */
  338. X    /*    HP-UX for the HP-9000 series */
  339. X    /*     TEK 4404 with some modifications (see install.ms) */
  340. X
  341. Xtypedef unsigned char byte;
  342. X
  343. X# define byteToInt(b) (b)
  344. X
  345. X# define longCanBeInt(l) (l == (l & 037777))
  346. X
  347. X# define STRING
  348. X# define SIGNALS
  349. X
  350. X# endif
  351. X
  352. X# ifdef TURBOC
  353. X    /* IBM PC and compatiables using the TURBO C compiler */
  354. X    
  355. X    /* there are also changes that have to be made to the 
  356. X        smalltalk source; see installation notes for
  357. X        details */
  358. X
  359. Xtypedef unsigned char byte;
  360. X
  361. X# define byteToInt(b) (b)
  362. X
  363. X# define longCanBeInt(l) (l == (l & 037777))
  364. X
  365. X# define STRING
  366. X# define SSIGNALS
  367. X# define ALLOC
  368. X# define BINREADWRITE
  369. X# define PROTO
  370. X
  371. X#endif
  372. X
  373. X/* ======== various defines that should work on all systems ==== */
  374. X
  375. X# define true 1
  376. X# define false 0
  377. X
  378. X    /* define the datatype boolean */
  379. X# ifdef NOTYPEDEF
  380. X# define boolean int
  381. X# endif
  382. X# ifndef NOTYPEDEF
  383. Xtypedef int boolean;
  384. X# endif
  385. X
  386. X    /* define a bit of lint silencing */
  387. X    /*  ignore means ``i know this function returns something,
  388. X        but I really, really do mean to ignore it */
  389. X# ifdef NOVOID
  390. X# define ignore
  391. X# define noreturn
  392. X# define void int
  393. X# endif
  394. X# ifndef NOVOID
  395. X# define ignore (void)
  396. X# define noreturn void
  397. X# endif
  398. X
  399. X/* prototypes are another problem.  If they are available, they should be
  400. Xused; but if they are not available their use will cause compiler errors.
  401. XTo get around this we define a lot of symbols which become nothing if
  402. Xprototypes aren't available */
  403. X# ifdef PROTO
  404. X
  405. X# define X ,
  406. X# define OBJ object
  407. X# define OBJP object *
  408. X# define INT int
  409. X# define BOOL boolean
  410. X# define STR char *
  411. X# define FLOAT double
  412. X# define NOARGS void
  413. X# define FILEP FILE *
  414. X
  415. X# endif
  416. X
  417. X# ifndef PROTO
  418. X
  419. X# define X
  420. X# define OBJ
  421. X# define OBJP
  422. X# define INT
  423. X# define BOOL
  424. X# define STR
  425. X# define FLOAT
  426. X# define NOARGS
  427. X# define FILEP
  428. X
  429. X# endif
  430. /
  431. echo 'x - interp.c'
  432. sed 's/^X//' > interp.c << '/'
  433. X/*
  434. X    Little Smalltalk version 2
  435. X    Written by Tim Budd, Oregon State University, July 1987
  436. X
  437. X    bytecode interpreter module
  438. X
  439. X    execute bytecodes for a given method until one of six events occur
  440. X    1. A message must be sent to another object
  441. X    2. A message must be sent to super
  442. X    3. A return from a method occurs
  443. X    4. An explicit return from a block occurs (backs up the process chain)
  444. X    5. A block must be created
  445. X    6. A block must begin execution
  446. X
  447. X    the global variable finalTask indicates which of the six events is to
  448. X    be performed.  Various other global variables (described in process.h)
  449. X    give other information to be used in performing the called for task.
  450. X
  451. X    Note that the interpreter is called as part of the
  452. X    main instruction sequence (single process) and (via a primitive call)
  453. X    as part of the multi-process scheduler loop (class Scheduler, Process,
  454. X    et al)
  455. X*/
  456. X
  457. X# include <stdio.h>
  458. X# include "env.h"
  459. X# include "memory.h"
  460. X# include "names.h"
  461. X# include "process.h"
  462. X# include "interp.h"
  463. X
  464. Xextern object unSyms[], binSyms[], keySyms[];
  465. Xextern boolean primitive(INT X OBJP X INT);
  466. X
  467. X# define nextByte() byteToInt(bytecodes[byteCounter++])
  468. X# define ipush(x) incr(stack[stacktop++] = x)
  469. X/* note that ipop leaves a ref count on the popped object */
  470. X# define ipop(x)  x=stack[--stacktop]; stack[stacktop]=nilobj
  471. X
  472. Xnoreturn execute(method, byteCounter, stack, stacktop, arguments, temporaries)
  473. Xobject method, *stack, *arguments, *temporaries;
  474. Xregister int byteCounter;
  475. Xregister int stacktop;
  476. X{
  477. X    int i, j, low, high;
  478. X    object receiver, *instance, *literals;
  479. X    object newobj;
  480. X    byte  *bytecodes;
  481. X    boolean done;
  482. X    double f;
  483. X
  484. X    /* do initialization */
  485. X    receiver = arguments[0];
  486. X    if (isInteger(receiver))
  487. X        instance = (object *) 0;
  488. X    else
  489. X        instance = memoryPtr(receiver);
  490. X    bytecodes = bytePtr(basicAt(method, bytecodesInMethod));
  491. X    literals = memoryPtr(basicAt(method, literalsInMethod));
  492. X    done = false;
  493. X
  494. X
  495. X    while( ! done ) {
  496. X        low = (high = nextByte()) & 0x0F;
  497. X        high >>= 4;
  498. X        if (high == 0) {
  499. X            high = low;
  500. X            low = nextByte();
  501. X            }
  502. X/*if (debugging) ignore fprintf(stderr,"executing %s %d %d %d\n", 
  503. XcharPtr(basicAt(method, messageInMethod)), byteCounter, high, low);*/
  504. X
  505. X        switch(high) {
  506. X            case PushInstance:
  507. X                ipush(instance[low]);
  508. X                break;
  509. X
  510. X            case PushArgument:
  511. X                ipush(arguments[low]);
  512. X                break;
  513. X
  514. X            case PushTemporary:
  515. X                ipush(temporaries[low]);
  516. X                break;
  517. X
  518. X            case PushLiteral:
  519. X                ipush(literals[low]);
  520. X                break;
  521. X
  522. X            case PushConstant:
  523. X                if (low == 3)
  524. X                    low = -1;
  525. X                if (low < 3) {
  526. X                    ipush(newInteger(low));
  527. X                    }
  528. X                else
  529. X                    switch(low) {
  530. X                        case 4: 
  531. X                            ipush(nilobj);
  532. X                            break;
  533. X
  534. X                        case 5:
  535. X                            ipush(trueobj);
  536. X                            break;
  537. X
  538. X                        case 6:
  539. X                            ipush(falseobj);
  540. X                            break;
  541. X
  542. X                        case 7:
  543. X                            ipush(smallobj);
  544. X                            break;
  545. X
  546. X                        case 8:
  547. X                            ipush(globalNames);
  548. X                            break;
  549. X
  550. X                        default:
  551. X                    sysError("not done yet","pushConstant");
  552. X                        }
  553. X                break;
  554. X
  555. X            case PushGlobal:
  556. X                newobj = nameTableLookup(globalNames, 
  557. X                    literals[low]);
  558. X                if (newobj == nilobj) {
  559. X                    /* send message instead */
  560. X                    ipush(smallobj);
  561. X                    ipush(literals[low]);
  562. X                    argumentsOnStack = stacktop - 2;
  563. X                    messageToSend = 
  564. X                        newSymbol("cantFindGlobal:");
  565. X                    finalTask = sendMessageTask;
  566. X                    done = true;
  567. X                    }
  568. X                else
  569. X                    ipush(newobj);
  570. X                break;
  571. X    
  572. X            case PopInstance:
  573. X                decr(instance[low]);
  574. X                /* we transfer reference count to instance */
  575. X                ipop(instance[low]);
  576. X                break;
  577. X
  578. X            case PopTemporary:
  579. X                decr(temporaries[low]);
  580. X                /* we transfer reference count to temporaries */
  581. X                ipop(temporaries[low]);
  582. X                break;
  583. X
  584. X            case SendMessage:
  585. X                argumentsOnStack = stacktop - (low + 1);
  586. X                messageToSend = literals[nextByte()];
  587. X                finalTask = sendMessageTask;
  588. X                done = true;
  589. X                break;
  590. X
  591. X            case SendUnary:
  592. X                /* we optimize a couple common messages */
  593. X                if (low == 0) {        /* isNil */
  594. X                    ipop(newobj);
  595. X                    if (newobj == nilobj) {
  596. X                        ipush(trueobj);
  597. X                        }
  598. X                    else {
  599. X                        decr(newobj);
  600. X                        ipush(falseobj);
  601. X                        }
  602. X                    }
  603. X                else if (low == 1) {    /* notNil */
  604. X                    ipop(newobj);
  605. X                    if (newobj == nilobj) {
  606. X                        ipush(falseobj);
  607. X                        }
  608. X                    else {
  609. X                        decr(newobj);
  610. X                        ipush(trueobj);
  611. X                        }
  612. X                    }
  613. X                else {
  614. X                    argumentsOnStack = stacktop - 1;
  615. X                    messageToSend = unSyms[low];
  616. X                    finalTask = sendMessageTask;
  617. X                    done = true;
  618. X                    }
  619. X                break;
  620. X
  621. X            case SendBinary:
  622. X                /* optimize arithmetic as long as no */
  623. X                /* conversions are necessary */
  624. X                /* and overflow does not occur */
  625. X                if (low <= 12) {
  626. X                    if (isInteger(stack[stacktop-1]) &&
  627. X                            isInteger(stack[stacktop-2])) {
  628. X                        ipop(newobj);
  629. X                        i = intValue(newobj);
  630. X                        ipop(newobj);
  631. X                        j = intValue(newobj);
  632. X                        ignore intBinary(low, j, i);
  633. X                        if (returnedObject != nilobj) {
  634. X                            ipush(returnedObject);
  635. X                            break;
  636. X                            }
  637. X                        /* overflowed, go do it */
  638. X                        /* the old fashioned way */
  639. X                        ipush(newInteger(j));
  640. X                        ipush(newInteger(i));
  641. X                        }
  642. X                    else if (isFloat(stack[stacktop-1]) &&
  643. X                        isFloat(stack[stacktop-2])) {
  644. X                        ipop(newobj);
  645. X                        f = floatValue(newobj);
  646. X                        decr(newobj);
  647. X                        ipop(newobj);
  648. X                        ignore floatBinary(low, floatValue(newobj), f);
  649. X                        decr(newobj);
  650. X                        ipush(returnedObject);
  651. X                        break;
  652. X                        }
  653. X                    }
  654. X                argumentsOnStack = stacktop - 2;
  655. X                messageToSend = binSyms[low];
  656. X                finalTask = sendMessageTask;
  657. X                done = true;
  658. X                break;
  659. X
  660. X            case SendKeyword:
  661. X                argumentsOnStack = stacktop - 3;
  662. X                messageToSend = keySyms[low];
  663. X                finalTask = sendMessageTask;
  664. X                done = true;
  665. X                break;
  666. X
  667. X            case DoPrimitive:
  668. X                i = nextByte();
  669. X                done = primitive(i, &stack[stacktop - low], low);
  670. X                incr(returnedObject);
  671. X                /* pop off arguments */
  672. X                for (i = low; i > 0; i--) {
  673. X                    ipop(newobj);
  674. X                    decr(newobj);
  675. X                    }
  676. X                if (! done) {
  677. X                    ipush(returnedObject);
  678. X                    decr(returnedObject);
  679. X                    }
  680. X                break;
  681. X
  682. X            case CreateBlock:
  683. X                /* we do most of the work in making the block */
  684. X                /* leaving it to the caller to fill in */
  685. X                /* the context information */
  686. X                newobj = allocObject(blockSize);
  687. X                setClass(newobj, blockclass);
  688. X                basicAtPut(newobj, argumentCountInBlock, newInteger(low));
  689. X                i = (low > 0) ? nextByte() : 0;
  690. X                basicAtPut(newobj, argumentLocationInBlock, 
  691. X                    newInteger(i));
  692. X                basicAtPut(newobj, bytecountPositionInBlock,
  693. X                    newInteger(byteCounter + 1));
  694. X                incr(returnedObject = newobj);
  695. X                /* avoid a subtle side effect here */
  696. X                i = nextByte();
  697. X                byteCounter = i;
  698. X                finalTask = BlockCreateTask;
  699. X                done = true;
  700. X                break;
  701. X
  702. X            case DoSpecial:
  703. X                switch(low) {
  704. X                    case SelfReturn:
  705. X                        incr(returnedObject = receiver);
  706. X                        finalTask = ReturnTask;
  707. X                        done = true;
  708. X                        break;
  709. X
  710. X                    case StackReturn:
  711. X                        ipop(returnedObject);
  712. X                        finalTask = ReturnTask;
  713. X                        done = true;
  714. X                        break;
  715. X
  716. X                    case BlockReturn:
  717. X                        ipop(returnedObject);
  718. X                        finalTask = BlockReturnTask;
  719. X                        done = true;
  720. X                        break;
  721. X
  722. X                    case Duplicate:
  723. X                        ipop(newobj);
  724. X                        ipush(newobj);
  725. X                        ipush(newobj);
  726. X                        decr(newobj);
  727. X                        break;
  728. X
  729. X                    case PopTop:
  730. X                        ipop(newobj);
  731. X                        decr(newobj);
  732. X                        break;
  733. X
  734. X                    case Branch:
  735. X                        /* avoid a subtle bug here */
  736. X                        i = nextByte();
  737. X                        byteCounter = i;
  738. X                        break;
  739. X
  740. X                    case BranchIfTrue:
  741. X                        ipop(newobj);
  742. X                        i = nextByte();
  743. X                        if (newobj == trueobj) {
  744. X                            /* leave nil on stack */
  745. X                            ++stacktop;
  746. X                            byteCounter = i;
  747. X                            }
  748. X                        decr(newobj);
  749. X                        break;
  750. X
  751. X                    case BranchIfFalse:
  752. X                        ipop(newobj);
  753. X                        i = nextByte();
  754. X                        if (newobj == falseobj) {
  755. X                            /* leave nil on stack */
  756. X                            ++stacktop;
  757. X                            byteCounter = i;
  758. X                            }
  759. X                        decr(newobj);
  760. X                        break;
  761. X
  762. X                    case AndBranch:
  763. X                        ipop(newobj);
  764. X                        i = nextByte();
  765. X                        if (newobj == falseobj) {
  766. X                            ipush(newobj);
  767. X                            byteCounter = i;
  768. X                            }
  769. X                        decr(newobj);
  770. X                        break;
  771. X
  772. X                    case OrBranch:
  773. X                        ipop(newobj);
  774. X                        i = nextByte();
  775. X                        if (newobj == trueobj) {
  776. X                            ipush(newobj);
  777. X                            byteCounter = i;
  778. X                            }
  779. X                        decr(newobj);
  780. X                        break;
  781. X
  782. X                    case SendToSuper:
  783. X                        argumentsOnStack = stacktop -
  784. X                            (nextByte() + 1);
  785. X                        messageToSend = 
  786. X                            literals[nextByte()];
  787. X                        finalTask = sendSuperTask;
  788. X                        done = true;
  789. X                        break;
  790. X
  791. X                    default:
  792. X                        sysError("invalid doSpecial","");
  793. X                        break;
  794. X                }
  795. X                break;
  796. X
  797. X            default:
  798. X                sysError("invalid bytecode","");
  799. X                break;
  800. X        }
  801. X    }
  802. X
  803. X    /* when done, save stack top and bytecode counter */
  804. X    /* before we exit */
  805. X
  806. X    finalStackTop = stacktop;
  807. X    finalByteCounter = byteCounter;
  808. X}
  809. /
  810. echo 'x - memory.c'
  811. sed 's/^X//' > memory.c << '/'
  812. X/*
  813. X    Little Smalltalk, version 2
  814. X    Written by Tim Budd, Oregon State University, July 1987
  815. X
  816. X    Improved incorporating suggestions by 
  817. X        Steve Crawley, Cambridge University, October 1987
  818. X        Steven Pemberton, CWI, Amsterdam, Oct 1987
  819. X
  820. X    memory management module
  821. X
  822. X    This is a rather simple, straightforward, reference counting scheme.
  823. X    There are no provisions for detecting cycles, nor any attempt made
  824. X    at compaction.  Free lists of various sizes are maintained.
  825. X    At present only objects up to 255 bytes can be allocated, 
  826. X    which mostly only limits the size of method (in text) you can create.
  827. X
  828. X    reference counts are not stored as part of an object image, but
  829. X    are instead recreated when the object is read back in.
  830. X    This is accomplished using a mark-sweep algorithm, similar
  831. X    to those used in garbage collection.
  832. X
  833. X    There is a large amount of differences in the qualities of malloc
  834. X    procedures in the Unix world.  Some perform very badly when asked
  835. X    to allocate thousands of very small memory blocks, while others
  836. X    take this without any difficulty.  The routine mBlockAlloc is used
  837. X    to allocate a small bit of memory; the version given below
  838. X    allocates a large block and then chops it up as needed; if desired,
  839. X    for versions of malloc that can handle small blocks with ease
  840. X    this can be replaced using the following macro: 
  841. X
  842. X# define mBlockAlloc(size) (object *) calloc((unsigned) size, sizeof(object))
  843. X
  844. X    This can, and should, be replaced by a better memory management
  845. X    algorithm.
  846. X*/
  847. X# include <stdio.h>
  848. X# include "env.h"
  849. X# include "memory.h"
  850. X# ifdef STRING
  851. X# include <string.h>
  852. X# endif
  853. X# ifdef STRINGS
  854. X# include <strings.h>
  855. X# endif
  856. X
  857. X# define ObjectTableMax 5000
  858. X# define MemoryBlockSize 2000
  859. X
  860. X# ifdef ALLOC
  861. X# include <alloc.h>
  862. X# endif
  863. X# ifndef ALLOC
  864. Xextern char *calloc();
  865. X# endif
  866. X
  867. Xboolean debugging = false;
  868. Xobject sysobj;    /* temporary used to avoid rereference in macros */
  869. Xobject intobj;
  870. X
  871. Xobject symbols;        /* table of all symbols created */
  872. Xobject globalNames;    /* table of all accessible global names */
  873. X
  874. X/*
  875. X    in theory the objectTable should only be accessible to the memory
  876. X    manager.  Indeed, given the right macro definitions, this can be
  877. X    made so.  Never the less, for efficiency sake some of the macros
  878. X    can also be defined to access the object table directly
  879. X*/
  880. X
  881. Xstruct objectStruct objectTable[ObjectTableMax];
  882. X
  883. X/*
  884. X    The following global variables are strictly local to the memory
  885. X    manager module
  886. X*/
  887. X
  888. X# define FREELISTMAX 256
  889. Xstatic object objectFreeList[FREELISTMAX];/* free list of objects */
  890. X
  891. X# ifndef mBlockAlloc
  892. X        /* the current memory block being hacked up */
  893. Xstatic object *memoryBlock;        /* malloc'ed chunck of memory */
  894. Xstatic int    currentMemoryPosition;    /* last used position in above */
  895. X# endif
  896. X
  897. X
  898. X/* initialize the memory management module */
  899. Xnoreturn initMemoryManager() {
  900. X    int i;
  901. X
  902. X    /* set all the free list pointers to zero */
  903. X    for (i = 0; i < FREELISTMAX; i++)
  904. X        objectFreeList[i] = nilobj;
  905. X
  906. X    /* set all the reference counts to zero */
  907. X    for (i = 0; i < ObjectTableMax; i++) {
  908. X        objectTable[i].referenceCount = 0;
  909. X        objectTable[i].size = 0;
  910. X        }
  911. X
  912. X    /* make up the initial free lists */
  913. X    setFreeLists();
  914. X
  915. X# ifndef mBlockAlloc
  916. X    /* force an allocation on first object assignment */
  917. X    currentMemoryPosition = MemoryBlockSize + 1;
  918. X# endif
  919. X
  920. X    /* object at location 0 is the nil object, so give it nonzero ref */
  921. X    objectTable[0].referenceCount = 1;
  922. X    objectTable[0].size = 0;
  923. X    objectTable[0].type = objectMemory;
  924. X
  925. X}
  926. X
  927. X/* setFreeLists - initialise the free lists */
  928. XsetFreeLists() {
  929. X    int z, i;
  930. X    struct objectStruct *p;
  931. X
  932. X    for (z=ObjectTableMax-1; z>0; z--) {
  933. X        if (objectTable[z].referenceCount == 0){
  934. X            /* Unreferenced, so do a sort of sysDecr: */
  935. X            p= &objectTable[z];
  936. X/*if (p->size > 0) printf("Unreferenced: %d\n", z);*/
  937. X            p->class = objectFreeList[p->size];
  938. X            objectFreeList[p->size]= z;
  939. X            for (i= p->size; i>0; )
  940. X                p->memory[--i] = nilobj;
  941. X            }
  942. X        }
  943. X}
  944. X
  945. X/* report a (generally fatal) memory manager error */
  946. Xnoreturn sysError(s1, s2)
  947. Xchar *s1, *s2;
  948. X{
  949. X    ignore fprintf(stderr,"%s\n%s\n", s1, s2);
  950. X    ignore abort();
  951. X}
  952. X
  953. X/*
  954. X  mBlockAlloc - rip out a block (array) of object of the given size from
  955. X    the current malloc block 
  956. X*/
  957. X# ifndef mBlockAlloc
  958. Xstatic object *mBlockAlloc(memorySize)
  959. Xint memorySize;
  960. X{    object *objptr;
  961. X
  962. X    if (currentMemoryPosition + memorySize >= MemoryBlockSize) {
  963. X        
  964. X        /* we toss away space here.  Space-Frugal users may want to
  965. X        fix this by making a new object of size
  966. X        MemoryBlockSize - currentMemoryPositon - 1
  967. X        and putting it on the free list, but I think
  968. X        the savings is potentially small */
  969. X
  970. X        memoryBlock = (object *) calloc((unsigned) MemoryBlockSize, sizeof(object));
  971. X        if (! memoryBlock)
  972. X            sysError("out of memory","malloc failed");
  973. X        currentMemoryPosition = 0;
  974. X        }
  975. X    objptr = (object *) &memoryBlock[currentMemoryPosition];
  976. X    currentMemoryPosition += memorySize;
  977. X    return(objptr);
  978. X}
  979. X# endif
  980. X
  981. X/* allocate a new memory object */
  982. Xobject alcObject(memorySize, memoryType)
  983. Xint memorySize;
  984. Xint memoryType;
  985. X{    int i;
  986. X    register int position;
  987. X    boolean done;
  988. X
  989. X    if (memorySize >= FREELISTMAX) {
  990. X        sysError("allocation bigger than 255","");
  991. X        }
  992. X
  993. X    /* first try the free lists, this is fastest */
  994. X    if ((position = objectFreeList[memorySize]) != 0) {
  995. X        objectFreeList[memorySize] = objectTable[position].class;
  996. X        }
  997. X
  998. X    /* if not there, next try making a size zero object and
  999. X        making it bigger */
  1000. X    else if ((position = objectFreeList[0]) != 0) {
  1001. X        objectFreeList[0] = objectTable[position].class;
  1002. X        objectTable[position].size = memorySize;
  1003. X        objectTable[position].memory = mBlockAlloc(memorySize);
  1004. X        }
  1005. X
  1006. X    else {        /* not found, must work a bit harder */
  1007. X        done = false;
  1008. X
  1009. X        /* first try making a bigger object smaller */
  1010. X        for (i = memorySize + 1; i < FREELISTMAX; i++)
  1011. X            if ((position = objectFreeList[i]) != 0) {
  1012. X                objectFreeList[i] = objectTable[position].class;
  1013. X                /* just trim it a bit */
  1014. X                objectTable[position].size = memorySize;
  1015. X                done = true;
  1016. X                break;
  1017. X                }
  1018. X
  1019. X        /* next try making a smaller object bigger */
  1020. X        if (! done)
  1021. X            for (i = 1; i < memorySize; i++)
  1022. X                if ((position = objectFreeList[i]) != 0) {
  1023. X                    objectFreeList[i] =
  1024. X                        objectTable[position].class;
  1025. X                    objectTable[position].size = memorySize;
  1026. X# ifdef mBlockAlloc
  1027. X                    free(objectTable[position].memory);
  1028. X# endif
  1029. X                    objectTable[position].memory = 
  1030. X                        mBlockAlloc(memorySize);
  1031. X                    done = true;
  1032. X                    break;
  1033. X                    }
  1034. X
  1035. X        /* if we STILL don't have it then there is nothing */
  1036. X        /* more we can do */
  1037. X        if (! done)
  1038. X            sysError("out of objects","alloc");
  1039. X        }
  1040. X
  1041. X    /* set class and type */
  1042. X    objectTable[position].referenceCount = 0;
  1043. X    objectTable[position].class = nilobj;
  1044. X    objectTable[position].type = memoryType;
  1045. X    return(position << 1);
  1046. X}
  1047. X
  1048. Xobject allocSymbol(str)
  1049. Xchar *str;
  1050. X{    object newSym;
  1051. X
  1052. X    newSym = alcObject((2 + strlen(str))/2, charMemory);
  1053. X    ignore strcpy(charPtr(newSym), str);
  1054. X    return(newSym);
  1055. X}
  1056. X
  1057. X# ifdef incr
  1058. Xobject incrobj;        /* buffer for increment macro */
  1059. X# endif
  1060. X# ifndef incr
  1061. Xnoreturn incr(z)
  1062. Xobject z;
  1063. X{
  1064. X    if (z && ! isInteger(z)) {
  1065. X        objectTable[z>>1].referenceCount++;
  1066. X        }
  1067. X}
  1068. X# endif
  1069. X
  1070. X# ifndef decr
  1071. Xnoreturn decr(z)
  1072. Xobject z;
  1073. X{
  1074. X    if (z && ! isInteger(z)) {
  1075. X        if (--objectTable[z>>1].referenceCount <= 0) {
  1076. X            sysDecr(z);
  1077. X            }
  1078. X        }
  1079. X}
  1080. X# endif
  1081. X
  1082. X/* do the real work in the decr procedure */
  1083. Xnoreturn sysDecr(z)
  1084. Xobject z;
  1085. X{    register struct objectStruct *p;
  1086. X    register int i;
  1087. X
  1088. X    p = &objectTable[z>>1];
  1089. X    if (p->referenceCount < 0) {
  1090. X        sysError("negative reference count","");
  1091. X        }
  1092. X    decr(p->class);
  1093. X    p->class = objectFreeList[p->size];
  1094. X    objectFreeList[p->size] = z>>1;
  1095. X    if (((int) p->size) > 0) {
  1096. X        if (p->type == objectMemory)
  1097. X            for (i = p->size; i > 0 ; )
  1098. X                decr(p->memory[--i]);
  1099. X        for (i = p->size; i > 0; )
  1100. X            p->memory[--i] = nilobj;
  1101. X        }
  1102. X
  1103. X}
  1104. X
  1105. X# ifndef basicAt
  1106. Xobject basicAt(z, i)
  1107. Xobject z;
  1108. Xregister int i;
  1109. X{
  1110. X    if (isInteger(z))
  1111. X        sysError("attempt to index","into integer");
  1112. X    else if ((i <= 0) || (i > objectSize(z))) {
  1113. X        ignore fprintf(stderr,"index %d size %d\n", i, (int) objectSize(z));
  1114. X        sysError("index out of range","in basicAt");
  1115. X        }
  1116. X    else
  1117. X        return(sysMemPtr(z)[i-1]);
  1118. X    return(0);
  1119. X}
  1120. X# endif
  1121. X# ifndef basicAtPut
  1122. X
  1123. Xnoreturn basicAtPut(z, i, v)
  1124. Xobject z, v;
  1125. Xregister int i;
  1126. X{
  1127. X    if (isInteger(z))
  1128. X        sysError("assigning index to","integer value");
  1129. X    else if ((i <= 0) || (i > objectSize(z))) {
  1130. X        ignore fprintf(stderr,"index %d size %d\n", i, (int) objectSize(z));
  1131. X        sysError("index out of range","in basicAtPut");
  1132. X        }
  1133. X    else {
  1134. X        incr(v);
  1135. X        decr(sysMemPtr(z)[i-1]);
  1136. X        sysMemPtr(z)[i-1] = v;
  1137. X        }
  1138. X}
  1139. X# endif
  1140. X
  1141. X# ifndef byteAt
  1142. Xint byteAt(z, i)
  1143. Xobject z;
  1144. Xregister int i;
  1145. X{    char *bp;
  1146. X
  1147. X    if (isInteger(z))
  1148. X        sysError("indexing integer","byteAt");
  1149. X    else if ((i <= 0) || (i > 2 * objectSize(z))) {
  1150. X        sysError("index out of range","byteAt");
  1151. X        }
  1152. X    else {
  1153. X        bp = charPtr(z);
  1154. X        i = bp[i-1];
  1155. X        }
  1156. X    return(i);
  1157. X}
  1158. X# endif
  1159. X
  1160. X# ifndef byteAtPut
  1161. Xnoreturn byteAtPut(z, i, x)
  1162. Xobject z;
  1163. Xint i, x;
  1164. X{    char *bp;
  1165. X
  1166. X    if (isInteger(z))
  1167. X        sysError("indexing integer","byteAtPut");
  1168. X    else if ((i <= 0) || (i > 2 * objectSize(z))) {
  1169. X        sysError("index out of range", "byteAtPut");
  1170. X        }
  1171. X    else {
  1172. X        bp = charPtr(z);
  1173. X        bp[i-1] = x;
  1174. X        }
  1175. X}
  1176. X# endif
  1177. X/*
  1178. X    imageWrite - write out an object image
  1179. X*/
  1180. Xstatic iwerr() { sysError("imageWrite count error",""); }
  1181. X
  1182. X/* ptr - used for conversions to keep lint happy */
  1183. X# define ptr(x) ((char *) x)
  1184. X
  1185. Xnoreturn imageWrite(fp)
  1186. XFILE *fp;
  1187. X{    short i;
  1188. X
  1189. X    if (fwrite(ptr(&symbols), sizeof(object), 1, fp) != 1) iwerr();
  1190. X    if (fwrite(ptr(&globalNames), sizeof(object), 1, fp) != 1) iwerr();
  1191. X
  1192. X    for (i = 0; i < ObjectTableMax; i++) {
  1193. X        if (objectTable[i].referenceCount > 0) {
  1194. X            if (fwrite(ptr(&i), sizeof(short), 1, fp) != 1) iwerr();
  1195. X            if (fwrite(ptr(&objectTable[i].class), sizeof(object), 1, fp)
  1196. X                != 1) iwerr();
  1197. X            if (fwrite(ptr(&objectTable[i].size), sizeof(byte), 1, fp)
  1198. X                != 1) iwerr();
  1199. X            if (fwrite(ptr(&objectTable[i].type), sizeof(byte), 1, fp)
  1200. X                != 1) iwerr();
  1201. X            if (objectTable[i].size != 0)
  1202. X                if (fwrite(ptr(objectTable[i].memory), sizeof(object),
  1203. X                    (int) byteToInt(objectTable[i].size), fp) != byteToInt(objectTable[i].size))
  1204. X                        iwerr();
  1205. X            }
  1206. X        }
  1207. X}
  1208. X
  1209. X/*
  1210. XWritten by Steven Pemberton:
  1211. XThe following routine assures that objects read in are really referenced,
  1212. Xeliminating junk that may be in the object file but not referenced.
  1213. XIt is essentially a marking garbage collector algorithm using the 
  1214. Xreference counts as the mark
  1215. X*/
  1216. X
  1217. Xstatic visit(x)
  1218. Xobject x;
  1219. X{
  1220. X    int i, s;
  1221. X    object *p;
  1222. X
  1223. X    if (x && !isInteger(x)) {
  1224. X        if (++(objectTable[x>>1].referenceCount) == 1) {
  1225. X            /* then it's the first time we've visited it, so: */
  1226. X            visit(objectTable[x>>1].class);
  1227. X            s= (int) byteToInt(objectTable[x>>1].size);
  1228. X            if (s>0 && objectTable[x>>1].type == objectMemory) {
  1229. X                p= objectTable[x>>1].memory;
  1230. X                for (i=0; i < s; i++) visit(p[i]);
  1231. X                }
  1232. X            }
  1233. X        }
  1234. X}
  1235. X
  1236. X/*
  1237. X    imageRead - read in an object image
  1238. X        we toss out the free lists built initially,
  1239. X        reconstruct the linkages, then rebuild the free
  1240. X        lists around the new objects.
  1241. X        The only objects with nonzero reference counts
  1242. X        will be those reachable from either symbols or
  1243. X        globalNames.
  1244. X*/
  1245. Xstatic irerr() { sysError("imageWrite count error",""); }
  1246. X
  1247. Xnoreturn imageRead(fp)
  1248. XFILE *fp;
  1249. X{    short i;
  1250. X    object *p;
  1251. X
  1252. X    if (fread(ptr(&symbols), sizeof(object), 1, fp) != 1) irerr();
  1253. X    if (fread(ptr(&globalNames), sizeof(object), 1, fp) != 1) irerr();
  1254. X
  1255. X    while(fread(ptr(&i), sizeof(short), 1, fp) == 1) {
  1256. X        if ((i < 0) || (i > ObjectTableMax))
  1257. X            sysError("index out of range","imageRead");
  1258. X        if (fread(ptr(&objectTable[i].class), sizeof(object), 1, fp)
  1259. X                != 1) irerr();
  1260. X        if ((objectTable[i].class < 0) || 
  1261. X            (objectTable[i].class > ObjectTableMax))
  1262. X                sysError("class out of range","imageRead");
  1263. X        if (fread(ptr(&objectTable[i].size), sizeof(byte), 1, fp)
  1264. X                != 1) irerr();
  1265. X        if (fread(ptr(&objectTable[i].type), sizeof(byte), 1, fp)
  1266. X                != 1) irerr();
  1267. X        if (objectTable[i].size != 0) {
  1268. X            p = objectTable[i].memory = mBlockAlloc((int) objectTable[i].size);
  1269. X            if (fread(ptr(p), sizeof(object),
  1270. X                 (int) byteToInt(objectTable[i].size), fp) != byteToInt(objectTable[i].size))
  1271. X                        irerr();
  1272. X            }
  1273. X        else
  1274. X            objectTable[i].memory = (object *) 0;
  1275. X        }
  1276. X
  1277. X    /* now restore ref counts, getting rid of unneeded junk */
  1278. X    visit(symbols);
  1279. X    visit(globalNames);
  1280. X    /* toss out the old free lists, build new ones */
  1281. X    objectFreeList[0] = nilobj;
  1282. X    setFreeLists();
  1283. X}
  1284. X
  1285. Xstatic ncopy(p, q, n)
  1286. Xchar *p, *q;
  1287. Xint n;
  1288. X{
  1289. X
  1290. X    while (n>0) {
  1291. X        *p++ = *q++; 
  1292. X        n--;
  1293. X        }
  1294. X}
  1295. X
  1296. Xobject allocFloat(d)
  1297. Xdouble d;
  1298. X{    object newObj;
  1299. X
  1300. X    newObj = alcObject((int) sizeof (double), floatMemory);
  1301. X    ncopy(charPtr(newObj), (char *) &d, (int) sizeof (double));
  1302. X    return(newObj);
  1303. X}
  1304. X
  1305. Xdouble floatValue(obj)
  1306. Xobject obj;
  1307. X{    double d;
  1308. X
  1309. X    ncopy((char *) &d, charPtr(obj), (int) sizeof (double));
  1310. X    return(d);
  1311. X}
  1312. X
  1313. Xint objcount() 
  1314. X{    int i, count;
  1315. X
  1316. X    
  1317. X    for (count = i = 0; i < ObjectTableMax; i++)
  1318. X        if (objectTable[i].referenceCount > 0)
  1319. X            count++;
  1320. X    return(count);
  1321. X}
  1322. /
  1323. echo 'x - process.c'
  1324. sed 's/^X//' > process.c << '/'
  1325. X/*
  1326. X    Little Smalltalk, version 2
  1327. X    Written by Tim Budd, Oregon State University, July 1987
  1328. X
  1329. X    Process Manager
  1330. X
  1331. X    This module manages the stack of pending processes.
  1332. X    SendMessage is called when it is desired to send a message to an
  1333. X    object.  It looks up the method associated with the class of
  1334. X    the receiver, then executes it.
  1335. X    A block context is created only when it is necessary, and when it
  1336. X    is required the routine executeFromContext is called instead of
  1337. X    sendMessage.
  1338. X    DoInterp is called by a primitive method to execute an interpreter,
  1339. X    it returns the interpreter to which execution should continue
  1340. X    following execution.
  1341. X*/
  1342. X# include <stdio.h>
  1343. X# include "env.h"
  1344. X# include "memory.h"
  1345. X# include "names.h"
  1346. X# include "process.h"
  1347. X
  1348. X# define ProcessStackMax 2000
  1349. X
  1350. Xextern noreturn execute(OBJ X INT X OBJP X INT X OBJP X OBJP);
  1351. X
  1352. X    /* values set by interpreter when exiting */
  1353. Xint finalStackTop;    /* stack top when finished with interpreter */
  1354. Xint finalByteCounter;    /* bytecode counter when finished with interpreter */
  1355. Xint argumentsOnStack;    /* position of arguments on stack for mess send */
  1356. Xobject messageToSend;    /* message to send */
  1357. Xobject returnedObject;    /* object returned from message */
  1358. XtaskType finalTask;    /* next task to do (see below) */
  1359. Xobject creator;        /* creating interpreter for blocks */
  1360. X
  1361. Xstatic object blockReturnContext;
  1362. X
  1363. Xobject processStack[ProcessStackMax];
  1364. Xint processStackTop = 0;
  1365. X
  1366. X/*
  1367. X    we cache recently used methods, in case we want them again
  1368. X*/
  1369. X
  1370. X# define ProcessCacheSize 101    /* a suitable prime number */
  1371. X
  1372. Xstruct {
  1373. X    object startClass, messageSymbol, methodClass, theMethod;
  1374. X    } methodCache[ProcessCacheSize];
  1375. X
  1376. Xnoreturn prpush(newobj)
  1377. Xobject newobj;
  1378. X{
  1379. X    incr(processStack[processStackTop++] = newobj);
  1380. X    if (processStackTop >= ProcessStackMax)
  1381. X        sysError("stack overflow","process stack");
  1382. X}
  1383. X
  1384. X/* flush out cache so new methods can be read in */
  1385. Xnoreturn flushMessageCache()
  1386. X{    int i;
  1387. X
  1388. X    for (i = 0; i < ProcessCacheSize; i++)
  1389. X        methodCache[i].messageSymbol = nilobj;
  1390. X}
  1391. X
  1392. Xstatic object findMethod(hash, message, startingClass)
  1393. Xint hash;
  1394. Xobject message, startingClass;
  1395. X{    object method, class, methodtable;
  1396. X
  1397. X    /* first examine cache */
  1398. X    if ((methodCache[hash].messageSymbol == message) &&
  1399. X        (methodCache[hash].startClass == startingClass)) {
  1400. X        /* found it in cache */
  1401. X        method = methodCache[hash].theMethod;
  1402. X        }
  1403. X    else {    /* must look in methods tables */
  1404. X        method = nilobj;
  1405. X        class = startingClass;
  1406. X        while ( class != nilobj ) {
  1407. X            methodtable = basicAt(class, methodsInClass);
  1408. X            if (methodtable != nilobj)
  1409. X                method = nameTableLookup(methodtable, message);
  1410. X            if (method != nilobj) {
  1411. X                /* fill in cache */
  1412. X                methodCache[hash].messageSymbol = message;
  1413. X                methodCache[hash].startClass = startingClass;
  1414. X                methodCache[hash].methodClass = class;
  1415. X                methodCache[hash].theMethod = method;
  1416. X                class = nilobj;
  1417. X                }
  1418. X            else
  1419. X                class = basicAt(class, superClassInClass);
  1420. X            }
  1421. X        }
  1422. X
  1423. X    return(method);
  1424. X}
  1425. X
  1426. X/* newContext - create a new context.  Note this returns three values,
  1427. Xvia side effects
  1428. X*/
  1429. Xstatic newContext(method, methodClass, contextobj, argobj, tempobj)
  1430. Xobject method, methodClass, *contextobj, argobj, *tempobj;
  1431. X{    int temporarysize;
  1432. X
  1433. X    *contextobj = allocObject(contextSize);
  1434. X    incr(*contextobj);
  1435. X    setClass(*contextobj, contextclass);
  1436. X    basicAtPut(*contextobj, methodInContext, method);
  1437. X    basicAtPut(*contextobj, methodClassInContext, methodClass);
  1438. X    basicAtPut(*contextobj, argumentsInContext, argobj);
  1439. X    temporarysize = intValue(basicAt(method, temporarySizeInMethod));
  1440. X    *tempobj = newArray(temporarysize);
  1441. X    basicAtPut(*contextobj, temporariesInContext, *tempobj);
  1442. X}
  1443. X
  1444. Xnoreturn sendMessage(message, startingClass, argumentPosition)
  1445. Xobject message, startingClass;
  1446. Xint argumentPosition;
  1447. X{    object method, methodClass, size;
  1448. X    object contextobj, tempobj, argobj, errMessage;
  1449. X    int i, hash, bytecounter, temporaryPosition, errloc;
  1450. X    int argumentsize, temporarySize;
  1451. X    boolean done;
  1452. X
  1453. X    /* compute size of arguments part of stack */
  1454. X    argumentsize = processStackTop - argumentPosition;
  1455. X
  1456. X    hash = (message + startingClass) % ProcessCacheSize;
  1457. X    method = findMethod(hash, message, startingClass);
  1458. X/*fprintf(stderr,"sending message %s class %s\n", charPtr(message), charPtr(basicAt(startingClass, nameInClass)));*/
  1459. X
  1460. X    if (method == nilobj) {        /* didn't find it */
  1461. X        errMessage = newSymbol("class:doesNotRespond:");
  1462. X        if (message == errMessage)
  1463. X            /* better give up */
  1464. X            sysError("didn't find method", charPtr(message));
  1465. X        else {
  1466. X            errloc = processStackTop;
  1467. X            prpush(smallobj);
  1468. X            prpush(startingClass);
  1469. X            prpush(message);
  1470. X            sendMessage(errMessage, getClass(smallobj), errloc);
  1471. X            }
  1472. X        }
  1473. X    else {            /* found it, start execution */
  1474. X        /* initialize things for execution */
  1475. X        bytecounter = 0;
  1476. X        done = false;
  1477. X
  1478. X        /* allocate temporaries */
  1479. X        temporaryPosition = processStackTop;
  1480. X        size = basicAt(method, temporarySizeInMethod);
  1481. X        if (! isInteger(size))
  1482. X            sysError("temp size not integer","in method");
  1483. X        else
  1484. X            for (i = temporarySize = intValue(size); i > 0; i--)
  1485. X                prpush(nilobj);
  1486. X        methodClass = methodCache[hash].methodClass;
  1487. X
  1488. X        while( ! done ) {
  1489. X            execute(method, bytecounter, 
  1490. X                processStack, processStackTop,
  1491. X                &processStack[argumentPosition],
  1492. X                &processStack[temporaryPosition]);
  1493. X            bytecounter = finalByteCounter;
  1494. X            processStackTop = finalStackTop;
  1495. X
  1496. X            switch(finalTask) {
  1497. X                case sendMessageTask:
  1498. X                    sendMessage(messageToSend, 
  1499. X                        getClass(processStack[argumentsOnStack]),
  1500. X                        argumentsOnStack);
  1501. X                    if (finalTask == BlockReturnTask)
  1502. X                        done = true;
  1503. X                    break;
  1504. X
  1505. X                case sendSuperTask:
  1506. X                    sendMessage(messageToSend,
  1507. X                        basicAt(methodClass, superClassInClass),
  1508. X                        argumentsOnStack);
  1509. X                    if (finalTask == BlockReturnTask)
  1510. X                        done = true;
  1511. X                    break;
  1512. X
  1513. X
  1514. X                case ContextExecuteTask:
  1515. X                    contextobj = messageToSend;
  1516. X                    executeFromContext(contextobj,
  1517. X                        argumentsOnStack);
  1518. X                    decr(contextobj);
  1519. X                    if (finalTask == ReturnTask)
  1520. X                        processStack[processStackTop++] = returnedObject;
  1521. X                    else
  1522. X                        done = true;
  1523. X                    break;
  1524. X
  1525. X                case BlockCreateTask:
  1526. X                    /* block is in returnedObject, we just add */
  1527. X                    /* context info  but first we must */
  1528. X                    /* create the context */
  1529. X                    argobj = newArray(argumentsize);
  1530. X                    newContext(method, methodClass, &contextobj, argobj, &tempobj);
  1531. X                    for (i = 1; i <= argumentsize; i++) {
  1532. X                        basicAtPut(argobj, i, processStack[argumentPosition + i - 1]);
  1533. X                        }
  1534. X                    for (i = 1; i <= temporarySize; i++) {
  1535. X                        basicAtPut(tempobj, i, processStack[temporaryPosition + i - 1]);
  1536. X                        }
  1537. X                    basicAtPut(returnedObject, contextInBlock, contextobj);
  1538. X                    processStack[processStackTop++] = returnedObject;
  1539. X                    /* we now execute using context - */
  1540. X                    /* so that changes to temp will be */
  1541. X                    /* recorded properly */
  1542. X                    executeFromContext(contextobj, bytecounter);
  1543. X                    while (processStackTop > argumentPosition) {
  1544. X                        decr(processStack[--processStackTop]);
  1545. X                        processStack[processStackTop] = nilobj;
  1546. X                        }
  1547. X
  1548. X                    /* if it is a block return, */
  1549. X                    /* see if it is our context */
  1550. X                    /* if so, make into a simple return */
  1551. X                    /* otherwise pass back to caller */
  1552. X                    /* we can decr, since only nums are */
  1553. X                    /* important */
  1554. X                    decr(contextobj);
  1555. X                    if (finalTask == BlockReturnTask) {
  1556. X                        if (blockReturnContext != contextobj)
  1557. X                            return;
  1558. X                        }
  1559. X                    finalTask = ReturnTask;
  1560. X                    /* fall into return code */
  1561. X
  1562. X                case ReturnTask:
  1563. X                    while (processStackTop > argumentPosition) {
  1564. X                        decr(processStack[--processStackTop]);
  1565. X                        processStack[processStackTop] = nilobj;
  1566. X                        }
  1567. X                    /* note that ref count is picked up */
  1568. X                    /* from the interpreter */
  1569. X                    processStack[processStackTop++] = returnedObject;
  1570. X                    done = true;
  1571. X                    break;
  1572. X
  1573. X                default:
  1574. X                    sysError("unknown task","in sendMessage");
  1575. X                }
  1576. X            }
  1577. X        }
  1578. X/*fprintf(stderr,"returning from message %s\n", charPtr(message));*/
  1579. X}
  1580. X
  1581. X/*
  1582. X    execute from a context rather than from the process stack
  1583. X*/
  1584. Xstatic executeFromContext(context, bytecounter)
  1585. Xobject context;
  1586. Xint bytecounter;
  1587. X{    object method, methodclass, arguments, temporaries;
  1588. X    boolean done = false;
  1589. X
  1590. X    method = basicAt(context, methodInContext);
  1591. X    methodclass = basicAt(context, methodClassInContext);
  1592. X    arguments = basicAt(context, argumentsInContext);
  1593. X    temporaries = basicAt(context, temporariesInContext);
  1594. X
  1595. X    while (! done) {
  1596. X        execute(method, bytecounter, processStack, processStackTop,
  1597. X            memoryPtr(arguments), memoryPtr(temporaries));
  1598. X        bytecounter = finalByteCounter;
  1599. X        processStackTop = finalStackTop;
  1600. X
  1601. X        switch(finalTask) {
  1602. X            case sendMessageTask:
  1603. X                sendMessage(messageToSend, 
  1604. X                    getClass(processStack[argumentsOnStack]),
  1605. X                    argumentsOnStack);
  1606. X                if (finalTask == BlockReturnTask)
  1607. X                    done = true;
  1608. X                break;
  1609. X
  1610. X            case sendSuperTask:
  1611. X                sendMessage(messageToSend,
  1612. X                    basicAt(methodclass, superClassInClass),
  1613. X                    argumentsOnStack);
  1614. X                if (finalTask == BlockReturnTask)
  1615. X                    done = true;
  1616. X                break;
  1617. X
  1618. X            case BlockCreateTask:
  1619. X                /* block is in returnedObject already */
  1620. X                /* just add our context to it */
  1621. X                basicAtPut(returnedObject, contextInBlock, context);
  1622. X                processStack[processStackTop++] = returnedObject;
  1623. X                break;
  1624. X
  1625. X            case BlockReturnTask:
  1626. X                blockReturnContext = context;
  1627. X                /* fall into next case and return */
  1628. X
  1629. X            case ReturnTask:
  1630. X                /* exit and let caller handle it */
  1631. X                done = true;
  1632. X                break;
  1633. X    
  1634. X            default:
  1635. X                sysError("unknown task","in context execute");
  1636. X        }
  1637. X    }
  1638. X}
  1639. X
  1640. Xflushstack()
  1641. X{
  1642. X    while (processStackTop > 0) {
  1643. X        decr(processStack[--processStackTop]);
  1644. X        processStack[processStackTop] = nilobj;
  1645. X        }
  1646. X}
  1647. X
  1648. Xstatic interpush(interp, value)
  1649. Xobject interp, value;
  1650. X{
  1651. X    int stacktop;
  1652. X    object stack;
  1653. X
  1654. X    stacktop = 1 + intValue(basicAt(interp, stackTopInInterpreter));
  1655. X    stack = basicAt(interp, stackInInterpreter);
  1656. X    basicAtPut(stack, stacktop, value);
  1657. X    basicAtPut(interp, stackTopInInterpreter, newInteger(stacktop));
  1658. X}
  1659. X
  1660. Xobject doInterp(interpreter)
  1661. Xobject interpreter;
  1662. X{    object context, method, arguments, temporaries, stack;
  1663. X    object prev, contextobj, obj, argobj, class, newinterp, tempobj;
  1664. X    int i, hash, argumentSize, bytecounter, stacktop;
  1665. X
  1666. X    context = basicAt(interpreter, contextInInterpreter);
  1667. X    method = basicAt(context, methodInContext);
  1668. X    arguments = basicAt(context, argumentsInContext);
  1669. X    temporaries = basicAt(context, temporariesInContext);
  1670. X    stack = basicAt(interpreter, stackInInterpreter);
  1671. X    stacktop = intValue(basicAt(interpreter, stackTopInInterpreter));
  1672. X    bytecounter = intValue(basicAt(interpreter, byteCodePointerInInterpreter));
  1673. X
  1674. X    execute(method, bytecounter, memoryPtr(stack), stacktop,
  1675. X        memoryPtr(arguments), memoryPtr(temporaries));
  1676. X    basicAtPut(interpreter, stackTopInInterpreter, newInteger(finalStackTop));
  1677. X    basicAtPut(interpreter, byteCodePointerInInterpreter, newInteger(finalByteCounter));
  1678. X
  1679. X    switch(finalTask) {
  1680. X        case sendMessageTask:
  1681. X        case sendSuperTask:
  1682. X            /* first gather up arguments */
  1683. X            argumentSize = finalStackTop - argumentsOnStack;
  1684. X            argobj = newArray(argumentSize);
  1685. X            for (i = argumentSize; i >= 1; i--) {
  1686. X                obj = basicAt(stack, finalStackTop);
  1687. X                basicAtPut(argobj, i, obj);
  1688. X                basicAtPut(stack, finalStackTop, nilobj);
  1689. X                finalStackTop--;
  1690. X                }
  1691. X
  1692. X            /* now go look up method */
  1693. X            if (finalTask == sendMessageTask)
  1694. X                class = getClass(basicAt(argobj, 1));
  1695. X            else 
  1696. X                class = basicAt(basicAt(context, 
  1697. X                    methodClassInContext), superClassInClass);
  1698. X            hash = (messageToSend + class) % ProcessCacheSize;
  1699. X            method = findMethod(hash, messageToSend, class);
  1700. X
  1701. X            if (method == nilobj) {
  1702. X                /* didn't find it, change message */
  1703. X                incr(argobj);    /* get rid of old args */
  1704. X                decr(argobj);
  1705. X                argobj = newArray(3);
  1706. X                basicAtPut(argobj, 1, smallobj);
  1707. X                basicAtPut(argobj, 2, class);
  1708. X                basicAtPut(argobj, 3, messageToSend);
  1709. X                class = getClass(smallobj);
  1710. X                messageToSend = newSymbol("class:doesNotRespond:");
  1711. X                hash = (messageToSend + class) % ProcessCacheSize;
  1712. X                method = findMethod(hash, messageToSend, class);
  1713. X                if (method == nilobj)    /* oh well */
  1714. X                    sysError("cant find method",charPtr(messageToSend));
  1715. X                }
  1716. X            newContext(method, methodCache[hash].methodClass, &contextobj, argobj, &tempobj);
  1717. X            basicAtPut(interpreter, stackTopInInterpreter, newInteger(finalStackTop));
  1718. X            argumentsOnStack = 0;
  1719. X            /* fall into context execute */
  1720. X
  1721. X        case ContextExecuteTask:
  1722. X            if (finalTask == ContextExecuteTask) {
  1723. X                contextobj = messageToSend;
  1724. X                }
  1725. X            newinterp = allocObject(InterpreterSize);
  1726. X            setClass(newinterp, intrclass);
  1727. X            basicAtPut(newinterp, contextInInterpreter, contextobj);
  1728. X            basicAtPut(newinterp, previousInterpreterInInterpreter, interpreter);
  1729. X            basicAtPut(newinterp, creatingInterpreterInInterpreter, creator);
  1730. X            /* this shouldn't be 15, but what should it be?*/
  1731. X            basicAtPut(newinterp, stackInInterpreter, newArray(15));
  1732. X            basicAtPut(newinterp, stackTopInInterpreter, newInteger(0));
  1733. X            basicAtPut(newinterp, byteCodePointerInInterpreter, newInteger(argumentsOnStack));
  1734. X            decr(contextobj);
  1735. X            return(newinterp);
  1736. X
  1737. X        case BlockCreateTask:
  1738. X            basicAtPut(returnedObject, contextInBlock, context);
  1739. X            prev = basicAt(interpreter, creatingInterpreterInInterpreter);
  1740. X            if (prev == nilobj)
  1741. X                prev = interpreter;
  1742. X            basicAtPut(returnedObject, creatingInterpreterInBlock, prev);
  1743. X            interpush(interpreter, returnedObject);
  1744. X            decr(returnedObject);
  1745. X            return(interpreter);
  1746. X
  1747. X        case BlockReturnTask:
  1748. X            interpreter = basicAt(interpreter, creatingInterpreterInInterpreter);
  1749. X            /* fall into return task */
  1750. X
  1751. X        case ReturnTask:
  1752. X            prev = basicAt(interpreter, previousInterpreterInInterpreter);
  1753. X            if (prev != nilobj) {
  1754. X                interpush(prev, returnedObject);
  1755. X                }
  1756. X            /* get rid of excess ref count */
  1757. X            decr(returnedObject);
  1758. X            return(prev);
  1759. X
  1760. X        default:
  1761. X            sysError("unknown final task","doInterp");
  1762. X        }
  1763. X    return(nilobj);
  1764. X}
  1765. /
  1766. echo 'Part 03 of small.v2 complete.'
  1767. exit
  1768.