Shil Sinha created GROOVY-7656:
----------------------------------

             Summary: Spread safe method calls on list literals result in the 
list expression being evaluated twice (SC)
                 Key: GROOVY-7656
                 URL: https://issues.apache.org/jira/browse/GROOVY-7656
             Project: Groovy
          Issue Type: Bug
          Components: Static compilation
    Affects Versions: 2.4.5
            Reporter: Shil Sinha
            Assignee: Cédric Champeau
            Priority: Critical


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:

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

The bytecode for the method above is:
{code}
 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
{code}

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:

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



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to