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