diff --git a/compiler/src/main/java/run/endive/compiler/internal/Compiler.java b/compiler/src/main/java/run/endive/compiler/internal/Compiler.java index 410c8a5e..90c6412a 100644 --- a/compiler/src/main/java/run/endive/compiler/internal/Compiler.java +++ b/compiler/src/main/java/run/endive/compiler/internal/Compiler.java @@ -44,11 +44,12 @@ import static run.endive.compiler.internal.ShadedRefs.AOT_INTERPRETER_MACHINE_CALL; import static run.endive.compiler.internal.ShadedRefs.CALL_HOST_FUNCTION; import static run.endive.compiler.internal.ShadedRefs.CALL_HOST_FUNCTION_WITH_REFS; -import static run.endive.compiler.internal.ShadedRefs.CALL_INDIRECT; +import static run.endive.compiler.internal.ShadedRefs.CALL_INDIRECT_CROSS_MODULE; import static run.endive.compiler.internal.ShadedRefs.CALL_INDIRECT_ON_INTERPRETER; import static run.endive.compiler.internal.ShadedRefs.CALL_INDIRECT_ON_INTERPRETER_WITH_REFS; -import static run.endive.compiler.internal.ShadedRefs.CALL_INDIRECT_WITH_REFS; +import static run.endive.compiler.internal.ShadedRefs.CALL_INDIRECT_WITH_REFS_CROSS_MODULE; import static run.endive.compiler.internal.ShadedRefs.CHECK_INTERRUPTION; +import static run.endive.compiler.internal.ShadedRefs.INSTANCE_GET_TYPE; import static run.endive.compiler.internal.ShadedRefs.INSTANCE_MEMORY; import static run.endive.compiler.internal.ShadedRefs.INSTANCE_TABLE; import static run.endive.compiler.internal.ShadedRefs.TABLE_INSTANCE; @@ -1756,11 +1757,13 @@ private void compileCallIndirect( emitBoxArgumentsWithRefs(asm, type.params()); // stack: long[], Object[] } + asm.load(instance, OBJECT_TYPE); asm.iconst(typeId); + emitInvokeVirtual(asm, INSTANCE_GET_TYPE); asm.load(funcId, INT_TYPE); asm.load(refInstance, OBJECT_TYPE); - emitInvokeStatic(asm, CALL_INDIRECT_WITH_REFS); + emitInvokeStatic(asm, CALL_INDIRECT_WITH_REFS_CROSS_MODULE); // returns CallResult emitUnboxCallResult(type, asm); } else { @@ -1769,11 +1772,13 @@ private void compileCallIndirect( } else { emitBoxArguments(asm, type.params()); } + asm.load(instance, OBJECT_TYPE); asm.iconst(typeId); + emitInvokeVirtual(asm, INSTANCE_GET_TYPE); asm.load(funcId, INT_TYPE); asm.load(refInstance, OBJECT_TYPE); - emitInvokeStatic(asm, CALL_INDIRECT); + emitInvokeStatic(asm, CALL_INDIRECT_CROSS_MODULE); emitUnboxResult(type, asm); } diff --git a/compiler/src/main/java/run/endive/compiler/internal/Shaded.java b/compiler/src/main/java/run/endive/compiler/internal/Shaded.java index 28ccdb8a..b2ea0d05 100644 --- a/compiler/src/main/java/run/endive/compiler/internal/Shaded.java +++ b/compiler/src/main/java/run/endive/compiler/internal/Shaded.java @@ -20,6 +20,7 @@ import run.endive.runtime.WasmStruct; import run.endive.wasm.InvalidException; import run.endive.wasm.WasmEngineException; +import run.endive.wasm.types.FunctionType; import run.endive.wasm.types.ValType; /** @@ -39,6 +40,15 @@ public static long[] callIndirect(long[] args, int typeId, int funcId, Instance return instance.getMachine().call(funcId, args); } + public static long[] callIndirect( + long[] args, FunctionType expectedType, int funcId, Instance instance) { + FunctionType actualType = instance.type(instance.functionType(funcId)); + if (!FunctionType.matches(actualType, expectedType, instance.module().typeSection())) { + throw throwIndirectCallTypeMismatch(); + } + return instance.getMachine().call(funcId, args); + } + public static long[] callIndirect(long[] args, int funcId, Instance instance) { return instance.getMachine().call(funcId, args); } @@ -59,6 +69,19 @@ public static CallResult callIndirectWithRefs( return instance.getMachine().callWithRefs(funcId, args, refArgs); } + public static CallResult callIndirectWithRefs( + long[] args, + Object[] refArgs, + FunctionType expectedType, + int funcId, + Instance instance) { + FunctionType actualType = instance.type(instance.functionType(funcId)); + if (!FunctionType.matches(actualType, expectedType, instance.module().typeSection())) { + throw throwIndirectCallTypeMismatch(); + } + return instance.getMachine().callWithRefs(funcId, args, refArgs); + } + public static long[] callHostFunction(Instance instance, int funcId, long[] args) { var imprt = instance.imports().function(funcId); return imprt.handle().apply(instance, args); diff --git a/compiler/src/main/java/run/endive/compiler/internal/ShadedRefs.java b/compiler/src/main/java/run/endive/compiler/internal/ShadedRefs.java index 1414771d..e38de72b 100644 --- a/compiler/src/main/java/run/endive/compiler/internal/ShadedRefs.java +++ b/compiler/src/main/java/run/endive/compiler/internal/ShadedRefs.java @@ -7,11 +7,13 @@ import run.endive.runtime.WasmException; import run.endive.runtime.internal.CompilerInterpreterMachine; import run.endive.wasm.types.Element; +import run.endive.wasm.types.FunctionType; public final class ShadedRefs { static final Method CHECK_INTERRUPTION; static final Method CALL_INDIRECT; + static final Method CALL_INDIRECT_CROSS_MODULE; static final Method CALL_INDIRECT_ON_INTERPRETER; static final Method CALL_INDIRECT_ON_INTERPRETER_WITH_REFS; static final Method INSTANCE_MEMORY; @@ -23,6 +25,7 @@ public final class ShadedRefs { static final Method WRITE_GLOBAL_REF; static final Method INSTANCE_SET_ELEMENT; static final Method INSTANCE_TABLE; + static final Method INSTANCE_GET_TYPE; static final Method MEMORY_COPY; static final Method MEMORY_COPY_2; static final Method MEMORY_FILL; @@ -155,6 +158,7 @@ public final class ShadedRefs { // WithRefs overloads for cross-module/host calls static final Method CALL_HOST_FUNCTION_WITH_REFS; static final Method CALL_INDIRECT_WITH_REFS; + static final Method CALL_INDIRECT_WITH_REFS_CROSS_MODULE; // GC static final Method STRUCT_NEW; @@ -209,6 +213,13 @@ public final class ShadedRefs { CALL_INDIRECT = Shaded.class.getMethod( "callIndirect", long[].class, int.class, int.class, Instance.class); + CALL_INDIRECT_CROSS_MODULE = + Shaded.class.getMethod( + "callIndirect", + long[].class, + FunctionType.class, + int.class, + Instance.class); CALL_INDIRECT_ON_INTERPRETER = Shaded.class.getMethod("callIndirect", long[].class, int.class, Instance.class); CALL_INDIRECT_ON_INTERPRETER_WITH_REFS = @@ -232,6 +243,7 @@ public final class ShadedRefs { "writeGlobalRef", Object.class, int.class, Instance.class); INSTANCE_SET_ELEMENT = Instance.class.getMethod("setElement", int.class, Element.class); INSTANCE_TABLE = Instance.class.getMethod("table", int.class); + INSTANCE_GET_TYPE = Instance.class.getMethod("type", int.class); MEMORY_COPY = Shaded.class.getMethod( "memoryCopy", int.class, int.class, int.class, Memory.class); @@ -834,6 +846,14 @@ public final class ShadedRefs { int.class, int.class, Instance.class); + CALL_INDIRECT_WITH_REFS_CROSS_MODULE = + Shaded.class.getMethod( + "callIndirectWithRefs", + long[].class, + Object[].class, + FunctionType.class, + int.class, + Instance.class); // GC STRUCT_NEW = diff --git a/compiler/src/test/resources/ApprovalTest.verifyLotsOfArgs.approved.template b/compiler/src/test/resources/ApprovalTest.verifyLotsOfArgs.approved.template index 8ead2d35..d8bfe6b5 100644 --- a/compiler/src/test/resources/ApprovalTest.verifyLotsOfArgs.approved.template +++ b/compiler/src/test/resources/ApprovalTest.verifyLotsOfArgs.approved.template @@ -109,10 +109,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime ILOAD 1 I2L LASTORE + ALOAD 5 ICONST_0 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 7 ALOAD 8 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J ICONST_0 LALOAD L2I @@ -154,10 +156,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime L1 ALOAD 0 ACONST_NULL + ALOAD 4 ICONST_1 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 6 ALOAD 7 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirectWithRefs ([J[Ljava/lang/Object;IILrun/endive/runtime/Instance;)Lrun/endive/runtime/CallResult; + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirectWithRefs ([J[Ljava/lang/Object;Lrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)Lrun/endive/runtime/CallResult; ICONST_0 INVOKEVIRTUAL run/endive/runtime/CallResult.longResult (I)J L2I diff --git a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.functions10.approved.txt b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.functions10.approved.txt index a78f8393..9e95b1db 100644 --- a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.functions10.approved.txt +++ b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.functions10.approved.txt @@ -133,10 +133,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime ILOAD 0 I2L LASTORE + ALOAD 4 ICONST_0 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 6 ALOAD 7 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J ICONST_0 LALOAD L2I diff --git a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyBrTable.approved.txt b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyBrTable.approved.txt index 8a60f83f..33a879b0 100644 --- a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyBrTable.approved.txt +++ b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyBrTable.approved.txt @@ -97,10 +97,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime ILOAD 0 I2L LASTORE + ALOAD 4 ICONST_0 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 6 ALOAD 7 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J ICONST_0 LALOAD L2I diff --git a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyBranching.approved.txt b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyBranching.approved.txt index 910a3b4e..00ea639d 100644 --- a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyBranching.approved.txt +++ b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyBranching.approved.txt @@ -97,10 +97,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime ILOAD 0 I2L LASTORE + ALOAD 4 ICONST_0 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 6 ALOAD 7 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J ICONST_0 LALOAD L2I diff --git a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyFloat.approved.txt b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyFloat.approved.txt index 64718e11..e306e044 100644 --- a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyFloat.approved.txt +++ b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyFloat.approved.txt @@ -91,10 +91,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime L1 ICONST_0 NEWARRAY T_LONG + ALOAD 3 ICONST_0 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 5 ALOAD 6 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J RETURN } diff --git a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyHelloWasi.approved.txt b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyHelloWasi.approved.txt index 4b091a72..5a0df60f 100644 --- a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyHelloWasi.approved.txt +++ b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyHelloWasi.approved.txt @@ -115,10 +115,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime ILOAD 3 I2L LASTORE + ALOAD 7 ICONST_0 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 9 ALOAD 10 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J ICONST_0 LALOAD L2I @@ -159,10 +161,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime L1 ICONST_0 NEWARRAY T_LONG + ALOAD 3 ICONST_1 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 5 ALOAD 6 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J RETURN } diff --git a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyI32.approved.txt b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyI32.approved.txt index 0f211fe1..758e858b 100644 --- a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyI32.approved.txt +++ b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyI32.approved.txt @@ -91,10 +91,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime L1 ICONST_0 NEWARRAY T_LONG + ALOAD 3 ICONST_0 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 5 ALOAD 6 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J RETURN } diff --git a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyI32Renamed.approved.txt b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyI32Renamed.approved.txt index eba6a117..180dc201 100644 --- a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyI32Renamed.approved.txt +++ b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyI32Renamed.approved.txt @@ -91,9 +91,11 @@ public final class FOO implements run/endive/runtime/Machine { L1 ICONST_0 NEWARRAY T_LONG + ALOAD 3 ICONST_0 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 5 ALOAD 6 - INVOKESTATIC FOOShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC FOOShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J RETURN } diff --git a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyIterFact.approved.txt b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyIterFact.approved.txt index bf73b5b6..2e2cedcf 100644 --- a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyIterFact.approved.txt +++ b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyIterFact.approved.txt @@ -97,10 +97,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime ILOAD 0 I2L LASTORE + ALOAD 4 ICONST_0 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 6 ALOAD 7 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J ICONST_0 LALOAD L2I diff --git a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyKitchenSink.approved.txt b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyKitchenSink.approved.txt index 1a5e8be4..ba4c280f 100644 --- a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyKitchenSink.approved.txt +++ b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyKitchenSink.approved.txt @@ -97,10 +97,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime ILOAD 0 I2L LASTORE + ALOAD 4 ICONST_0 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 6 ALOAD 7 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J ICONST_0 LALOAD L2I diff --git a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyMemory.approved.txt b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyMemory.approved.txt index 86328367..85d985c9 100644 --- a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyMemory.approved.txt +++ b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyMemory.approved.txt @@ -97,10 +97,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime ILOAD 0 I2L LASTORE + ALOAD 4 ICONST_0 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 6 ALOAD 7 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J ICONST_0 LALOAD L2I @@ -146,10 +148,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime ICONST_0 LLOAD 0 LASTORE + ALOAD 5 ICONST_1 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 7 ALOAD 8 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J ICONST_0 LALOAD LRETURN diff --git a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyStart.approved.txt b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyStart.approved.txt index 4c55ce05..27059438 100644 --- a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyStart.approved.txt +++ b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyStart.approved.txt @@ -97,10 +97,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime ILOAD 0 I2L LASTORE + ALOAD 4 ICONST_0 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 6 ALOAD 7 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J RETURN public static call_indirect_1(IILrun/endive/runtime/Memory;Lrun/endive/runtime/Instance;)V @@ -138,10 +140,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime L1 ICONST_0 NEWARRAY T_LONG + ALOAD 3 ICONST_1 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 5 ALOAD 6 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J RETURN } diff --git a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyTailCall.approved.txt b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyTailCall.approved.txt index 3df14c84..ffdb4cca 100644 --- a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyTailCall.approved.txt +++ b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyTailCall.approved.txt @@ -149,10 +149,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime ILOAD 2 I2L LASTORE + ALOAD 6 ICONST_0 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 8 ALOAD 9 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J ICONST_0 LALOAD L2I diff --git a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyTrap.approved.txt b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyTrap.approved.txt index f1f29d3d..1ce418ad 100644 --- a/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyTrap.approved.txt +++ b/compiler/src/test/resources/run/endive/approvals/ApprovalTest.verifyTrap.approved.txt @@ -99,10 +99,12 @@ public final class run/endive/$gen/CompiledMachine implements run/endive/runtime L1 ICONST_0 NEWARRAY T_LONG + ALOAD 3 ICONST_0 + INVOKEVIRTUAL run/endive/runtime/Instance.type (I)Lrun/endive/wasm/types/FunctionType; ILOAD 5 ALOAD 6 - INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JIILrun/endive/runtime/Instance;)[J + INVOKESTATIC run/endive/$gen/CompiledMachineShaded.callIndirect ([JLrun/endive/wasm/types/FunctionType;ILrun/endive/runtime/Instance;)[J RETURN } diff --git a/machine-tests/src/test/java/run/endive/testing/MachinesTest.java b/machine-tests/src/test/java/run/endive/testing/MachinesTest.java index 62cb5042..ac27a2e1 100644 --- a/machine-tests/src/test/java/run/endive/testing/MachinesTest.java +++ b/machine-tests/src/test/java/run/endive/testing/MachinesTest.java @@ -18,7 +18,12 @@ import java.nio.file.StandardCopyOption; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import run.endive.compiler.MachineFactoryCompiler; import run.endive.corpus.CorpusResources; import run.endive.runtime.HostFunction; @@ -26,6 +31,7 @@ import run.endive.runtime.ImportValues; import run.endive.runtime.Instance; import run.endive.runtime.InterpreterMachine; +import run.endive.runtime.Machine; import run.endive.runtime.Store; import run.endive.runtime.TableInstance; import run.endive.runtime.TrapException; @@ -339,6 +345,51 @@ public void shouldCallIndirectAotToInterpreter() { assertTrue(className.contains("InterpreterMachine"), className); } + private static Stream crossModuleMachineFactories() { + return Stream.of( + Arguments.of( + "interp-interp", + (Function) InterpreterMachine::new, + (Function) InterpreterMachine::new), + Arguments.of( + "interp-aot", + (Function) InterpreterMachine::new, + (Function) MachineFactoryCompiler::compile), + Arguments.of( + "aot-interp", + (Function) MachineFactoryCompiler::compile, + (Function) InterpreterMachine::new), + Arguments.of( + "aot-aot", + (Function) MachineFactoryCompiler::compile, + (Function) MachineFactoryCompiler::compile)); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("crossModuleMachineFactories") + public void shouldCallIndirectCrossModuleTypeIndex( + String name, + Function callerFactory, + Function calleeFactory) { + var store = new Store(); + + var instance = + Instance.builder( + loadModule( + "compiled/call_indirect_cross_module_types-export.wat.wasm")) + .withImportValues(store.toImportValues()) + .withMachineFactory(callerFactory) + .build(); + store.register("test", instance); + + Instance.builder(loadModule("compiled/call_indirect_cross_module_types-import.wat.wasm")) + .withImportValues(store.toImportValues()) + .withMachineFactory(calleeFactory) + .build(); + + assertEquals(42, instance.export("call-other").apply()[0]); + } + @Test public void tailcallReturnCallAot() { var instance = diff --git a/runtime/src/main/java/run/endive/runtime/InterpreterMachine.java b/runtime/src/main/java/run/endive/runtime/InterpreterMachine.java index 5581dcb5..616e210a 100644 --- a/runtime/src/main/java/run/endive/runtime/InterpreterMachine.java +++ b/runtime/src/main/java/run/endive/runtime/InterpreterMachine.java @@ -2924,14 +2924,19 @@ private static StackFrame RETURN_CALL_INDIRECT( int funcId = table.requiredRef(funcTableIdx); var refInstance = requireNonNullElse(table.instance(funcTableIdx), instance); - var type = refInstance.type(typeId); + var type = instance.type(typeId); - // Verify type match using nominal type indices - var actualTypeIdx = refInstance.functionType(funcId); - verifyIndirectCallByTypeIdx(actualTypeIdx, typeId, refInstance.module().typeSection()); + boolean sameInstance = refInstance == instance; + if (sameInstance) { + var actualTypeIdx = instance.functionType(funcId); + verifyIndirectCallByTypeIdx(actualTypeIdx, typeId, instance.module().typeSection()); + } else { + var actualType = refInstance.type(refInstance.functionType(funcId)); + verifyIndirectCall(actualType, type, instance.module().typeSection()); + } var refMachine = refInstance.getMachine().getClass(); - if (!refInstance.equals(instance) && !refMachine.equals(instance.getMachine().getClass())) { + if (!sameInstance && !refMachine.equals(instance.getMachine().getClass())) { throw new WasmEngineException( "Indirect tail-call to a different Machine implementation is not supported: " + refMachine.getName()); @@ -3055,11 +3060,15 @@ private void CALL_INDIRECT( int funcId = table.requiredRef(funcTableIdx); var refInstance = requireNonNullElse(table.instance(funcTableIdx), instance); - var type = refInstance.type(typeId); + var type = instance.type(typeId); - // Verify type match using nominal type indices - var actualTypeIdx = refInstance.functionType(funcId); - verifyIndirectCallByTypeIdx(actualTypeIdx, typeId, refInstance.module().typeSection()); + if (refInstance == instance) { + var actualTypeIdx = instance.functionType(funcId); + verifyIndirectCallByTypeIdx(actualTypeIdx, typeId, instance.module().typeSection()); + } else { + var actualType = refInstance.type(refInstance.functionType(funcId)); + verifyIndirectCall(actualType, type, instance.module().typeSection()); + } // given a list of param types, let's pop those params off the stack // and pass as args to the function call @@ -3375,32 +3384,7 @@ protected static Object[] extractArgsAndRefsForParams( private static boolean functionTypeMatch( FunctionType actual, FunctionType expected, TypeSection ts) { - if (actual.params().size() != expected.params().size() - || actual.returns().size() != expected.returns().size()) { - return false; - } - - for (int i = 0; i < actual.params().size(); i++) { - var actualParam = actual.params().get(i); - var expectedParam = expected.params().get(i); - - // Contravariant: expected.param <: actual.param - if (!ValType.matches(expectedParam, actualParam, ts)) { - return false; - } - } - - for (int i = 0; i < actual.returns().size(); i++) { - var actualReturn = actual.returns().get(i); - var expectedReturn = expected.returns().get(i); - - // Covariant: actual.return <: expected.return - if (!ValType.matches(actualReturn, expectedReturn, ts)) { - return false; - } - } - - return true; + return FunctionType.matches(actual, expected, ts); } protected static void verifyIndirectCall( diff --git a/wasm-corpus/src/main/resources/compiled/call_indirect_cross_module_types-export.wat.wasm b/wasm-corpus/src/main/resources/compiled/call_indirect_cross_module_types-export.wat.wasm new file mode 100644 index 00000000..76869d8c Binary files /dev/null and b/wasm-corpus/src/main/resources/compiled/call_indirect_cross_module_types-export.wat.wasm differ diff --git a/wasm-corpus/src/main/resources/compiled/call_indirect_cross_module_types-import.wat.wasm b/wasm-corpus/src/main/resources/compiled/call_indirect_cross_module_types-import.wat.wasm new file mode 100644 index 00000000..38d5b6c2 Binary files /dev/null and b/wasm-corpus/src/main/resources/compiled/call_indirect_cross_module_types-import.wat.wasm differ diff --git a/wasm-corpus/src/main/resources/wat/call_indirect_cross_module_types-export.wat b/wasm-corpus/src/main/resources/wat/call_indirect_cross_module_types-export.wat new file mode 100644 index 00000000..1d53718c --- /dev/null +++ b/wasm-corpus/src/main/resources/wat/call_indirect_cross_module_types-export.wat @@ -0,0 +1,11 @@ +(module + (type $pad0 (func (param i32 i32) (result i32))) + (type $pad1 (func (param i64) (result i64))) + (type $target (func (result i32))) + + (table (export "shared-table") 10 funcref) + + (func (export "call-other") (result i32) + i32.const 0 + call_indirect (type $target)) +) diff --git a/wasm-corpus/src/main/resources/wat/call_indirect_cross_module_types-import.wat b/wasm-corpus/src/main/resources/wat/call_indirect_cross_module_types-import.wat new file mode 100644 index 00000000..5c87facc --- /dev/null +++ b/wasm-corpus/src/main/resources/wat/call_indirect_cross_module_types-import.wat @@ -0,0 +1,8 @@ +(module + (import "test" "shared-table" (table 10 funcref)) + + (func $provider (result i32) + i32.const 42) + + (elem (i32.const 0) func $provider) +) diff --git a/wasm/src/main/java/run/endive/wasm/types/FunctionType.java b/wasm/src/main/java/run/endive/wasm/types/FunctionType.java index d1192f9c..27b0ffc9 100644 --- a/wasm/src/main/java/run/endive/wasm/types/FunctionType.java +++ b/wasm/src/main/java/run/endive/wasm/types/FunctionType.java @@ -93,6 +93,24 @@ public boolean typesMatch(FunctionType other) { return paramsMatch(other) && returnsMatch(other); } + public static boolean matches(FunctionType actual, FunctionType expected, TypeSection ts) { + if (actual.params.size() != expected.params.size() + || actual.returns.size() != expected.returns.size()) { + return false; + } + for (int i = 0; i < actual.params.size(); i++) { + if (!ValType.matches(expected.params.get(i), actual.params.get(i), ts)) { + return false; + } + } + for (int i = 0; i < actual.returns.size(); i++) { + if (!ValType.matches(actual.returns.get(i), expected.returns.get(i), ts)) { + return false; + } + } + return true; + } + public static FunctionType of(List params, List returns) { if (params.isEmpty()) { if (returns.isEmpty()) {