From jon.rafkind at hp.com Tue Oct 7 01:19:42 2014 From: jon.rafkind at hp.com (Rafkind, Jon) Date: Tue, 7 Oct 2014 01:19:42 +0000 Subject: generated lambda names - lambda$null$0 Message-ID: Tools that work with bytecode will inevitably come across the generated lambda method names, and I noticed that lambdas nested inside other lambdas have strange 'null' names in them. public class x{ interface T{ int g(); } public void test(){ T t1 = () -> { T t2 = () -> 2; return 1; }; } } The bytecode contains these two desugared lambda methods: .method synthetic static private lambda$test$1 : ()I .method synthetic static private lambda$null$0 : ()I Where lambda$test$1 is the 't1' lambda, and lambda$null$0 is the 't2' lambda. It's not the end of the world to have 'null' there, but since an attempt at putting some useful info there is made maybe something better than 'null' could be chosen. Tested on jdk8u20. BTW, javap cannot dissassemble/show any of the generated lambda code. Perhaps hiding the generated lambda name from the user is ok, but there is no way to see the method bodies. I was about to write my own dissassembler based on the ASM library, but I found this nice github project that works just fine: https://github.com/Storyyeller/Krakatau From jonathan.gibbons at oracle.com Tue Oct 7 01:30:44 2014 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Mon, 06 Oct 2014 18:30:44 -0700 Subject: generated lambda names - lambda$null$0 In-Reply-To: References: Message-ID: <54334244.2060901@oracle.com> On 10/06/2014 06:19 PM, Rafkind, Jon wrote: > BTW, javap cannot dissassemble/show any of the generated lambda code. That sounds like a bug. Can you give a specific example? -- Jon From jonathan.gibbons at oracle.com Tue Oct 7 01:51:40 2014 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Mon, 06 Oct 2014 18:51:40 -0700 Subject: generated lambda names - lambda$null$0 In-Reply-To: <54334244.2060901@oracle.com> References: <54334244.2060901@oracle.com> Message-ID: <5433472C.6020305@oracle.com> On 10/06/2014 06:30 PM, Jonathan Gibbons wrote: > > On 10/06/2014 06:19 PM, Rafkind, Jon wrote: >> BTW, javap cannot dissassemble/show any of the generated lambda code. > > That sounds like a bug. Can you give a specific example? > > -- Jon > Partially answering my own question, for the example given in the original post, javap does show pretty much everything. The lambda method bodies are there: don't forget to use the -private option. Source: $ more play/x.java public class x{ interface T{ int g(); } public void test(){ T t1 = () -> { T t2 = () -> 2; return 1; }; } } javap: $ javap -v -private play/x.class Classfile /w/jjg/work/play/x.class Last modified Oct 6, 2014; size 886 bytes MD5 checksum 411cf2b7dea73faaee670b25e3739753 Compiled from "x.java" public class x minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #5.#19 // java/lang/Object."":()V #2 = InvokeDynamic #0:#24 // #0:g:()Lx$T; #3 = InvokeDynamic #1:#24 // #1:g:()Lx$T; #4 = Class #26 // x #5 = Class #27 // java/lang/Object #6 = Class #28 // x$T #7 = Utf8 T #8 = Utf8 InnerClasses #9 = Utf8 #10 = Utf8 ()V #11 = Utf8 Code #12 = Utf8 LineNumberTable #13 = Utf8 test #14 = Utf8 lambda$test$1 #15 = Utf8 ()I #16 = Utf8 lambda$null$0 #17 = Utf8 SourceFile #18 = Utf8 x.java #19 = NameAndType #9:#10 // "":()V #20 = Utf8 BootstrapMethods #21 = MethodHandle #6:#29 // 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; #22 = MethodType #15 // ()I #23 = MethodHandle #6:#30 // invokestatic x.lambda$test$1:()I #24 = NameAndType #31:#32 // g:()Lx$T; #25 = MethodHandle #6:#33 // invokestatic x.lambda$null$0:()I #26 = Utf8 x #27 = Utf8 java/lang/Object #28 = Utf8 x$T #29 = Methodref #34.#35 // 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; #30 = Methodref #4.#36 // x.lambda$test$1:()I #31 = Utf8 g #32 = Utf8 ()Lx$T; #33 = Methodref #4.#37 // x.lambda$null$0:()I #34 = Class #38 // java/lang/invoke/LambdaMetafactory #35 = NameAndType #39:#42 // 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; #36 = NameAndType #14:#15 // lambda$test$1:()I #37 = NameAndType #16:#15 // lambda$null$0:()I #38 = Utf8 java/lang/invoke/LambdaMetafactory #39 = Utf8 metafactory #40 = Class #44 // java/lang/invoke/MethodHandles$Lookup #41 = Utf8 Lookup #42 = Utf8 (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; #43 = Class #45 // java/lang/invoke/MethodHandles #44 = Utf8 java/lang/invoke/MethodHandles$Lookup #45 = Utf8 java/lang/invoke/MethodHandles { public x(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return LineNumberTable: line 1: 0 line 2: 4 public void test(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:g:()Lx$T; 5: astore_1 6: return LineNumberTable: line 7: 0 line 11: 6 private static int lambda$test$1(); descriptor: ()I flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC Code: stack=1, locals=1, args_size=0 0: invokedynamic #3, 0 // InvokeDynamic #1:g:()Lx$T; 5: astore_0 6: iconst_1 7: ireturn LineNumberTable: line 8: 0 line 9: 6 private static int lambda$null$0(); descriptor: ()I flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC Code: stack=1, locals=0, args_size=0 0: iconst_2 1: ireturn LineNumberTable: line 8: 0 } SourceFile: "x.java" InnerClasses: static #7= #6 of #4; // T=class x$T of class x public static final #41= #40 of #43; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles BootstrapMethods: 0: #21 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; Method arguments: #22 ()I #23 invokestatic x.lambda$test$1:()I #22 ()I 1: #21 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; Method arguments: #22 ()I #25 invokestatic x.lambda$null$0:()I #22 ()I From robert.field at oracle.com Tue Oct 7 02:16:51 2014 From: robert.field at oracle.com (Robert Field) Date: Mon, 06 Oct 2014 19:16:51 -0700 Subject: generated lambda names - lambda$null$0 In-Reply-To: References: Message-ID: <54334D13.2040206@oracle.com> No attempt was made to make the name user friendly or descriptive -- they were designed to be unique and for javac debugging purposes remain generally constant over small changes. The "null" in the name is NOT a bug. -Robert On 10/06/14 18:19, Rafkind, Jon wrote: > Tools that work with bytecode will inevitably come across the generated > lambda method names, and I noticed that lambdas nested inside other > lambdas have strange 'null' names in them. > > public class x{ > interface T{ > int g(); > } > > public void test(){ > T t1 = () -> { > T t2 = () -> 2; > return 1; > }; > } > } > > The bytecode contains these two desugared lambda methods: > > .method synthetic static private lambda$test$1 : ()I > .method synthetic static private lambda$null$0 : ()I > > Where lambda$test$1 is the 't1' lambda, and lambda$null$0 is the 't2' > lambda. It's not the end of the world to have 'null' there, but since an > attempt at putting some useful info there is made maybe something better > than 'null' could be chosen. > > Tested on jdk8u20. > > BTW, javap cannot dissassemble/show any of the generated lambda code. > Perhaps hiding the generated lambda name from the user is ok, but there > is no way to see the method bodies. I was about to write my own > dissassembler based on the ASM library, but I found this nice github > project that works just fine: https://github.com/Storyyeller/Krakatau > From jon.rafkind at hp.com Tue Oct 7 04:43:10 2014 From: jon.rafkind at hp.com (Rafkind, Jon) Date: Tue, 7 Oct 2014 04:43:10 +0000 Subject: generated lambda names - lambda$null$0 References: <54334244.2060901@oracle.com> <5433472C.6020305@oracle.com> Message-ID: On 10/06/2014 06:52 PM, Jonathan Gibbons wrote: > On 10/06/2014 06:30 PM, Jonathan Gibbons wrote: >> On 10/06/2014 06:19 PM, Rafkind, Jon wrote: >>> BTW, javap cannot dissassemble/show any of the generated lambda code. >> That sounds like a bug. Can you give a specific example? >> >> -- Jon >> > Partially answering my own question, for the example given in the > original post, javap does show pretty much everything. The lambda method > bodies are there: don't forget to use the -private option. Aha, I didn't know about -private. Thanks! > Source: > $ more play/x.java > public class x{ > interface T{ > int g(); > } > > public void test(){ > T t1 = () -> { > T t2 = () -> 2; > return 1; > }; > } > } > > > javap: > $ javap -v -private play/x.class > Classfile /w/jjg/work/play/x.class > Last modified Oct 6, 2014; size 886 bytes > MD5 checksum 411cf2b7dea73faaee670b25e3739753 > Compiled from "x.java" > public class x > minor version: 0 > major version: 52 > flags: ACC_PUBLIC, ACC_SUPER > Constant pool: > #1 = Methodref #5.#19 // java/lang/Object."":()V > #2 = InvokeDynamic #0:#24 // #0:g:()Lx$T; > #3 = InvokeDynamic #1:#24 // #1:g:()Lx$T; > #4 = Class #26 // x > #5 = Class #27 // java/lang/Object > #6 = Class #28 // x$T > #7 = Utf8 T > #8 = Utf8 InnerClasses > #9 = Utf8 > #10 = Utf8 ()V > #11 = Utf8 Code > #12 = Utf8 LineNumberTable > #13 = Utf8 test > #14 = Utf8 lambda$test$1 > #15 = Utf8 ()I > #16 = Utf8 lambda$null$0 > #17 = Utf8 SourceFile > #18 = Utf8 x.java > #19 = NameAndType #9:#10 // "":()V > #20 = Utf8 BootstrapMethods > #21 = MethodHandle #6:#29 // 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; > #22 = MethodType #15 // ()I > #23 = MethodHandle #6:#30 // invokestatic > x.lambda$test$1:()I > #24 = NameAndType #31:#32 // g:()Lx$T; > #25 = MethodHandle #6:#33 // invokestatic > x.lambda$null$0:()I > #26 = Utf8 x > #27 = Utf8 java/lang/Object > #28 = Utf8 x$T > #29 = Methodref #34.#35 // > 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; > #30 = Methodref #4.#36 // x.lambda$test$1:()I > #31 = Utf8 g > #32 = Utf8 ()Lx$T; > #33 = Methodref #4.#37 // x.lambda$null$0:()I > #34 = Class #38 // > java/lang/invoke/LambdaMetafactory > #35 = NameAndType #39:#42 // > 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; > #36 = NameAndType #14:#15 // lambda$test$1:()I > #37 = NameAndType #16:#15 // lambda$null$0:()I > #38 = Utf8 java/lang/invoke/LambdaMetafactory > #39 = Utf8 metafactory > #40 = Class #44 // > java/lang/invoke/MethodHandles$Lookup > #41 = Utf8 Lookup > #42 = Utf8 > (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; > #43 = Class #45 // java/lang/invoke/MethodHandles > #44 = Utf8 java/lang/invoke/MethodHandles$Lookup > #45 = Utf8 java/lang/invoke/MethodHandles > { > public x(); > descriptor: ()V > flags: ACC_PUBLIC > Code: > stack=1, locals=1, args_size=1 > 0: aload_0 > 1: invokespecial #1 // Method > java/lang/Object."":()V > 4: return > LineNumberTable: > line 1: 0 > line 2: 4 > > public void test(); > descriptor: ()V > flags: ACC_PUBLIC > Code: > stack=1, locals=2, args_size=1 > 0: invokedynamic #2, 0 // InvokeDynamic #0:g:()Lx$T; > 5: astore_1 > 6: return > LineNumberTable: > line 7: 0 > line 11: 6 > > private static int lambda$test$1(); > descriptor: ()I > flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC > Code: > stack=1, locals=1, args_size=0 > 0: invokedynamic #3, 0 // InvokeDynamic #1:g:()Lx$T; > 5: astore_0 > 6: iconst_1 > 7: ireturn > LineNumberTable: > line 8: 0 > line 9: 6 > > private static int lambda$null$0(); > descriptor: ()I > flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC > Code: > stack=1, locals=0, args_size=0 > 0: iconst_2 > 1: ireturn > LineNumberTable: > line 8: 0 > } > SourceFile: "x.java" > InnerClasses: > static #7= #6 of #4; // T=class x$T of class x > public static final #41= #40 of #43; // Lookup=class > java/lang/invoke/MethodHandles$Lookup of class > java/lang/invoke/MethodHandles > BootstrapMethods: > 0: #21 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; > Method arguments: > #22 ()I > #23 invokestatic x.lambda$test$1:()I > #22 ()I > 1: #21 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; > Method arguments: > #22 ()I > #25 invokestatic x.lambda$null$0:()I > #22 ()I > > > From neal at gafter.com Mon Oct 13 18:12:13 2014 From: neal at gafter.com (Neal Gafter) Date: Mon, 13 Oct 2014 11:12:13 -0700 Subject: Allocation of Lambdas that capture "this" In-Reply-To: References: Message-ID: On Wed, Aug 20, 2014 at 4:58 PM, Zhong Yu wrote: > Is there any reason not to initialize the field directly? like > > final Consumer readHandler = (Msg obj)-> { > this.doSomethingWith(obj); > ... > }; > You are not allowed to access "this" in a field initializer. From zhong.j.yu at gmail.com Tue Oct 14 18:36:05 2014 From: zhong.j.yu at gmail.com (Zhong Yu) Date: Tue, 14 Oct 2014 13:36:05 -0500 Subject: Allocation of Lambdas that capture "this" In-Reply-To: References: Message-ID: On Mon, Oct 13, 2014 at 1:12 PM, Neal Gafter wrote: > On Wed, Aug 20, 2014 at 4:58 PM, Zhong Yu wrote: >> >> Is there any reason not to initialize the field directly? like >> >> final Consumer readHandler = (Msg obj)-> { >> this.doSomethingWith(obj); >> ... >> }; > > > You are not allowed to access "this" in a field initializer. Apparently it is allowed, according to javac. What's not allowed is to reference a final field that "might not have been initialized" when the lambda is constructed; which I think is unnecessarily strict and inconvenient for many legitimate use cases. final Runnable r = ()->{ this.o.toString(); }; // javac error final Object o; // assigned in constructor It can be worked around by obfuscating `this` final Runnable r = ()->{ (this).o.toString(); }; // ok Zhong Yu bayou.io From sam at sampullara.com Tue Oct 14 19:40:57 2014 From: sam at sampullara.com (Sam Pullara) Date: Tue, 14 Oct 2014 12:40:57 -0700 Subject: Allocation of Lambdas that capture "this" In-Reply-To: References: Message-ID: Since you can do this ? even if wrong ? with anonymous inner classes I think it probably should be generally allowed. Sam final Runnable r = ()->{ (this).o.toString(); }; // javac error final Object o; // assigned in constructor { r.run(); } public ZhongTest() { this.o = ""; } java.lang.NullPointerException at spullara.ZhongTest.lambda$new$0(ZhongTest.java:10) at spullara.ZhongTest$$Lambda$1/693632176.run(Unknown Source) at spullara.ZhongTest.(ZhongTest.java:13) On Tue, Oct 14, 2014 at 11:36 AM, Zhong Yu wrote: > On Mon, Oct 13, 2014 at 1:12 PM, Neal Gafter wrote: > > On Wed, Aug 20, 2014 at 4:58 PM, Zhong Yu wrote: > >> > >> Is there any reason not to initialize the field directly? like > >> > >> final Consumer readHandler = (Msg obj)-> { > >> this.doSomethingWith(obj); > >> ... > >> }; > > > > > > You are not allowed to access "this" in a field initializer. > > Apparently it is allowed, according to javac. > > What's not allowed is to reference a final field that "might not have > been initialized" when the lambda is constructed; which I think is > unnecessarily strict and inconvenient for many legitimate use cases. > > final Runnable r = ()->{ this.o.toString(); }; // javac error > > final Object o; // assigned in constructor > > It can be worked around by obfuscating `this` > > final Runnable r = ()->{ (this).o.toString(); }; // ok > > Zhong Yu > bayou.io > >