dylibso / chicory

Native JVM WebAssembly runtime
Apache License 2.0
497 stars 37 forks source link

AOT Engine Error: Class too large #453

Open heroicefforts opened 3 months ago

heroicefforts commented 3 months ago

Very cool project.

I just wanted to report this edge case. I wrapped a .NET module from my employer and compiled using the .NET 9.0 Preview AOT LLVM compiler. It spits out a huge wasm file. It runs cleanly on the Chicory interpreter; albeit, slowly at 12 seconds for an invocation. I decided to give the nightly AOT compiler a shot, but it fails with the following error:

01:09:01.437 [main] ERROR Chicory - Const pool: 198793 org.objectweb.asm.ClassTooLargeException: Class too large: com/dylibso/chicory/$gen/CompiledModule at org.objectweb.asm.ClassWriter.toByteArray(ClassWriter.java:622)

It appears that at 198793, the constant pool size is a smidge more than 3x the 65534 max size. Are there any plans to detect this condition and split the generated class?

Just as reference, the module will run cleanly on Wasmer's Python Cranelift compiler runtime and executes at 100ms for an invocation. However, that doesn't help support a Java based embedding.

bhelx commented 3 months ago

Thanks for reporting!

Might be related: https://github.com/dylibso/chicory/issues/405

There is work being done to split methods that are too large. In the meantime could you try: -XX:-DontCompileHugeMethods

That seemed to work for me when the compiled method was on the edge of being too big.

bhelx commented 3 months ago

You could also try some running wasm-opt and other post processing optimizers on the resulting module. Some things may not be runnable until we can split methods though.

heroicefforts commented 3 months ago

I think it's in the same category as #405. I interpreted the error as ASM saying, "I can't generate your class bytecode because it is invalid." It seems to me that this step would come before the decision to natively compile the methods (e.g. rendering the DontCompileHugeMethods JVM arg irrelevant), is that correct or am I misunderstanding?

I've tried wasm-opt, but the output wasms from various optimization levels are always unstable / crashy.

bhelx commented 3 months ago

Yes, definitely a different error and earlier in the process. I'm unsure if the method splitting work would address this const pool issue. @electrum is working on this and he would know.

electrum commented 3 months ago

The -XX:-DontCompileHugeMethods flag is to allow the JVM JIT to work for large methods. The error here is that the WASM method is to large to convert to a single JVM method. So these aren't really related (other than that method splitting might prevent the need for that JVM flag).

electrum commented 3 months ago

If you could provide a reproduction, possibly based on #450, that would be helpful to ensure that the method splitting will work for this. What does your original method look like?

electrum commented 3 months ago

The constant pool issue might require splitting the methods across multiple classes, as you suggest. It's hard to say what might be required without seeing an example of the WASM input. I'm not sure if there is a good generic solution to this problem, as it is easy to construct pathological cases given the much larger WASM limits compared to JVM bytecode.

heroicefforts commented 3 months ago

I can't supply the specific WASM, but I'll try to take a closer look at the class file that is attempting to be generated and try to get a grasp of what is going on there.

electrum commented 3 months ago

Seeing what is in the constant pool would be helpful.

electrum commented 2 months ago

@heroicefforts Could you send us a dump of the constant pool? You could obfuscate it if necessary.