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