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