From c12d39f25a9ed2fd59a665cbc3288341eb989c5f Mon Sep 17 00:00:00 2001 From: David Phillips Date: Sat, 7 Sep 2024 13:04:47 -0700 Subject: [PATCH] Make Instruction class immutable --- .../com/dylibso/chicory/aot/AotEmitters.java | 50 +++--- .../com/dylibso/chicory/aot/AotMachine.java | 7 +- .../chicory/runtime/ConstantEvaluators.java | 16 +- .../chicory/runtime/ExecutionListener.java | 4 +- .../com/dylibso/chicory/runtime/Instance.java | 5 +- .../chicory/runtime/InterpreterMachine.java | 169 +++++++++--------- .../dylibso/chicory/runtime/ModuleTest.java | 10 +- .../java/com/dylibso/chicory/wasm/Parser.java | 14 +- .../com/dylibso/chicory/wasm/Validator.java | 75 ++++---- .../chicory/wasm/types/Instruction.java | 14 +- .../com/dylibso/chicory/wasm/ParserTest.java | 36 ++-- 11 files changed, 208 insertions(+), 192 deletions(-) diff --git a/aot/src/main/java/com/dylibso/chicory/aot/AotEmitters.java b/aot/src/main/java/com/dylibso/chicory/aot/AotEmitters.java index e7b1a5d29..4a073e2c7 100644 --- a/aot/src/main/java/com/dylibso/chicory/aot/AotEmitters.java +++ b/aot/src/main/java/com/dylibso/chicory/aot/AotEmitters.java @@ -102,7 +102,7 @@ public static void DROP(AotContext ctx, AnnotatedInstruction ins, MethodVisitor } public static void ELEM_DROP(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - int index = (int) ins.operands()[0]; + int index = (int) ins.operand(0); asm.visitVarInsn(Opcodes.ALOAD, ctx.instanceSlot()); asm.visitLdcInsn(index); asm.visitInsn(Opcodes.ACONST_NULL); @@ -126,7 +126,7 @@ public static void SELECT(AotContext ctx, AnnotatedInstruction ins, MethodVisito } public static void CALL(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - int funcId = (int) ins.operands()[0]; + int funcId = (int) ins.operand(0); FunctionType functionType = ctx.functionTypes().get(funcId); MethodType methodType = methodTypeFor(functionType); @@ -149,8 +149,8 @@ public static void CALL(AotContext ctx, AnnotatedInstruction ins, MethodVisitor } public static void CALL_INDIRECT(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - int typeId = (int) ins.operands()[0]; - int tableIdx = (int) ins.operands()[1]; + int typeId = (int) ins.operand(0); + int tableIdx = (int) ins.operand(1); FunctionType functionType = ctx.types()[typeId]; MethodType methodType = callIndirectMethodType(functionType); @@ -175,7 +175,7 @@ public static void CALL_INDIRECT(AotContext ctx, AnnotatedInstruction ins, Metho } public static void REF_FUNC(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - asm.visitLdcInsn((int) ins.operands()[0]); + asm.visitLdcInsn((int) ins.operand(0)); } public static void REF_NULL(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { @@ -187,14 +187,14 @@ public static void REF_IS_NULL(AotContext ctx, AnnotatedInstruction ins, MethodV } public static void LOCAL_GET(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - var loadIndex = (int) ins.operands()[0]; + var loadIndex = (int) ins.operand(0); var localType = localType(ctx.getType(), ctx.getBody(), loadIndex); asm.visitVarInsn(loadTypeOpcode(localType), ctx.localSlotIndex(loadIndex)); ctx.pushStackSize(stackSize(jvmType(localType))); } public static void LOCAL_SET(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - int index = (int) ins.operands()[0]; + int index = (int) ins.operand(0); var localType = localType(ctx.getType(), ctx.getBody(), index); asm.visitVarInsn(storeTypeOpcode(localType), ctx.localSlotIndex(index)); } @@ -212,7 +212,7 @@ public static void LOCAL_TEE(AotContext ctx, AnnotatedInstruction ins, MethodVis } public static void GLOBAL_GET(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - int globalIndex = (int) ins.operands()[0]; + int globalIndex = (int) ins.operand(0); asm.visitVarInsn(Opcodes.ALOAD, ctx.instanceSlot()); asm.visitLdcInsn(globalIndex); @@ -225,7 +225,7 @@ public static void GLOBAL_GET(AotContext ctx, AnnotatedInstruction ins, MethodVi } public static void GLOBAL_SET(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - int globalIndex = (int) ins.operands()[0]; + int globalIndex = (int) ins.operand(0); emitInvokeStatic(asm, boxer(ctx.globalTypes().get(globalIndex))); asm.visitVarInsn(Opcodes.ALOAD, ctx.instanceSlot()); @@ -236,51 +236,51 @@ public static void GLOBAL_SET(AotContext ctx, AnnotatedInstruction ins, MethodVi } public static void TABLE_GET(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - asm.visitLdcInsn((int) ins.operands()[0]); + asm.visitLdcInsn((int) ins.operand(0)); asm.visitVarInsn(Opcodes.ALOAD, ctx.instanceSlot()); emitInvokeStatic(asm, TABLE_GET); } public static void TABLE_SET(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - asm.visitLdcInsn((int) ins.operands()[0]); + asm.visitLdcInsn((int) ins.operand(0)); asm.visitVarInsn(Opcodes.ALOAD, ctx.instanceSlot()); emitInvokeStatic(asm, TABLE_SET); } public static void TABLE_SIZE(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - asm.visitLdcInsn((int) ins.operands()[0]); + asm.visitLdcInsn((int) ins.operand(0)); asm.visitVarInsn(Opcodes.ALOAD, ctx.instanceSlot()); emitInvokeStatic(asm, TABLE_SIZE); } public static void TABLE_GROW(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - asm.visitLdcInsn((int) ins.operands()[0]); + asm.visitLdcInsn((int) ins.operand(0)); asm.visitVarInsn(Opcodes.ALOAD, ctx.instanceSlot()); emitInvokeStatic(asm, TABLE_GROW); } public static void TABLE_FILL(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - asm.visitLdcInsn((int) ins.operands()[0]); + asm.visitLdcInsn((int) ins.operand(0)); asm.visitVarInsn(Opcodes.ALOAD, ctx.instanceSlot()); emitInvokeStatic(asm, TABLE_FILL); } public static void TABLE_COPY(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - asm.visitLdcInsn((int) ins.operands()[0]); - asm.visitLdcInsn((int) ins.operands()[1]); + asm.visitLdcInsn((int) ins.operand(0)); + asm.visitLdcInsn((int) ins.operand(1)); asm.visitVarInsn(Opcodes.ALOAD, ctx.instanceSlot()); emitInvokeStatic(asm, TABLE_COPY); } public static void TABLE_INIT(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - asm.visitLdcInsn((int) ins.operands()[0]); - asm.visitLdcInsn((int) ins.operands()[1]); + asm.visitLdcInsn((int) ins.operand(0)); + asm.visitLdcInsn((int) ins.operand(1)); asm.visitVarInsn(Opcodes.ALOAD, ctx.instanceSlot()); emitInvokeStatic(asm, TABLE_INIT); } public static void MEMORY_INIT(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - int segmentId = (int) ins.operands()[0]; + int segmentId = (int) ins.operand(0); asm.visitLdcInsn(segmentId); asm.visitVarInsn(Opcodes.ALOAD, ctx.memorySlot()); emitInvokeStatic(asm, MEMORY_INIT); @@ -308,7 +308,7 @@ public static void MEMORY_SIZE(AotContext ctx, AnnotatedInstruction ins, MethodV } public static void DATA_DROP(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - int segmentId = (int) ins.operands()[0]; + int segmentId = (int) ins.operand(0); asm.visitVarInsn(Opcodes.ALOAD, ctx.memorySlot()); asm.visitLdcInsn(segmentId); emitInvokeVirtual(asm, MEMORY_DROP); @@ -323,7 +323,7 @@ public static void I32_AND(AotContext ctx, AnnotatedInstruction ins, MethodVisit } public static void I32_CONST(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - asm.visitLdcInsn((int) ins.operands()[0]); + asm.visitLdcInsn((int) ins.operand(0)); } public static void I32_MUL(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { @@ -367,7 +367,7 @@ public static void I64_AND(AotContext ctx, AnnotatedInstruction ins, MethodVisit } public static void I64_CONST(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - asm.visitLdcInsn(ins.operands()[0]); + asm.visitLdcInsn(ins.operand(0)); } public static void I64_EXTEND_I32_S( @@ -411,7 +411,7 @@ public static void F32_ADD(AotContext ctx, AnnotatedInstruction ins, MethodVisit } public static void F32_CONST(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - asm.visitLdcInsn(Float.intBitsToFloat((int) ins.operands()[0])); + asm.visitLdcInsn(Float.intBitsToFloat((int) ins.operand(0))); } public static void F32_DEMOTE_F64(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { @@ -439,7 +439,7 @@ public static void F64_ADD(AotContext ctx, AnnotatedInstruction ins, MethodVisit } public static void F64_CONST(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { - asm.visitLdcInsn(Double.longBitsToDouble(ins.operands()[0])); + asm.visitLdcInsn(Double.longBitsToDouble(ins.operand(0))); } public static void F64_DIV(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) { @@ -574,7 +574,7 @@ public static void F64_STORE(AotContext ctx, AnnotatedInstruction ins, MethodVis private static void emitLoadOrStore( AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm, Method method) { - long offset = ins.operands()[1]; + long offset = ins.operand(1); if (offset < 0 || offset >= Integer.MAX_VALUE) { emitInvokeStatic(asm, THROW_OUT_OF_BOUNDS_MEMORY_ACCESS); diff --git a/aot/src/main/java/com/dylibso/chicory/aot/AotMachine.java b/aot/src/main/java/com/dylibso/chicory/aot/AotMachine.java index ef0a206cf..3c7ce63a9 100644 --- a/aot/src/main/java/com/dylibso/chicory/aot/AotMachine.java +++ b/aot/src/main/java/com/dylibso/chicory/aot/AotMachine.java @@ -21,6 +21,7 @@ import static com.dylibso.chicory.aot.AotUtil.storeTypeOpcode; import static com.dylibso.chicory.aot.AotUtil.unboxer; import static com.dylibso.chicory.aot.AotUtil.unboxerHandle; +import static com.dylibso.chicory.wasm.types.Instruction.EMPTY_OPERANDS; import static java.lang.invoke.MethodHandles.filterArguments; import static java.lang.invoke.MethodHandles.filterReturnValue; import static java.lang.invoke.MethodHandles.insertArguments; @@ -81,7 +82,9 @@ public final class AotMachine implements Machine { public static final String DEFAULT_CLASS_NAME = "com.dylibso.chicory.$gen.CompiledModule"; - private static final Instruction FUNCTION_SCOPE = new Instruction(-1, OpCode.NOP, new long[0]); + + private static final Instruction FUNCTION_SCOPE = + new Instruction(-1, OpCode.NOP, EMPTY_OPERANDS); private final Module module; private final Instance instance; @@ -865,7 +868,7 @@ private void emitUnwindStack( } private FunctionType blockType(Instruction ins) { - var typeId = (int) ins.operands()[0]; + var typeId = (int) ins.operand(0); if (typeId == 0x40) { return FunctionType.empty(); } diff --git a/runtime/src/main/java/com/dylibso/chicory/runtime/ConstantEvaluators.java b/runtime/src/main/java/com/dylibso/chicory/runtime/ConstantEvaluators.java index 36462e44e..877af3265 100644 --- a/runtime/src/main/java/com/dylibso/chicory/runtime/ConstantEvaluators.java +++ b/runtime/src/main/java/com/dylibso/chicory/runtime/ConstantEvaluators.java @@ -23,27 +23,27 @@ public static Value computeConstantValue(Instance instance, List ex switch (instruction.opcode()) { case F32_CONST: { - tos = Value.f32(instruction.operands()[0]); + tos = Value.f32(instruction.operand(0)); break; } case F64_CONST: { - tos = Value.f64(instruction.operands()[0]); + tos = Value.f64(instruction.operand(0)); break; } case I32_CONST: { - tos = Value.i32(instruction.operands()[0]); + tos = Value.i32(instruction.operand(0)); break; } case I64_CONST: { - tos = Value.i64(instruction.operands()[0]); + tos = Value.i64(instruction.operand(0)); break; } case REF_NULL: { - ValueType vt = ValueType.refTypeForId((int) instruction.operands()[0]); + ValueType vt = ValueType.refTypeForId((int) instruction.operand(0)); if (vt == ValueType.ExternRef) { tos = Value.EXTREF_NULL; } else if (vt == ValueType.FuncRef) { @@ -56,14 +56,14 @@ public static Value computeConstantValue(Instance instance, List ex } case REF_FUNC: { - var idx = (int) instruction.operands()[0]; + var idx = (int) instruction.operand(0); instance.function(idx); tos = Value.funcRef(idx); break; } case GLOBAL_GET: { - var idx = (int) instruction.operands()[0]; + var idx = (int) instruction.operand(0); if (idx < instance.imports().globalCount()) { if (instance.imports().global(idx).instance().getMutabilityType() != MutabilityType.Const) { @@ -102,7 +102,7 @@ public static Value computeConstantValue(Instance instance, List ex public static Instance computeConstantInstance(Instance instance, List expr) { for (Instruction instruction : expr) { if (instruction.opcode() == GLOBAL_GET) { - return instance.global((int) instruction.operands()[0]).getInstance(); + return instance.global((int) instruction.operand(0)).getInstance(); } } return instance; diff --git a/runtime/src/main/java/com/dylibso/chicory/runtime/ExecutionListener.java b/runtime/src/main/java/com/dylibso/chicory/runtime/ExecutionListener.java index c81a3d5e5..afc5c6973 100644 --- a/runtime/src/main/java/com/dylibso/chicory/runtime/ExecutionListener.java +++ b/runtime/src/main/java/com/dylibso/chicory/runtime/ExecutionListener.java @@ -1,6 +1,6 @@ package com.dylibso.chicory.runtime; -import com.dylibso.chicory.wasm.types.AnnotatedInstruction; +import com.dylibso.chicory.wasm.types.Instruction; @FunctionalInterface public interface ExecutionListener { @@ -13,5 +13,5 @@ public interface ExecutionListener { * * If you have a specific use case for this functionality, please, open an Issue at: https://github.com/dylibso/chicory/issues */ - void onExecution(AnnotatedInstruction instruction, long[] operands, MStack stack); + void onExecution(Instruction instruction, MStack stack); } diff --git a/runtime/src/main/java/com/dylibso/chicory/runtime/Instance.java b/runtime/src/main/java/com/dylibso/chicory/runtime/Instance.java index 29a7f4cc9..9d2ef1db5 100644 --- a/runtime/src/main/java/com/dylibso/chicory/runtime/Instance.java +++ b/runtime/src/main/java/com/dylibso/chicory/runtime/Instance.java @@ -12,7 +12,6 @@ import com.dylibso.chicory.wasm.exceptions.UnlinkableException; import com.dylibso.chicory.wasm.types.ActiveDataSegment; import com.dylibso.chicory.wasm.types.ActiveElement; -import com.dylibso.chicory.wasm.types.AnnotatedInstruction; import com.dylibso.chicory.wasm.types.DataSegment; import com.dylibso.chicory.wasm.types.DeclarativeElement; import com.dylibso.chicory.wasm.types.Element; @@ -344,9 +343,9 @@ public Value[] callHostFunction(int funcId, Value[] args) { return imprt.handle().apply(this, args); } - public void onExecution(AnnotatedInstruction instruction, long[] operands, MStack stack) { + public void onExecution(Instruction instruction, MStack stack) { if (listener != null) { - listener.onExecution(instruction, operands, stack); + listener.onExecution(instruction, stack); } } 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 7bf2d1172..93fabd783 100644 --- a/runtime/src/main/java/com/dylibso/chicory/runtime/InterpreterMachine.java +++ b/runtime/src/main/java/com/dylibso/chicory/runtime/InterpreterMachine.java @@ -125,8 +125,8 @@ static void eval(MStack stack, Instance instance, Deque callStack) // + " stack=" // + stack); var opcode = instruction.opcode(); - var operands = instruction.operands(); - instance.onExecution(instruction, operands, stack); + Operands operands = instruction::operand; + instance.onExecution(instruction, stack); switch (opcode) { case UNREACHABLE: throw new TrapException("Trapped on unreachable instruction", callStack); @@ -185,14 +185,14 @@ static void eval(MStack stack, Instance instance, Deque callStack) SELECT_T(stack); break; case LOCAL_GET: - stack.push(frame.local((int) operands[0])); + stack.push(frame.local((int) operands.get(0))); break; case LOCAL_SET: - frame.setLocal((int) operands[0], stack.pop()); + frame.setLocal((int) operands.get(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()); + frame.setLocal((int) operands.get(0), stack.peek()); break; case GLOBAL_GET: GLOBAL_GET(stack, instance, operands); @@ -283,16 +283,16 @@ static void eval(MStack stack, Instance instance, Deque callStack) break; // TODO 32bit and 64 bit operations are the same for now case I32_CONST: - stack.push(Value.i32(operands[0])); + stack.push(Value.i32(operands.get(0))); break; case I64_CONST: - stack.push(Value.i64(operands[0])); + stack.push(Value.i64(operands.get(0))); break; case F32_CONST: - stack.push(Value.f32(operands[0])); + stack.push(Value.f32(operands.get(0))); break; case F64_CONST: - stack.push(Value.f64(operands[0])); + stack.push(Value.f64(operands.get(0))); break; case I32_EQ: I32_EQ(stack); @@ -733,7 +733,7 @@ static void eval(MStack stack, Instance instance, Deque callStack) TABLE_GROW(stack, instance, operands); break; case REF_FUNC: - stack.push(Value.funcRef((int) operands[0])); + stack.push(Value.funcRef((int) operands.get(0))); break; case REF_NULL: REF_NULL(stack, operands); @@ -1260,15 +1260,15 @@ private static void MEMORY_SIZE(MStack stack, Instance instance) { stack.push(Value.i32(sz)); } - private static void I64_STORE32(MStack stack, Instance instance, long[] operands) { + private static void I64_STORE32(MStack stack, Instance instance, Operands operands) { var value = stack.pop().asLong(); - var ptr = (int) (operands[1] + stack.pop().asInt()); + var ptr = (int) (operands.get(1) + stack.pop().asInt()); instance.memory().writeI32(ptr, (int) value); } - private static void I64_STORE8(MStack stack, Instance instance, long[] operands) { + private static void I64_STORE8(MStack stack, Instance instance, Operands operands) { var value = stack.pop().asByte(); - var ptr = (int) (operands[1] + stack.pop().asInt()); + var ptr = (int) (operands.get(1) + stack.pop().asInt()); instance.memory().writeByte(ptr, value); } @@ -1419,13 +1419,13 @@ private static void F32_CONVERT_I64_S(MStack stack) { 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]); + private static void REF_NULL(MStack stack, Operands operands) { + var type = ValueType.forId((int) operands.get(0)); stack.push(new Value(type, (long) REF_NULL_VALUE)); } - private static void ELEM_DROP(Instance instance, long[] operands) { - var x = (int) operands[0]; + private static void ELEM_DROP(Instance instance, Operands operands) { + var x = (int) operands.get(0); instance.setElement(x, null); } @@ -1437,8 +1437,8 @@ private static void REF_IS_NULL(MStack stack) { : Value.FALSE); } - private static void DATA_DROP(Instance instance, long[] operands) { - var segment = (int) operands[0]; + private static void DATA_DROP(Instance instance, Operands operands) { + var segment = (int) operands.get(0); instance.memory().drop(segment); } @@ -1447,8 +1447,8 @@ private static void F64_CONVERT_I64_S(MStack stack) { 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]; + private static void TABLE_GROW(MStack stack, Instance instance, Operands operands) { + var tableidx = (int) operands.get(0); var table = instance.table(tableidx); var size = stack.pop().asInt(); @@ -1459,15 +1459,15 @@ private static void TABLE_GROW(MStack stack, Instance instance, long[] operands) stack.push(Value.i32(res)); } - private static void TABLE_SIZE(MStack stack, Instance instance, long[] operands) { - var tableidx = (int) operands[0]; + private static void TABLE_SIZE(MStack stack, Instance instance, Operands operands) { + var tableidx = (int) operands.get(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]; + private static void TABLE_FILL(MStack stack, Instance instance, Operands operands) { + var tableidx = (int) operands.get(0); var size = stack.pop().asInt(); var val = stack.pop().asExtRef(); @@ -1476,9 +1476,9 @@ private static void TABLE_FILL(MStack stack, Instance instance, long[] operands) 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]; + private static void TABLE_COPY(MStack stack, Instance instance, Operands operands) { + var tableidxSrc = (int) operands.get(1); + var tableidxDst = (int) operands.get(0); var size = stack.pop().asInt(); var s = stack.pop().asInt(); @@ -1487,9 +1487,9 @@ private static void TABLE_COPY(MStack stack, Instance instance, long[] operands) 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]; + private static void MEMORY_COPY(MStack stack, Instance instance, Operands operands) { + var memidxSrc = (int) operands.get(0); + var memidxDst = (int) operands.get(1); if (memidxDst != 0 && memidxSrc != 0) { throw new WASMRuntimeException( "We don't support non zero index for memory: " + memidxSrc + " " + memidxDst); @@ -1500,9 +1500,9 @@ private static void MEMORY_COPY(MStack stack, Instance instance, long[] operands 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]; + private static void TABLE_INIT(MStack stack, Instance instance, Operands operands) { + var tableidx = (int) operands.get(1); + var elementidx = (int) operands.get(0); var size = stack.pop().asInt(); var elemidx = stack.pop().asInt(); @@ -1511,9 +1511,9 @@ private static void TABLE_INIT(MStack stack, Instance instance, long[] operands) 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]; + private static void MEMORY_INIT(MStack stack, Instance instance, Operands operands) { + var segmentId = (int) operands.get(0); + var memidx = (int) operands.get(1); if (memidx != 0) { throw new WASMRuntimeException("We don't support non zero index for memory: " + memidx); } @@ -1615,8 +1615,8 @@ private static void F32_TRUNC(MStack stack) { } private static void CALL( - MStack stack, Instance instance, Deque callStack, long[] operands) { - var funcId = (int) operands[0]; + MStack stack, Instance instance, Deque callStack, Operands operands) { + var funcId = (int) operands.get(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 @@ -1635,8 +1635,8 @@ private static void F32_NEG(MStack stack) { stack.push(Value.fromFloat(-tos)); } - private static void MEMORY_FILL(MStack stack, Instance instance, long[] operands) { - var memidx = (int) operands[0]; + private static void MEMORY_FILL(MStack stack, Instance instance, Operands operands) { + var memidx = (int) operands.get(0); if (memidx != 0) { throw new WASMRuntimeException("We don't support multiple memories just yet"); } @@ -1653,135 +1653,135 @@ private static void MEMORY_GROW(MStack stack, Instance instance) { stack.push(Value.i32(nPages)); } - private static int readMemPtr(MStack stack, long[] operands) { + private static int readMemPtr(MStack stack, Operands operands) { int offset = stack.pop().asInt(); - if (operands[1] < 0 || operands[1] >= Integer.MAX_VALUE || offset < 0) { + if (operands.get(1) < 0 || operands.get(1) >= Integer.MAX_VALUE || offset < 0) { throw new WASMRuntimeException("out of bounds memory access"); } - return (int) (operands[1] + offset); + return (int) (operands.get(1) + offset); } - private static void F64_STORE(MStack stack, Instance instance, long[] operands) { + private static void F64_STORE(MStack stack, Instance instance, Operands 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) { + private static void F32_STORE(MStack stack, Instance instance, Operands 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) { + private static void I64_STORE(MStack stack, Instance instance, Operands 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) { + private static void I64_STORE16(MStack stack, Instance instance, Operands 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) { + private static void I32_STORE(MStack stack, Instance instance, Operands 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) { + private static void I64_LOAD32_U(MStack stack, Instance instance, Operands 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) { + private static void I64_LOAD32_S(MStack stack, Instance instance, Operands 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) { + private static void I64_LOAD16_U(MStack stack, Instance instance, Operands 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) { + private static void I32_LOAD16_U(MStack stack, Instance instance, Operands 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) { + private static void I64_LOAD16_S(MStack stack, Instance instance, Operands 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) { + private static void I32_LOAD16_S(MStack stack, Instance instance, Operands 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) { + private static void I64_LOAD8_U(MStack stack, Instance instance, Operands 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) { + private static void I32_LOAD8_U(MStack stack, Instance instance, Operands 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) { + private static void I64_LOAD8_S(MStack stack, Instance instance, Operands 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) { + private static void I32_LOAD8_S(MStack stack, Instance instance, Operands 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) { + private static void F64_LOAD(MStack stack, Instance instance, Operands 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) { + private static void F32_LOAD(MStack stack, Instance instance, Operands 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) { + private static void I64_LOAD(MStack stack, Instance instance, Operands 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) { + private static void I32_LOAD(MStack stack, Instance instance, Operands 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]; + private static void TABLE_SET(MStack stack, Instance instance, Operands operands) { + var idx = (int) operands.get(0); var table = instance.table(idx); var value = stack.pop().asExtRef(); @@ -1789,20 +1789,20 @@ private static void TABLE_SET(MStack stack, Instance instance, long[] operands) table.setRef(i, value, instance); } - private static void TABLE_GET(MStack stack, Instance instance, long[] operands) { - var idx = (int) operands[0]; + private static void TABLE_GET(MStack stack, Instance instance, Operands operands) { + var idx = (int) operands.get(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]; + private static void GLOBAL_SET(MStack stack, Instance instance, Operands operands) { + var id = (int) operands.get(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]; + private static void GLOBAL_GET(MStack stack, Instance instance, Operands operands) { + int idx = (int) operands.get(0); var val = instance.readGlobal(idx); stack.push(val); @@ -1831,11 +1831,11 @@ private static void SELECT_T(MStack stack) { } private static void CALL_INDIRECT( - MStack stack, Instance instance, Deque callStack, long[] operands) { - var tableIdx = (int) operands[1]; + MStack stack, Instance instance, Deque callStack, Operands operands) { + var tableIdx = (int) operands.get(1); var table = instance.table(tableIdx); - var typeId = (int) operands[0]; + var typeId = (int) operands.get(0); int funcTableIdx = stack.pop().asInt(); int funcId = table.ref(funcTableIdx).asFuncRef(); var tableInstance = table.instance(funcTableIdx); @@ -1854,7 +1854,7 @@ private static void CALL_INDIRECT( } private static int numberOfParams(Instance instance, AnnotatedInstruction scope) { - var typeId = (int) scope.operands()[0]; + var typeId = (int) scope.operand(0); if (typeId == 0x40) { // epsilon return 0; } @@ -1868,7 +1868,7 @@ private static int numberOfValuesToReturn(Instance instance, AnnotatedInstructio if (scope.opcode() == OpCode.END) { return 0; } - var typeId = (int) scope.operands()[0]; + var typeId = (int) scope.operand(0); if (typeId == 0x40) { // epsilon return 0; } @@ -1906,7 +1906,7 @@ private static void ctrlJump(StackFrame frame, MStack stack, int n) { private static void BR(StackFrame frame, MStack stack, AnnotatedInstruction instruction) { checkInterruption(); - ctrlJump(frame, stack, (int) instruction.operands()[0]); + ctrlJump(frame, stack, (int) instruction.operand(0)); frame.jumpTo(instruction.labelTrue()); } @@ -1914,13 +1914,13 @@ private static void BR_TABLE(StackFrame frame, MStack stack, AnnotatedInstructio var predValue = stack.pop(); var pred = predValue.asInt(); - var defaultIdx = instruction.operands().length - 1; + var defaultIdx = instruction.operandCount() - 1; if (pred < 0 || pred >= defaultIdx) { // choose default - ctrlJump(frame, stack, (int) instruction.operands()[defaultIdx]); + ctrlJump(frame, stack, (int) instruction.operand(defaultIdx)); frame.jumpTo(instruction.labelTable().get(defaultIdx)); } else { - ctrlJump(frame, stack, (int) instruction.operands()[pred]); + ctrlJump(frame, stack, (int) instruction.operand(pred)); frame.jumpTo(instruction.labelTable().get(pred)); } } @@ -1932,7 +1932,7 @@ private static void BR_IF(StackFrame frame, MStack stack, AnnotatedInstruction i if (pred == 0) { frame.jumpTo(instruction.labelFalse()); } else { - ctrlJump(frame, stack, (int) instruction.operands()[0]); + ctrlJump(frame, stack, (int) instruction.operand(0)); frame.jumpTo(instruction.labelTrue()); } } @@ -1982,4 +1982,9 @@ private static void checkInterruption() { throw new ChicoryException("Thread interrupted"); } } + + @FunctionalInterface + private interface Operands { + long get(int index); + } } diff --git a/runtime/src/test/java/com/dylibso/chicory/runtime/ModuleTest.java b/runtime/src/test/java/com/dylibso/chicory/runtime/ModuleTest.java index a52ae8e36..61236aadb 100644 --- a/runtime/src/test/java/com/dylibso/chicory/runtime/ModuleTest.java +++ b/runtime/src/test/java/com/dylibso/chicory/runtime/ModuleTest.java @@ -8,7 +8,6 @@ import com.dylibso.chicory.wasm.Module; import com.dylibso.chicory.wasm.Parser; import com.dylibso.chicory.wasm.exceptions.UninstantiableException; -import com.dylibso.chicory.wasm.types.AnnotatedInstruction; import com.dylibso.chicory.wasm.types.MemoryLimits; import com.dylibso.chicory.wasm.types.Value; import com.dylibso.chicory.wasm.types.ValueType; @@ -328,8 +327,7 @@ public void shouldCountNumberOfInstructions() { var instance = Instance.builder(loadModule("compiled/iterfact.wat.wasm")) .withUnsafeExecutionListener( - (AnnotatedInstruction instruction, long[] operands, MStack stack) -> - count.getAndIncrement()) + (instruction, stack) -> count.getAndIncrement()) .build(); var iterFact = instance.export("iterFact"); @@ -346,11 +344,7 @@ public void shouldConsumeStackLoopOperations() { var instance = Instance.builder(loadModule("compiled/fac.wat.wasm")) .withUnsafeExecutionListener( - (AnnotatedInstruction instruction, - long[] operands, - MStack stack) -> { - finalStackSize.set(stack.size()); - }) + (instruction, stack) -> finalStackSize.set(stack.size())) .build(); var facSsa = instance.export("fac-ssa"); 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 1e9d3499e..499102650 100644 --- a/wasm/src/main/java/com/dylibso/chicory/wasm/Parser.java +++ b/wasm/src/main/java/com/dylibso/chicory/wasm/Parser.java @@ -5,6 +5,7 @@ import static com.dylibso.chicory.wasm.Encoding.readSigned64Leb128; import static com.dylibso.chicory.wasm.Encoding.readUnsignedLeb128; import static com.dylibso.chicory.wasm.WasmLimits.MAX_FUNCTION_LOCALS; +import static com.dylibso.chicory.wasm.types.Instruction.EMPTY_OPERANDS; import static java.util.Objects.requireNonNull; import com.dylibso.chicory.wasm.exceptions.ChicoryException; @@ -659,7 +660,7 @@ private static Element parseSingleElement(ByteBuffer buffer) { List.of( new Instruction( -1, OpCode.REF_FUNC, new long[] {readVarUInt32(buffer)}), - new Instruction(-1, OpCode.END, new long[0]))); + new Instruction(-1, OpCode.END, EMPTY_OPERANDS))); } } if (declarative) { @@ -791,7 +792,7 @@ private static CodeSection parseCodeSection(ByteBuffer buffer) { // fallthrough case BR: { - var offset = (int) baseInstruction.operands()[0]; + var offset = (int) baseInstruction.operand(0); ControlTree reference = currentControlFlow; while (offset > 0) { if (reference == null) { @@ -805,11 +806,11 @@ private static CodeSection parseCodeSection(ByteBuffer buffer) { } case BR_TABLE: { - var length = baseInstruction.operands().length; + var length = baseInstruction.operandCount(); var labelTable = new ArrayList(); for (var idx = 0; idx < length; idx++) { labelTable.add(null); - var offset = (int) baseInstruction.operands()[idx]; + var offset = (int) baseInstruction.operand(idx); ControlTree reference = currentControlFlow; while (offset > 0) { if (reference == null) { @@ -921,6 +922,11 @@ private static Instruction parseInstruction(ByteBuffer buffer) { default: break; } + + if (signature.isEmpty()) { + return new Instruction(address, op, EMPTY_OPERANDS); + } + var operands = new ArrayList(); for (var sig : signature) { switch (sig) { diff --git a/wasm/src/main/java/com/dylibso/chicory/wasm/Validator.java b/wasm/src/main/java/com/dylibso/chicory/wasm/Validator.java index 25a518b5e..a84f4ca2e 100644 --- a/wasm/src/main/java/com/dylibso/chicory/wasm/Validator.java +++ b/wasm/src/main/java/com/dylibso/chicory/wasm/Validator.java @@ -123,7 +123,7 @@ public Validator(Module module) { private Stream declaredFunctions(List init) { if (!init.isEmpty() && init.get(0).opcode() == OpCode.REF_FUNC) { - int idx = (int) init.get(0).operands()[0]; + int idx = (int) init.get(0).operand(0); getFunctionType(idx); if (idx >= functionImports.size()) { return Stream.of(idx); @@ -240,7 +240,7 @@ private void validateDataSegment(int idx) { } private List getReturns(AnnotatedInstruction op) { - var typeId = (int) op.operands()[0]; + var typeId = (int) op.operand(0); if (typeId == 0x40) { // epsilon return List.of(); } @@ -251,7 +251,7 @@ private List getReturns(AnnotatedInstruction op) { } private List getParams(AnnotatedInstruction op) { - var typeId = (int) op.operands()[0]; + var typeId = (int) op.operand(0); if (typeId == 0x40) { // epsilon return List.of(); } @@ -372,7 +372,6 @@ private void validateConstantExpression( for (var instruction : expr) { ValueType exprType = null; - long[] operands = instruction.operands(); switch (instruction.opcode()) { case I32_CONST: exprType = ValueType.I32; @@ -392,7 +391,7 @@ private void validateConstantExpression( break; case REF_NULL: { - exprType = ValueType.refTypeForId((int) operands[0]); + exprType = ValueType.refTypeForId((int) instruction.operand(0)); constInstrCount++; if (exprType != ValueType.ExternRef && exprType != ValueType.FuncRef) { throw new IllegalStateException( @@ -404,7 +403,7 @@ private void validateConstantExpression( { exprType = ValueType.FuncRef; constInstrCount++; - long idx = operands[0]; + long idx = instruction.operand(0); if (idx < 0 || idx > allFuncCount) { throw new InvalidException("unknown function " + idx); @@ -414,7 +413,7 @@ private void validateConstantExpression( } case GLOBAL_GET: { - var idx = (int) operands[0]; + var idx = (int) instruction.operand(0); if (idx < globalImports.size()) { var global = globalImports.get(idx); if (global.mutabilityType() != MutabilityType.Const) { @@ -513,7 +512,7 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi } case BR: { - var n = (int) op.operands()[0]; + var n = (int) op.operand(0); popVals(labelTypes(getCtrl(n))); unreachable(); break; @@ -521,7 +520,7 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi case BR_IF: { popVal(ValueType.I32); - var n = (int) op.operands()[0]; + var n = (int) op.operand(0); var labelTypes = labelTypes(getCtrl(n)); popVals(labelTypes); pushVals(labelTypes); @@ -530,14 +529,14 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi case BR_TABLE: { popVal(ValueType.I32); - var m = (int) op.operands()[op.operands().length - 1]; + var m = (int) op.operand(op.operandCount() - 1); if ((ctrlFrameStack.size() - 1 - m) < 0) { throw new InvalidException("unknown label " + m); } var defaultBranchLabelTypes = labelTypes(getCtrl(m)); var arity = defaultBranchLabelTypes.size(); - for (var idx = 0; idx < op.operands().length - 1; idx++) { - var n = (int) op.operands()[idx]; + for (var idx = 0; idx < op.operandCount() - 1; idx++) { + var n = (int) op.operand(idx); CtrlFrame ctrlFrame; try { ctrlFrame = getCtrl(n); @@ -582,15 +581,15 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi switch (op.opcode()) { case MEMORY_COPY: - validateMemory((int) op.operands()[0]); - validateMemory((int) op.operands()[1]); + validateMemory((int) op.operand(0)); + validateMemory((int) op.operand(1)); break; case MEMORY_FILL: - validateMemory((int) op.operands()[0]); + validateMemory((int) op.operand(0)); break; case MEMORY_INIT: - validateMemory((int) op.operands()[1]); - validateDataSegment((int) op.operands()[0]); + validateMemory((int) op.operand(1)); + validateDataSegment((int) op.operand(0)); break; case MEMORY_SIZE: case MEMORY_GROW: @@ -638,7 +637,7 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi break; case DATA_DROP: { - validateDataSegment((int) op.operands()[0]); + validateDataSegment((int) op.operand(0)); break; } case DROP: @@ -972,7 +971,7 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi } case LOCAL_SET: { - var index = (int) op.operands()[0]; + var index = (int) op.operand(0); ValueType expectedType = (index < inputLen) ? functionType.params().get(index) @@ -982,7 +981,7 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi } case LOCAL_GET: { - var index = (int) op.operands()[0]; + var index = (int) op.operand(0); ValueType expectedType = (index < inputLen) ? functionType.params().get(index) @@ -992,7 +991,7 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi } case LOCAL_TEE: { - var index = (int) op.operands()[0]; + var index = (int) op.operand(0); ValueType expectedType = (index < inputLen) ? functionType.params().get(index) @@ -1003,13 +1002,13 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi } case GLOBAL_GET: { - var global = getGlobal((int) op.operands()[0]); + var global = getGlobal((int) op.operand(0)); pushVal(global.valueType()); break; } case GLOBAL_SET: { - var global = getGlobal((int) op.operands()[0]); + var global = getGlobal((int) op.operand(0)); if (global.mutabilityType() == MutabilityType.Const) { throw new InvalidException("global is immutable"); } @@ -1018,7 +1017,7 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi } case CALL: { - int typeId = getFunctionType((int) op.operands()[0]); + int typeId = getFunctionType((int) op.operand(0)); var types = getType(typeId); for (int j = types.params().size() - 1; j >= 0; j--) { popVal(types.params().get(j)); @@ -1028,9 +1027,9 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi } case CALL_INDIRECT: { - var typeId = (int) op.operands()[0]; + var typeId = (int) op.operand(0); popVal(ValueType.I32); - getTableType((int) op.operands()[1]); + getTableType((int) op.operand(1)); var types = getType(typeId); for (int j = types.params().size() - 1; j >= 0; j--) { popVal(types.params().get(j)); @@ -1040,7 +1039,7 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi } case REF_NULL: { - pushVal(ValueType.forId((int) op.operands()[0])); + pushVal(ValueType.forId((int) op.operand(0))); break; } case REF_IS_NULL: @@ -1055,7 +1054,7 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi } case REF_FUNC: { - var idx = (int) op.operands()[0]; + var idx = (int) op.operand(0); if (idx == funcIdx // reference to self && !declaredFunctions.contains(idx)) { throw new InvalidException("undeclared function reference"); @@ -1086,7 +1085,7 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi case SELECT_T: { popVal(ValueType.I32); - var t = ValueType.forId((int) op.operands()[0]); + var t = ValueType.forId((int) op.operand(0)); popVal(t); popVal(t); pushVal(t); @@ -1094,8 +1093,8 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi } case TABLE_COPY: { - var table1 = getTableType((int) op.operands()[1]); - var table2 = getTableType((int) op.operands()[0]); + var table1 = getTableType((int) op.operand(1)); + var table2 = getTableType((int) op.operand(0)); if (table1 != table2) { throw new InvalidException( @@ -1112,8 +1111,8 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi } case TABLE_INIT: { - var table = getTableType((int) op.operands()[1]); - var elemIdx = (int) op.operands()[0]; + var table = getTableType((int) op.operand(1)); + var elemIdx = (int) op.operand(0); var elem = getElement(elemIdx); if (table != elem.type()) { @@ -1141,32 +1140,32 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi case TABLE_FILL: { popVal(ValueType.I32); - popVal(getTableType((int) op.operands()[0])); + popVal(getTableType((int) op.operand(0))); popVal(ValueType.I32); break; } case TABLE_GET: { popVal(ValueType.I32); - pushVal(getTableType((int) op.operands()[0])); + pushVal(getTableType((int) op.operand(0))); break; } case TABLE_SET: { - popVal(getTableType((int) op.operands()[0])); + popVal(getTableType((int) op.operand(0))); popVal(ValueType.I32); break; } case TABLE_GROW: { popVal(ValueType.I32); - popVal(getTableType((int) op.operands()[0])); + popVal(getTableType((int) op.operand(0))); pushVal(ValueType.I32); break; } case ELEM_DROP: { - var index = (int) op.operands()[0]; + var index = (int) op.operand(0); getElement(index); break; } diff --git a/wasm/src/main/java/com/dylibso/chicory/wasm/types/Instruction.java b/wasm/src/main/java/com/dylibso/chicory/wasm/types/Instruction.java index df4e57c98..d81c35791 100644 --- a/wasm/src/main/java/com/dylibso/chicory/wasm/types/Instruction.java +++ b/wasm/src/main/java/com/dylibso/chicory/wasm/types/Instruction.java @@ -3,6 +3,8 @@ import java.util.Arrays; public class Instruction { + public static final long[] EMPTY_OPERANDS = new long[0]; + private final int address; private final OpCode opcode; private final long[] operands; @@ -10,7 +12,7 @@ public class Instruction { public Instruction(int address, OpCode opcode, long[] operands) { this.address = address; this.opcode = opcode; - this.operands = operands; + this.operands = operands.length == 0 ? EMPTY_OPERANDS : operands.clone(); } public int address() { @@ -22,7 +24,15 @@ public OpCode opcode() { } public long[] operands() { - return operands; + return operands.clone(); + } + + public int operandCount() { + return operands.length; + } + + public long operand(int index) { + return operands[index]; } @Override diff --git a/wasm/src/test/java/com/dylibso/chicory/wasm/ParserTest.java b/wasm/src/test/java/com/dylibso/chicory/wasm/ParserTest.java index dc2fc31f0..9261c0234 100644 --- a/wasm/src/test/java/com/dylibso/chicory/wasm/ParserTest.java +++ b/wasm/src/test/java/com/dylibso/chicory/wasm/ParserTest.java @@ -85,9 +85,9 @@ public void shouldParseFile() throws IOException { assertTrue(instructions.get(0).toString().contains("0x00000032: I32_CONST [42]")); assertEquals(OpCode.I32_CONST, instructions.get(0).opcode()); - assertEquals(42L, instructions.get(0).operands()[0]); + assertEquals(42L, instructions.get(0).operand(0)); assertEquals(OpCode.CALL, instructions.get(1).opcode()); - assertEquals(0L, instructions.get(1).operands()[0]); + assertEquals(0L, instructions.get(1).operand(0)); assertEquals(OpCode.END, instructions.get(2).opcode()); } } @@ -170,9 +170,9 @@ public void shouldParseFloats() throws IOException { var module = Parser.parse(is); var codeSection = module.codeSection(); var fbody = codeSection.getFunctionBody(0); - var f32 = Float.intBitsToFloat((int) fbody.instructions().get(0).operands()[0]); + var f32 = Float.intBitsToFloat((int) fbody.instructions().get(0).operand(0)); assertEquals(0.12345678f, f32, 0.0); - var f64 = Double.longBitsToDouble(fbody.instructions().get(1).operands()[0]); + var f64 = Double.longBitsToDouble(fbody.instructions().get(1).operand(0)); assertEquals(0.123456789012345d, f64, 0.0); } } @@ -183,20 +183,20 @@ public void shouldProperlyParseSignedValue() throws IOException { var module = Parser.parse(is); var codeSection = module.codeSection(); var fbody = codeSection.getFunctionBody(0); - assertEquals(-2147483648L, fbody.instructions().get(0).operands()[0]); - assertEquals(0L, fbody.instructions().get(2).operands()[0]); - assertEquals(2147483647L, fbody.instructions().get(4).operands()[0]); - assertEquals(-9223372036854775808L, fbody.instructions().get(6).operands()[0]); - assertEquals(0L, fbody.instructions().get(8).operands()[0]); - assertEquals(9223372036854775807L, fbody.instructions().get(10).operands()[0]); - assertEquals(-2147483647L, fbody.instructions().get(12).operands()[0]); - assertEquals(2147483646L, fbody.instructions().get(14).operands()[0]); - assertEquals(-9223372036854775807L, fbody.instructions().get(16).operands()[0]); - assertEquals(9223372036854775806L, fbody.instructions().get(18).operands()[0]); - assertEquals(-1L, fbody.instructions().get(20).operands()[0]); - assertEquals(1L, fbody.instructions().get(22).operands()[0]); - assertEquals(-1L, fbody.instructions().get(24).operands()[0]); - assertEquals(1L, fbody.instructions().get(26).operands()[0]); + assertEquals(-2147483648L, fbody.instructions().get(0).operand(0)); + assertEquals(0L, fbody.instructions().get(2).operand(0)); + assertEquals(2147483647L, fbody.instructions().get(4).operand(0)); + assertEquals(-9223372036854775808L, fbody.instructions().get(6).operand(0)); + assertEquals(0L, fbody.instructions().get(8).operand(0)); + assertEquals(9223372036854775807L, fbody.instructions().get(10).operand(0)); + assertEquals(-2147483647L, fbody.instructions().get(12).operand(0)); + assertEquals(2147483646L, fbody.instructions().get(14).operand(0)); + assertEquals(-9223372036854775807L, fbody.instructions().get(16).operand(0)); + assertEquals(9223372036854775806L, fbody.instructions().get(18).operand(0)); + assertEquals(-1L, fbody.instructions().get(20).operand(0)); + assertEquals(1L, fbody.instructions().get(22).operand(0)); + assertEquals(-1L, fbody.instructions().get(24).operand(0)); + assertEquals(1L, fbody.instructions().get(26).operand(0)); } }