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