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