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