groovy-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jochen Theodorou <blackd...@gmx.org>
Subject Re: About the native-lambda branch
Date Mon, 15 Jan 2018 17:28:26 GMT


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



Mime
View raw message