1818 */
1919package org .codehaus .groovy .transform .sc .transformers ;
2020
21+ import org .codehaus .groovy .ast .ClassHelper ;
22+ import org .codehaus .groovy .ast .ClassNode ;
2123import org .codehaus .groovy .ast .ConstructorNode ;
24+ import org .codehaus .groovy .ast .GroovyCodeVisitor ;
2225import org .codehaus .groovy .ast .MethodNode ;
26+ import org .codehaus .groovy .ast .Parameter ;
2327import org .codehaus .groovy .ast .expr .ArgumentListExpression ;
2428import org .codehaus .groovy .ast .expr .ArrayExpression ;
29+ import org .codehaus .groovy .ast .expr .ConstantExpression ;
2530import org .codehaus .groovy .ast .expr .ConstructorCallExpression ;
2631import org .codehaus .groovy .ast .expr .Expression ;
32+ import org .codehaus .groovy .ast .expr .ExpressionTransformer ;
2733import org .codehaus .groovy .ast .expr .ListExpression ;
34+ import org .codehaus .groovy .classgen .AsmClassGenerator ;
2835import org .codehaus .groovy .transform .stc .StaticTypesMarker ;
2936
37+ import java .util .ArrayList ;
3038import java .util .List ;
3139
32- import static java .util .stream .Collectors .toList ;
40+ import static org .codehaus .groovy .classgen .AsmClassGenerator .containsSpreadExpression ;
41+ import static org .objectweb .asm .Opcodes .DUP ;
42+ import static org .objectweb .asm .Opcodes .INVOKEVIRTUAL ;
3343
3444class ListExpressionTransformer {
3545
@@ -42,7 +52,7 @@ class ListExpressionTransformer {
4252 Expression transformListExpression (final ListExpression le ) {
4353 MethodNode mn = le .getNodeMetaData (StaticTypesMarker .DIRECT_METHOD_CALL_TARGET );
4454 if (mn instanceof ConstructorNode ) {
45- List <Expression > elements = le .getExpressions ().stream ().map (scTransformer ::transform ).collect ( toList () );
55+ List <Expression > elements = le .getExpressions ().stream ().map (scTransformer ::transform ).toList ();
4656
4757 if (mn .getDeclaringClass ().isArray ()) {
4858 var ae = new ArrayExpression (mn .getDeclaringClass ().getComponentType (), elements );
@@ -56,6 +66,60 @@ Expression transformListExpression(final ListExpression le) {
5666 return cce ;
5767 }
5868
69+ // GROOVY-8699: emit direct bytecode for simple list
70+ if (mn == null && le .getExpressions ().size () < 25 && !containsSpreadExpression (le )) {
71+ ClassNode type = scTransformer .getTypeChooser ().resolveType (le , scTransformer .getClassNode ());
72+ if (ArrayList_TYPE .equals (type )) { // annotation attributes cannot be transformed
73+ var list = new NewListExpression (le .getExpressions ().stream ().map (scTransformer ::transform ).toList ());
74+ list .setSourcePosition (le );
75+ list .copyNodeMetaData (le );
76+ return list ;
77+ }
78+ }
79+
5980 return scTransformer .superTransform (le );
6081 }
82+
83+ //--------------------------------------------------------------------------
84+
85+ private static final ClassNode ArrayList_TYPE = ClassHelper .makeWithoutCaching (ArrayList .class );
86+
87+ private static final MethodNode ArrayList_NEW = ArrayList_TYPE .getDeclaredConstructor (new Parameter [] {new Parameter (ClassHelper .int_TYPE , "capacity" )});
88+
89+ private static class NewListExpression extends ListExpression {
90+
91+ NewListExpression (final List <Expression > values ) {
92+ super (values );
93+ }
94+
95+ @ Override
96+ public Expression transformExpression (final ExpressionTransformer transformer ) {
97+ var list = new NewListExpression (transformExpressions (getExpressions (), transformer ));
98+ list .setSourcePosition (this );
99+ list .copyNodeMetaData (this );
100+ return list ;
101+ }
102+
103+ @ Override
104+ public void visit (final GroovyCodeVisitor visitor ) {
105+ if (!(visitor instanceof AsmClassGenerator g )) {
106+ super .visit (visitor );
107+ } else {
108+ var mv = g .getController ().getMethodVisitor ();
109+ var os = g .getController ().getOperandStack ();
110+
111+ var list = new ConstructorCallExpression (ArrayList_TYPE , new ConstantExpression (getExpressions ().size (), true ));
112+ list .putNodeMetaData (StaticTypesMarker .DIRECT_METHOD_CALL_TARGET , ArrayList_NEW );
113+ list .visit (visitor );
114+
115+ for (Expression li : getExpressions ()) {
116+ mv .visitInsn (DUP );
117+ li .visit (visitor );
118+ os .box ();
119+ mv .visitMethodInsn (INVOKEVIRTUAL , "java/util/ArrayList" , "add" , "(Ljava/lang/Object;)Z" , false );
120+ os .pop (); // boolean return value
121+ }
122+ }
123+ }
124+ }
61125}
0 commit comments