src/Interpreter.cpp
author David Anderson <dvander@alliedmods.net>
Sat Nov 17 19:07:49 2012 -0800 (2012-11-17)
changeset 196 9904633b1dfc
parent 195 c1ba166f3fc4
child 207 04ce04a54936
permissions -rw-r--r--
Fix Linux build problems.
     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() && 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     top.pc += READ_INT32(top.pc);
   450     continue;
   451 
   452 case OP_GETLOCAL:
   453 {
   454     unsigned slot = READ_UINT32(top.pc);
   455     assert(slot < top.fp->code()->nlocals());
   456     *top.sp++ = locals[slot];
   457     break;
   458 }
   459 
   460 case OP_SETLOCAL:
   461 {
   462     unsigned slot = READ_UINT32(top.pc);
   463     assert(slot < top.fp->code()->nlocals());
   464     locals[slot] = top.sp[-1];
   465     break;
   466 }
   467 
   468 case OP_ADD:
   469 {
   470     top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
   471     top.sp--;
   472     break;
   473 }
   474 
   475 case OP_SUB:
   476 {
   477     top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
   478     top.sp--;
   479     break;
   480 }
   481 
   482 case OP_MUL:
   483 {
   484     top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
   485     top.sp--;
   486     break;
   487 }
   488 
   489 case OP_DIV:
   490 {
   491     if (top.sp[-1].i32 == 0) {
   492         zone->reportError(Message_IntegerDivideByZero);
   493         goto error;
   494     }
   495     top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
   496     top.sp--;
   497     break;
   498 }
   499 
   500 case OP_MOD:
   501 {
   502     if (top.sp[-1].i32 == 0) {
   503         zone->reportError(Message_IntegerDivideByZero);
   504         goto error;
   505     }
   506     top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
   507     top.sp--;
   508     break;
   509 }
   510 
   511 case OP_LT:
   512 {
   513     top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
   514     top.sp--;
   515     break;
   516 }
   517 
   518 case OP_LE:
   519 {
   520     top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
   521     top.sp--;
   522     break;
   523 }
   524 
   525 case OP_GT:
   526 {
   527     top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
   528     top.sp--;
   529     break;
   530 }
   531 
   532 case OP_GE:
   533 {
   534     top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
   535     top.sp--;
   536     break;
   537 }
   538 
   539 case OP_EQ:
   540 {
   541     top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
   542     top.sp--;
   543     break;
   544 }
   545 
   546 case OP_NE:
   547 {
   548     top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
   549     top.sp--;
   550     break;
   551 }
   552 
   553 case OP_ADD_F:
   554 {
   555     top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
   556     top.sp--;
   557     break;
   558 }
   559 
   560 case OP_SUB_F:
   561 {
   562     top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
   563     top.sp--;
   564     break;
   565 }
   566 
   567 case OP_MUL_F:
   568 {
   569     top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
   570     top.sp--;
   571     break;
   572 }
   573 
   574 case OP_DIV_F:
   575 {
   576     top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
   577     top.sp--;
   578     break;
   579 }
   580 
   581 case OP_LT_F:
   582 {
   583     top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
   584     top.sp--;
   585     break;
   586 }
   587 
   588 case OP_LE_F:
   589 {
   590     top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
   591     top.sp--;
   592     break;
   593 }
   594 
   595 case OP_GT_F:
   596 {
   597     top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
   598     top.sp--;
   599     break;
   600 }
   601 
   602 case OP_GE_F:
   603 {
   604     top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
   605     top.sp--;
   606     break;
   607 }
   608 
   609 case OP_EQ_F:
   610 {
   611     top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
   612     top.sp--;
   613     break;
   614 }
   615 
   616 case OP_NE_F:
   617 {
   618     top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
   619     top.sp--;
   620     break;
   621 }
   622 
   623 case OP_SHL:
   624 {
   625     top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
   626     top.sp--;
   627     break;
   628 }
   629 
   630 case OP_SHR:
   631 {
   632     top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
   633     top.sp--;
   634     break;
   635 }
   636 
   637 case OP_USHR:
   638 {
   639     top.sp[-2].i32 = unsigned(top.sp[-2].i32) << unsigned(top.sp[-1].i32);
   640     top.sp--;
   641     break;
   642 }
   643 
   644 case OP_BITAND:
   645 {
   646     top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
   647     top.sp--;
   648     break;
   649 }
   650 
   651 case OP_BITOR:
   652 {
   653     top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
   654     top.sp--;
   655     break;
   656 }
   657 
   658 case OP_BITXOR:
   659 {
   660     top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
   661     top.sp--;
   662     break;
   663 }
   664 
   665 case OP_BITNOT:
   666 {
   667     top.sp[-1].i32 = ~top.sp[-1].i32;
   668     break;
   669 }
   670 
   671 case OP_NOT:
   672 {
   673     top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
   674     break;
   675 }
   676 
   677 case OP_NOT_F:
   678 {
   679     top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
   680     break;
   681 }
   682 
   683 case OP_NEG:
   684 {
   685     top.sp[-1].i32 = -top.sp[-1].i32;
   686     break;
   687 }
   688 
   689 case OP_NEG_F:
   690 {
   691     top.sp[-1].f = -top.sp[-1].f;
   692     break;
   693 }
   694 
   695 case OP_CALL:
   696 {
   697     Local<Function> newFun(zone, Function::cast(top.sp[-1].obj));
   698     top.sp--;
   699 
   700     if (!zone->stack().pushInlineFrame(newFun))
   701         goto error;
   702 
   703     locals = top.fp->locals();
   704     continue;
   705 }
   706 
   707 case OP_GETARG:
   708 {
   709     unsigned slot = READ_UINT32(top.pc);
   710     *top.sp++ = top.fp->arg(slot);
   711     break;
   712 }
   713 
   714 case OP_SETARG:
   715 {
   716     unsigned slot = READ_UINT32(top.pc);
   717     top.fp->arg(slot) = top.sp[-1];
   718     break;
   719 }
   720 
   721 case OP_GETELEM:
   722 {
   723     Array *array = Array::cast(top.sp[-2].obj);
   724     int index = top.sp[-1].i32;
   725 
   726     if (index < 0 || unsigned(index) >= array->length()) {
   727         zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
   728         goto error;
   729     }
   730 
   731     GetElement(array, index, &top.sp[-2]);
   732     top.sp--;
   733     break;
   734 }
   735 
   736 case OP_SETELEM:
   737 {
   738     Array *array = Array::cast(top.sp[-3].obj);
   739     int index = top.sp[-2].i32;
   740 
   741     if (index < 0 || unsigned(index) >= array->length()) {
   742         zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
   743         goto error;
   744     }
   745 
   746     SetElement(zone, array, index, top.sp[-1]);
   747     top.sp[-3] = top.sp[-1];
   748     top.sp -= 2;
   749     break;
   750 }
   751 
   752 case OP_CVT_I2F:
   753 {
   754     int ival = POP_I32(top);
   755     float fval = (float)ival;
   756     PUSH_F(top, fval);
   757     break;
   758 }
   759 
   760 case OP_NEWFIXED:
   761 {
   762     Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
   763     Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
   764     Array *array = Array::NewFixed(zone, map, tenure);
   765     if (!array)
   766         goto error;
   767     top.sp->obj = array;
   768     top.sp++;
   769     break;
   770 }
   771 
   772 case OP_NEWEMPTY:
   773 {
   774     Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
   775     Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
   776     Array *array = Array::NewEmpty(zone, map, tenure);
   777     if (!array)
   778         goto error;
   779     top.sp->obj = array;
   780     top.sp++;
   781     break;
   782 }
   783 
   784 case OP_NEWSIZED:
   785 {
   786     Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
   787     Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
   788     assert(map->type()->levels() < MAX_ARRAY_DEPTH);
   789 
   790     int dims[MAX_ARRAY_DEPTH];
   791     for (unsigned i = map->type()->levels() - 1; i < map->type()->levels(); i--)
   792         dims[i] = POP_I32(top);
   793 
   794     Array *array = Array::NewSized(zone, map, dims, tenure);
   795     if (!array)
   796         goto error;
   797     top.sp->obj = array;
   798     top.sp++;
   799     break;
   800 }
   801 
   802 case OP_NEWSTRUCT:
   803 {
   804     Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
   805     Local<StructMap> map(zone, StructMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
   806     top.sp->obj = Struct::New(zone, map, tenure);
   807     if (!top.sp->obj)
   808         goto error;
   809     top.sp++;
   810     break;
   811 }
   812 
   813 case OP_SAVELIFO:
   814 {
   815     unsigned slot = READ_UINT32(top.pc);
   816     locals[slot].address = zone->heap().lifoPosition();
   817     break;
   818 }
   819 
   820 case OP_UNWINDLIFO:
   821 {
   822     unsigned slot = READ_UINT32(top.pc);
   823     zone->heap().unwindLifo(locals[slot].address);
   824     break;
   825 }
   826 
   827 case OP_VARREF_LIFO:
   828 {
   829     unsigned slot = READ_UINT32(top.pc);
   830     if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
   831         goto error;
   832     break;
   833 }
   834 
   835 case OP_ARGREF_LIFO:
   836 {
   837     unsigned slot = READ_UINT32(top.pc);
   838     if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
   839         goto error;
   840     break;
   841 }
   842 
   843 case OP_SLOTREF_LIFO:
   844 {
   845     Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
   846     if (!ref)
   847         goto error;
   848     top.sp[-1].ref = ref;
   849     break;
   850 }
   851 
   852 case OP_GETREF_I:
   853 {
   854     top.sp[-1].i32 = top.sp[-1].ref->getInt();
   855     break;
   856 }
   857 
   858 case OP_SETREF_I:
   859 {
   860     top.sp[-2].ref->setInt(top.sp[-1].i32);
   861     top.sp[-2].i32 = top.sp[-1].i32;
   862     top.sp--;
   863     break;
   864 }
   865 
   866 case OP_GETREF_F:
   867 {
   868     top.sp[-1].f = top.sp[-1].ref->getFloat();
   869     break;
   870 }
   871 
   872 case OP_SETREF_F:
   873 {
   874     top.sp[-2].ref->setFloat(top.sp[-1].f);
   875     top.sp[-2].f = top.sp[-1].f;
   876     break;
   877 }
   878 
   879 case OP_OBJECT:
   880 {
   881     top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
   882     top.sp++;
   883     break;
   884 }
   885 
   886 case OP_COPYARRAY:
   887 {
   888     // Note for this assignment opcode, we return the left-hand side, not the
   889     // right, since in this case the result of the expression could be different.
   890     Local<Array> left(zone, Array::cast(top.sp[-2].array));
   891     Local<Array> right(zone, Array::cast(top.sp[-1].array));
   892     if (!CopyArray(zone, left, right))
   893         goto error;
   894     top.sp--;
   895     break;
   896 }
   897 
   898 case OP_DUP:
   899 {
   900     top.sp++;
   901     top.sp[-1] = top.sp[-2];
   902     break;
   903 }
   904 
   905 case OP_DUP2:
   906 {
   907     top.sp += 2;
   908     top.sp[-2] = top.sp[-4];
   909     top.sp[-1] = top.sp[-3];
   910     break;
   911 }
   912 
   913 case OP_SWAP:
   914 {
   915     LocalSlot slot = top.sp[-2];
   916     top.sp[-2] = top.sp[-1];
   917     top.sp[-1] = slot;
   918     break;
   919 }
   920 
   921 case OP_ROLL3:
   922 {
   923     LocalSlot slot = top.sp[-3];
   924     top.sp[-3] = top.sp[-2];
   925     top.sp[-2] = top.sp[-1];
   926     top.sp[-1] = slot;
   927     break;
   928 }
   929 
   930 case OP_PICK2:
   931 {
   932     top.sp++;
   933     top.sp[-1] = top.sp[-3];
   934     break;
   935 }
   936 
   937 case OP_PICK3:
   938 {
   939     top.sp++;
   940     top.sp[-1] = top.sp[-4];
   941     break;
   942 }
   943 
   944 case OP_CALLNATIVE:
   945 {
   946     unsigned argc = READ_UINT32(top.pc);
   947 
   948     Local<Native> native(zone, Native::cast(top.sp[-1].obj));
   949     top.sp--;
   950 
   951     int result;
   952     void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
   953     if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
   954         goto error;
   955 
   956     top.sp -= argc;
   957     PUSH_I32(top, result);
   958     break;
   959 }
   960 
   961 case OP_BITS_I2F:
   962 case OP_BITS_F2I:
   963 {
   964     // Because the stack is a union, these are actually no-ops in the
   965     // interpreter.
   966     break;
   967 }
   968 
   969 case OP_TRUE:
   970 {
   971     top.sp++;
   972     top.sp[-1].i32 = 1;
   973     break;
   974 }
   975 
   976 case OP_FALSE:
   977 {
   978     top.sp++;
   979     top.sp[-1].i32 = 0;
   980     break;
   981 }
   982 
   983 case OP_GETFIELD:
   984 {
   985     Struct *obj = Struct::cast(top.sp[-1].obj);
   986     GetField(obj, READ_UINT32(top.pc), &top.sp[-1]);
   987     break;
   988 }
   989 
   990 case OP_SETFIELD:
   991 {
   992     Struct *obj = Struct::cast(top.sp[-2].obj);
   993     SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]);
   994     top.sp[-2] = top.sp[-1];
   995     top.sp--;
   996     break;
   997 }
   998 
   999 case OP_COPYSTRUCT:
  1000 {
  1001     Local<Struct> left(zone, Struct::cast(top.sp[-2].obj));
  1002     Local<Struct> right(zone, Struct::cast(top.sp[-1].obj));
  1003     if (!CopyStruct(zone, left, right))
  1004         goto error;
  1005     top.sp[-2].obj = top.sp[-1].obj;
  1006     top.sp--;
  1007     break;
  1008 }
  1009 
  1010 case OP_TABLESWITCH:
  1011 {
  1012     int value = top.sp[-1].i32;
  1013     int low = READ_TABLESWITCH_LOW(top.pc);
  1014     int high = READ_TABLESWITCH_HIGH(top.pc);
  1015 
  1016     top.sp--;
  1017 
  1018     unsigned index = unsigned(value - low);
  1019     unsigned tablesize = TableSwitchEntries(low, high);
  1020     if (index < tablesize) {
  1021         top.pc += OP_TABLESWITCH_LENGTH + OP_JUMP_LENGTH;
  1022         top.pc += index * OP_JUMP_LENGTH;
  1023         continue;
  1024     }
  1025     break;
  1026 }
  1027 
  1028 case OP_SIZEOF:
  1029 {
  1030     Array *array = Array::cast(top.sp[-1].obj);
  1031     top.sp[-1].i32 = array->length();
  1032     break;
  1033 }
  1034 
  1035 case OP_PUBLIC:
  1036 {
  1037     Local<Function> fun(zone, Function::cast(top.sp[-1].obj));
  1038     zone->registerPublic(fun);
  1039     top.sp--;
  1040     break;
  1041 }
  1042 
  1043 case OP_SETGLOBAL:
  1044 {
  1045     Local<Code> code(zone, top.fp->code());
  1046     Local<Struct> obj(zone, code->module()->globals());
  1047     Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
  1048     SetGlobal(zone, obj, name, top.sp[-1]);
  1049     break;
  1050 }
  1051 
  1052 case OP_GETGLOBAL:
  1053 {
  1054     Local<Code> code(zone, top.fp->code());
  1055     Local<Struct> obj(zone, code->module()->globals());
  1056     Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
  1057     GetGlobal(zone, obj, name, top.sp);
  1058     top.sp++;
  1059     break;
  1060 }
  1061 
  1062 default:
  1063     assert(false);
  1064     return false;
  1065 
  1066         }
  1067 
  1068         top.pc += OpcodeInfo[op].length;
  1069         assert(top.sp >= top.fp->stackBase());
  1070     }
  1071 
  1072 done:
  1073     return true;
  1074 
  1075 error:
  1076     // Unwind frames until we can continue.
  1077     while (top.fp != entryFrame)
  1078         zone->stack().popInlineFrame();
  1079     return false;
  1080 }