konsoletyper / teavm

Compiles Java bytecode to JavaScript, WebAssembly and C
https://teavm.org
Apache License 2.0
2.55k stars 260 forks source link

org.teavm.tooling.builder.BuildException: java.lang.AssertionError: Variable used before definition: @11 at $66 #910

Closed xupwup closed 1 month ago

xupwup commented 2 months ago

Hi,

I'm getting this error, but TeaVM doesn't tell me where the problem is. I've tried debugging, and it seems to point me to org/teavm/classlib/java/lang/TThrowable.java, in printStackTrace(PrintStream stream), on the for loop that iterates over the stack trace. But that class seems to be supplied by TeaVM, so that should work, right? I'm trying to generate wasm here by the way.

What am I doing wrong here? And is there a way to get a better error message from TeaVM to help me change my code to make things work?

My teavm configuration options are:

plugins {
    id "java"
    id "org.teavm" version "0.9.2"
}

teavm {
    wasm {
        maxHeapSize = 128 // might be enough
    }
    all {
        mainClass = "com.vanderlande.viking.render.webteavm.Meep"
        debugInformation = true
        //optimization = org.teavm.gradle.api.OptimizationLevel.NONE
        //outOfProcess = true
        //fastGlobalAnalysis = true
        processMemory = 1024
    }
}

The complete stack trace is:

Caused by: org.teavm.tooling.builder.BuildException: java.lang.AssertionError: Variable used before definition: @11 at $66
    at org.teavm.tooling.builder.InProcessBuildStrategy.build(InProcessBuildStrategy.java:268)
    at org.teavm.gradle.tasks.TeaVMTask.executeWithBuilder(TeaVMTask.java:163)
    at org.teavm.gradle.tasks.TeaVMTask.execute(TeaVMTask.java:119)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)
    ... 114 more
Caused by: java.lang.AssertionError: Variable used before definition: @11 at $66
    at org.teavm.model.util.PhiUpdater.use(PhiUpdater.java:617)
    at org.teavm.model.util.PhiUpdater$1.visit(PhiUpdater.java:661)
    at org.teavm.model.instructions.BinaryInstruction.acceptVisitor(BinaryInstruction.java:67)
    at org.teavm.model.util.PhiUpdater.renameVariables(PhiUpdater.java:353)
    at org.teavm.model.util.PhiUpdater.updatePhis(PhiUpdater.java:175)
    at org.teavm.model.util.PhiUpdater.updatePhis(PhiUpdater.java:121)
    at org.teavm.backend.lowlevel.transform.CoroutineTransformation.apply(CoroutineTransformation.java:129)
    at org.teavm.backend.wasm.WasmTarget.afterOptimizations(WasmTarget.java:456)
    at org.teavm.vm.TeaVM.optimizeMethodCacheMiss(TeaVM.java:755)
    at org.teavm.vm.TeaVM.optimizeMethod(TeaVM.java:721)
    at org.teavm.vm.TeaVM.optimize(TeaVM.java:703)
    at org.teavm.vm.TeaVM.eagerPipeline(TeaVM.java:489)
    at org.teavm.vm.TeaVM.build(TeaVM.java:407)
    at org.teavm.tooling.TeaVMTool.generate(TeaVMTool.java:456)
    at org.teavm.tooling.builder.InProcessBuildStrategy.build(InProcessBuildStrategy.java:265)
    ... 120 more
konsoletyper commented 2 months ago

It's a crash within TeaVM itself. Looks like you are trying to compile to WebAssembly target code with coroutines, which is known to be quite buggy. I'm not motivated to fix bugs in WebAssembly backend, so I suggest switching to JS backend instead.

xupwup commented 2 months ago

Ah, ok, I was planning on getting rid of my Thread use anyway. Nice to know that that's what's causing the problem.

Aside from that, out of curiosity, what's the reason you don't want to work on the wasm backend? I was under the impression that wasm was the future...

konsoletyper commented 2 months ago

@xupwup WebAssembly does not bring anything useful in this case. Performance is not significantly better, but everything other is: generated binary size, debugging, interop with JS, complexity of compiler internals. And there's no demand: people just satisfied with JS and I don't know of anyone who is going to use WebAssembly on production.

Anyway, you better start with JS backend and then, when everything ok, you can start digging in WebAssembly direction

xupwup commented 2 months ago

Thanks for the help so far. I'm now running into errors like below. I see classes like TMath where you replace some implementations. It looks like I have to replace your TMath by mine, and I seem to need to override something inside JOML too (to disable MemUtilUnsafe for example). Can you tell me how to do that?

Method java.lang.Math.fma(FFF)F was not found at org.joml.Math.fma(Math.java:445) at org.joml.Vector3f.normalize(Vector3f.java:1402)

Class java.lang.Module was not found at jdk.internal.reflect.Reflection.(Reflection.java:55) at sun.misc.Unsafe.(Unsafe.java:59) at sun.misc.Unsafe.arrayBaseOffset at org.joml.MemUtil$MemUtilUnsafe.(MemUtil.java:3841) at org.joml.MemUtil.createInstance(MemUtil.java:47) at org.joml.MemUtil.(MemUtil.java:38) at org.joml.Matrix4f.translation(Matrix4f.java:3049)

konsoletyper commented 2 months ago

You can write a TeaVM plugin that defines class transformer. In detail: include teavm-core artifact into your build, implement TeaVMPlugin and register it using ServiceLoader convention. Then, implement ClassHolderTransformer and add your implementation in TeaVMPlugin implementation to host (add method). In ClassHolderTransformer you can add method fma to class java.lang.Math. The best way to create a program is to take it from some other class (which you of course write). Also, you can use ProgramEmitter class. As for MemUtil, after brief observation I found that you can patch MemUtil.createInstance class and make it return MemUtilNIO instance.

Please, don't ask me for details. Just clone TeaVM sources and find examples of TeaVMPlugin, ClassHolderTransformer, ProgramEmitter, etc. This should be enough.

xupwup commented 2 months ago

Ok, I've managed to replace a lot of functions, but the only one I'm struggling with now is java.nio.channels.Channels.

ReadableByteChannel newChannel(InputStream in)

It's just saying Class java.nio.channels.Channels was not found. Is there a way to add that class?

konsoletyper commented 2 months ago

Sure. Notice how emulating classes are named in TeaVM repository. You can create you own class using same naming pattern in your own project and this should work just fine.

xupwup commented 1 month ago

I got everything working, thanks for the help and for making such an awesome library!