Description
We are having a strange problem when using static compile transformation.
Most likely what we are doing is not the best approach. However, this was working in 3.0.9 and stopped working with 3.0.10.
If we take this main class:
package org.example; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.script.Bindings; import javax.script.ScriptEngine; import javax.script.ScriptException; import javax.script.SimpleBindings; import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.control.CompilerConfiguration; import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer; import org.codehaus.groovy.jsr223.GroovyScriptEngineImpl; import groovy.lang.GroovyClassLoader; import groovy.transform.CompileStatic; public class GroovyProblemExample { public static final String VAR_TYPES = "variable.types"; public static final ThreadLocal<Map<String, Object>> COMPILE_OPTIONS = new ThreadLocal<>(); public static void main(String[] args) throws ScriptException { ScriptEngine scriptEngine = new GroovyScriptEngineImpl(createClassLoader()); String script = "" + "int sum = 0\n" + "for ( i in inputArray ) {\n" + " sum += i\n" + "}\n" + "execution.setVariable(\"sum\", sum)"; Map<String, Object> input = new HashMap<>(); TestExecution execution = new TestExecution(); int[] inputArray = new int[] { 1, 2, 3, 4, 5 }; input.put("inputArray", inputArray); input.put("execution", execution); Bindings bindings = createBindings(input); COMPILE_OPTIONS.remove(); Map<String, ClassNode> variableTypes = new HashMap<>(); for (Map.Entry<String, Object> entry : bindings.entrySet()) { variableTypes.put(entry.getKey(), ClassHelper.make(entry.getValue().getClass())); } variableTypes.put("execution", ClassHelper.make(TestExecution.class)); Map<String, Object> options = new HashMap<>(); options.put(VAR_TYPES, variableTypes); COMPILE_OPTIONS.set(options); scriptEngine.eval(script, bindings); System.out.println(execution.getVariable("sum")); } public static Bindings createBindings(Map<String, Object> parameters) { return new SimpleBindings(parameters); } public static GroovyClassLoader createClassLoader() { return new GroovyClassLoader(GroovyProblemExample.class.getClassLoader(), createStaticConfiguration(), true); } protected static CompilerConfiguration createStaticConfiguration() { CompilerConfiguration compilerConfiguration = new CompilerConfiguration(); ASTTransformationCustomizer astTransformationCustomizer = new ASTTransformationCustomizer( Collections.singletonMap("extensions", Collections.singletonList("ExampleExtension.groovy")), CompileStatic.class, "org.codehaus.groovy.transform.sc.StaticCompileTransformation"); compilerConfiguration.addCompilationCustomizers(astTransformationCustomizer); return compilerConfiguration; } public static class TestExecution { protected final Map<String, Object> data = new HashMap<>(); public void setVariable(String name, Object value) { data.put(name, value); } public Object getVariable(String name) { return data.get(name); } } }
and this extension:
import static org.example.GroovyProblemExample.COMPILE_OPTIONS import static org.example.GroovyProblemExample.VAR_TYPES def typesOfVariables = COMPILE_OPTIONS.get()[VAR_TYPES] unresolvedVariable { var -> if (typesOfVariables[var.name]) { return makeDynamic(var, typesOfVariables[var.name]) } }
Running the main class with Groovy 3.0.9 we have 15 printed out in the console. However, running it with 3.0.10 we get the following error:
Exception in thread "main" java.lang.VerifyError: Bad type on operand stack in aaload Exception Details: Location: Script1.run()Ljava/lang/Object; @54: aaload Reason: Type '[I' (current frame, stack[0]) is not assignable to reference type Current Frame: bci: @54 flags: { } locals: { 'Script1', '[Lorg/codehaus/groovy/runtime/callsite/CallSite;', integer, top, '[I', integer, integer } stack: { '[I', integer } Bytecode: 0000000: 00b8 0024 4c03 3d1c 5701 4e2b 1225 322a 0000010: b900 2b02 0059 122d b800 33c0 002d 3a04 0000020: c600 2719 04be 3605 0336 0615 0615 05a2 0000030: 0018 1904 1506 324e 8406 011c 2db8 0039 0000040: 6059 3d57 a7ff e72b 123a 322a b900 2b02 0000050: 00c0 003c 123e 1cb8 0044 b600 4801 b0 Stackmap Table: full_frame(@43,{Object[#2],Object[#77],Integer,Top,Object[#45],Integer,Integer},{}) chop_frame(@71,2) at java.base/java.lang.Class.getDeclaredConstructors0(Native Method) at java.base/java.lang.Class.privateGetDeclaredConstructors(Class.java:3373) at java.base/java.lang.Class.getConstructor0(Class.java:3578) at java.base/java.lang.Class.getConstructor(Class.java:2271) at org.codehaus.groovy.runtime.InvokerHelper.newScript(InvokerHelper.java:502) at org.codehaus.groovy.runtime.InvokerHelper.createScript(InvokerHelper.java:461) at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:266) at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:155) at java.scripting/javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:231) at org.example.GroovyProblemExample.main(GroovyProblemExample.java:55)
This happens with Java 17 and Java 11.
This is a simplified example that is taken from something that we have in the Flowable Engine (https://github.com/flowable/flowable-engine/tree/main/modules/flowable-groovy-script-static-engine).