src/Interpreter.cpp
author David Anderson <dvander@alliedmods.net>
Sat Jul 28 16:42:38 2012 -0700 (2012-07-28)
changeset 108 9dcf58a17d32
parent 91 5f4402180204
child 142 a000bafece09
permissions -rw-r--r--
Stop using ccache on OS X.
     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 <string.h>
    20 #include "Interpreter.h"
    21 #include "Modules.h"
    22 #include "Zone.h"
    23 #include "Types.h"
    24 #include "Array.h"
    25 #include "Reference.h"
    26 #include "Strings.h"
    27 #include "Environments.h"
    28 #include "Heap-inl.h"
    29 
    30 using namespace ke;
    31 
    32 #define PUSH_I32(top, value)    \
    33     do {                        \
    34         top.sp->i32 = value;    \
    35         top.sp++;               \
    36    } while (0)
    37 
    38 #define PUSH_F(top, value)      \
    39     do {                        \
    40         top.sp->f = value;      \
    41         top.sp++;               \
    42    } while (0)
    43 
    44 static inline int
    45 POP_I32(Top &top)
    46 {
    47     int value = top.sp[-1].i32;
    48     top.sp--;
    49     return value;
    50 }
    51 
    52 static inline float
    53 POP_F(Top &top)
    54 {
    55     float value = top.sp[-1].f;
    56     top.sp--;
    57     return value;
    58 }
    59 
    60 // Pawn's original semantics specify some kind of floor operation, so
    61 // (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses
    62 // the upstream algorithm when constant folding. However the SourcePawn 1 JIT
    63 // does not. My guess is that Borja freaked out seeing the 13-instruction x86
    64 // sequence necessary to get this functionality (I vaguely recall a thread
    65 // where we discussed this with Mark Peter? But the ITB forums are gone...),
    66 // and we just decided to break the damn thing. So SP1 was inconsistent, but
    67 // we are not. And for completeness, we assert that the C compiler does the
    68 // right thing, since C89 leaves it unspecified.
    69 STATIC_ASSERT(8 / -3 == -2);
    70 STATIC_ASSERT(-8 / 3 == -2);
    71 
    72 static inline bool
    73 PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
    74 {
    75     Reference *ref = Reference::NewStack(zone, location, tenure);
    76     if (!ref)
    77         return false;
    78     top.sp->ref = ref;
    79     top.sp++;
    80     return true;
    81 }
    82 
    83 // Generate an array with completely static sizes.
    84 static Array *
    85 GenerateArray(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
    86 {
    87     assert(map->type()->elements() != -1);
    88 
    89     Local<Array> array(zone, Array::New(zone, map, map->type()->elements(), tenure));
    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, tenure);
   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     return !zone->hasPendingException();
   171 }
   172 
   173 bool
   174 ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
   175 {
   176     Top &top = *zone->stack().top();
   177     if (!entryFrame)
   178         entryFrame = top.fp;
   179 
   180     LocalSlot *locals = entryFrame->locals();
   181 
   182     for (;;) {
   183         Opcode op = Opcode(*top.pc);
   184         switch (op) {
   185 
   186 case OP_NOP:
   187     break;
   188 
   189 case OP_INT:
   190     PUSH_I32(top, READ_INT32(top.pc));
   191     break;
   192 
   193 case OP_FLOAT:
   194     PUSH_F(top, READ_FLOAT(top.pc));
   195     break;
   196 
   197 case OP_RETURN:
   198 case OP_RETURNVOID:
   199 case OP_STOP:
   200 {
   201     if (op == OP_RETURN)
   202         *result = *--top.sp;
   203 
   204     if (top.fp == entryFrame)
   205         goto done;
   206 
   207     // This must not GC.
   208     zone->stack().popInlineFrame();
   209     locals = top.fp->locals();
   210 
   211     if (op == OP_RETURN)
   212         *top.sp++ = *result;
   213 
   214     top.pc += OpcodeInfo[*top.pc].length;
   215     continue;
   216 }
   217 
   218 case OP_POP:
   219 {
   220     top.sp--;
   221     break;
   222 }
   223 
   224 #define RELATIONAL_JUMP(op)                 \
   225     {                                       \
   226         int right = POP_I32(top);           \
   227         int left = POP_I32(top);            \
   228         if (left op right) {                \
   229             top.pc += READ_INT32(top.pc);   \
   230             continue;                       \
   231         }                                   \
   232     }
   233 
   234 case OP_JL:
   235     RELATIONAL_JUMP(<);
   236     break;
   237 
   238 case OP_JLE:
   239     RELATIONAL_JUMP(<=);
   240     break;
   241 
   242 case OP_JG:
   243     RELATIONAL_JUMP(>);
   244     break;
   245 
   246 case OP_JGE:
   247     RELATIONAL_JUMP(>=);
   248     break;
   249 
   250 case OP_JEQ:
   251     RELATIONAL_JUMP(==);
   252     break;
   253 
   254 case OP_JNE:
   255     RELATIONAL_JUMP(!=);
   256     break;
   257 
   258 #undef RELATIONAL_JUMP
   259 
   260 case OP_JT:
   261 {
   262     int value = POP_I32(top);
   263     if (value) {
   264         top.pc += READ_INT32(top.pc);
   265         continue;
   266     }
   267     break;
   268 }
   269 
   270 case OP_JF:
   271 {
   272     int value = POP_I32(top);
   273     if (!value) {
   274         top.pc += READ_INT32(top.pc);
   275         continue;
   276     }
   277     break;
   278 }
   279 
   280 #define RELATIONAL_JUMP_F(op)               \
   281     {                                       \
   282         float right = POP_F(top);           \
   283         float left = POP_F(top);            \
   284         if (left op right) {                \
   285             top.pc += READ_INT32(top.pc);   \
   286             continue;                       \
   287         }                                   \
   288     }
   289 
   290 case OP_JL_F:
   291     RELATIONAL_JUMP_F(<);
   292     break;
   293 
   294 case OP_JLE_F:
   295     RELATIONAL_JUMP_F(<=);
   296     break;
   297 
   298 case OP_JG_F:
   299     RELATIONAL_JUMP_F(>);
   300     break;
   301 
   302 case OP_JGE_F:
   303     RELATIONAL_JUMP_F(>=);
   304     break;
   305 
   306 case OP_JEQ_F:
   307     RELATIONAL_JUMP_F(==);
   308     break;
   309 
   310 case OP_JNE_F:
   311     RELATIONAL_JUMP_F(!=);
   312     break;
   313 
   314 case OP_JT_F:
   315 {
   316     float value = POP_F(top);
   317     if (value) {
   318         top.pc += READ_INT32(top.pc);
   319         continue;
   320     }
   321     break;
   322 }
   323 
   324 case OP_JF_F:
   325 {
   326     float value = POP_F(top);
   327     if (!value) {
   328         top.pc += READ_INT32(top.pc);
   329         continue;
   330     }
   331     break;
   332 }
   333 
   334 case OP_JUMP:
   335     top.pc += READ_INT32(top.pc);
   336     continue;
   337 
   338 case OP_GETLOCAL:
   339 {
   340     int slot = READ_INT32(top.pc);
   341     *top.sp++ = locals[slot];
   342     break;
   343 }
   344 
   345 case OP_SETLOCAL:
   346 {
   347     int slot = READ_INT32(top.pc);
   348     locals[slot] = top.sp[-1];
   349     break;
   350 }
   351 
   352 case OP_ADD:
   353 {
   354     top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
   355     top.sp--;
   356     break;
   357 }
   358 
   359 case OP_SUB:
   360 {
   361     top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
   362     top.sp--;
   363     break;
   364 }
   365 
   366 case OP_MUL:
   367 {
   368     top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
   369     top.sp--;
   370     break;
   371 }
   372 
   373 case OP_DIV:
   374 {
   375     if (top.sp[-1].i32 == 0) {
   376         zone->reportError(Message_IntegerDivideByZero);
   377         goto error;
   378     }
   379     top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
   380     top.sp--;
   381     break;
   382 }
   383 
   384 case OP_MOD:
   385 {
   386     if (top.sp[-1].i32 == 0) {
   387         zone->reportError(Message_IntegerDivideByZero);
   388         goto error;
   389     }
   390     top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
   391     top.sp--;
   392     break;
   393 }
   394 
   395 case OP_LT:
   396 {
   397     top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
   398     top.sp--;
   399     break;
   400 }
   401 
   402 case OP_LE:
   403 {
   404     top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
   405     top.sp--;
   406     break;
   407 }
   408 
   409 case OP_GT:
   410 {
   411     top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
   412     top.sp--;
   413     break;
   414 }
   415 
   416 case OP_GE:
   417 {
   418     top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
   419     top.sp--;
   420     break;
   421 }
   422 
   423 case OP_EQ:
   424 {
   425     top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
   426     top.sp--;
   427     break;
   428 }
   429 
   430 case OP_NE:
   431 {
   432     top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
   433     top.sp--;
   434     break;
   435 }
   436 
   437 case OP_ADD_F:
   438 {
   439     top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
   440     top.sp--;
   441     break;
   442 }
   443 
   444 case OP_SUB_F:
   445 {
   446     top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
   447     top.sp--;
   448     break;
   449 }
   450 
   451 case OP_MUL_F:
   452 {
   453     top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
   454     top.sp--;
   455     break;
   456 }
   457 
   458 case OP_DIV_F:
   459 {
   460     top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
   461     top.sp--;
   462     break;
   463 }
   464 
   465 case OP_LT_F:
   466 {
   467     top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
   468     top.sp--;
   469     break;
   470 }
   471 
   472 case OP_LE_F:
   473 {
   474     top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
   475     top.sp--;
   476     break;
   477 }
   478 
   479 case OP_GT_F:
   480 {
   481     top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
   482     top.sp--;
   483     break;
   484 }
   485 
   486 case OP_GE_F:
   487 {
   488     top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
   489     top.sp--;
   490     break;
   491 }
   492 
   493 case OP_EQ_F:
   494 {
   495     top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
   496     top.sp--;
   497     break;
   498 }
   499 
   500 case OP_NE_F:
   501 {
   502     top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
   503     top.sp--;
   504     break;
   505 }
   506 
   507 case OP_SHL:
   508 {
   509     top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
   510     top.sp--;
   511     break;
   512 }
   513 
   514 case OP_SHR:
   515 {
   516     top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
   517     top.sp--;
   518     break;
   519 }
   520 
   521 case OP_USHR:
   522 {
   523     top.sp[-2].i32 = unsigned(top.sp[-2].i32) << unsigned(top.sp[-1].i32);
   524     top.sp--;
   525     break;
   526 }
   527 
   528 case OP_BITAND:
   529 {
   530     top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
   531     top.sp--;
   532     break;
   533 }
   534 
   535 case OP_BITOR:
   536 {
   537     top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
   538     top.sp--;
   539     break;
   540 }
   541 
   542 case OP_BITXOR:
   543 {
   544     top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
   545     top.sp--;
   546     break;
   547 }
   548 
   549 case OP_BITNOT:
   550 {
   551     top.sp[-1].i32 = ~top.sp[-1].i32;
   552     break;
   553 }
   554 
   555 case OP_NOT:
   556 {
   557     top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
   558     break;
   559 }
   560 
   561 case OP_NOT_F:
   562 {
   563     top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
   564     break;
   565 }
   566 
   567 case OP_NEG:
   568 {
   569     top.sp[-1].i32 = -top.sp[-1].i32;
   570     break;
   571 }
   572 
   573 case OP_NEG_F:
   574 {
   575     top.sp[-1].f = -top.sp[-1].f;
   576     break;
   577 }
   578 
   579 case OP_CALL:
   580 {
   581     Local<Function> newFun(zone, top.sp[-1].fun);
   582     top.sp--;
   583 
   584     if (!zone->stack().pushInlineFrame(newFun))
   585         goto error;
   586 
   587     locals = top.fp->locals();
   588     continue;
   589 }
   590 
   591 case OP_GETARG:
   592 {
   593     unsigned slot = READ_UINT32(top.pc);
   594     *top.sp++ = top.fp->arg(slot);
   595     break;
   596 }
   597 
   598 case OP_SETARG:
   599 {
   600     unsigned slot = READ_UINT32(top.pc);
   601     top.fp->arg(slot) = *--top.sp;
   602     break;
   603 }
   604 
   605 case OP_BOUNDS:
   606 {
   607     Array *array = top.sp[-2].array;
   608     int index = top.sp[-1].i32;
   609     if (index < 0 || unsigned(index) >= array->nelements()) {
   610         zone->reportError(Message_ArrayIndexOutOfBounds, index, array->nelements());
   611         goto error;
   612     }
   613     break;
   614 }
   615 
   616 case OP_GETARRAY_I:
   617 {
   618     Array *array = top.sp[-2].array;
   619     int index = top.sp[-1].i32;
   620     top.sp[-2].i32 = array->readInt32(index);
   621     top.sp--;
   622     break;
   623 }
   624 
   625 case OP_GETARRAY_F:
   626 {
   627     Array *array = top.sp[-2].array;
   628     int index = top.sp[-1].i32;
   629     top.sp[-2].f = array->readFloat(index);
   630     top.sp--;
   631     break;
   632 }
   633 
   634 case OP_GETARRAY_C:
   635 {
   636     Array *array = top.sp[-2].array;
   637     int index = top.sp[-1].i32;
   638     top.sp[-2].i32 = array->readChar(index);
   639     top.sp--;
   640     break;
   641 }
   642 
   643 case OP_SETARRAY_I:
   644 {
   645     Array *array = top.sp[-3].array;
   646     int index = top.sp[-2].i32;
   647     array->writeInt32(index, top.sp[-1].i32);
   648     top.sp[-3] = top.sp[-1];
   649     top.sp -= 2;
   650     break;
   651 }
   652 
   653 case OP_SETARRAY_F:
   654 {
   655     Array *array = top.sp[-3].array;
   656     int index = top.sp[-2].i32;
   657     array->writeFloat(index, top.sp[-1].f);
   658     top.sp[-3] = top.sp[-1];
   659     top.sp -= 2;
   660     break;
   661 }
   662 
   663 case OP_SETARRAY_C:
   664 {
   665     Array *array = top.sp[-3].array;
   666     int index = top.sp[-2].i32;
   667     array->writeChar(index, top.sp[-1].i32);
   668     top.sp[-3] = top.sp[-1];
   669     top.sp -= 2;
   670     break;
   671 }
   672 
   673 case OP_GETARRAY_O:
   674 {
   675     Array *array = top.sp[-2].array;
   676     int index = top.sp[-1].i32;
   677     top.sp[-2].array = Array::cast(array->readObject(index));
   678     top.sp--;
   679     break;
   680 }
   681 
   682 case OP_CVT_I2F:
   683 {
   684     int ival = POP_I32(top);
   685     float fval = (float)ival;
   686     PUSH_F(top, fval);
   687     break;
   688 }
   689 
   690 case OP_NEWARRAY:
   691 {
   692     Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
   693     Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
   694     Array *array = GenerateArray(zone, map, tenure);
   695     if (!array)
   696         goto error;
   697     top.sp->obj = array;
   698     top.sp++;
   699     break;
   700 }
   701 
   702 case OP_SAVELIFO:
   703 {
   704     unsigned slot = READ_UINT32(top.pc);
   705     locals[slot].address = zone->heap().lifoPosition();
   706     break;
   707 }
   708 
   709 case OP_UNWINDLIFO:
   710 {
   711     unsigned slot = READ_UINT32(top.pc);
   712     zone->heap().unwindLifo(locals[slot].address);
   713     break;
   714 }
   715 
   716 case OP_VARREF_LIFO:
   717 {
   718     unsigned slot = READ_UINT32(top.pc);
   719     if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
   720         goto error;
   721     break;
   722 }
   723 
   724 case OP_ARGREF_LIFO:
   725 {
   726     unsigned slot = READ_UINT32(top.pc);
   727     if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
   728         goto error;
   729     break;
   730 }
   731 
   732 case OP_ARRAYREF_LIFO:
   733 {
   734     Local<Array> array(zone, top.sp[-2].array);
   735     Local<Reference> ref(zone, Reference::NewArray(zone, array, top.sp[-1].i32, Heap::Tenure_Stack));
   736     if (!ref)
   737         goto error;
   738     top.sp[-2].ref = ref;
   739     top.sp--;
   740     break;
   741 }
   742 
   743 case OP_SLOTREF_LIFO:
   744 {
   745     Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
   746     if (!ref)
   747         goto error;
   748     top.sp[-1].ref = ref;
   749     break;
   750 }
   751 
   752 case OP_GETREF_I:
   753 {
   754     top.sp[-1].i32 = top.sp[-1].ref->getInt();
   755     break;
   756 }
   757 
   758 case OP_SETREF_I:
   759 {
   760     top.sp[-2].ref->setInt(top.sp[-1].i32);
   761     top.sp[-2].i32 = top.sp[-1].i32;
   762     top.sp--;
   763     break;
   764 }
   765 
   766 case OP_GETREF_F:
   767 {
   768     top.sp[-1].f = top.sp[-1].ref->getFloat();
   769     break;
   770 }
   771 
   772 case OP_SETREF_F:
   773 {
   774     top.sp[-2].ref->setFloat(top.sp[-1].f);
   775     top.sp[-2].f = top.sp[-1].f;
   776     break;
   777 }
   778 
   779 case OP_OBJECT:
   780 {
   781     top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
   782     top.sp++;
   783     break;
   784 }
   785 
   786 case OP_ARRAYCOPY:
   787 {
   788     // Note for this assignment opcode, we return the left-hand side, not the
   789     // right, since in this case the result of the expression could be different.
   790     if (!CopyArray(zone, top.sp[-2].array, top.sp[-1].array))
   791         goto error;
   792     top.sp--;
   793     break;
   794 }
   795 
   796 case OP_DUP:
   797 {
   798     top.sp++;
   799     top.sp[-1] = top.sp[-2];
   800     break;
   801 }
   802 
   803 case OP_DUP2:
   804 {
   805     top.sp += 2;
   806     top.sp[-2] = top.sp[-4];
   807     top.sp[-1] = top.sp[-3];
   808     break;
   809 }
   810 
   811 case OP_SWAP:
   812 {
   813     LocalSlot slot = top.sp[-2];
   814     top.sp[-2] = top.sp[-1];
   815     top.sp[-1] = slot;
   816     break;
   817 }
   818 
   819 case OP_ROLL3:
   820 {
   821     LocalSlot slot = top.sp[-3];
   822     top.sp[-3] = top.sp[-2];
   823     top.sp[-2] = top.sp[-1];
   824     top.sp[-1] = slot;
   825     break;
   826 }
   827 
   828 case OP_PICK2:
   829 {
   830     top.sp++;
   831     top.sp[-1] = top.sp[-3];
   832     break;
   833 }
   834 
   835 case OP_PICK3:
   836 {
   837     top.sp++;
   838     top.sp[-1] = top.sp[-4];
   839     break;
   840 }
   841 
   842 case OP_CALLNATIVE:
   843 {
   844     unsigned index = READ_UINT32(top.pc);
   845     unsigned argc = READ_UINT32(top.pc + 4);
   846 
   847     Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
   848     if (!native->function()) {
   849         zone->reportError(Message_NativeNotBound, native->name()->chars());
   850         goto error;
   851     }
   852 
   853     int result;
   854     void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
   855     if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
   856         goto error;
   857 
   858     top.sp -= argc;
   859     PUSH_I32(top, result);
   860     break;
   861 }
   862 
   863 case OP_MODULE:
   864 {
   865     top.sp++;
   866     top.sp[-1].module = top.fp->code()->module();
   867     break;
   868 }
   869 
   870 case OP_GETMODULE_FN:
   871 {
   872     top.sp[-1].fun = top.sp[-1].module->getFunction(READ_UINT32(top.pc));
   873     break;
   874 }
   875 
   876 case OP_GETGLOBAL_I:
   877 {
   878     unsigned slot = READ_UINT32(top.pc);
   879     top.sp++;
   880     top.sp[-1].i32 = top.fp->code()->module()->environment()->getInt32(slot);
   881     break;
   882 }
   883 
   884 case OP_GETGLOBAL_F:
   885 {
   886     unsigned slot = READ_UINT32(top.pc);
   887     top.sp++;
   888     top.sp[-1].f = top.fp->code()->module()->environment()->getFloat(slot);
   889     break;
   890 }
   891 
   892 case OP_GETGLOBAL_O:
   893 {
   894     unsigned slot = READ_UINT32(top.pc);
   895     top.sp++;
   896     top.sp[-1].obj = top.fp->code()->module()->environment()->getObject(slot);
   897     break;
   898 }
   899 
   900 case OP_SETGLOBAL_I:
   901 {
   902     unsigned slot = READ_UINT32(top.pc);
   903     top.fp->code()->module()->environment()->setInt32(slot, top.sp[-1].i32);
   904     break;
   905 }
   906 
   907 case OP_SETGLOBAL_F:
   908 {
   909     unsigned slot = READ_UINT32(top.pc);
   910     top.fp->code()->module()->environment()->setFloat(slot, top.sp[-1].f);
   911     break;
   912 }
   913 
   914 case OP_SETGLOBAL_O:
   915 {
   916     unsigned slot = READ_UINT32(top.pc);
   917     top.fp->code()->module()->environment()->setObject(slot, top.sp[-1].obj);
   918     break;
   919 }
   920 
   921 default:
   922     assert(false);
   923     return false;
   924 
   925         }
   926 
   927         top.pc += OpcodeInfo[op].length;
   928     }
   929 
   930 done:
   931     return true;
   932 
   933 error:
   934     // Unwind frames until we can continue.
   935     while (top.fp != entryFrame)
   936         zone->stack().popInlineFrame();
   937     return false;
   938 }