jitcraft/Interpreter.cpp
author David Anderson <dvander@alliedmods.net>
Wed Jul 18 21:46:29 2012 -0700 (2012-07-18)
changeset 82 f99bc938522a
parent 81 77c318a4badd
child 85 06a0015b6a5c
permissions -rw-r--r--
Added support for modulo operator.
     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 // Pawn's original semantics specify some kind of floor operation, so
    59 // (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses
    60 // the upstream algorithm when constant folding. However the SourcePawn 1 JIT
    61 // does not. My guess is that Borja freaked out seeing the 13-instruction x86
    62 // sequence necessary to get this functionality (I vaguely recall a thread
    63 // where we discussed this with Mark Peter? But the ITB forums are gone...),
    64 // and we just decided to break the damn thing. So SP1 was inconsistent, but
    65 // we are not. And for completeness, we assert that the C compiler does the
    66 // right thing, since C89 leaves it unspecified.
    67 STATIC_ASSERT(8 / -3 == -2);
    68 STATIC_ASSERT(-8 / 3 == -2);
    69 
    70 static inline bool
    71 PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
    72 {
    73     Reference *ref = Reference::NewStack(zone, location, tenure);
    74     if (!ref)
    75         return false;
    76     top.sp->ref = ref;
    77     top.sp++;
    78     return true;
    79 }
    80 
    81 // Generate an array with completely static sizes.
    82 static Array *
    83 GenerateArray(Zone *zone, Handle<ArrayMap> map)
    84 {
    85     assert(map->type()->elements() != -1);
    86 
    87     Local<Array> array(zone, Array::New(zone, map, map->type()->elements(), Heap::Tenure_Stack));
    88     if (!array)
    89         return NULL;
    90 
    91     if (map->type()->levels() == 1)
    92         return array;
    93 
    94     Local<ArrayMap> contained(zone, map->contained());
    95     Local<Array> sub(zone);
    96     for (unsigned i = 0; i < unsigned(map->type()->elements()); i++) {
    97         sub = GenerateArray(zone, contained);
    98         if (!sub)
    99             return NULL;
   100         array->writeObject(zone, i, sub);
   101     }
   102 
   103     return array;
   104 }
   105 
   106 static bool
   107 CopyArray(Zone *zone, Array *source, Array *dest)
   108 {
   109     assert(source->type()->levels() == 1);
   110     assert(dest->type()->levels() == 1);
   111     assert(source->type()->contained()->primitive() ==
   112            dest->type()->contained()->primitive());
   113     assert(source->nelements() >= dest->nelements());
   114     assert(dest->elementSize() == source->elementSize());
   115 
   116     memcpy(source->vec(), dest->vec(), dest->nelements() * dest->elementSize());
   117     return true;
   118 }
   119 
   120 static bool
   121 InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
   122              int *result)
   123 {
   124     NativeArgs guard;
   125 
   126     if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
   127         return false;
   128 
   129     intptr_t *cells = guard.args();
   130 
   131     // params[0] == argc, in ISPE
   132     cells[0] = argc;
   133 
   134     // Pass the formal arguments.
   135     Local<Type> type(zone, native->type());
   136     Local<Type> param(zone);
   137     for (unsigned i = 0; i < type->parameters()->length(); i++) {
   138         param = type->parameterAt(i);
   139         
   140         // For floats, we rely on the aliasing of |i32| and |f|.
   141         LocalSlot &arg = args[-int(i) - 1];
   142         if (param->isInt32() || param->isFloat()) {
   143             cells[i + 1] = arg.i32;
   144         } else if (param->isReference()) {
   145             cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
   146         } else {
   147             assert(param->isArray());
   148             cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
   149         }
   150     }
   151 
   152     // For variadic arguments, the compiler left either arrays or references.
   153     for (unsigned i = type->parameters()->length(); i < argc; i++) {
   154         LocalSlot &arg = args[-int(i) - 1];
   155 
   156         if (arg.obj->is(MapKind_Reference)) {
   157             cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
   158         } else {
   159             assert(arg.obj->is(MapKind_Array));
   160             cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
   161         }
   162     }
   163 
   164     typedef intptr_t (*INVOKE)(void *, intptr_t *);
   165     INVOKE invoke = (INVOKE)native->function();
   166     *result = invoke(identity, cells);
   167 
   168     return !zone->hasPendingException();
   169 }
   170 
   171 bool
   172 ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
   173 {
   174     Top &top = *zone->stack().top();
   175     if (!entryFrame)
   176         entryFrame = top.fp;
   177 
   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 case OP_RETURNVOID:
   197 case OP_STOP:
   198 {
   199     if (op == OP_RETURN)
   200         *result = *--top.sp;
   201 
   202     if (top.fp == entryFrame)
   203         goto done;
   204 
   205     // This must not GC.
   206     zone->stack().popInlineFrame();
   207     locals = top.fp->locals();
   208 
   209     if (op == OP_RETURN)
   210         *top.sp++ = *result;
   211 
   212     top.pc += OpcodeInfo[*top.pc].length;
   213     continue;
   214 }
   215 
   216 case OP_POP:
   217 {
   218     top.sp--;
   219     break;
   220 }
   221 
   222 #define RELATIONAL_JUMP(op)                 \
   223     {                                       \
   224         int right = POP_I32(top);           \
   225         int left = POP_I32(top);            \
   226         if (left op right) {                \
   227             top.pc += READ_INT32(top.pc);   \
   228             continue;                       \
   229         }                                   \
   230     }
   231 
   232 case OP_JL:
   233     RELATIONAL_JUMP(<);
   234     break;
   235 
   236 case OP_JLE:
   237     RELATIONAL_JUMP(<=);
   238     break;
   239 
   240 case OP_JG:
   241     RELATIONAL_JUMP(>);
   242     break;
   243 
   244 case OP_JGE:
   245     RELATIONAL_JUMP(>=);
   246     break;
   247 
   248 case OP_JEQ:
   249     RELATIONAL_JUMP(==);
   250     break;
   251 
   252 case OP_JNE:
   253     RELATIONAL_JUMP(!=);
   254     break;
   255 
   256 #undef RELATIONAL_JUMP
   257 
   258 case OP_JT:
   259 {
   260     int value = POP_I32(top);
   261     if (value) {
   262         top.pc += READ_INT32(top.pc);
   263         continue;
   264     }
   265     break;
   266 }
   267 
   268 case OP_JF:
   269 {
   270     int value = POP_I32(top);
   271     if (!value) {
   272         top.pc += READ_INT32(top.pc);
   273         continue;
   274     }
   275     break;
   276 }
   277 
   278 #define RELATIONAL_JUMP_F(op)               \
   279     {                                       \
   280         float right = POP_F(top);           \
   281         float left = POP_F(top);            \
   282         if (left op right) {                \
   283             top.pc += READ_INT32(top.pc);   \
   284             continue;                       \
   285         }                                   \
   286     }
   287 
   288 case OP_JL_F:
   289     RELATIONAL_JUMP_F(<);
   290     break;
   291 
   292 case OP_JLE_F:
   293     RELATIONAL_JUMP_F(<=);
   294     break;
   295 
   296 case OP_JG_F:
   297     RELATIONAL_JUMP_F(>);
   298     break;
   299 
   300 case OP_JGE_F:
   301     RELATIONAL_JUMP_F(>=);
   302     break;
   303 
   304 case OP_JEQ_F:
   305     RELATIONAL_JUMP_F(==);
   306     break;
   307 
   308 case OP_JNE_F:
   309     RELATIONAL_JUMP_F(!=);
   310     break;
   311 
   312 case OP_JT_F:
   313 {
   314     float value = POP_F(top);
   315     if (value) {
   316         top.pc += READ_INT32(top.pc);
   317         continue;
   318     }
   319     break;
   320 }
   321 
   322 case OP_JF_F:
   323 {
   324     float value = POP_F(top);
   325     if (!value) {
   326         top.pc += READ_INT32(top.pc);
   327         continue;
   328     }
   329     break;
   330 }
   331 
   332 case OP_JUMP:
   333     top.pc += READ_INT32(top.pc);
   334     continue;
   335 
   336 case OP_GETLOCAL:
   337 {
   338     int slot = READ_INT32(top.pc);
   339     *top.sp++ = locals[slot];
   340     break;
   341 }
   342 
   343 case OP_SETLOCAL:
   344 {
   345     int slot = READ_INT32(top.pc);
   346     locals[slot] = top.sp[-1];
   347     break;
   348 }
   349 
   350 case OP_ADD:
   351 {
   352     top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
   353     top.sp--;
   354     break;
   355 }
   356 
   357 case OP_SUB:
   358 {
   359     top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
   360     top.sp--;
   361     break;
   362 }
   363 
   364 case OP_MUL:
   365 {
   366     top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
   367     top.sp--;
   368     break;
   369 }
   370 
   371 case OP_DIV:
   372 {
   373     if (top.sp[-1].i32 == 0) {
   374         zone->reportError(Message_IntegerDivideByZero);
   375         goto error;
   376     }
   377     top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
   378     top.sp--;
   379     break;
   380 }
   381 
   382 case OP_MOD:
   383 {
   384     if (top.sp[-1].i32 == 0) {
   385         zone->reportError(Message_IntegerDivideByZero);
   386         goto error;
   387     }
   388     top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
   389     top.sp--;
   390     break;
   391 }
   392 
   393 case OP_LT:
   394 {
   395     top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
   396     top.sp--;
   397     break;
   398 }
   399 
   400 case OP_LE:
   401 {
   402     top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
   403     top.sp--;
   404     break;
   405 }
   406 
   407 case OP_GT:
   408 {
   409     top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
   410     top.sp--;
   411     break;
   412 }
   413 
   414 case OP_GE:
   415 {
   416     top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
   417     top.sp--;
   418     break;
   419 }
   420 
   421 case OP_EQ:
   422 {
   423     top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
   424     top.sp--;
   425     break;
   426 }
   427 
   428 case OP_NE:
   429 {
   430     top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
   431     top.sp--;
   432     break;
   433 }
   434 
   435 case OP_ADD_F:
   436 {
   437     top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
   438     top.sp--;
   439     break;
   440 }
   441 
   442 case OP_SUB_F:
   443 {
   444     top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
   445     top.sp--;
   446     break;
   447 }
   448 
   449 case OP_MUL_F:
   450 {
   451     top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
   452     top.sp--;
   453     break;
   454 }
   455 
   456 case OP_DIV_F:
   457 {
   458     top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
   459     top.sp--;
   460     break;
   461 }
   462 
   463 case OP_LT_F:
   464 {
   465     top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
   466     top.sp--;
   467     break;
   468 }
   469 
   470 case OP_LE_F:
   471 {
   472     top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
   473     top.sp--;
   474     break;
   475 }
   476 
   477 case OP_GT_F:
   478 {
   479     top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
   480     top.sp--;
   481     break;
   482 }
   483 
   484 case OP_GE_F:
   485 {
   486     top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
   487     top.sp--;
   488     break;
   489 }
   490 
   491 case OP_EQ_F:
   492 {
   493     top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
   494     top.sp--;
   495     break;
   496 }
   497 
   498 case OP_NE_F:
   499 {
   500     top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
   501     top.sp--;
   502     break;
   503 }
   504 
   505 case OP_SHL:
   506 {
   507     top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
   508     top.sp--;
   509     break;
   510 }
   511 
   512 case OP_SHR:
   513 {
   514     top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
   515     top.sp--;
   516     break;
   517 }
   518 
   519 case OP_USHR:
   520 {
   521     top.sp[-2].i32 = unsigned(top.sp[-2].i32) << unsigned(top.sp[-1].i32);
   522     top.sp--;
   523     break;
   524 }
   525 
   526 case OP_BITAND:
   527 {
   528     top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
   529     top.sp--;
   530     break;
   531 }
   532 
   533 case OP_BITOR:
   534 {
   535     top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
   536     top.sp--;
   537     break;
   538 }
   539 
   540 case OP_BITXOR:
   541 {
   542     top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
   543     top.sp--;
   544     break;
   545 }
   546 
   547 case OP_BITNOT:
   548 {
   549     top.sp[-1].i32 = ~top.sp[-1].i32;
   550     break;
   551 }
   552 
   553 case OP_NOT:
   554 {
   555     top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
   556     break;
   557 }
   558 
   559 case OP_NOT_F:
   560 {
   561     top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
   562     break;
   563 }
   564 
   565 case OP_NEG:
   566 {
   567     top.sp[-1].i32 = -top.sp[-1].i32;
   568     break;
   569 }
   570 
   571 case OP_NEG_F:
   572 {
   573     top.sp[-1].f = -top.sp[-1].f;
   574     break;
   575 }
   576 
   577 case OP_CALL:
   578 {
   579     Local<Function> newFun(zone, top.sp[-1].fun);
   580     top.sp--;
   581 
   582     if (!zone->stack().pushInlineFrame(newFun))
   583         goto error;
   584 
   585     locals = top.fp->locals();
   586     continue;
   587 }
   588 
   589 case OP_GETARG:
   590 {
   591     unsigned slot = READ_UINT32(top.pc);
   592     *top.sp++ = top.fp->arg(slot);
   593     break;
   594 }
   595 
   596 case OP_SETARG:
   597 {
   598     unsigned slot = READ_UINT32(top.pc);
   599     top.fp->arg(slot) = *--top.sp;
   600     break;
   601 }
   602 
   603 case OP_BOUNDS:
   604 {
   605     Array *array = top.sp[-2].array;
   606     int index = top.sp[-1].i32;
   607     if (index < 0 || unsigned(index) >= array->nelements()) {
   608         zone->reportError(Message_ArrayIndexOutOfBounds, index, array->nelements());
   609         goto error;
   610     }
   611     break;
   612 }
   613 
   614 case OP_GETARRAY_I:
   615 {
   616     Array *array = top.sp[-2].array;
   617     int index = top.sp[-1].i32;
   618     top.sp[-2].i32 = array->readInt32(index);
   619     top.sp--;
   620     break;
   621 }
   622 
   623 case OP_GETARRAY_F:
   624 {
   625     Array *array = top.sp[-2].array;
   626     int index = top.sp[-1].i32;
   627     top.sp[-2].f = array->readFloat(index);
   628     top.sp--;
   629     break;
   630 }
   631 
   632 case OP_GETARRAY_C:
   633 {
   634     Array *array = top.sp[-2].array;
   635     int index = top.sp[-1].i32;
   636     top.sp[-2].i32 = array->readChar(index);
   637     top.sp--;
   638     break;
   639 }
   640 
   641 case OP_SETARRAY_I:
   642 {
   643     Array *array = top.sp[-3].array;
   644     int index = top.sp[-2].i32;
   645     array->writeInt32(index, top.sp[-1].i32);
   646     top.sp[-3] = top.sp[-1];
   647     top.sp -= 2;
   648     break;
   649 }
   650 
   651 case OP_SETARRAY_F:
   652 {
   653     Array *array = top.sp[-3].array;
   654     int index = top.sp[-2].i32;
   655     array->writeFloat(index, top.sp[-1].f);
   656     top.sp[-3] = top.sp[-1];
   657     top.sp -= 2;
   658     break;
   659 }
   660 
   661 case OP_SETARRAY_C:
   662 {
   663     Array *array = top.sp[-3].array;
   664     int index = top.sp[-2].i32;
   665     array->writeChar(index, top.sp[-1].i32);
   666     top.sp[-3] = top.sp[-1];
   667     top.sp -= 2;
   668     break;
   669 }
   670 
   671 case OP_GETARRAY_O:
   672 {
   673     Array *array = top.sp[-2].array;
   674     int index = top.sp[-1].i32;
   675     top.sp[-2].array = Array::cast(array->readObject(index));
   676     top.sp--;
   677     break;
   678 }
   679 
   680 case OP_CVT_I2F:
   681 {
   682     int ival = POP_I32(top);
   683     float fval = (float)ival;
   684     PUSH_F(top, fval);
   685     break;
   686 }
   687 
   688 case OP_NEWARRAY_LIFO:
   689 {
   690     Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc))));
   691     Array *array = GenerateArray(zone, map);
   692     if (!array)
   693         goto error;
   694     top.sp->obj = array;
   695     top.sp++;
   696     break;
   697 }
   698 
   699 case OP_SAVELIFO:
   700 {
   701     unsigned slot = READ_UINT32(top.pc);
   702     locals[slot].address = zone->heap().lifoPosition();
   703     break;
   704 }
   705 
   706 case OP_UNWINDLIFO:
   707 {
   708     unsigned slot = READ_UINT32(top.pc);
   709     zone->heap().unwindLifo(locals[slot].address);
   710     break;
   711 }
   712 
   713 case OP_VARREF_LIFO:
   714 {
   715     unsigned slot = READ_UINT32(top.pc);
   716     if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
   717         goto error;
   718     break;
   719 }
   720 
   721 case OP_ARGREF_LIFO:
   722 {
   723     unsigned slot = READ_UINT32(top.pc);
   724     if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
   725         goto error;
   726     break;
   727 }
   728 
   729 case OP_ARRAYREF_LIFO:
   730 {
   731     Local<Array> array(zone, top.sp[-2].array);
   732     Local<Reference> ref(zone, Reference::NewArray(zone, array, top.sp[-1].i32, Heap::Tenure_Stack));
   733     if (!ref)
   734         goto error;
   735     top.sp[-2].ref = ref;
   736     top.sp--;
   737     break;
   738 }
   739 
   740 case OP_SLOTREF_LIFO:
   741 {
   742     Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
   743     if (!ref)
   744         goto error;
   745     top.sp[-1].ref = ref;
   746     break;
   747 }
   748 
   749 case OP_GETREF_I:
   750 {
   751     top.sp[-1].i32 = top.sp[-1].ref->getInt();
   752     break;
   753 }
   754 
   755 case OP_SETREF_I:
   756 {
   757     top.sp[-2].ref->setInt(top.sp[-1].i32);
   758     top.sp[-2].i32 = top.sp[-1].i32;
   759     top.sp--;
   760     break;
   761 }
   762 
   763 case OP_GETREF_F:
   764 {
   765     top.sp[-1].f = top.sp[-1].ref->getFloat();
   766     break;
   767 }
   768 
   769 case OP_SETREF_F:
   770 {
   771     top.sp[-2].ref->setFloat(top.sp[-1].f);
   772     top.sp[-2].f = top.sp[-1].f;
   773     break;
   774 }
   775 
   776 case OP_OBJECT:
   777 {
   778     top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
   779     top.sp++;
   780     break;
   781 }
   782 
   783 case OP_ARRAYCOPY:
   784 {
   785     // Note for this assignment opcode, we return the left-hand side, not the
   786     // right, since in this case the result of the expression could be different.
   787     if (!CopyArray(zone, top.sp[-2].array, top.sp[-1].array))
   788         goto error;
   789     top.sp--;
   790     break;
   791 }
   792 
   793 case OP_DUP:
   794 {
   795     top.sp++;
   796     top.sp[-1] = top.sp[-2];
   797     break;
   798 }
   799 
   800 case OP_DUP2:
   801 {
   802     top.sp += 2;
   803     top.sp[-2] = top.sp[-4];
   804     top.sp[-1] = top.sp[-3];
   805     break;
   806 }
   807 
   808 case OP_SWAP:
   809 {
   810     LocalSlot slot = top.sp[-2];
   811     top.sp[-2] = top.sp[-1];
   812     top.sp[-1] = slot;
   813     break;
   814 }
   815 
   816 case OP_ROLL3:
   817 {
   818     LocalSlot slot = top.sp[-3];
   819     top.sp[-3] = top.sp[-2];
   820     top.sp[-2] = top.sp[-1];
   821     top.sp[-1] = slot;
   822     break;
   823 }
   824 
   825 case OP_PICK2:
   826 {
   827     top.sp++;
   828     top.sp[-1] = top.sp[-3];
   829     break;
   830 }
   831 
   832 case OP_PICK3:
   833 {
   834     top.sp++;
   835     top.sp[-1] = top.sp[-4];
   836     break;
   837 }
   838 
   839 case OP_CALLNATIVE:
   840 {
   841     unsigned index = READ_UINT32(top.pc);
   842     unsigned argc = READ_UINT32(top.pc + 4);
   843 
   844     Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
   845     if (!native->function()) {
   846         zone->reportError(Message_NativeNotBound, native->name()->chars());
   847         goto error;
   848     }
   849 
   850     int result;
   851     void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
   852     if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
   853         goto error;
   854 
   855     top.sp -= argc;
   856     PUSH_I32(top, result);
   857     break;
   858 }
   859 
   860 case OP_MODULE:
   861 {
   862     top.sp++;
   863     top.sp[-1].module = top.fp->code()->module();
   864     break;
   865 }
   866 
   867 case OP_GETMODULE_FN:
   868 {
   869     top.sp[-1].fun = top.sp[-1].module->getFunction(READ_UINT32(top.pc));
   870     break;
   871 }
   872 
   873 default:
   874     assert(false);
   875     return false;
   876 
   877         }
   878 
   879         top.pc += OpcodeInfo[op].length;
   880     }
   881 
   882 done:
   883     return true;
   884 
   885 error:
   886     // Unwind frames until we can continue.
   887     while (top.fp != entryFrame)
   888         zone->stack().popInlineFrame();
   889     return false;
   890 }