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