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