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

Spread safe method calls on list literals result in the list expression being evaluated twice (SC)

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Critical
    • Resolution: Fixed
    • Affects Version/s: 2.4.5
    • Fix Version/s: 2.4.6
    • Component/s: Static compilation
    • Labels:
      None

      Description

      When a list literal is the receiver for a statically compiled spread safe method call expression, the instructions to create the list are included twice. Example:

      @groovy.transform.CompileStatic
      void test() {
          ['a']*.size()
      }
      

      The bytecode for the method above is:

       L0
          LINENUMBER 3 L0
          NEW java/util/ArrayList
          DUP
          INVOKESPECIAL java/util/ArrayList.<init> ()V
          ASTORE 1
         L1
          ALOAD 1
          POP
          ICONST_1
          ANEWARRAY java/lang/Object
          DUP
          ICONST_0
          LDC "a"
          AASTORE
          INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.createList ([Ljava/lang/Object;)Ljava/util/List;
          IFNULL L2
          ACONST_NULL
          ASTORE 2
         L3
          ICONST_1
          ANEWARRAY java/lang/Object
          DUP
          ICONST_0
          LDC "a"
          AASTORE
          INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.createList ([Ljava/lang/Object;)Ljava/util/List;
          INVOKEINTERFACE java/util/List.iterator ()Ljava/util/Iterator;
          ASTORE 3
         L4
          ALOAD 3
          INVOKEINTERFACE java/util/Iterator.hasNext ()Z
          IFEQ L2
          ALOAD 3
          INVOKEINTERFACE java/util/Iterator.next ()Ljava/lang/Object;
          ASTORE 2
          ALOAD 1
          ALOAD 2
          DUP
          ASTORE 4
          IFNULL L5
          ALOAD 4
          INVOKESTATIC org/codehaus/groovy/runtime/typehandling/ShortTypeHandling.castToString (Ljava/lang/Object;)Ljava/lang/String;
          CHECKCAST java/lang/String
          INVOKESTATIC org/codehaus/groovy/runtime/StringGroovyMethods.size (Ljava/lang/String;)I
          INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
          GOTO L6
         L5
          ACONST_NULL
         L6
          INVOKEVIRTUAL java/util/ArrayList.add (Ljava/lang/Object;)Z
          POP
          GOTO L4
         L2
          ALOAD 1
          POP
      

      If the list expression contains method calls that have side effects, this can cause serious problems. The example below is trivial, but shows the general case:

      @groovy.transform.CompileStatic
      void test() {
          def list = ['abc']
          def lengths = [list.removeAt(0)]*.length() // throws IndexOutOfBoundsException
      }
      

        Attachments

          Activity

            People

            • Assignee:
              shils Shil Sinha
              Reporter:
              shils Shil Sinha
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: