[
https://issues.apache.org/jira/browse/GROOVY-9892?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17264338#comment-17264338
]
Frédéric Chuong commented on GROOVY-9892:
-----------------------------------------
Adding a
[{{POP}}|https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.pop]
instruction seems to do the trick (at least for {{int}} values):
{noformat}
diff --git
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
index
4f5c4e071ad94d65a70ec1fa2b5493701d99f7dc..06d5e9d9b8a0cb29486397cf3a024179b817388d
100644
---
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
+++
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
@@ -814,6 +814,10 @@ public class StaticTypesCallSiteWriter extends
CallSiteWriter implements Opcodes
call.setMethodTarget(methodNode);
call.visit(controller.getAcg());
+ // GROOVY-9892: assuming that the mutator method
has a return value, make sure the operand
+ // stack is not polluted with the result of the
method call
+ controller.getOperandStack().pop();
+
controller.getCompileStack().removeVar(i);
return;
}
{noformat}
{noformat}
ICONST_1
IADD
DUP
ISTORE 1
ALOAD 0
INVOKEVIRTUAL groovy/lang/Closure.getThisObject ()Ljava/lang/Object;
CHECKCAST OuterClass
ILOAD 1
INVOKESTATIC OuterClass.pfaccess$00 (LOuterClass;I)I
POP <<<< discard the result of the pfaccess mutator method
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
{noformat}
Beginner's question: if this is correct, as the [generated
mutator|https://github.com/apache/groovy/blob/GROOVY_3_0_7/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java#L286]
returns the value being set, could this be optimized by getting rid of the
{{DUP}} instruction
([https://github.com/apache/groovy/blob/GROOVY_3_0_7/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java#L778])
to avoid such {{POP}}?
> STC: VerifyError when embedding unary pre/postfix inc/decrement operation of
> outer field in GString
> ---------------------------------------------------------------------------------------------------
>
> Key: GROOVY-9892
> URL: https://issues.apache.org/jira/browse/GROOVY-9892
> Project: Groovy
> Issue Type: Bug
> Components: Static compilation
> Affects Versions: 3.0.6, 3.0.7
> Environment: OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build
> 25.265-b01, mixed mode)
> Eclipse OpenJ9 VM (build openj9-0.21.0, JRE 1.8.0 Windows 10 amd64-64-Bit
> Compressed References 20200728_776 (JIT enabled, AOT enabled)
> ASM 9.0
> Reporter: Frédéric Chuong
> Priority: Major
>
> h1. Issue
> With Groovy 3.0.6 (& 3.0.7), when embedding an outer field unary pre/postfix
> operation within a GString, combined with static compilation
> ({{\@CompileStatic}}), the generated bytecode fails at class loading time
> (VerifyError)
> {code:groovy}
> package org.example
> import groovy.transform.CompileStatic
> import org.objectweb.asm.ClassReader
> import org.objectweb.asm.util.CheckClassAdapter
> @CompileStatic
> class OuterClass {
> int counter = 0
> def call() {
> { ->
> "Hello${++counter}Bar"
> }.call()
> }
> static void main(String[] args) {
> CheckClassAdapter.verify(new
> ClassReader('org/example/OuterClass$_call_closure1'), true, new
> PrintWriter(System.err))
> assert new OuterClass().call() == 'Hello1Bar'
> }
> }
> {code}
> {noformat:title=HotSpot VM error}
> java.lang.VerifyError: Bad type on operand stack
> Exception Details:
> Location:
> org/example/OuterClass$_call_closure1.doCall()Ljava/lang/Object; @46:
> aastore
> Reason:
> Type integer (current frame, stack[4]) is not assignable to reference type
> Current Frame:
> bci: @46
> flags: { }
> locals: { 'org/example/OuterClass$_call_closure1', integer }
> stack: { uninitialized 0, uninitialized 0, '[Ljava/lang/Object;',
> '[Ljava/lang/Object;', integer, integer, 'java/lang/Integer' }
> Bytecode:
> 0x0000000: bb00 1c59 04bd 001e 5903 2ac0 0002 b600
> 0x0000010: 2112 09b8 0027 c000 09b6 002b 0460 593c
> 0x0000020: 2ab6 002c c000 091b b800 30b8 0036 5305
> 0x0000030: bd00 3859 0312 3a53 5904 123c 53b7 003f
> 0x0000040: b000 bf
> Stackmap Table:
> full_frame(@65,{},{Object[#65]})
> at org.example.OuterClass.call(OuterClass.groovy:12)
> at org.example.OuterClass.main(OuterClass.groovy:19)
> {noformat}
> {noformat:title=OpenJ9 VM error}
> java.lang.VerifyError: JVMVRFY012 stack shape inconsistent;
> class=org/example/OuterClass$_call_closure1,
> method=doCall()Ljava/lang/Object;, pc=46
> Exception Details:
> Location:
> org/example/OuterClass$_call_closure1.doCall()Ljava/lang/Object; @46:
> JBaastore
> Reason:
> Type 'java/lang/Integer' (current frame, stack[6]) is not assignable to
> 'java/lang/Object'
> Current Frame:
> bci: @46
> flags: { }
> locals: { 'org/example/OuterClass$_call_closure1', integer }
> stack: { 'uninitialized', 'uninitialized', '[Ljava/lang/Object;',
> '[Ljava/lang/Object;', integer, integer, 'java/lang/Integer' }
> Stackmap Table:
> full_frame(@65,{},{Object[#19]})
> at org.example.OuterClass.call(OuterClass.groovy:12)
> at org.example.OuterClass.main(OuterClass.groovy:19)
> {noformat}
> This did not happen with Groovy 3.0.5.
> {noformat:title=ASM CheckClassAdapter output / Groovy 3.0.6 bytecode
> KO|borderColor=red}
> org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 34:
> Method owner: expected Lorg/codehaus/groovy/runtime/GStringImpl;, but found
> [Ljava/lang/Object;
> at org.objectweb.asm.tree.analysis.Analyzer.analyze(Analyzer.java:291)
> at
> org.objectweb.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:1063)
> at
> org.objectweb.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:1021)
> at org.example.OuterClass.main(OuterClass.groovy:18)
> Caused by: org.objectweb.asm.tree.analysis.AnalyzerException: Method owner:
> expected Lorg/codehaus/groovy/runtime/GStringImpl;, but found
> [Ljava/lang/Object;
> at
> org.objectweb.asm.tree.analysis.BasicVerifier.naryOperation(BasicVerifier.java:390)
> at
> org.objectweb.asm.tree.analysis.BasicVerifier.naryOperation(BasicVerifier.java:43)
> at
> org.objectweb.asm.tree.analysis.Frame.executeInvokeInsn(Frame.java:646)
> at org.objectweb.asm.tree.analysis.Frame.execute(Frame.java:573)
> at org.objectweb.asm.tree.analysis.Analyzer.analyze(Analyzer.java:187)
> ... 3 more
> doCall()Ljava/lang/Object;
> 00000 OuterClass$_call_closure1 . : : NEW
> org/codehaus/groovy/runtime/GStringImpl
> 00001 OuterClass$_call_closure1 . : GStringImpl : DUP
> 00002 OuterClass$_call_closure1 . : GStringImpl GStringImpl : ICONST_1
> 00003 OuterClass$_call_closure1 . : GStringImpl GStringImpl I :
> ANEWARRAY java/lang/Object
> 00004 OuterClass$_call_closure1 . : GStringImpl GStringImpl Object : DUP
> 00005 OuterClass$_call_closure1 . : GStringImpl GStringImpl Object Object :
> ICONST_0
> 00006 OuterClass$_call_closure1 . : GStringImpl GStringImpl Object Object I
> : ALOAD 0
> 00007 OuterClass$_call_closure1 . : GStringImpl GStringImpl Object Object I
> OuterClass$_call_closure1 : CHECKCAST
> org/example/OuterClass$_call_closure1
> 00008 OuterClass$_call_closure1 . : GStringImpl GStringImpl Object Object I
> OuterClass$_call_closure1 : INVOKEVIRTUAL
> org/example/OuterClass$_call_closure1.getThisObject ()Ljava/lang/Object;
> 00009 OuterClass$_call_closure1 . : GStringImpl GStringImpl Object Object I
> Object : LDC Lorg/example/OuterClass;.class
> 00010 OuterClass$_call_closure1 . : GStringImpl GStringImpl Object Object I
> Object Class : INVOKESTATIC
> org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType
> (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
> 00011 OuterClass$_call_closure1 . : GStringImpl GStringImpl Object Object I
> Object : CHECKCAST org/example/OuterClass
> 00012 OuterClass$_call_closure1 . : GStringImpl GStringImpl Object Object I
> OuterClass : INVOKEVIRTUAL org/example/OuterClass.getCounter ()I
> Caused by: org.objectweb.asm.tree.analysis.AnalyzerException: Method owner:
> expected Lorg/codehaus/groovy/runtime/GStringImpl;, but found
> [Ljava/lang/Object;
> 00013 OuterClass$_call_closure1 . : GStringImpl GStringImpl Object Object I
> I : ICONST_1
> 00014 OuterClass$_call_closure1 . : GStringImpl GStringImpl Object Object I
> I I : IADD
> 00015 OuterClass$_call_closure1 . : GStringImpl GStringImpl Object Object I
> I : DUP
> 00016 OuterClass$_call_closure1 . : GStringImpl GStringImpl Object Object I
> I I : ISTORE 1
> 00017 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object I
> I : ALOAD 0
> 00018 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object I
> I OuterClass$_call_closure1 : INVOKEVIRTUAL
> groovy/lang/Closure.getThisObject ()Ljava/lang/Object;
> 00019 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object I
> I Object : CHECKCAST org/example/OuterClass
> 00020 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object I
> I OuterClass : ILOAD 1
> 00021 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object I
> I OuterClass I : INVOKESTATIC org/example/OuterClass.pfaccess$00
> (Lorg/example/OuterClass;I)I
> 00022 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object I
> I I : INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
> 00023 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object I
> I Integer : AASTORE
> 00024 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object :
> ICONST_2
> 00025 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object I
> : ANEWARRAY java/lang/String
> 00026 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object
> String : DUP
> 00027 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object
> String String : ICONST_0
> 00028 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object
> String String I : LDC "Hello"
> 00029 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object
> String String I String : AASTORE
> 00030 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object
> String : DUP
> 00031 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object
> String String : ICONST_1
> 00032 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object
> String String I : LDC "Bar"
> 00033 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object
> String String I String : AASTORE
> 00034 OuterClass$_call_closure1 I : GStringImpl GStringImpl Object Object
> String : INVOKESPECIAL org/codehaus/groovy/runtime/GStringImpl.<init>
> ([Ljava/lang/Object;[Ljava/lang/String;)V
> 00035 ? : ARETURN
> 00036 ? : L0
> 00037 ? : FRAME FULL [] [java/lang/Throwable]
> 00038 ? : NOP
> 00039 ? : ATHROW
> {noformat}
> {noformat:title=ASM CheckClassAdapter output / Groovy 3.0.5
> OK|borderColor=green}
> doCall()Ljava/lang/Object;
> 00000 OuterClass$_call_closure1 : : NEW
> org/codehaus/groovy/runtime/GStringImpl
> 00001 OuterClass$_call_closure1 : GStringImpl : DUP
> 00002 OuterClass$_call_closure1 : GStringImpl GStringImpl : ICONST_1
> 00003 OuterClass$_call_closure1 : GStringImpl GStringImpl I : ANEWARRAY
> java/lang/Object
> 00004 OuterClass$_call_closure1 : GStringImpl GStringImpl Object : DUP
> 00005 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object :
> ICONST_0
> 00006 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I :
> ALOAD 0
> 00007 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I
> OuterClass$_call_closure1 : CHECKCAST
> org/example/OuterClass$_call_closure1
> 00008 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I
> OuterClass$_call_closure1 : INVOKEVIRTUAL
> org/example/OuterClass$_call_closure1.getThisObject ()Ljava/lang/Object;
> 00009 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I
> Object : LDC Lorg/example/OuterClass;.class
> 00010 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I
> Object Class : INVOKESTATIC
> org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType
> (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
> 00011 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I
> Object : CHECKCAST org/example/OuterClass
> 00012 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I
> OuterClass : INVOKEVIRTUAL org/example/OuterClass.getCounter ()I
> 00013 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I I
> : ICONST_1
> 00014 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I I
> I : IADD
> 00015 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I I
> : DUP
> 00016 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I I
> I : INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
> 00017 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I I
> Integer : LDC Lorg/example/OuterClass$_call_closure1;.class
> 00018 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I I
> Integer Class : ALOAD 0
> 00019 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I I
> Integer Class OuterClass$_call_closure1 : LDC "counter"
> 00020 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I I
> Integer Class OuterClass$_call_closure1 String : CHECKCAST
> java/lang/String
> 00021 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I I
> Integer Class OuterClass$_call_closure1 String : INVOKESTATIC
> org/codehaus/groovy/runtime/ScriptBytecodeAdapter.setGroovyObjectProperty
> (Ljava/lang/Object;Ljava/lang/Class;Lgroovy/lang/GroovyObject;Ljava/lang/String;)V
> 00022 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I I
> : INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
> 00023 OuterClass$_call_closure1 : GStringImpl GStringImpl Object Object I
> Integer : AASTORE
> 00024 OuterClass$_call_closure1 : GStringImpl GStringImpl Object :
> ICONST_2
> 00025 OuterClass$_call_closure1 : GStringImpl GStringImpl Object I :
> ANEWARRAY java/lang/String
> 00026 OuterClass$_call_closure1 : GStringImpl GStringImpl Object String :
> DUP
> 00027 OuterClass$_call_closure1 : GStringImpl GStringImpl Object String
> String : ICONST_0
> 00028 OuterClass$_call_closure1 : GStringImpl GStringImpl Object String
> String I : LDC "Hello"
> 00029 OuterClass$_call_closure1 : GStringImpl GStringImpl Object String
> String I String : AASTORE
> 00030 OuterClass$_call_closure1 : GStringImpl GStringImpl Object String :
> DUP
> 00031 OuterClass$_call_closure1 : GStringImpl GStringImpl Object String
> String : ICONST_1
> 00032 OuterClass$_call_closure1 : GStringImpl GStringImpl Object String
> String I : LDC "Bar"
> 00033 OuterClass$_call_closure1 : GStringImpl GStringImpl Object String
> String I String : AASTORE
> 00034 OuterClass$_call_closure1 : GStringImpl GStringImpl Object String :
> INVOKESPECIAL org/codehaus/groovy/runtime/GStringImpl.<init>
> ([Ljava/lang/Object;[Ljava/lang/String;)V
> 00035 OuterClass$_call_closure1 : GStringImpl : ARETURN
> 00036 ? : L0
> 00037 ? : FRAME FULL [] [java/lang/Throwable]
> 00038 ? : NOP
> 00039 ? : ATHROW
> {noformat}
> h1. Workaround
> A workaround is to lift the unary operation out of the GString (i.e. use a
> temporary variable).
--
This message was sent by Atlassian Jira
(v8.3.4#803005)