jitcraft/Interpreter.cpp
author David Anderson <dvander@alliedmods.net>
Sat Jul 14 21:01:52 2012 -0700 (2012-07-14)
changeset 72 40746ab0a30b
parent 69 dfce0539a77d
child 73 ef5492aa8d8b
permissions -rw-r--r--
Added support for calling return-void functions.
Fixed a bug in array size calculation.
     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_CALLGLOBAL:
   411 {
   412     zone->heap().reclaim();
   413     unsigned index = READ_UINT32(top.pc);
   414     Local<Function> newFun(zone, top.fp->code()->module()->getFunction(index));
   415     if (!zone->stack().pushInlineFrame(newFun))
   416         goto error;
   417 
   418     locals = top.fp->locals();
   419     continue;
   420 }
   421 
   422 case OP_GETARG:
   423 {
   424     unsigned slot = READ_UINT32(top.pc);
   425     *top.sp++ = top.fp->arg(slot);
   426     break;
   427 }
   428 
   429 case OP_SETARG:
   430 {
   431     unsigned slot = READ_UINT32(top.pc);
   432     top.fp->arg(slot) = *--top.sp;
   433     break;
   434 }
   435 
   436 case OP_BOUNDS:
   437 {
   438     Array *array = top.sp[-2].array;
   439     int index = top.sp[-1].i32;
   440     if (index < 0 || unsigned(index) >= array->nelements()) {
   441         zone->reportError(Message_ArrayIndexOutOfBounds, index, array->nelements());
   442         goto error;
   443     }
   444     break;
   445 }
   446 
   447 case OP_GETARRAY_I:
   448 {
   449     Array *array = top.sp[-2].array;
   450     int index = top.sp[-1].i32;
   451     top.sp[-2].i32 = array->readInt32(index);
   452     top.sp--;
   453     break;
   454 }
   455 
   456 case OP_GETARRAY_F:
   457 {
   458     Array *array = top.sp[-2].array;
   459     int index = top.sp[-1].i32;
   460     top.sp[-2].f = array->readFloat(index);
   461     top.sp--;
   462     break;
   463 }
   464 
   465 case OP_GETARRAY_C:
   466 {
   467     Array *array = top.sp[-2].array;
   468     int index = top.sp[-1].i32;
   469     top.sp[-2].i32 = array->readChar(index);
   470     top.sp--;
   471     break;
   472 }
   473 
   474 case OP_SETARRAY_I:
   475 {
   476     Array *array = top.sp[-3].array;
   477     int index = top.sp[-2].i32;
   478     array->writeInt32(index, top.sp[-1].i32);
   479     top.sp[-3] = top.sp[-1];
   480     top.sp -= 2;
   481     break;
   482 }
   483 
   484 case OP_SETARRAY_F:
   485 {
   486     Array *array = top.sp[-3].array;
   487     int index = top.sp[-2].i32;
   488     array->writeFloat(index, top.sp[-1].f);
   489     top.sp[-3] = top.sp[-1];
   490     top.sp -= 2;
   491     break;
   492 }
   493 
   494 case OP_SETARRAY_C:
   495 {
   496     Array *array = top.sp[-3].array;
   497     int index = top.sp[-2].i32;
   498     array->writeChar(index, top.sp[-1].i32);
   499     top.sp[-3] = top.sp[-1];
   500     top.sp -= 2;
   501     break;
   502 }
   503 
   504 case OP_GETARRAY_O:
   505 {
   506     Array *array = top.sp[-2].array;
   507     int index = top.sp[-1].i32;
   508     top.sp[-2].array = Array::cast(array->readObject(index));
   509     top.sp--;
   510     break;
   511 }
   512 
   513 case OP_CVT_I2F:
   514 {
   515     int ival = POP_I32(top);
   516     float fval = (float)ival;
   517     PUSH_F(top, fval);
   518     break;
   519 }
   520 
   521 case OP_NEWARRAY_LIFO:
   522 {
   523     Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc))));
   524     Array *array = GenerateArray(zone, map);
   525     if (!array)
   526         goto error;
   527     top.sp->obj = array;
   528     top.sp++;
   529     break;
   530 }
   531 
   532 case OP_SAVELIFO:
   533 {
   534     unsigned slot = READ_UINT32(top.pc);
   535     locals[slot].address = zone->heap().lifoPosition();
   536     break;
   537 }
   538 
   539 case OP_UNWINDLIFO:
   540 {
   541     unsigned slot = READ_UINT32(top.pc);
   542     zone->heap().unwindLifo(locals[slot].address);
   543     break;
   544 }
   545 
   546 case OP_VARREF_LIFO:
   547 {
   548     unsigned slot = READ_UINT32(top.pc);
   549     if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
   550         goto error;
   551     break;
   552 }
   553 
   554 case OP_ARGREF_LIFO:
   555 {
   556     unsigned slot = READ_UINT32(top.pc);
   557     if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
   558         goto error;
   559     break;
   560 }
   561 
   562 case OP_ARRAYREF_LIFO:
   563 {
   564     Local<Array> array(zone, top.sp[-2].array);
   565     Local<Reference> ref(zone, Reference::NewArray(zone, array, top.sp[-1].i32, Heap::Tenure_Stack));
   566     if (!ref)
   567         goto error;
   568     top.sp[-2].ref = ref;
   569     top.sp--;
   570     break;
   571 }
   572 
   573 case OP_SLOTREF_LIFO:
   574 {
   575     Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
   576     if (!ref)
   577         goto error;
   578     top.sp[-1].ref = ref;
   579     break;
   580 }
   581 
   582 case OP_GETREF_I:
   583 {
   584     top.sp[-1].i32 = top.sp[-1].ref->getInt();
   585     break;
   586 }
   587 
   588 case OP_SETREF_I:
   589 {
   590     top.sp[-2].ref->setInt(top.sp[-1].i32);
   591     top.sp[-2].i32 = top.sp[-1].i32;
   592     top.sp--;
   593     break;
   594 }
   595 
   596 case OP_GETREF_F:
   597 {
   598     top.sp[-1].f = top.sp[-1].ref->getFloat();
   599     break;
   600 }
   601 
   602 case OP_SETREF_F:
   603 {
   604     top.sp[-2].ref->setFloat(top.sp[-1].f);
   605     top.sp[-2].f = top.sp[-1].f;
   606     break;
   607 }
   608 
   609 case OP_OBJECT:
   610 {
   611     top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
   612     top.sp++;
   613     break;
   614 }
   615 
   616 case OP_ARRAYCOPY:
   617 {
   618     // Note for this assignment opcode, we return the left-hand side, not the
   619     // right, since in this case the result of the expression could be different.
   620     if (!CopyArray(zone, top.sp[-2].array, top.sp[-1].array))
   621         goto error;
   622     top.sp--;
   623     break;
   624 }
   625 
   626 case OP_DUP:
   627 {
   628     top.sp++;
   629     top.sp[-1] = top.sp[-2];
   630     break;
   631 }
   632 
   633 case OP_DUP2:
   634 {
   635     top.sp += 2;
   636     top.sp[-2] = top.sp[-4];
   637     top.sp[-1] = top.sp[-3];
   638     break;
   639 }
   640 
   641 case OP_SWAP:
   642 {
   643     LocalSlot slot = top.sp[-2];
   644     top.sp[-2] = top.sp[-1];
   645     top.sp[-1] = slot;
   646     break;
   647 }
   648 
   649 case OP_ROLL3:
   650 {
   651     LocalSlot slot = top.sp[-3];
   652     top.sp[-3] = top.sp[-2];
   653     top.sp[-2] = top.sp[-1];
   654     top.sp[-1] = slot;
   655     break;
   656 }
   657 
   658 case OP_PICK2:
   659 {
   660     top.sp++;
   661     top.sp[-1] = top.sp[-3];
   662     break;
   663 }
   664 
   665 case OP_PICK3:
   666 {
   667     top.sp++;
   668     top.sp[-1] = top.sp[-4];
   669     break;
   670 }
   671 
   672 case OP_CALLNATIVE:
   673 {
   674     unsigned index = READ_UINT32(top.pc);
   675     unsigned argc = READ_UINT32(top.pc + 4);
   676 
   677     Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
   678     if (!native->function()) {
   679         zone->reportError(Message_NativeNotBound, native->name()->chars());
   680         goto error;
   681     }
   682 
   683     int result;
   684     void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
   685     if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
   686         goto error;
   687 
   688     top.sp -= argc;
   689     PUSH_I32(top, result);
   690     break;
   691 }
   692 
   693 default:
   694     assert(false);
   695     return false;
   696 
   697         }
   698 
   699         top.pc += OpcodeInfo[op].length;
   700     }
   701 
   702 done:
   703     return true;
   704 
   705 error:
   706     // Unwind frames until we can continue.
   707     while (top.fp != entryFrame)
   708         zone->stack().popInlineFrame();
   709     return false;
   710 }