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