From 00324c7c51c8d848c2dbe798990f52638b556cfa Mon Sep 17 00:00:00 2001 From: Andrea Peruffo Date: Mon, 29 Jul 2024 19:20:26 +0100 Subject: [PATCH] Attempt to revamp the closure interpreter --- .../chicory/runtime/InterpreterMachine.java | 3081 +++++++---------- .../dylibso/chicory/runtime/StackFrame.java | 10 + 2 files changed, 1302 insertions(+), 1789 deletions(-) diff --git a/runtime/src/main/java/com/dylibso/chicory/runtime/InterpreterMachine.java b/runtime/src/main/java/com/dylibso/chicory/runtime/InterpreterMachine.java index f6b35b447..8100f5693 100644 --- a/runtime/src/main/java/com/dylibso/chicory/runtime/InterpreterMachine.java +++ b/runtime/src/main/java/com/dylibso/chicory/runtime/InterpreterMachine.java @@ -94,16 +94,25 @@ public static Value[] call( return results; } + interface ExecuteInstruction { + void execute( + StackFrame frame, + MStack stack, + Instance instance, + ArrayDeque callStack, + Instruction instruction, + long[] operands) + throws ChicoryException; + } + static void eval(MStack stack, Instance instance, ArrayDeque callStack) throws ChicoryException { try { var frame = callStack.peek(); - boolean shouldReturn = false; - loop: while (!frame.terminated()) { - if (shouldReturn) return; + if (frame.shouldReturn()) return; var instruction = frame.loadCurrentInstruction(); // LOGGER.log( // System.Logger.Level.DEBUG, @@ -118,627 +127,13 @@ static void eval(MStack stack, Instance instance, ArrayDeque callSta var opcode = instruction.opcode(); var operands = instruction.operands(); instance.onExecution(instruction, operands, stack); - switch (opcode) { - case UNREACHABLE: - throw new TrapException("Trapped on unreachable instruction", callStack); - case NOP: - break; - case LOOP: - case BLOCK: - BLOCK(frame, stack, instance, instruction); - break; - case IF: - IF(frame, stack, instance, instruction); - break; - case ELSE: - frame.jumpTo(instruction.labelTrue()); - break; - case BR: - BR(frame, stack, instruction); - break; - case BR_IF: - BR_IF(frame, stack, instruction); - break; - case BR_TABLE: - BR_TABLE(frame, stack, instruction); - break; - case END: - { - var ctrlFrame = frame.popCtrl(); - StackFrame.doControlTransfer(ctrlFrame, stack); - // if this is the last end, then we're done with - // the function - if (frame.isLastBlock()) { - break loop; - } - break; - } - case RETURN: - { - // RETURN doesn't pass through the END - var ctrlFrame = frame.popCtrlTillCall(); - StackFrame.doControlTransfer(ctrlFrame, stack); - - shouldReturn = true; - break; - } - case CALL_INDIRECT: - CALL_INDIRECT(stack, instance, callStack, operands); - break; - case DROP: - stack.pop(); - break; - case SELECT: - SELECT(stack); - break; - case SELECT_T: - SELECT_T(stack, operands); - break; - case LOCAL_GET: - stack.push(frame.local((int) operands[0])); - break; - case LOCAL_SET: - frame.setLocal((int) operands[0], stack.pop()); - break; - case LOCAL_TEE: - // here we peek instead of pop, leaving it on the stack - frame.setLocal((int) operands[0], stack.peek()); - break; - case GLOBAL_GET: - GLOBAL_GET(stack, instance, operands); - break; - case GLOBAL_SET: - GLOBAL_SET(stack, instance, operands); - break; - case TABLE_GET: - TABLE_GET(stack, instance, operands); - break; - case TABLE_SET: - TABLE_SET(stack, instance, operands); - break; - // TODO signed and unsigned are the same right now - case I32_LOAD: - I32_LOAD(stack, instance, operands); - break; - case I64_LOAD: - I64_LOAD(stack, instance, operands); - break; - case F32_LOAD: - F32_LOAD(stack, instance, operands); - break; - case F64_LOAD: - F64_LOAD(stack, instance, operands); - break; - case I32_LOAD8_S: - I32_LOAD8_S(stack, instance, operands); - break; - case I64_LOAD8_S: - I64_LOAD8_S(stack, instance, operands); - break; - case I32_LOAD8_U: - I32_LOAD8_U(stack, instance, operands); - break; - case I64_LOAD8_U: - I64_LOAD8_U(stack, instance, operands); - break; - case I32_LOAD16_S: - I32_LOAD16_S(stack, instance, operands); - break; - case I64_LOAD16_S: - I64_LOAD16_S(stack, instance, operands); - break; - case I32_LOAD16_U: - I32_LOAD16_U(stack, instance, operands); - break; - case I64_LOAD16_U: - I64_LOAD16_U(stack, instance, operands); - break; - case I64_LOAD32_S: - I64_LOAD32_S(stack, instance, operands); - break; - case I64_LOAD32_U: - I64_LOAD32_U(stack, instance, operands); - break; - case I32_STORE: - I32_STORE(stack, instance, operands); - break; - case I32_STORE16: - case I64_STORE16: - I64_STORE16(stack, instance, operands); - break; - case I64_STORE: - I64_STORE(stack, instance, operands); - break; - case F32_STORE: - F32_STORE(stack, instance, operands); - break; - case F64_STORE: - F64_STORE(stack, instance, operands); - break; - case MEMORY_GROW: - MEMORY_GROW(stack, instance); - break; - case MEMORY_FILL: - MEMORY_FILL(stack, instance, operands); - break; - case I32_STORE8: - case I64_STORE8: - I64_STORE8(stack, instance, operands); - break; - case I64_STORE32: - I64_STORE32(stack, instance, operands); - break; - case MEMORY_SIZE: - MEMORY_SIZE(stack, instance); - break; - // TODO 32bit and 64 bit operations are the same for now - case I32_CONST: - stack.push(Value.i32(operands[0])); - break; - case I64_CONST: - stack.push(Value.i64(operands[0])); - break; - case F32_CONST: - stack.push(Value.f32(operands[0])); - break; - case F64_CONST: - stack.push(Value.f64(operands[0])); - break; - case I32_EQ: - I32_EQ(stack); - break; - case I64_EQ: - I64_EQ(stack); - break; - case I32_NE: - I32_NE(stack); - break; - case I64_NE: - I64_NE(stack); - break; - case I32_EQZ: - I32_EQZ(stack); - break; - case I64_EQZ: - I64_EQZ(stack); - break; - case I32_LT_S: - I32_LT_S(stack); - break; - case I32_LT_U: - I32_LT_U(stack); - break; - case I64_LT_S: - I64_LT_S(stack); - break; - case I64_LT_U: - I64_LT_U(stack); - break; - case I32_GT_S: - I32_GT_S(stack); - break; - case I32_GT_U: - I32_GT_U(stack); - break; - case I64_GT_S: - I64_GT_S(stack); - break; - case I64_GT_U: - I64_GT_U(stack); - break; - case I32_GE_S: - I32_GE_S(stack); - break; - case I32_GE_U: - I32_GE_U(stack); - break; - case I64_GE_U: - I64_GE_U(stack); - break; - case I64_GE_S: - I64_GE_S(stack); - break; - case I32_LE_S: - I32_LE_S(stack); - break; - case I32_LE_U: - I32_LE_U(stack); - break; - case I64_LE_S: - I64_LE_S(stack); - break; - case I64_LE_U: - I64_LE_U(stack); - break; - case F32_EQ: - F32_EQ(stack); - break; - case F64_EQ: - F64_EQ(stack); - break; - case I32_CLZ: - I32_CLZ(stack); - break; - case I32_CTZ: - I32_CTZ(stack); - break; - case I32_POPCNT: - I32_POPCNT(stack); - break; - case I32_ADD: - I32_ADD(stack); - break; - case I64_ADD: - I64_ADD(stack); - break; - case I32_SUB: - I32_SUB(stack); - break; - case I64_SUB: - I64_SUB(stack); - break; - case I32_MUL: - I32_MUL(stack); - break; - case I64_MUL: - I64_MUL(stack); - break; - case I32_DIV_S: - I32_DIV_S(stack); - break; - case I32_DIV_U: - I32_DIV_U(stack); - break; - case I64_DIV_S: - I64_DIV_S(stack); - break; - case I64_DIV_U: - I64_DIV_U(stack); - break; - case I32_REM_S: - I32_REM_S(stack); - break; - case I32_REM_U: - I32_REM_U(stack); - break; - case I64_AND: - I64_AND(stack); - break; - case I64_OR: - I64_OR(stack); - break; - case I64_XOR: - I64_XOR(stack); - break; - case I64_SHL: - I64_SHL(stack); - break; - case I64_SHR_S: - I64_SHR_S(stack); - break; - case I64_SHR_U: - I64_SHR_U(stack); - break; - case I64_REM_S: - I64_REM_S(stack); - break; - case I64_REM_U: - I64_REM_U(stack); - break; - case I64_ROTL: - I64_ROTL(stack); - break; - case I64_ROTR: - I64_ROTR(stack); - break; - case I64_CLZ: - I64_CLZ(stack); - break; - case I64_CTZ: - I64_CTZ(stack); - break; - case I64_POPCNT: - I64_POPCNT(stack); - break; - case F32_NEG: - F32_NEG(stack); - break; - case F64_NEG: - F64_NEG(stack); - break; - case CALL: - CALL(stack, instance, callStack, operands); - break; - case I32_AND: - I32_AND(stack); - break; - case I32_OR: - I32_OR(stack); - break; - case I32_XOR: - I32_XOR(stack); - break; - case I32_SHL: - I32_SHL(stack); - break; - case I32_SHR_S: - I32_SHR_S(stack); - break; - case I32_SHR_U: - I32_SHR_U(stack); - break; - case I32_ROTL: - I32_ROTL(stack); - break; - case I32_ROTR: - I32_ROTR(stack); - break; - case F32_ADD: - F32_ADD(stack); - break; - case F64_ADD: - F64_ADD(stack); - break; - case F32_SUB: - F32_SUB(stack); - break; - case F64_SUB: - F64_SUB(stack); - break; - case F32_MUL: - F32_MUL(stack); - break; - case F64_MUL: - F64_MUL(stack); - break; - case F32_DIV: - F32_DIV(stack); - break; - case F64_DIV: - F64_DIV(stack); - break; - case F32_MIN: - F32_MIN(stack); - break; - case F64_MIN: - F64_MIN(stack); - break; - case F32_MAX: - F32_MAX(stack); - break; - case F64_MAX: - F64_MAX(stack); - break; - case F32_SQRT: - F32_SQRT(stack); - break; - case F64_SQRT: - F64_SQRT(stack); - break; - case F32_FLOOR: - F32_FLOOR(stack); - break; - case F64_FLOOR: - F64_FLOOR(stack); - break; - case F32_CEIL: - F32_CEIL(stack); - break; - case F64_CEIL: - F64_CEIL(stack); - break; - case F32_TRUNC: - F32_TRUNC(stack); - break; - case F64_TRUNC: - F64_TRUNC(stack); - break; - case F32_NEAREST: - F32_NEAREST(stack); - break; - case F64_NEAREST: - F64_NEAREST(stack); - break; - // For the extend_* operations, note that java - // automatically does this when casting from - // smaller to larger primitives - case I32_EXTEND_8_S: - I32_EXTEND_8_S(stack); - break; - case I32_EXTEND_16_S: - I32_EXTEND_16_S(stack); - break; - case I64_EXTEND_8_S: - I64_EXTEND_8_S(stack); - break; - case I64_EXTEND_16_S: - I64_EXTEND_16_S(stack); - break; - case I64_EXTEND_32_S: - I64_EXTEND_32_S(stack); - break; - case F64_CONVERT_I64_U: - F64_CONVERT_I64_U(stack); - break; - case F64_CONVERT_I32_U: - F64_CONVERT_I32_U(stack); - break; - case F64_CONVERT_I32_S: - F64_CONVERT_I32_S(stack); - break; - case F64_PROMOTE_F32: - F64_PROMOTE_F32(stack); - break; - case F64_REINTERPRET_I64: - F64_REINTERPRET_I64(stack); - break; - case I64_TRUNC_F64_S: - I64_TRUNC_F64_S(stack); - break; - case I32_WRAP_I64: - I32_WRAP_I64(stack); - break; - case I64_EXTEND_I32_S: - I64_EXTEND_I32_S(stack); - break; - case I64_EXTEND_I32_U: - I64_EXTEND_I32_U(stack); - break; - case I32_REINTERPRET_F32: - I32_REINTERPRET_F32(stack); - break; - case I64_REINTERPRET_F64: - I64_REINTERPRET_F64(stack); - break; - case F32_REINTERPRET_I32: - F32_REINTERPRET_I32(stack); - break; - case F32_COPYSIGN: - F32_COPYSIGN(stack); - break; - case F32_ABS: - F32_ABS(stack); - break; - case F64_COPYSIGN: - F64_COPYSIGN(stack); - break; - case F64_ABS: - F64_ABS(stack); - break; - case F32_NE: - F32_NE(stack); - break; - case F64_NE: - F64_NE(stack); - break; - case F32_LT: - F32_LT(stack); - break; - case F64_LT: - F64_LT(stack); - break; - case F32_LE: - F32_LE(stack); - break; - case F64_LE: - F64_LE(stack); - break; - case F32_GE: - F32_GE(stack); - break; - case F64_GE: - F64_GE(stack); - break; - case F32_GT: - F32_GT(stack); - break; - case F64_GT: - F64_GT(stack); - break; - case F32_DEMOTE_F64: - F32_DEMOTE_F64(stack); - break; - case F32_CONVERT_I32_S: - F32_CONVERT_I32_S(stack); - break; - case I32_TRUNC_F32_S: - I32_TRUNC_F32_S(stack); - break; - case I32_TRUNC_SAT_F32_S: - I32_TRUNC_SAT_F32_S(stack); - break; - case I32_TRUNC_SAT_F32_U: - I32_TRUNC_SAT_F32_U(stack); - break; - case I32_TRUNC_SAT_F64_S: - I32_TRUNC_SAT_F64_S(stack); - break; - case I32_TRUNC_SAT_F64_U: - I32_TRUNC_SAT_F64_U(stack); - break; - case F32_CONVERT_I32_U: - F32_CONVERT_I32_U(stack); - break; - case I32_TRUNC_F32_U: - I32_TRUNC_F32_U(stack); - break; - case F32_CONVERT_I64_S: - F32_CONVERT_I64_S(stack); - break; - case F32_CONVERT_I64_U: - F32_CONVERT_I64_U(stack); - break; - case F64_CONVERT_I64_S: - F64_CONVERT_I64_S(stack); - break; - case I64_TRUNC_F32_U: - I64_TRUNC_F32_U(stack); - break; - case I64_TRUNC_F64_U: - I64_TRUNC_F64_U(stack); - break; - case I64_TRUNC_SAT_F32_S: - I64_TRUNC_SAT_F32_S(stack); - break; - case I64_TRUNC_SAT_F32_U: - I64_TRUNC_SAT_F32_U(stack); - break; - case I64_TRUNC_SAT_F64_S: - I64_TRUNC_SAT_F64_S(stack); - break; - case I64_TRUNC_SAT_F64_U: - I64_TRUNC_SAT_F64_U(stack); - break; - case I32_TRUNC_F64_S: - I32_TRUNC_F64_S(stack); - break; - case I32_TRUNC_F64_U: - I32_TRUNC_F64_U(stack); - break; - case I64_TRUNC_F32_S: - I64_TRUNC_F32_S(stack); - break; - case MEMORY_INIT: - MEMORY_INIT(stack, instance, operands); - break; - case TABLE_INIT: - TABLE_INIT(stack, instance, operands); - break; - case DATA_DROP: - DATA_DROP(instance, operands); - break; - case MEMORY_COPY: - MEMORY_COPY(stack, instance, operands); - break; - case TABLE_COPY: - TABLE_COPY(stack, instance, operands); - break; - case TABLE_FILL: - TABLE_FILL(stack, instance, operands); - break; - case TABLE_SIZE: - TABLE_SIZE(stack, instance, operands); - break; - case TABLE_GROW: - TABLE_GROW(stack, instance, operands); - break; - case REF_FUNC: - stack.push(Value.funcRef((int) operands[0])); - break; - case REF_NULL: - REF_NULL(stack, operands); - break; - case REF_IS_NULL: - REF_IS_NULL(stack); - break; - case ELEM_DROP: - ELEM_DROP(instance, operands); - break; - default: - throw new RuntimeException( - "Machine doesn't recognize Instruction " + instruction); + var exec = instructions[opcode.ordinal()]; + if (exec == null) { + throw new RuntimeException( + "Machine doesn't recognize Instruction " + instruction); } + exec.execute(frame, stack, instance, callStack, instruction, operands); } } catch (ChicoryException e) { // propagate ChicoryExceptions @@ -752,1146 +147,1287 @@ static void eval(MStack stack, Instance instance, ArrayDeque callSta } } - private static void I32_GE_U(MStack stack) { - var b = stack.pop().asInt(); - var a = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_GE_U(a, b))); - } - - private static void I64_GT_U(MStack stack) { - var b = stack.pop().asLong(); - var a = stack.pop().asLong(); - stack.push(Value.i64(OpcodeImpl.I64_GT_U(a, b))); - } - - private static void I32_GE_S(MStack stack) { - var b = stack.pop().asInt(); - var a = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_GE_S(a, b))); - } - - private static void I64_GE_U(MStack stack) { - var b = stack.pop().asLong(); - var a = stack.pop().asLong(); - stack.push(Value.i64(OpcodeImpl.I64_GE_U(a, b))); - } - - private static void I64_GE_S(MStack stack) { - var b = stack.pop().asLong(); - var a = stack.pop().asLong(); - stack.push(Value.i64(OpcodeImpl.I64_GE_S(a, b))); - } - - private static void I32_LE_S(MStack stack) { - var b = stack.pop().asInt(); - var a = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_LE_S(a, b))); - } - - private static void I32_LE_U(MStack stack) { - var b = stack.pop().asInt(); - var a = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_LE_U(a, b))); - } - - private static void I64_LE_S(MStack stack) { - var b = stack.pop().asLong(); - var a = stack.pop().asLong(); - stack.push(Value.i64(OpcodeImpl.I64_LE_S(a, b))); - } - - private static void I64_LE_U(MStack stack) { - var b = stack.pop().asLong(); - var a = stack.pop().asLong(); - stack.push(Value.i64(OpcodeImpl.I64_LE_U(a, b))); - } - - private static void F32_EQ(MStack stack) { - var b = stack.pop().asFloat(); - var a = stack.pop().asFloat(); - stack.push(Value.i32(OpcodeImpl.F32_EQ(a, b))); - } - - private static void F64_EQ(MStack stack) { - var b = stack.pop().asDouble(); - var a = stack.pop().asDouble(); - stack.push(Value.i32(OpcodeImpl.F64_EQ(a, b))); - } - - private static void I32_CLZ(MStack stack) { - var tos = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_CLZ(tos))); - } - - private static void I32_CTZ(MStack stack) { - var tos = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_CTZ(tos))); - } - - private static void I32_POPCNT(MStack stack) { - var tos = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_POPCNT(tos))); - } - - private static void I32_ADD(MStack stack) { - var a = stack.pop().asInt(); - var b = stack.pop().asInt(); - stack.push(Value.i32(a + b)); + static ExecuteInstruction[] instructions = new ExecuteInstruction[OpCode.values().length]; + + static { + instructions[OpCode.UNREACHABLE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + throw new TrapException("Trapped on unreachable instruction", callStack); + }; + instructions[OpCode.NOP.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + // do nothing + }; + instructions[OpCode.I32_GE_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asInt(); + var a = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_GE_U(a, b))); + }; + instructions[OpCode.I64_GT_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asLong(); + var a = stack.pop().asLong(); + stack.push(Value.i64(OpcodeImpl.I64_GT_U(a, b))); + }; + instructions[OpCode.I32_GE_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asInt(); + var a = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_GE_S(a, b))); + }; + instructions[OpCode.I64_GE_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asLong(); + var a = stack.pop().asLong(); + stack.push(Value.i64(OpcodeImpl.I64_GE_U(a, b))); + }; + instructions[OpCode.I64_GE_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asLong(); + var a = stack.pop().asLong(); + stack.push(Value.i64(OpcodeImpl.I64_GE_S(a, b))); + }; + instructions[OpCode.I32_LE_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asInt(); + var a = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_LE_S(a, b))); + }; + instructions[OpCode.I32_LE_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asInt(); + var a = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_LE_U(a, b))); + }; + instructions[OpCode.I64_LE_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asLong(); + var a = stack.pop().asLong(); + stack.push(Value.i64(OpcodeImpl.I64_LE_S(a, b))); + }; + instructions[OpCode.I64_LE_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asLong(); + var a = stack.pop().asLong(); + stack.push(Value.i64(OpcodeImpl.I64_LE_U(a, b))); + }; + instructions[OpCode.F32_EQ.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asFloat(); + var a = stack.pop().asFloat(); + stack.push(Value.i32(OpcodeImpl.F32_EQ(a, b))); + }; + instructions[OpCode.F64_EQ.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asDouble(); + var a = stack.pop().asDouble(); + stack.push(Value.i32(OpcodeImpl.F64_EQ(a, b))); + }; + instructions[OpCode.I32_CLZ.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_CLZ(tos))); + }; + instructions[OpCode.I32_CTZ.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_CTZ(tos))); + }; + instructions[OpCode.I32_POPCNT.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_POPCNT(tos))); + }; + instructions[OpCode.I32_ADD.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asInt(); + var b = stack.pop().asInt(); + stack.push(Value.i32(a + b)); + }; + instructions[OpCode.I64_ADD.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asLong(); + var b = stack.pop().asLong(); + stack.push(Value.i64(a + b)); + }; + instructions[OpCode.I32_SUB.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asInt(); + var b = stack.pop().asInt(); + stack.push(Value.i32(b - a)); + }; + instructions[OpCode.I64_SUB.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asLong(); + var b = stack.pop().asLong(); + stack.push(Value.i64(b - a)); + }; + instructions[OpCode.I32_MUL.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asInt(); + var b = stack.pop().asInt(); + stack.push(Value.i32(a * b)); + }; + instructions[OpCode.I64_MUL.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asLong(); + var b = stack.pop().asLong(); + stack.push(Value.i64(a * b)); + }; + instructions[OpCode.I32_DIV_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asInt(); + var a = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_DIV_S(a, b))); + }; + instructions[OpCode.I32_DIV_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asInt(); + var a = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_DIV_U(a, b))); + }; + instructions[OpCode.I64_EXTEND_8_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asLong(); + stack.push(Value.i64(OpcodeImpl.I64_EXTEND_8_S(tos))); + }; + instructions[OpCode.I64_EXTEND_16_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asLong(); + stack.push(Value.i64(OpcodeImpl.I64_EXTEND_16_S(tos))); + }; + instructions[OpCode.I64_EXTEND_32_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asLong(); + stack.push(Value.i64(OpcodeImpl.I64_EXTEND_32_S(tos))); + }; + instructions[OpCode.F64_CONVERT_I64_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asLong(); + stack.push(Value.fromDouble(OpcodeImpl.F64_CONVERT_I64_U(tos))); + }; + instructions[OpCode.F64_CONVERT_I32_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asInt(); + stack.push(Value.fromDouble(OpcodeImpl.F64_CONVERT_I32_U(tos))); + }; + instructions[OpCode.F64_CONVERT_I32_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asInt(); + stack.push(Value.fromDouble(OpcodeImpl.F64_CONVERT_I32_S(tos))); + }; + instructions[OpCode.I32_EXTEND_8_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_EXTEND_8_S(tos))); + }; + instructions[OpCode.F64_NEAREST.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var val = stack.pop().asDouble(); + stack.push(Value.fromDouble(OpcodeImpl.F64_NEAREST(val))); + }; + instructions[OpCode.F32_NEAREST.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var val = stack.pop().asFloat(); + stack.push(Value.fromFloat(OpcodeImpl.F32_NEAREST(val))); + }; + instructions[OpCode.F64_TRUNC.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var val = stack.pop().asDouble(); + stack.push(Value.fromDouble(OpcodeImpl.F64_TRUNC(val))); + }; + instructions[OpCode.F64_CEIL.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var val = stack.pop().asDouble(); + stack.push(Value.fromDouble(OpcodeImpl.F64_CEIL(val))); + }; + instructions[OpCode.F32_CEIL.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var val = stack.pop().asFloat(); + stack.push(Value.fromFloat(OpcodeImpl.F32_CEIL(val))); + }; + instructions[OpCode.F64_FLOOR.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var val = stack.pop().asDouble(); + stack.push(Value.fromDouble(OpcodeImpl.F64_FLOOR(val))); + }; + instructions[OpCode.F32_FLOOR.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var val = stack.pop().asFloat(); + stack.push(Value.fromFloat(OpcodeImpl.F32_FLOOR(val))); + }; + instructions[OpCode.F64_SQRT.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var val = stack.pop().asDouble(); + stack.push(Value.fromDouble(OpcodeImpl.F64_SQRT(val))); + }; + instructions[OpCode.F32_SQRT.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var val = stack.pop().asFloat(); + stack.push(Value.fromFloat(OpcodeImpl.F32_SQRT(val))); + }; + instructions[OpCode.F64_MAX.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asDouble(); + var b = stack.pop().asDouble(); + stack.push(Value.fromDouble(OpcodeImpl.F64_MAX(a, b))); + }; + instructions[OpCode.F32_MAX.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asFloat(); + var b = stack.pop().asFloat(); + stack.push(Value.fromFloat(OpcodeImpl.F32_MAX(a, b))); + }; + instructions[OpCode.F64_MIN.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asDouble(); + var b = stack.pop().asDouble(); + stack.push(Value.fromDouble(OpcodeImpl.F64_MIN(a, b))); + }; + instructions[OpCode.F32_MIN.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asFloat(); + var b = stack.pop().asFloat(); + stack.push(Value.fromFloat(OpcodeImpl.F32_MIN(a, b))); + }; + instructions[OpCode.F64_DIV.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asDouble(); + var b = stack.pop().asDouble(); + stack.push(Value.fromDouble(b / a)); + }; + instructions[OpCode.F32_DIV.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asFloat(); + var b = stack.pop().asFloat(); + stack.push(Value.fromFloat(b / a)); + }; + instructions[OpCode.F64_MUL.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asDouble(); + var b = stack.pop().asDouble(); + stack.push(Value.fromDouble(b * a)); + }; + instructions[OpCode.F32_MUL.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asFloat(); + var b = stack.pop().asFloat(); + stack.push(Value.fromFloat(b * a)); + }; + instructions[OpCode.F64_SUB.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asDouble(); + var b = stack.pop().asDouble(); + stack.push(Value.fromDouble(b - a)); + }; + instructions[OpCode.F32_SUB.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asFloat(); + var b = stack.pop().asFloat(); + stack.push(Value.fromFloat(b - a)); + }; + instructions[OpCode.F64_ADD.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asDouble(); + var b = stack.pop().asDouble(); + stack.push(Value.fromDouble(a + b)); + }; + instructions[OpCode.F32_ADD.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asFloat(); + var b = stack.pop().asFloat(); + stack.push(Value.fromFloat(a + b)); + }; + instructions[OpCode.I32_ROTR.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var c = stack.pop().asInt(); + var v = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_ROTR(v, c))); + }; + instructions[OpCode.I32_ROTL.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var c = stack.pop().asInt(); + var v = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_ROTL(v, c))); + }; + instructions[OpCode.I32_SHR_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var c = stack.pop().asInt(); + var v = stack.pop().asInt(); + stack.push(Value.i32(v >>> c)); + }; + instructions[OpCode.I32_SHR_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var c = stack.pop().asInt(); + var v = stack.pop().asInt(); + stack.push(Value.i32(v >> c)); + }; + instructions[OpCode.I32_SHL.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var c = stack.pop().asInt(); + var v = stack.pop().asInt(); + stack.push(Value.i32(v << c)); + }; + instructions[OpCode.I32_XOR.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asInt(); + var b = stack.pop().asInt(); + stack.push(Value.i32(a ^ b)); + }; + instructions[OpCode.I32_OR.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asInt(); + var b = stack.pop().asInt(); + stack.push(Value.i32(a | b)); + }; + instructions[OpCode.I32_AND.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asInt(); + var b = stack.pop().asInt(); + stack.push(Value.i32(a & b)); + }; + instructions[OpCode.I64_POPCNT.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asLong(); + stack.push(Value.i64(OpcodeImpl.I64_POPCNT(tos))); + }; + instructions[OpCode.I64_CTZ.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop(); + stack.push(Value.i64(OpcodeImpl.I64_CTZ(tos.asLong()))); + }; + instructions[OpCode.I64_CLZ.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop(); + stack.push(Value.i64(OpcodeImpl.I64_CLZ(tos.asLong()))); + }; + instructions[OpCode.I64_ROTR.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var c = stack.pop().asLong(); + var v = stack.pop().asLong(); + stack.push(Value.i64(OpcodeImpl.I64_ROTR(v, c))); + }; + instructions[OpCode.I64_ROTL.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var c = stack.pop().asLong(); + var v = stack.pop().asLong(); + stack.push(Value.i64(OpcodeImpl.I64_ROTL(v, c))); + }; + instructions[OpCode.I64_REM_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asLong(); + var a = stack.pop().asLong(); + stack.push(Value.i64(OpcodeImpl.I64_REM_U(a, b))); + }; + instructions[OpCode.I64_REM_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asLong(); + var a = stack.pop().asLong(); + stack.push(Value.i64(OpcodeImpl.I64_REM_S(a, b))); + }; + instructions[OpCode.I64_SHR_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var c = stack.pop().asLong(); + var v = stack.pop().asLong(); + stack.push(Value.i64(v >>> c)); + }; + instructions[OpCode.I64_SHR_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var c = stack.pop().asLong(); + var v = stack.pop().asLong(); + stack.push(Value.i64(v >> c)); + }; + instructions[OpCode.I64_SHL.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var c = stack.pop().asLong(); + var v = stack.pop().asLong(); + stack.push(Value.i64(v << c)); + }; + instructions[OpCode.I64_XOR.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asLong(); + var b = stack.pop().asLong(); + stack.push(Value.i64(a ^ b)); + }; + instructions[OpCode.I64_OR.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asLong(); + var b = stack.pop().asLong(); + stack.push(Value.i64(a | b)); + }; + instructions[OpCode.I64_AND.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asLong(); + var b = stack.pop().asLong(); + stack.push(Value.i64(a & b)); + }; + instructions[OpCode.I32_REM_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asInt(); + var a = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_REM_U(a, b))); + }; + instructions[OpCode.I32_REM_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asInt(); + var a = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_REM_S(a, b))); + }; + instructions[OpCode.I64_DIV_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asLong(); + var a = stack.pop().asLong(); + stack.push(Value.i64(OpcodeImpl.I64_DIV_U(a, b))); + }; + instructions[OpCode.I64_DIV_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asLong(); + var a = stack.pop().asLong(); + stack.push(Value.i64(OpcodeImpl.I64_DIV_S(a, b))); + }; + instructions[OpCode.I64_GT_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asLong(); + var a = stack.pop().asLong(); + stack.push(Value.i32(OpcodeImpl.I64_GT_S(a, b))); + }; + instructions[OpCode.I32_GT_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asInt(); + var a = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_GT_U(a, b))); + }; + instructions[OpCode.I32_GT_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asInt(); + var a = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_GT_S(a, b))); + }; + instructions[OpCode.I64_LT_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asLong(); + var a = stack.pop().asLong(); + stack.push(Value.i32(OpcodeImpl.I64_LT_U(a, b))); + }; + instructions[OpCode.I64_LT_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asLong(); + var a = stack.pop().asLong(); + stack.push(Value.i32(OpcodeImpl.I64_LT_S(a, b))); + }; + instructions[OpCode.I32_LT_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asInt(); + var a = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_LT_U(a, b))); + }; + instructions[OpCode.I32_LT_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asInt(); + var a = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_LT_S(a, b))); + }; + instructions[OpCode.I64_EQZ.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asLong(); + stack.push(Value.i32(OpcodeImpl.I64_EQZ(a))); + }; + instructions[OpCode.I32_EQZ.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_EQZ(a))); + }; + instructions[OpCode.I64_NE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asLong(); + var b = stack.pop().asLong(); + stack.push(Value.i32(OpcodeImpl.I64_NE(a, b))); + }; + instructions[OpCode.I32_NE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asInt(); + var b = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_NE(a, b))); + }; + instructions[OpCode.I64_EQ.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asLong(); + var b = stack.pop().asLong(); + stack.push(Value.i32(OpcodeImpl.I64_EQ(a, b))); + }; + instructions[OpCode.I32_EQ.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var a = stack.pop().asInt(); + var b = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_EQ(a, b))); + }; + instructions[OpCode.MEMORY_SIZE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var sz = instance.memory().pages(); + stack.push(Value.i32(sz)); + }; + instructions[OpCode.I64_STORE32.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var value = stack.pop().asLong(); + var ptr = (int) (operands[1] + stack.pop().asInt()); + instance.memory().writeI32(ptr, (int) value); + }; + instructions[OpCode.I32_STORE8.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var value = stack.pop().asByte(); + var ptr = (int) (operands[1] + stack.pop().asInt()); + instance.memory().writeByte(ptr, value); + }; + instructions[OpCode.I64_STORE8.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var value = stack.pop().asByte(); + var ptr = (int) (operands[1] + stack.pop().asInt()); + instance.memory().writeByte(ptr, value); + }; + instructions[OpCode.F64_PROMOTE_F32.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop(); + stack.push(Value.fromDouble(tos.asFloat())); + }; + instructions[OpCode.F64_REINTERPRET_I64.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + long tos = stack.pop().asLong(); + stack.push(Value.fromDouble(OpcodeImpl.F64_REINTERPRET_I64(tos))); + }; + instructions[OpCode.I32_WRAP_I64.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop(); + stack.push(Value.i32(tos.asInt())); + }; + instructions[OpCode.I64_EXTEND_I32_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop(); + stack.push(Value.i64(tos.asInt())); + }; + instructions[OpCode.I64_EXTEND_I32_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + int tos = stack.pop().asInt(); + stack.push(Value.i64(OpcodeImpl.I64_EXTEND_I32_U(tos))); + }; + instructions[OpCode.I32_REINTERPRET_F32.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + float tos = stack.pop().asFloat(); + stack.push(Value.i32(OpcodeImpl.I32_REINTERPRET_F32(tos))); + }; + instructions[OpCode.I64_REINTERPRET_F64.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + double tos = stack.pop().asDouble(); + stack.push(Value.i64(OpcodeImpl.I64_REINTERPRET_F64(tos))); + }; + instructions[OpCode.F32_REINTERPRET_I32.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + int tos = stack.pop().asInt(); + stack.push(Value.fromFloat(OpcodeImpl.F32_REINTERPRET_I32(tos))); + }; + instructions[OpCode.F32_DEMOTE_F64.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var val = stack.pop().asDouble(); + + stack.push(Value.fromFloat((float) val)); + }; + instructions[OpCode.F32_CONVERT_I32_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asInt(); + stack.push(Value.fromFloat(OpcodeImpl.F32_CONVERT_I32_S(tos))); + }; + instructions[OpCode.I32_EXTEND_16_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asInt(); + stack.push(Value.i32(OpcodeImpl.I32_EXTEND_16_S(tos))); + }; + instructions[OpCode.I64_TRUNC_F64_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + double tos = stack.pop().asDouble(); + stack.push(Value.i64(OpcodeImpl.I64_TRUNC_F64_S(tos))); + }; + instructions[OpCode.F32_COPYSIGN.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asFloat(); + var a = stack.pop().asFloat(); + stack.push(Value.fromFloat(OpcodeImpl.F32_COPYSIGN(a, b))); + }; + instructions[OpCode.F32_ABS.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var val = stack.pop().asFloat(); + stack.push(Value.fromFloat(OpcodeImpl.F32_ABS(val))); + }; + instructions[OpCode.F64_ABS.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var val = stack.pop().asDouble(); + stack.push(Value.fromDouble(OpcodeImpl.F64_ABS(val))); + }; + instructions[OpCode.F32_NE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asFloat(); + var a = stack.pop().asFloat(); + stack.push(Value.i32(OpcodeImpl.F32_NE(a, b))); + }; + instructions[OpCode.F64_NE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asDouble(); + var a = stack.pop().asDouble(); + stack.push(Value.i32(OpcodeImpl.F64_NE(a, b))); + }; + instructions[OpCode.F32_LT.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asFloat(); + var a = stack.pop().asFloat(); + stack.push(Value.i32(OpcodeImpl.F32_LT(a, b))); + }; + instructions[OpCode.F64_LT.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asDouble(); + var a = stack.pop().asDouble(); + stack.push(Value.i32(OpcodeImpl.F64_LT(a, b))); + }; + instructions[OpCode.F32_LE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asFloat(); + var a = stack.pop().asFloat(); + stack.push(Value.i32(OpcodeImpl.F32_LE(a, b))); + }; + instructions[OpCode.F64_LE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asDouble(); + var a = stack.pop().asDouble(); + stack.push(Value.i32(OpcodeImpl.F64_LE(a, b))); + }; + instructions[OpCode.F32_GE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asFloat(); + var a = stack.pop().asFloat(); + stack.push(Value.i32(OpcodeImpl.F32_GE(a, b))); + }; + instructions[OpCode.F64_GE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asDouble(); + var a = stack.pop().asDouble(); + stack.push(Value.i32(OpcodeImpl.F64_GE(a, b))); + }; + instructions[OpCode.F32_GT.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asFloat(); + var a = stack.pop().asFloat(); + stack.push(Value.i32(OpcodeImpl.F32_GT(a, b))); + }; + instructions[OpCode.F64_GT.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asDouble(); + var a = stack.pop().asDouble(); + stack.push(Value.i32(OpcodeImpl.F64_GT(a, b))); + }; + instructions[OpCode.F32_CONVERT_I32_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asInt(); + stack.push(Value.fromFloat(OpcodeImpl.F32_CONVERT_I32_U(tos))); + }; + instructions[OpCode.F32_CONVERT_I64_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asLong(); + stack.push(Value.fromFloat(OpcodeImpl.F32_CONVERT_I64_S(tos))); + }; + instructions[OpCode.REF_NULL.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var type = ValueType.forId((int) operands[0]); + stack.push(new Value(type, (long) REF_NULL_VALUE)); + }; + instructions[OpCode.ELEM_DROP.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var x = (int) operands[0]; + instance.setElement(x, null); + }; + instructions[OpCode.REF_IS_NULL.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var val = stack.pop(); + stack.push( + val.equals(Value.EXTREF_NULL) || val.equals(Value.FUNCREF_NULL) + ? Value.TRUE + : Value.FALSE); + }; + instructions[OpCode.DATA_DROP.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var segment = (int) operands[0]; + instance.memory().drop(segment); + }; + instructions[OpCode.F64_CONVERT_I64_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asLong(); + stack.push(Value.fromDouble(OpcodeImpl.F64_CONVERT_I64_S(tos))); + }; + instructions[OpCode.TABLE_GROW.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tableidx = (int) operands[0]; + var table = instance.table(tableidx); + + var size = stack.pop().asInt(); + var valValue = stack.pop(); + var val = valValue.asExtRef(); + + var res = table.grow(size, val, instance); + stack.push(Value.i32(res)); + }; + instructions[OpCode.TABLE_SIZE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tableidx = (int) operands[0]; + var table = instance.table(tableidx); + + stack.push(Value.i32(table.size())); + }; + instructions[OpCode.TABLE_FILL.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tableidx = (int) operands[0]; + + var size = stack.pop().asInt(); + var val = stack.pop().asExtRef(); + var offset = stack.pop().asInt(); + + OpcodeImpl.TABLE_FILL(instance, tableidx, size, val, offset); + }; + instructions[OpCode.TABLE_COPY.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tableidxSrc = (int) operands[1]; + var tableidxDst = (int) operands[0]; + + var size = stack.pop().asInt(); + var s = stack.pop().asInt(); + var d = stack.pop().asInt(); + + OpcodeImpl.TABLE_COPY(instance, tableidxSrc, tableidxDst, size, s, d); + }; + instructions[OpCode.MEMORY_COPY.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var memidxSrc = (int) operands[0]; + var memidxDst = (int) operands[1]; + if (memidxDst != 0 && memidxSrc != 0) + throw new WASMRuntimeException( + "We don't support non zero index for memory: " + + memidxSrc + + " " + + memidxDst); + var size = stack.pop().asInt(); + var offset = stack.pop().asInt(); + var destination = stack.pop().asInt(); + instance.memory().copy(destination, offset, size); + }; + instructions[OpCode.TABLE_INIT.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tableidx = (int) operands[1]; + var elementidx = (int) operands[0]; + + var size = stack.pop().asInt(); + var elemidx = stack.pop().asInt(); + var offset = stack.pop().asInt(); + + OpcodeImpl.TABLE_INIT(instance, tableidx, elementidx, size, elemidx, offset); + }; + instructions[OpCode.MEMORY_INIT.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var segmentId = (int) operands[0]; + var memidx = (int) operands[1]; + if (memidx != 0) + throw new WASMRuntimeException( + "We don't support non zero index for memory: " + memidx); + var size = stack.pop().asInt(); + var offset = stack.pop().asInt(); + var destination = stack.pop().asInt(); + instance.memory().initPassiveSegment(segmentId, destination, offset, size); + }; + instructions[OpCode.I64_TRUNC_F32_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asFloat(); + stack.push(Value.i64(OpcodeImpl.I64_TRUNC_F32_S(tos))); + }; + instructions[OpCode.I32_TRUNC_F64_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + double tos = stack.pop().asDouble(); + stack.push(Value.i32(OpcodeImpl.I32_TRUNC_F64_U(tos))); + }; + instructions[OpCode.I32_TRUNC_F64_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asDouble(); + stack.push(Value.i32(OpcodeImpl.I32_TRUNC_F64_S(tos))); + }; + instructions[OpCode.I64_TRUNC_SAT_F64_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + double tos = stack.pop().asDouble(); + stack.push(Value.i64(OpcodeImpl.I64_TRUNC_SAT_F64_U(tos))); + }; + instructions[OpCode.I64_TRUNC_SAT_F64_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asDouble(); + stack.push(Value.i64(OpcodeImpl.I64_TRUNC_SAT_F64_S(tos))); + }; + instructions[OpCode.I64_TRUNC_SAT_F32_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asFloat(); + stack.push(Value.i64(OpcodeImpl.I64_TRUNC_SAT_F32_U(tos))); + }; + instructions[OpCode.I64_TRUNC_SAT_F32_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asFloat(); + stack.push(Value.i64(OpcodeImpl.I64_TRUNC_SAT_F32_S(tos))); + }; + instructions[OpCode.I64_TRUNC_F64_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asDouble(); + stack.push(Value.i64(OpcodeImpl.I64_TRUNC_F64_U(tos))); + }; + instructions[OpCode.I64_TRUNC_F32_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asFloat(); + stack.push(Value.i64(OpcodeImpl.I64_TRUNC_F32_U(tos))); + }; + instructions[OpCode.F32_CONVERT_I64_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asLong(); + stack.push(Value.fromFloat(OpcodeImpl.F32_CONVERT_I64_U(tos))); + }; + instructions[OpCode.I32_TRUNC_F32_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asFloat(); + stack.push(Value.i32(OpcodeImpl.I32_TRUNC_F32_U(tos))); + }; + instructions[OpCode.I32_TRUNC_SAT_F64_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + double tos = Double.longBitsToDouble(stack.pop().asLong()); + stack.push(Value.i32(OpcodeImpl.I32_TRUNC_SAT_F64_U(tos))); + }; + instructions[OpCode.I32_TRUNC_SAT_F64_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asDouble(); + stack.push(Value.i32(OpcodeImpl.I32_TRUNC_SAT_F64_S(tos))); + }; + instructions[OpCode.I32_TRUNC_SAT_F32_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asFloat(); + stack.push(Value.i32(OpcodeImpl.I32_TRUNC_SAT_F32_U(tos))); + }; + instructions[OpCode.I32_TRUNC_SAT_F32_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asFloat(); + stack.push(Value.i32(OpcodeImpl.I32_TRUNC_SAT_F32_S(tos))); + }; + instructions[OpCode.I32_TRUNC_F32_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + float tos = stack.pop().asFloat(); + stack.push(Value.i32(OpcodeImpl.I32_TRUNC_F32_S(tos))); + }; + instructions[OpCode.F64_COPYSIGN.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var b = stack.pop().asDouble(); + var a = stack.pop().asDouble(); + stack.push(Value.fromDouble(OpcodeImpl.F64_COPYSIGN(a, b))); + }; + instructions[OpCode.F32_TRUNC.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var val = stack.pop().asFloat(); + stack.push(Value.fromFloat(OpcodeImpl.F32_TRUNC(val))); + }; + instructions[OpCode.CALL.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var funcId = (int) operands[0]; + var typeId = instance.functionType(funcId); + var type = instance.type(typeId); + // given a list of param types, let's pop those params off the stack + // and pass as args to the function call + var args = extractArgsForParams(stack, type.params()); + call(stack, instance, callStack, funcId, args, type, false); + }; + instructions[OpCode.F64_NEG.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asDouble(); + stack.push(Value.fromDouble(-tos)); + }; + instructions[OpCode.F32_NEG.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tos = stack.pop().asFloat(); + stack.push(Value.fromFloat(-tos)); + }; + instructions[OpCode.MEMORY_FILL.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var memidx = (int) operands[0]; + if (memidx != 0) { + throw new WASMRuntimeException( + "We don't support multiple memories just yet"); + } + var size = stack.pop().asInt(); + var val = stack.pop().asByte(); + var offset = stack.pop().asInt(); + var end = (size + offset); + instance.memory().fill(val, offset, end); + }; + instructions[OpCode.MEMORY_GROW.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var size = stack.pop().asInt(); + var nPages = instance.memory().grow(size); + stack.push(Value.i32(nPages)); + }; + + instructions[OpCode.F64_STORE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var value = stack.pop().asDouble(); + var ptr = readMemPtr(stack, operands); + instance.memory().writeF64(ptr, value); + }; + instructions[OpCode.F32_STORE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var value = stack.pop().asFloat(); + var ptr = readMemPtr(stack, operands); + instance.memory().writeF32(ptr, value); + }; + instructions[OpCode.I64_STORE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var value = stack.pop().asLong(); + var ptr = readMemPtr(stack, operands); + instance.memory().writeLong(ptr, value); + }; + instructions[OpCode.I32_STORE16.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var value = stack.pop().asShort(); + var ptr = readMemPtr(stack, operands); + instance.memory().writeShort(ptr, value); + }; + instructions[OpCode.I64_STORE16.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var value = stack.pop().asShort(); + var ptr = readMemPtr(stack, operands); + instance.memory().writeShort(ptr, value); + }; + instructions[OpCode.I32_STORE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var value = stack.pop().asInt(); + var ptr = readMemPtr(stack, operands); + instance.memory().writeI32(ptr, value); + }; + instructions[OpCode.I64_LOAD32_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var ptr = readMemPtr(stack, operands); + var val = instance.memory().readU32(ptr); + stack.push(val); + }; + instructions[OpCode.I64_LOAD32_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var ptr = readMemPtr(stack, operands); + var val = instance.memory().readI32(ptr); + // TODO this is a bit hacky + stack.push(Value.i64(val.asInt())); + }; + instructions[OpCode.I64_LOAD16_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var ptr = readMemPtr(stack, operands); + var val = instance.memory().readU16(ptr); + // TODO this is a bit hacky + stack.push(Value.i64(val.asInt())); + }; + instructions[OpCode.I32_LOAD16_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var ptr = readMemPtr(stack, operands); + var val = instance.memory().readU16(ptr); + stack.push(val); + }; + instructions[OpCode.I64_LOAD16_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var ptr = readMemPtr(stack, operands); + var val = instance.memory().readI16(ptr); + // TODO this is a bit hacky + stack.push(Value.i64(val.asInt())); + }; + instructions[OpCode.I32_LOAD16_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var ptr = readMemPtr(stack, operands); + var val = instance.memory().readI16(ptr); + stack.push(val); + }; + instructions[OpCode.I64_LOAD8_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var ptr = readMemPtr(stack, operands); + var val = instance.memory().readU8(ptr); + // TODO a bit hacky + stack.push(Value.i64(val.asInt())); + }; + instructions[OpCode.I32_LOAD8_U.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var ptr = readMemPtr(stack, operands); + var val = instance.memory().readU8(ptr); + stack.push(val); + }; + instructions[OpCode.I64_LOAD8_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var ptr = readMemPtr(stack, operands); + var val = instance.memory().readI8(ptr); + // TODO a bit hacky + stack.push(Value.i64(val.asInt())); + }; + instructions[OpCode.I32_LOAD8_S.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var ptr = readMemPtr(stack, operands); + var val = instance.memory().readI8(ptr); + stack.push(val); + }; + instructions[OpCode.F64_LOAD.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var ptr = readMemPtr(stack, operands); + var val = instance.memory().readF64(ptr); + stack.push(val); + }; + instructions[OpCode.F32_LOAD.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var ptr = readMemPtr(stack, operands); + var val = instance.memory().readF32(ptr); + stack.push(val); + }; + instructions[OpCode.I64_LOAD.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var ptr = readMemPtr(stack, operands); + var val = instance.memory().readI64(ptr); + stack.push(val); + }; + instructions[OpCode.I32_LOAD.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var ptr = readMemPtr(stack, operands); + var val = instance.memory().readI32(ptr); + stack.push(val); + }; + instructions[OpCode.TABLE_SET.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var idx = (int) operands[0]; + var table = instance.table(idx); + + var value = stack.pop().asExtRef(); + var i = stack.pop().asInt(); + table.setRef(i, value, instance); + }; + instructions[OpCode.TABLE_GET.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var idx = (int) operands[0]; + var i = stack.pop().asInt(); + stack.push(OpcodeImpl.TABLE_GET(instance, idx, i)); + }; + instructions[OpCode.GLOBAL_SET.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var id = (int) operands[0]; + var val = stack.pop(); + instance.writeGlobal(id, val); + }; + instructions[OpCode.GLOBAL_GET.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + int idx = (int) operands[0]; + var val = instance.readGlobal(idx); + + stack.push(val); + }; + instructions[OpCode.SELECT.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var pred = stack.pop().asInt(); + var b = stack.pop(); + var a = stack.pop(); + if (pred == 0) { + stack.push(b); + } else { + stack.push(a); + } + }; + instructions[OpCode.SELECT_T.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var pred = stack.pop().asInt(); + var b = stack.pop(); + var a = stack.pop(); + if (pred == 0) { + stack.push(b); + } else { + stack.push(a); + } + }; + instructions[OpCode.CALL_INDIRECT.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var tableIdx = (int) operands[1]; + var table = instance.table(tableIdx); + + var typeId = (int) operands[0]; + int funcTableIdx = stack.pop().asInt(); + int funcId = table.ref(funcTableIdx).asFuncRef(); + var tableInstance = table.instance(funcTableIdx); + if (tableInstance != null) { + instance = tableInstance; + } + if (funcId == REF_NULL_VALUE) { + throw new ChicoryException("uninitialized element " + funcTableIdx); + } + var type = instance.type(typeId); + + // given a list of param types, let's pop those params off the stack + // and pass as args to the function call + var args = extractArgsForParams(stack, type.params()); + call(stack, instance, callStack, funcId, args, type, false); + }; + instructions[OpCode.BLOCK.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var paramsSize = numberOfParams(instance, instruction); + var returnsSize = numberOfValuesToReturn(instance, instruction); + frame.pushCtrl( + instruction.opcode(), + paramsSize, + returnsSize, + stack.size() - paramsSize); + }; + instructions[OpCode.LOOP.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var paramsSize = numberOfParams(instance, instruction); + var returnsSize = numberOfValuesToReturn(instance, instruction); + frame.pushCtrl( + instruction.opcode(), + paramsSize, + returnsSize, + stack.size() - paramsSize); + }; + instructions[OpCode.IF.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var predValue = stack.pop(); + var paramsSize = numberOfParams(instance, instruction); + var returnsSize = numberOfValuesToReturn(instance, instruction); + frame.pushCtrl( + instruction.opcode(), + paramsSize, + returnsSize, + stack.size() - paramsSize); + + frame.jumpTo( + predValue.asInt() == 0 + ? instruction.labelFalse() + : instruction.labelTrue()); + }; + instructions[OpCode.BR.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + checkInterruption(); + ctrlJump(frame, stack, (int) instruction.operands()[0]); + frame.jumpTo(instruction.labelTrue()); + }; + instructions[OpCode.BR_TABLE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var predValue = stack.pop(); + var pred = predValue.asInt(); + + var defaultIdx = instruction.operands().length - 1; + if (pred < 0 || pred >= defaultIdx) { + // choose default + ctrlJump(frame, stack, (int) instruction.operands()[defaultIdx]); + frame.jumpTo(instruction.labelTable()[defaultIdx]); + } else { + ctrlJump(frame, stack, (int) instruction.operands()[pred]); + frame.jumpTo(instruction.labelTable()[pred]); + } + }; + instructions[OpCode.BR_IF.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var predValue = stack.pop(); + var pred = predValue.asInt(); + + if (pred == 0) { + frame.jumpTo(instruction.labelFalse()); + } else { + ctrlJump(frame, stack, (int) instruction.operands()[0]); + frame.jumpTo(instruction.labelTrue()); + } + }; + instructions[OpCode.END.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + var ctrlFrame = frame.popCtrl(); + StackFrame.doControlTransfer(ctrlFrame, stack); + + // if this is the last end, then we're done with + // the function + if (frame.isLastBlock()) { + frame.shouldReturn(true); + } + }; + instructions[OpCode.RETURN.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + // RETURN doesn't pass through the END + var ctrlFrame = frame.popCtrlTillCall(); + StackFrame.doControlTransfer(ctrlFrame, stack); + + frame.shouldReturn(true); + }; + instructions[OpCode.ELSE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + frame.jumpTo(instruction.labelTrue()); + }; + instructions[OpCode.I32_CONST.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + stack.push(Value.i32(operands[0])); + }; + instructions[OpCode.I64_CONST.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + stack.push(Value.i64(operands[0])); + }; + instructions[OpCode.F32_CONST.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + stack.push(Value.f32(operands[0])); + }; + instructions[OpCode.F64_CONST.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + stack.push(Value.f64(operands[0])); + }; + instructions[OpCode.REF_FUNC.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + stack.push(Value.funcRef((int) operands[0])); + }; + instructions[OpCode.LOCAL_GET.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + stack.push(frame.local((int) operands[0])); + }; + instructions[OpCode.LOCAL_SET.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + frame.setLocal((int) operands[0], stack.pop()); + }; + instructions[OpCode.LOCAL_TEE.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + // here we peek instead of pop, leaving it on the stack + frame.setLocal((int) operands[0], stack.peek()); + }; + instructions[OpCode.DROP.ordinal()] = + (frame, stack, instance, callStack, instruction, operands) -> { + stack.pop(); + }; } - private static void I64_ADD(MStack stack) { - var a = stack.pop().asLong(); - var b = stack.pop().asLong(); - stack.push(Value.i64(a + b)); + private static int numberOfParams(Instance instance, Instruction scope) { + var typeId = (int) scope.operands()[0]; + if (typeId == 0x40) { // epsilon + return 0; + } + if (ValueType.isValid(typeId)) { + return 0; + } + return instance.type(typeId).params().size(); } - private static void I32_SUB(MStack stack) { - var a = stack.pop().asInt(); - var b = stack.pop().asInt(); - stack.push(Value.i32(b - a)); + private static int numberOfValuesToReturn(Instance instance, Instruction scope) { + if (scope.opcode() == OpCode.END) { + return 0; + } + var typeId = (int) scope.operands()[0]; + if (typeId == 0x40) { // epsilon + return 0; + } + if (ValueType.isValid(typeId)) { + return 1; + } + return instance.type(typeId).returns().size(); } - private static void I64_SUB(MStack stack) { - var a = stack.pop().asLong(); - var b = stack.pop().asLong(); - stack.push(Value.i64(b - a)); - } - - private static void I32_MUL(MStack stack) { - var a = stack.pop().asInt(); - var b = stack.pop().asInt(); - stack.push(Value.i32(a * b)); - } - - private static void I64_MUL(MStack stack) { - var a = stack.pop().asLong(); - var b = stack.pop().asLong(); - stack.push(Value.i64(a * b)); - } - - private static void I32_DIV_S(MStack stack) { - var b = stack.pop().asInt(); - var a = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_DIV_S(a, b))); - } - - private static void I32_DIV_U(MStack stack) { - var b = stack.pop().asInt(); - var a = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_DIV_U(a, b))); - } - - private static void I64_EXTEND_8_S(MStack stack) { - var tos = stack.pop().asLong(); - stack.push(Value.i64(OpcodeImpl.I64_EXTEND_8_S(tos))); - } - - private static void I64_EXTEND_16_S(MStack stack) { - var tos = stack.pop().asLong(); - stack.push(Value.i64(OpcodeImpl.I64_EXTEND_16_S(tos))); - } - - private static void I64_EXTEND_32_S(MStack stack) { - var tos = stack.pop().asLong(); - stack.push(Value.i64(OpcodeImpl.I64_EXTEND_32_S(tos))); - } - - private static void F64_CONVERT_I64_U(MStack stack) { - var tos = stack.pop().asLong(); - stack.push(Value.fromDouble(OpcodeImpl.F64_CONVERT_I64_U(tos))); - } - - private static void F64_CONVERT_I32_U(MStack stack) { - var tos = stack.pop().asInt(); - stack.push(Value.fromDouble(OpcodeImpl.F64_CONVERT_I32_U(tos))); - } - - private static void F64_CONVERT_I32_S(MStack stack) { - var tos = stack.pop().asInt(); - stack.push(Value.fromDouble(OpcodeImpl.F64_CONVERT_I32_S(tos))); - } - - private static void I32_EXTEND_8_S(MStack stack) { - var tos = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_EXTEND_8_S(tos))); - } - - private static void F64_NEAREST(MStack stack) { - var val = stack.pop().asDouble(); - stack.push(Value.fromDouble(OpcodeImpl.F64_NEAREST(val))); - } - - private static void F32_NEAREST(MStack stack) { - var val = stack.pop().asFloat(); - stack.push(Value.fromFloat(OpcodeImpl.F32_NEAREST(val))); - } - - private static void F64_TRUNC(MStack stack) { - var val = stack.pop().asDouble(); - stack.push(Value.fromDouble(OpcodeImpl.F64_TRUNC(val))); - } - - private static void F64_CEIL(MStack stack) { - var val = stack.pop().asDouble(); - stack.push(Value.fromDouble(OpcodeImpl.F64_CEIL(val))); - } - - private static void F32_CEIL(MStack stack) { - var val = stack.pop().asFloat(); - stack.push(Value.fromFloat(OpcodeImpl.F32_CEIL(val))); - } - - private static void F64_FLOOR(MStack stack) { - var val = stack.pop().asDouble(); - stack.push(Value.fromDouble(OpcodeImpl.F64_FLOOR(val))); - } - - private static void F32_FLOOR(MStack stack) { - var val = stack.pop().asFloat(); - stack.push(Value.fromFloat(OpcodeImpl.F32_FLOOR(val))); - } - - private static void F64_SQRT(MStack stack) { - var val = stack.pop().asDouble(); - stack.push(Value.fromDouble(OpcodeImpl.F64_SQRT(val))); - } - - private static void F32_SQRT(MStack stack) { - var val = stack.pop().asFloat(); - stack.push(Value.fromFloat(OpcodeImpl.F32_SQRT(val))); - } - - private static void F64_MAX(MStack stack) { - var a = stack.pop().asDouble(); - var b = stack.pop().asDouble(); - stack.push(Value.fromDouble(OpcodeImpl.F64_MAX(a, b))); - } - - private static void F32_MAX(MStack stack) { - var a = stack.pop().asFloat(); - var b = stack.pop().asFloat(); - stack.push(Value.fromFloat(OpcodeImpl.F32_MAX(a, b))); - } - - private static void F64_MIN(MStack stack) { - var a = stack.pop().asDouble(); - var b = stack.pop().asDouble(); - stack.push(Value.fromDouble(OpcodeImpl.F64_MIN(a, b))); - } - - private static void F32_MIN(MStack stack) { - var a = stack.pop().asFloat(); - var b = stack.pop().asFloat(); - stack.push(Value.fromFloat(OpcodeImpl.F32_MIN(a, b))); - } - - private static void F64_DIV(MStack stack) { - var a = stack.pop().asDouble(); - var b = stack.pop().asDouble(); - stack.push(Value.fromDouble(b / a)); - } - - private static void F32_DIV(MStack stack) { - var a = stack.pop().asFloat(); - var b = stack.pop().asFloat(); - stack.push(Value.fromFloat(b / a)); - } - - private static void F64_MUL(MStack stack) { - var a = stack.pop().asDouble(); - var b = stack.pop().asDouble(); - stack.push(Value.fromDouble(b * a)); - } - - private static void F32_MUL(MStack stack) { - var a = stack.pop().asFloat(); - var b = stack.pop().asFloat(); - stack.push(Value.fromFloat(b * a)); - } - - private static void F64_SUB(MStack stack) { - var a = stack.pop().asDouble(); - var b = stack.pop().asDouble(); - stack.push(Value.fromDouble(b - a)); - } - - private static void F32_SUB(MStack stack) { - var a = stack.pop().asFloat(); - var b = stack.pop().asFloat(); - stack.push(Value.fromFloat(b - a)); - } - - private static void F64_ADD(MStack stack) { - var a = stack.pop().asDouble(); - var b = stack.pop().asDouble(); - stack.push(Value.fromDouble(a + b)); - } - - private static void F32_ADD(MStack stack) { - var a = stack.pop().asFloat(); - var b = stack.pop().asFloat(); - stack.push(Value.fromFloat(a + b)); - } - - private static void I32_ROTR(MStack stack) { - var c = stack.pop().asInt(); - var v = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_ROTR(v, c))); - } - - private static void I32_ROTL(MStack stack) { - var c = stack.pop().asInt(); - var v = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_ROTL(v, c))); - } - - private static void I32_SHR_U(MStack stack) { - var c = stack.pop().asInt(); - var v = stack.pop().asInt(); - stack.push(Value.i32(v >>> c)); - } - - private static void I32_SHR_S(MStack stack) { - var c = stack.pop().asInt(); - var v = stack.pop().asInt(); - stack.push(Value.i32(v >> c)); - } - - private static void I32_SHL(MStack stack) { - var c = stack.pop().asInt(); - var v = stack.pop().asInt(); - stack.push(Value.i32(v << c)); - } - - private static void I32_XOR(MStack stack) { - var a = stack.pop().asInt(); - var b = stack.pop().asInt(); - stack.push(Value.i32(a ^ b)); - } - - private static void I32_OR(MStack stack) { - var a = stack.pop().asInt(); - var b = stack.pop().asInt(); - stack.push(Value.i32(a | b)); - } - - private static void I32_AND(MStack stack) { - var a = stack.pop().asInt(); - var b = stack.pop().asInt(); - stack.push(Value.i32(a & b)); - } - - private static void I64_POPCNT(MStack stack) { - var tos = stack.pop().asLong(); - stack.push(Value.i64(OpcodeImpl.I64_POPCNT(tos))); - } - - private static void I64_CTZ(MStack stack) { - var tos = stack.pop(); - stack.push(Value.i64(OpcodeImpl.I64_CTZ(tos.asLong()))); - } - - private static void I64_CLZ(MStack stack) { - var tos = stack.pop(); - stack.push(Value.i64(OpcodeImpl.I64_CLZ(tos.asLong()))); - } - - private static void I64_ROTR(MStack stack) { - var c = stack.pop().asLong(); - var v = stack.pop().asLong(); - stack.push(Value.i64(OpcodeImpl.I64_ROTR(v, c))); - } - - private static void I64_ROTL(MStack stack) { - var c = stack.pop().asLong(); - var v = stack.pop().asLong(); - stack.push(Value.i64(OpcodeImpl.I64_ROTL(v, c))); - } - - private static void I64_REM_U(MStack stack) { - var b = stack.pop().asLong(); - var a = stack.pop().asLong(); - stack.push(Value.i64(OpcodeImpl.I64_REM_U(a, b))); - } - - private static void I64_REM_S(MStack stack) { - var b = stack.pop().asLong(); - var a = stack.pop().asLong(); - stack.push(Value.i64(OpcodeImpl.I64_REM_S(a, b))); - } - - private static void I64_SHR_U(MStack stack) { - var c = stack.pop().asLong(); - var v = stack.pop().asLong(); - stack.push(Value.i64(v >>> c)); - } - - private static void I64_SHR_S(MStack stack) { - var c = stack.pop().asLong(); - var v = stack.pop().asLong(); - stack.push(Value.i64(v >> c)); - } - - private static void I64_SHL(MStack stack) { - var c = stack.pop().asLong(); - var v = stack.pop().asLong(); - stack.push(Value.i64(v << c)); - } - - private static void I64_XOR(MStack stack) { - var a = stack.pop().asLong(); - var b = stack.pop().asLong(); - stack.push(Value.i64(a ^ b)); - } - - private static void I64_OR(MStack stack) { - var a = stack.pop().asLong(); - var b = stack.pop().asLong(); - stack.push(Value.i64(a | b)); - } - - private static void I64_AND(MStack stack) { - var a = stack.pop().asLong(); - var b = stack.pop().asLong(); - stack.push(Value.i64(a & b)); - } - - private static void I32_REM_U(MStack stack) { - var b = stack.pop().asInt(); - var a = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_REM_U(a, b))); - } - - private static void I32_REM_S(MStack stack) { - var b = stack.pop().asInt(); - var a = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_REM_S(a, b))); - } - - private static void I64_DIV_U(MStack stack) { - var b = stack.pop().asLong(); - var a = stack.pop().asLong(); - stack.push(Value.i64(OpcodeImpl.I64_DIV_U(a, b))); - } - - private static void I64_DIV_S(MStack stack) { - var b = stack.pop().asLong(); - var a = stack.pop().asLong(); - stack.push(Value.i64(OpcodeImpl.I64_DIV_S(a, b))); - } - - private static void I64_GT_S(MStack stack) { - var b = stack.pop().asLong(); - var a = stack.pop().asLong(); - stack.push(Value.i32(OpcodeImpl.I64_GT_S(a, b))); - } - - private static void I32_GT_U(MStack stack) { - var b = stack.pop().asInt(); - var a = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_GT_U(a, b))); - } - - private static void I32_GT_S(MStack stack) { - var b = stack.pop().asInt(); - var a = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_GT_S(a, b))); - } - - private static void I64_LT_U(MStack stack) { - var b = stack.pop().asLong(); - var a = stack.pop().asLong(); - stack.push(Value.i32(OpcodeImpl.I64_LT_U(a, b))); - } - - private static void I64_LT_S(MStack stack) { - var b = stack.pop().asLong(); - var a = stack.pop().asLong(); - stack.push(Value.i32(OpcodeImpl.I64_LT_S(a, b))); - } - - private static void I32_LT_U(MStack stack) { - var b = stack.pop().asInt(); - var a = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_LT_U(a, b))); - } - - private static void I32_LT_S(MStack stack) { - var b = stack.pop().asInt(); - var a = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_LT_S(a, b))); - } - - private static void I64_EQZ(MStack stack) { - var a = stack.pop().asLong(); - stack.push(Value.i32(OpcodeImpl.I64_EQZ(a))); - } - - private static void I32_EQZ(MStack stack) { - var a = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_EQZ(a))); - } - - private static void I64_NE(MStack stack) { - var a = stack.pop().asLong(); - var b = stack.pop().asLong(); - stack.push(Value.i32(OpcodeImpl.I64_NE(a, b))); - } - - private static void I32_NE(MStack stack) { - var a = stack.pop().asInt(); - var b = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_NE(a, b))); - } - - private static void I64_EQ(MStack stack) { - var a = stack.pop().asLong(); - var b = stack.pop().asLong(); - stack.push(Value.i32(OpcodeImpl.I64_EQ(a, b))); - } - - private static void I32_EQ(MStack stack) { - var a = stack.pop().asInt(); - var b = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_EQ(a, b))); - } - - private static void MEMORY_SIZE(MStack stack, Instance instance) { - var sz = instance.memory().pages(); - stack.push(Value.i32(sz)); - } - - private static void I64_STORE32(MStack stack, Instance instance, long[] operands) { - var value = stack.pop().asLong(); - var ptr = (int) (operands[1] + stack.pop().asInt()); - instance.memory().writeI32(ptr, (int) value); - } - - private static void I64_STORE8(MStack stack, Instance instance, long[] operands) { - var value = stack.pop().asByte(); - var ptr = (int) (operands[1] + stack.pop().asInt()); - instance.memory().writeByte(ptr, value); - } - - private static void F64_PROMOTE_F32(MStack stack) { - var tos = stack.pop(); - stack.push(Value.fromDouble(tos.asFloat())); - } - - private static void F64_REINTERPRET_I64(MStack stack) { - long tos = stack.pop().asLong(); - stack.push(Value.fromDouble(OpcodeImpl.F64_REINTERPRET_I64(tos))); - } - - private static void I32_WRAP_I64(MStack stack) { - var tos = stack.pop(); - stack.push(Value.i32(tos.asInt())); - } - - private static void I64_EXTEND_I32_S(MStack stack) { - var tos = stack.pop(); - stack.push(Value.i64(tos.asInt())); - } - - private static void I64_EXTEND_I32_U(MStack stack) { - int tos = stack.pop().asInt(); - stack.push(Value.i64(OpcodeImpl.I64_EXTEND_I32_U(tos))); - } - - private static void I32_REINTERPRET_F32(MStack stack) { - float tos = stack.pop().asFloat(); - stack.push(Value.i32(OpcodeImpl.I32_REINTERPRET_F32(tos))); - } - - private static void I64_REINTERPRET_F64(MStack stack) { - double tos = stack.pop().asDouble(); - stack.push(Value.i64(OpcodeImpl.I64_REINTERPRET_F64(tos))); - } - - private static void F32_REINTERPRET_I32(MStack stack) { - int tos = stack.pop().asInt(); - stack.push(Value.fromFloat(OpcodeImpl.F32_REINTERPRET_I32(tos))); - } - - private static void F32_DEMOTE_F64(MStack stack) { - var val = stack.pop().asDouble(); - - stack.push(Value.fromFloat((float) val)); - } - - private static void F32_CONVERT_I32_S(MStack stack) { - var tos = stack.pop().asInt(); - stack.push(Value.fromFloat(OpcodeImpl.F32_CONVERT_I32_S(tos))); - } - - private static void I32_EXTEND_16_S(MStack stack) { - var tos = stack.pop().asInt(); - stack.push(Value.i32(OpcodeImpl.I32_EXTEND_16_S(tos))); - } - - private static void I64_TRUNC_F64_S(MStack stack) { - double tos = stack.pop().asDouble(); - stack.push(Value.i64(OpcodeImpl.I64_TRUNC_F64_S(tos))); - } - - private static void F32_COPYSIGN(MStack stack) { - var b = stack.pop().asFloat(); - var a = stack.pop().asFloat(); - stack.push(Value.fromFloat(OpcodeImpl.F32_COPYSIGN(a, b))); - } - - private static void F32_ABS(MStack stack) { - var val = stack.pop().asFloat(); - stack.push(Value.fromFloat(OpcodeImpl.F32_ABS(val))); - } - - private static void F64_ABS(MStack stack) { - var val = stack.pop().asDouble(); - stack.push(Value.fromDouble(OpcodeImpl.F64_ABS(val))); - } - - private static void F32_NE(MStack stack) { - var b = stack.pop().asFloat(); - var a = stack.pop().asFloat(); - stack.push(Value.i32(OpcodeImpl.F32_NE(a, b))); - } - - private static void F64_NE(MStack stack) { - var b = stack.pop().asDouble(); - var a = stack.pop().asDouble(); - stack.push(Value.i32(OpcodeImpl.F64_NE(a, b))); - } - - private static void F32_LT(MStack stack) { - var b = stack.pop().asFloat(); - var a = stack.pop().asFloat(); - stack.push(Value.i32(OpcodeImpl.F32_LT(a, b))); - } - - private static void F64_LT(MStack stack) { - var b = stack.pop().asDouble(); - var a = stack.pop().asDouble(); - stack.push(Value.i32(OpcodeImpl.F64_LT(a, b))); - } - - private static void F32_LE(MStack stack) { - var b = stack.pop().asFloat(); - var a = stack.pop().asFloat(); - stack.push(Value.i32(OpcodeImpl.F32_LE(a, b))); - } - - private static void F64_LE(MStack stack) { - var b = stack.pop().asDouble(); - var a = stack.pop().asDouble(); - stack.push(Value.i32(OpcodeImpl.F64_LE(a, b))); - } - - private static void F32_GE(MStack stack) { - var b = stack.pop().asFloat(); - var a = stack.pop().asFloat(); - stack.push(Value.i32(OpcodeImpl.F32_GE(a, b))); - } - - private static void F64_GE(MStack stack) { - var b = stack.pop().asDouble(); - var a = stack.pop().asDouble(); - stack.push(Value.i32(OpcodeImpl.F64_GE(a, b))); - } - - private static void F32_GT(MStack stack) { - var b = stack.pop().asFloat(); - var a = stack.pop().asFloat(); - stack.push(Value.i32(OpcodeImpl.F32_GT(a, b))); - } - - private static void F64_GT(MStack stack) { - var b = stack.pop().asDouble(); - var a = stack.pop().asDouble(); - stack.push(Value.i32(OpcodeImpl.F64_GT(a, b))); - } - - private static void F32_CONVERT_I32_U(MStack stack) { - var tos = stack.pop().asInt(); - stack.push(Value.fromFloat(OpcodeImpl.F32_CONVERT_I32_U(tos))); - } - - private static void F32_CONVERT_I64_S(MStack stack) { - var tos = stack.pop().asLong(); - stack.push(Value.fromFloat(OpcodeImpl.F32_CONVERT_I64_S(tos))); - } - - private static void REF_NULL(MStack stack, long[] operands) { - var type = ValueType.forId((int) operands[0]); - stack.push(new Value(type, (long) REF_NULL_VALUE)); - } - - private static void ELEM_DROP(Instance instance, long[] operands) { - var x = (int) operands[0]; - instance.setElement(x, null); - } - - private static void REF_IS_NULL(MStack stack) { - var val = stack.pop(); - stack.push( - val.equals(Value.EXTREF_NULL) || val.equals(Value.FUNCREF_NULL) - ? Value.TRUE - : Value.FALSE); - } - - private static void DATA_DROP(Instance instance, long[] operands) { - var segment = (int) operands[0]; - instance.memory().drop(segment); - } - - private static void F64_CONVERT_I64_S(MStack stack) { - var tos = stack.pop().asLong(); - stack.push(Value.fromDouble(OpcodeImpl.F64_CONVERT_I64_S(tos))); - } - - private static void TABLE_GROW(MStack stack, Instance instance, long[] operands) { - var tableidx = (int) operands[0]; - var table = instance.table(tableidx); - - var size = stack.pop().asInt(); - var valValue = stack.pop(); - var val = valValue.asExtRef(); - - var res = table.grow(size, val, instance); - stack.push(Value.i32(res)); - } - - private static void TABLE_SIZE(MStack stack, Instance instance, long[] operands) { - var tableidx = (int) operands[0]; - var table = instance.table(tableidx); - - stack.push(Value.i32(table.size())); - } - - private static void TABLE_FILL(MStack stack, Instance instance, long[] operands) { - var tableidx = (int) operands[0]; - - var size = stack.pop().asInt(); - var val = stack.pop().asExtRef(); - var offset = stack.pop().asInt(); - - OpcodeImpl.TABLE_FILL(instance, tableidx, size, val, offset); - } - - private static void TABLE_COPY(MStack stack, Instance instance, long[] operands) { - var tableidxSrc = (int) operands[1]; - var tableidxDst = (int) operands[0]; - - var size = stack.pop().asInt(); - var s = stack.pop().asInt(); - var d = stack.pop().asInt(); - - OpcodeImpl.TABLE_COPY(instance, tableidxSrc, tableidxDst, size, s, d); - } - - private static void MEMORY_COPY(MStack stack, Instance instance, long[] operands) { - var memidxSrc = (int) operands[0]; - var memidxDst = (int) operands[1]; - if (memidxDst != 0 && memidxSrc != 0) - throw new WASMRuntimeException( - "We don't support non zero index for memory: " + memidxSrc + " " + memidxDst); - var size = stack.pop().asInt(); - var offset = stack.pop().asInt(); - var destination = stack.pop().asInt(); - instance.memory().copy(destination, offset, size); - } - - private static void TABLE_INIT(MStack stack, Instance instance, long[] operands) { - var tableidx = (int) operands[1]; - var elementidx = (int) operands[0]; - - var size = stack.pop().asInt(); - var elemidx = stack.pop().asInt(); - var offset = stack.pop().asInt(); - - OpcodeImpl.TABLE_INIT(instance, tableidx, elementidx, size, elemidx, offset); - } - - private static void MEMORY_INIT(MStack stack, Instance instance, long[] operands) { - var segmentId = (int) operands[0]; - var memidx = (int) operands[1]; - if (memidx != 0) - throw new WASMRuntimeException("We don't support non zero index for memory: " + memidx); - var size = stack.pop().asInt(); - var offset = stack.pop().asInt(); - var destination = stack.pop().asInt(); - instance.memory().initPassiveSegment(segmentId, destination, offset, size); - } - - private static void I64_TRUNC_F32_S(MStack stack) { - var tos = stack.pop().asFloat(); - stack.push(Value.i64(OpcodeImpl.I64_TRUNC_F32_S(tos))); - } - - private static void I32_TRUNC_F64_U(MStack stack) { - double tos = stack.pop().asDouble(); - stack.push(Value.i32(OpcodeImpl.I32_TRUNC_F64_U(tos))); - } - - private static void I32_TRUNC_F64_S(MStack stack) { - var tos = stack.pop().asDouble(); - stack.push(Value.i32(OpcodeImpl.I32_TRUNC_F64_S(tos))); - } - - private static void I64_TRUNC_SAT_F64_U(MStack stack) { - double tos = stack.pop().asDouble(); - stack.push(Value.i64(OpcodeImpl.I64_TRUNC_SAT_F64_U(tos))); - } - - private static void I64_TRUNC_SAT_F64_S(MStack stack) { - var tos = stack.pop().asDouble(); - stack.push(Value.i64(OpcodeImpl.I64_TRUNC_SAT_F64_S(tos))); - } - - private static void I64_TRUNC_SAT_F32_U(MStack stack) { - var tos = stack.pop().asFloat(); - stack.push(Value.i64(OpcodeImpl.I64_TRUNC_SAT_F32_U(tos))); - } - - private static void I64_TRUNC_SAT_F32_S(MStack stack) { - var tos = stack.pop().asFloat(); - stack.push(Value.i64(OpcodeImpl.I64_TRUNC_SAT_F32_S(tos))); - } - - private static void I64_TRUNC_F64_U(MStack stack) { - var tos = stack.pop().asDouble(); - stack.push(Value.i64(OpcodeImpl.I64_TRUNC_F64_U(tos))); - } - - private static void I64_TRUNC_F32_U(MStack stack) { - var tos = stack.pop().asFloat(); - stack.push(Value.i64(OpcodeImpl.I64_TRUNC_F32_U(tos))); - } - - private static void F32_CONVERT_I64_U(MStack stack) { - var tos = stack.pop().asLong(); - stack.push(Value.fromFloat(OpcodeImpl.F32_CONVERT_I64_U(tos))); - } - - private static void I32_TRUNC_F32_U(MStack stack) { - var tos = stack.pop().asFloat(); - stack.push(Value.i32(OpcodeImpl.I32_TRUNC_F32_U(tos))); - } - - private static void I32_TRUNC_SAT_F64_U(MStack stack) { - double tos = Double.longBitsToDouble(stack.pop().asLong()); - stack.push(Value.i32(OpcodeImpl.I32_TRUNC_SAT_F64_U(tos))); - } - - private static void I32_TRUNC_SAT_F64_S(MStack stack) { - var tos = stack.pop().asDouble(); - stack.push(Value.i32(OpcodeImpl.I32_TRUNC_SAT_F64_S(tos))); - } - - private static void I32_TRUNC_SAT_F32_U(MStack stack) { - var tos = stack.pop().asFloat(); - stack.push(Value.i32(OpcodeImpl.I32_TRUNC_SAT_F32_U(tos))); - } - - private static void I32_TRUNC_SAT_F32_S(MStack stack) { - var tos = stack.pop().asFloat(); - stack.push(Value.i32(OpcodeImpl.I32_TRUNC_SAT_F32_S(tos))); - } - - private static void I32_TRUNC_F32_S(MStack stack) { - float tos = stack.pop().asFloat(); - stack.push(Value.i32(OpcodeImpl.I32_TRUNC_F32_S(tos))); - } - - private static void F64_COPYSIGN(MStack stack) { - var b = stack.pop().asDouble(); - var a = stack.pop().asDouble(); - stack.push(Value.fromDouble(OpcodeImpl.F64_COPYSIGN(a, b))); - } - - private static void F32_TRUNC(MStack stack) { - var val = stack.pop().asFloat(); - stack.push(Value.fromFloat(OpcodeImpl.F32_TRUNC(val))); - } - - private static void CALL( - MStack stack, Instance instance, ArrayDeque callStack, long[] operands) { - var funcId = (int) operands[0]; - var typeId = instance.functionType(funcId); - var type = instance.type(typeId); - // given a list of param types, let's pop those params off the stack - // and pass as args to the function call - var args = extractArgsForParams(stack, type.params()); - call(stack, instance, callStack, funcId, args, type, false); - } - - private static void F64_NEG(MStack stack) { - var tos = stack.pop().asDouble(); - stack.push(Value.fromDouble(-tos)); - } - - private static void F32_NEG(MStack stack) { - var tos = stack.pop().asFloat(); - stack.push(Value.fromFloat(-tos)); - } - - private static void MEMORY_FILL(MStack stack, Instance instance, long[] operands) { - var memidx = (int) operands[0]; - if (memidx != 0) { - throw new WASMRuntimeException("We don't support multiple memories just yet"); - } - var size = stack.pop().asInt(); - var val = stack.pop().asByte(); - var offset = stack.pop().asInt(); - var end = (size + offset); - instance.memory().fill(val, offset, end); - } - - private static void MEMORY_GROW(MStack stack, Instance instance) { - var size = stack.pop().asInt(); - var nPages = instance.memory().grow(size); - stack.push(Value.i32(nPages)); - } - - private static int readMemPtr(MStack stack, long[] operands) { - int offset = stack.pop().asInt(); - if (operands[1] < 0 || operands[1] >= Integer.MAX_VALUE || offset < 0) { - throw new WASMRuntimeException("out of bounds memory access"); - } - return (int) (operands[1] + offset); - } - - private static void F64_STORE(MStack stack, Instance instance, long[] operands) { - var value = stack.pop().asDouble(); - var ptr = readMemPtr(stack, operands); - instance.memory().writeF64(ptr, value); - } - - private static void F32_STORE(MStack stack, Instance instance, long[] operands) { - var value = stack.pop().asFloat(); - var ptr = readMemPtr(stack, operands); - instance.memory().writeF32(ptr, value); - } - - private static void I64_STORE(MStack stack, Instance instance, long[] operands) { - var value = stack.pop().asLong(); - var ptr = readMemPtr(stack, operands); - instance.memory().writeLong(ptr, value); - } - - private static void I64_STORE16(MStack stack, Instance instance, long[] operands) { - var value = stack.pop().asShort(); - var ptr = readMemPtr(stack, operands); - instance.memory().writeShort(ptr, value); - } - - private static void I32_STORE(MStack stack, Instance instance, long[] operands) { - var value = stack.pop().asInt(); - var ptr = readMemPtr(stack, operands); - instance.memory().writeI32(ptr, value); - } - - private static void I64_LOAD32_U(MStack stack, Instance instance, long[] operands) { - var ptr = readMemPtr(stack, operands); - var val = instance.memory().readU32(ptr); - stack.push(val); - } - - private static void I64_LOAD32_S(MStack stack, Instance instance, long[] operands) { - var ptr = readMemPtr(stack, operands); - var val = instance.memory().readI32(ptr); - // TODO this is a bit hacky - stack.push(Value.i64(val.asInt())); - } - - private static void I64_LOAD16_U(MStack stack, Instance instance, long[] operands) { - var ptr = readMemPtr(stack, operands); - var val = instance.memory().readU16(ptr); - // TODO this is a bit hacky - stack.push(Value.i64(val.asInt())); - } - - private static void I32_LOAD16_U(MStack stack, Instance instance, long[] operands) { - var ptr = readMemPtr(stack, operands); - var val = instance.memory().readU16(ptr); - stack.push(val); - } - - private static void I64_LOAD16_S(MStack stack, Instance instance, long[] operands) { - var ptr = readMemPtr(stack, operands); - var val = instance.memory().readI16(ptr); - // TODO this is a bit hacky - stack.push(Value.i64(val.asInt())); - } - - private static void I32_LOAD16_S(MStack stack, Instance instance, long[] operands) { - var ptr = readMemPtr(stack, operands); - var val = instance.memory().readI16(ptr); - stack.push(val); - } - - private static void I64_LOAD8_U(MStack stack, Instance instance, long[] operands) { - var ptr = readMemPtr(stack, operands); - var val = instance.memory().readU8(ptr); - // TODO a bit hacky - stack.push(Value.i64(val.asInt())); - } - - private static void I32_LOAD8_U(MStack stack, Instance instance, long[] operands) { - var ptr = readMemPtr(stack, operands); - var val = instance.memory().readU8(ptr); - stack.push(val); - } - - private static void I64_LOAD8_S(MStack stack, Instance instance, long[] operands) { - var ptr = readMemPtr(stack, operands); - var val = instance.memory().readI8(ptr); - // TODO a bit hacky - stack.push(Value.i64(val.asInt())); - } - - private static void I32_LOAD8_S(MStack stack, Instance instance, long[] operands) { - var ptr = readMemPtr(stack, operands); - var val = instance.memory().readI8(ptr); - stack.push(val); - } - - private static void F64_LOAD(MStack stack, Instance instance, long[] operands) { - var ptr = readMemPtr(stack, operands); - var val = instance.memory().readF64(ptr); - stack.push(val); - } - - private static void F32_LOAD(MStack stack, Instance instance, long[] operands) { - var ptr = readMemPtr(stack, operands); - var val = instance.memory().readF32(ptr); - stack.push(val); - } - - private static void I64_LOAD(MStack stack, Instance instance, long[] operands) { - var ptr = readMemPtr(stack, operands); - var val = instance.memory().readI64(ptr); - stack.push(val); - } - - private static void I32_LOAD(MStack stack, Instance instance, long[] operands) { - var ptr = readMemPtr(stack, operands); - var val = instance.memory().readI32(ptr); - stack.push(val); - } - - private static void TABLE_SET(MStack stack, Instance instance, long[] operands) { - var idx = (int) operands[0]; - var table = instance.table(idx); - - var value = stack.pop().asExtRef(); - var i = stack.pop().asInt(); - table.setRef(i, value, instance); - } - - private static void TABLE_GET(MStack stack, Instance instance, long[] operands) { - var idx = (int) operands[0]; - var i = stack.pop().asInt(); - stack.push(OpcodeImpl.TABLE_GET(instance, idx, i)); - } - - private static void GLOBAL_SET(MStack stack, Instance instance, long[] operands) { - var id = (int) operands[0]; - var val = stack.pop(); - instance.writeGlobal(id, val); - } - - private static void GLOBAL_GET(MStack stack, Instance instance, long[] operands) { - int idx = (int) operands[0]; - var val = instance.readGlobal(idx); - - stack.push(val); - } - - private static void SELECT(MStack stack) { - var pred = stack.pop().asInt(); - var b = stack.pop(); - var a = stack.pop(); - if (pred == 0) { - stack.push(b); - } else { - stack.push(a); - } - } - - private static void SELECT_T(MStack stack, long[] operands) { - var pred = stack.pop().asInt(); - var b = stack.pop(); - var a = stack.pop(); - if (pred == 0) { - stack.push(b); - } else { - stack.push(a); - } - } - - private static void CALL_INDIRECT( - MStack stack, Instance instance, ArrayDeque callStack, long[] operands) { - var tableIdx = (int) operands[1]; - var table = instance.table(tableIdx); - - var typeId = (int) operands[0]; - int funcTableIdx = stack.pop().asInt(); - int funcId = table.ref(funcTableIdx).asFuncRef(); - var tableInstance = table.instance(funcTableIdx); - if (tableInstance != null) { - instance = tableInstance; - } - if (funcId == REF_NULL_VALUE) { - throw new ChicoryException("uninitialized element " + funcTableIdx); - } - var type = instance.type(typeId); - - // given a list of param types, let's pop those params off the stack - // and pass as args to the function call - var args = extractArgsForParams(stack, type.params()); - call(stack, instance, callStack, funcId, args, type, false); - } - - private static int numberOfParams(Instance instance, Instruction scope) { - var typeId = (int) scope.operands()[0]; - if (typeId == 0x40) { // epsilon - return 0; - } - if (ValueType.isValid(typeId)) { - return 0; - } - return instance.type(typeId).params().size(); - } - - private static int numberOfValuesToReturn(Instance instance, Instruction scope) { - if (scope.opcode() == OpCode.END) { - return 0; - } - var typeId = (int) scope.operands()[0]; - if (typeId == 0x40) { // epsilon - return 0; - } - if (ValueType.isValid(typeId)) { - return 1; - } - return instance.type(typeId).returns().size(); - } - - private static void BLOCK( - StackFrame frame, MStack stack, Instance instance, Instruction instruction) { - var paramsSize = numberOfParams(instance, instruction); - var returnsSize = numberOfValuesToReturn(instance, instruction); - frame.pushCtrl(instruction.opcode(), paramsSize, returnsSize, stack.size() - paramsSize); - } - - private static void IF( - StackFrame frame, MStack stack, Instance instance, Instruction instruction) { - var predValue = stack.pop(); - var paramsSize = numberOfParams(instance, instruction); - var returnsSize = numberOfValuesToReturn(instance, instruction); - frame.pushCtrl(instruction.opcode(), paramsSize, returnsSize, stack.size() - paramsSize); - - frame.jumpTo(predValue.asInt() == 0 ? instruction.labelFalse() : instruction.labelTrue()); + private static int readMemPtr(MStack stack, long[] operands) { + int offset = stack.pop().asInt(); + if (operands[1] < 0 || operands[1] >= Integer.MAX_VALUE || offset < 0) { + throw new WASMRuntimeException("out of bounds memory access"); + } + return (int) (operands[1] + offset); } private static void ctrlJump(StackFrame frame, MStack stack, int n) { @@ -1903,39 +1439,6 @@ private static void ctrlJump(StackFrame frame, MStack stack, int n) { } } - private static void BR(StackFrame frame, MStack stack, Instruction instruction) { - checkInterruption(); - ctrlJump(frame, stack, (int) instruction.operands()[0]); - frame.jumpTo(instruction.labelTrue()); - } - - private static void BR_TABLE(StackFrame frame, MStack stack, Instruction instruction) { - var predValue = stack.pop(); - var pred = predValue.asInt(); - - var defaultIdx = instruction.operands().length - 1; - if (pred < 0 || pred >= defaultIdx) { - // choose default - ctrlJump(frame, stack, (int) instruction.operands()[defaultIdx]); - frame.jumpTo(instruction.labelTable()[defaultIdx]); - } else { - ctrlJump(frame, stack, (int) instruction.operands()[pred]); - frame.jumpTo(instruction.labelTable()[pred]); - } - } - - private static void BR_IF(StackFrame frame, MStack stack, Instruction instruction) { - var predValue = stack.pop(); - var pred = predValue.asInt(); - - if (pred == 0) { - frame.jumpTo(instruction.labelFalse()); - } else { - ctrlJump(frame, stack, (int) instruction.operands()[0]); - frame.jumpTo(instruction.labelTrue()); - } - } - @Override public List getStackTrace() { return List.copyOf(callStack); diff --git a/runtime/src/main/java/com/dylibso/chicory/runtime/StackFrame.java b/runtime/src/main/java/com/dylibso/chicory/runtime/StackFrame.java index 5d9a3c582..fca641e27 100644 --- a/runtime/src/main/java/com/dylibso/chicory/runtime/StackFrame.java +++ b/runtime/src/main/java/com/dylibso/chicory/runtime/StackFrame.java @@ -30,6 +30,8 @@ public class StackFrame { private final List ctrlStack = new ArrayList<>(); + private boolean shouldReturn = false; + public StackFrame(Instance instance, int funcId, Value[] args, List localTypes) { this(Collections.emptyList(), instance, funcId, args, localTypes); } @@ -146,4 +148,12 @@ public static void doControlTransfer(CtrlFrame ctrlFrame, MStack stack) { } } } + + public void shouldReturn(boolean v) { + this.shouldReturn = v; + } + + public boolean shouldReturn() { + return this.shouldReturn; + } }