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