1.1 --- a/src/Interpreter.cpp Mon Jun 10 00:46:29 2013 +0100
1.2 +++ b/src/Interpreter.cpp Mon Jun 10 01:04:43 2013 +0100
1.3 @@ -1,1041 +1,1041 @@
1.4 -/* vim: set ts=4 sw=4 tw=99 et:
1.5 - *
1.6 - * Copyright (C) 2012 David Anderson
1.7 - *
1.8 - * This file is part of JITCraft.
1.9 - *
1.10 - * JITCraft is free software: you can redistribute it and/or modify it under
1.11 - * the terms of the GNU General Public License as published by the Free
1.12 - * Software Foundation, either version 3 of the License, or (at your option)
1.13 - * any later version.
1.14 - *
1.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
1.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
1.18 - *
1.19 - * You should have received a copy of the GNU General Public License along with
1.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
1.21 - */
1.22 -#include <string.h>
1.23 -#include "Interpreter.h"
1.24 -#include "Modules.h"
1.25 -#include "Zone.h"
1.26 -#include "Types.h"
1.27 -#include "Array.h"
1.28 -#include "Reference.h"
1.29 -#include "Strings.h"
1.30 -#include "Environments.h"
1.31 -#include "Structures.h"
1.32 -#include "NativeTable.h"
1.33 -#include "Packages.h"
1.34 -#include "Heap-inl.h"
1.35 -
1.36 -using namespace ke;
1.37 -
1.38 -#define PUSH_I32(top, value) \
1.39 - do { \
1.40 - top.sp->i32 = value; \
1.41 - top.sp++; \
1.42 - } while (0)
1.43 -
1.44 -#define PUSH_F(top, value) \
1.45 - do { \
1.46 - top.sp->f = value; \
1.47 - top.sp++; \
1.48 - } while (0)
1.49 -
1.50 -static inline int
1.51 -POP_I32(Top &top)
1.52 -{
1.53 - int value = top.sp[-1].i32;
1.54 - top.sp--;
1.55 - return value;
1.56 -}
1.57 -
1.58 -static inline float
1.59 -POP_F(Top &top)
1.60 -{
1.61 - float value = top.sp[-1].f;
1.62 - top.sp--;
1.63 - return value;
1.64 -}
1.65 -
1.66 -// Pawn's original semantics specify some kind of floor operation, so
1.67 -// (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses
1.68 -// the upstream algorithm when constant folding. However the SourcePawn 1 JIT
1.69 -// does not. My guess is that Borja freaked out seeing the 13-instruction x86
1.70 -// sequence necessary to get this functionality (I vaguely recall a thread
1.71 -// where we discussed this with Mark Peter? But the ITB forums are gone...),
1.72 -// and we just decided to break the damn thing. So SP1 was inconsistent, but
1.73 -// we are not. And for completeness, we assert that the C compiler does the
1.74 -// right thing, since C89 leaves it unspecified.
1.75 -STATIC_ASSERT(8 / -3 == -2);
1.76 -STATIC_ASSERT(-8 / 3 == -2);
1.77 -
1.78 -static inline bool
1.79 -PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
1.80 -{
1.81 - Reference *ref = Reference::NewStack(zone, location, tenure);
1.82 - if (!ref)
1.83 - return false;
1.84 - top.sp->ref = ref;
1.85 - top.sp++;
1.86 - return true;
1.87 -}
1.88 -
1.89 -static void
1.90 -GetElement(Array *array, int index, LocalSlot *vp)
1.91 -{
1.92 - if (array->type()->contained()->isTraceable()) {
1.93 - vp->obj = array->readObject(index);
1.94 - return;
1.95 - }
1.96 -
1.97 - switch (array->type()->contained()->pod()) {
1.98 - case PrimitiveType_Float:
1.99 - vp->f = array->readFloat(index);
1.100 - break;
1.101 -
1.102 - case PrimitiveType_Char:
1.103 - vp->i32 = array->readChar(index);
1.104 - break;
1.105 -
1.106 - default:
1.107 - assert(array->type()->contained()->pod() == PrimitiveType_Int32);
1.108 - vp->i32 = array->readInt32(index);
1.109 - break;
1.110 - }
1.111 -}
1.112 -
1.113 -static void
1.114 -SetElement(Zone *zone, Array *array, int index, const LocalSlot &v)
1.115 -{
1.116 - if (array->type()->contained()->isTraceable()) {
1.117 - array->writeObject(zone, index, v.obj);
1.118 - return;
1.119 - }
1.120 -
1.121 - switch (array->type()->contained()->pod()) {
1.122 - case PrimitiveType_Float:
1.123 - array->writeFloat(index, v.f);
1.124 - break;
1.125 -
1.126 - case PrimitiveType_Char:
1.127 - array->writeChar(index, v.i32);
1.128 - break;
1.129 -
1.130 - default:
1.131 - assert(array->type()->contained()->pod() == PrimitiveType_Int32);
1.132 - array->writeInt32(index, v.i32);
1.133 - break;
1.134 - }
1.135 -}
1.136 -
1.137 -static void
1.138 -FetchField(Struct *obj, Descriptor *desc, LocalSlot *vp)
1.139 -{
1.140 - // :TODO: assert no GC.
1.141 - if (desc->type()->isTraceable()) {
1.142 - vp->obj = obj->get<Object *>(desc);
1.143 - return;
1.144 - }
1.145 -
1.146 - switch (desc->type()->pod()) {
1.147 - case PrimitiveType_Float:
1.148 - vp->f = obj->get<float>(desc);
1.149 - break;
1.150 -
1.151 - default:
1.152 - assert(desc->type()->pod() == PrimitiveType_Int32);
1.153 - vp->i32 = obj->get<int>(desc);
1.154 - break;
1.155 - }
1.156 -}
1.157 -
1.158 -static void
1.159 -GetField(Struct *obj, unsigned index, LocalSlot *vp)
1.160 -{
1.161 - StructType *type = StructType::cast(obj->map()->type());
1.162 - Descriptor *desc = Descriptor::cast(type->fields()->at(index));
1.163 - FetchField(obj, desc, vp);
1.164 -}
1.165 -
1.166 -static void
1.167 -GetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot *vp)
1.168 -{
1.169 - Local<StructType> type(zone, StructType::cast(obj->map()->type()));
1.170 - Local<Descriptor> desc(zone, type->lookupField(name, NULL));
1.171 - FetchField(obj, desc, vp);
1.172 -}
1.173 -
1.174 -static void
1.175 -StoreField(Zone *zone, Struct *obj, Descriptor *desc, const LocalSlot &v)
1.176 -{
1.177 - // :TODO: assert no GC.
1.178 - if (desc->type()->isTraceable()) {
1.179 - obj->set(zone, desc, v.obj);
1.180 - return;
1.181 - }
1.182 -
1.183 - switch (desc->type()->pod()) {
1.184 - case PrimitiveType_Float:
1.185 - obj->set<float>(desc, v.f);
1.186 - break;
1.187 -
1.188 - default:
1.189 - assert(desc->type()->pod() == PrimitiveType_Int32);
1.190 - obj->set<int>(desc, v.i32);
1.191 - break;
1.192 - }
1.193 -}
1.194 -
1.195 -static void
1.196 -SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
1.197 -{
1.198 - StructType *type = StructType::cast(obj->map()->type());
1.199 - Descriptor *desc = Descriptor::cast(type->fields()->at(index));
1.200 - StoreField(zone, obj, desc, v);
1.201 -}
1.202 -
1.203 -static void
1.204 -SetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot &v)
1.205 -{
1.206 - Local<StructType> type(zone, StructType::cast(obj->map()->type()));
1.207 - Local<Descriptor> desc(zone, type->lookupField(name, NULL));
1.208 - StoreField(zone, obj, desc, v);
1.209 -}
1.210 -
1.211 -static bool
1.212 -InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
1.213 - int *result)
1.214 -{
1.215 - NativeArgs guard;
1.216 -
1.217 - void *address = zone->nativeTable()->address(native->index());
1.218 - if (!address) {
1.219 - Local<String> name(zone, zone->nativeTable()->name(native->index()));
1.220 - zone->reportError(Message_NativeNotBound, name->chars());
1.221 - return false;
1.222 - }
1.223 -
1.224 - if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
1.225 - return false;
1.226 -
1.227 - intptr_t *cells = guard.args();
1.228 -
1.229 - // params[0] == argc, in ISPE
1.230 - cells[0] = argc;
1.231 -
1.232 - // Pass the formal arguments.
1.233 - Local<FunctionType> type(zone, native->type());
1.234 - Local<Type> param(zone);
1.235 - for (unsigned i = 0; i < type->parameters()->length(); i++) {
1.236 - param = type->parameterAt(i);
1.237 -
1.238 - // For floats, we rely on the aliasing of |i32| and |f|.
1.239 - LocalSlot &arg = args[-int(i) - 1];
1.240 - if (param->isInt32() || param->isFloat()) {
1.241 - cells[i + 1] = arg.i32;
1.242 - } else if (param->isReference()) {
1.243 - cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
1.244 - } else {
1.245 - assert(param->isArray());
1.246 - cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
1.247 - }
1.248 - }
1.249 -
1.250 - // For variadic arguments, the compiler left either arrays or references.
1.251 - for (unsigned i = type->parameters()->length(); i < argc; i++) {
1.252 - LocalSlot &arg = args[-int(i) - 1];
1.253 -
1.254 - if (arg.obj->is(MapKind_Reference)) {
1.255 - cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
1.256 - } else {
1.257 - assert(arg.obj->is(MapKind_Array));
1.258 - cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
1.259 - }
1.260 - }
1.261 -
1.262 - typedef intptr_t (*INVOKE)(void *, intptr_t *);
1.263 - INVOKE invoke = (INVOKE)address;
1.264 - *result = invoke(identity, cells);
1.265 -
1.266 - return !zone->hasPendingException();
1.267 -}
1.268 -
1.269 -bool
1.270 -ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
1.271 -{
1.272 - Top &top = *zone->stack().top();
1.273 - if (!entryFrame)
1.274 - entryFrame = top.fp;
1.275 -
1.276 - LocalSlot *locals = entryFrame->locals();
1.277 -
1.278 - for (;;) {
1.279 - Opcode op = Opcode(*top.pc);
1.280 -
1.281 - if (OpcodeInfo[op].nuses > 0)
1.282 - assert(top.sp - OpcodeInfo[op].nuses >= top.fp->stackBase());
1.283 -
1.284 - switch (op) {
1.285 -
1.286 -case OP_NOP:
1.287 - break;
1.288 -
1.289 -case OP_INT:
1.290 - PUSH_I32(top, READ_INT32(top.pc));
1.291 - break;
1.292 -
1.293 -case OP_FLOAT:
1.294 - PUSH_F(top, READ_FLOAT(top.pc));
1.295 - break;
1.296 -
1.297 -case OP_RETURN:
1.298 -case OP_RETURNVOID:
1.299 -case OP_STOP:
1.300 -{
1.301 - if (op == OP_RETURN)
1.302 - *result = *--top.sp;
1.303 -
1.304 - if (top.fp == entryFrame)
1.305 - goto done;
1.306 -
1.307 - // This must not GC.
1.308 - zone->stack().popInlineFrame();
1.309 - locals = top.fp->locals();
1.310 -
1.311 - if (op == OP_RETURN)
1.312 - *top.sp++ = *result;
1.313 -
1.314 - top.pc += OpcodeInfo[*top.pc].length;
1.315 - continue;
1.316 -}
1.317 -
1.318 -case OP_POP:
1.319 -{
1.320 - top.sp--;
1.321 - break;
1.322 -}
1.323 -
1.324 -case OP_JT:
1.325 -{
1.326 - int value = POP_I32(top);
1.327 - if (value) {
1.328 - top.pc += READ_INT32(top.pc);
1.329 - continue;
1.330 - }
1.331 - break;
1.332 -}
1.333 -
1.334 -case OP_JF:
1.335 -{
1.336 - int value = POP_I32(top);
1.337 - if (!value) {
1.338 - top.pc += READ_INT32(top.pc);
1.339 - continue;
1.340 - }
1.341 - break;
1.342 -}
1.343 -
1.344 -case OP_JUMP:
1.345 -{
1.346 - top.pc += READ_INT32(top.pc);
1.347 - continue;
1.348 -}
1.349 -
1.350 -case OP_BREAK:
1.351 -case OP_CONTINUE:
1.352 -{
1.353 - top.fp->leaveLoop(zone);
1.354 - top.pc += READ_INT32(top.pc);
1.355 - continue;
1.356 -}
1.357 -
1.358 -case OP_GETLOCAL:
1.359 -{
1.360 - unsigned slot = READ_UINT32(top.pc);
1.361 - assert(slot < top.fp->code()->nlocals());
1.362 - *top.sp++ = locals[slot];
1.363 - break;
1.364 -}
1.365 -
1.366 -case OP_SETLOCAL:
1.367 -{
1.368 - unsigned slot = READ_UINT32(top.pc);
1.369 - assert(slot < top.fp->code()->nlocals());
1.370 - locals[slot] = top.sp[-1];
1.371 - break;
1.372 -}
1.373 -
1.374 -case OP_ADD:
1.375 -{
1.376 - top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
1.377 - top.sp--;
1.378 - break;
1.379 -}
1.380 -
1.381 -case OP_SUB:
1.382 -{
1.383 - top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
1.384 - top.sp--;
1.385 - break;
1.386 -}
1.387 -
1.388 -case OP_MUL:
1.389 -{
1.390 - top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
1.391 - top.sp--;
1.392 - break;
1.393 -}
1.394 -
1.395 -case OP_DIV:
1.396 -{
1.397 - if (top.sp[-1].i32 == 0) {
1.398 - zone->reportError(Message_IntegerDivideByZero);
1.399 - goto error;
1.400 - }
1.401 - top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
1.402 - top.sp--;
1.403 - break;
1.404 -}
1.405 -
1.406 -case OP_MOD:
1.407 -{
1.408 - if (top.sp[-1].i32 == 0) {
1.409 - zone->reportError(Message_IntegerDivideByZero);
1.410 - goto error;
1.411 - }
1.412 - top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
1.413 - top.sp--;
1.414 - break;
1.415 -}
1.416 -
1.417 -case OP_LT:
1.418 -{
1.419 - top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
1.420 - top.sp--;
1.421 - break;
1.422 -}
1.423 -
1.424 -case OP_LE:
1.425 -{
1.426 - top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
1.427 - top.sp--;
1.428 - break;
1.429 -}
1.430 -
1.431 -case OP_GT:
1.432 -{
1.433 - top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
1.434 - top.sp--;
1.435 - break;
1.436 -}
1.437 -
1.438 -case OP_GE:
1.439 -{
1.440 - top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
1.441 - top.sp--;
1.442 - break;
1.443 -}
1.444 -
1.445 -case OP_EQ:
1.446 -{
1.447 - top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
1.448 - top.sp--;
1.449 - break;
1.450 -}
1.451 -
1.452 -case OP_NE:
1.453 -{
1.454 - top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
1.455 - top.sp--;
1.456 - break;
1.457 -}
1.458 -
1.459 -case OP_ADD_F:
1.460 -{
1.461 - top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
1.462 - top.sp--;
1.463 - break;
1.464 -}
1.465 -
1.466 -case OP_SUB_F:
1.467 -{
1.468 - top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
1.469 - top.sp--;
1.470 - break;
1.471 -}
1.472 -
1.473 -case OP_MUL_F:
1.474 -{
1.475 - top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
1.476 - top.sp--;
1.477 - break;
1.478 -}
1.479 -
1.480 -case OP_DIV_F:
1.481 -{
1.482 - top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
1.483 - top.sp--;
1.484 - break;
1.485 -}
1.486 -
1.487 -case OP_LT_F:
1.488 -{
1.489 - top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
1.490 - top.sp--;
1.491 - break;
1.492 -}
1.493 -
1.494 -case OP_LE_F:
1.495 -{
1.496 - top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
1.497 - top.sp--;
1.498 - break;
1.499 -}
1.500 -
1.501 -case OP_GT_F:
1.502 -{
1.503 - top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
1.504 - top.sp--;
1.505 - break;
1.506 -}
1.507 -
1.508 -case OP_GE_F:
1.509 -{
1.510 - top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
1.511 - top.sp--;
1.512 - break;
1.513 -}
1.514 -
1.515 -case OP_EQ_F:
1.516 -{
1.517 - top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
1.518 - top.sp--;
1.519 - break;
1.520 -}
1.521 -
1.522 -case OP_NE_F:
1.523 -{
1.524 - top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
1.525 - top.sp--;
1.526 - break;
1.527 -}
1.528 -
1.529 -case OP_SHL:
1.530 -{
1.531 - top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
1.532 - top.sp--;
1.533 - break;
1.534 -}
1.535 -
1.536 -case OP_SHR:
1.537 -{
1.538 - top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
1.539 - top.sp--;
1.540 - break;
1.541 -}
1.542 -
1.543 -case OP_USHR:
1.544 -{
1.545 - top.sp[-2].i32 = unsigned(top.sp[-2].i32) >> unsigned(top.sp[-1].i32);
1.546 - top.sp--;
1.547 - break;
1.548 -}
1.549 -
1.550 -case OP_BITAND:
1.551 -{
1.552 - top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
1.553 - top.sp--;
1.554 - break;
1.555 -}
1.556 -
1.557 -case OP_BITOR:
1.558 -{
1.559 - top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
1.560 - top.sp--;
1.561 - break;
1.562 -}
1.563 -
1.564 -case OP_BITXOR:
1.565 -{
1.566 - top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
1.567 - top.sp--;
1.568 - break;
1.569 -}
1.570 -
1.571 -case OP_BITNOT:
1.572 -{
1.573 - top.sp[-1].i32 = ~top.sp[-1].i32;
1.574 - break;
1.575 -}
1.576 -
1.577 -case OP_NOT:
1.578 -{
1.579 - top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
1.580 - break;
1.581 -}
1.582 -
1.583 -case OP_NOT_F:
1.584 -{
1.585 - top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
1.586 - break;
1.587 -}
1.588 -
1.589 -case OP_NEG:
1.590 -{
1.591 - top.sp[-1].i32 = -top.sp[-1].i32;
1.592 - break;
1.593 -}
1.594 -
1.595 -case OP_NEG_F:
1.596 -{
1.597 - top.sp[-1].f = -top.sp[-1].f;
1.598 - break;
1.599 -}
1.600 -
1.601 -case OP_CALL:
1.602 -{
1.603 - Local<Function> newFun(zone, Function::cast(top.sp[-1].obj));
1.604 - top.sp--;
1.605 -
1.606 - if (!zone->stack().pushInlineFrame(newFun))
1.607 - goto error;
1.608 -
1.609 - locals = top.fp->locals();
1.610 - continue;
1.611 -}
1.612 -
1.613 -case OP_GETARG:
1.614 -{
1.615 - unsigned slot = READ_UINT32(top.pc);
1.616 - *top.sp++ = top.fp->arg(slot);
1.617 - break;
1.618 -}
1.619 -
1.620 -case OP_SETARG:
1.621 -{
1.622 - unsigned slot = READ_UINT32(top.pc);
1.623 - top.fp->arg(slot) = top.sp[-1];
1.624 - break;
1.625 -}
1.626 -
1.627 -case OP_GETELEM:
1.628 -{
1.629 - Array *array = Array::cast(top.sp[-2].obj);
1.630 - int index = top.sp[-1].i32;
1.631 -
1.632 - if (index < 0 || unsigned(index) >= array->length()) {
1.633 - zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
1.634 - goto error;
1.635 - }
1.636 -
1.637 - GetElement(array, index, &top.sp[-2]);
1.638 - top.sp--;
1.639 - break;
1.640 -}
1.641 -
1.642 -case OP_SETELEM:
1.643 -{
1.644 - Array *array = Array::cast(top.sp[-3].obj);
1.645 - int index = top.sp[-2].i32;
1.646 -
1.647 - if (index < 0 || unsigned(index) >= array->length()) {
1.648 - zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
1.649 - goto error;
1.650 - }
1.651 -
1.652 - SetElement(zone, array, index, top.sp[-1]);
1.653 - top.sp[-3] = top.sp[-1];
1.654 - top.sp -= 2;
1.655 - break;
1.656 -}
1.657 -
1.658 -case OP_CVT_I2F:
1.659 -{
1.660 - int ival = POP_I32(top);
1.661 - float fval = (float)ival;
1.662 - PUSH_F(top, fval);
1.663 - break;
1.664 -}
1.665 -
1.666 -case OP_CVT_I2B:
1.667 -{
1.668 - top.sp[-1].i32 = !!top.sp[-1].i32;
1.669 - break;
1.670 -}
1.671 -
1.672 -case OP_DUPARRAY:
1.673 -{
1.674 - Local<Array> src(zone, Array::cast(top.sp[-1].obj));
1.675 - top.sp[-1].obj = Array::DeepCopy(zone, src, Heap::Tenure_Default);
1.676 - if (!top.sp[-1].obj)
1.677 - goto error;
1.678 - break;
1.679 -}
1.680 -
1.681 -case OP_NEWFIXED:
1.682 -{
1.683 - Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
1.684 - Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
1.685 - Array *array = Array::NewFixed(zone, map, tenure);
1.686 - if (!array)
1.687 - goto error;
1.688 - top.sp->obj = array;
1.689 - top.sp++;
1.690 - break;
1.691 -}
1.692 -
1.693 -case OP_NEWEMPTY:
1.694 -{
1.695 - Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
1.696 - Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
1.697 - Array *array = Array::NewEmpty(zone, map, tenure);
1.698 - if (!array)
1.699 - goto error;
1.700 - top.sp->obj = array;
1.701 - top.sp++;
1.702 - break;
1.703 -}
1.704 -
1.705 -case OP_NEWSIZED:
1.706 -{
1.707 - Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
1.708 - Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
1.709 - assert(map->type()->levels() < MAX_ARRAY_DEPTH);
1.710 -
1.711 - int dims[MAX_ARRAY_DEPTH];
1.712 - for (unsigned i = map->type()->levels() - 1; i < map->type()->levels(); i--)
1.713 - dims[i] = POP_I32(top);
1.714 -
1.715 - Array *array = Array::NewSized(zone, map, dims, tenure);
1.716 - if (!array)
1.717 - goto error;
1.718 - top.sp->obj = array;
1.719 - top.sp++;
1.720 - break;
1.721 -}
1.722 -
1.723 -case OP_NEWSTRUCT:
1.724 -{
1.725 - Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
1.726 - Local<StructMap> map(zone, StructMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
1.727 - top.sp->obj = Struct::New(zone, map, tenure);
1.728 - if (!top.sp->obj)
1.729 - goto error;
1.730 - top.sp++;
1.731 - break;
1.732 -}
1.733 -
1.734 -case OP_SAVELIFO:
1.735 -{
1.736 - unsigned slot = READ_UINT32(top.pc);
1.737 - locals[slot].address = zone->heap().lifoPosition();
1.738 - break;
1.739 -}
1.740 -
1.741 -case OP_UNWINDLIFO:
1.742 -{
1.743 - unsigned slot = READ_UINT32(top.pc);
1.744 - zone->heap().unwindLifo(locals[slot].address);
1.745 - break;
1.746 -}
1.747 -
1.748 -case OP_VARREF_LIFO:
1.749 -{
1.750 - unsigned slot = READ_UINT32(top.pc);
1.751 - if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
1.752 - goto error;
1.753 - break;
1.754 -}
1.755 -
1.756 -case OP_ARGREF_LIFO:
1.757 -{
1.758 - unsigned slot = READ_UINT32(top.pc);
1.759 - if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
1.760 - goto error;
1.761 - break;
1.762 -}
1.763 -
1.764 -case OP_SLOTREF_LIFO:
1.765 -{
1.766 - Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
1.767 - if (!ref)
1.768 - goto error;
1.769 - top.sp[-1].ref = ref;
1.770 - break;
1.771 -}
1.772 -
1.773 -case OP_GETREF_I:
1.774 -{
1.775 - top.sp[-1].i32 = top.sp[-1].ref->getInt();
1.776 - break;
1.777 -}
1.778 -
1.779 -case OP_SETREF_I:
1.780 -{
1.781 - top.sp[-2].ref->setInt(top.sp[-1].i32);
1.782 - top.sp[-2].i32 = top.sp[-1].i32;
1.783 - top.sp--;
1.784 - break;
1.785 -}
1.786 -
1.787 -case OP_GETREF_F:
1.788 -{
1.789 - top.sp[-1].f = top.sp[-1].ref->getFloat();
1.790 - break;
1.791 -}
1.792 -
1.793 -case OP_SETREF_F:
1.794 -{
1.795 - top.sp[-2].ref->setFloat(top.sp[-1].f);
1.796 - top.sp[-2].f = top.sp[-1].f;
1.797 - break;
1.798 -}
1.799 -
1.800 -case OP_OBJECT:
1.801 -{
1.802 - top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
1.803 - top.sp++;
1.804 - break;
1.805 -}
1.806 -
1.807 -case OP_COPYARRAY:
1.808 -{
1.809 - // Note for this assignment opcode, we return the left-hand side, not the
1.810 - // right, since in this case the result of the expression could be different.
1.811 - Local<Array> left(zone, Array::cast(top.sp[-2].array));
1.812 - Local<Array> right(zone, Array::cast(top.sp[-1].array));
1.813 - if (!Array::ShallowCopy(zone, left, right))
1.814 - goto error;
1.815 - top.sp--;
1.816 - break;
1.817 -}
1.818 -
1.819 -case OP_DUP:
1.820 -{
1.821 - top.sp++;
1.822 - top.sp[-1] = top.sp[-2];
1.823 - break;
1.824 -}
1.825 -
1.826 -case OP_DUP2:
1.827 -{
1.828 - top.sp += 2;
1.829 - top.sp[-2] = top.sp[-4];
1.830 - top.sp[-1] = top.sp[-3];
1.831 - break;
1.832 -}
1.833 -
1.834 -case OP_SWAP:
1.835 -{
1.836 - LocalSlot slot = top.sp[-2];
1.837 - top.sp[-2] = top.sp[-1];
1.838 - top.sp[-1] = slot;
1.839 - break;
1.840 -}
1.841 -
1.842 -case OP_ROLL3:
1.843 -{
1.844 - LocalSlot slot = top.sp[-3];
1.845 - top.sp[-3] = top.sp[-2];
1.846 - top.sp[-2] = top.sp[-1];
1.847 - top.sp[-1] = slot;
1.848 - break;
1.849 -}
1.850 -
1.851 -case OP_PICK2:
1.852 -{
1.853 - top.sp++;
1.854 - top.sp[-1] = top.sp[-3];
1.855 - break;
1.856 -}
1.857 -
1.858 -case OP_PICK3:
1.859 -{
1.860 - top.sp++;
1.861 - top.sp[-1] = top.sp[-4];
1.862 - break;
1.863 -}
1.864 -
1.865 -case OP_CALLNATIVE:
1.866 -{
1.867 - unsigned argc = READ_UINT32(top.pc);
1.868 -
1.869 - Local<Native> native(zone, Native::cast(top.sp[-1].obj));
1.870 - top.sp--;
1.871 -
1.872 - int result;
1.873 - void *nativeIdentity = top.fp->code()->module()->parent()->getNativeIdentity();
1.874 - if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
1.875 - goto error;
1.876 -
1.877 - top.sp -= argc;
1.878 - PUSH_I32(top, result);
1.879 - break;
1.880 -}
1.881 -
1.882 -case OP_BITCAST:
1.883 -{
1.884 - // Because the stack is a union, this is a no-op.
1.885 - break;
1.886 -}
1.887 -
1.888 -case OP_TRUE:
1.889 -{
1.890 - top.sp++;
1.891 - top.sp[-1].i32 = 1;
1.892 - break;
1.893 -}
1.894 -
1.895 -case OP_FALSE:
1.896 -{
1.897 - top.sp++;
1.898 - top.sp[-1].i32 = 0;
1.899 - break;
1.900 -}
1.901 -
1.902 -case OP_GETFIELD:
1.903 -{
1.904 - Struct *obj;
1.905 - if (top.sp[-1].obj->is(MapKind_Module))
1.906 - obj = Module::cast(top.sp[-1].obj)->globals();
1.907 - else
1.908 - obj = Struct::cast(top.sp[-1].obj);
1.909 - GetField(obj, READ_UINT32(top.pc), &top.sp[-1]);
1.910 - break;
1.911 -}
1.912 -
1.913 -case OP_SETFIELD:
1.914 -{
1.915 - Struct *obj = Struct::cast(top.sp[-2].obj);
1.916 - SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]);
1.917 - top.sp[-2] = top.sp[-1];
1.918 - top.sp--;
1.919 - break;
1.920 -}
1.921 -
1.922 -case OP_COPYSTRUCT:
1.923 -{
1.924 - Local<Struct> left(zone, Struct::cast(top.sp[-2].obj));
1.925 - Local<Struct> right(zone, Struct::cast(top.sp[-1].obj));
1.926 - if (!Struct::Copy(zone, left, right))
1.927 - goto error;
1.928 - top.sp[-2].obj = top.sp[-1].obj;
1.929 - top.sp--;
1.930 - break;
1.931 -}
1.932 -
1.933 -case OP_TABLESWITCH:
1.934 -{
1.935 - int value = top.sp[-1].i32;
1.936 - int low = READ_TABLESWITCH_LOW(top.pc);
1.937 - int high = READ_TABLESWITCH_HIGH(top.pc);
1.938 -
1.939 - top.sp--;
1.940 -
1.941 - unsigned index = unsigned(value - low);
1.942 - unsigned tablesize = TableSwitchEntries(low, high);
1.943 - if (index < tablesize) {
1.944 - top.pc += OP_TABLESWITCH_LENGTH + OP_JUMP_LENGTH;
1.945 - top.pc += index * OP_JUMP_LENGTH;
1.946 - continue;
1.947 - }
1.948 - break;
1.949 -}
1.950 -
1.951 -case OP_SIZEOF:
1.952 -{
1.953 - Array *array = Array::cast(top.sp[-1].obj);
1.954 - top.sp[-1].i32 = array->length();
1.955 - break;
1.956 -}
1.957 -
1.958 -case OP_PUBLIC:
1.959 -{
1.960 - Local<Function> fun(zone, Function::cast(top.sp[-1].obj));
1.961 - zone->registerPublic(fun);
1.962 - top.sp--;
1.963 - break;
1.964 -}
1.965 -
1.966 -case OP_SETGLOBAL:
1.967 -{
1.968 - Local<Code> code(zone, top.fp->code());
1.969 - Local<Struct> obj(zone, code->module()->globals());
1.970 - Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
1.971 - SetGlobal(zone, obj, name, top.sp[-1]);
1.972 - break;
1.973 -}
1.974 -
1.975 -case OP_GETGLOBAL:
1.976 -{
1.977 - Local<Code> code(zone, top.fp->code());
1.978 - Local<Struct> obj(zone, code->module()->globals());
1.979 - Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
1.980 - GetGlobal(zone, obj, name, top.sp);
1.981 - top.sp++;
1.982 - break;
1.983 -}
1.984 -
1.985 -case OP_ENTERLOOP:
1.986 -{
1.987 - top.fp->enterLoop(zone);
1.988 - break;
1.989 -}
1.990 -
1.991 -case OP_LEAVELOOP:
1.992 -{
1.993 - top.fp->leaveLoop(zone);
1.994 - break;
1.995 -}
1.996 -
1.997 -case OP_DEPARRAY:
1.998 -{
1.999 - Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->object(READ_UINT32(top.pc))));
1.1000 - Local<Array> array(zone, Array::cast(top.sp[-2].obj));
1.1001 - int index = top.sp[-1].i32;
1.1002 -
1.1003 - // We allow taking 0-length dependent arrays.
1.1004 - if (index < 0 || unsigned(index) > array->length()) {
1.1005 - zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
1.1006 - goto error;
1.1007 - }
1.1008 -
1.1009 - top.sp[-2].obj = DependentArray::New(zone, array, map, index);
1.1010 - if (!top.sp[-2].obj)
1.1011 - goto error;
1.1012 -
1.1013 - top.sp--;
1.1014 - break;
1.1015 -}
1.1016 -
1.1017 -case OP_IMPORT:
1.1018 -{
1.1019 - unsigned index = READ_UINT32(top.pc);
1.1020 -
1.1021 - top.sp++;
1.1022 - top.sp[-1].obj = top.fp->code()->module()->getImportAt(index);
1.1023 - break;
1.1024 -}
1.1025 -
1.1026 -default:
1.1027 - assert(false);
1.1028 - return false;
1.1029 -
1.1030 - }
1.1031 -
1.1032 - top.pc += OpcodeInfo[op].length;
1.1033 - assert(top.sp >= top.fp->stackBase());
1.1034 - }
1.1035 -
1.1036 -done:
1.1037 - return true;
1.1038 -
1.1039 -error:
1.1040 - // Unwind frames until we can continue.
1.1041 - while (top.fp != entryFrame)
1.1042 - zone->stack().popInlineFrame();
1.1043 - return false;
1.1044 -}
1.1045 +/* vim: set ts=4 sw=4 tw=99 et:
1.1046 + *
1.1047 + * Copyright (C) 2012 David Anderson
1.1048 + *
1.1049 + * This file is part of JITCraft.
1.1050 + *
1.1051 + * JITCraft is free software: you can redistribute it and/or modify it under
1.1052 + * the terms of the GNU General Public License as published by the Free
1.1053 + * Software Foundation, either version 3 of the License, or (at your option)
1.1054 + * any later version.
1.1055 + *
1.1056 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
1.1057 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.1058 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
1.1059 + *
1.1060 + * You should have received a copy of the GNU General Public License along with
1.1061 + * JITCraft. If not, see http://www.gnu.org/licenses/.
1.1062 + */
1.1063 +#include <string.h>
1.1064 +#include "Interpreter.h"
1.1065 +#include "Modules.h"
1.1066 +#include "Zone.h"
1.1067 +#include "Types.h"
1.1068 +#include "Array.h"
1.1069 +#include "Reference.h"
1.1070 +#include "Strings.h"
1.1071 +#include "Environments.h"
1.1072 +#include "Structures.h"
1.1073 +#include "NativeTable.h"
1.1074 +#include "Packages.h"
1.1075 +#include "Heap-inl.h"
1.1076 +
1.1077 +using namespace ke;
1.1078 +
1.1079 +#define PUSH_I32(top, value) \
1.1080 + do { \
1.1081 + top.sp->i32 = value; \
1.1082 + top.sp++; \
1.1083 + } while (0)
1.1084 +
1.1085 +#define PUSH_F(top, value) \
1.1086 + do { \
1.1087 + top.sp->f = value; \
1.1088 + top.sp++; \
1.1089 + } while (0)
1.1090 +
1.1091 +static inline int
1.1092 +POP_I32(Top &top)
1.1093 +{
1.1094 + int value = top.sp[-1].i32;
1.1095 + top.sp--;
1.1096 + return value;
1.1097 +}
1.1098 +
1.1099 +static inline float
1.1100 +POP_F(Top &top)
1.1101 +{
1.1102 + float value = top.sp[-1].f;
1.1103 + top.sp--;
1.1104 + return value;
1.1105 +}
1.1106 +
1.1107 +// Pawn's original semantics specify some kind of floor operation, so
1.1108 +// (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses
1.1109 +// the upstream algorithm when constant folding. However the SourcePawn 1 JIT
1.1110 +// does not. My guess is that Borja freaked out seeing the 13-instruction x86
1.1111 +// sequence necessary to get this functionality (I vaguely recall a thread
1.1112 +// where we discussed this with Mark Peter? But the ITB forums are gone...),
1.1113 +// and we just decided to break the damn thing. So SP1 was inconsistent, but
1.1114 +// we are not. And for completeness, we assert that the C compiler does the
1.1115 +// right thing, since C89 leaves it unspecified.
1.1116 +STATIC_ASSERT(8 / -3 == -2);
1.1117 +STATIC_ASSERT(-8 / 3 == -2);
1.1118 +
1.1119 +static inline bool
1.1120 +PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
1.1121 +{
1.1122 + Reference *ref = Reference::NewStack(zone, location, tenure);
1.1123 + if (!ref)
1.1124 + return false;
1.1125 + top.sp->ref = ref;
1.1126 + top.sp++;
1.1127 + return true;
1.1128 +}
1.1129 +
1.1130 +static void
1.1131 +GetElement(Array *array, int index, LocalSlot *vp)
1.1132 +{
1.1133 + if (array->type()->contained()->isTraceable()) {
1.1134 + vp->obj = array->readObject(index);
1.1135 + return;
1.1136 + }
1.1137 +
1.1138 + switch (array->type()->contained()->pod()) {
1.1139 + case PrimitiveType_Float:
1.1140 + vp->f = array->readFloat(index);
1.1141 + break;
1.1142 +
1.1143 + case PrimitiveType_Char:
1.1144 + vp->i32 = array->readChar(index);
1.1145 + break;
1.1146 +
1.1147 + default:
1.1148 + assert(array->type()->contained()->pod() == PrimitiveType_Int32);
1.1149 + vp->i32 = array->readInt32(index);
1.1150 + break;
1.1151 + }
1.1152 +}
1.1153 +
1.1154 +static void
1.1155 +SetElement(Zone *zone, Array *array, int index, const LocalSlot &v)
1.1156 +{
1.1157 + if (array->type()->contained()->isTraceable()) {
1.1158 + array->writeObject(zone, index, v.obj);
1.1159 + return;
1.1160 + }
1.1161 +
1.1162 + switch (array->type()->contained()->pod()) {
1.1163 + case PrimitiveType_Float:
1.1164 + array->writeFloat(index, v.f);
1.1165 + break;
1.1166 +
1.1167 + case PrimitiveType_Char:
1.1168 + array->writeChar(index, v.i32);
1.1169 + break;
1.1170 +
1.1171 + default:
1.1172 + assert(array->type()->contained()->pod() == PrimitiveType_Int32);
1.1173 + array->writeInt32(index, v.i32);
1.1174 + break;
1.1175 + }
1.1176 +}
1.1177 +
1.1178 +static void
1.1179 +FetchField(Struct *obj, Descriptor *desc, LocalSlot *vp)
1.1180 +{
1.1181 + // :TODO: assert no GC.
1.1182 + if (desc->type()->isTraceable()) {
1.1183 + vp->obj = obj->get<Object *>(desc);
1.1184 + return;
1.1185 + }
1.1186 +
1.1187 + switch (desc->type()->pod()) {
1.1188 + case PrimitiveType_Float:
1.1189 + vp->f = obj->get<float>(desc);
1.1190 + break;
1.1191 +
1.1192 + default:
1.1193 + assert(desc->type()->pod() == PrimitiveType_Int32);
1.1194 + vp->i32 = obj->get<int>(desc);
1.1195 + break;
1.1196 + }
1.1197 +}
1.1198 +
1.1199 +static void
1.1200 +GetField(Struct *obj, unsigned index, LocalSlot *vp)
1.1201 +{
1.1202 + StructType *type = StructType::cast(obj->map()->type());
1.1203 + Descriptor *desc = Descriptor::cast(type->fields()->at(index));
1.1204 + FetchField(obj, desc, vp);
1.1205 +}
1.1206 +
1.1207 +static void
1.1208 +GetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot *vp)
1.1209 +{
1.1210 + Local<StructType> type(zone, StructType::cast(obj->map()->type()));
1.1211 + Local<Descriptor> desc(zone, type->lookupField(name, NULL));
1.1212 + FetchField(obj, desc, vp);
1.1213 +}
1.1214 +
1.1215 +static void
1.1216 +StoreField(Zone *zone, Struct *obj, Descriptor *desc, const LocalSlot &v)
1.1217 +{
1.1218 + // :TODO: assert no GC.
1.1219 + if (desc->type()->isTraceable()) {
1.1220 + obj->set(zone, desc, v.obj);
1.1221 + return;
1.1222 + }
1.1223 +
1.1224 + switch (desc->type()->pod()) {
1.1225 + case PrimitiveType_Float:
1.1226 + obj->set<float>(desc, v.f);
1.1227 + break;
1.1228 +
1.1229 + default:
1.1230 + assert(desc->type()->pod() == PrimitiveType_Int32);
1.1231 + obj->set<int>(desc, v.i32);
1.1232 + break;
1.1233 + }
1.1234 +}
1.1235 +
1.1236 +static void
1.1237 +SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
1.1238 +{
1.1239 + StructType *type = StructType::cast(obj->map()->type());
1.1240 + Descriptor *desc = Descriptor::cast(type->fields()->at(index));
1.1241 + StoreField(zone, obj, desc, v);
1.1242 +}
1.1243 +
1.1244 +static void
1.1245 +SetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot &v)
1.1246 +{
1.1247 + Local<StructType> type(zone, StructType::cast(obj->map()->type()));
1.1248 + Local<Descriptor> desc(zone, type->lookupField(name, NULL));
1.1249 + StoreField(zone, obj, desc, v);
1.1250 +}
1.1251 +
1.1252 +static bool
1.1253 +InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
1.1254 + int *result)
1.1255 +{
1.1256 + NativeArgs guard;
1.1257 +
1.1258 + void *address = zone->nativeTable()->address(native->index());
1.1259 + if (!address) {
1.1260 + Local<String> name(zone, zone->nativeTable()->name(native->index()));
1.1261 + zone->reportError(Message_NativeNotBound, name->chars());
1.1262 + return false;
1.1263 + }
1.1264 +
1.1265 + if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
1.1266 + return false;
1.1267 +
1.1268 + intptr_t *cells = guard.args();
1.1269 +
1.1270 + // params[0] == argc, in ISPE
1.1271 + cells[0] = argc;
1.1272 +
1.1273 + // Pass the formal arguments.
1.1274 + Local<FunctionType> type(zone, native->type());
1.1275 + Local<Type> param(zone);
1.1276 + for (unsigned i = 0; i < type->parameters()->length(); i++) {
1.1277 + param = type->parameterAt(i);
1.1278 +
1.1279 + // For floats, we rely on the aliasing of |i32| and |f|.
1.1280 + LocalSlot &arg = args[-int(i) - 1];
1.1281 + if (param->isInt32() || param->isFloat()) {
1.1282 + cells[i + 1] = arg.i32;
1.1283 + } else if (param->isReference()) {
1.1284 + cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
1.1285 + } else {
1.1286 + assert(param->isArray());
1.1287 + cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
1.1288 + }
1.1289 + }
1.1290 +
1.1291 + // For variadic arguments, the compiler left either arrays or references.
1.1292 + for (unsigned i = type->parameters()->length(); i < argc; i++) {
1.1293 + LocalSlot &arg = args[-int(i) - 1];
1.1294 +
1.1295 + if (arg.obj->is(MapKind_Reference)) {
1.1296 + cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
1.1297 + } else {
1.1298 + assert(arg.obj->is(MapKind_Array));
1.1299 + cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
1.1300 + }
1.1301 + }
1.1302 +
1.1303 + typedef intptr_t (*INVOKE)(void *, intptr_t *);
1.1304 + INVOKE invoke = (INVOKE)address;
1.1305 + *result = invoke(identity, cells);
1.1306 +
1.1307 + return !zone->hasPendingException();
1.1308 +}
1.1309 +
1.1310 +bool
1.1311 +ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
1.1312 +{
1.1313 + Top &top = *zone->stack().top();
1.1314 + if (!entryFrame)
1.1315 + entryFrame = top.fp;
1.1316 +
1.1317 + LocalSlot *locals = entryFrame->locals();
1.1318 +
1.1319 + for (;;) {
1.1320 + Opcode op = Opcode(*top.pc);
1.1321 +
1.1322 + if (OpcodeInfo[op].nuses > 0)
1.1323 + assert(top.sp - OpcodeInfo[op].nuses >= top.fp->stackBase());
1.1324 +
1.1325 + switch (op) {
1.1326 +
1.1327 +case OP_NOP:
1.1328 + break;
1.1329 +
1.1330 +case OP_INT:
1.1331 + PUSH_I32(top, READ_INT32(top.pc));
1.1332 + break;
1.1333 +
1.1334 +case OP_FLOAT:
1.1335 + PUSH_F(top, READ_FLOAT(top.pc));
1.1336 + break;
1.1337 +
1.1338 +case OP_RETURN:
1.1339 +case OP_RETURNVOID:
1.1340 +case OP_STOP:
1.1341 +{
1.1342 + if (op == OP_RETURN)
1.1343 + *result = *--top.sp;
1.1344 +
1.1345 + if (top.fp == entryFrame)
1.1346 + goto done;
1.1347 +
1.1348 + // This must not GC.
1.1349 + zone->stack().popInlineFrame();
1.1350 + locals = top.fp->locals();
1.1351 +
1.1352 + if (op == OP_RETURN)
1.1353 + *top.sp++ = *result;
1.1354 +
1.1355 + top.pc += OpcodeInfo[*top.pc].length;
1.1356 + continue;
1.1357 +}
1.1358 +
1.1359 +case OP_POP:
1.1360 +{
1.1361 + top.sp--;
1.1362 + break;
1.1363 +}
1.1364 +
1.1365 +case OP_JT:
1.1366 +{
1.1367 + int value = POP_I32(top);
1.1368 + if (value) {
1.1369 + top.pc += READ_INT32(top.pc);
1.1370 + continue;
1.1371 + }
1.1372 + break;
1.1373 +}
1.1374 +
1.1375 +case OP_JF:
1.1376 +{
1.1377 + int value = POP_I32(top);
1.1378 + if (!value) {
1.1379 + top.pc += READ_INT32(top.pc);
1.1380 + continue;
1.1381 + }
1.1382 + break;
1.1383 +}
1.1384 +
1.1385 +case OP_JUMP:
1.1386 +{
1.1387 + top.pc += READ_INT32(top.pc);
1.1388 + continue;
1.1389 +}
1.1390 +
1.1391 +case OP_BREAK:
1.1392 +case OP_CONTINUE:
1.1393 +{
1.1394 + top.fp->leaveLoop(zone);
1.1395 + top.pc += READ_INT32(top.pc);
1.1396 + continue;
1.1397 +}
1.1398 +
1.1399 +case OP_GETLOCAL:
1.1400 +{
1.1401 + unsigned slot = READ_UINT32(top.pc);
1.1402 + assert(slot < top.fp->code()->nlocals());
1.1403 + *top.sp++ = locals[slot];
1.1404 + break;
1.1405 +}
1.1406 +
1.1407 +case OP_SETLOCAL:
1.1408 +{
1.1409 + unsigned slot = READ_UINT32(top.pc);
1.1410 + assert(slot < top.fp->code()->nlocals());
1.1411 + locals[slot] = top.sp[-1];
1.1412 + break;
1.1413 +}
1.1414 +
1.1415 +case OP_ADD:
1.1416 +{
1.1417 + top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
1.1418 + top.sp--;
1.1419 + break;
1.1420 +}
1.1421 +
1.1422 +case OP_SUB:
1.1423 +{
1.1424 + top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
1.1425 + top.sp--;
1.1426 + break;
1.1427 +}
1.1428 +
1.1429 +case OP_MUL:
1.1430 +{
1.1431 + top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
1.1432 + top.sp--;
1.1433 + break;
1.1434 +}
1.1435 +
1.1436 +case OP_DIV:
1.1437 +{
1.1438 + if (top.sp[-1].i32 == 0) {
1.1439 + zone->reportError(Message_IntegerDivideByZero);
1.1440 + goto error;
1.1441 + }
1.1442 + top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
1.1443 + top.sp--;
1.1444 + break;
1.1445 +}
1.1446 +
1.1447 +case OP_MOD:
1.1448 +{
1.1449 + if (top.sp[-1].i32 == 0) {
1.1450 + zone->reportError(Message_IntegerDivideByZero);
1.1451 + goto error;
1.1452 + }
1.1453 + top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
1.1454 + top.sp--;
1.1455 + break;
1.1456 +}
1.1457 +
1.1458 +case OP_LT:
1.1459 +{
1.1460 + top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
1.1461 + top.sp--;
1.1462 + break;
1.1463 +}
1.1464 +
1.1465 +case OP_LE:
1.1466 +{
1.1467 + top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
1.1468 + top.sp--;
1.1469 + break;
1.1470 +}
1.1471 +
1.1472 +case OP_GT:
1.1473 +{
1.1474 + top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
1.1475 + top.sp--;
1.1476 + break;
1.1477 +}
1.1478 +
1.1479 +case OP_GE:
1.1480 +{
1.1481 + top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
1.1482 + top.sp--;
1.1483 + break;
1.1484 +}
1.1485 +
1.1486 +case OP_EQ:
1.1487 +{
1.1488 + top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
1.1489 + top.sp--;
1.1490 + break;
1.1491 +}
1.1492 +
1.1493 +case OP_NE:
1.1494 +{
1.1495 + top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
1.1496 + top.sp--;
1.1497 + break;
1.1498 +}
1.1499 +
1.1500 +case OP_ADD_F:
1.1501 +{
1.1502 + top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
1.1503 + top.sp--;
1.1504 + break;
1.1505 +}
1.1506 +
1.1507 +case OP_SUB_F:
1.1508 +{
1.1509 + top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
1.1510 + top.sp--;
1.1511 + break;
1.1512 +}
1.1513 +
1.1514 +case OP_MUL_F:
1.1515 +{
1.1516 + top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
1.1517 + top.sp--;
1.1518 + break;
1.1519 +}
1.1520 +
1.1521 +case OP_DIV_F:
1.1522 +{
1.1523 + top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
1.1524 + top.sp--;
1.1525 + break;
1.1526 +}
1.1527 +
1.1528 +case OP_LT_F:
1.1529 +{
1.1530 + top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
1.1531 + top.sp--;
1.1532 + break;
1.1533 +}
1.1534 +
1.1535 +case OP_LE_F:
1.1536 +{
1.1537 + top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
1.1538 + top.sp--;
1.1539 + break;
1.1540 +}
1.1541 +
1.1542 +case OP_GT_F:
1.1543 +{
1.1544 + top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
1.1545 + top.sp--;
1.1546 + break;
1.1547 +}
1.1548 +
1.1549 +case OP_GE_F:
1.1550 +{
1.1551 + top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
1.1552 + top.sp--;
1.1553 + break;
1.1554 +}
1.1555 +
1.1556 +case OP_EQ_F:
1.1557 +{
1.1558 + top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
1.1559 + top.sp--;
1.1560 + break;
1.1561 +}
1.1562 +
1.1563 +case OP_NE_F:
1.1564 +{
1.1565 + top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
1.1566 + top.sp--;
1.1567 + break;
1.1568 +}
1.1569 +
1.1570 +case OP_SHL:
1.1571 +{
1.1572 + top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
1.1573 + top.sp--;
1.1574 + break;
1.1575 +}
1.1576 +
1.1577 +case OP_SHR:
1.1578 +{
1.1579 + top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
1.1580 + top.sp--;
1.1581 + break;
1.1582 +}
1.1583 +
1.1584 +case OP_USHR:
1.1585 +{
1.1586 + top.sp[-2].i32 = unsigned(top.sp[-2].i32) >> unsigned(top.sp[-1].i32);
1.1587 + top.sp--;
1.1588 + break;
1.1589 +}
1.1590 +
1.1591 +case OP_BITAND:
1.1592 +{
1.1593 + top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
1.1594 + top.sp--;
1.1595 + break;
1.1596 +}
1.1597 +
1.1598 +case OP_BITOR:
1.1599 +{
1.1600 + top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
1.1601 + top.sp--;
1.1602 + break;
1.1603 +}
1.1604 +
1.1605 +case OP_BITXOR:
1.1606 +{
1.1607 + top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
1.1608 + top.sp--;
1.1609 + break;
1.1610 +}
1.1611 +
1.1612 +case OP_BITNOT:
1.1613 +{
1.1614 + top.sp[-1].i32 = ~top.sp[-1].i32;
1.1615 + break;
1.1616 +}
1.1617 +
1.1618 +case OP_NOT:
1.1619 +{
1.1620 + top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
1.1621 + break;
1.1622 +}
1.1623 +
1.1624 +case OP_NOT_F:
1.1625 +{
1.1626 + top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
1.1627 + break;
1.1628 +}
1.1629 +
1.1630 +case OP_NEG:
1.1631 +{
1.1632 + top.sp[-1].i32 = -top.sp[-1].i32;
1.1633 + break;
1.1634 +}
1.1635 +
1.1636 +case OP_NEG_F:
1.1637 +{
1.1638 + top.sp[-1].f = -top.sp[-1].f;
1.1639 + break;
1.1640 +}
1.1641 +
1.1642 +case OP_CALL:
1.1643 +{
1.1644 + Local<Function> newFun(zone, Function::cast(top.sp[-1].obj));
1.1645 + top.sp--;
1.1646 +
1.1647 + if (!zone->stack().pushInlineFrame(newFun))
1.1648 + goto error;
1.1649 +
1.1650 + locals = top.fp->locals();
1.1651 + continue;
1.1652 +}
1.1653 +
1.1654 +case OP_GETARG:
1.1655 +{
1.1656 + unsigned slot = READ_UINT32(top.pc);
1.1657 + *top.sp++ = top.fp->arg(slot);
1.1658 + break;
1.1659 +}
1.1660 +
1.1661 +case OP_SETARG:
1.1662 +{
1.1663 + unsigned slot = READ_UINT32(top.pc);
1.1664 + top.fp->arg(slot) = top.sp[-1];
1.1665 + break;
1.1666 +}
1.1667 +
1.1668 +case OP_GETELEM:
1.1669 +{
1.1670 + Array *array = Array::cast(top.sp[-2].obj);
1.1671 + int index = top.sp[-1].i32;
1.1672 +
1.1673 + if (index < 0 || unsigned(index) >= array->length()) {
1.1674 + zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
1.1675 + goto error;
1.1676 + }
1.1677 +
1.1678 + GetElement(array, index, &top.sp[-2]);
1.1679 + top.sp--;
1.1680 + break;
1.1681 +}
1.1682 +
1.1683 +case OP_SETELEM:
1.1684 +{
1.1685 + Array *array = Array::cast(top.sp[-3].obj);
1.1686 + int index = top.sp[-2].i32;
1.1687 +
1.1688 + if (index < 0 || unsigned(index) >= array->length()) {
1.1689 + zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
1.1690 + goto error;
1.1691 + }
1.1692 +
1.1693 + SetElement(zone, array, index, top.sp[-1]);
1.1694 + top.sp[-3] = top.sp[-1];
1.1695 + top.sp -= 2;
1.1696 + break;
1.1697 +}
1.1698 +
1.1699 +case OP_CVT_I2F:
1.1700 +{
1.1701 + int ival = POP_I32(top);
1.1702 + float fval = (float)ival;
1.1703 + PUSH_F(top, fval);
1.1704 + break;
1.1705 +}
1.1706 +
1.1707 +case OP_CVT_I2B:
1.1708 +{
1.1709 + top.sp[-1].i32 = !!top.sp[-1].i32;
1.1710 + break;
1.1711 +}
1.1712 +
1.1713 +case OP_DUPARRAY:
1.1714 +{
1.1715 + Local<Array> src(zone, Array::cast(top.sp[-1].obj));
1.1716 + top.sp[-1].obj = Array::DeepCopy(zone, src, Heap::Tenure_Default);
1.1717 + if (!top.sp[-1].obj)
1.1718 + goto error;
1.1719 + break;
1.1720 +}
1.1721 +
1.1722 +case OP_NEWFIXED:
1.1723 +{
1.1724 + Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
1.1725 + Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
1.1726 + Array *array = Array::NewFixed(zone, map, tenure);
1.1727 + if (!array)
1.1728 + goto error;
1.1729 + top.sp->obj = array;
1.1730 + top.sp++;
1.1731 + break;
1.1732 +}
1.1733 +
1.1734 +case OP_NEWEMPTY:
1.1735 +{
1.1736 + Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
1.1737 + Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
1.1738 + Array *array = Array::NewEmpty(zone, map, tenure);
1.1739 + if (!array)
1.1740 + goto error;
1.1741 + top.sp->obj = array;
1.1742 + top.sp++;
1.1743 + break;
1.1744 +}
1.1745 +
1.1746 +case OP_NEWSIZED:
1.1747 +{
1.1748 + Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
1.1749 + Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
1.1750 + assert(map->type()->levels() < MAX_ARRAY_DEPTH);
1.1751 +
1.1752 + int dims[MAX_ARRAY_DEPTH];
1.1753 + for (unsigned i = map->type()->levels() - 1; i < map->type()->levels(); i--)
1.1754 + dims[i] = POP_I32(top);
1.1755 +
1.1756 + Array *array = Array::NewSized(zone, map, dims, tenure);
1.1757 + if (!array)
1.1758 + goto error;
1.1759 + top.sp->obj = array;
1.1760 + top.sp++;
1.1761 + break;
1.1762 +}
1.1763 +
1.1764 +case OP_NEWSTRUCT:
1.1765 +{
1.1766 + Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
1.1767 + Local<StructMap> map(zone, StructMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
1.1768 + top.sp->obj = Struct::New(zone, map, tenure);
1.1769 + if (!top.sp->obj)
1.1770 + goto error;
1.1771 + top.sp++;
1.1772 + break;
1.1773 +}
1.1774 +
1.1775 +case OP_SAVELIFO:
1.1776 +{
1.1777 + unsigned slot = READ_UINT32(top.pc);
1.1778 + locals[slot].address = zone->heap().lifoPosition();
1.1779 + break;
1.1780 +}
1.1781 +
1.1782 +case OP_UNWINDLIFO:
1.1783 +{
1.1784 + unsigned slot = READ_UINT32(top.pc);
1.1785 + zone->heap().unwindLifo(locals[slot].address);
1.1786 + break;
1.1787 +}
1.1788 +
1.1789 +case OP_VARREF_LIFO:
1.1790 +{
1.1791 + unsigned slot = READ_UINT32(top.pc);
1.1792 + if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
1.1793 + goto error;
1.1794 + break;
1.1795 +}
1.1796 +
1.1797 +case OP_ARGREF_LIFO:
1.1798 +{
1.1799 + unsigned slot = READ_UINT32(top.pc);
1.1800 + if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
1.1801 + goto error;
1.1802 + break;
1.1803 +}
1.1804 +
1.1805 +case OP_SLOTREF_LIFO:
1.1806 +{
1.1807 + Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
1.1808 + if (!ref)
1.1809 + goto error;
1.1810 + top.sp[-1].ref = ref;
1.1811 + break;
1.1812 +}
1.1813 +
1.1814 +case OP_GETREF_I:
1.1815 +{
1.1816 + top.sp[-1].i32 = top.sp[-1].ref->getInt();
1.1817 + break;
1.1818 +}
1.1819 +
1.1820 +case OP_SETREF_I:
1.1821 +{
1.1822 + top.sp[-2].ref->setInt(top.sp[-1].i32);
1.1823 + top.sp[-2].i32 = top.sp[-1].i32;
1.1824 + top.sp--;
1.1825 + break;
1.1826 +}
1.1827 +
1.1828 +case OP_GETREF_F:
1.1829 +{
1.1830 + top.sp[-1].f = top.sp[-1].ref->getFloat();
1.1831 + break;
1.1832 +}
1.1833 +
1.1834 +case OP_SETREF_F:
1.1835 +{
1.1836 + top.sp[-2].ref->setFloat(top.sp[-1].f);
1.1837 + top.sp[-2].f = top.sp[-1].f;
1.1838 + break;
1.1839 +}
1.1840 +
1.1841 +case OP_OBJECT:
1.1842 +{
1.1843 + top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
1.1844 + top.sp++;
1.1845 + break;
1.1846 +}
1.1847 +
1.1848 +case OP_COPYARRAY:
1.1849 +{
1.1850 + // Note for this assignment opcode, we return the left-hand side, not the
1.1851 + // right, since in this case the result of the expression could be different.
1.1852 + Local<Array> left(zone, Array::cast(top.sp[-2].array));
1.1853 + Local<Array> right(zone, Array::cast(top.sp[-1].array));
1.1854 + if (!Array::ShallowCopy(zone, left, right))
1.1855 + goto error;
1.1856 + top.sp--;
1.1857 + break;
1.1858 +}
1.1859 +
1.1860 +case OP_DUP:
1.1861 +{
1.1862 + top.sp++;
1.1863 + top.sp[-1] = top.sp[-2];
1.1864 + break;
1.1865 +}
1.1866 +
1.1867 +case OP_DUP2:
1.1868 +{
1.1869 + top.sp += 2;
1.1870 + top.sp[-2] = top.sp[-4];
1.1871 + top.sp[-1] = top.sp[-3];
1.1872 + break;
1.1873 +}
1.1874 +
1.1875 +case OP_SWAP:
1.1876 +{
1.1877 + LocalSlot slot = top.sp[-2];
1.1878 + top.sp[-2] = top.sp[-1];
1.1879 + top.sp[-1] = slot;
1.1880 + break;
1.1881 +}
1.1882 +
1.1883 +case OP_ROLL3:
1.1884 +{
1.1885 + LocalSlot slot = top.sp[-3];
1.1886 + top.sp[-3] = top.sp[-2];
1.1887 + top.sp[-2] = top.sp[-1];
1.1888 + top.sp[-1] = slot;
1.1889 + break;
1.1890 +}
1.1891 +
1.1892 +case OP_PICK2:
1.1893 +{
1.1894 + top.sp++;
1.1895 + top.sp[-1] = top.sp[-3];
1.1896 + break;
1.1897 +}
1.1898 +
1.1899 +case OP_PICK3:
1.1900 +{
1.1901 + top.sp++;
1.1902 + top.sp[-1] = top.sp[-4];
1.1903 + break;
1.1904 +}
1.1905 +
1.1906 +case OP_CALLNATIVE:
1.1907 +{
1.1908 + unsigned argc = READ_UINT32(top.pc);
1.1909 +
1.1910 + Local<Native> native(zone, Native::cast(top.sp[-1].obj));
1.1911 + top.sp--;
1.1912 +
1.1913 + int result;
1.1914 + void *nativeIdentity = top.fp->code()->module()->parent()->getNativeIdentity();
1.1915 + if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
1.1916 + goto error;
1.1917 +
1.1918 + top.sp -= argc;
1.1919 + PUSH_I32(top, result);
1.1920 + break;
1.1921 +}
1.1922 +
1.1923 +case OP_BITCAST:
1.1924 +{
1.1925 + // Because the stack is a union, this is a no-op.
1.1926 + break;
1.1927 +}
1.1928 +
1.1929 +case OP_TRUE:
1.1930 +{
1.1931 + top.sp++;
1.1932 + top.sp[-1].i32 = 1;
1.1933 + break;
1.1934 +}
1.1935 +
1.1936 +case OP_FALSE:
1.1937 +{
1.1938 + top.sp++;
1.1939 + top.sp[-1].i32 = 0;
1.1940 + break;
1.1941 +}
1.1942 +
1.1943 +case OP_GETFIELD:
1.1944 +{
1.1945 + Struct *obj;
1.1946 + if (top.sp[-1].obj->is(MapKind_Module))
1.1947 + obj = Module::cast(top.sp[-1].obj)->globals();
1.1948 + else
1.1949 + obj = Struct::cast(top.sp[-1].obj);
1.1950 + GetField(obj, READ_UINT32(top.pc), &top.sp[-1]);
1.1951 + break;
1.1952 +}
1.1953 +
1.1954 +case OP_SETFIELD:
1.1955 +{
1.1956 + Struct *obj = Struct::cast(top.sp[-2].obj);
1.1957 + SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]);
1.1958 + top.sp[-2] = top.sp[-1];
1.1959 + top.sp--;
1.1960 + break;
1.1961 +}
1.1962 +
1.1963 +case OP_COPYSTRUCT:
1.1964 +{
1.1965 + Local<Struct> left(zone, Struct::cast(top.sp[-2].obj));
1.1966 + Local<Struct> right(zone, Struct::cast(top.sp[-1].obj));
1.1967 + if (!Struct::Copy(zone, left, right))
1.1968 + goto error;
1.1969 + top.sp[-2].obj = top.sp[-1].obj;
1.1970 + top.sp--;
1.1971 + break;
1.1972 +}
1.1973 +
1.1974 +case OP_TABLESWITCH:
1.1975 +{
1.1976 + int value = top.sp[-1].i32;
1.1977 + int low = READ_TABLESWITCH_LOW(top.pc);
1.1978 + int high = READ_TABLESWITCH_HIGH(top.pc);
1.1979 +
1.1980 + top.sp--;
1.1981 +
1.1982 + unsigned index = unsigned(value - low);
1.1983 + unsigned tablesize = TableSwitchEntries(low, high);
1.1984 + if (index < tablesize) {
1.1985 + top.pc += OP_TABLESWITCH_LENGTH + OP_JUMP_LENGTH;
1.1986 + top.pc += index * OP_JUMP_LENGTH;
1.1987 + continue;
1.1988 + }
1.1989 + break;
1.1990 +}
1.1991 +
1.1992 +case OP_SIZEOF:
1.1993 +{
1.1994 + Array *array = Array::cast(top.sp[-1].obj);
1.1995 + top.sp[-1].i32 = array->length();
1.1996 + break;
1.1997 +}
1.1998 +
1.1999 +case OP_PUBLIC:
1.2000 +{
1.2001 + Local<Function> fun(zone, Function::cast(top.sp[-1].obj));
1.2002 + zone->registerPublic(fun);
1.2003 + top.sp--;
1.2004 + break;
1.2005 +}
1.2006 +
1.2007 +case OP_SETGLOBAL:
1.2008 +{
1.2009 + Local<Code> code(zone, top.fp->code());
1.2010 + Local<Struct> obj(zone, code->module()->globals());
1.2011 + Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
1.2012 + SetGlobal(zone, obj, name, top.sp[-1]);
1.2013 + break;
1.2014 +}
1.2015 +
1.2016 +case OP_GETGLOBAL:
1.2017 +{
1.2018 + Local<Code> code(zone, top.fp->code());
1.2019 + Local<Struct> obj(zone, code->module()->globals());
1.2020 + Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
1.2021 + GetGlobal(zone, obj, name, top.sp);
1.2022 + top.sp++;
1.2023 + break;
1.2024 +}
1.2025 +
1.2026 +case OP_ENTERLOOP:
1.2027 +{
1.2028 + top.fp->enterLoop(zone);
1.2029 + break;
1.2030 +}
1.2031 +
1.2032 +case OP_LEAVELOOP:
1.2033 +{
1.2034 + top.fp->leaveLoop(zone);
1.2035 + break;
1.2036 +}
1.2037 +
1.2038 +case OP_DEPARRAY:
1.2039 +{
1.2040 + Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->object(READ_UINT32(top.pc))));
1.2041 + Local<Array> array(zone, Array::cast(top.sp[-2].obj));
1.2042 + int index = top.sp[-1].i32;
1.2043 +
1.2044 + // We allow taking 0-length dependent arrays.
1.2045 + if (index < 0 || unsigned(index) > array->length()) {
1.2046 + zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
1.2047 + goto error;
1.2048 + }
1.2049 +
1.2050 + top.sp[-2].obj = DependentArray::New(zone, array, map, index);
1.2051 + if (!top.sp[-2].obj)
1.2052 + goto error;
1.2053 +
1.2054 + top.sp--;
1.2055 + break;
1.2056 +}
1.2057 +
1.2058 +case OP_IMPORT:
1.2059 +{
1.2060 + unsigned index = READ_UINT32(top.pc);
1.2061 +
1.2062 + top.sp++;
1.2063 + top.sp[-1].obj = top.fp->code()->module()->getImportAt(index);
1.2064 + break;
1.2065 +}
1.2066 +
1.2067 +default:
1.2068 + assert(false);
1.2069 + return false;
1.2070 +
1.2071 + }
1.2072 +
1.2073 + top.pc += OpcodeInfo[op].length;
1.2074 + assert(top.sp >= top.fp->stackBase());
1.2075 + }
1.2076 +
1.2077 +done:
1.2078 + return true;
1.2079 +
1.2080 +error:
1.2081 + // Unwind frames until we can continue.
1.2082 + while (top.fp != entryFrame)
1.2083 + zone->stack().popInlineFrame();
1.2084 + return false;
1.2085 +}