home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 116.lha / SmallTalk / Sources / INTERP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-20  |  8.3 KB  |  377 lines

  1. /*
  2.     Little Smalltalk version 2
  3.     Written by Tim Budd, Oregon State University, July 1987
  4.  
  5.     bytecode interpreter module
  6.  
  7.     execute bytecodes for a given method until one of six events occur
  8.     1. A message must be sent to another object
  9.     2. A message must be sent to super
  10.     3. A return from a method occurs
  11.     4. An explicit return from a block occurs (backs up the process chain)
  12.     5. A block must be created
  13.     6. A block must begin execution
  14.  
  15.     the global variable finalTask indicates which of the six events is to
  16.     be performed.  Various other global variables (described in process.h)
  17.     give other information to be used in performing the called for task.
  18.  
  19.     Note that the interpreter is called as part of the
  20.     main instruction sequence (single process) and (via a primitive call)
  21.     as part of the multi-process scheduler loop (class Scheduler, Process,
  22.     et al)
  23. */
  24.  
  25. # include <stdio.h>
  26. # include "env.h"
  27. # include "memory.h"
  28. # include "names.h"
  29. # include "process.h"
  30. # include "interp.h"
  31.  
  32. extern object unSyms[], binSyms[], keySyms[];
  33. extern boolean primitive(INT X OBJP X INT);
  34.  
  35. # define nextByte() byteToInt(bytecodes[byteCounter++])
  36. # define ipush(x) incr(stack[stacktop++] = x)
  37. /* note that ipop leaves a ref count on the popped object */
  38. # define ipop(x)  x=stack[--stacktop]; stack[stacktop]=nilobj
  39.  
  40. noreturn execute(method, byteCounter, stack, stacktop, arguments, temporaries)
  41. object method, *stack, *arguments, *temporaries;
  42. register int byteCounter;
  43. register int stacktop;
  44. {
  45.     int i, j, low, high;
  46.     object receiver, *instance, *literals;
  47.     object newobj;
  48.     byte  *bytecodes;
  49.     boolean done;
  50.     double f;
  51.  
  52.     /* do initialization */
  53.     receiver = arguments[0];
  54.     if (isInteger(receiver))
  55.         instance = (object *) 0;
  56.     else
  57.         instance = memoryPtr(receiver);
  58.     bytecodes = bytePtr(basicAt(method, bytecodesInMethod));
  59.     literals = memoryPtr(basicAt(method, literalsInMethod));
  60.     done = false;
  61.  
  62.  
  63.     while( ! done ) {
  64.         low = (high = nextByte()) & 0x0F;
  65.         high >>= 4;
  66.         if (high == 0) {
  67.             high = low;
  68.             low = nextByte();
  69.             }
  70. /*if (debugging) ignore fprintf(stderr,"executing %s %d %d %d\n", 
  71. charPtr(basicAt(method, messageInMethod)), byteCounter, high, low);*/
  72.  
  73.         switch(high) {
  74.             case PushInstance:
  75.                 ipush(instance[low]);
  76.                 break;
  77.  
  78.             case PushArgument:
  79.                 ipush(arguments[low]);
  80.                 break;
  81.  
  82.             case PushTemporary:
  83.                 ipush(temporaries[low]);
  84.                 break;
  85.  
  86.             case PushLiteral:
  87.                 ipush(literals[low]);
  88.                 break;
  89.  
  90.             case PushConstant:
  91.                 if (low == 3)
  92.                     low = -1;
  93.                 if (low < 3) {
  94.                     ipush(newInteger(low));
  95.                     }
  96.                 else
  97.                     switch(low) {
  98.                         case 4: 
  99.                             ipush(nilobj);
  100.                             break;
  101.  
  102.                         case 5:
  103.                             ipush(trueobj);
  104.                             break;
  105.  
  106.                         case 6:
  107.                             ipush(falseobj);
  108.                             break;
  109.  
  110.                         case 7:
  111.                             ipush(smallobj);
  112.                             break;
  113.  
  114.                         case 8:
  115.                             ipush(globalNames);
  116.                             break;
  117.  
  118.                         default:
  119.                     sysError("not done yet","pushConstant");
  120.                         }
  121.                 break;
  122.  
  123.             case PushGlobal:
  124.                 newobj = nameTableLookup(globalNames, 
  125.                     literals[low]);
  126.                 if (newobj == nilobj) {
  127.                     /* send message instead */
  128.                     ipush(smallobj);
  129.                     ipush(literals[low]);
  130.                     argumentsOnStack = stacktop - 2;
  131.                     messageToSend = 
  132.                         newSymbol("cantFindGlobal:");
  133.                     finalTask = sendMessageTask;
  134.                     done = true;
  135.                     }
  136.                 else
  137.                     ipush(newobj);
  138.                 break;
  139.     
  140.             case PopInstance:
  141.                 decr(instance[low]);
  142.                 /* we transfer reference count to instance */
  143.                 ipop(instance[low]);
  144.                 break;
  145.  
  146.             case PopTemporary:
  147.                 decr(temporaries[low]);
  148.                 /* we transfer reference count to temporaries */
  149.                 ipop(temporaries[low]);
  150.                 break;
  151.  
  152.             case SendMessage:
  153.                 argumentsOnStack = stacktop - (low + 1);
  154.                 messageToSend = literals[nextByte()];
  155.                 finalTask = sendMessageTask;
  156.                 done = true;
  157.                 break;
  158.  
  159.             case SendUnary:
  160.                 /* we optimize a couple common messages */
  161.                 if (low == 0) {        /* isNil */
  162.                     ipop(newobj);
  163.                     if (newobj == nilobj) {
  164.                         ipush(trueobj);
  165.                         }
  166.                     else {
  167.                         decr(newobj);
  168.                         ipush(falseobj);
  169.                         }
  170.                     }
  171.                 else if (low == 1) {    /* notNil */
  172.                     ipop(newobj);
  173.                     if (newobj == nilobj) {
  174.                         ipush(falseobj);
  175.                         }
  176.                     else {
  177.                         decr(newobj);
  178.                         ipush(trueobj);
  179.                         }
  180.                     }
  181.                 else {
  182.                     argumentsOnStack = stacktop - 1;
  183.                     messageToSend = unSyms[low];
  184.                     finalTask = sendMessageTask;
  185.                     done = true;
  186.                     }
  187.                 break;
  188.  
  189.             case SendBinary:
  190.                 /* optimize arithmetic as long as no */
  191.                 /* conversions are necessary */
  192.                 /* and overflow does not occur */
  193.                 if (low <= 12) {
  194.                     if (isInteger(stack[stacktop-1]) &&
  195.                             isInteger(stack[stacktop-2])) {
  196.                         ipop(newobj);
  197.                         i = intValue(newobj);
  198.                         ipop(newobj);
  199.                         j = intValue(newobj);
  200.                         ignore intBinary(low, j, i);
  201.                         if (returnedObject != nilobj) {
  202.                             ipush(returnedObject);
  203.                             break;
  204.                             }
  205.                         /* overflowed, go do it */
  206.                         /* the old fashioned way */
  207.                         ipush(newInteger(j));
  208.                         ipush(newInteger(i));
  209.                         }
  210.                     else if (isFloat(stack[stacktop-1]) &&
  211.                         isFloat(stack[stacktop-2])) {
  212.                         ipop(newobj);
  213.                         f = floatValue(newobj);
  214.                         decr(newobj);
  215.                         ipop(newobj);
  216.                         ignore floatBinary(low, floatValue(newobj), f);
  217.                         decr(newobj);
  218.                         ipush(returnedObject);
  219.                         break;
  220.                         }
  221.                     }
  222.                 argumentsOnStack = stacktop - 2;
  223.                 messageToSend = binSyms[low];
  224.                 finalTask = sendMessageTask;
  225.                 done = true;
  226.                 break;
  227.  
  228.             case SendKeyword:
  229.                 argumentsOnStack = stacktop - 3;
  230.                 messageToSend = keySyms[low];
  231.                 finalTask = sendMessageTask;
  232.                 done = true;
  233.                 break;
  234.  
  235.             case DoPrimitive:
  236.                 i = nextByte();
  237.                 done = primitive(i, &stack[stacktop - low], low);
  238.                 incr(returnedObject);
  239.                 /* pop off arguments */
  240.                 for (i = low; i > 0; i--) {
  241.                     ipop(newobj);
  242.                     decr(newobj);
  243.                     }
  244.                 if (! done) {
  245.                     ipush(returnedObject);
  246.                     decr(returnedObject);
  247.                     }
  248.                 break;
  249.  
  250.             case CreateBlock:
  251.                 /* we do most of the work in making the block */
  252.                 /* leaving it to the caller to fill in */
  253.                 /* the context information */
  254.                 newobj = allocObject(blockSize);
  255.                 setClass(newobj, blockclass);
  256.                 basicAtPut(newobj, argumentCountInBlock, newInteger(low));
  257.                 i = (low > 0) ? nextByte() : 0;
  258.                 basicAtPut(newobj, argumentLocationInBlock, 
  259.                     newInteger(i));
  260.                 basicAtPut(newobj, bytecountPositionInBlock,
  261.                     newInteger(byteCounter + 1));
  262.                 incr(returnedObject = newobj);
  263.                 /* avoid a subtle side effect here */
  264.                 i = nextByte();
  265.                 byteCounter = i;
  266.                 finalTask = BlockCreateTask;
  267.                 done = true;
  268.                 break;
  269.  
  270.             case DoSpecial:
  271.                 switch(low) {
  272.                     case SelfReturn:
  273.                         incr(returnedObject = receiver);
  274.                         finalTask = ReturnTask;
  275.                         done = true;
  276.                         break;
  277.  
  278.                     case StackReturn:
  279.                         ipop(returnedObject);
  280.                         finalTask = ReturnTask;
  281.                         done = true;
  282.                         break;
  283.  
  284.                     case BlockReturn:
  285.                         ipop(returnedObject);
  286.                         finalTask = BlockReturnTask;
  287.                         done = true;
  288.                         break;
  289.  
  290.                     case Duplicate:
  291.                         ipop(newobj);
  292.                         ipush(newobj);
  293.                         ipush(newobj);
  294.                         decr(newobj);
  295.                         break;
  296.  
  297.                     case PopTop:
  298.                         ipop(newobj);
  299.                         decr(newobj);
  300.                         break;
  301.  
  302.                     case Branch:
  303.                         /* avoid a subtle bug here */
  304.                         i = nextByte();
  305.                         byteCounter = i;
  306.                         break;
  307.  
  308.                     case BranchIfTrue:
  309.                         ipop(newobj);
  310.                         i = nextByte();
  311.                         if (newobj == trueobj) {
  312.                             /* leave nil on stack */
  313.                             ++stacktop;
  314.                             byteCounter = i;
  315.                             }
  316.                         decr(newobj);
  317.                         break;
  318.  
  319.                     case BranchIfFalse:
  320.                         ipop(newobj);
  321.                         i = nextByte();
  322.                         if (newobj == falseobj) {
  323.                             /* leave nil on stack */
  324.                             ++stacktop;
  325.                             byteCounter = i;
  326.                             }
  327.                         decr(newobj);
  328.                         break;
  329.  
  330.                     case AndBranch:
  331.                         ipop(newobj);
  332.                         i = nextByte();
  333.                         if (newobj == falseobj) {
  334.                             ipush(newobj);
  335.                             byteCounter = i;
  336.                             }
  337.                         decr(newobj);
  338.                         break;
  339.  
  340.                     case OrBranch:
  341.                         ipop(newobj);
  342.                         i = nextByte();
  343.                         if (newobj == trueobj) {
  344.                             ipush(newobj);
  345.                             byteCounter = i;
  346.                             }
  347.                         decr(newobj);
  348.                         break;
  349.  
  350.                     case SendToSuper:
  351.                         argumentsOnStack = stacktop -
  352.                             (nextByte() + 1);
  353.                         messageToSend = 
  354.                             literals[nextByte()];
  355.                         finalTask = sendSuperTask;
  356.                         done = true;
  357.                         break;
  358.  
  359.                     default:
  360.                         sysError("invalid doSpecial","");
  361.                         break;
  362.                 }
  363.                 break;
  364.  
  365.             default:
  366.                 sysError("invalid bytecode","");
  367.                 break;
  368.         }
  369.     }
  370.  
  371.     /* when done, save stack top and bytecode counter */
  372.     /* before we exit */
  373.  
  374.     finalStackTop = stacktop;
  375.     finalByteCounter = byteCounter;
  376. }
  377.