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