Am 15.01.2018 um 10:53 schrieb Daniel Sun:
Hi Jochen,

      `ArrayIndexOutOfBoundsException` is fixed. I encounter another
problem(i.e. How to load arguments according to some specified order): I
want to load local variables[1] according to the order in which the local
variables appear in lambda body. For example:
(1)
```
String x = 'x'
Integer y = 2
Stream.of(1, 2, 3).map(e -> '' + x + y + e) // Note the order of `x` and
`y`(`x` is before `y`)
```
I hope load `x`, then load `y` before invokedynamic.

(2)
```
String x = 'x'
Integer y = 2
Stream.of(1, 2, 3).map(e -> '' + y + x + e) // Note the order of `x` and
`y`(`y` is before `x`)
```
I hope  load `y`, then load `x` before invokedynamic.

     Here is how I try to archieve[2], but I can not get the expected
result[3], i.e. I get `groovy.lang.Reference` instances... not String
instances.

If you use the Closure code, then variables used in Closures are marked as Reference even if they are only read


     The following bytecode is generated for java code[4] by javac. The key
part is shown as follows and is what I want to generate via ASM utilities of
Groovy(e.g. `CompileStack`, `OperandStack`, etc):

what you do is for exmple

        Parameter[] lambdaSharedVariableParameters = 
syntheticLambdaMethodNode.getNodeMetaData(LAMBDA_SHARED_VARIABLES);
        for (int i = 0; i < lambdaSharedVariableParameters.length; i++) {
            mv.visitVarInsn(ALOAD, i);
            
operandStack.doGroovyCast(lambdaSharedVariableParameters[i].getType().redirect());
//            
operandStack.push(lambdaSharedVariableParameters[i].getType().redirect());
        }

Assuming you manage to not wrap in a Reference, then the shared parameter might be a primitive. in that case aload is the wrong bytecode instruction. Please use CompileStack to handle the local variables instead.

[...]

The complete bytecode:
```
// class version 52.0 (52)
// access flags 0x21
public class Test2 {
[...]
   // access flags 0x9
   public static p()V
    L0
     LINENUMBER 10 L0
     LDC "#"
     ASTORE 0

this creates a String and stores it in 0

    L1
     LINENUMBER 12 L1
     ICONST_3
     ANEWARRAY java/lang/Integer
     DUP
     ICONST_0
     ICONST_1
     INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
     AASTORE
     DUP
     ICONST_1
     ICONST_2
     INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
     AASTORE
     DUP
     ICONST_2
     ICONST_3
     INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
     AASTORE

this creates an Integer[]{1,2,3} and leaves that on the operand stack

     INVOKESTATIC java/util/stream/Stream.of
([Ljava/lang/Object;)Ljava/util/stream/Stream;

this calls Stream.of with the Integer[], leaving a Stream object on the operand stack

     ALOAD 0

loads back the string from 0, now we have String on top and the Stream as second operand

     INVOKEDYNAMIC apply(Ljava/lang/String;)Ljava/util/function/Function; [
       // handle kind 0x6 : INVOKESTATIC >
java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
       // arguments:
       (Ljava/lang/Object;)Ljava/lang/Object;,
       // handle kind 0x6 : INVOKESTATIC
Test2.lambda$p$0(Ljava/lang/String;Ljava/lang/Integer;)Ljava/lang/String;,
       (Ljava/lang/Integer;)Ljava/lang/String;
     ]

hm.... I am not too familiar with the LambdaFactory logic so I cannot read this all too well. I see in the last two a parameters the constants for the lambda$p$0 and its minified MethodType. the lambda has a String and an Integer parameter and return a String. But because the String is bound through the factory to create the value for x, the resulting minified/cleanedup reference is (Ljava/lang/Integer;)Ljava/lang/String; instead.

As of why there is a (Ljava/lang/Object;)Ljava/lang/Object; I do not know. But the whole construct should take a String and give back a Function.


     INVOKEINTERFACE java/util/stream/Stream.map
(Ljava/util/function/Function;)Ljava/util/stream/Stream;

till here we had Stream, Function (the String was consumed by the lambdafactory call) on the stack, this calls map with the Function as argument on the Stream.

     POP

and here we forget about the return value....


Does this description help you?

bye Jochen


Reply via email to