From eed93b8beaaa5867c61b28c1342c18217110c956 Mon Sep 17 00:00:00 2001 From: Andrea Peruffo Date: Mon, 25 Sep 2023 13:41:16 +0100 Subject: [PATCH] Switch to back to Java 11 --- pom.xml | 9 +- .../dylibso/chicory/runtime/HostFunction.java | 36 +- .../com/dylibso/chicory/runtime/Machine.java | 359 ++++++++++++------ .../com/dylibso/chicory/runtime/Memory.java | 24 +- .../com/dylibso/chicory/runtime/Module.java | 2 +- .../dylibso/chicory/runtime/StackFrame.java | 16 +- .../com/dylibso/chicory/wasm/ControlFlow.java | 15 +- .../dylibso/chicory/wasm/ModuleBuilder.java | 52 ++- .../java/com/dylibso/chicory/wasm/Parser.java | 73 ++-- .../com/dylibso/chicory/wasm/types/Ast.java | 11 +- .../chicory/wasm/types/ImportDesc.java | 28 +- .../com/dylibso/chicory/wasm/types/Value.java | 54 ++- 12 files changed, 480 insertions(+), 199 deletions(-) diff --git a/pom.xml b/pom.xml index a5ca28064..709c66571 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,10 @@ pom - 17 + UTF-8 + UTF-8 + 11 + 11 UTF-8 3.10.1 2.22.2 @@ -46,7 +49,9 @@ maven-compiler-plugin ${maven-compiler-plugin.version} - ${java.version} + ${maven.compiler.source} + ${maven.compiler.target} + ${maven.compiler.target} diff --git a/runtime/src/main/java/com/dylibso/chicory/runtime/HostFunction.java b/runtime/src/main/java/com/dylibso/chicory/runtime/HostFunction.java index f34e79288..9ff6eb4ef 100644 --- a/runtime/src/main/java/com/dylibso/chicory/runtime/HostFunction.java +++ b/runtime/src/main/java/com/dylibso/chicory/runtime/HostFunction.java @@ -4,5 +4,39 @@ import java.util.List; -public record HostFunction(WasmFunctionHandle handle, String moduleName, String fieldName, List paramTypes, List returnTypes) { +public class HostFunction { + private final WasmFunctionHandle handle; + private final String moduleName; + private final String fieldName; + private final List paramTypes; + private final List returnTypes; + + HostFunction(WasmFunctionHandle handle, String moduleName, String fieldName, List paramTypes, List returnTypes) { + this.handle = handle; + this.moduleName = moduleName; + this.fieldName = fieldName; + this.paramTypes = paramTypes; + this.returnTypes = returnTypes; + } + + public WasmFunctionHandle getHandle() { + return handle; + } + + public String getModuleName() { + return moduleName; + } + + public String getFieldName() { + return fieldName; + } + + public List getParamTypes() { + return paramTypes; + } + + public List getReturnTypes() { + return returnTypes; + } + } diff --git a/runtime/src/main/java/com/dylibso/chicory/runtime/Machine.java b/runtime/src/main/java/com/dylibso/chicory/runtime/Machine.java index 33581ff33..2d5880ba6 100644 --- a/runtime/src/main/java/com/dylibso/chicory/runtime/Machine.java +++ b/runtime/src/main/java/com/dylibso/chicory/runtime/Machine.java @@ -26,7 +26,7 @@ public Value call(int funcId, Value[] args, boolean popResults) throws ChicoryEx } else { this.callStack.push(new StackFrame(funcId, 0, args, List.of())); var imprt = instance.getImports()[funcId]; - var hostFunc = imprt.handle(); + var hostFunc = imprt.getHandle(); var results = hostFunc.apply(this.instance.getMemory(), args); // a host function can return null or an array of ints // which we will push onto the stack @@ -58,12 +58,16 @@ void eval(List code) throws ChicoryException { var operands = instruction.getOperands(); //System.out.println("func="+frame.funcId + "@"+frame.pc + ": " + instruction + " stack="+this.stack); switch (opcode) { - case UNREACHABLE -> throw new TrapException("Trapped on unreachable instruction", callStack); - case NOP -> {} - case LOOP, BLOCK -> { + case UNREACHABLE: + throw new TrapException("Trapped on unreachable instruction", callStack); + case NOP: + break; + case LOOP: + case BLOCK: { frame.blockDepth++; + break; } - case IF -> { + case IF: { frame.blockDepth++; var pred = this.stack.pop().asInt(); if (pred == 0) { @@ -71,19 +75,23 @@ void eval(List code) throws ChicoryException { } else { frame.pc = instruction.getLabelTrue(); } + break; } - case ELSE, BR -> { + case ELSE: + case BR: { frame.pc = instruction.getLabelTrue(); + break; } - case BR_IF -> { + case BR_IF: { var pred = this.stack.pop().asInt(); if (pred == 0) { frame.pc = instruction.getLabelFalse(); } else { frame.pc = instruction.getLabelTrue(); } + break; } - case BR_TABLE -> { + case BR_TABLE: { var pred = this.stack.pop().asInt(); if (pred < 0 || pred >= instruction.getLabelTable().length - 1) { // choose default @@ -91,9 +99,12 @@ void eval(List code) throws ChicoryException { } else { frame.pc = instruction.getLabelTable()[pred]; } + break; } - case RETURN -> shouldReturn = true; - case CALL_INDIRECT -> { + case RETURN: + shouldReturn = true; + break; + case CALL_INDIRECT: { // var index = this.stack.pop().asInt(); // var funcId = instance.getTable().getFuncRef(index); // var typeId = instance.getFunctionTypes().get(funcId); @@ -102,9 +113,12 @@ void eval(List code) throws ChicoryException { // // and pass as args to the function call // var args = extractArgsForParams(type.paramTypes()); // call(funcId, args, false); + break; } - case DROP -> this.stack.pop(); - case SELECT -> { + case DROP: + this.stack.pop(); + break; + case SELECT: { var pred = this.stack.pop().asInt(); var b = this.stack.pop(); var a = this.stack.pop(); @@ -113,426 +127,514 @@ void eval(List code) throws ChicoryException { } else { this.stack.push(a); } + break; } - case END -> { + case END: { frame.blockDepth--; // if this is the last end, then we're done with // the function if (frame.blockDepth == 0) { break loop; } + break; } - case LOCAL_GET -> { + case LOCAL_GET: { this.stack.push(frame.getLocal((int) operands[0])); + break; } - case LOCAL_SET -> { + case LOCAL_SET: { frame.setLocal((int) operands[0], this.stack.pop()); + break; } - case LOCAL_TEE -> { + case LOCAL_TEE: { // here we peek instead of pop, leaving it on the stack frame.setLocal((int) operands[0], this.stack.peek()); + break; } - case GLOBAL_GET -> { + case GLOBAL_GET: { var val = instance.getGlobal((int) operands[0]); this.stack.push(val); + break; } - case GLOBAL_SET -> { + case GLOBAL_SET: { var id = (int) operands[0]; var global = instance.getGlobalInitalizers()[id]; if (global.getMutabilityType() == MutabilityType.Const) throw new RuntimeException("Can't call GLOBAL_SET on immutable global"); var val = this.stack.pop(); instance.setGlobal(id, val); + break; } // TODO signed and unsigned are the same right now - case I32_LOAD -> { + case I32_LOAD: { var ptr = (int) (operands[0] + this.stack.pop().asInt()); var val = instance.getMemory().getI32(ptr); this.stack.push(val); + break; } - case I64_LOAD -> { + case I64_LOAD: { var ptr = (int) (operands[0] + this.stack.pop().asInt()); var val = instance.getMemory().getI64(ptr); this.stack.push(val); + break; } - case F32_LOAD -> { + case F32_LOAD: { var ptr = (int) (operands[0] + this.stack.pop().asInt()); var val = instance.getMemory().getF32(ptr); this.stack.push(val); + break; } - case F64_LOAD -> { + case F64_LOAD: { var ptr = (int) (operands[0] + this.stack.pop().asInt()); var val = instance.getMemory().getF64(ptr); this.stack.push(val); + break; } - case I32_LOAD8_S -> { + case I32_LOAD8_S: { var ptr = (int) (operands[0] + this.stack.pop().asInt()); var val = instance.getMemory().getI8(ptr); this.stack.push(val); + break; } - case I64_LOAD8_S -> { + case I64_LOAD8_S: { var ptr = (int) (operands[0] + this.stack.pop().asInt()); var val = instance.getMemory().getI8(ptr); // TODO a bit hacky this.stack.push(Value.i64(val.asInt())); + break; } - case I32_LOAD8_U -> { + case I32_LOAD8_U: { var ptr = (int) (operands[0] + this.stack.pop().asInt()); var val = instance.getMemory().getI8U(ptr); this.stack.push(val); + break; } - case I64_LOAD8_U -> { + case I64_LOAD8_U: { var ptr = (int) (operands[0] + this.stack.pop().asInt()); var val = instance.getMemory().getI8U(ptr); // TODO a bit hacky this.stack.push(Value.i64(val.asInt())); + break; } - case I32_LOAD16_S -> { + case I32_LOAD16_S: { var ptr = (int) (operands[0] + this.stack.pop().asInt()); var val = instance.getMemory().getI16(ptr); this.stack.push(val); + break; } - case I64_LOAD16_S -> { + case I64_LOAD16_S: { var ptr = (int) (operands[0] + this.stack.pop().asInt()); var val = instance.getMemory().getI16(ptr); // TODO this is a bit hacky this.stack.push(Value.i64(val.asInt())); + break; } - case I32_LOAD16_U -> { + case I32_LOAD16_U: { var ptr = (int) (operands[0] + this.stack.pop().asInt()); var val = instance.getMemory().getU16(ptr); this.stack.push(val); + break; } - case I64_LOAD16_U -> { + case I64_LOAD16_U: { var ptr = (int) (operands[0] + this.stack.pop().asInt()); var val = instance.getMemory().getU16(ptr); // TODO this is a bit hacky this.stack.push(Value.i64(val.asInt())); + break; } - case I64_LOAD32_S -> { + case I64_LOAD32_S: { var ptr = (int) (operands[0] + this.stack.pop().asInt()); var val = instance.getMemory().getI32(ptr); // TODO this is a bit hacky this.stack.push(Value.i64(val.asInt())); + break; } - case I64_LOAD32_U -> { + case I64_LOAD32_U: { var ptr = (int) (operands[0] + this.stack.pop().asInt()); var val = instance.getMemory().getU32(ptr); this.stack.push(val); + break; } - case I32_STORE -> { + case I32_STORE: { var value = this.stack.pop().asInt(); var ptr = (int) (operands[0] + this.stack.pop().asInt()); instance.getMemory().putI32(ptr, value); + break; } - case I32_STORE16, I64_STORE16 -> { + case I32_STORE16: + case I64_STORE16: { var value = this.stack.pop().asShort(); var ptr = (int) (operands[0] + this.stack.pop().asInt()); instance.getMemory().putShort(ptr, value); + break; } - case I64_STORE -> { + case I64_STORE: { var value = this.stack.pop().asLong(); var ptr = (int) (operands[0] + this.stack.pop().asInt()); instance.getMemory().putI64(ptr, value); + break; } - case MEMORY_GROW -> { + case MEMORY_GROW: { instance.getMemory().grow(); + break; } - case I32_STORE8, I64_STORE8 -> { + case I32_STORE8: + case I64_STORE8: { var value = this.stack.pop().asByte(); var ptr = (int) (operands[0] + this.stack.pop().asInt()); instance.getMemory().putByte(ptr, value); + break; } - case I64_STORE32 -> { + case I64_STORE32: { var value = this.stack.pop().asInt(); var ptr = (int) (operands[0] + this.stack.pop().asInt()); instance.getMemory().putI32(ptr, value); + break; } - case MEMORY_SIZE -> { + case MEMORY_SIZE: { var sz = instance.getMemory().getInitialSize(); this.stack.push(Value.i32(sz)); + break; } // TODO 32bit and 64 bit operations are the same for now - case I32_CONST -> { + case I32_CONST: { this.stack.push(Value.i32(operands[0])); + break; } - case I64_CONST -> { + case I64_CONST: { this.stack.push(Value.i64(operands[0])); + break; } - case F32_CONST -> { + case F32_CONST: { this.stack.push(Value.f32(operands[0])); + break; } - case F64_CONST -> { + case F64_CONST: { this.stack.push(Value.f64(operands[0])); + break; } - case I32_EQ -> { + case I32_EQ: { var a = stack.pop().asInt(); var b = stack.pop().asInt(); this.stack.push(a == b ? Value.TRUE : Value.FALSE); + break; } - case I64_EQ -> { + case I64_EQ: { var a = this.stack.pop().asLong(); var b = this.stack.pop().asLong(); this.stack.push(a == b ? Value.TRUE : Value.FALSE); + break; } - case I32_NE -> { + case I32_NE: { var a = this.stack.pop().asInt(); var b = this.stack.pop().asInt(); this.stack.push(a == b ? Value.FALSE : Value.TRUE); + break; } - case I64_NE -> { + case I64_NE: { var a = this.stack.pop().asLong(); var b = this.stack.pop().asLong(); this.stack.push(a == b ? Value.FALSE : Value.TRUE); + break; } - case I32_EQZ -> { + case I32_EQZ: { var a = this.stack.pop().asInt(); this.stack.push(a == 0 ? Value.TRUE : Value.FALSE); + break; } - case I64_EQZ -> { + case I64_EQZ: { var a = this.stack.pop().asLong(); this.stack.push(a == 0L ? Value.TRUE : Value.FALSE); + break; } - case I32_LT_S -> { + case I32_LT_S: { var b = this.stack.pop().asInt(); var a = this.stack.pop().asInt(); this.stack.push(a < b ? Value.TRUE : Value.FALSE); + break; } - case I32_LT_U -> { + case I32_LT_U: { var b = this.stack.pop().asUInt(); var a = this.stack.pop().asUInt(); this.stack.push(a < b ? Value.TRUE : Value.FALSE); + break; } - case I64_LT_S -> { + case I64_LT_S: { var b = this.stack.pop().asLong(); var a = this.stack.pop().asLong(); this.stack.push(a < b ? Value.TRUE : Value.FALSE); + break; } - case I64_LT_U -> { + case I64_LT_U: { var b = this.stack.pop().asULong(); var a = this.stack.pop().asULong(); this.stack.push(a.compareTo(b) < 0 ? Value.TRUE : Value.FALSE); + break; } - case I32_GT_S -> { + case I32_GT_S: { var b = this.stack.pop().asInt(); var a = this.stack.pop().asInt(); this.stack.push(a > b ? Value.TRUE : Value.FALSE); + break; } - case I32_GT_U -> { + case I32_GT_U: { var b = this.stack.pop().asUInt(); var a = this.stack.pop().asUInt(); this.stack.push(a > b ? Value.TRUE : Value.FALSE); + break; } - case I64_GT_S -> { + case I64_GT_S: { var b = this.stack.pop().asLong(); var a = this.stack.pop().asLong(); this.stack.push(a > b ? Value.TRUE : Value.FALSE); + break; } - case I64_GT_U -> { + case I64_GT_U: { var b = this.stack.pop().asULong(); var a = this.stack.pop().asULong(); this.stack.push(a.compareTo(b) > 0 ? Value.TRUE : Value.FALSE); + break; } - case I32_GE_S -> { + case I32_GE_S: { var b = this.stack.pop().asInt(); var a = this.stack.pop().asInt(); this.stack.push(a >= b ? Value.TRUE : Value.FALSE); + break; } - case I32_GE_U -> { + case I32_GE_U: { var b = this.stack.pop().asUInt(); var a = this.stack.pop().asUInt(); this.stack.push(a >= b ? Value.TRUE : Value.FALSE); + break; } - case I64_GE_U -> { + case I64_GE_U: { var b = this.stack.pop().asULong(); var a = this.stack.pop().asULong(); this.stack.push(a.compareTo(b) >= 0 ? Value.TRUE : Value.FALSE); + break; } - case I64_GE_S -> { + case I64_GE_S: { var b = this.stack.pop().asLong(); var a = this.stack.pop().asLong(); this.stack.push(a >= b ? Value.TRUE : Value.FALSE); + break; } - case I32_LE_S -> { + case I32_LE_S: { var b = this.stack.pop().asInt(); var a = this.stack.pop().asInt(); this.stack.push(a <= b ? Value.TRUE : Value.FALSE); + break; } - case I32_LE_U -> { + case I32_LE_U: { var b = this.stack.pop().asUInt(); var a = this.stack.pop().asUInt(); this.stack.push(a <= b ? Value.TRUE : Value.FALSE); + break; } - case I64_LE_S -> { + case I64_LE_S: { var b = this.stack.pop().asLong(); var a = this.stack.pop().asLong(); this.stack.push(a <= b ? Value.TRUE : Value.FALSE); + break; } - case I64_LE_U -> { + case I64_LE_U: { var b = this.stack.pop().asULong(); var a = this.stack.pop().asULong(); this.stack.push(a.compareTo(b) <= 0 ? Value.TRUE : Value.FALSE); + break; } - case F32_EQ -> { + case F32_EQ: { var a = this.stack.pop().asFloat(); var b = this.stack.pop().asFloat(); this.stack.push(a == b ? Value.TRUE : Value.FALSE); + break; } - case F64_EQ -> { + case F64_EQ: { var a = this.stack.pop().asDouble(); var b = this.stack.pop().asDouble(); this.stack.push(a == b ? Value.TRUE : Value.FALSE); + break; } - case I32_CLZ -> { + case I32_CLZ: { var tos = this.stack.pop().asInt(); var count = Integer.numberOfLeadingZeros(tos); this.stack.push(Value.i32(count)); + break; } - case I32_CTZ -> { + case I32_CTZ: { var tos = this.stack.pop().asInt(); var count = Integer.numberOfTrailingZeros(tos); this.stack.push(Value.i32(count)); + break; } - case I32_POPCNT -> { + case I32_POPCNT: { var tos = this.stack.pop().asInt(); var count = Integer.bitCount(tos); this.stack.push(Value.i32(count)); + break; } - case I32_ADD -> { + case I32_ADD: { var a = this.stack.pop().asInt(); var b = this.stack.pop().asInt(); this.stack.push(Value.i32(a + b)); + break; } - case I64_ADD -> { + case I64_ADD: { var a = this.stack.pop().asLong(); var b = this.stack.pop().asLong(); this.stack.push(Value.i64(a + b)); + break; } - case I32_SUB -> { + case I32_SUB: { var a = this.stack.pop().asInt(); var b = this.stack.pop().asInt(); this.stack.push(Value.i32(b - a)); + break; } - case I64_SUB -> { + case I64_SUB: { var a = this.stack.pop().asLong(); var b = this.stack.pop().asLong(); this.stack.push(Value.i64(b - a)); + break; } - case I32_MUL -> { + case I32_MUL: { var a = this.stack.pop().asInt(); var b = this.stack.pop().asInt(); this.stack.push(Value.i32(a * b)); + break; } - case I64_MUL -> { + case I64_MUL: { var a = this.stack.pop().asLong(); var b = this.stack.pop().asLong(); this.stack.push(Value.i64(a * b)); + break; } - case I32_DIV_S -> { + case I32_DIV_S: { var b = this.stack.pop().asInt(); var a = this.stack.pop().asInt(); this.stack.push(Value.i32(a / b)); + break; } - case I32_DIV_U -> { + case I32_DIV_U: { var b = this.stack.pop().asUInt(); var a = this.stack.pop().asUInt(); this.stack.push(Value.i32(a / b)); + break; } - case I64_DIV_S -> { + case I64_DIV_S: { var b = this.stack.pop().asLong(); var a = this.stack.pop().asLong(); this.stack.push(Value.i64(a / b)); + break; } - case I64_DIV_U -> { + case I64_DIV_U: { var b = this.stack.pop().asLong(); var a = this.stack.pop().asLong(); this.stack.push(Value.i64(Long.divideUnsigned(a, b))); + break; } - case I32_REM_S -> { + case I32_REM_S: { var b = this.stack.pop().asInt(); var a = this.stack.pop().asInt(); this.stack.push(Value.i32(a % b)); + break; } - case I32_REM_U -> { + case I32_REM_U: { var b = this.stack.pop().asUInt(); var a = this.stack.pop().asUInt(); this.stack.push(Value.i32(a % b)); + break; } - case I64_AND -> { + case I64_AND: { var a = this.stack.pop().asLong(); var b = this.stack.pop().asLong(); this.stack.push(Value.i64(a & b)); + break; } - case I64_OR -> { + case I64_OR: { var a = this.stack.pop().asLong(); var b = this.stack.pop().asLong(); this.stack.push(Value.i64(a | b)); + break; } - case I64_XOR -> { + case I64_XOR: { var a = this.stack.pop().asLong(); var b = this.stack.pop().asLong(); this.stack.push(Value.i64(a ^ b)); + break; } - case I64_SHL -> { + case I64_SHL: { var c = this.stack.pop().asLong(); var v = this.stack.pop().asLong(); this.stack.push(Value.i64(v << c)); + break; } - case I64_SHR_S -> { + case I64_SHR_S: { var c = this.stack.pop().asLong(); var v = this.stack.pop().asLong(); this.stack.push(Value.i64(v >> c)); + break; } - case I64_SHR_U -> { + case I64_SHR_U: { var c = this.stack.pop().asLong(); var v = this.stack.pop().asLong(); this.stack.push(Value.i64(v >>> c)); + break; } - case I64_REM_S -> { + case I64_REM_S: { var b = this.stack.pop().asLong(); var a = this.stack.pop().asLong(); this.stack.push(Value.i64(a % b)); + break; } - case I64_REM_U -> { + case I64_REM_U: { var b = this.stack.pop().asLong(); var a = this.stack.pop().asLong(); this.stack.push(Value.i64(Long.remainderUnsigned(a, b))); + break; } - case I64_ROTL -> { + case I64_ROTL: { var c = this.stack.pop().asLong(); var v = this.stack.pop().asLong(); var z = (v << c) | (v >>> (64 - c)); this.stack.push(Value.i64(z)); + break; } - case I64_ROTR -> { + case I64_ROTR: { var c = this.stack.pop().asLong(); var v = this.stack.pop().asLong(); var z = (v >>> c) | (v << (64 - c)); this.stack.push(Value.i64(z)); + break; } - case I64_CLZ -> { + case I64_CLZ: { var tos = this.stack.pop(); var count = Long.numberOfLeadingZeros(tos.asLong()); this.stack.push(Value.i64(count)); + break; } - case I64_CTZ -> { + case I64_CTZ: { var tos = this.stack.pop(); var count = Long.numberOfTrailingZeros(tos.asLong()); this.stack.push(Value.i64(count)); + break; } - case I64_POPCNT -> { + case I64_POPCNT: { var tos = this.stack.pop().asLong(); var count = Long.bitCount(tos); this.stack.push(Value.i64(count)); + break; } - case F32_NEG -> { + case F32_NEG: { var tos = this.stack.pop().asFloat(); this.stack.push(Value.fromFloat(-1.0f * tos)); + break; } - case F64_NEG -> { + case F64_NEG: { var tos = this.stack.pop().asDouble(); this.stack.push(Value.fromDouble(-1.0d * tos)); + break; } - case CALL -> { + case CALL: { var funcId = (int) operands[0]; var typeId = instance.getFunctionTypes()[funcId]; var type = instance.getTypes()[typeId]; @@ -540,99 +642,120 @@ void eval(List code) throws ChicoryException { // and pass as args to the function call var args = extractArgsForParams(type.getParams()); call(funcId, args, false); + break; } - case I32_AND -> { + case I32_AND: { var a = this.stack.pop().asInt(); var b = this.stack.pop().asInt(); this.stack.push(Value.i32(a & b)); + break; } - case I32_OR -> { + case I32_OR: { var a = this.stack.pop().asInt(); var b = this.stack.pop().asInt(); this.stack.push(Value.i32(a | b)); + break; } - case I32_XOR -> { + case I32_XOR: { var a = this.stack.pop().asInt(); var b = this.stack.pop().asInt(); this.stack.push(Value.i32(a ^ b)); + break; } - case I32_SHL -> { + case I32_SHL: { var c = this.stack.pop().asInt(); var v = this.stack.pop().asInt(); this.stack.push(Value.i32(v << c)); + break; } - case I32_SHR_S -> { + case I32_SHR_S: { var c = this.stack.pop().asInt(); var v = this.stack.pop().asInt(); this.stack.push(Value.i32(v >> c)); + break; } - case I32_SHR_U -> { + case I32_SHR_U: { var c = this.stack.pop().asInt(); var v = this.stack.pop().asInt(); this.stack.push(Value.i32(v >>> c)); + break; } - case I32_ROTL -> { + case I32_ROTL: { var c = this.stack.pop().asInt(); var v = this.stack.pop().asInt(); var z = (v << c) | (v >>> (32 - c)); this.stack.push(Value.i32(z)); + break; } - case I32_ROTR -> { + case I32_ROTR: { var c = this.stack.pop().asInt(); var v = this.stack.pop().asInt(); var z = (v >>> c) | (v << (32 - c)); this.stack.push(Value.i32(z)); + break; } - case F64_ADD -> { + case F64_ADD: { var a = this.stack.pop().asDouble(); var b = this.stack.pop().asDouble(); this.stack.push(Value.fromDouble(a + b)); + break; } // For the extend_* operations, note that java // automatically does this when casting from // smaller to larger primitives - case I32_EXTEND_8_S -> { + case I32_EXTEND_8_S: { var tos = this.stack.pop().asByte(); this.stack.push(Value.i32(tos)); + break; } - case I32_EXTEND_16_S -> { + case I32_EXTEND_16_S: { var original = this.stack.pop().asInt() & 0xFFFF; if ((original & 0x8000) != 0) original |= 0xFFFF0000; this.stack.push(Value.i32(original & 0xFFFFFFFFL)); + break; } - case I64_EXTEND_8_S -> { + case I64_EXTEND_8_S: { var tos = this.stack.pop().asByte(); this.stack.push(Value.i64(tos)); + break; } - case I64_EXTEND_16_S -> { + case I64_EXTEND_16_S: { var tos = this.stack.pop().asShort(); this.stack.push(Value.i64(tos)); + break; } - case I64_EXTEND_32_S -> { + case I64_EXTEND_32_S: { var tos = this.stack.pop().asInt(); this.stack.push(Value.i64(tos)); + break; } - case F64_CONVERT_I64_U -> { + case F64_CONVERT_I64_U: { var tos = this.stack.pop(); this.stack.push(Value.i64(tos.asLong())); + break; } - case F64_CONVERT_I32_U -> { + case F64_CONVERT_I32_U: { var tos = this.stack.pop(); this.stack.push(Value.i32(tos.asUInt())); + break; } - case F64_CONVERT_I32_S -> { + case F64_CONVERT_I32_S: { var tos = this.stack.pop(); this.stack.push(Value.i32(tos.asInt())); + break; } - case F64_PROMOTE_F32 -> { + case F64_PROMOTE_F32: { var tos = this.stack.pop(); this.stack.push(Value.f64(tos.asUInt())); + break; } - case F64_REINTERPRET_I64 -> { + case F64_REINTERPRET_I64: { var tos = this.stack.pop(); this.stack.push(Value.i64(tos.asLong())); + break; } - default -> throw new RuntimeException("Machine doesn't recognize Instruction " + instruction); + default: + throw new RuntimeException("Machine doesn't recognize Instruction " + instruction); } } } diff --git a/runtime/src/main/java/com/dylibso/chicory/runtime/Memory.java b/runtime/src/main/java/com/dylibso/chicory/runtime/Memory.java index 2a54a8cae..d694d1281 100644 --- a/runtime/src/main/java/com/dylibso/chicory/runtime/Memory.java +++ b/runtime/src/main/java/com/dylibso/chicory/runtime/Memory.java @@ -67,28 +67,42 @@ public void reinstantiate() { var data = segment.getData(); var offset = (int) offsetInstr.getOperands()[0]; System.out.println("Writing data segment " + offset + " " + new String(data)); - this.buffer.put(offset, data); + for (int i = 0, j = offset; i < data.length; i++, j++) { + this.buffer.put(j, data[i]); + } } } public String getString(int offset, int len) { var data = new byte[len]; - this.buffer.get(offset, data); + for (int i = 0, j = offset; i < len; i++, j++) { + data[i] = this.buffer.get(j); + } + return new String(data); } public void put(int offset, String data) { var bytes = data.getBytes(StandardCharsets.UTF_8); - this.buffer.put(offset, bytes); + for (int i = 0, j = offset; i < bytes.length; i++, j++) { + byte b = bytes[i]; + this.buffer.put(j, b); + } } public void put(int offset, byte[] data) { //System.out.println("mem-write@" + offset + " " + data); - this.buffer.put(offset, data); + for (int i = 0, j = offset; i < data.length; i++, j++) { + byte b = data[i]; + this.buffer.put(j, b); + } } public void put(int offset, Value data) { - this.buffer.put(offset, data.getData()); + var bytes = data.getData(); + for (int i = 0, j = offset; i < bytes.length; i++, j++) { + this.buffer.put(j, bytes[i]); + } } public void putI32(int offset, int data) { diff --git a/runtime/src/main/java/com/dylibso/chicory/runtime/Module.java b/runtime/src/main/java/com/dylibso/chicory/runtime/Module.java index 1da2fdc5f..12f9765e5 100644 --- a/runtime/src/main/java/com/dylibso/chicory/runtime/Module.java +++ b/runtime/src/main/java/com/dylibso/chicory/runtime/Module.java @@ -124,7 +124,7 @@ private HostFunction[] mapHostFunctions(Import[] imports, HostFunction[] hostFun for (var f : hostFunctions) { Integer foundId = null; for (var i : imports) { - if (i.getModuleName().equals(f.moduleName()) && i.getFieldName().equals(f.fieldName())) { + if (i.getModuleName().equals(f.getModuleName()) && i.getFieldName().equals(f.getFieldName())) { foundId = (int) i.getDesc().getIndex(); break; } 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 1899a48d9..509e8396b 100644 --- a/runtime/src/main/java/com/dylibso/chicory/runtime/StackFrame.java +++ b/runtime/src/main/java/com/dylibso/chicory/runtime/StackFrame.java @@ -34,10 +34,18 @@ public StackFrame(int funcId, int pc, Value[] args, List initLocals) { // TODO need a cleaner way to initialize? // there are footguns to using the raw Value constructor switch (type) { - case I32 -> this.setLocal(i, Value.i32(0)); - case F32 -> this.setLocal(i, Value.f32(0)); - case I64 -> this.setLocal(i, Value.i64(0)); - case F64 -> this.setLocal(i, Value.f64(0)); + case I32: + this.setLocal(i, Value.i32(0)); + break; + case F32: + this.setLocal(i, Value.f32(0)); + break; + case I64: + this.setLocal(i, Value.i64(0)); + break; + case F64: + this.setLocal(i, Value.f64(0)); + break; } } // set values from args diff --git a/wasm/src/main/java/com/dylibso/chicory/wasm/ControlFlow.java b/wasm/src/main/java/com/dylibso/chicory/wasm/ControlFlow.java index 4f80cbd3f..5ffd56cc9 100644 --- a/wasm/src/main/java/com/dylibso/chicory/wasm/ControlFlow.java +++ b/wasm/src/main/java/com/dylibso/chicory/wasm/ControlFlow.java @@ -55,7 +55,7 @@ public static void labelBranches(List instructions) { for (int i = 0; i < instructions.size(); i++) { var instr = instructions.get(i); switch (instr.getOpcode()) { - case IF -> { + case IF: { instr.setLabelTrue(clamp.apply(i + 1)); // find the matching ELSE (which is optional) var next = findNext(instructions, OpCode.ELSE, instr.getDepth(), clamp.apply(i + 1)); @@ -66,12 +66,14 @@ public static void labelBranches(List instructions) { var end = findNext(instructions, OpCode.END, instr.getDepth(), clamp.apply(i + 1)); instr.setLabelFalse(clamp.apply(end + 1)); } + break; } - case ELSE -> { + case ELSE: { var end = findNext(instructions, OpCode.END, instr.getDepth(), clamp.apply(i + 1)); instr.setLabelTrue(clamp.apply(end + 1)); + break; } - case BR -> { + case BR: { var d = (int) instr.getOperands()[0]; var end = findNext(instructions, OpCode.END, instr.getDepth() - d, clamp.apply(i + 1)); var endI = instructions.get(end); @@ -81,8 +83,9 @@ public static void labelBranches(List instructions) { } else { instr.setLabelTrue(clamp.apply(end + 1)); } + break; } - case BR_IF -> { + case BR_IF: { instr.setLabelFalse(clamp.apply(i + 1)); var d = (int) instr.getOperands()[0]; var end = findNext(instructions, OpCode.END, instr.getDepth() - d, clamp.apply(i + 1)); @@ -93,8 +96,9 @@ public static void labelBranches(List instructions) { } else { instr.setLabelTrue(clamp.apply(end + 1)); } + break; } - case BR_TABLE -> { + case BR_TABLE: { instr.setLabelTable(new int[instr.getOperands().length]); for (var idx = 0; idx < instr.getLabelTable().length; idx++) { var d = (int) instr.getOperands()[idx]; @@ -107,6 +111,7 @@ public static void labelBranches(List instructions) { instr.getLabelTable()[idx] = clamp.apply(end + 1); } } + break; } } } diff --git a/wasm/src/main/java/com/dylibso/chicory/wasm/ModuleBuilder.java b/wasm/src/main/java/com/dylibso/chicory/wasm/ModuleBuilder.java index 367a23a97..a58e68085 100644 --- a/wasm/src/main/java/com/dylibso/chicory/wasm/ModuleBuilder.java +++ b/wasm/src/main/java/com/dylibso/chicory/wasm/ModuleBuilder.java @@ -14,19 +14,45 @@ public ModuleBuilder() { @Override public void onSection(Section s) { switch (s.getSectionId()) { - case SectionId.CUSTOM -> module.addCustomSection((CustomSection) s); - case SectionId.TYPE -> module.setTypeSection((TypeSection) s); - case SectionId.IMPORT -> module.setImportSection((ImportSection) s); - case SectionId.FUNCTION -> module.setFunctionSection((FunctionSection) s); - case SectionId.TABLE -> module.setTableSection((TableSection) s); - case SectionId.MEMORY -> module.setMemorySection((MemorySection) s); - case SectionId.GLOBAL -> module.setGlobalSection((GlobalSection) s); - case SectionId.EXPORT -> module.setExportSection((ExportSection) s); - case SectionId.START -> module.setStartSection((StartSection) s); - case SectionId.ELEMENT -> module.setElementSection((ElementSection) s); - case SectionId.CODE -> module.setCodeSection((CodeSection) s); - case SectionId.DATA -> module.setDataSection((DataSection) s); - default -> System.out.println("Ignoring section with id: " + s.getSectionId()); + case SectionId.CUSTOM: + module.addCustomSection((CustomSection) s); + break; + case SectionId.TYPE: + module.setTypeSection((TypeSection) s); + break; + case SectionId.IMPORT: + module.setImportSection((ImportSection) s); + break; + case SectionId.FUNCTION: + module.setFunctionSection((FunctionSection) s); + break; + case SectionId.TABLE: + module.setTableSection((TableSection) s); + break; + case SectionId.MEMORY: + module.setMemorySection((MemorySection) s); + break; + case SectionId.GLOBAL: + module.setGlobalSection((GlobalSection) s); + break; + case SectionId.EXPORT: + module.setExportSection((ExportSection) s); + break; + case SectionId.START: + module.setStartSection((StartSection) s); + break; + case SectionId.ELEMENT: + module.setElementSection((ElementSection) s); + break; + case SectionId.CODE: + module.setCodeSection((CodeSection) s); + break; + case SectionId.DATA: + module.setDataSection((DataSection) s); + break; + default: + System.out.println("Ignoring section with id: " + s.getSectionId()); + break; } } } diff --git a/wasm/src/main/java/com/dylibso/chicory/wasm/Parser.java b/wasm/src/main/java/com/dylibso/chicory/wasm/Parser.java index a8187c79b..b2fd857e1 100644 --- a/wasm/src/main/java/com/dylibso/chicory/wasm/Parser.java +++ b/wasm/src/main/java/com/dylibso/chicory/wasm/Parser.java @@ -79,57 +79,70 @@ public void parse() { if (shouldParseSection(sectionId)) { // Process different section types based on the sectionId switch (sectionId) { - case SectionId.CUSTOM -> { + case SectionId.CUSTOM: { var customSection = parseCustomSection(buffer, sectionId, sectionSize); listener.onSection(customSection); + break; } - case SectionId.TYPE -> { + case SectionId.TYPE: { var typeSection = parseTypeSection(buffer, sectionId, sectionSize); listener.onSection(typeSection); + break; } - case SectionId.IMPORT -> { + case SectionId.IMPORT: { var importSection = parseImportSection(buffer, sectionId, sectionSize); listener.onSection(importSection); + break; } - case SectionId.FUNCTION -> { + case SectionId.FUNCTION: { var funcSection = parseFunctionSection(buffer, sectionId, sectionSize); listener.onSection(funcSection); + break; } - case SectionId.TABLE-> { + case SectionId.TABLE: { var tableSection = parseTableSection(buffer, sectionId, sectionSize); listener.onSection(tableSection); + break; } - case SectionId.MEMORY -> { + case SectionId.MEMORY: { var memorySection = parseMemorySection(buffer, sectionId, sectionSize); listener.onSection(memorySection); + break; } - case SectionId.GLOBAL -> { + case SectionId.GLOBAL: { var globalSection = parseGlobalSection(buffer, sectionId, sectionSize); listener.onSection(globalSection); + break; } - case SectionId.EXPORT -> { + case SectionId.EXPORT: { var exportSection = parseExportSection(buffer, sectionId, sectionSize); listener.onSection(exportSection); + break; } - case SectionId.START -> { + case SectionId.START: { var startSection = parseStartSection(buffer, sectionId, sectionSize); listener.onSection(startSection); + break; } - case SectionId.ELEMENT -> { + case SectionId.ELEMENT: { var elementSection = parseElementSection(buffer, sectionId, sectionSize); listener.onSection(elementSection); + break; } - case SectionId.CODE -> { + case SectionId.CODE: { var codeSection = parseCodeSection(buffer, sectionId, sectionSize); listener.onSection(codeSection); + break; } - case SectionId.DATA -> { + case SectionId.DATA: { var dataSection = parseDataSection(buffer, sectionId, sectionSize); listener.onSection(dataSection); + break; } - default -> { + default: { System.out.println("Skipping Unknown Section with ID: " + sectionId); buffer.position((int) (buffer.position() + sectionSize)); + break; } } } else { @@ -336,12 +349,15 @@ private static CodeSection parseCodeSection(ByteBuffer buffer, long sectionId, l do { var instruction = parseInstruction(buffer); switch (instruction.getOpcode()) { - case BLOCK, LOOP, IF -> { + case BLOCK: + case LOOP: + case IF: { instruction.setDepth(++depth); blockScope.push(instruction.getOpcode()); instruction.setScope(blockScope.peek()); + break; } - case END -> { + case END: { instruction.setDepth(depth); depth--; if (blockScope.isEmpty()) { @@ -349,9 +365,11 @@ private static CodeSection parseCodeSection(ByteBuffer buffer, long sectionId, l } else { instruction.setScope(blockScope.pop()); } + break; } - default -> { + default: { instruction.setDepth(depth); + break; } } instructions.add(instruction); @@ -399,16 +417,27 @@ private static Instruction parseInstruction(ByteBuffer buffer) { var operands = new ArrayList(); for (var sig : signature) { switch (sig) { - case VARUINT -> operands.add(readVarUInt32(buffer)); - case VARSINT32 -> operands.add(readVarSInt32(buffer)); - case VARSINT64 -> operands.add(readVarSInt64(buffer)); - case FLOAT64 -> operands.add(readFloat64(buffer)); - case FLOAT32 ->operands.add(readFloat32(buffer)); - case VEC_VARUINT -> { + case VARUINT: + operands.add(readVarUInt32(buffer)); + break; + case VARSINT32: + operands.add(readVarSInt32(buffer)); + break; + case VARSINT64: + operands.add(readVarSInt64(buffer)); + break; + case FLOAT64: + operands.add(readFloat64(buffer)); + break; + case FLOAT32: + operands.add(readFloat32(buffer)); + break; + case VEC_VARUINT: { var vcount = (int) readVarUInt32(buffer); for (var j = 0; j < vcount; j++) { operands.add(readVarUInt32(buffer)); } + break; } } } diff --git a/wasm/src/main/java/com/dylibso/chicory/wasm/types/Ast.java b/wasm/src/main/java/com/dylibso/chicory/wasm/types/Ast.java index 4fe276a69..8af04bfb9 100644 --- a/wasm/src/main/java/com/dylibso/chicory/wasm/types/Ast.java +++ b/wasm/src/main/java/com/dylibso/chicory/wasm/types/Ast.java @@ -20,23 +20,26 @@ public CodeBlock getRoot() { public void addInstruction(Instruction i) { var current = peek(); switch (i.getOpcode()) { - case BLOCK -> { + case BLOCK: { current.addInstruction(i); var next = new CodeBlock(BlockType.BLOCK); i.setCodeBlock(next); push(next); + break; } - case LOOP -> { + case LOOP: { current.addInstruction(i); var next = new CodeBlock(BlockType.LOOP); i.setCodeBlock(next); push(next); + break; } - case END -> { + case END: { current.addInstruction(i); pop(); + break; } - default -> current.addInstruction(i); + default: current.addInstruction(i); } } diff --git a/wasm/src/main/java/com/dylibso/chicory/wasm/types/ImportDesc.java b/wasm/src/main/java/com/dylibso/chicory/wasm/types/ImportDesc.java index 547b83218..75438980b 100644 --- a/wasm/src/main/java/com/dylibso/chicory/wasm/types/ImportDesc.java +++ b/wasm/src/main/java/com/dylibso/chicory/wasm/types/ImportDesc.java @@ -18,11 +18,27 @@ public ImportDescType getType() { } public String toString() { - return switch (type) { - case FuncIdx -> "func["+index+"]"; - case TableIdx -> "table["+index+"]"; - case MemIdx -> "memory["+index+"]"; - case GlobalIdx -> "global["+index+"]"; - }; + switch (type) { + case FuncIdx: + return "func["+index+"]"; + case TableIdx: + return "table["+index+"]"; + case MemIdx: + return "memory["+index+"]"; + case GlobalIdx: + return "global["+index+"]"; + default: + return "unknown["+index+"]"; + } + // if (type instanceof FuncIdx) { + // return "func["+index+"]"; + // } else if (type instanceof TableIdx) { + // return "table["+index+"]"; + // } else if (type instanceof MemIdx) { + // return "memory["+index+"]"; + // } else if (type instanceof GlobalIdx) { + // return "global["+index+"]"; + // } + } } diff --git a/wasm/src/main/java/com/dylibso/chicory/wasm/types/Value.java b/wasm/src/main/java/com/dylibso/chicory/wasm/types/Value.java index f4e178e9d..3fc6e5a1a 100644 --- a/wasm/src/main/java/com/dylibso/chicory/wasm/types/Value.java +++ b/wasm/src/main/java/com/dylibso/chicory/wasm/types/Value.java @@ -60,14 +60,17 @@ public Value(ValueType type, int data) { public Value(ValueType type, long data) { this.type = type; switch (type) { - case I32, F32 -> { + case I32: + case F32: { this.data = new byte[4]; this.data[0] = (byte) (data >> 24); this.data[1] = (byte) (data >> 16); this.data[2] = (byte) (data >> 8); this.data[3] = (byte) data; + break; } - case I64, F64 -> { + case I64: + case F64: { this.data = new byte[8]; this.data[0] = (byte) (data >> 56); this.data[1] = (byte) (data >> 48); @@ -77,26 +80,39 @@ public Value(ValueType type, long data) { this.data[5] = (byte) (data >> 16); this.data[6] = (byte) (data >> 8); this.data[7] = (byte) data; + break; } - default -> this.data = new byte[]{}; + default: + this.data = new byte[]{}; + break; } } // TODO memoize these public int asInt() { - return switch (type) { - case I32, F32 -> ByteBuffer.wrap(this.data).getInt(); - case I64, F64 -> ByteBuffer.wrap(this.data, 4, 4).getInt(); + switch (type) { + case I32: + case F32: + return ByteBuffer.wrap(this.data).getInt(); + case I64: + case F64: + return ByteBuffer.wrap(this.data, 4, 4).getInt(); }; + throw new IllegalArgumentException("Can't turn wasm value of type " + type + " to a int"); } // The unsigned representation of the int, stored in a long // so there are enough bits public long asUInt() { - return switch (type) { - case I32, F32 -> ByteBuffer.wrap(this.data).getInt() & 0xFFFFFFFFL; - case I64, F64 -> ByteBuffer.wrap(this.data, 4, 4).getInt() & 0xFFFFFFFFL; + switch (type) { + case I32: + case F32: + return ByteBuffer.wrap(this.data).getInt() & 0xFFFFFFFFL; + case I64: + case F64: + return ByteBuffer.wrap(this.data, 4, 4).getInt() & 0xFFFFFFFFL; }; + throw new IllegalArgumentException("Can't turn wasm value of type " + type + " to a uint"); } // TODO memoize these @@ -118,11 +134,13 @@ public byte asByte() { } public short asShort() { - return switch (type) { - case I32 -> ByteBuffer.wrap(this.data, 2, 2).getShort(); - case I64 -> ByteBuffer.wrap(this.data, 6, 2).getShort(); - default -> throw new IllegalArgumentException("Can't turn wasm value of type " + type + " to a short"); + switch (type) { + case I32: + return ByteBuffer.wrap(this.data, 2, 2).getShort(); + case I64: + return ByteBuffer.wrap(this.data, 6, 2).getShort(); }; + throw new IllegalArgumentException("Can't turn wasm value of type " + type + " to a short"); } public float asFloat() { @@ -135,19 +153,19 @@ public double asDouble() { public String toString() { switch (this.type) { - case I32 -> { + case I32: { return this.asInt() + "@i32"; } - case I64 -> { + case I64: { return this.asLong() + "@i64"; } - case F32 -> { + case F32: { return this.asFloat() + "@f32"; } - case F64 -> { + case F64: { return this.asDouble() + "@f64"; } - default -> throw new RuntimeException("TODO handle float"); + default: throw new RuntimeException("TODO handle float"); } }