jitcraft/Interpreter.cpp
author David Anderson <dvander@alliedmods.net>
Tue Jul 17 03:59:52 2012 -0700 (2012-07-17)
changeset 78 93e0a19c805a
parent 77 6d8b34cad6d3
child 79 0206df35882c
permissions -rw-r--r--
Added complement operator support.
     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 "Interpreter.h"
    20 #include "Modules.h"
    21 #include "Zone.h"
    22 #include "Types.h"
    23 #include "Array.h"
    24 #include "Reference.h"
    25 #include "Strings.h"
    26 #include "Heap-inl.h"
    27 
    28 using namespace ke;
    29 
    30 #define PUSH_I32(top, value)    \
    31     do {                        \
    32         top.sp->i32 = value;    \
    33         top.sp++;               \
    34    } while (0)
    35 
    36 #define PUSH_F(top, value)      \
    37     do {                        \
    38         top.sp->f = value;      \
    39         top.sp++;               \
    40    } while (0)
    41 
    42 static inline int
    43 POP_I32(Top &top)
    44 {
    45     int value = top.sp[-1].i32;
    46     top.sp--;
    47     return value;
    48 }
    49 
    50 static inline float
    51 POP_F(Top &top)
    52 {
    53     float value = top.sp[-1].f;
    54     top.sp--;
    55     return value;
    56 }
    57 
    58 // Pawn's original semantics specify some kind of floor operation, so
    59 // (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses
    60 // the upstream algorithm when constant folding. However the SourcePawn 1 JIT
    61 // does not. My guess is that Borja freaked out seeing the 13-instruction x86
    62 // sequence necessary to get this functionality (I vaguely recall a thread
    63 // where we discussed this with Mark Peter? But the ITB forums are gone...),
    64 // and we just decided to break the damn thing. So SP1 was inconsistent, but
    65 // we are not. And for completeness, we assert that the C compiler does the
    66 // right thing, since C89 leaves it unspecified.
    67 STATIC_ASSERT(8 / -3 == -2);
    68 STATIC_ASSERT(-8 / 3 == -2);
    69 
    70 static inline bool
    71 PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
    72 {
    73     Reference *ref = Reference::NewStack(zone, location, tenure);
    74     if (!ref)
    75         return false;
    76     top.sp->ref = ref;
    77     top.sp++;
    78     return true;
    79 }
    80 
    81 // Generate an array with completely static sizes.
    82 static Array *
    83 GenerateArray(Zone *zone, Handle<ArrayMap> map)
    84 {
    85     assert(map->type()->elements() != -1);
    86 
    87     Local<Array> array(zone, Array::New(zone, map, map->type()->elements(), Heap::Tenure_Stack));
    88     if (!array)
    89         return NULL;
    90 
    91     if (map->type()->levels() == 1)
    92         return array;
    93 
    94     Local<ArrayMap> contained(zone, map->contained());
    95     Local<Array> sub(zone);
    96     for (unsigned i = 0; i < unsigned(map->type()->elements()); i++) {
    97         sub = GenerateArray(zone, contained);
    98         if (!sub)
    99             return NULL;
   100         array->writeObject(zone, i, sub);
   101     }
   102 
   103     return array;
   104 }
   105 
   106 static bool
   107 CopyArray(Zone *zone, Array *source, Array *dest)
   108 {
   109     assert(source->type()->levels() == 1);
   110     assert(dest->type()->levels() == 1);
   111     assert(source->type()->contained()->primitive() ==
   112            dest->type()->contained()->primitive());
   113     assert(source->nelements() >= dest->nelements());
   114     assert(dest->elementSize() == source->elementSize());
   115 
   116     memcpy(source->vec(), dest->vec(), dest->nelements() * dest->elementSize());
   117     return true;
   118 }
   119 
   120 static bool
   121 InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
   122              int *result)
   123 {
   124     NativeArgs guard;
   125 
   126     if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
   127         return false;
   128 
   129     intptr_t *cells = guard.args();
   130 
   131     // params[0] == argc, in ISPE
   132     cells[0] = argc;
   133 
   134     // Pass the formal arguments.
   135     Local<Type> type(zone, native->type());
   136     Local<Type> param(zone);
   137     for (unsigned i = 0; i < type->parameters()->length(); i++) {
   138         param = type->parameterAt(i);
   139         
   140         // For floats, we rely on the aliasing of |i32| and |f|.
   141         LocalSlot &arg = args[-int(i) - 1];
   142         if (param->isInt32() || param->isFloat()) {
   143             cells[i + 1] = arg.i32;
   144         } else if (param->isReference()) {
   145             cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
   146         } else {
   147             assert(param->isArray());
   148             cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
   149         }
   150     }
   151 
   152     // For variadic arguments, the compiler left either arrays or references.
   153     for (unsigned i = type->parameters()->length(); i < argc; i++) {
   154         LocalSlot &arg = args[-int(i) - 1];
   155 
   156         if (arg.obj->is(MapKind_Reference)) {
   157             cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
   158         } else {
   159             assert(arg.obj->is(MapKind_Array));
   160             cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
   161         }
   162     }
   163 
   164     typedef intptr_t (*INVOKE)(void *, intptr_t *);
   165     INVOKE invoke = (INVOKE)native->function();
   166     *result = invoke(identity, cells);
   167 
   168     return !zone->hasPendingException();
   169 }
   170 
   171 bool
   172 ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
   173 {
   174     Top &top = *zone->stack().top();
   175     if (!entryFrame)
   176         entryFrame = top.fp;
   177 
   178     LocalSlot *locals = entryFrame->locals();
   179 
   180     for (;;) {
   181         Opcode op = Opcode(*top.pc);
   182         switch (op) {
   183 
   184 case OP_NOP:
   185     break;
   186 
   187 case OP_INT:
   188     PUSH_I32(top, READ_INT32(top.pc));
   189     break;
   190 
   191 case OP_FLOAT:
   192     PUSH_F(top, READ_FLOAT(top.pc));
   193     break;
   194 
   195 case OP_RETURN:
   196 case OP_RETURNVOID:
   197 case OP_STOP:
   198 {
   199     if (op == OP_RETURN)
   200         *result = *--top.sp;
   201 
   202     if (top.fp == entryFrame)
   203         goto done;
   204 
   205     // This must not GC.
   206     zone->stack().popInlineFrame();
   207     locals = top.fp->locals();
   208 
   209     if (op == OP_RETURN)
   210         *top.sp++ = *result;
   211 
   212     top.pc += OpcodeInfo[*top.pc].length;
   213     continue;
   214 }
   215 
   216 #define RELATIONAL_JUMP(op)                 \
   217     {                                       \
   218         int right = POP_I32(top);           \
   219         int left = POP_I32(top);            \
   220         if (left op right) {                \
   221             top.pc += READ_INT32(top.pc);   \
   222             continue;                       \
   223         }                                   \
   224     }
   225 
   226 case OP_JL:
   227     RELATIONAL_JUMP(<);
   228     break;
   229 
   230 case OP_JLE:
   231     RELATIONAL_JUMP(<=);
   232     break;
   233 
   234 case OP_JG:
   235     RELATIONAL_JUMP(>);
   236     break;
   237 
   238 case OP_JGE:
   239     RELATIONAL_JUMP(>=);
   240     break;
   241 
   242 case OP_JEQ:
   243     RELATIONAL_JUMP(==);
   244     break;
   245 
   246 case OP_JNE:
   247     RELATIONAL_JUMP(!=);
   248     break;
   249 
   250 #undef RELATIONAL_JUMP
   251 
   252 case OP_JT:
   253 {
   254     int value = POP_I32(top);
   255     if (value) {
   256         top.pc += READ_INT32(top.pc);
   257         continue;
   258     }
   259     break;
   260 }
   261 
   262 case OP_JF:
   263 {
   264     int value = POP_I32(top);
   265     if (!value) {
   266         top.pc += READ_INT32(top.pc);
   267         continue;
   268     }
   269     break;
   270 }
   271 
   272 #define RELATIONAL_JUMP_F(op)               \
   273     {                                       \
   274         float right = POP_F(top);           \
   275         float left = POP_F(top);            \
   276         if (left op right) {                \
   277             top.pc += READ_INT32(top.pc);   \
   278             continue;                       \
   279         }                                   \
   280     }
   281 
   282 case OP_JL_F:
   283     RELATIONAL_JUMP_F(<);
   284     break;
   285 
   286 case OP_JLE_F:
   287     RELATIONAL_JUMP_F(<=);
   288     break;
   289 
   290 case OP_JG_F:
   291     RELATIONAL_JUMP_F(>);
   292     break;
   293 
   294 case OP_JGE_F:
   295     RELATIONAL_JUMP_F(>=);
   296     break;
   297 
   298 case OP_JEQ_F:
   299     RELATIONAL_JUMP_F(==);
   300     break;
   301 
   302 case OP_JNE_F:
   303     RELATIONAL_JUMP_F(!=);
   304     break;
   305 
   306 case OP_JT_F:
   307 {
   308     float value = POP_F(top);
   309     if (value) {
   310         top.pc += READ_INT32(top.pc);
   311         continue;
   312     }
   313     break;
   314 }
   315 
   316 case OP_JF_F:
   317 {
   318     float value = POP_F(top);
   319     if (!value) {
   320         top.pc += READ_INT32(top.pc);
   321         continue;
   322     }
   323     break;
   324 }
   325 
   326 case OP_JUMP:
   327     top.pc += READ_INT32(top.pc);
   328     continue;
   329 
   330 case OP_GETLOCAL:
   331 {
   332     int slot = READ_INT32(top.pc);
   333     *top.sp++ = locals[slot];
   334     break;
   335 }
   336 
   337 case OP_SETLOCAL:
   338 {
   339     int slot = READ_INT32(top.pc);
   340     locals[slot] = top.sp[-1];
   341     break;
   342 }
   343 
   344 case OP_ADD:
   345 {
   346     top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
   347     top.sp--;
   348     break;
   349 }
   350 
   351 case OP_SUB:
   352 {
   353     top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
   354     top.sp--;
   355     break;
   356 }
   357 
   358 case OP_MUL:
   359 {
   360     top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
   361     top.sp--;
   362     break;
   363 }
   364 
   365 case OP_DIV:
   366 {
   367     if (top.sp[-1].i32 == 0) {
   368         zone->reportError(Message_IntegerDivideByZero);
   369         goto error;
   370     }
   371     top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
   372     top.sp--;
   373     break;
   374 }
   375 
   376 case OP_LT:
   377 {
   378     top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
   379     top.sp--;
   380     break;
   381 }
   382 
   383 case OP_LE:
   384 {
   385     top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
   386     top.sp--;
   387     break;
   388 }
   389 
   390 case OP_GT:
   391 {
   392     top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
   393     top.sp--;
   394     break;
   395 }
   396 
   397 case OP_GE:
   398 {
   399     top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
   400     top.sp--;
   401     break;
   402 }
   403 
   404 case OP_EQ:
   405 {
   406     top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
   407     top.sp--;
   408     break;
   409 }
   410 
   411 case OP_NE:
   412 {
   413     top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
   414     top.sp--;
   415     break;
   416 }
   417 
   418 case OP_ADD_F:
   419 {
   420     top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
   421     top.sp--;
   422     break;
   423 }
   424 
   425 case OP_SUB_F:
   426 {
   427     top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
   428     top.sp--;
   429     break;
   430 }
   431 
   432 case OP_MUL_F:
   433 {
   434     top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
   435     top.sp--;
   436     break;
   437 }
   438 
   439 case OP_DIV_F:
   440 {
   441     top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
   442     top.sp--;
   443     break;
   444 }
   445 
   446 case OP_LT_F:
   447 {
   448     top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
   449     top.sp--;
   450     break;
   451 }
   452 
   453 case OP_LE_F:
   454 {
   455     top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
   456     top.sp--;
   457     break;
   458 }
   459 
   460 case OP_GT_F:
   461 {
   462     top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
   463     top.sp--;
   464     break;
   465 }
   466 
   467 case OP_GE_F:
   468 {
   469     top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
   470     top.sp--;
   471     break;
   472 }
   473 
   474 case OP_EQ_F:
   475 {
   476     top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
   477     top.sp--;
   478     break;
   479 }
   480 
   481 case OP_NE_F:
   482 {
   483     top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
   484     top.sp--;
   485     break;
   486 }
   487 
   488 case OP_SHL:
   489 {
   490     top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
   491     top.sp--;
   492     break;
   493 }
   494 
   495 case OP_SHR:
   496 {
   497     top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
   498     top.sp--;
   499     break;
   500 }
   501 
   502 case OP_USHR:
   503 {
   504     top.sp[-2].i32 = unsigned(top.sp[-2].i32) << unsigned(top.sp[-1].i32);
   505     top.sp--;
   506     break;
   507 }
   508 
   509 case OP_BITAND:
   510 {
   511     top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
   512     top.sp--;
   513     break;
   514 }
   515 
   516 case OP_BITOR:
   517 {
   518     top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
   519     top.sp--;
   520     break;
   521 }
   522 
   523 case OP_BITXOR:
   524 {
   525     top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
   526     top.sp--;
   527     break;
   528 }
   529 
   530 case OP_BITNOT:
   531 {
   532     top.sp[-1].i32 = ~top.sp[-1].i32;
   533     break;
   534 }
   535 
   536 case OP_POP:
   537     top.sp--;
   538     break;
   539 
   540 case OP_CALL:
   541 {
   542     zone->heap().reclaim();
   543 
   544     Local<Function> newFun(zone, top.sp[-1].fun);
   545     top.sp--;
   546 
   547     if (!zone->stack().pushInlineFrame(newFun))
   548         goto error;
   549 
   550     locals = top.fp->locals();
   551     continue;
   552 }
   553 
   554 case OP_GETARG:
   555 {
   556     unsigned slot = READ_UINT32(top.pc);
   557     *top.sp++ = top.fp->arg(slot);
   558     break;
   559 }
   560 
   561 case OP_SETARG:
   562 {
   563     unsigned slot = READ_UINT32(top.pc);
   564     top.fp->arg(slot) = *--top.sp;
   565     break;
   566 }
   567 
   568 case OP_BOUNDS:
   569 {
   570     Array *array = top.sp[-2].array;
   571     int index = top.sp[-1].i32;
   572     if (index < 0 || unsigned(index) >= array->nelements()) {
   573         zone->reportError(Message_ArrayIndexOutOfBounds, index, array->nelements());
   574         goto error;
   575     }
   576     break;
   577 }
   578 
   579 case OP_GETARRAY_I:
   580 {
   581     Array *array = top.sp[-2].array;
   582     int index = top.sp[-1].i32;
   583     top.sp[-2].i32 = array->readInt32(index);
   584     top.sp--;
   585     break;
   586 }
   587 
   588 case OP_GETARRAY_F:
   589 {
   590     Array *array = top.sp[-2].array;
   591     int index = top.sp[-1].i32;
   592     top.sp[-2].f = array->readFloat(index);
   593     top.sp--;
   594     break;
   595 }
   596 
   597 case OP_GETARRAY_C:
   598 {
   599     Array *array = top.sp[-2].array;
   600     int index = top.sp[-1].i32;
   601     top.sp[-2].i32 = array->readChar(index);
   602     top.sp--;
   603     break;
   604 }
   605 
   606 case OP_SETARRAY_I:
   607 {
   608     Array *array = top.sp[-3].array;
   609     int index = top.sp[-2].i32;
   610     array->writeInt32(index, top.sp[-1].i32);
   611     top.sp[-3] = top.sp[-1];
   612     top.sp -= 2;
   613     break;
   614 }
   615 
   616 case OP_SETARRAY_F:
   617 {
   618     Array *array = top.sp[-3].array;
   619     int index = top.sp[-2].i32;
   620     array->writeFloat(index, top.sp[-1].f);
   621     top.sp[-3] = top.sp[-1];
   622     top.sp -= 2;
   623     break;
   624 }
   625 
   626 case OP_SETARRAY_C:
   627 {
   628     Array *array = top.sp[-3].array;
   629     int index = top.sp[-2].i32;
   630     array->writeChar(index, top.sp[-1].i32);
   631     top.sp[-3] = top.sp[-1];
   632     top.sp -= 2;
   633     break;
   634 }
   635 
   636 case OP_GETARRAY_O:
   637 {
   638     Array *array = top.sp[-2].array;
   639     int index = top.sp[-1].i32;
   640     top.sp[-2].array = Array::cast(array->readObject(index));
   641     top.sp--;
   642     break;
   643 }
   644 
   645 case OP_CVT_I2F:
   646 {
   647     int ival = POP_I32(top);
   648     float fval = (float)ival;
   649     PUSH_F(top, fval);
   650     break;
   651 }
   652 
   653 case OP_NEWARRAY_LIFO:
   654 {
   655     Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc))));
   656     Array *array = GenerateArray(zone, map);
   657     if (!array)
   658         goto error;
   659     top.sp->obj = array;
   660     top.sp++;
   661     break;
   662 }
   663 
   664 case OP_SAVELIFO:
   665 {
   666     unsigned slot = READ_UINT32(top.pc);
   667     locals[slot].address = zone->heap().lifoPosition();
   668     break;
   669 }
   670 
   671 case OP_UNWINDLIFO:
   672 {
   673     unsigned slot = READ_UINT32(top.pc);
   674     zone->heap().unwindLifo(locals[slot].address);
   675     break;
   676 }
   677 
   678 case OP_VARREF_LIFO:
   679 {
   680     unsigned slot = READ_UINT32(top.pc);
   681     if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
   682         goto error;
   683     break;
   684 }
   685 
   686 case OP_ARGREF_LIFO:
   687 {
   688     unsigned slot = READ_UINT32(top.pc);
   689     if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
   690         goto error;
   691     break;
   692 }
   693 
   694 case OP_ARRAYREF_LIFO:
   695 {
   696     Local<Array> array(zone, top.sp[-2].array);
   697     Local<Reference> ref(zone, Reference::NewArray(zone, array, top.sp[-1].i32, Heap::Tenure_Stack));
   698     if (!ref)
   699         goto error;
   700     top.sp[-2].ref = ref;
   701     top.sp--;
   702     break;
   703 }
   704 
   705 case OP_SLOTREF_LIFO:
   706 {
   707     Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
   708     if (!ref)
   709         goto error;
   710     top.sp[-1].ref = ref;
   711     break;
   712 }
   713 
   714 case OP_GETREF_I:
   715 {
   716     top.sp[-1].i32 = top.sp[-1].ref->getInt();
   717     break;
   718 }
   719 
   720 case OP_SETREF_I:
   721 {
   722     top.sp[-2].ref->setInt(top.sp[-1].i32);
   723     top.sp[-2].i32 = top.sp[-1].i32;
   724     top.sp--;
   725     break;
   726 }
   727 
   728 case OP_GETREF_F:
   729 {
   730     top.sp[-1].f = top.sp[-1].ref->getFloat();
   731     break;
   732 }
   733 
   734 case OP_SETREF_F:
   735 {
   736     top.sp[-2].ref->setFloat(top.sp[-1].f);
   737     top.sp[-2].f = top.sp[-1].f;
   738     break;
   739 }
   740 
   741 case OP_OBJECT:
   742 {
   743     top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
   744     top.sp++;
   745     break;
   746 }
   747 
   748 case OP_ARRAYCOPY:
   749 {
   750     // Note for this assignment opcode, we return the left-hand side, not the
   751     // right, since in this case the result of the expression could be different.
   752     if (!CopyArray(zone, top.sp[-2].array, top.sp[-1].array))
   753         goto error;
   754     top.sp--;
   755     break;
   756 }
   757 
   758 case OP_DUP:
   759 {
   760     top.sp++;
   761     top.sp[-1] = top.sp[-2];
   762     break;
   763 }
   764 
   765 case OP_DUP2:
   766 {
   767     top.sp += 2;
   768     top.sp[-2] = top.sp[-4];
   769     top.sp[-1] = top.sp[-3];
   770     break;
   771 }
   772 
   773 case OP_SWAP:
   774 {
   775     LocalSlot slot = top.sp[-2];
   776     top.sp[-2] = top.sp[-1];
   777     top.sp[-1] = slot;
   778     break;
   779 }
   780 
   781 case OP_ROLL3:
   782 {
   783     LocalSlot slot = top.sp[-3];
   784     top.sp[-3] = top.sp[-2];
   785     top.sp[-2] = top.sp[-1];
   786     top.sp[-1] = slot;
   787     break;
   788 }
   789 
   790 case OP_PICK2:
   791 {
   792     top.sp++;
   793     top.sp[-1] = top.sp[-3];
   794     break;
   795 }
   796 
   797 case OP_PICK3:
   798 {
   799     top.sp++;
   800     top.sp[-1] = top.sp[-4];
   801     break;
   802 }
   803 
   804 case OP_CALLNATIVE:
   805 {
   806     unsigned index = READ_UINT32(top.pc);
   807     unsigned argc = READ_UINT32(top.pc + 4);
   808 
   809     Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
   810     if (!native->function()) {
   811         zone->reportError(Message_NativeNotBound, native->name()->chars());
   812         goto error;
   813     }
   814 
   815     int result;
   816     void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
   817     if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
   818         goto error;
   819 
   820     top.sp -= argc;
   821     PUSH_I32(top, result);
   822     break;
   823 }
   824 
   825 case OP_MODULE:
   826 {
   827     top.sp++;
   828     top.sp[-1].module = top.fp->code()->module();
   829     break;
   830 }
   831 
   832 case OP_GETMODULE_FN:
   833 {
   834     top.sp[-1].fun = top.sp[-1].module->getFunction(READ_UINT32(top.pc));
   835     break;
   836 }
   837 
   838 default:
   839     assert(false);
   840     return false;
   841 
   842         }
   843 
   844         top.pc += OpcodeInfo[op].length;
   845     }
   846 
   847 done:
   848     return true;
   849 
   850 error:
   851     // Unwind frames until we can continue.
   852     while (top.fp != entryFrame)
   853         zone->stack().popInlineFrame();
   854     return false;
   855 }