Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-9892

STC: VerifyError when embedding unary pre/postfix inc/decrement operation of outer field in GString

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 3.0.6, 3.0.7
    • 3.0.8, 4.0.0-alpha-3
    • Static compilation
    • None
    • 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

    Description

      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)

      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'
          }
      }
      
      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)
      
      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)
      

      This did not happen with Groovy 3.0.5.

      ASM CheckClassAdapter output / Groovy 3.0.6 bytecode KO
      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
      
      ASM CheckClassAdapter output / Groovy 3.0.5 OK
      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
      

      Workaround

      A workaround is to lift the unary operation out of the GString (i.e. use a temporary variable).

      Attachments

        Issue Links

          Activity

            People

              daniel_sun Daniel Sun
              chuong_f Frédéric Chuong
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - 0h
                  0h
                  Logged:
                  Time Spent - 1h 40m
                  1h 40m