diff --git a/compiler-tests/src/test/java/run/endive/testing/MethodTooLargeTest.java b/compiler-tests/src/test/java/run/endive/testing/MethodTooLargeTest.java index 267e3b048..0485b6fe6 100644 --- a/compiler-tests/src/test/java/run/endive/testing/MethodTooLargeTest.java +++ b/compiler-tests/src/test/java/run/endive/testing/MethodTooLargeTest.java @@ -1,6 +1,7 @@ package run.endive.testing; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.objectweb.asm.Type.getInternalName; import static run.endive.corpus.WatGenerator.methodTooLarge; @@ -14,6 +15,7 @@ import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.util.TraceClassVisitor; +import run.endive.compiler.InterpreterFallback; import run.endive.compiler.internal.Compiler; import run.endive.compiler.internal.Shaded; import run.endive.wabt.Wat2Wasm; @@ -33,6 +35,29 @@ public void testBigFunc() { verifyClass(result.classBytes(), true); } + @Test + public void testFuncWithFarJumpsAndManyLocals() { + var wat = new StringBuilder("(module (func (param i32) (local"); + wat.append(" i32".repeat(1500)).append(") (block (br_if 0 (local.get 0))"); + for (int i = 1; i <= 3000; i++) { + int local = (i % 1500) + 1; + wat.append( + String.format( + " (local.set %d (i32.add (local.get %d) (i32.const %d)))", + local, local, i)); + } + wat.append(")))"); + var module = Parser.parse(Wat2Wasm.parse(wat.toString())); + + var result = + Compiler.builder(module) + .withInterpreterFallback(InterpreterFallback.FAIL) + .build() + .compile(); + + assertTrue(result.interpretedFunctions().isEmpty()); + } + private static void verifyClass(Map classBytes, boolean skipMethodsClss) { var writer = new StringWriter(); 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 0d874286d..76efdd9c4 100644 --- a/compiler/src/main/java/run/endive/compiler/internal/Compiler.java +++ b/compiler/src/main/java/run/endive/compiler/internal/Compiler.java @@ -36,6 +36,7 @@ import static run.endive.compiler.internal.CompilerUtil.localType; import static run.endive.compiler.internal.CompilerUtil.methodNameForFunc; import static run.endive.compiler.internal.CompilerUtil.methodTypeFor; +import static run.endive.compiler.internal.CompilerUtil.newClassWriter; import static run.endive.compiler.internal.CompilerUtil.rawMethodTypeFor; import static run.endive.compiler.internal.CompilerUtil.slotCount; import static run.endive.compiler.internal.CompilerUtil.valueMethodName; @@ -574,7 +575,7 @@ private Consumer emitFunctionGroup(int start, int end, String inte private byte[] compileClass() { var internalClassName = internalClassName(className); - ClassWriter binaryWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + ClassWriter binaryWriter = newClassWriter(); ClassVisitor classWriter = shadedClassRemapper(binaryWriter, className); classWriter.visit( @@ -1077,7 +1078,7 @@ private void compileMachineCallWithTailCalls( } private void compileMachineCallClass() { - ClassWriter binaryWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + ClassWriter binaryWriter = newClassWriter(); ClassVisitor classWriter = shadedClassRemapper(binaryWriter, className); String machineCallClassName = internalClassName(className + "MachineCall"); @@ -1169,7 +1170,7 @@ private void compileMachineCallClass() { private void compileExtraClass( ClassCollector collector, String name, Consumer consumer) { - ClassWriter binaryWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + ClassWriter binaryWriter = newClassWriter(); ClassVisitor classWriter = shadedClassRemapper(binaryWriter, className); String internalClassName = internalClassName(name); classWriter.visit( diff --git a/compiler/src/main/java/run/endive/compiler/internal/CompilerUtil.java b/compiler/src/main/java/run/endive/compiler/internal/CompilerUtil.java index baae22163..a8fc12792 100644 --- a/compiler/src/main/java/run/endive/compiler/internal/CompilerUtil.java +++ b/compiler/src/main/java/run/endive/compiler/internal/CompilerUtil.java @@ -15,6 +15,7 @@ import java.lang.reflect.Modifier; import java.util.List; import java.util.Locale; +import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; @@ -55,6 +56,30 @@ private CompilerUtil() {} } } + // ClassWriter.setComputeLimits exists since ASM 9.11 + private static final boolean HAS_COMPUTE_LIMITS = hasComputeLimits(); + + private static boolean hasComputeLimits() { + try { + ClassWriter.class.getMethod("setComputeLimits", int.class, long.class); + return true; + } catch (NoSuchMethodException e) { + return false; + } + } + + /** + * Returns a {@link ClassWriter} computing stack map frames, with no limit on the work ASM does + * to compute them. + */ + public static ClassWriter newClassWriter() { + var writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + if (HAS_COMPUTE_LIMITS) { + writer.setComputeLimits(Integer.MAX_VALUE, Long.MAX_VALUE); + } + return writer; + } + public static Class jvmType(ValType type) { switch (type.opcode()) { case ValType.ID.I32: diff --git a/compiler/src/main/java/run/endive/compiler/internal/Shader.java b/compiler/src/main/java/run/endive/compiler/internal/Shader.java index 7bdede4d1..ca22d6896 100644 --- a/compiler/src/main/java/run/endive/compiler/internal/Shader.java +++ b/compiler/src/main/java/run/endive/compiler/internal/Shader.java @@ -2,6 +2,7 @@ import static org.objectweb.asm.Type.getInternalName; import static run.endive.compiler.internal.CompilerUtil.internalClassName; +import static run.endive.compiler.internal.CompilerUtil.newClassWriter; import java.io.IOException; import org.objectweb.asm.ClassReader; @@ -21,7 +22,7 @@ private Shader() {} public static void createShadedClass(String className, ClassCollector collector) { String shadedClassName = internalClassName(className + "Shaded"); - ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + ClassWriter writer = newClassWriter(); ClassVisitor visitor = shadedClassRemapper(writer, className); visitor = diff --git a/pom.xml b/pom.xml index d18c08afa..97cee160b 100644 --- a/pom.xml +++ b/pom.xml @@ -53,7 +53,7 @@ true 31.0.0 - 9.10.1 + 9.11.1