src/Interpreter.cpp
author David Anderson <dvander@alliedmods.net>
Sat Aug 11 12:11:39 2012 -0700 (2012-08-11)
changeset 170 5e4570966ece
parent 164 3bf7c007883d
child 172 48cffae8c9e0
permissions -rw-r--r--
Parser support for public variables.
     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         switch (op) {
   324 
   325 case OP_NOP:
   326     break;
   327 
   328 case OP_INT:
   329     PUSH_I32(top, READ_INT32(top.pc));
   330     break;
   331 
   332 case OP_FLOAT:
   333     PUSH_F(top, READ_FLOAT(top.pc));
   334     break;
   335 
   336 case OP_RETURN:
   337 case OP_RETURNVOID:
   338 case OP_STOP:
   339 {
   340     if (op == OP_RETURN)
   341         *result = *--top.sp;
   342 
   343     if (top.fp == entryFrame)
   344         goto done;
   345 
   346     // This must not GC.
   347     zone->stack().popInlineFrame();
   348     locals = top.fp->locals();
   349 
   350     if (op == OP_RETURN)
   351         *top.sp++ = *result;
   352 
   353     top.pc += OpcodeInfo[*top.pc].length;
   354     continue;
   355 }
   356 
   357 case OP_POP:
   358 {
   359     top.sp--;
   360     break;
   361 }
   362 
   363 #define RELATIONAL_JUMP(op)                 \
   364     {                                       \
   365         int right = POP_I32(top);           \
   366         int left = POP_I32(top);            \
   367         if (left op right) {                \
   368             top.pc += READ_INT32(top.pc);   \
   369             continue;                       \
   370         }                                   \
   371     }
   372 
   373 case OP_JL:
   374     RELATIONAL_JUMP(<);
   375     break;
   376 
   377 case OP_JLE:
   378     RELATIONAL_JUMP(<=);
   379     break;
   380 
   381 case OP_JG:
   382     RELATIONAL_JUMP(>);
   383     break;
   384 
   385 case OP_JGE:
   386     RELATIONAL_JUMP(>=);
   387     break;
   388 
   389 case OP_JEQ:
   390     RELATIONAL_JUMP(==);
   391     break;
   392 
   393 case OP_JNE:
   394     RELATIONAL_JUMP(!=);
   395     break;
   396 
   397 #undef RELATIONAL_JUMP
   398 
   399 case OP_JT:
   400 {
   401     int value = POP_I32(top);
   402     if (value) {
   403         top.pc += READ_INT32(top.pc);
   404         continue;
   405     }
   406     break;
   407 }
   408 
   409 case OP_JF:
   410 {
   411     int value = POP_I32(top);
   412     if (!value) {
   413         top.pc += READ_INT32(top.pc);
   414         continue;
   415     }
   416     break;
   417 }
   418 
   419 #define RELATIONAL_JUMP_F(op)               \
   420     {                                       \
   421         float right = POP_F(top);           \
   422         float left = POP_F(top);            \
   423         if (left op right) {                \
   424             top.pc += READ_INT32(top.pc);   \
   425             continue;                       \
   426         }                                   \
   427     }
   428 
   429 case OP_JL_F:
   430     RELATIONAL_JUMP_F(<);
   431     break;
   432 
   433 case OP_JLE_F:
   434     RELATIONAL_JUMP_F(<=);
   435     break;
   436 
   437 case OP_JG_F:
   438     RELATIONAL_JUMP_F(>);
   439     break;
   440 
   441 case OP_JGE_F:
   442     RELATIONAL_JUMP_F(>=);
   443     break;
   444 
   445 case OP_JEQ_F:
   446     RELATIONAL_JUMP_F(==);
   447     break;
   448 
   449 case OP_JNE_F:
   450     RELATIONAL_JUMP_F(!=);
   451     break;
   452 
   453 case OP_JT_F:
   454 {
   455     float value = POP_F(top);
   456     if (value) {
   457         top.pc += READ_INT32(top.pc);
   458         continue;
   459     }
   460     break;
   461 }
   462 
   463 case OP_JF_F:
   464 {
   465     float value = POP_F(top);
   466     if (!value) {
   467         top.pc += READ_INT32(top.pc);
   468         continue;
   469     }
   470     break;
   471 }
   472 
   473 case OP_JUMP:
   474     top.pc += READ_INT32(top.pc);
   475     continue;
   476 
   477 case OP_GETLOCAL:
   478 {
   479     int slot = READ_INT32(top.pc);
   480     *top.sp++ = locals[slot];
   481     break;
   482 }
   483 
   484 case OP_SETLOCAL:
   485 {
   486     int slot = READ_INT32(top.pc);
   487     locals[slot] = top.sp[-1];
   488     break;
   489 }
   490 
   491 case OP_ADD:
   492 {
   493     top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
   494     top.sp--;
   495     break;
   496 }
   497 
   498 case OP_SUB:
   499 {
   500     top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
   501     top.sp--;
   502     break;
   503 }
   504 
   505 case OP_MUL:
   506 {
   507     top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
   508     top.sp--;
   509     break;
   510 }
   511 
   512 case OP_DIV:
   513 {
   514     if (top.sp[-1].i32 == 0) {
   515         zone->reportError(Message_IntegerDivideByZero);
   516         goto error;
   517     }
   518     top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
   519     top.sp--;
   520     break;
   521 }
   522 
   523 case OP_MOD:
   524 {
   525     if (top.sp[-1].i32 == 0) {
   526         zone->reportError(Message_IntegerDivideByZero);
   527         goto error;
   528     }
   529     top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
   530     top.sp--;
   531     break;
   532 }
   533 
   534 case OP_LT:
   535 {
   536     top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
   537     top.sp--;
   538     break;
   539 }
   540 
   541 case OP_LE:
   542 {
   543     top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
   544     top.sp--;
   545     break;
   546 }
   547 
   548 case OP_GT:
   549 {
   550     top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
   551     top.sp--;
   552     break;
   553 }
   554 
   555 case OP_GE:
   556 {
   557     top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
   558     top.sp--;
   559     break;
   560 }
   561 
   562 case OP_EQ:
   563 {
   564     top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
   565     top.sp--;
   566     break;
   567 }
   568 
   569 case OP_NE:
   570 {
   571     top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
   572     top.sp--;
   573     break;
   574 }
   575 
   576 case OP_ADD_F:
   577 {
   578     top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
   579     top.sp--;
   580     break;
   581 }
   582 
   583 case OP_SUB_F:
   584 {
   585     top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
   586     top.sp--;
   587     break;
   588 }
   589 
   590 case OP_MUL_F:
   591 {
   592     top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
   593     top.sp--;
   594     break;
   595 }
   596 
   597 case OP_DIV_F:
   598 {
   599     top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
   600     top.sp--;
   601     break;
   602 }
   603 
   604 case OP_LT_F:
   605 {
   606     top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
   607     top.sp--;
   608     break;
   609 }
   610 
   611 case OP_LE_F:
   612 {
   613     top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
   614     top.sp--;
   615     break;
   616 }
   617 
   618 case OP_GT_F:
   619 {
   620     top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
   621     top.sp--;
   622     break;
   623 }
   624 
   625 case OP_GE_F:
   626 {
   627     top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
   628     top.sp--;
   629     break;
   630 }
   631 
   632 case OP_EQ_F:
   633 {
   634     top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
   635     top.sp--;
   636     break;
   637 }
   638 
   639 case OP_NE_F:
   640 {
   641     top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
   642     top.sp--;
   643     break;
   644 }
   645 
   646 case OP_SHL:
   647 {
   648     top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
   649     top.sp--;
   650     break;
   651 }
   652 
   653 case OP_SHR:
   654 {
   655     top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
   656     top.sp--;
   657     break;
   658 }
   659 
   660 case OP_USHR:
   661 {
   662     top.sp[-2].i32 = unsigned(top.sp[-2].i32) << unsigned(top.sp[-1].i32);
   663     top.sp--;
   664     break;
   665 }
   666 
   667 case OP_BITAND:
   668 {
   669     top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
   670     top.sp--;
   671     break;
   672 }
   673 
   674 case OP_BITOR:
   675 {
   676     top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
   677     top.sp--;
   678     break;
   679 }
   680 
   681 case OP_BITXOR:
   682 {
   683     top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
   684     top.sp--;
   685     break;
   686 }
   687 
   688 case OP_BITNOT:
   689 {
   690     top.sp[-1].i32 = ~top.sp[-1].i32;
   691     break;
   692 }
   693 
   694 case OP_NOT:
   695 {
   696     top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
   697     break;
   698 }
   699 
   700 case OP_NOT_F:
   701 {
   702     top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
   703     break;
   704 }
   705 
   706 case OP_NEG:
   707 {
   708     top.sp[-1].i32 = -top.sp[-1].i32;
   709     break;
   710 }
   711 
   712 case OP_NEG_F:
   713 {
   714     top.sp[-1].f = -top.sp[-1].f;
   715     break;
   716 }
   717 
   718 case OP_CALL:
   719 {
   720     Local<Function> newFun(zone, top.sp[-1].fun);
   721     top.sp--;
   722 
   723     if (!zone->stack().pushInlineFrame(newFun))
   724         goto error;
   725 
   726     locals = top.fp->locals();
   727     continue;
   728 }
   729 
   730 case OP_GETARG:
   731 {
   732     unsigned slot = READ_UINT32(top.pc);
   733     *top.sp++ = top.fp->arg(slot);
   734     break;
   735 }
   736 
   737 case OP_SETARG:
   738 {
   739     unsigned slot = READ_UINT32(top.pc);
   740     top.fp->arg(slot) = *--top.sp;
   741     break;
   742 }
   743 
   744 case OP_GETELEM:
   745 {
   746     Array *array = Array::cast(top.sp[-2].obj);
   747     int index = top.sp[-1].i32;
   748 
   749     if (index < 0 || unsigned(index) >= array->length()) {
   750         zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
   751         goto error;
   752     }
   753 
   754     GetElement(array, index, &top.sp[-2]);
   755     top.sp--;
   756     break;
   757 }
   758 
   759 case OP_SETELEM:
   760 {
   761     Array *array = Array::cast(top.sp[-3].obj);
   762     int index = top.sp[-2].i32;
   763 
   764     if (index < 0 || unsigned(index) >= array->length()) {
   765         zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
   766         goto error;
   767     }
   768 
   769     SetElement(zone, array, index, top.sp[-1]);
   770     top.sp[-3] = top.sp[-1];
   771     top.sp -= 2;
   772     break;
   773 }
   774 
   775 case OP_CVT_I2F:
   776 {
   777     int ival = POP_I32(top);
   778     float fval = (float)ival;
   779     PUSH_F(top, fval);
   780     break;
   781 }
   782 
   783 case OP_NEWARRAY:
   784 {
   785     Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
   786     Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
   787     Array *array = Array::New(zone, map, map->type()->elements(), tenure);
   788     if (!array)
   789         goto error;
   790     top.sp->obj = array;
   791     top.sp++;
   792     break;
   793 }
   794 
   795 case OP_NEWSTRUCT:
   796 {
   797     Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
   798     Local<StructMap> map(zone, StructMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
   799     top.sp->obj = Struct::New(zone, map, tenure);
   800     if (!top.sp->obj)
   801         goto error;
   802     top.sp++;
   803     break;
   804 }
   805 
   806 case OP_SAVELIFO:
   807 {
   808     unsigned slot = READ_UINT32(top.pc);
   809     locals[slot].address = zone->heap().lifoPosition();
   810     break;
   811 }
   812 
   813 case OP_UNWINDLIFO:
   814 {
   815     unsigned slot = READ_UINT32(top.pc);
   816     zone->heap().unwindLifo(locals[slot].address);
   817     break;
   818 }
   819 
   820 case OP_VARREF_LIFO:
   821 {
   822     unsigned slot = READ_UINT32(top.pc);
   823     if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
   824         goto error;
   825     break;
   826 }
   827 
   828 case OP_ARGREF_LIFO:
   829 {
   830     unsigned slot = READ_UINT32(top.pc);
   831     if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
   832         goto error;
   833     break;
   834 }
   835 
   836 case OP_ARRAYREF_LIFO:
   837 {
   838     Local<Array> array(zone, Array::cast(top.sp[-2].obj));
   839     Local<Reference> ref(zone, Reference::NewArray(zone, array, top.sp[-1].i32, Heap::Tenure_Stack));
   840     if (!ref)
   841         goto error;
   842     top.sp[-2].ref = ref;
   843     top.sp--;
   844     break;
   845 }
   846 
   847 case OP_SLOTREF_LIFO:
   848 {
   849     Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
   850     if (!ref)
   851         goto error;
   852     top.sp[-1].ref = ref;
   853     break;
   854 }
   855 
   856 case OP_FIELDREF_LIFO:
   857 {
   858     Local<Struct> obj(zone, Struct::cast(top.sp[-1].obj));
   859     top.sp[-1].obj = Reference::NewField(zone, obj, READ_UINT32(top.pc), Heap::Tenure_Stack);
   860     if (!top.sp[-1].obj)
   861         goto error;
   862     break;
   863 }
   864 
   865 case OP_GETREF_I:
   866 {
   867     top.sp[-1].i32 = top.sp[-1].ref->getInt();
   868     break;
   869 }
   870 
   871 case OP_SETREF_I:
   872 {
   873     top.sp[-2].ref->setInt(top.sp[-1].i32);
   874     top.sp[-2].i32 = top.sp[-1].i32;
   875     top.sp--;
   876     break;
   877 }
   878 
   879 case OP_GETREF_F:
   880 {
   881     top.sp[-1].f = top.sp[-1].ref->getFloat();
   882     break;
   883 }
   884 
   885 case OP_SETREF_F:
   886 {
   887     top.sp[-2].ref->setFloat(top.sp[-1].f);
   888     top.sp[-2].f = top.sp[-1].f;
   889     break;
   890 }
   891 
   892 case OP_OBJECT:
   893 {
   894     top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
   895     top.sp++;
   896     break;
   897 }
   898 
   899 case OP_COPYARRAY:
   900 {
   901     // Note for this assignment opcode, we return the left-hand side, not the
   902     // right, since in this case the result of the expression could be different.
   903     if (!CopyArray(zone, top.sp[-2].array, top.sp[-1].array))
   904         goto error;
   905     top.sp--;
   906     break;
   907 }
   908 
   909 case OP_DUP:
   910 {
   911     top.sp++;
   912     top.sp[-1] = top.sp[-2];
   913     break;
   914 }
   915 
   916 case OP_DUP2:
   917 {
   918     top.sp += 2;
   919     top.sp[-2] = top.sp[-4];
   920     top.sp[-1] = top.sp[-3];
   921     break;
   922 }
   923 
   924 case OP_SWAP:
   925 {
   926     LocalSlot slot = top.sp[-2];
   927     top.sp[-2] = top.sp[-1];
   928     top.sp[-1] = slot;
   929     break;
   930 }
   931 
   932 case OP_ROLL3:
   933 {
   934     LocalSlot slot = top.sp[-3];
   935     top.sp[-3] = top.sp[-2];
   936     top.sp[-2] = top.sp[-1];
   937     top.sp[-1] = slot;
   938     break;
   939 }
   940 
   941 case OP_PICK2:
   942 {
   943     top.sp++;
   944     top.sp[-1] = top.sp[-3];
   945     break;
   946 }
   947 
   948 case OP_PICK3:
   949 {
   950     top.sp++;
   951     top.sp[-1] = top.sp[-4];
   952     break;
   953 }
   954 
   955 case OP_CALLNATIVE:
   956 {
   957     unsigned index = READ_UINT32(top.pc);
   958     unsigned argc = READ_UINT32(top.pc + 4);
   959 
   960     Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
   961     if (!native->function()) {
   962         zone->reportError(Message_NativeNotBound, native->name()->chars());
   963         goto error;
   964     }
   965 
   966     int result;
   967     void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
   968     if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
   969         goto error;
   970 
   971     top.sp -= argc;
   972     PUSH_I32(top, result);
   973     break;
   974 }
   975 
   976 case OP_MODULE:
   977 {
   978     top.sp++;
   979     top.sp[-1].module = top.fp->code()->module();
   980     break;
   981 }
   982 
   983 case OP_GETMODULE_FN:
   984 {
   985     top.sp[-1].fun = top.sp[-1].module->getFunction(READ_UINT32(top.pc));
   986     break;
   987 }
   988 
   989 case OP_GETGLOBAL_I:
   990 {
   991     unsigned slot = READ_UINT32(top.pc);
   992     top.sp++;
   993     top.sp[-1].i32 = top.fp->code()->module()->environment()->getInt32(slot);
   994     break;
   995 }
   996 
   997 case OP_GETGLOBAL_F:
   998 {
   999     unsigned slot = READ_UINT32(top.pc);
  1000     top.sp++;
  1001     top.sp[-1].f = top.fp->code()->module()->environment()->getFloat(slot);
  1002     break;
  1003 }
  1004 
  1005 case OP_GETGLOBAL_O:
  1006 {
  1007     unsigned slot = READ_UINT32(top.pc);
  1008     top.sp++;
  1009     top.sp[-1].obj = top.fp->code()->module()->environment()->getObject(slot);
  1010     break;
  1011 }
  1012 
  1013 case OP_SETGLOBAL_I:
  1014 {
  1015     unsigned slot = READ_UINT32(top.pc);
  1016     top.fp->code()->module()->environment()->setInt32(slot, top.sp[-1].i32);
  1017     break;
  1018 }
  1019 
  1020 case OP_SETGLOBAL_F:
  1021 {
  1022     unsigned slot = READ_UINT32(top.pc);
  1023     top.fp->code()->module()->environment()->setFloat(slot, top.sp[-1].f);
  1024     break;
  1025 }
  1026 
  1027 case OP_SETGLOBAL_O:
  1028 {
  1029     unsigned slot = READ_UINT32(top.pc);
  1030     top.fp->code()->module()->environment()->setObject(slot, top.sp[-1].obj);
  1031     break;
  1032 }
  1033 
  1034 case OP_BITS_I2F:
  1035 case OP_BITS_F2I:
  1036 {
  1037     // Because the stack is a union, these are actually no-ops in the
  1038     // interpreter.
  1039     break;
  1040 }
  1041 
  1042 case OP_TRUE:
  1043 {
  1044     top.sp++;
  1045     top.sp[-1].i32 = 1;
  1046     break;
  1047 }
  1048 
  1049 case OP_FALSE:
  1050 {
  1051     top.sp++;
  1052     top.sp[-1].i32 = 0;
  1053     break;
  1054 }
  1055 
  1056 case OP_GETFIELD:
  1057 {
  1058     Struct *obj = Struct::cast(top.sp[-1].obj);
  1059     GetField(obj, READ_UINT32(top.pc), &top.sp[-1]);
  1060     break;
  1061 }
  1062 
  1063 case OP_SETFIELD:
  1064 {
  1065     Struct *obj = Struct::cast(top.sp[-2].obj);
  1066     SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]);
  1067     top.sp[-2] = top.sp[-1];
  1068     top.sp--;
  1069     break;
  1070 }
  1071 
  1072 case OP_COPYSTRUCT:
  1073 {
  1074     if (!CopyStruct(zone, Struct::cast(top.sp[-2].obj), Struct::cast(top.sp[-1].obj)))
  1075         goto error;
  1076     top.sp[-2].obj = top.sp[-1].obj;
  1077     top.sp--;
  1078     break;
  1079 }
  1080 
  1081 default:
  1082     assert(false);
  1083     return false;
  1084 
  1085         }
  1086 
  1087         top.pc += OpcodeInfo[op].length;
  1088     }
  1089 
  1090 done:
  1091     return true;
  1092 
  1093 error:
  1094     // Unwind frames until we can continue.
  1095     while (top.fp != entryFrame)
  1096         zone->stack().popInlineFrame();
  1097     return false;
  1098 }