dvander@39: /* vim: set ts=4 sw=4 tw=99 et: dvander@39: * dvander@0: * Copyright (C) 2012 David Anderson dvander@0: * dvander@0: * This file is part of JITCraft. dvander@0: * dvander@0: * JITCraft is free software: you can redistribute it and/or modify it under dvander@0: * the terms of the GNU General Public License as published by the Free dvander@0: * Software Foundation, either version 3 of the License, or (at your option) dvander@0: * any later version. dvander@0: * dvander@0: * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY dvander@0: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@0: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@0: * dvander@0: * You should have received a copy of the GNU General Public License along with dvander@0: * JITCraft. If not, see http://www.gnu.org/licenses/. dvander@0: */ danderson@91: #include dvander@0: #include "Interpreter.h" dvander@0: #include "Modules.h" dvander@0: #include "Zone.h" dvander@0: #include "Types.h" dvander@12: #include "Array.h" dvander@14: #include "Reference.h" dvander@69: #include "Strings.h" dvander@85: #include "Environments.h" dvander@147: #include "Structures.h" dvander@195: #include "NativeTable.h" dvander@28: #include "Heap-inl.h" dvander@0: dvander@59: using namespace ke; dvander@0: dvander@0: #define PUSH_I32(top, value) \ dvander@0: do { \ dvander@0: top.sp->i32 = value; \ dvander@0: top.sp++; \ dvander@0: } while (0) dvander@0: dvander@4: #define PUSH_F(top, value) \ dvander@4: do { \ dvander@4: top.sp->f = value; \ dvander@4: top.sp++; \ dvander@4: } while (0) dvander@4: dvander@0: static inline int dvander@0: POP_I32(Top &top) dvander@0: { dvander@0: int value = top.sp[-1].i32; dvander@0: top.sp--; dvander@0: return value; dvander@0: } dvander@0: dvander@4: static inline float dvander@4: POP_F(Top &top) dvander@4: { dvander@4: float value = top.sp[-1].f; dvander@4: top.sp--; dvander@4: return value; dvander@4: } dvander@4: dvander@77: // Pawn's original semantics specify some kind of floor operation, so dvander@77: // (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses dvander@77: // the upstream algorithm when constant folding. However the SourcePawn 1 JIT dvander@77: // does not. My guess is that Borja freaked out seeing the 13-instruction x86 dvander@77: // sequence necessary to get this functionality (I vaguely recall a thread dvander@77: // where we discussed this with Mark Peter? But the ITB forums are gone...), dvander@77: // and we just decided to break the damn thing. So SP1 was inconsistent, but dvander@77: // we are not. And for completeness, we assert that the C compiler does the dvander@77: // right thing, since C89 leaves it unspecified. dvander@77: STATIC_ASSERT(8 / -3 == -2); dvander@77: STATIC_ASSERT(-8 / 3 == -2); dvander@77: dvander@0: static inline bool dvander@14: PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure) dvander@14: { dvander@14: Reference *ref = Reference::NewStack(zone, location, tenure); dvander@14: if (!ref) dvander@14: return false; dvander@14: top.sp->ref = ref; dvander@14: top.sp++; dvander@14: return true; dvander@14: } dvander@14: dvander@152: static void dvander@157: GetElement(Array *array, int index, LocalSlot *vp) dvander@157: { dvander@157: if (array->type()->contained()->isTraceable()) { dvander@157: vp->obj = array->readObject(index); dvander@157: return; dvander@157: } dvander@157: dvander@157: switch (array->type()->contained()->pod()) { dvander@157: case PrimitiveType_Float: dvander@157: vp->f = array->readFloat(index); dvander@157: break; dvander@157: dvander@157: case PrimitiveType_Char: dvander@157: vp->i32 = array->readChar(index); dvander@157: break; dvander@157: dvander@157: default: dvander@157: assert(array->type()->contained()->pod() == PrimitiveType_Int32); dvander@157: vp->i32 = array->readInt32(index); dvander@157: break; dvander@157: } dvander@157: } dvander@157: dvander@157: static void dvander@157: SetElement(Zone *zone, Array *array, int index, const LocalSlot &v) dvander@157: { dvander@157: if (array->type()->contained()->isTraceable()) { dvander@157: array->writeObject(zone, index, v.obj); dvander@157: return; dvander@157: } dvander@157: dvander@157: switch (array->type()->contained()->pod()) { dvander@157: case PrimitiveType_Float: dvander@157: array->writeFloat(index, v.f); dvander@157: break; dvander@157: dvander@157: case PrimitiveType_Char: dvander@157: array->writeChar(index, v.i32); dvander@157: break; dvander@157: dvander@157: default: dvander@157: assert(array->type()->contained()->pod() == PrimitiveType_Int32); dvander@157: array->writeInt32(index, v.i32); dvander@157: break; dvander@157: } dvander@157: } dvander@157: dvander@157: static void dvander@196: FetchField(Struct *obj, Descriptor *desc, LocalSlot *vp) dvander@152: { dvander@152: // :TODO: assert no GC. dvander@152: if (desc->type()->isTraceable()) { dvander@152: vp->obj = obj->get(desc); dvander@157: return; dvander@157: } dvander@152: dvander@157: switch (desc->type()->pod()) { dvander@157: case PrimitiveType_Float: dvander@157: vp->f = obj->get(desc); dvander@157: break; dvander@157: dvander@157: default: dvander@157: assert(desc->type()->pod() == PrimitiveType_Int32); dvander@157: vp->i32 = obj->get(desc); dvander@157: break; dvander@152: } dvander@152: } dvander@152: dvander@152: static void dvander@152: GetField(Struct *obj, unsigned index, LocalSlot *vp) dvander@152: { dvander@195: StructType *type = StructType::cast(obj->map()->type()); dvander@195: Descriptor *desc = Descriptor::cast(type->fields()->at(index)); dvander@196: FetchField(obj, desc, vp); dvander@195: } dvander@195: dvander@195: static void dvander@195: GetGlobal(Zone *zone, Handle obj, Handle name, LocalSlot *vp) dvander@195: { dvander@195: Local type(zone, StructType::cast(obj->map()->type())); dvander@195: Local desc(zone, type->lookupField(name, NULL)); dvander@196: FetchField(obj, desc, vp); dvander@152: } dvander@152: dvander@152: static void dvander@196: StoreField(Zone *zone, Struct *obj, Descriptor *desc, const LocalSlot &v) dvander@152: { dvander@152: // :TODO: assert no GC. dvander@152: if (desc->type()->isTraceable()) { dvander@152: obj->set(zone, desc, v.obj); dvander@157: return; dvander@157: } dvander@152: dvander@157: switch (desc->type()->pod()) { dvander@157: case PrimitiveType_Float: dvander@157: obj->set(desc, v.f); dvander@157: break; dvander@157: dvander@157: default: dvander@157: assert(desc->type()->pod() == PrimitiveType_Int32); dvander@157: obj->set(desc, v.i32); dvander@157: break; dvander@152: } dvander@152: } dvander@152: dvander@152: static void dvander@152: SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v) dvander@152: { dvander@195: StructType *type = StructType::cast(obj->map()->type()); dvander@195: Descriptor *desc = Descriptor::cast(type->fields()->at(index)); dvander@196: StoreField(zone, obj, desc, v); dvander@195: } dvander@195: dvander@195: static void dvander@195: SetGlobal(Zone *zone, Handle obj, Handle name, LocalSlot &v) dvander@195: { dvander@195: Local type(zone, StructType::cast(obj->map()->type())); dvander@195: Local desc(zone, type->lookupField(name, NULL)); dvander@196: StoreField(zone, obj, desc, v); dvander@152: } dvander@152: dvander@68: static bool dvander@68: InvokeNative(Zone *zone, Handle native, void *identity, LocalSlot *args, unsigned argc, dvander@68: int *result) dvander@68: { dvander@68: NativeArgs guard; dvander@68: dvander@195: void *address = zone->nativeTable()->address(native->index()); dvander@195: if (!address) { dvander@195: Local name(zone, zone->nativeTable()->name(native->index())); dvander@195: zone->reportError(Message_NativeNotBound, name->chars()); dvander@195: return false; dvander@195: } dvander@195: dvander@68: if (!zone->stack().pushNativeFrame(native, guard, argc + 1)) dvander@68: return false; dvander@68: dvander@68: intptr_t *cells = guard.args(); dvander@68: dvander@68: // params[0] == argc, in ISPE dvander@68: cells[0] = argc; dvander@68: dvander@68: // Pass the formal arguments. dvander@195: Local type(zone, native->type()); dvander@68: Local param(zone); dvander@68: for (unsigned i = 0; i < type->parameters()->length(); i++) { dvander@68: param = type->parameterAt(i); dvander@68: dvander@68: // For floats, we rely on the aliasing of |i32| and |f|. dvander@68: LocalSlot &arg = args[-int(i) - 1]; dvander@68: if (param->isInt32() || param->isFloat()) { dvander@68: cells[i + 1] = arg.i32; dvander@68: } else if (param->isReference()) { dvander@68: cells[i + 1] = reinterpret_cast(arg.ref->location()); dvander@68: } else { dvander@68: assert(param->isArray()); dvander@188: cells[i + 1] = reinterpret_cast(arg.array->bytes()); dvander@68: } dvander@68: } dvander@68: dvander@68: // For variadic arguments, the compiler left either arrays or references. dvander@68: for (unsigned i = type->parameters()->length(); i < argc; i++) { dvander@68: LocalSlot &arg = args[-int(i) - 1]; dvander@68: dvander@68: if (arg.obj->is(MapKind_Reference)) { dvander@68: cells[i + 1] = reinterpret_cast(arg.ref->location()); dvander@68: } else { dvander@68: assert(arg.obj->is(MapKind_Array)); dvander@188: cells[i + 1] = reinterpret_cast(arg.array->bytes()); dvander@68: } dvander@68: } dvander@68: dvander@68: typedef intptr_t (*INVOKE)(void *, intptr_t *); dvander@195: INVOKE invoke = (INVOKE)address; dvander@68: *result = invoke(identity, cells); dvander@68: dvander@69: return !zone->hasPendingException(); dvander@68: } dvander@68: dvander@0: bool dvander@59: ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result) dvander@0: { dvander@42: Top &top = *zone->stack().top(); dvander@69: if (!entryFrame) dvander@69: entryFrame = top.fp; dvander@69: dvander@47: LocalSlot *locals = entryFrame->locals(); dvander@0: dvander@0: for (;;) { dvander@0: Opcode op = Opcode(*top.pc); dvander@174: dvander@174: if (OpcodeInfo[op].nuses > 0) dvander@174: assert(top.sp - OpcodeInfo[op].nuses >= top.fp->stackBase()); dvander@174: dvander@0: switch (op) { dvander@0: dvander@0: case OP_NOP: dvander@0: break; dvander@0: dvander@0: case OP_INT: dvander@0: PUSH_I32(top, READ_INT32(top.pc)); dvander@0: break; dvander@0: dvander@4: case OP_FLOAT: dvander@4: PUSH_F(top, READ_FLOAT(top.pc)); dvander@4: break; dvander@4: dvander@0: case OP_RETURN: dvander@72: case OP_RETURNVOID: dvander@72: case OP_STOP: dvander@0: { dvander@72: if (op == OP_RETURN) dvander@72: *result = *--top.sp; dvander@72: dvander@69: if (top.fp == entryFrame) dvander@69: goto done; dvander@0: dvander@72: // This must not GC. dvander@65: zone->stack().popInlineFrame(); dvander@47: locals = top.fp->locals(); dvander@72: dvander@72: if (op == OP_RETURN) dvander@72: *top.sp++ = *result; dvander@72: dvander@0: top.pc += OpcodeInfo[*top.pc].length; dvander@0: continue; dvander@0: } dvander@0: dvander@80: case OP_POP: dvander@80: { dvander@80: top.sp--; dvander@80: break; dvander@80: } dvander@80: dvander@0: case OP_JT: dvander@0: { dvander@0: int value = POP_I32(top); dvander@0: if (value) { dvander@0: top.pc += READ_INT32(top.pc); dvander@0: continue; dvander@0: } dvander@0: break; dvander@0: } dvander@0: dvander@0: case OP_JF: dvander@0: { dvander@0: int value = POP_I32(top); dvander@0: if (!value) { dvander@0: top.pc += READ_INT32(top.pc); dvander@0: continue; dvander@0: } dvander@0: break; dvander@0: } dvander@0: dvander@0: case OP_JUMP: dvander@230: { dvander@0: top.pc += READ_INT32(top.pc); dvander@0: continue; dvander@230: } dvander@230: dvander@230: case OP_BREAK: dvander@230: case OP_CONTINUE: dvander@230: { dvander@230: top.fp->leaveLoop(zone); dvander@230: top.pc += READ_INT32(top.pc); dvander@230: continue; dvander@230: } dvander@0: dvander@0: case OP_GETLOCAL: dvander@0: { dvander@195: unsigned slot = READ_UINT32(top.pc); dvander@195: assert(slot < top.fp->code()->nlocals()); dvander@0: *top.sp++ = locals[slot]; dvander@0: break; dvander@0: } dvander@0: dvander@0: case OP_SETLOCAL: dvander@0: { dvander@195: unsigned slot = READ_UINT32(top.pc); dvander@195: assert(slot < top.fp->code()->nlocals()); dvander@0: locals[slot] = top.sp[-1]; dvander@0: break; dvander@0: } dvander@0: dvander@0: case OP_ADD: dvander@0: { dvander@77: top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32; dvander@77: top.sp--; dvander@0: break; dvander@0: } dvander@0: dvander@0: case OP_SUB: dvander@0: { dvander@77: top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32; dvander@77: top.sp--; dvander@0: break; dvander@0: } dvander@0: dvander@0: case OP_MUL: dvander@0: { dvander@77: top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32; dvander@77: top.sp--; dvander@0: break; dvander@0: } dvander@0: dvander@0: case OP_DIV: dvander@0: { dvander@77: if (top.sp[-1].i32 == 0) { dvander@69: zone->reportError(Message_IntegerDivideByZero); dvander@69: goto error; dvander@69: } dvander@77: top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32; dvander@77: top.sp--; dvander@0: break; dvander@0: } dvander@0: dvander@82: case OP_MOD: dvander@82: { dvander@82: if (top.sp[-1].i32 == 0) { dvander@82: zone->reportError(Message_IntegerDivideByZero); dvander@82: goto error; dvander@82: } dvander@82: top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32; dvander@82: top.sp--; dvander@82: break; dvander@82: } dvander@82: dvander@74: case OP_LT: dvander@74: { dvander@74: top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32; dvander@74: top.sp--; dvander@74: break; dvander@74: } dvander@74: dvander@74: case OP_LE: dvander@74: { dvander@74: top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32; dvander@74: top.sp--; dvander@74: break; dvander@74: } dvander@74: dvander@74: case OP_GT: dvander@74: { dvander@74: top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32; dvander@74: top.sp--; dvander@74: break; dvander@74: } dvander@74: dvander@74: case OP_GE: dvander@74: { dvander@74: top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32; dvander@74: top.sp--; dvander@74: break; dvander@74: } dvander@74: dvander@74: case OP_EQ: dvander@74: { dvander@74: top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32); dvander@74: top.sp--; dvander@74: break; dvander@74: } dvander@74: dvander@74: case OP_NE: dvander@74: { dvander@74: top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32); dvander@74: top.sp--; dvander@74: break; dvander@74: } dvander@74: dvander@4: case OP_ADD_F: dvander@4: { dvander@77: top.sp[-2].f = top.sp[-2].f + top.sp[-1].f; dvander@77: top.sp--; dvander@4: break; dvander@4: } dvander@4: dvander@4: case OP_SUB_F: dvander@4: { dvander@77: top.sp[-2].f = top.sp[-2].f - top.sp[-1].f; dvander@77: top.sp--; dvander@4: break; dvander@4: } dvander@4: dvander@4: case OP_MUL_F: dvander@4: { dvander@77: top.sp[-2].f = top.sp[-2].f * top.sp[-1].f; dvander@77: top.sp--; dvander@4: break; dvander@4: } dvander@4: dvander@4: case OP_DIV_F: dvander@4: { dvander@77: top.sp[-2].f = top.sp[-2].f / top.sp[-1].f; dvander@77: top.sp--; dvander@4: break; dvander@4: } dvander@4: dvander@74: case OP_LT_F: dvander@74: { dvander@74: top.sp[-2].f = top.sp[-2].f < top.sp[-1].f; dvander@74: top.sp--; dvander@74: break; dvander@74: } dvander@74: dvander@74: case OP_LE_F: dvander@74: { dvander@74: top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f; dvander@74: top.sp--; dvander@74: break; dvander@74: } dvander@74: dvander@74: case OP_GT_F: dvander@74: { dvander@74: top.sp[-2].f = top.sp[-2].f > top.sp[-1].f; dvander@74: top.sp--; dvander@74: break; dvander@74: } dvander@74: dvander@74: case OP_GE_F: dvander@74: { dvander@74: top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f; dvander@74: top.sp--; dvander@74: break; dvander@74: } dvander@74: dvander@74: case OP_EQ_F: dvander@74: { dvander@74: top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f); dvander@74: top.sp--; dvander@74: break; dvander@74: } dvander@74: dvander@74: case OP_NE_F: dvander@74: { dvander@74: top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f); dvander@74: top.sp--; dvander@74: break; dvander@74: } dvander@74: dvander@8: case OP_SHL: dvander@8: { dvander@77: top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32; dvander@77: top.sp--; dvander@8: break; dvander@8: } dvander@8: dvander@8: case OP_SHR: dvander@8: { dvander@77: top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32; dvander@77: top.sp--; dvander@8: break; dvander@8: } dvander@8: dvander@8: case OP_USHR: dvander@8: { dvander@207: top.sp[-2].i32 = unsigned(top.sp[-2].i32) >> unsigned(top.sp[-1].i32); dvander@77: top.sp--; dvander@8: break; dvander@8: } dvander@8: dvander@8: case OP_BITAND: dvander@8: { dvander@77: top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32; dvander@77: top.sp--; dvander@8: break; dvander@8: } dvander@8: dvander@8: case OP_BITOR: dvander@8: { dvander@77: top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32; dvander@77: top.sp--; dvander@8: break; dvander@8: } dvander@8: dvander@8: case OP_BITXOR: dvander@8: { dvander@77: top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32; dvander@77: top.sp--; dvander@8: break; dvander@8: } dvander@8: dvander@78: case OP_BITNOT: dvander@78: { dvander@78: top.sp[-1].i32 = ~top.sp[-1].i32; dvander@78: break; dvander@78: } dvander@78: dvander@79: case OP_NOT: dvander@79: { dvander@79: top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1; dvander@79: break; dvander@79: } dvander@79: dvander@79: case OP_NOT_F: dvander@79: { dvander@79: top.sp[-1].i32 = top.sp[-1].f ? 0 : 1; dvander@79: break; dvander@79: } dvander@79: dvander@80: case OP_NEG: dvander@79: { dvander@80: top.sp[-1].i32 = -top.sp[-1].i32; dvander@80: break; dvander@80: } dvander@80: dvander@80: case OP_NEG_F: dvander@80: { dvander@80: top.sp[-1].f = -top.sp[-1].f; dvander@0: break; dvander@79: } dvander@0: dvander@73: case OP_CALL: dvander@0: { dvander@195: Local newFun(zone, Function::cast(top.sp[-1].obj)); dvander@73: top.sp--; dvander@73: dvander@69: if (!zone->stack().pushInlineFrame(newFun)) dvander@69: goto error; dvander@0: dvander@47: locals = top.fp->locals(); dvander@0: continue; dvander@0: } dvander@0: dvander@0: case OP_GETARG: dvander@0: { dvander@0: unsigned slot = READ_UINT32(top.pc); dvander@47: *top.sp++ = top.fp->arg(slot); dvander@0: break; dvander@0: } dvander@0: dvander@0: case OP_SETARG: dvander@0: { dvander@0: unsigned slot = READ_UINT32(top.pc); dvander@174: top.fp->arg(slot) = top.sp[-1]; dvander@0: break; dvander@0: } dvander@0: dvander@158: case OP_GETELEM: dvander@0: { dvander@158: Array *array = Array::cast(top.sp[-2].obj); dvander@0: int index = top.sp[-1].i32; dvander@158: dvander@155: if (index < 0 || unsigned(index) >= array->length()) { dvander@155: zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length()); dvander@69: goto error; dvander@69: } dvander@0: dvander@157: GetElement(array, index, &top.sp[-2]); dvander@21: top.sp--; dvander@21: break; dvander@21: } dvander@21: dvander@157: case OP_SETELEM: dvander@0: { dvander@157: Array *array = Array::cast(top.sp[-3].obj); dvander@0: int index = top.sp[-2].i32; dvander@158: dvander@158: if (index < 0 || unsigned(index) >= array->length()) { dvander@158: zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length()); dvander@158: goto error; dvander@158: } dvander@158: dvander@157: SetElement(zone, array, index, top.sp[-1]); dvander@7: top.sp[-3] = top.sp[-1]; dvander@7: top.sp -= 2; dvander@7: break; dvander@7: } dvander@7: dvander@4: case OP_CVT_I2F: dvander@4: { dvander@4: int ival = POP_I32(top); dvander@4: float fval = (float)ival; dvander@4: PUSH_F(top, fval); dvander@4: break; dvander@4: } dvander@4: dvander@208: case OP_CVT_I2B: dvander@208: { dvander@208: top.sp[-1].i32 = !!top.sp[-1].i32; dvander@208: break; dvander@208: } dvander@208: dvander@234: case OP_DUPARRAY: dvander@234: { dvander@234: Local src(zone, Array::cast(top.sp[-1].obj)); dvander@234: top.sp[-1].obj = Array::DeepCopy(zone, src, Heap::Tenure_Default); dvander@234: if (!top.sp[-1].obj) dvander@234: goto error; dvander@234: break; dvander@234: } dvander@234: dvander@185: case OP_NEWFIXED: dvander@12: { dvander@85: Heap::Tenure tenure = (Heap::Tenure)top.pc[1]; dvander@85: Local map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1)))); dvander@187: Array *array = Array::NewFixed(zone, map, tenure); dvander@185: if (!array) dvander@185: goto error; dvander@185: top.sp->obj = array; dvander@185: top.sp++; dvander@185: break; dvander@185: } dvander@185: dvander@185: case OP_NEWEMPTY: dvander@185: { dvander@185: Heap::Tenure tenure = (Heap::Tenure)top.pc[1]; dvander@185: Local map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1)))); dvander@187: Array *array = Array::NewEmpty(zone, map, tenure); dvander@187: if (!array) dvander@187: goto error; dvander@187: top.sp->obj = array; dvander@187: top.sp++; dvander@187: break; dvander@187: } dvander@187: dvander@187: case OP_NEWSIZED: dvander@187: { dvander@187: Heap::Tenure tenure = (Heap::Tenure)top.pc[1]; dvander@187: Local map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1)))); dvander@187: assert(map->type()->levels() < MAX_ARRAY_DEPTH); dvander@187: dvander@187: int dims[MAX_ARRAY_DEPTH]; dvander@187: for (unsigned i = map->type()->levels() - 1; i < map->type()->levels(); i--) dvander@187: dims[i] = POP_I32(top); dvander@187: dvander@187: Array *array = Array::NewSized(zone, map, dims, tenure); dvander@69: if (!array) dvander@69: goto error; dvander@12: top.sp->obj = array; dvander@12: top.sp++; dvander@12: break; dvander@12: } dvander@12: dvander@147: case OP_NEWSTRUCT: dvander@147: { dvander@147: Heap::Tenure tenure = (Heap::Tenure)top.pc[1]; dvander@147: Local map(zone, StructMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1)))); dvander@147: top.sp->obj = Struct::New(zone, map, tenure); dvander@147: if (!top.sp->obj) dvander@147: goto error; dvander@147: top.sp++; dvander@147: break; dvander@147: } dvander@147: dvander@12: case OP_SAVELIFO: dvander@10: { dvander@10: unsigned slot = READ_UINT32(top.pc); dvander@42: locals[slot].address = zone->heap().lifoPosition(); dvander@12: break; dvander@12: } dvander@12: dvander@12: case OP_UNWINDLIFO: dvander@12: { dvander@12: unsigned slot = READ_UINT32(top.pc); dvander@42: zone->heap().unwindLifo(locals[slot].address); dvander@10: break; dvander@10: } dvander@10: dvander@14: case OP_VARREF_LIFO: dvander@14: { dvander@14: unsigned slot = READ_UINT32(top.pc); dvander@69: if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack)) dvander@69: goto error; dvander@14: break; dvander@14: } dvander@14: dvander@14: case OP_ARGREF_LIFO: dvander@14: { dvander@14: unsigned slot = READ_UINT32(top.pc); dvander@69: if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack)) dvander@69: goto error; dvander@14: break; dvander@14: } dvander@14: dvander@16: case OP_SLOTREF_LIFO: dvander@16: { dvander@42: Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack); dvander@69: if (!ref) dvander@69: goto error; dvander@16: top.sp[-1].ref = ref; dvander@16: break; dvander@16: } dvander@16: dvander@14: case OP_GETREF_I: dvander@14: { dvander@14: top.sp[-1].i32 = top.sp[-1].ref->getInt(); dvander@14: break; dvander@14: } dvander@14: dvander@14: case OP_SETREF_I: dvander@14: { dvander@14: top.sp[-2].ref->setInt(top.sp[-1].i32); dvander@14: top.sp[-2].i32 = top.sp[-1].i32; dvander@23: top.sp--; dvander@14: break; dvander@14: } dvander@14: dvander@14: case OP_GETREF_F: dvander@14: { dvander@14: top.sp[-1].f = top.sp[-1].ref->getFloat(); dvander@14: break; dvander@14: } dvander@14: dvander@14: case OP_SETREF_F: dvander@14: { dvander@14: top.sp[-2].ref->setFloat(top.sp[-1].f); dvander@14: top.sp[-2].f = top.sp[-1].f; dvander@14: break; dvander@14: } dvander@14: dvander@21: case OP_OBJECT: dvander@21: { dvander@47: top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc)); dvander@21: top.sp++; dvander@21: break; dvander@21: } dvander@21: dvander@152: case OP_COPYARRAY: dvander@21: { dvander@21: // Note for this assignment opcode, we return the left-hand side, not the dvander@21: // right, since in this case the result of the expression could be different. dvander@178: Local left(zone, Array::cast(top.sp[-2].array)); dvander@178: Local right(zone, Array::cast(top.sp[-1].array)); dvander@234: if (!Array::ShallowCopy(zone, left, right)) dvander@69: goto error; dvander@21: top.sp--; dvander@21: break; dvander@21: } dvander@21: dvander@22: case OP_DUP: dvander@22: { dvander@23: top.sp++; dvander@23: top.sp[-1] = top.sp[-2]; dvander@22: break; dvander@22: } dvander@22: dvander@22: case OP_DUP2: dvander@22: { dvander@23: top.sp += 2; dvander@23: top.sp[-2] = top.sp[-4]; dvander@23: top.sp[-1] = top.sp[-3]; dvander@23: break; dvander@23: } dvander@23: dvander@23: case OP_SWAP: dvander@23: { dvander@23: LocalSlot slot = top.sp[-2]; dvander@23: top.sp[-2] = top.sp[-1]; dvander@23: top.sp[-1] = slot; dvander@23: break; dvander@23: } dvander@23: dvander@23: case OP_ROLL3: dvander@23: { dvander@23: LocalSlot slot = top.sp[-3]; dvander@23: top.sp[-3] = top.sp[-2]; dvander@23: top.sp[-2] = top.sp[-1]; dvander@23: top.sp[-1] = slot; dvander@23: break; dvander@23: } dvander@23: dvander@23: case OP_PICK2: dvander@23: { dvander@23: top.sp++; dvander@23: top.sp[-1] = top.sp[-3]; dvander@23: break; dvander@23: } dvander@23: dvander@23: case OP_PICK3: dvander@23: { dvander@23: top.sp++; dvander@23: top.sp[-1] = top.sp[-4]; dvander@22: break; dvander@22: } dvander@22: dvander@68: case OP_CALLNATIVE: dvander@68: { dvander@195: unsigned argc = READ_UINT32(top.pc); dvander@68: dvander@195: Local native(zone, Native::cast(top.sp[-1].obj)); dvander@195: top.sp--; dvander@68: dvander@68: int result; dvander@68: void *nativeIdentity = top.fp->code()->module()->nativeIdentity(); dvander@69: if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result)) dvander@69: goto error; dvander@68: dvander@68: top.sp -= argc; dvander@68: PUSH_I32(top, result); dvander@68: break; dvander@68: } dvander@68: dvander@142: case OP_BITS_I2F: dvander@142: case OP_BITS_F2I: dvander@142: { dvander@142: // Because the stack is a union, these are actually no-ops in the dvander@142: // interpreter. dvander@142: break; dvander@142: } dvander@142: dvander@143: case OP_TRUE: dvander@143: { dvander@143: top.sp++; dvander@143: top.sp[-1].i32 = 1; dvander@143: break; dvander@143: } dvander@143: dvander@143: case OP_FALSE: dvander@143: { dvander@143: top.sp++; dvander@143: top.sp[-1].i32 = 0; dvander@143: break; dvander@143: } dvander@143: dvander@152: case OP_GETFIELD: dvander@152: { dvander@152: Struct *obj = Struct::cast(top.sp[-1].obj); dvander@152: GetField(obj, READ_UINT32(top.pc), &top.sp[-1]); dvander@152: break; dvander@152: } dvander@152: dvander@152: case OP_SETFIELD: dvander@152: { dvander@152: Struct *obj = Struct::cast(top.sp[-2].obj); dvander@152: SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]); dvander@152: top.sp[-2] = top.sp[-1]; dvander@152: top.sp--; dvander@152: break; dvander@152: } dvander@152: dvander@152: case OP_COPYSTRUCT: dvander@152: { dvander@178: Local left(zone, Struct::cast(top.sp[-2].obj)); dvander@178: Local right(zone, Struct::cast(top.sp[-1].obj)); dvander@234: if (!Struct::Copy(zone, left, right)) dvander@152: goto error; dvander@152: top.sp[-2].obj = top.sp[-1].obj; dvander@152: top.sp--; dvander@152: break; dvander@152: } dvander@152: dvander@172: case OP_TABLESWITCH: dvander@172: { dvander@172: int value = top.sp[-1].i32; dvander@172: int low = READ_TABLESWITCH_LOW(top.pc); dvander@172: int high = READ_TABLESWITCH_HIGH(top.pc); dvander@172: dvander@172: top.sp--; dvander@172: dvander@172: unsigned index = unsigned(value - low); dvander@172: unsigned tablesize = TableSwitchEntries(low, high); dvander@172: if (index < tablesize) { dvander@172: top.pc += OP_TABLESWITCH_LENGTH + OP_JUMP_LENGTH; dvander@172: top.pc += index * OP_JUMP_LENGTH; dvander@172: continue; dvander@172: } dvander@172: break; dvander@172: } dvander@172: dvander@194: case OP_SIZEOF: dvander@194: { dvander@194: Array *array = Array::cast(top.sp[-1].obj); dvander@194: top.sp[-1].i32 = array->length(); dvander@194: break; dvander@194: } dvander@194: dvander@195: case OP_PUBLIC: dvander@195: { dvander@195: Local fun(zone, Function::cast(top.sp[-1].obj)); dvander@195: zone->registerPublic(fun); dvander@195: top.sp--; dvander@195: break; dvander@195: } dvander@195: dvander@195: case OP_SETGLOBAL: dvander@195: { dvander@195: Local code(zone, top.fp->code()); dvander@195: Local obj(zone, code->module()->globals()); dvander@195: Local name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc)))); dvander@195: SetGlobal(zone, obj, name, top.sp[-1]); dvander@195: break; dvander@195: } dvander@195: dvander@195: case OP_GETGLOBAL: dvander@195: { dvander@195: Local code(zone, top.fp->code()); dvander@195: Local obj(zone, code->module()->globals()); dvander@195: Local name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc)))); dvander@195: GetGlobal(zone, obj, name, top.sp); dvander@195: top.sp++; dvander@195: break; dvander@195: } dvander@195: dvander@230: case OP_ENTERLOOP: dvander@230: { dvander@230: top.fp->enterLoop(zone); dvander@230: break; dvander@230: } dvander@230: dvander@230: case OP_LEAVELOOP: dvander@230: { dvander@230: top.fp->leaveLoop(zone); dvander@230: break; dvander@230: } dvander@230: dvander@0: default: dvander@0: assert(false); dvander@0: return false; dvander@0: dvander@0: } dvander@0: dvander@0: top.pc += OpcodeInfo[op].length; dvander@174: assert(top.sp >= top.fp->stackBase()); dvander@0: } dvander@0: dvander@69: done: dvander@0: return true; dvander@69: dvander@69: error: dvander@69: // Unwind frames until we can continue. dvander@69: while (top.fp != entryFrame) dvander@69: zone->stack().popInlineFrame(); dvander@69: return false; dvander@0: }