[ https://issues.apache.org/jira/browse/GROOVY-7526?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14647334#comment-14647334 ]
Jochen Theodorou commented on GROOVY-7526: ------------------------------------------ The reduced bytecode of this is the following (using asm){code} // access flags 0x1 public foo()Ljava/lang/Object; L0 INVOKESTATIC JavaTool.getData ()LJavaTool$Data; ASTORE 1 L2 ALOAD 1 DUP IFNONNULL L3 GOTO L4 L3 FRAME FULL [test JavaTool$Data] [JavaTool$Data] GETFIELD JavaTool$Data.fieldData : Ljava/lang/String; L4 FRAME SAME1 java/lang/Object INVOKEDYNAMIC cast(Ljava/lang/String;)Z [...] IFEQ L5 L6 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; LDC "HAS GROOVY TOOL DATA" INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V ACONST_NULL ARETURN {code} The actual error is then to be found in the invokedynamic call for cast. The call expects a String on the stack, but the frame claims the stack element is of type Object. The @CompileStatic version does not have this problem since it will call booleanUnbox(Object)Z, then there is no type mismatch. But simulating this method call, will provoke the same error:{code:Java} public class JavaTool { public static Data getData() { return new Data("fieldDataString") } public static class Data { public String fieldData; public Data(String fieldData) { this.fieldData = fieldData } } } boolean bar(String s){true} @CompileStatic def foo() { JavaTool.Data jdata = JavaTool.getData() if ( bar(jdata?.fieldData) ) { System.out.println("HAS GROOVY TOOL DATA") } } foo(){code] now the method bar will make the boolean conversion and expect a String. Without frame information this will then lead to "java.lang.VerifyError: (class: test, method: foo signature: ()Ljava/lang/Object;) Incompatible argument to function" and forcing higher bytecodes, by for example using groovy.target.bytecode=1.7, will produce "java.lang.VerifyError: Bad type on operand stack". Since this is without indy I can identify this as a static compilation problem. > Safe navigation broken on java fields with indy and @CompileStatic > ------------------------------------------------------------------ > > Key: GROOVY-7526 > URL: https://issues.apache.org/jira/browse/GROOVY-7526 > Project: Groovy > Issue Type: Bug > Components: Compiler > Affects Versions: 2.4.3 > Reporter: Matthew Turnbull > Priority: Minor > Attachments: groovy_test.tar.gz > > > Trying to directly access a native Java object field, from a Groovy class > compiled with invokedynamic and @CompileStatic, causes a > "java.lang.VerifyError: Bad type on operand stack" error. > I have reproduced this on Linux with Groovy 2.4.3/2.4.4 and Java 1.7.0_80 > (64bit). > {noformat} > ~ $ cd /tmp/groovy_test/ > /tmp/groovy_test $ rm -f com/*.class > /tmp/groovy_test $ javac com/*.java > /tmp/groovy_test $ /opt/groovy-2.4.4/bin/groovyc --indy --configscript > config.groovyc com/*.groovy > /tmp/groovy_test $ java -cp .:/opt/groovy-2.4.4/lib/groovy-2.4.4.jar com.Test > {noformat} > {noformat} > Exception in thread "main" java.lang.VerifyError: Bad type on operand stack > Exception Details: > Location: > com/Controller.run()V @55: invokedynamic > Reason: > Type 'java/lang/Object' (current frame, stack[0]) is not assignable to > 'java/lang/String' > Current Frame: > bci: @55 > flags: { } > locals: { 'com/Controller', 'com/GroovyTool$Data', 'com/GroovyTool$Data', > 'com/JavaTool$Data' } > stack: { 'java/lang/Object' } > Bytecode: > 0000000: b800 224c 2b57 2b59 4dc6 000a 2cb6 0028 > 0000010: a700 0401 ba00 3600 0099 000d b200 3c12 > 0000020: 3eb6 0044 0157 b800 494e 2d57 2d59 c700 > 0000030: 06a7 0006 b400 4fba 0036 0000 9900 0db2 > 0000040: 003c 1251 b600 4401 57b1 > Stackmap Table: > append_frame(@19,Object[#36],Object[#36]) > same_locals_1_stack_item_frame(@20,Object[#87]) > same_frame(@38) > > full_frame(@52,{Object[#2],Object[#36],Object[#36],Object[#75]},{Object[#75]}) > same_locals_1_stack_item_frame(@55,Object[#4]) > same_frame(@73) > at java.lang.Class.getDeclaredConstructors0(Native Method) > at java.lang.Class.privateGetDeclaredConstructors(Class.java:2595) > at java.lang.Class.getConstructor0(Class.java:2895) > at java.lang.Class.newInstance(Class.java:354) > at com.Test.loadController(Test.java:20) > at com.Test.test(Test.java:30) > at com.Test.main(Test.java:10) > {noformat} > Work arounds that I found: > * Remove @CompileStatic > * Disable --indy > * Cast the safely navigated field to it's object type i.e. (String)data?.field > * Define a getter method to use in lieu of the field. -- This message was sent by Atlassian JIRA (v6.3.4#6332)