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