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@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@155: static bool CopyStruct(Zone *zone, Struct *left, Struct *right); dvander@155: dvander@152: // Even though this function can fail, we immediately bail out, so it doesn't dvander@152: // matter if we've leaving things unrooted. dvander@21: static bool dvander@21: CopyArray(Zone *zone, Array *source, Array *dest) dvander@21: { dvander@155: if (source->type()->contained()->isArray()) { dvander@155: assert(dest->type()->contained()->isArray()); dvander@155: assert(source->length() == dest->length()); dvander@155: dvander@155: for (unsigned i = 0; i < source->length(); i++) { dvander@155: Array *left = Array::cast(source->readObject(i)); dvander@155: Array *right = Array::cast(dest->readObject(i)); dvander@155: if (!CopyArray(zone, left, right)) dvander@155: return false; dvander@155: } dvander@155: } else if (source->type()->contained()->isStruct()) { dvander@155: assert(dest->type()->contained() == source->type()->contained()); dvander@155: assert(source->length() == dest->length()); dvander@21: dvander@155: for (unsigned i = 0; i < source->length(); i++) { dvander@155: Struct *left = Struct::cast(source->readObject(i)); dvander@155: Struct *right = Struct::cast(dest->readObject(i)); dvander@155: if (!CopyStruct(zone, left, right)) dvander@155: return false; dvander@155: } dvander@155: } else { dvander@156: assert(source->type()->contained()->pod() == dest->type()->contained()->pod()); dvander@156: assert(source->type()->contained()->pod() == PrimitiveType_Char dvander@155: ? source->length() >= dest->length() dvander@155: : source->length() == dest->length()); dvander@155: dvander@155: memcpy(source->vec(), dest->vec(), dest->length() * dest->elementSize()); dvander@155: } dvander@21: return true; dvander@21: } dvander@21: 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@152: GetField(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@152: Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index)); dvander@152: GetField(obj, desc, vp); dvander@152: } dvander@152: dvander@152: static void dvander@152: SetField(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@152: Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index)); dvander@152: SetField(zone, obj, desc, v); dvander@152: } dvander@152: dvander@152: // Even though this function can fail, we immediately bail out, so it doesn't dvander@152: // matter if we've leaving things unrooted. dvander@152: static bool dvander@152: CopyStruct(Zone *zone, Struct *left, Struct *right) dvander@152: { dvander@152: assert(left->map()->type() == right->map()->type()); dvander@152: dvander@152: Type *type = left->map()->type(); dvander@152: for (unsigned i = 0; i < type->fields()->length(); i++) { dvander@152: Descriptor *desc = Descriptor::cast(type->fields()->at(i)); dvander@152: dvander@152: LocalSlot rval; dvander@152: GetField(right, desc, &rval); dvander@152: dvander@152: // If the field is a struct, we need to deep-copy. dvander@152: if (desc->type()->isStruct()) { dvander@152: LocalSlot lval; dvander@152: dvander@152: GetField(left, desc, &lval); dvander@152: if (!CopyStruct(zone, Struct::cast(lval.obj), Struct::cast(rval.obj))) dvander@152: return false; dvander@152: } else if (desc->type()->isArray()) { dvander@152: LocalSlot lval; dvander@152: dvander@152: GetField(left, desc, &lval); dvander@152: if (!CopyArray(zone, Array::cast(lval.obj), Array::cast(rval.obj))) dvander@152: return false; dvander@152: } else { dvander@152: SetField(zone, left, desc, rval); dvander@152: } dvander@152: } dvander@152: dvander@152: return true; 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@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@68: 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@68: cells[i + 1] = reinterpret_cast(arg.array->vec()); 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@68: cells[i + 1] = reinterpret_cast(arg.array->vec()); dvander@68: } dvander@68: } dvander@68: dvander@68: typedef intptr_t (*INVOKE)(void *, intptr_t *); dvander@68: INVOKE invoke = (INVOKE)native->function(); 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@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: #define RELATIONAL_JUMP(op) \ dvander@0: { \ dvander@0: int right = POP_I32(top); \ dvander@0: int left = POP_I32(top); \ dvander@0: if (left op right) { \ dvander@0: top.pc += READ_INT32(top.pc); \ dvander@0: continue; \ dvander@0: } \ dvander@0: } dvander@0: dvander@0: case OP_JL: dvander@0: RELATIONAL_JUMP(<); dvander@0: break; dvander@0: dvander@0: case OP_JLE: dvander@0: RELATIONAL_JUMP(<=); dvander@0: break; dvander@0: dvander@0: case OP_JG: dvander@0: RELATIONAL_JUMP(>); dvander@0: break; dvander@0: dvander@0: case OP_JGE: dvander@0: RELATIONAL_JUMP(>=); dvander@0: break; dvander@0: dvander@0: case OP_JEQ: dvander@0: RELATIONAL_JUMP(==); dvander@0: break; dvander@0: dvander@0: case OP_JNE: dvander@0: RELATIONAL_JUMP(!=); dvander@0: break; dvander@0: dvander@74: #undef RELATIONAL_JUMP dvander@74: 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@74: #define RELATIONAL_JUMP_F(op) \ dvander@74: { \ dvander@74: float right = POP_F(top); \ dvander@74: float left = POP_F(top); \ dvander@74: if (left op right) { \ dvander@74: top.pc += READ_INT32(top.pc); \ dvander@74: continue; \ dvander@74: } \ dvander@74: } dvander@74: dvander@74: case OP_JL_F: dvander@74: RELATIONAL_JUMP_F(<); dvander@74: break; dvander@74: dvander@74: case OP_JLE_F: dvander@74: RELATIONAL_JUMP_F(<=); dvander@74: break; dvander@74: dvander@74: case OP_JG_F: dvander@74: RELATIONAL_JUMP_F(>); dvander@74: break; dvander@74: dvander@74: case OP_JGE_F: dvander@74: RELATIONAL_JUMP_F(>=); dvander@74: break; dvander@74: dvander@74: case OP_JEQ_F: dvander@74: RELATIONAL_JUMP_F(==); dvander@74: break; dvander@74: dvander@74: case OP_JNE_F: dvander@74: RELATIONAL_JUMP_F(!=); dvander@74: break; dvander@74: dvander@74: case OP_JT_F: dvander@74: { dvander@74: float value = POP_F(top); dvander@74: if (value) { dvander@74: top.pc += READ_INT32(top.pc); dvander@74: continue; dvander@74: } dvander@74: break; dvander@74: } dvander@74: dvander@74: case OP_JF_F: dvander@74: { dvander@74: float value = POP_F(top); dvander@74: if (!value) { dvander@74: top.pc += READ_INT32(top.pc); dvander@74: continue; dvander@74: } dvander@74: break; dvander@74: } dvander@74: dvander@0: case OP_JUMP: dvander@0: top.pc += READ_INT32(top.pc); dvander@0: continue; dvander@0: dvander@0: case OP_GETLOCAL: dvander@0: { dvander@0: int slot = READ_INT32(top.pc); dvander@0: *top.sp++ = locals[slot]; dvander@0: break; dvander@0: } dvander@0: dvander@0: case OP_SETLOCAL: dvander@0: { dvander@0: int slot = READ_INT32(top.pc); 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@77: 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@73: Local newFun(zone, top.sp[-1].fun); 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@47: top.fp->arg(slot) = *--top.sp; 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@85: case OP_NEWARRAY: 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@154: Array *array = Array::New(zone, map, map->type()->elements(), 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@17: case OP_ARRAYREF_LIFO: dvander@17: { dvander@164: Local array(zone, Array::cast(top.sp[-2].obj)); dvander@42: Local ref(zone, Reference::NewArray(zone, array, top.sp[-1].i32, Heap::Tenure_Stack)); dvander@69: if (!ref) dvander@69: goto error; dvander@17: top.sp[-2].ref = ref; dvander@17: top.sp--; dvander@17: break; dvander@17: } dvander@17: 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@164: case OP_FIELDREF_LIFO: dvander@164: { dvander@164: Local obj(zone, Struct::cast(top.sp[-1].obj)); dvander@164: top.sp[-1].obj = Reference::NewField(zone, obj, READ_UINT32(top.pc), Heap::Tenure_Stack); dvander@164: if (!top.sp[-1].obj) dvander@164: goto error; dvander@164: break; dvander@164: } dvander@164: 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@69: if (!CopyArray(zone, top.sp[-2].array, top.sp[-1].array)) 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@68: unsigned index = READ_UINT32(top.pc); dvander@68: unsigned argc = READ_UINT32(top.pc + 4); dvander@68: dvander@68: Local native(zone, Native::cast(top.fp->code()->module()->natives()->at(index))); dvander@68: if (!native->function()) { dvander@69: zone->reportError(Message_NativeNotBound, native->name()->chars()); dvander@69: goto error; dvander@68: } 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@73: case OP_MODULE: dvander@73: { dvander@73: top.sp++; dvander@73: top.sp[-1].module = top.fp->code()->module(); dvander@73: break; dvander@73: } dvander@73: dvander@73: case OP_GETMODULE_FN: dvander@73: { dvander@73: top.sp[-1].fun = top.sp[-1].module->getFunction(READ_UINT32(top.pc)); dvander@73: break; dvander@73: } dvander@73: dvander@85: case OP_GETGLOBAL_I: dvander@85: { dvander@85: unsigned slot = READ_UINT32(top.pc); dvander@85: top.sp++; dvander@85: top.sp[-1].i32 = top.fp->code()->module()->environment()->getInt32(slot); dvander@85: break; dvander@85: } dvander@85: dvander@85: case OP_GETGLOBAL_F: dvander@85: { dvander@85: unsigned slot = READ_UINT32(top.pc); dvander@85: top.sp++; dvander@85: top.sp[-1].f = top.fp->code()->module()->environment()->getFloat(slot); dvander@85: break; dvander@85: } dvander@85: dvander@85: case OP_GETGLOBAL_O: dvander@85: { dvander@85: unsigned slot = READ_UINT32(top.pc); dvander@85: top.sp++; dvander@85: top.sp[-1].obj = top.fp->code()->module()->environment()->getObject(slot); dvander@85: break; dvander@85: } dvander@85: dvander@85: case OP_SETGLOBAL_I: dvander@85: { dvander@85: unsigned slot = READ_UINT32(top.pc); dvander@85: top.fp->code()->module()->environment()->setInt32(slot, top.sp[-1].i32); dvander@85: break; dvander@85: } dvander@85: dvander@85: case OP_SETGLOBAL_F: dvander@85: { dvander@85: unsigned slot = READ_UINT32(top.pc); dvander@85: top.fp->code()->module()->environment()->setFloat(slot, top.sp[-1].f); dvander@85: break; dvander@85: } dvander@85: dvander@85: case OP_SETGLOBAL_O: dvander@85: { dvander@85: unsigned slot = READ_UINT32(top.pc); dvander@85: top.fp->code()->module()->environment()->setObject(slot, top.sp[-1].obj); dvander@85: break; dvander@85: } dvander@85: 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@152: if (!CopyStruct(zone, Struct::cast(top.sp[-2].obj), Struct::cast(top.sp[-1].obj))) 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@0: default: dvander@0: assert(false); dvander@0: return false; dvander@0: dvander@0: } dvander@0: dvander@0: top.pc += OpcodeInfo[op].length; 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: }