src/Interpreter.cpp
author David Anderson <dvander@alliedmods.net>
Sun Sep 02 13:06:09 2012 -0700 (2012-09-02)
changeset 177 56f7e5b0243c
parent 174 e718b56aba78
child 178 9efe9a1456fd
permissions -rw-r--r--
Fix bug in bytecode resizing.
     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 "Structures.h"
    29 #include "Heap-inl.h"
    30 
    31 using namespace ke;
    32 
    33 #define PUSH_I32(top, value)    \
    34     do {                        \
    35         top.sp->i32 = value;    \
    36         top.sp++;               \
    37    } while (0)
    38 
    39 #define PUSH_F(top, value)      \
    40     do {                        \
    41         top.sp->f = value;      \
    42         top.sp++;               \
    43    } while (0)
    44 
    45 static inline int
    46 POP_I32(Top &top)
    47 {
    48     int value = top.sp[-1].i32;
    49     top.sp--;
    50     return value;
    51 }
    52 
    53 static inline float
    54 POP_F(Top &top)
    55 {
    56     float value = top.sp[-1].f;
    57     top.sp--;
    58     return value;
    59 }
    60 
    61 // Pawn's original semantics specify some kind of floor operation, so
    62 // (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses
    63 // the upstream algorithm when constant folding. However the SourcePawn 1 JIT
    64 // does not. My guess is that Borja freaked out seeing the 13-instruction x86
    65 // sequence necessary to get this functionality (I vaguely recall a thread
    66 // where we discussed this with Mark Peter? But the ITB forums are gone...),
    67 // and we just decided to break the damn thing. So SP1 was inconsistent, but
    68 // we are not. And for completeness, we assert that the C compiler does the
    69 // right thing, since C89 leaves it unspecified.
    70 STATIC_ASSERT(8 / -3 == -2);
    71 STATIC_ASSERT(-8 / 3 == -2);
    72 
    73 static inline bool
    74 PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
    75 {
    76     Reference *ref = Reference::NewStack(zone, location, tenure);
    77     if (!ref)
    78         return false;
    79     top.sp->ref = ref;
    80     top.sp++;
    81     return true;
    82 }
    83 
    84 static bool CopyStruct(Zone *zone, Struct *left, Struct *right);
    85 
    86 // Even though this function can fail, we immediately bail out, so it doesn't
    87 // matter if we've leaving things unrooted.
    88 static bool
    89 CopyArray(Zone *zone, Array *source, Array *dest)
    90 {
    91     if (source->type()->contained()->isArray()) {
    92         assert(dest->type()->contained()->isArray());
    93         assert(source->length() == dest->length());
    94 
    95         for (unsigned i = 0; i < source->length(); i++) {
    96             Array *left = Array::cast(source->readObject(i));
    97             Array *right = Array::cast(dest->readObject(i));
    98             if (!CopyArray(zone, left, right))
    99                 return false;
   100         }
   101     } else if (source->type()->contained()->isStruct()) {
   102         assert(dest->type()->contained() == source->type()->contained());
   103         assert(source->length() == dest->length());
   104 
   105         for (unsigned i = 0; i < source->length(); i++) {
   106             Struct *left = Struct::cast(source->readObject(i));
   107             Struct *right = Struct::cast(dest->readObject(i));
   108             if (!CopyStruct(zone, left, right))
   109                 return false;
   110         }
   111     } else {
   112         assert(source->type()->contained()->pod() == dest->type()->contained()->pod());
   113         assert(source->type()->contained()->pod() == PrimitiveType_Char
   114                ? source->length() >= dest->length()
   115                : source->length() == dest->length());
   116 
   117         memcpy(source->vec(), dest->vec(), dest->length() * dest->elementSize());
   118     }
   119     return true;
   120 }
   121 
   122 static void
   123 GetElement(Array *array, int index, LocalSlot *vp)
   124 {
   125     if (array->type()->contained()->isTraceable()) {
   126         vp->obj = array->readObject(index);
   127         return;
   128     }
   129 
   130     switch (array->type()->contained()->pod()) {
   131       case PrimitiveType_Float:
   132         vp->f = array->readFloat(index);
   133         break;
   134 
   135       case PrimitiveType_Char:
   136         vp->i32 = array->readChar(index);
   137         break;
   138 
   139       default:
   140         assert(array->type()->contained()->pod() == PrimitiveType_Int32);
   141         vp->i32 = array->readInt32(index);
   142         break;
   143     }
   144 }
   145 
   146 static void
   147 SetElement(Zone *zone, Array *array, int index, const LocalSlot &v)
   148 {
   149     if (array->type()->contained()->isTraceable()) {
   150         array->writeObject(zone, index, v.obj);
   151         return;
   152     }
   153 
   154     switch (array->type()->contained()->pod()) {
   155       case PrimitiveType_Float:
   156         array->writeFloat(index, v.f);
   157         break;
   158 
   159       case PrimitiveType_Char:
   160         array->writeChar(index, v.i32);
   161         break;
   162 
   163       default:
   164         assert(array->type()->contained()->pod() == PrimitiveType_Int32);
   165         array->writeInt32(index, v.i32);
   166         break;
   167     }
   168 }
   169 
   170 static void
   171 GetField(Struct *obj, Descriptor *desc, LocalSlot *vp)
   172 {
   173     // :TODO: assert no GC.
   174     if (desc->type()->isTraceable()) {
   175         vp->obj = obj->get<Object *>(desc);
   176         return;
   177     }
   178 
   179     switch (desc->type()->pod()) {
   180       case PrimitiveType_Float:
   181         vp->f = obj->get<float>(desc);
   182         break;
   183 
   184       default:
   185         assert(desc->type()->pod() == PrimitiveType_Int32);
   186         vp->i32 = obj->get<int>(desc);
   187         break;
   188     }
   189 }
   190 
   191 static void
   192 GetField(Struct *obj, unsigned index, LocalSlot *vp)
   193 {
   194     Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
   195     GetField(obj, desc, vp);
   196 }
   197 
   198 static void
   199 SetField(Zone *zone, Struct *obj, Descriptor *desc, const LocalSlot &v)
   200 {
   201     // :TODO: assert no GC.
   202     if (desc->type()->isTraceable()) {
   203         obj->set(zone, desc, v.obj);
   204         return;
   205     }
   206 
   207     switch (desc->type()->pod()) {
   208       case PrimitiveType_Float:
   209         obj->set<float>(desc, v.f);
   210         break;
   211 
   212       default:
   213         assert(desc->type()->pod() == PrimitiveType_Int32);
   214         obj->set<int>(desc, v.i32);
   215         break;
   216     }
   217 }
   218 
   219 static void
   220 SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
   221 {
   222     Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
   223     SetField(zone, obj, desc, v);
   224 }
   225 
   226 // Even though this function can fail, we immediately bail out, so it doesn't
   227 // matter if we've leaving things unrooted.
   228 static bool
   229 CopyStruct(Zone *zone, Struct *left, Struct *right)
   230 {
   231     assert(left->map()->type() == right->map()->type());
   232 
   233     Type *type = left->map()->type();
   234     for (unsigned i = 0; i < type->fields()->length(); i++) {
   235         Descriptor *desc = Descriptor::cast(type->fields()->at(i));
   236 
   237         LocalSlot rval;
   238         GetField(right, desc, &rval);
   239 
   240         // If the field is a struct, we need to deep-copy.
   241         if (desc->type()->isStruct()) {
   242             LocalSlot lval;
   243 
   244             GetField(left, desc, &lval);
   245             if (!CopyStruct(zone, Struct::cast(lval.obj), Struct::cast(rval.obj)))
   246                 return false;
   247         } else if (desc->type()->isArray()) {
   248             LocalSlot lval;
   249 
   250             GetField(left, desc, &lval);
   251             if (!CopyArray(zone, Array::cast(lval.obj), Array::cast(rval.obj)))
   252                 return false;
   253         } else {
   254             SetField(zone, left, desc, rval);
   255         }
   256     }
   257 
   258     return true;
   259 }
   260 
   261 static bool
   262 InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
   263              int *result)
   264 {
   265     NativeArgs guard;
   266 
   267     if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
   268         return false;
   269 
   270     intptr_t *cells = guard.args();
   271 
   272     // params[0] == argc, in ISPE
   273     cells[0] = argc;
   274 
   275     // Pass the formal arguments.
   276     Local<Type> type(zone, native->type());
   277     Local<Type> param(zone);
   278     for (unsigned i = 0; i < type->parameters()->length(); i++) {
   279         param = type->parameterAt(i);
   280         
   281         // For floats, we rely on the aliasing of |i32| and |f|.
   282         LocalSlot &arg = args[-int(i) - 1];
   283         if (param->isInt32() || param->isFloat()) {
   284             cells[i + 1] = arg.i32;
   285         } else if (param->isReference()) {
   286             cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
   287         } else {
   288             assert(param->isArray());
   289             cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
   290         }
   291     }
   292 
   293     // For variadic arguments, the compiler left either arrays or references.
   294     for (unsigned i = type->parameters()->length(); i < argc; i++) {
   295         LocalSlot &arg = args[-int(i) - 1];
   296 
   297         if (arg.obj->is(MapKind_Reference)) {
   298             cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
   299         } else {
   300             assert(arg.obj->is(MapKind_Array));
   301             cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
   302         }
   303     }
   304 
   305     typedef intptr_t (*INVOKE)(void *, intptr_t *);
   306     INVOKE invoke = (INVOKE)native->function();
   307     *result = invoke(identity, cells);
   308 
   309     return !zone->hasPendingException();
   310 }
   311 
   312 bool
   313 ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
   314 {
   315     Top &top = *zone->stack().top();
   316     if (!entryFrame)
   317         entryFrame = top.fp;
   318 
   319     LocalSlot *locals = entryFrame->locals();
   320 
   321     for (;;) {
   322         Opcode op = Opcode(*top.pc);
   323 
   324         if (OpcodeInfo[op].nuses > 0)
   325             assert(top.sp - OpcodeInfo[op].nuses >= top.fp->stackBase());
   326 
   327         switch (op) {
   328 
   329 case OP_NOP:
   330     break;
   331 
   332 case OP_INT:
   333     PUSH_I32(top, READ_INT32(top.pc));
   334     break;
   335 
   336 case OP_FLOAT:
   337     PUSH_F(top, READ_FLOAT(top.pc));
   338     break;
   339 
   340 case OP_RETURN:
   341 case OP_RETURNVOID:
   342 case OP_STOP:
   343 {
   344     if (op == OP_RETURN)
   345         *result = *--top.sp;
   346 
   347     if (top.fp == entryFrame)
   348         goto done;
   349 
   350     // This must not GC.
   351     zone->stack().popInlineFrame();
   352     locals = top.fp->locals();
   353 
   354     if (op == OP_RETURN)
   355         *top.sp++ = *result;
   356 
   357     top.pc += OpcodeInfo[*top.pc].length;
   358     continue;
   359 }
   360 
   361 case OP_POP:
   362 {
   363     top.sp--;
   364     break;
   365 }
   366 
   367 #define RELATIONAL_JUMP(op)                 \
   368     {                                       \
   369         int right = POP_I32(top);           \
   370         int left = POP_I32(top);            \
   371         if (left op right) {                \
   372             top.pc += READ_INT32(top.pc);   \
   373             continue;                       \
   374         }                                   \
   375     }
   376 
   377 case OP_JL:
   378     RELATIONAL_JUMP(<);
   379     break;
   380 
   381 case OP_JLE:
   382     RELATIONAL_JUMP(<=);
   383     break;
   384 
   385 case OP_JG:
   386     RELATIONAL_JUMP(>);
   387     break;
   388 
   389 case OP_JGE:
   390     RELATIONAL_JUMP(>=);
   391     break;
   392 
   393 case OP_JEQ:
   394     RELATIONAL_JUMP(==);
   395     break;
   396 
   397 case OP_JNE:
   398     RELATIONAL_JUMP(!=);
   399     break;
   400 
   401 #undef RELATIONAL_JUMP
   402 
   403 case OP_JT:
   404 {
   405     int value = POP_I32(top);
   406     if (value) {
   407         top.pc += READ_INT32(top.pc);
   408         continue;
   409     }
   410     break;
   411 }
   412 
   413 case OP_JF:
   414 {
   415     int value = POP_I32(top);
   416     if (!value) {
   417         top.pc += READ_INT32(top.pc);
   418         continue;
   419     }
   420     break;
   421 }
   422 
   423 #define RELATIONAL_JUMP_F(op)               \
   424     {                                       \
   425         float right = POP_F(top);           \
   426         float left = POP_F(top);            \
   427         if (left op right) {                \
   428             top.pc += READ_INT32(top.pc);   \
   429             continue;                       \
   430         }                                   \
   431     }
   432 
   433 case OP_JL_F:
   434     RELATIONAL_JUMP_F(<);
   435     break;
   436 
   437 case OP_JLE_F:
   438     RELATIONAL_JUMP_F(<=);
   439     break;
   440 
   441 case OP_JG_F:
   442     RELATIONAL_JUMP_F(>);
   443     break;
   444 
   445 case OP_JGE_F:
   446     RELATIONAL_JUMP_F(>=);
   447     break;
   448 
   449 case OP_JEQ_F:
   450     RELATIONAL_JUMP_F(==);
   451     break;
   452 
   453 case OP_JNE_F:
   454     RELATIONAL_JUMP_F(!=);
   455     break;
   456 
   457 case OP_JT_F:
   458 {
   459     float value = POP_F(top);
   460     if (value) {
   461         top.pc += READ_INT32(top.pc);
   462         continue;
   463     }
   464     break;
   465 }
   466 
   467 case OP_JF_F:
   468 {
   469     float value = POP_F(top);
   470     if (!value) {
   471         top.pc += READ_INT32(top.pc);
   472         continue;
   473     }
   474     break;
   475 }
   476 
   477 case OP_JUMP:
   478     top.pc += READ_INT32(top.pc);
   479     continue;
   480 
   481 case OP_GETLOCAL:
   482 {
   483     int slot = READ_INT32(top.pc);
   484     *top.sp++ = locals[slot];
   485     break;
   486 }
   487 
   488 case OP_SETLOCAL:
   489 {
   490     int slot = READ_INT32(top.pc);
   491     locals[slot] = top.sp[-1];
   492     break;
   493 }
   494 
   495 case OP_ADD:
   496 {
   497     top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
   498     top.sp--;
   499     break;
   500 }
   501 
   502 case OP_SUB:
   503 {
   504     top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
   505     top.sp--;
   506     break;
   507 }
   508 
   509 case OP_MUL:
   510 {
   511     top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
   512     top.sp--;
   513     break;
   514 }
   515 
   516 case OP_DIV:
   517 {
   518     if (top.sp[-1].i32 == 0) {
   519         zone->reportError(Message_IntegerDivideByZero);
   520         goto error;
   521     }
   522     top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
   523     top.sp--;
   524     break;
   525 }
   526 
   527 case OP_MOD:
   528 {
   529     if (top.sp[-1].i32 == 0) {
   530         zone->reportError(Message_IntegerDivideByZero);
   531         goto error;
   532     }
   533     top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
   534     top.sp--;
   535     break;
   536 }
   537 
   538 case OP_LT:
   539 {
   540     top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
   541     top.sp--;
   542     break;
   543 }
   544 
   545 case OP_LE:
   546 {
   547     top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
   548     top.sp--;
   549     break;
   550 }
   551 
   552 case OP_GT:
   553 {
   554     top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
   555     top.sp--;
   556     break;
   557 }
   558 
   559 case OP_GE:
   560 {
   561     top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
   562     top.sp--;
   563     break;
   564 }
   565 
   566 case OP_EQ:
   567 {
   568     top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
   569     top.sp--;
   570     break;
   571 }
   572 
   573 case OP_NE:
   574 {
   575     top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
   576     top.sp--;
   577     break;
   578 }
   579 
   580 case OP_ADD_F:
   581 {
   582     top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
   583     top.sp--;
   584     break;
   585 }
   586 
   587 case OP_SUB_F:
   588 {
   589     top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
   590     top.sp--;
   591     break;
   592 }
   593 
   594 case OP_MUL_F:
   595 {
   596     top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
   597     top.sp--;
   598     break;
   599 }
   600 
   601 case OP_DIV_F:
   602 {
   603     top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
   604     top.sp--;
   605     break;
   606 }
   607 
   608 case OP_LT_F:
   609 {
   610     top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
   611     top.sp--;
   612     break;
   613 }
   614 
   615 case OP_LE_F:
   616 {
   617     top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
   618     top.sp--;
   619     break;
   620 }
   621 
   622 case OP_GT_F:
   623 {
   624     top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
   625     top.sp--;
   626     break;
   627 }
   628 
   629 case OP_GE_F:
   630 {
   631     top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
   632     top.sp--;
   633     break;
   634 }
   635 
   636 case OP_EQ_F:
   637 {
   638     top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
   639     top.sp--;
   640     break;
   641 }
   642 
   643 case OP_NE_F:
   644 {
   645     top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
   646     top.sp--;
   647     break;
   648 }
   649 
   650 case OP_SHL:
   651 {
   652     top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
   653     top.sp--;
   654     break;
   655 }
   656 
   657 case OP_SHR:
   658 {
   659     top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
   660     top.sp--;
   661     break;
   662 }
   663 
   664 case OP_USHR:
   665 {
   666     top.sp[-2].i32 = unsigned(top.sp[-2].i32) << unsigned(top.sp[-1].i32);
   667     top.sp--;
   668     break;
   669 }
   670 
   671 case OP_BITAND:
   672 {
   673     top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
   674     top.sp--;
   675     break;
   676 }
   677 
   678 case OP_BITOR:
   679 {
   680     top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
   681     top.sp--;
   682     break;
   683 }
   684 
   685 case OP_BITXOR:
   686 {
   687     top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
   688     top.sp--;
   689     break;
   690 }
   691 
   692 case OP_BITNOT:
   693 {
   694     top.sp[-1].i32 = ~top.sp[-1].i32;
   695     break;
   696 }
   697 
   698 case OP_NOT:
   699 {
   700     top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
   701     break;
   702 }
   703 
   704 case OP_NOT_F:
   705 {
   706     top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
   707     break;
   708 }
   709 
   710 case OP_NEG:
   711 {
   712     top.sp[-1].i32 = -top.sp[-1].i32;
   713     break;
   714 }
   715 
   716 case OP_NEG_F:
   717 {
   718     top.sp[-1].f = -top.sp[-1].f;
   719     break;
   720 }
   721 
   722 case OP_CALL:
   723 {
   724     Local<Function> newFun(zone, top.sp[-1].fun);
   725     top.sp--;
   726 
   727     if (!zone->stack().pushInlineFrame(newFun))
   728         goto error;
   729 
   730     locals = top.fp->locals();
   731     continue;
   732 }
   733 
   734 case OP_GETARG:
   735 {
   736     unsigned slot = READ_UINT32(top.pc);
   737     *top.sp++ = top.fp->arg(slot);
   738     break;
   739 }
   740 
   741 case OP_SETARG:
   742 {
   743     unsigned slot = READ_UINT32(top.pc);
   744     top.fp->arg(slot) = top.sp[-1];
   745     break;
   746 }
   747 
   748 case OP_GETELEM:
   749 {
   750     Array *array = Array::cast(top.sp[-2].obj);
   751     int index = top.sp[-1].i32;
   752 
   753     if (index < 0 || unsigned(index) >= array->length()) {
   754         zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
   755         goto error;
   756     }
   757 
   758     GetElement(array, index, &top.sp[-2]);
   759     top.sp--;
   760     break;
   761 }
   762 
   763 case OP_SETELEM:
   764 {
   765     Array *array = Array::cast(top.sp[-3].obj);
   766     int index = top.sp[-2].i32;
   767 
   768     if (index < 0 || unsigned(index) >= array->length()) {
   769         zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
   770         goto error;
   771     }
   772 
   773     SetElement(zone, array, index, top.sp[-1]);
   774     top.sp[-3] = top.sp[-1];
   775     top.sp -= 2;
   776     break;
   777 }
   778 
   779 case OP_CVT_I2F:
   780 {
   781     int ival = POP_I32(top);
   782     float fval = (float)ival;
   783     PUSH_F(top, fval);
   784     break;
   785 }
   786 
   787 case OP_NEWARRAY:
   788 {
   789     Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
   790     Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
   791     Array *array = Array::New(zone, map, map->type()->elements(), tenure);
   792     if (!array)
   793         goto error;
   794     top.sp->obj = array;
   795     top.sp++;
   796     break;
   797 }
   798 
   799 case OP_NEWSTRUCT:
   800 {
   801     Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
   802     Local<StructMap> map(zone, StructMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
   803     top.sp->obj = Struct::New(zone, map, tenure);
   804     if (!top.sp->obj)
   805         goto error;
   806     top.sp++;
   807     break;
   808 }
   809 
   810 case OP_SAVELIFO:
   811 {
   812     unsigned slot = READ_UINT32(top.pc);
   813     locals[slot].address = zone->heap().lifoPosition();
   814     break;
   815 }
   816 
   817 case OP_UNWINDLIFO:
   818 {
   819     unsigned slot = READ_UINT32(top.pc);
   820     zone->heap().unwindLifo(locals[slot].address);
   821     break;
   822 }
   823 
   824 case OP_VARREF_LIFO:
   825 {
   826     unsigned slot = READ_UINT32(top.pc);
   827     if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
   828         goto error;
   829     break;
   830 }
   831 
   832 case OP_ARGREF_LIFO:
   833 {
   834     unsigned slot = READ_UINT32(top.pc);
   835     if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
   836         goto error;
   837     break;
   838 }
   839 
   840 case OP_ARRAYREF_LIFO:
   841 {
   842     Local<Array> array(zone, Array::cast(top.sp[-2].obj));
   843     Local<Reference> ref(zone, Reference::NewArray(zone, array, top.sp[-1].i32, Heap::Tenure_Stack));
   844     if (!ref)
   845         goto error;
   846     top.sp[-2].ref = ref;
   847     top.sp--;
   848     break;
   849 }
   850 
   851 case OP_SLOTREF_LIFO:
   852 {
   853     Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
   854     if (!ref)
   855         goto error;
   856     top.sp[-1].ref = ref;
   857     break;
   858 }
   859 
   860 case OP_FIELDREF_LIFO:
   861 {
   862     Local<Struct> obj(zone, Struct::cast(top.sp[-1].obj));
   863     top.sp[-1].obj = Reference::NewField(zone, obj, READ_UINT32(top.pc), Heap::Tenure_Stack);
   864     if (!top.sp[-1].obj)
   865         goto error;
   866     break;
   867 }
   868 
   869 case OP_GETREF_I:
   870 {
   871     top.sp[-1].i32 = top.sp[-1].ref->getInt();
   872     break;
   873 }
   874 
   875 case OP_SETREF_I:
   876 {
   877     top.sp[-2].ref->setInt(top.sp[-1].i32);
   878     top.sp[-2].i32 = top.sp[-1].i32;
   879     top.sp--;
   880     break;
   881 }
   882 
   883 case OP_GETREF_F:
   884 {
   885     top.sp[-1].f = top.sp[-1].ref->getFloat();
   886     break;
   887 }
   888 
   889 case OP_SETREF_F:
   890 {
   891     top.sp[-2].ref->setFloat(top.sp[-1].f);
   892     top.sp[-2].f = top.sp[-1].f;
   893     break;
   894 }
   895 
   896 case OP_OBJECT:
   897 {
   898     top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
   899     top.sp++;
   900     break;
   901 }
   902 
   903 case OP_COPYARRAY:
   904 {
   905     // Note for this assignment opcode, we return the left-hand side, not the
   906     // right, since in this case the result of the expression could be different.
   907     if (!CopyArray(zone, top.sp[-2].array, top.sp[-1].array))
   908         goto error;
   909     top.sp--;
   910     break;
   911 }
   912 
   913 case OP_DUP:
   914 {
   915     top.sp++;
   916     top.sp[-1] = top.sp[-2];
   917     break;
   918 }
   919 
   920 case OP_DUP2:
   921 {
   922     top.sp += 2;
   923     top.sp[-2] = top.sp[-4];
   924     top.sp[-1] = top.sp[-3];
   925     break;
   926 }
   927 
   928 case OP_SWAP:
   929 {
   930     LocalSlot slot = top.sp[-2];
   931     top.sp[-2] = top.sp[-1];
   932     top.sp[-1] = slot;
   933     break;
   934 }
   935 
   936 case OP_ROLL3:
   937 {
   938     LocalSlot slot = top.sp[-3];
   939     top.sp[-3] = top.sp[-2];
   940     top.sp[-2] = top.sp[-1];
   941     top.sp[-1] = slot;
   942     break;
   943 }
   944 
   945 case OP_PICK2:
   946 {
   947     top.sp++;
   948     top.sp[-1] = top.sp[-3];
   949     break;
   950 }
   951 
   952 case OP_PICK3:
   953 {
   954     top.sp++;
   955     top.sp[-1] = top.sp[-4];
   956     break;
   957 }
   958 
   959 case OP_CALLNATIVE:
   960 {
   961     unsigned index = READ_UINT32(top.pc);
   962     unsigned argc = READ_UINT32(top.pc + 4);
   963 
   964     Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
   965     if (!native->function()) {
   966         zone->reportError(Message_NativeNotBound, native->name()->chars());
   967         goto error;
   968     }
   969 
   970     int result;
   971     void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
   972     if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
   973         goto error;
   974 
   975     top.sp -= argc;
   976     PUSH_I32(top, result);
   977     break;
   978 }
   979 
   980 case OP_MODULE:
   981 {
   982     top.sp++;
   983     top.sp[-1].module = top.fp->code()->module();
   984     break;
   985 }
   986 
   987 case OP_GETMODULE_FN:
   988 {
   989     top.sp[-1].fun = top.sp[-1].module->getFunction(READ_UINT32(top.pc));
   990     break;
   991 }
   992 
   993 case OP_GETGLOBAL_I:
   994 {
   995     unsigned slot = READ_UINT32(top.pc);
   996     top.sp++;
   997     top.sp[-1].i32 = top.fp->code()->module()->environment()->getInt32(slot);
   998     break;
   999 }
  1000 
  1001 case OP_GETGLOBAL_F:
  1002 {
  1003     unsigned slot = READ_UINT32(top.pc);
  1004     top.sp++;
  1005     top.sp[-1].f = top.fp->code()->module()->environment()->getFloat(slot);
  1006     break;
  1007 }
  1008 
  1009 case OP_GETGLOBAL_O:
  1010 {
  1011     unsigned slot = READ_UINT32(top.pc);
  1012     top.sp++;
  1013     top.sp[-1].obj = top.fp->code()->module()->environment()->getObject(slot);
  1014     break;
  1015 }
  1016 
  1017 case OP_SETGLOBAL_I:
  1018 {
  1019     unsigned slot = READ_UINT32(top.pc);
  1020     top.fp->code()->module()->environment()->setInt32(slot, top.sp[-1].i32);
  1021     break;
  1022 }
  1023 
  1024 case OP_SETGLOBAL_F:
  1025 {
  1026     unsigned slot = READ_UINT32(top.pc);
  1027     top.fp->code()->module()->environment()->setFloat(slot, top.sp[-1].f);
  1028     break;
  1029 }
  1030 
  1031 case OP_SETGLOBAL_O:
  1032 {
  1033     unsigned slot = READ_UINT32(top.pc);
  1034     top.fp->code()->module()->environment()->setObject(slot, top.sp[-1].obj);
  1035     break;
  1036 }
  1037 
  1038 case OP_BITS_I2F:
  1039 case OP_BITS_F2I:
  1040 {
  1041     // Because the stack is a union, these are actually no-ops in the
  1042     // interpreter.
  1043     break;
  1044 }
  1045 
  1046 case OP_TRUE:
  1047 {
  1048     top.sp++;
  1049     top.sp[-1].i32 = 1;
  1050     break;
  1051 }
  1052 
  1053 case OP_FALSE:
  1054 {
  1055     top.sp++;
  1056     top.sp[-1].i32 = 0;
  1057     break;
  1058 }
  1059 
  1060 case OP_GETFIELD:
  1061 {
  1062     Struct *obj = Struct::cast(top.sp[-1].obj);
  1063     GetField(obj, READ_UINT32(top.pc), &top.sp[-1]);
  1064     break;
  1065 }
  1066 
  1067 case OP_SETFIELD:
  1068 {
  1069     Struct *obj = Struct::cast(top.sp[-2].obj);
  1070     SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]);
  1071     top.sp[-2] = top.sp[-1];
  1072     top.sp--;
  1073     break;
  1074 }
  1075 
  1076 case OP_COPYSTRUCT:
  1077 {
  1078     if (!CopyStruct(zone, Struct::cast(top.sp[-2].obj), Struct::cast(top.sp[-1].obj)))
  1079         goto error;
  1080     top.sp[-2].obj = top.sp[-1].obj;
  1081     top.sp--;
  1082     break;
  1083 }
  1084 
  1085 case OP_TABLESWITCH:
  1086 {
  1087     int value = top.sp[-1].i32;
  1088     int low = READ_TABLESWITCH_LOW(top.pc);
  1089     int high = READ_TABLESWITCH_HIGH(top.pc);
  1090 
  1091     top.sp--;
  1092 
  1093     unsigned index = unsigned(value - low);
  1094     unsigned tablesize = TableSwitchEntries(low, high);
  1095     if (index < tablesize) {
  1096         top.pc += OP_TABLESWITCH_LENGTH + OP_JUMP_LENGTH;
  1097         top.pc += index * OP_JUMP_LENGTH;
  1098         continue;
  1099     }
  1100     break;
  1101 }
  1102 
  1103 default:
  1104     assert(false);
  1105     return false;
  1106 
  1107         }
  1108 
  1109         top.pc += OpcodeInfo[op].length;
  1110         assert(top.sp >= top.fp->stackBase());
  1111     }
  1112 
  1113 done:
  1114     return true;
  1115 
  1116 error:
  1117     // Unwind frames until we can continue.
  1118     while (top.fp != entryFrame)
  1119         zone->stack().popInlineFrame();
  1120     return false;
  1121 }