You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Shil Sinha (JIRA)" <ji...@apache.org> on 2015/11/02 18:57:27 UTC
[jira] [Commented] (GROOVY-7656) Spread safe method calls on list
literals result in the list expression being evaluated twice (SC)
[ https://issues.apache.org/jira/browse/GROOVY-7656?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14985636#comment-14985636 ]
Shil Sinha commented on GROOVY-7656:
------------------------------------
This appears to happen because the list expression is visited twice by the ACG - once as a receiver for the spread safe method call, and once as a receiver for the iterator of the resulting for loop.
> 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)