jitcraft/Interpreter.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jul 15 14:40:11 2012 -0700 (2012-07-15)
changeset 73 ef5492aa8d8b
parent 72 40746ab0a30b
child 74 80e29e23eb4e
permissions -rw-r--r--
Small refactoring to make callees pushed explicitly.
     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 "Strings.h"
    26 #include "Heap-inl.h"
    27 
    28 using namespace ke;
    29 
    30 #define PUSH_I32(top, value)    \
    31     do {                        \
    32         top.sp->i32 = value;    \
    33         top.sp++;               \
    34    } while (0)
    35 
    36 #define PUSH_F(top, value)      \
    37     do {                        \
    38         top.sp->f = value;      \
    39         top.sp++;               \
    40    } while (0)
    41 
    42 static inline int
    43 POP_I32(Top &top)
    44 {
    45     int value = top.sp[-1].i32;
    46     top.sp--;
    47     return value;
    48 }
    49 
    50 static inline float
    51 POP_F(Top &top)
    52 {
    53     float value = top.sp[-1].f;
    54     top.sp--;
    55     return value;
    56 }
    57 
    58 static inline bool
    59 PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
    60 {
    61     Reference *ref = Reference::NewStack(zone, location, tenure);
    62     if (!ref)
    63         return false;
    64     top.sp->ref = ref;
    65     top.sp++;
    66     return true;
    67 }
    68 
    69 // Generate an array with completely static sizes.
    70 static Array *
    71 GenerateArray(Zone *zone, Handle<ArrayMap> map)
    72 {
    73     assert(map->type()->elements() != -1);
    74 
    75     Local<Array> array(zone, Array::New(zone, map, map->type()->elements(), Heap::Tenure_Stack));
    76     if (!array)
    77         return NULL;
    78 
    79     if (map->type()->levels() == 1)
    80         return array;
    81 
    82     Local<ArrayMap> contained(zone, map->contained());
    83     Local<Array> sub(zone);
    84     for (unsigned i = 0; i < unsigned(map->type()->elements()); i++) {
    85         sub = GenerateArray(zone, contained);
    86         if (!sub)
    87             return NULL;
    88         array->writeObject(zone, i, sub);
    89     }
    90 
    91     return array;
    92 }
    93 
    94 static bool
    95 CopyArray(Zone *zone, Array *source, Array *dest)
    96 {
    97     assert(source->type()->levels() == 1);
    98     assert(dest->type()->levels() == 1);
    99     assert(source->type()->contained()->primitive() ==
   100            dest->type()->contained()->primitive());
   101     assert(source->nelements() >= dest->nelements());
   102     assert(dest->elementSize() == source->elementSize());
   103 
   104     memcpy(source->vec(), dest->vec(), dest->nelements() * dest->elementSize());
   105     return true;
   106 }
   107 
   108 static bool
   109 InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
   110              int *result)
   111 {
   112     NativeArgs guard;
   113 
   114     if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
   115         return false;
   116 
   117     intptr_t *cells = guard.args();
   118 
   119     // params[0] == argc, in ISPE
   120     cells[0] = argc;
   121 
   122     // Pass the formal arguments.
   123     Local<Type> type(zone, native->type());
   124     Local<Type> param(zone);
   125     for (unsigned i = 0; i < type->parameters()->length(); i++) {
   126         param = type->parameterAt(i);
   127         
   128         // For floats, we rely on the aliasing of |i32| and |f|.
   129         LocalSlot &arg = args[-int(i) - 1];
   130         if (param->isInt32() || param->isFloat()) {
   131             cells[i + 1] = arg.i32;
   132         } else if (param->isReference()) {
   133             cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
   134         } else {
   135             assert(param->isArray());
   136             cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
   137         }
   138     }
   139 
   140     // For variadic arguments, the compiler left either arrays or references.
   141     for (unsigned i = type->parameters()->length(); i < argc; i++) {
   142         LocalSlot &arg = args[-int(i) - 1];
   143 
   144         if (arg.obj->is(MapKind_Reference)) {
   145             cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
   146         } else {
   147             assert(arg.obj->is(MapKind_Array));
   148             cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
   149         }
   150     }
   151 
   152     typedef intptr_t (*INVOKE)(void *, intptr_t *);
   153     INVOKE invoke = (INVOKE)native->function();
   154     *result = invoke(identity, cells);
   155 
   156     return !zone->hasPendingException();
   157 }
   158 
   159 bool
   160 ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
   161 {
   162     Top &top = *zone->stack().top();
   163     if (!entryFrame)
   164         entryFrame = top.fp;
   165 
   166     LocalSlot *locals = entryFrame->locals();
   167 
   168     for (;;) {
   169         Opcode op = Opcode(*top.pc);
   170         switch (op) {
   171 
   172 case OP_NOP:
   173     break;
   174 
   175 case OP_INT:
   176     PUSH_I32(top, READ_INT32(top.pc));
   177     break;
   178 
   179 case OP_FLOAT:
   180     PUSH_F(top, READ_FLOAT(top.pc));
   181     break;
   182 
   183 case OP_RETURN:
   184 case OP_RETURNVOID:
   185 case OP_STOP:
   186 {
   187     if (op == OP_RETURN)
   188         *result = *--top.sp;
   189 
   190     if (top.fp == entryFrame)
   191         goto done;
   192 
   193     // This must not GC.
   194     zone->stack().popInlineFrame();
   195     locals = top.fp->locals();
   196 
   197     if (op == OP_RETURN)
   198         *top.sp++ = *result;
   199 
   200     top.pc += OpcodeInfo[*top.pc].length;
   201     continue;
   202 }
   203 
   204 #define RELATIONAL_JUMP(op)                 \
   205     {                                       \
   206         int right = POP_I32(top);           \
   207         int left = POP_I32(top);            \
   208         if (left op right) {                \
   209             top.pc += READ_INT32(top.pc);   \
   210             continue;                       \
   211         }                                   \
   212     }
   213 
   214 case OP_JL:
   215     RELATIONAL_JUMP(<);
   216     break;
   217 
   218 case OP_JLE:
   219     RELATIONAL_JUMP(<=);
   220     break;
   221 
   222 case OP_JG:
   223     RELATIONAL_JUMP(>);
   224     break;
   225 
   226 case OP_JGE:
   227     RELATIONAL_JUMP(>=);
   228     break;
   229 
   230 case OP_JEQ:
   231     RELATIONAL_JUMP(==);
   232     break;
   233 
   234 case OP_JNE:
   235     RELATIONAL_JUMP(!=);
   236     break;
   237 
   238 case OP_JT:
   239 {
   240     int value = POP_I32(top);
   241     if (value) {
   242         top.pc += READ_INT32(top.pc);
   243         continue;
   244     }
   245     break;
   246 }
   247 
   248 case OP_JF:
   249 {
   250     int value = POP_I32(top);
   251     if (!value) {
   252         top.pc += READ_INT32(top.pc);
   253         continue;
   254     }
   255     break;
   256 }
   257 
   258 case OP_JUMP:
   259     top.pc += READ_INT32(top.pc);
   260     continue;
   261 
   262 case OP_GETLOCAL:
   263 {
   264     int slot = READ_INT32(top.pc);
   265     *top.sp++ = locals[slot];
   266     break;
   267 }
   268 
   269 case OP_SETLOCAL:
   270 {
   271     int slot = READ_INT32(top.pc);
   272     locals[slot] = top.sp[-1];
   273     break;
   274 }
   275 
   276 case OP_ADD:
   277 {
   278     int right = POP_I32(top);
   279     int left = POP_I32(top);
   280     int result = left + right;
   281     PUSH_I32(top, result);
   282     break;
   283 }
   284 
   285 case OP_SUB:
   286 {
   287     int right = POP_I32(top);
   288     int left = POP_I32(top);
   289     int result = left - right;
   290     PUSH_I32(top, result);
   291     break;
   292 }
   293 
   294 case OP_MUL:
   295 {
   296     int right = POP_I32(top);
   297     int left = POP_I32(top);
   298     int result = left * right;
   299     PUSH_I32(top, result);
   300     break;
   301 }
   302 
   303 case OP_DIV:
   304 {
   305     int right = POP_I32(top);
   306     int left = POP_I32(top);
   307     if (!right) {
   308         zone->reportError(Message_IntegerDivideByZero);
   309         goto error;
   310     }
   311     int result = left / right;
   312     PUSH_I32(top, result);
   313     break;
   314 }
   315 
   316 case OP_ADD_F:
   317 {
   318     float right = POP_F(top);
   319     float left = POP_F(top);
   320     float result = left + right;
   321     PUSH_F(top, result);
   322     break;
   323 }
   324 
   325 case OP_SUB_F:
   326 {
   327     float right = POP_F(top);
   328     float left = POP_F(top);
   329     float result = left - right;
   330     PUSH_F(top, result);
   331     break;
   332 }
   333 
   334 case OP_MUL_F:
   335 {
   336     float right = POP_F(top);
   337     float left = POP_F(top);
   338     float result = left * right;
   339     PUSH_F(top, result);
   340     break;
   341 }
   342 
   343 case OP_DIV_F:
   344 {
   345     float right = POP_F(top);
   346     float left = POP_F(top);
   347     float result = left / right;
   348     PUSH_F(top, result);
   349     break;
   350 }
   351 
   352 case OP_SHL:
   353 {
   354     int right = POP_I32(top);
   355     int left = POP_I32(top);
   356     int result = left << right;
   357     PUSH_I32(top, result);
   358     break;
   359 }
   360 
   361 case OP_SHR:
   362 {
   363     int right = POP_I32(top);
   364     int left = POP_I32(top);
   365     int result = left >> right;
   366     PUSH_I32(top, result);
   367     break;
   368 }
   369 
   370 case OP_USHR:
   371 {
   372     int right = POP_I32(top);
   373     int left = POP_I32(top);
   374     int result = unsigned(left) >> unsigned(right);
   375     PUSH_I32(top, result);
   376     break;
   377 }
   378 
   379 case OP_BITAND:
   380 {
   381     int right = POP_I32(top);
   382     int left = POP_I32(top);
   383     int result = left & right;
   384     PUSH_I32(top, result);
   385     break;
   386 }
   387 
   388 case OP_BITOR:
   389 {
   390     int right = POP_I32(top);
   391     int left = POP_I32(top);
   392     int result = left | right;
   393     PUSH_I32(top, result);
   394     break;
   395 }
   396 
   397 case OP_BITXOR:
   398 {
   399     int right = POP_I32(top);
   400     int left = POP_I32(top);
   401     int result = left ^ right;
   402     PUSH_I32(top, result);
   403     break;
   404 }
   405 
   406 case OP_POP:
   407     top.sp--;
   408     break;
   409 
   410 case OP_CALL:
   411 {
   412     zone->heap().reclaim();
   413 
   414     Local<Function> newFun(zone, top.sp[-1].fun);
   415     top.sp--;
   416 
   417     if (!zone->stack().pushInlineFrame(newFun))
   418         goto error;
   419 
   420     locals = top.fp->locals();
   421     continue;
   422 }
   423 
   424 case OP_GETARG:
   425 {
   426     unsigned slot = READ_UINT32(top.pc);
   427     *top.sp++ = top.fp->arg(slot);
   428     break;
   429 }
   430 
   431 case OP_SETARG:
   432 {
   433     unsigned slot = READ_UINT32(top.pc);
   434     top.fp->arg(slot) = *--top.sp;
   435     break;
   436 }
   437 
   438 case OP_BOUNDS:
   439 {
   440     Array *array = top.sp[-2].array;
   441     int index = top.sp[-1].i32;
   442     if (index < 0 || unsigned(index) >= array->nelements()) {
   443         zone->reportError(Message_ArrayIndexOutOfBounds, index, array->nelements());
   444         goto error;
   445     }
   446     break;
   447 }
   448 
   449 case OP_GETARRAY_I:
   450 {
   451     Array *array = top.sp[-2].array;
   452     int index = top.sp[-1].i32;
   453     top.sp[-2].i32 = array->readInt32(index);
   454     top.sp--;
   455     break;
   456 }
   457 
   458 case OP_GETARRAY_F:
   459 {
   460     Array *array = top.sp[-2].array;
   461     int index = top.sp[-1].i32;
   462     top.sp[-2].f = array->readFloat(index);
   463     top.sp--;
   464     break;
   465 }
   466 
   467 case OP_GETARRAY_C:
   468 {
   469     Array *array = top.sp[-2].array;
   470     int index = top.sp[-1].i32;
   471     top.sp[-2].i32 = array->readChar(index);
   472     top.sp--;
   473     break;
   474 }
   475 
   476 case OP_SETARRAY_I:
   477 {
   478     Array *array = top.sp[-3].array;
   479     int index = top.sp[-2].i32;
   480     array->writeInt32(index, top.sp[-1].i32);
   481     top.sp[-3] = top.sp[-1];
   482     top.sp -= 2;
   483     break;
   484 }
   485 
   486 case OP_SETARRAY_F:
   487 {
   488     Array *array = top.sp[-3].array;
   489     int index = top.sp[-2].i32;
   490     array->writeFloat(index, top.sp[-1].f);
   491     top.sp[-3] = top.sp[-1];
   492     top.sp -= 2;
   493     break;
   494 }
   495 
   496 case OP_SETARRAY_C:
   497 {
   498     Array *array = top.sp[-3].array;
   499     int index = top.sp[-2].i32;
   500     array->writeChar(index, top.sp[-1].i32);
   501     top.sp[-3] = top.sp[-1];
   502     top.sp -= 2;
   503     break;
   504 }
   505 
   506 case OP_GETARRAY_O:
   507 {
   508     Array *array = top.sp[-2].array;
   509     int index = top.sp[-1].i32;
   510     top.sp[-2].array = Array::cast(array->readObject(index));
   511     top.sp--;
   512     break;
   513 }
   514 
   515 case OP_CVT_I2F:
   516 {
   517     int ival = POP_I32(top);
   518     float fval = (float)ival;
   519     PUSH_F(top, fval);
   520     break;
   521 }
   522 
   523 case OP_NEWARRAY_LIFO:
   524 {
   525     Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc))));
   526     Array *array = GenerateArray(zone, map);
   527     if (!array)
   528         goto error;
   529     top.sp->obj = array;
   530     top.sp++;
   531     break;
   532 }
   533 
   534 case OP_SAVELIFO:
   535 {
   536     unsigned slot = READ_UINT32(top.pc);
   537     locals[slot].address = zone->heap().lifoPosition();
   538     break;
   539 }
   540 
   541 case OP_UNWINDLIFO:
   542 {
   543     unsigned slot = READ_UINT32(top.pc);
   544     zone->heap().unwindLifo(locals[slot].address);
   545     break;
   546 }
   547 
   548 case OP_VARREF_LIFO:
   549 {
   550     unsigned slot = READ_UINT32(top.pc);
   551     if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
   552         goto error;
   553     break;
   554 }
   555 
   556 case OP_ARGREF_LIFO:
   557 {
   558     unsigned slot = READ_UINT32(top.pc);
   559     if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
   560         goto error;
   561     break;
   562 }
   563 
   564 case OP_ARRAYREF_LIFO:
   565 {
   566     Local<Array> array(zone, top.sp[-2].array);
   567     Local<Reference> ref(zone, Reference::NewArray(zone, array, top.sp[-1].i32, Heap::Tenure_Stack));
   568     if (!ref)
   569         goto error;
   570     top.sp[-2].ref = ref;
   571     top.sp--;
   572     break;
   573 }
   574 
   575 case OP_SLOTREF_LIFO:
   576 {
   577     Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
   578     if (!ref)
   579         goto error;
   580     top.sp[-1].ref = ref;
   581     break;
   582 }
   583 
   584 case OP_GETREF_I:
   585 {
   586     top.sp[-1].i32 = top.sp[-1].ref->getInt();
   587     break;
   588 }
   589 
   590 case OP_SETREF_I:
   591 {
   592     top.sp[-2].ref->setInt(top.sp[-1].i32);
   593     top.sp[-2].i32 = top.sp[-1].i32;
   594     top.sp--;
   595     break;
   596 }
   597 
   598 case OP_GETREF_F:
   599 {
   600     top.sp[-1].f = top.sp[-1].ref->getFloat();
   601     break;
   602 }
   603 
   604 case OP_SETREF_F:
   605 {
   606     top.sp[-2].ref->setFloat(top.sp[-1].f);
   607     top.sp[-2].f = top.sp[-1].f;
   608     break;
   609 }
   610 
   611 case OP_OBJECT:
   612 {
   613     top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
   614     top.sp++;
   615     break;
   616 }
   617 
   618 case OP_ARRAYCOPY:
   619 {
   620     // Note for this assignment opcode, we return the left-hand side, not the
   621     // right, since in this case the result of the expression could be different.
   622     if (!CopyArray(zone, top.sp[-2].array, top.sp[-1].array))
   623         goto error;
   624     top.sp--;
   625     break;
   626 }
   627 
   628 case OP_DUP:
   629 {
   630     top.sp++;
   631     top.sp[-1] = top.sp[-2];
   632     break;
   633 }
   634 
   635 case OP_DUP2:
   636 {
   637     top.sp += 2;
   638     top.sp[-2] = top.sp[-4];
   639     top.sp[-1] = top.sp[-3];
   640     break;
   641 }
   642 
   643 case OP_SWAP:
   644 {
   645     LocalSlot slot = top.sp[-2];
   646     top.sp[-2] = top.sp[-1];
   647     top.sp[-1] = slot;
   648     break;
   649 }
   650 
   651 case OP_ROLL3:
   652 {
   653     LocalSlot slot = top.sp[-3];
   654     top.sp[-3] = top.sp[-2];
   655     top.sp[-2] = top.sp[-1];
   656     top.sp[-1] = slot;
   657     break;
   658 }
   659 
   660 case OP_PICK2:
   661 {
   662     top.sp++;
   663     top.sp[-1] = top.sp[-3];
   664     break;
   665 }
   666 
   667 case OP_PICK3:
   668 {
   669     top.sp++;
   670     top.sp[-1] = top.sp[-4];
   671     break;
   672 }
   673 
   674 case OP_CALLNATIVE:
   675 {
   676     unsigned index = READ_UINT32(top.pc);
   677     unsigned argc = READ_UINT32(top.pc + 4);
   678 
   679     Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
   680     if (!native->function()) {
   681         zone->reportError(Message_NativeNotBound, native->name()->chars());
   682         goto error;
   683     }
   684 
   685     int result;
   686     void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
   687     if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
   688         goto error;
   689 
   690     top.sp -= argc;
   691     PUSH_I32(top, result);
   692     break;
   693 }
   694 
   695 case OP_MODULE:
   696 {
   697     top.sp++;
   698     top.sp[-1].module = top.fp->code()->module();
   699     break;
   700 }
   701 
   702 case OP_GETMODULE_FN:
   703 {
   704     top.sp[-1].fun = top.sp[-1].module->getFunction(READ_UINT32(top.pc));
   705     break;
   706 }
   707 
   708 default:
   709     assert(false);
   710     return false;
   711 
   712         }
   713 
   714         top.pc += OpcodeInfo[op].length;
   715     }
   716 
   717 done:
   718     return true;
   719 
   720 error:
   721     // Unwind frames until we can continue.
   722     while (top.fp != entryFrame)
   723         zone->stack().popInlineFrame();
   724     return false;
   725 }