jitcraft/Interpreter.cpp
author David Anderson <dvander@alliedmods.net>
Mon Jul 02 01:52:57 2012 -0700 (2012-07-02)
changeset 26 a48382113da6
parent 23 8a31742781c1
child 27 28697d267222
permissions -rw-r--r--
Added a Function object to sit in between Module and Code.
     1 /*
     2  * Copyright (C) 2012 David Anderson
     3  *
     4  * This file is part of JITCraft.
     5  *
     6  * JITCraft is free software: you can redistribute it and/or modify it under
     7  * the terms of the GNU General Public License as published by the Free
     8  * Software Foundation, either version 3 of the License, or (at your option)
     9  * any later version.
    10  * 
    11  * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    13  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License along with
    16  * JITCraft. If not, see http://www.gnu.org/licenses/.
    17  */
    18 #include "Interpreter.h"
    19 #include "Modules.h"
    20 #include "Zone.h"
    21 #include "Types.h"
    22 #include "Array.h"
    23 #include "Reference.h"
    24 
    25 using namespace jc;
    26 
    27 #define PUSH_I32(top, value)    \
    28     do {                        \
    29         top.sp->i32 = value;    \
    30         top.sp++;               \
    31    } while (0)
    32 
    33 #define PUSH_F(top, value)      \
    34     do {                        \
    35         top.sp->f = value;      \
    36         top.sp++;               \
    37    } while (0)
    38 
    39 static inline int
    40 POP_I32(Top &top)
    41 {
    42     int value = top.sp[-1].i32;
    43     top.sp--;
    44     return value;
    45 }
    46 
    47 static inline float
    48 POP_F(Top &top)
    49 {
    50     float value = top.sp[-1].f;
    51     top.sp--;
    52     return value;
    53 }
    54 
    55 static inline bool
    56 PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
    57 {
    58     Reference *ref = Reference::NewStack(zone, location, tenure);
    59     if (!ref)
    60         return false;
    61     top.sp->ref = ref;
    62     top.sp++;
    63     return true;
    64 }
    65 
    66 static inline bool
    67 CheckDimensionSize(int size, unsigned width)
    68 {
    69     if (size <= 0) {
    70         assert(false);
    71         return false;
    72     }
    73     // One  word, because we hide stuff below and need to add that in.
    74     if (unsigned(size) >= (INT_MAX / width) - sizeof(unsigned)) {
    75         assert(false);
    76         return false;
    77     }
    78     return true;
    79 }
    80 
    81 // Generate an array with completely static sizes.
    82 static Array *
    83 GenerateArray(Zone *zone, ArrayMap *map)
    84 {
    85     assert(map->type()->elements() != -1);
    86 
    87     // :TODO: use Local
    88     Array *array = Array::New(zone, map, map->type()->elements(), Heap::Tenure_Stack);
    89     if (!array)
    90         return NULL;
    91 
    92     if (map->type()->levels() == 1)
    93         return array;
    94 
    95     for (unsigned i = 0; i < unsigned(map->type()->elements()); i++) {
    96         Array *sub = GenerateArray(zone, map->contained());
    97         if (!sub)
    98             return NULL;
    99         array->writeObject(zone, i, sub);
   100     }
   101 
   102     return array;
   103 }
   104 
   105 static bool
   106 CopyArray(Zone *zone, Array *source, Array *dest)
   107 {
   108     assert(source->type()->levels() == 1);
   109     assert(dest->type()->levels() == 1);
   110     assert(source->type()->contained()->primitive() ==
   111            dest->type()->contained()->primitive());
   112     assert(source->nelements() >= dest->nelements());
   113     assert(dest->elementSize() == source->elementSize());
   114 
   115     memcpy(source->vec(), dest->vec(), dest->nelements() * dest->elementSize());
   116     return true;
   117 }
   118 
   119 bool
   120 jc::Interpret(Frame *frame, LocalSlot *result)
   121 {
   122     Top &top = *ZONE()->stack().top();
   123     LocalSlot *locals = frame->locals();
   124 
   125     for (;;) {
   126         Opcode op = Opcode(*top.pc);
   127         switch (op) {
   128 
   129 case OP_NOP:
   130     break;
   131 
   132 case OP_INT:
   133     PUSH_I32(top, READ_INT32(top.pc));
   134     break;
   135 
   136 case OP_FLOAT:
   137     PUSH_F(top, READ_FLOAT(top.pc));
   138     break;
   139 
   140 case OP_RETURN:
   141 {
   142     *result = *--top.sp;
   143     if (!frame->prev())
   144         return true;
   145 
   146     frame = ZONE()->stack().popFrame(frame);
   147     locals = frame->locals();
   148     *top.sp++ = *result;
   149     top.pc += OpcodeInfo[*top.pc].length;
   150     continue;
   151 }
   152 
   153 #define RELATIONAL_JUMP(op)                 \
   154     {                                       \
   155         int right = POP_I32(top);           \
   156         int left = POP_I32(top);            \
   157         if (left op right) {                \
   158             top.pc += READ_INT32(top.pc);   \
   159             continue;                       \
   160         }                                   \
   161     }
   162 
   163 case OP_JL:
   164     RELATIONAL_JUMP(<);
   165     break;
   166 
   167 case OP_JLE:
   168     RELATIONAL_JUMP(<=);
   169     break;
   170 
   171 case OP_JG:
   172     RELATIONAL_JUMP(>);
   173     break;
   174 
   175 case OP_JGE:
   176     RELATIONAL_JUMP(>=);
   177     break;
   178 
   179 case OP_JEQ:
   180     RELATIONAL_JUMP(==);
   181     break;
   182 
   183 case OP_JNE:
   184     RELATIONAL_JUMP(!=);
   185     break;
   186 
   187 case OP_JT:
   188 {
   189     int value = POP_I32(top);
   190     if (value) {
   191         top.pc += READ_INT32(top.pc);
   192         continue;
   193     }
   194     break;
   195 }
   196 
   197 case OP_JF:
   198 {
   199     int value = POP_I32(top);
   200     if (!value) {
   201         top.pc += READ_INT32(top.pc);
   202         continue;
   203     }
   204     break;
   205 }
   206 
   207 case OP_JUMP:
   208     top.pc += READ_INT32(top.pc);
   209     continue;
   210 
   211 case OP_GETLOCAL:
   212 {
   213     int slot = READ_INT32(top.pc);
   214     *top.sp++ = locals[slot];
   215     break;
   216 }
   217 
   218 case OP_SETLOCAL:
   219 {
   220     int slot = READ_INT32(top.pc);
   221     locals[slot] = top.sp[-1];
   222     break;
   223 }
   224 
   225 case OP_ADD:
   226 {
   227     int right = POP_I32(top);
   228     int left = POP_I32(top);
   229     int result = left + right;
   230     PUSH_I32(top, result);
   231     break;
   232 }
   233 
   234 case OP_SUB:
   235 {
   236     int right = POP_I32(top);
   237     int left = POP_I32(top);
   238     int result = left - right;
   239     PUSH_I32(top, result);
   240     break;
   241 }
   242 
   243 case OP_MUL:
   244 {
   245     int right = POP_I32(top);
   246     int left = POP_I32(top);
   247     int result = left * right;
   248     PUSH_I32(top, result);
   249     break;
   250 }
   251 
   252 case OP_DIV:
   253 {
   254     int right = POP_I32(top);
   255     int left = POP_I32(top);
   256     if (!right)
   257         return false;
   258     int result = left / right;
   259     PUSH_I32(top, result);
   260     break;
   261 }
   262 
   263 case OP_ADD_F:
   264 {
   265     float right = POP_F(top);
   266     float left = POP_F(top);
   267     float result = left + right;
   268     PUSH_F(top, result);
   269     break;
   270 }
   271 
   272 case OP_SUB_F:
   273 {
   274     float right = POP_F(top);
   275     float left = POP_F(top);
   276     float result = left - right;
   277     PUSH_F(top, result);
   278     break;
   279 }
   280 
   281 case OP_MUL_F:
   282 {
   283     float right = POP_F(top);
   284     float left = POP_F(top);
   285     float result = left * right;
   286     PUSH_F(top, result);
   287     break;
   288 }
   289 
   290 case OP_DIV_F:
   291 {
   292     float right = POP_F(top);
   293     float left = POP_F(top);
   294     if (!right)
   295         return false;
   296     float result = left / right;
   297     PUSH_F(top, result);
   298     break;
   299 }
   300 
   301 case OP_SHL:
   302 {
   303     int right = POP_I32(top);
   304     int left = POP_I32(top);
   305     int result = left << right;
   306     PUSH_I32(top, result);
   307     break;
   308 }
   309 
   310 case OP_SHR:
   311 {
   312     int right = POP_I32(top);
   313     int left = POP_I32(top);
   314     int result = left >> right;
   315     PUSH_I32(top, result);
   316     break;
   317 }
   318 
   319 case OP_USHR:
   320 {
   321     int right = POP_I32(top);
   322     int left = POP_I32(top);
   323     int result = unsigned(left) >> unsigned(right);
   324     PUSH_I32(top, result);
   325     break;
   326 }
   327 
   328 case OP_BITAND:
   329 {
   330     int right = POP_I32(top);
   331     int left = POP_I32(top);
   332     int result = left & right;
   333     PUSH_I32(top, result);
   334     break;
   335 }
   336 
   337 case OP_BITOR:
   338 {
   339     int right = POP_I32(top);
   340     int left = POP_I32(top);
   341     int result = left | right;
   342     PUSH_I32(top, result);
   343     break;
   344 }
   345 
   346 case OP_BITXOR:
   347 {
   348     int right = POP_I32(top);
   349     int left = POP_I32(top);
   350     int result = left ^ right;
   351     PUSH_I32(top, result);
   352     break;
   353 }
   354 
   355 case OP_POP:
   356     top.sp--;
   357     break;
   358 
   359 case OP_STOP:
   360     assert(false);
   361     break;
   362 
   363 case OP_CALLGLOBAL:
   364 {
   365     unsigned argc = READ_UINT32(top.pc);
   366     unsigned index = READ_UINT32(top.pc + 4);
   367     Function *newFun = frame->code()->module()->getFunction(index);
   368     frame = ZONE()->stack().pushFrame(frame, newFun);
   369     assert(frame);
   370     assert(newFun->nargs() == argc);
   371 
   372     locals = frame->locals();
   373     continue;
   374 }
   375 
   376 case OP_GETARG:
   377 {
   378     unsigned slot = READ_UINT32(top.pc);
   379     *top.sp++ = frame->arg(slot);
   380     break;
   381 }
   382 
   383 case OP_SETARG:
   384 {
   385     unsigned slot = READ_UINT32(top.pc);
   386     frame->arg(slot) = *--top.sp;
   387     break;
   388 }
   389 
   390 case OP_BOUNDS:
   391 {
   392     Array *array = top.sp[-2].array;
   393     int index = top.sp[-1].i32;
   394     if (index < 0 || unsigned(index) >= array->nelements())
   395         return false;
   396     break;
   397 }
   398 
   399 case OP_GETARRAY_I:
   400 {
   401     Array *array = top.sp[-2].array;
   402     int index = top.sp[-1].i32;
   403     top.sp[-2].i32 = array->readInt32(index);
   404     top.sp--;
   405     break;
   406 }
   407 
   408 case OP_GETARRAY_F:
   409 {
   410     Array *array = top.sp[-2].array;
   411     int index = top.sp[-1].i32;
   412     top.sp[-2].f = array->readFloat(index);
   413     top.sp--;
   414     break;
   415 }
   416 
   417 case OP_GETARRAY_C:
   418 {
   419     Array *array = top.sp[-2].array;
   420     int index = top.sp[-1].i32;
   421     top.sp[-2].i32 = array->readChar(index);
   422     top.sp--;
   423     break;
   424 }
   425 
   426 case OP_SETARRAY_I:
   427 {
   428     Array *array = top.sp[-3].array;
   429     int index = top.sp[-2].i32;
   430     array->writeInt32(index, top.sp[-1].i32);
   431     top.sp[-3] = top.sp[-1];
   432     top.sp -= 2;
   433     break;
   434 }
   435 
   436 case OP_SETARRAY_F:
   437 {
   438     Array *array = top.sp[-3].array;
   439     int index = top.sp[-2].i32;
   440     array->writeFloat(index, top.sp[-1].f);
   441     top.sp[-3] = top.sp[-1];
   442     top.sp -= 2;
   443     break;
   444 }
   445 
   446 case OP_SETARRAY_C:
   447 {
   448     Array *array = top.sp[-3].array;
   449     int index = top.sp[-2].i32;
   450     array->writeChar(index, top.sp[-1].i32);
   451     top.sp[-3] = top.sp[-1];
   452     top.sp -= 2;
   453     break;
   454 }
   455 
   456 case OP_GETARRAY_O:
   457 {
   458     Array *array = top.sp[-2].array;
   459     int index = top.sp[-1].i32;
   460     top.sp[-2].array = Array::cast(array->readObject(index));
   461     top.sp--;
   462     break;
   463 }
   464 
   465 case OP_CVT_I2F:
   466 {
   467     int ival = POP_I32(top);
   468     float fval = (float)ival;
   469     PUSH_F(top, fval);
   470     break;
   471 }
   472 
   473 case OP_NEWARRAY_LIFO:
   474 {
   475     // :TODO: use Local
   476     ArrayMap *map = ArrayMap::cast(frame->code()->map(READ_UINT32(top.pc)));
   477     Array *array = GenerateArray(ZONE(), map);
   478     if (!array) {
   479         assert(false);
   480         return false;
   481     }
   482     top.sp->obj = array;
   483     top.sp++;
   484     break;
   485 }
   486 
   487 case OP_SAVELIFO:
   488 {
   489     unsigned slot = READ_UINT32(top.pc);
   490     locals[slot].address = ZONE()->heap().lifoPosition();
   491     break;
   492 }
   493 
   494 case OP_UNWINDLIFO:
   495 {
   496     unsigned slot = READ_UINT32(top.pc);
   497     ZONE()->heap().unwindLifo(locals[slot].address);
   498     break;
   499 }
   500 
   501 case OP_VARREF_LIFO:
   502 {
   503     unsigned slot = READ_UINT32(top.pc);
   504     if (!PushNewRef(ZONE(), top, &locals[slot], Heap::Tenure_Stack)) {
   505         assert(false);
   506         return false;
   507     }
   508     break;
   509 }
   510 
   511 case OP_ARGREF_LIFO:
   512 {
   513     unsigned slot = READ_UINT32(top.pc);
   514     if (!PushNewRef(ZONE(), top, &frame->arg(slot), Heap::Tenure_Stack)) {
   515         assert(false);
   516         return false;
   517     }
   518     break;
   519 }
   520 
   521 case OP_ARRAYREF_LIFO:
   522 {
   523     Reference *ref = Reference::NewArray(ZONE(), top.sp[-2].array, top.sp[-1].i32, Heap::Tenure_Stack);
   524     if (!ref) {
   525         assert(false);
   526         return false;
   527     }
   528     top.sp[-2].ref = ref;
   529     top.sp--;
   530     break;
   531 }
   532 
   533 case OP_SLOTREF_LIFO:
   534 {
   535     Reference *ref = Reference::NewStack(ZONE(), top.sp[-1], Heap::Tenure_Stack);
   536     if (!ref) {
   537         assert(false);
   538         return false;
   539     }
   540     top.sp[-1].ref = ref;
   541     break;
   542 }
   543 
   544 case OP_GETREF_I:
   545 {
   546     top.sp[-1].i32 = top.sp[-1].ref->getInt();
   547     break;
   548 }
   549 
   550 case OP_SETREF_I:
   551 {
   552     top.sp[-2].ref->setInt(top.sp[-1].i32);
   553     top.sp[-2].i32 = top.sp[-1].i32;
   554     top.sp--;
   555     break;
   556 }
   557 
   558 case OP_GETREF_F:
   559 {
   560     top.sp[-1].f = top.sp[-1].ref->getFloat();
   561     break;
   562 }
   563 
   564 case OP_SETREF_F:
   565 {
   566     top.sp[-2].ref->setFloat(top.sp[-1].f);
   567     top.sp[-2].f = top.sp[-1].f;
   568     break;
   569 }
   570 
   571 case OP_OBJECT:
   572 {
   573     top.sp->obj = frame->code()->object(READ_UINT32(top.pc));
   574     top.sp++;
   575     break;
   576 }
   577 
   578 case OP_ARRAYCOPY:
   579 {
   580     // Note for this assignment opcode, we return the left-hand side, not the
   581     // right, since in this case the result of the expression could be different.
   582     if (!CopyArray(ZONE(), top.sp[-2].array, top.sp[-1].array)) {
   583         assert(false);
   584         return false;
   585     }
   586     top.sp--;
   587     break;
   588 }
   589 
   590 case OP_DUP:
   591 {
   592     top.sp++;
   593     top.sp[-1] = top.sp[-2];
   594     break;
   595 }
   596 
   597 case OP_DUP2:
   598 {
   599     top.sp += 2;
   600     top.sp[-2] = top.sp[-4];
   601     top.sp[-1] = top.sp[-3];
   602     break;
   603 }
   604 
   605 case OP_SWAP:
   606 {
   607     LocalSlot slot = top.sp[-2];
   608     top.sp[-2] = top.sp[-1];
   609     top.sp[-1] = slot;
   610     break;
   611 }
   612 
   613 case OP_ROLL3:
   614 {
   615     LocalSlot slot = top.sp[-3];
   616     top.sp[-3] = top.sp[-2];
   617     top.sp[-2] = top.sp[-1];
   618     top.sp[-1] = slot;
   619     break;
   620 }
   621 
   622 case OP_PICK2:
   623 {
   624     top.sp++;
   625     top.sp[-1] = top.sp[-3];
   626     break;
   627 }
   628 
   629 case OP_PICK3:
   630 {
   631     top.sp++;
   632     top.sp[-1] = top.sp[-4];
   633     break;
   634 }
   635 
   636 default:
   637     assert(false);
   638     return false;
   639 
   640         }
   641 
   642         top.pc += OpcodeInfo[op].length;
   643     }
   644 
   645     return true;
   646 }