From forax at univ-mlv.fr Thu Nov 5 09:37:27 2015 From: forax at univ-mlv.fr (Remi Forax) Date: Thu, 5 Nov 2015 10:37:27 +0100 (CET) Subject: javac doesn't generate the correct bytecode for lambda if the target type is an intersection type In-Reply-To: <1334968687.2198479.1446714977277.JavaMail.zimbra@u-pem.fr> Message-ID: <564557894.2212535.1446716247203.JavaMail.zimbra@u-pem.fr> About this bug, https://bugs.openjdk.java.net/browse/JDK-8141508 javac has trouble with intersection type that are target type of a lambda and method reference, Usually when there is an intersection type, javac substitute it by the first type of the intersection type and add cast when necessary. Let suppose we have this code, public class Intersection { interface I { } interface J { void foo(); } static void bar(T t) { Runnable r = t::foo; } public static void main(String[] args) { class A implements I, J { public void foo() {} } bar(new A()); } } Currently, javac generates a method reference on J::foo with an invokedynamic that takes an I as parameter, hence it fails at runtime. javac should de-sugar t::foo into a lambda that take an I and then add a cast to J like for a call to a method of an intersection type. So the workaround is to use a lambda instead, Runnable r = t -> t.foo(); I've already seen this bug somewhere but was not able to find a corresponding bug report in the database :( cheers, R?mi From maurizio.cimadamore at oracle.com Thu Nov 5 09:47:59 2015 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 5 Nov 2015 09:47:59 +0000 Subject: javac doesn't generate the correct bytecode for lambda if the target type is an intersection type In-Reply-To: <564557894.2212535.1446716247203.JavaMail.zimbra@u-pem.fr> References: <564557894.2212535.1446716247203.JavaMail.zimbra@u-pem.fr> Message-ID: <563B25CF.9040908@oracle.com> Thanks for the report - looks an interesting issue; I also note that a MethodHandle.asType adaptation would have solved this issue? Maurizio On 05/11/15 09:37, Remi Forax wrote: > About this bug, > https://bugs.openjdk.java.net/browse/JDK-8141508 > > javac has trouble with intersection type that are target type of a lambda and method reference, > Usually when there is an intersection type, javac substitute it by the first type of the intersection type and add cast when necessary. > > Let suppose we have this code, > > public class Intersection { > interface I { > } > interface J { > void foo(); > } > > static void bar(T t) { > Runnable r = t::foo; > } > > public static void main(String[] args) { > class A implements I, J { public void foo() {} } > bar(new A()); > } > } > > > Currently, javac generates a method reference on J::foo with an invokedynamic that takes an I as parameter, hence it fails at runtime. > javac should de-sugar t::foo into a lambda that take an I and then add a cast to J like for a call to a method of an intersection type. > > So the workaround is to use a lambda instead, > Runnable r = t -> t.foo(); > > I've already seen this bug somewhere but was not able to find a corresponding bug report in the database :( > > cheers, > R?mi > > From forax at univ-mlv.fr Thu Nov 5 10:12:42 2015 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Thu, 5 Nov 2015 11:12:42 +0100 (CET) Subject: javac doesn't generate the correct bytecode for lambda if the target type is an intersection type In-Reply-To: <563B25CF.9040908@oracle.com> References: <564557894.2212535.1446716247203.JavaMail.zimbra@u-pem.fr> <563B25CF.9040908@oracle.com> Message-ID: <677809457.2259214.1446718362598.JavaMail.zimbra@u-pem.fr> ----- Mail original ----- > De: "Maurizio Cimadamore" > ?: "Remi Forax" , compiler-dev at openjdk.java.net > Envoy?: Jeudi 5 Novembre 2015 10:47:59 > Objet: Re: javac doesn't generate the correct bytecode for lambda if the target type is an intersection type > > Thanks for the report - looks an interesting issue; I also note that a > MethodHandle.asType adaptation would have solved this issue? yes, right. at runtime, an intersection type is a class that implements all the types so asType() works here and you can do that for any reference which has an interface as declaring type. I don't think it's a good idea to try to replace the check which is done during linking time (invokedynamic linking time) to a check done at runtime. If something bark at linking time it's usually a bug in javac (or a separate compilation issue). > > Maurizio R?mi > > On 05/11/15 09:37, Remi Forax wrote: > > About this bug, > > https://bugs.openjdk.java.net/browse/JDK-8141508 > > > > javac has trouble with intersection type that are target type of a lambda > > and method reference, > > Usually when there is an intersection type, javac substitute it by the > > first type of the intersection type and add cast when necessary. > > > > Let suppose we have this code, > > > > public class Intersection { > > interface I { > > } > > interface J { > > void foo(); > > } > > > > static void bar(T t) { > > Runnable r = t::foo; > > } > > > > public static void main(String[] args) { > > class A implements I, J { public void foo() {} } > > bar(new A()); > > } > > } > > > > > > Currently, javac generates a method reference on J::foo with an > > invokedynamic that takes an I as parameter, hence it fails at runtime. > > javac should de-sugar t::foo into a lambda that take an I and then add a > > cast to J like for a call to a method of an intersection type. > > > > So the workaround is to use a lambda instead, > > Runnable r = t -> t.foo(); > > > > I've already seen this bug somewhere but was not able to find a > > corresponding bug report in the database :( > > > > cheers, > > R?mi > > > > > > From srikanth.adayapalam at oracle.com Fri Nov 6 06:09:46 2015 From: srikanth.adayapalam at oracle.com (Srikanth) Date: Fri, 06 Nov 2015 11:39:46 +0530 Subject: javac doesn't generate the correct bytecode for lambda if the target type is an intersection type In-Reply-To: <564557894.2212535.1446716247203.JavaMail.zimbra@u-pem.fr> References: <564557894.2212535.1446716247203.JavaMail.zimbra@u-pem.fr> Message-ID: <563C442A.2070301@oracle.com> On Thursday 05 November 2015 03:07 PM, Remi Forax wrote: > About this bug, > https://bugs.openjdk.java.net/browse/JDK-8141508 [...] > I've already seen this bug somewhere but was not able to find a corresponding bug report in the database :( I think you are looking for https://bugs.openjdk.java.net/browse/JDK-8049898 ? I have a candidate fix that addresses the above bug and the reduced test case you have posted but not yet the full test case in https://bugs.openjdk.java.net/browse/JDK-8141508 I'll grab this one and take it to conclusion. Thanks! Srikanth > > cheers, > R?mi > > From forax at univ-mlv.fr Fri Nov 6 07:19:08 2015 From: forax at univ-mlv.fr (Remi Forax) Date: Fri, 6 Nov 2015 08:19:08 +0100 (CET) Subject: javac doesn't generate the correct bytecode for lambda if the target type is an intersection type In-Reply-To: <563C442A.2070301@oracle.com> References: <564557894.2212535.1446716247203.JavaMail.zimbra@u-pem.fr> <563C442A.2070301@oracle.com> Message-ID: <1379049123.260565.1446794348156.JavaMail.zimbra@u-pem.fr> ----- Mail original ----- > De: "Srikanth" > ?: compiler-dev at openjdk.java.net > Envoy?: Vendredi 6 Novembre 2015 07:09:46 > Objet: Re: javac doesn't generate the correct bytecode for lambda if the target type is an intersection type > > > > On Thursday 05 November 2015 03:07 PM, Remi Forax wrote: > > About this bug, > > https://bugs.openjdk.java.net/browse/JDK-8141508 > [...] > > I've already seen this bug somewhere but was not able to find a > > corresponding bug report in the database :( > > I think you are looking for > https://bugs.openjdk.java.net/browse/JDK-8049898 ? yes, you found it ! > > I have a candidate fix that addresses the above bug and the reduced test > case you have posted > but not yet the full test case in > https://bugs.openjdk.java.net/browse/JDK-8141508 > > I'll grab this one and take it to conclusion. > > Thanks! > Srikanth regards, R?mi > > > > > cheers, > > R?mi > > > > > > From srikanth.adayapalam at oracle.com Fri Nov 6 09:52:47 2015 From: srikanth.adayapalam at oracle.com (Srikanth) Date: Fri, 06 Nov 2015 15:22:47 +0530 Subject: javac doesn't generate the correct bytecode for lambda if the target type is an intersection type In-Reply-To: <1379049123.260565.1446794348156.JavaMail.zimbra@u-pem.fr> References: <564557894.2212535.1446716247203.JavaMail.zimbra@u-pem.fr> <563C442A.2070301@oracle.com> <1379049123.260565.1446794348156.JavaMail.zimbra@u-pem.fr> Message-ID: <563C786F.4050305@oracle.com> On Friday 06 November 2015 12:49 PM, Remi Forax wrote: > ----- Mail original ----- >> De: "Srikanth" >> ?: compiler-dev at openjdk.java.net >> Envoy?: Vendredi 6 Novembre 2015 07:09:46 >> Objet: Re: javac doesn't generate the correct bytecode for lambda if the target type is an intersection type >> >> >> >> On Thursday 05 November 2015 03:07 PM, Remi Forax wrote: >>> About this bug, >>> https://bugs.openjdk.java.net/browse/JDK-8141508 >> [...] >>> I've already seen this bug somewhere but was not able to find a >>> corresponding bug report in the database :( >> I think you are looking for >> https://bugs.openjdk.java.net/browse/JDK-8049898 ? > yes, you found it ! Thanks, this bug though open and is somewhat related is not reproducible as of JDK 9 b42. I'll locate the bug of which this was duplicate and close it. Srikanth >> I have a candidate fix that addresses the above bug and the reduced test >> case you have posted >> but not yet the full test case in >> https://bugs.openjdk.java.net/browse/JDK-8141508 >> >> I'll grab this one and take it to conclusion. >> >> Thanks! >> Srikanth > regards, > R?mi > >>> cheers, >>> R?mi >>> >>> >> From bitterfoxc at gmail.com Thu Nov 12 05:19:26 2015 From: bitterfoxc at gmail.com (ShinyaYoshida) Date: Thu, 12 Nov 2015 14:19:26 +0900 Subject: RFR 8142535: Compiler throws NPE when classpath includes "/" Message-ID: Hi, I found that javac throws NPE when the class path is "/" and have the fix and the test for this issue. Could you consider and review my patch? Webrev: http://cr.openjdk.java.net/~shinyafox/8142535/webrev.00/ Bugs: https://bugs.openjdk.java.net/browse/JDK-8142535 Regards, shinyafox(Shinya Yoshida) -------------- next part -------------- An HTML attachment was scrubbed... URL: From mark.reinhold at oracle.com Thu Nov 19 01:28:55 2015 From: mark.reinhold at oracle.com (mark.reinhold at oracle.com) Date: Wed, 18 Nov 2015 17:28:55 -0800 (PST) Subject: JEP 280: Indify String Concatenation Message-ID: <20151119012855.D501981AC8@eggemoggin.niobe.net> New JEP Candidate: http://openjdk.java.net/jeps/280 - Mark From aleksey.shipilev at oracle.com Thu Nov 19 20:58:06 2015 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Thu, 19 Nov 2015 23:58:06 +0300 Subject: Code (Pre-)Review for JEP 280: Indify String Concat Message-ID: <564E37DE.4070805@oracle.com> Hi, I would like to have a code pre-review for Indify String Concat changes. For the reference, the rationale, design constraints, etc. are outlined in the JEP itself: https://bugs.openjdk.java.net/browse/JDK-8085796 The experimental notes, including the bytecode shapes, benchmark data, and benchmark analysis, interaction with Compact Strings are here: http://cr.openjdk.java.net/~shade/8085796/notes.txt Javadoc (CCC is in progress): http://cr.openjdk.java.net/~shade/8085796/javadocs/StringConcatFactory.html === javac change: Webrev: http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.00/ A little guide: * We cut in at the same two points current javac does the String concat. But instead of emitting the StringBuilder append chains, we collect all arguments and hand them over to JDK's java.lang.invoke.StringConcatFactory. * The bytecode flavor is guarded by hidden -XDstringConcat option, with three possible values: inline, indy, indyWithConstants. "indyWithConstants" is selected as the default bytecode flavor. * Since a String concat expression may contain more operands than any Java call can manage, we sometimes have to peel the concat in several back-to-back calls, and concat-ting the results. That peeling is one-level, and can accommodate 200*200 = 40000 arguments, well beyond what can be achieved for a singular String concat expression (limited either by constant pool size, or by method code size). === JDK change: Webrev: http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.00/ A little guide: * The entry point is java.lang.invoke.StringConcatFactory. Its methods would be used as invokedynamic bootstrap methods, at least in javac. * There are multiple concatenation strategies supported by SCF. We explored the performance characteristics of all factories, chosen one performing good throughput- and startup-wise. All strategies are fully functional, covered by tests, and kept as the base for the future work and fine tuning. * Most strategies delegate to public StringBuilder API, which makes them quite simple, since they are not forced to deal with actual storage (this got complicated with Compact Strings). * The only strategy that builds the String directly is MH_INLINE_SIZED_EXACT strategy, and thus it is the most complicated of all. It uses private java.lang.StringConcatHelper class to get access to package-private (Integer|Long).(stringSize|getChar*) methods; the access to j.l.SCH is granted by a private lookup. * Some tests assume the particular code shape and/or invokedynamic counts, needed to fix those as well. === Build change (I don't copy build-dev@ to avoid spamming that list with langtools/jdk reviews; this section is FYI) Webrev: http://cr.openjdk.java.net/~shade/8085796/webrev.root.00/ * This one is simple: we exempt java.base and interim classes from Indy String Concat to avoid bootstrapping issues. Thanks, -Aleksey -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From luke-mail at online.de Mon Nov 23 13:35:33 2015 From: luke-mail at online.de (Lukas Magel) Date: Mon, 23 Nov 2015 14:35:33 +0100 Subject: Inverse annotation inheritance issue with generic interfaces Message-ID: <56531625.4090708@online.de> Hello, I am currently working on a Java EE web project and have been experiencing a compiler behavior which I don't know how to interpret. In our code we define interfaces like the following: public interface SampleInterface { public void sampleMethod(T t); } as well as an implementing class: public class Main implements SampleInterface { @SampleAnnotation public void sampleMethod(B t) { } } and the corresponding annotation: @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface SampleAnnotation { } Where Class B extends A. All classes are compiled using the OpenJDK compiler. If I use Reflection to retrieve all methods of the Main class at runtime and print each method with its annotations I get the following list of methods: class Main public void Main.sampleMethod(A) @SampleAnnotation() public void Main.sampleMethod(B) @SampleAnnotation() The compiler will assign the annotation to the method declaration of the interface although the annotation is only declared in the implementing class. I cannot reproduce this behavior with the Oracle Java Compiler or the Eclipse JDT Compiler. If I compile the example with one of the two compilers the resulting program will yield the following result: class annotation.Main public void Main.sampleMethod(A) public void Main.sampleMethod(B) @SampleAnnotation() The JRE type (Oracle, OpenJDK) that the program is executed with has no influence on the result. This behavior is reproducible with the following constellations: JDK Operating System Hardware 1.7.0_85 Ubuntu 14.04.03 x86-64 1.7.0_91 Arch Linux x86-64 1.8.0_66 Arch Linux x86-64 It is NOT reproducible with the following constellation: 1.7.0_51 Ubuntu 13.04 x86-64 My actual question is whether this behavior is intended or not. It causes quite some issues with our Jax-RS REST implementations. All REST classes each implement an interface like the one above and are annotated with multiple annotations to allow the container to identify endpoints at runtime. The Jax-RS framework uses reflection to determine possible method candidates at runtime and will happily accept both the generic and the special method since both of them carry the annotations. I can also provide an example project if necessary. Thanks, Lukas From alex.buckley at oracle.com Mon Nov 23 20:41:26 2015 From: alex.buckley at oracle.com (Alex Buckley) Date: Mon, 23 Nov 2015 12:41:26 -0800 Subject: Inverse annotation inheritance issue with generic interfaces In-Reply-To: <56531625.4090708@online.de> References: <56531625.4090708@online.de> Message-ID: <565379F6.3040608@oracle.com> Enumerating the methods of Main.class shouldn't reveal sampleMethod(A), since sampleMethod(B) overrides it. I suspect a bridge method bug is being tickled, probably in Core Reflection rather than javac. What is the full javap output for Main.class as compiled with Oracle JDK 1.7.0_51 versus Oracle JDK 1.7.0_85 ? (Plain text inline, please.) Alex On 11/23/2015 5:35 AM, Lukas Magel wrote: > Hello, > > I am currently working on a Java EE web project and have been > experiencing a compiler behavior which I don't know how to interpret. > > In our code we define interfaces like the following: > > public interface SampleInterface { > > public void sampleMethod(T t); > > } > > as well as an implementing class: > > public class Main implements SampleInterface { > > @SampleAnnotation > public void sampleMethod(B t) { > > } > } > > and the corresponding annotation: > > @Retention(RetentionPolicy.RUNTIME) > @Target(ElementType.METHOD) > public @interface SampleAnnotation { > > } > > Where Class B extends A. All classes are compiled using the OpenJDK > compiler. If I use Reflection to retrieve all methods of the Main class > at runtime and print each method with its annotations I get the > following list of methods: > > class Main > > public void Main.sampleMethod(A) > @SampleAnnotation() > > public void Main.sampleMethod(B) > @SampleAnnotation() > > The compiler will assign the annotation to the method declaration of the > interface although the annotation is only declared in the implementing > class. I cannot reproduce this behavior with the Oracle Java Compiler or > the Eclipse JDT Compiler. If I compile the example with one of the two > compilers the resulting program will yield the following result: > > class annotation.Main > > public void Main.sampleMethod(A) > > public void Main.sampleMethod(B) > @SampleAnnotation() > > The JRE type (Oracle, OpenJDK) that the program is executed with has no > influence on the result. > > This behavior is reproducible with the following constellations: > JDK Operating System Hardware > 1.7.0_85 Ubuntu 14.04.03 x86-64 > 1.7.0_91 Arch Linux x86-64 > 1.8.0_66 Arch Linux x86-64 > > It is NOT reproducible with the following constellation: > 1.7.0_51 Ubuntu 13.04 x86-64 > > My actual question is whether this behavior is intended or not. It > causes quite some issues with our Jax-RS REST implementations. All REST > classes each implement an interface like the one above and are annotated > with multiple annotations to allow the container to identify endpoints > at runtime. The Jax-RS framework uses reflection to determine possible > method candidates at runtime and will happily accept both the generic > and the special method since both of them carry the annotations. > > I can also provide an example project if necessary. > > Thanks, > Lukas From maurizio.cimadamore at oracle.com Mon Nov 23 21:50:15 2015 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 23 Nov 2015 21:50:15 +0000 Subject: Inverse annotation inheritance issue with generic interfaces In-Reply-To: <565379F6.3040608@oracle.com> References: <56531625.4090708@online.de> <565379F6.3040608@oracle.com> Message-ID: <56538A17.7000803@oracle.com> On 23/11/15 20:41, Alex Buckley wrote: > Enumerating the methods of Main.class shouldn't reveal > sampleMethod(A), since sampleMethod(B) overrides it. I suspect a > bridge method bug is being tickled, probably in Core Reflection rather > than javac. Not sure what you mean here - as far as I recall, reflection always listed all methods (bridges included) in a given class. I think what is being observed is this: https://bugs.openjdk.java.net/browse/JDK-669537 Which I think was a legitimate fix - the callee probably wants to be able to retrieve all applicable annotations, regardless of whether it accidentally hit the bridge doing the reflective lookup. Maurizio > What is the full javap output for Main.class as compiled with Oracle > JDK 1.7.0_51 versus Oracle JDK 1.7.0_85 ? (Plain text inline, please.) > > Alex > > On 11/23/2015 5:35 AM, Lukas Magel wrote: >> Hello, >> >> I am currently working on a Java EE web project and have been >> experiencing a compiler behavior which I don't know how to interpret. >> >> In our code we define interfaces like the following: >> >> public interface SampleInterface { >> >> public void sampleMethod(T t); >> >> } >> >> as well as an implementing class: >> >> public class Main implements SampleInterface { >> >> @SampleAnnotation >> public void sampleMethod(B t) { >> >> } >> } >> >> and the corresponding annotation: >> >> @Retention(RetentionPolicy.RUNTIME) >> @Target(ElementType.METHOD) >> public @interface SampleAnnotation { >> >> } >> >> Where Class B extends A. All classes are compiled using the OpenJDK >> compiler. If I use Reflection to retrieve all methods of the Main class >> at runtime and print each method with its annotations I get the >> following list of methods: >> >> class Main >> >> public void Main.sampleMethod(A) >> @SampleAnnotation() >> >> public void Main.sampleMethod(B) >> @SampleAnnotation() >> >> The compiler will assign the annotation to the method declaration of the >> interface although the annotation is only declared in the implementing >> class. I cannot reproduce this behavior with the Oracle Java Compiler or >> the Eclipse JDT Compiler. If I compile the example with one of the two >> compilers the resulting program will yield the following result: >> >> class annotation.Main >> >> public void Main.sampleMethod(A) >> >> public void Main.sampleMethod(B) >> @SampleAnnotation() >> >> The JRE type (Oracle, OpenJDK) that the program is executed with has no >> influence on the result. >> >> This behavior is reproducible with the following constellations: >> JDK Operating System Hardware >> 1.7.0_85 Ubuntu 14.04.03 x86-64 >> 1.7.0_91 Arch Linux x86-64 >> 1.8.0_66 Arch Linux x86-64 >> >> It is NOT reproducible with the following constellation: >> 1.7.0_51 Ubuntu 13.04 x86-64 >> >> My actual question is whether this behavior is intended or not. It >> causes quite some issues with our Jax-RS REST implementations. All REST >> classes each implement an interface like the one above and are annotated >> with multiple annotations to allow the container to identify endpoints >> at runtime. The Jax-RS framework uses reflection to determine possible >> method candidates at runtime and will happily accept both the generic >> and the special method since both of them carry the annotations. >> >> I can also provide an example project if necessary. >> >> Thanks, >> Lukas From luke-mail at online.de Mon Nov 23 22:43:00 2015 From: luke-mail at online.de (Lukas Magel) Date: Mon, 23 Nov 2015 23:43:00 +0100 Subject: Inverse annotation inheritance issue with generic interfaces In-Reply-To: <565379F6.3040608@oracle.com> References: <56531625.4090708@online.de> <565379F6.3040608@oracle.com> Message-ID: <56539674.6030504@online.de> In the listing in my previous e-mail I forgot to mention that the OpenJDK was used for all constellations. Here's the javap output for the Main class compiled with OpenJDK version 1.7.0_51 vs 1.7.0_85. I hope this is correct. I only compiled the test project once using the Oracle JDK 7u79 to cross-check but was unable to reproduce the issue. 1.7.0_51 Classfile Main.class Last modified Nov 23, 2015; size 1155 bytes MD5 checksum 24e9fdb3ed8e97132f012579dadbbf90 Compiled from "Main.java" public class Main extends java.lang.Object implements SampleInterface Signature: #29 // Ljava/lang/Object;LSampleInterface; SourceFile: "Main.java" minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #9.#32 // java/lang/Object."":()V #2 = Class #33 // Main #3 = Fieldref #34.#35 // java/lang/System.out:Ljava/io/PrintStream; #4 = Methodref #36.#37 // java/io/PrintStream.println:(Ljava/lang/Object;)V #5 = Methodref #38.#39 // java/lang/Class.getMethods:()[Ljava/lang/reflect/Method; #6 = Methodref #40.#41 // java/lang/reflect/Method.getAnnotations:()[Ljava/lang/annotation/Annotation; #7 = Class #42 // B #8 = Methodref #2.#43 // Main.sampleMethod:(LB;)V #9 = Class #44 // java/lang/Object #10 = Class #45 // SampleInterface #11 = Utf8 #12 = Utf8 ()V #13 = Utf8 Code #14 = Utf8 LineNumberTable #15 = Utf8 main #16 = Utf8 ([Ljava/lang/String;)V #17 = Utf8 StackMapTable #18 = Class #46 // "[Ljava/lang/String;" #19 = Class #47 // java/lang/Class #20 = Class #48 // "[Ljava/lang/reflect/Method;" #21 = Class #49 // java/lang/reflect/Method #22 = Class #50 // "[Ljava/lang/annotation/Annotation;" #23 = Utf8 sampleMethod #24 = Utf8 (LB;)V #25 = Utf8 RuntimeVisibleAnnotations #26 = Utf8 LSampleAnnotation; #27 = Utf8 (LA;)V #28 = Utf8 Signature #29 = Utf8 Ljava/lang/Object;LSampleInterface; #30 = Utf8 SourceFile #31 = Utf8 Main.java #32 = NameAndType #11:#12 // "":()V #33 = Utf8 Main #34 = Class #51 // java/lang/System #35 = NameAndType #52:#53 // out:Ljava/io/PrintStream; #36 = Class #54 // java/io/PrintStream #37 = NameAndType #55:#56 // println:(Ljava/lang/Object;)V #38 = Class #47 // java/lang/Class #39 = NameAndType #57:#58 // getMethods:()[Ljava/lang/reflect/Method; #40 = Class #49 // java/lang/reflect/Method #41 = NameAndType #59:#60 // getAnnotations:()[Ljava/lang/annotation/Annotation; #42 = Utf8 B #43 = NameAndType #23:#24 // sampleMethod:(LB;)V #44 = Utf8 java/lang/Object #45 = Utf8 SampleInterface #46 = Utf8 [Ljava/lang/String; #47 = Utf8 java/lang/Class #48 = Utf8 [Ljava/lang/reflect/Method; #49 = Utf8 java/lang/reflect/Method #50 = Utf8 [Ljava/lang/annotation/Annotation; #51 = Utf8 java/lang/System #52 = Utf8 out #53 = Utf8 Ljava/io/PrintStream; #54 = Utf8 java/io/PrintStream #55 = Utf8 println #56 = Utf8 (Ljava/lang/Object;)V #57 = Utf8 getMethods #58 = Utf8 ()[Ljava/lang/reflect/Method; #59 = Utf8 getAnnotations #60 = Utf8 ()[Ljava/lang/annotation/Annotation; { public Main(); Signature: ()V flags: ACC_PUBLIC LineNumberTable: line 6: 0 Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return LineNumberTable: line 6: 0 public static void main(java.lang.String[]); Signature: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC LineNumberTable: line 9: 0 line 10: 4 line 11: 11 line 12: 34 line 13: 42 line 14: 71 line 13: 79 line 11: 85 line 17: 91 Code: stack=2, locals=10, args_size=1 0: ldc_w #2 // class Main 3: astore_1 4: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 7: aload_1 8: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V 11: aload_1 12: invokevirtual #5 // Method java/lang/Class.getMethods:()[Ljava/lang/reflect/Method; 15: astore_2 16: aload_2 17: arraylength 18: istore_3 19: iconst_0 20: istore 4 22: iload 4 24: iload_3 25: if_icmpge 91 28: aload_2 29: iload 4 31: aaload 32: astore 5 34: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 37: aload 5 39: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V 42: aload 5 44: invokevirtual #6 // Method java/lang/reflect/Method.getAnnotations:()[Ljava/lang/annotation/Annotation; 47: astore 6 49: aload 6 51: arraylength 52: istore 7 54: iconst_0 55: istore 8 57: iload 8 59: iload 7 61: if_icmpge 85 64: aload 6 66: iload 8 68: aaload 69: astore 9 71: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 74: aload 9 76: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V 79: iinc 8, 1 82: goto 57 85: iinc 4, 1 88: goto 22 91: return LineNumberTable: line 9: 0 line 10: 4 line 11: 11 line 12: 34 line 13: 42 line 14: 71 line 13: 79 line 11: 85 line 17: 91 StackMapTable: number_of_entries = 4 frame_type = 255 /* full_frame */ offset_delta = 22 locals = [ class "[Ljava/lang/String;", class java/lang/Class, class "[Ljava/lang/reflect/Method;", int, int ] stack = [] frame_type = 255 /* full_frame */ offset_delta = 34 locals = [ class "[Ljava/lang/String;", class java/lang/Class, class "[Ljava/lang/reflect/Method;", int, int, class java/lang/reflect/Method, class "[Ljava/lang/annotation/Annotation;", int, int ] stack = [] frame_type = 255 /* full_frame */ offset_delta = 27 locals = [ class "[Ljava/lang/String;", class java/lang/Class, class "[Ljava/lang/reflect/Method;", int, int ] stack = [] frame_type = 248 /* chop */ offset_delta = 5 public void sampleMethod(B); Signature: (LB;)V flags: ACC_PUBLIC LineNumberTable: line 23: 0 Code: stack=0, locals=2, args_size=2 0: return LineNumberTable: line 23: 0 RuntimeVisibleAnnotations: 0: #26() public void sampleMethod(A); Signature: (LA;)V flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC LineNumberTable: line 6: 0 Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 2: checkcast #7 // class B 5: invokevirtual #8 // Method sampleMethod:(LB;)V 8: return LineNumberTable: line 6: 0 } 1.7.0_85 Classfile Main.class Last modified Nov 23, 2015; size 1167 bytes MD5 checksum a4f2d871550c785d2a87a21bd34bd1fb Compiled from "Main.java" public class Main extends java.lang.Object implements SampleInterface Signature: #29 // Ljava/lang/Object;LSampleInterface; SourceFile: "Main.java" minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #9.#32 // java/lang/Object."":()V #2 = Class #33 // Main #3 = Fieldref #34.#35 // java/lang/System.out:Ljava/io/PrintStream; #4 = Methodref #36.#37 // java/io/PrintStream.println:(Ljava/lang/Object;)V #5 = Methodref #38.#39 // java/lang/Class.getMethods:()[Ljava/lang/reflect/Method; #6 = Methodref #40.#41 // java/lang/reflect/Method.getAnnotations:()[Ljava/lang/annotation/Annotation; #7 = Class #42 // B #8 = Methodref #2.#43 // Main.sampleMethod:(LB;)V #9 = Class #44 // java/lang/Object #10 = Class #45 // SampleInterface #11 = Utf8 #12 = Utf8 ()V #13 = Utf8 Code #14 = Utf8 LineNumberTable #15 = Utf8 main #16 = Utf8 ([Ljava/lang/String;)V #17 = Utf8 StackMapTable #18 = Class #46 // "[Ljava/lang/String;" #19 = Class #47 // java/lang/Class #20 = Class #48 // "[Ljava/lang/reflect/Method;" #21 = Class #49 // java/lang/reflect/Method #22 = Class #50 // "[Ljava/lang/annotation/Annotation;" #23 = Utf8 sampleMethod #24 = Utf8 (LB;)V #25 = Utf8 RuntimeVisibleAnnotations #26 = Utf8 LSampleAnnotation; #27 = Utf8 (LA;)V #28 = Utf8 Signature #29 = Utf8 Ljava/lang/Object;LSampleInterface; #30 = Utf8 SourceFile #31 = Utf8 Main.java #32 = NameAndType #11:#12 // "":()V #33 = Utf8 Main #34 = Class #51 // java/lang/System #35 = NameAndType #52:#53 // out:Ljava/io/PrintStream; #36 = Class #54 // java/io/PrintStream #37 = NameAndType #55:#56 // println:(Ljava/lang/Object;)V #38 = Class #47 // java/lang/Class #39 = NameAndType #57:#58 // getMethods:()[Ljava/lang/reflect/Method; #40 = Class #49 // java/lang/reflect/Method #41 = NameAndType #59:#60 // getAnnotations:()[Ljava/lang/annotation/Annotation; #42 = Utf8 B #43 = NameAndType #23:#24 // sampleMethod:(LB;)V #44 = Utf8 java/lang/Object #45 = Utf8 SampleInterface #46 = Utf8 [Ljava/lang/String; #47 = Utf8 java/lang/Class #48 = Utf8 [Ljava/lang/reflect/Method; #49 = Utf8 java/lang/reflect/Method #50 = Utf8 [Ljava/lang/annotation/Annotation; #51 = Utf8 java/lang/System #52 = Utf8 out #53 = Utf8 Ljava/io/PrintStream; #54 = Utf8 java/io/PrintStream #55 = Utf8 println #56 = Utf8 (Ljava/lang/Object;)V #57 = Utf8 getMethods #58 = Utf8 ()[Ljava/lang/reflect/Method; #59 = Utf8 getAnnotations #60 = Utf8 ()[Ljava/lang/annotation/Annotation; { public Main(); Signature: ()V flags: ACC_PUBLIC LineNumberTable: line 6: 0 Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return LineNumberTable: line 6: 0 public static void main(java.lang.String[]); Signature: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC LineNumberTable: line 9: 0 line 10: 4 line 11: 11 line 12: 34 line 13: 42 line 14: 71 line 13: 79 line 11: 85 line 17: 91 Code: stack=2, locals=10, args_size=1 0: ldc_w #2 // class Main 3: astore_1 4: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 7: aload_1 8: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V 11: aload_1 12: invokevirtual #5 // Method java/lang/Class.getMethods:()[Ljava/lang/reflect/Method; 15: astore_2 16: aload_2 17: arraylength 18: istore_3 19: iconst_0 20: istore 4 22: iload 4 24: iload_3 25: if_icmpge 91 28: aload_2 29: iload 4 31: aaload 32: astore 5 34: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 37: aload 5 39: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V 42: aload 5 44: invokevirtual #6 // Method java/lang/reflect/Method.getAnnotations:()[Ljava/lang/annotation/Annotation; 47: astore 6 49: aload 6 51: arraylength 52: istore 7 54: iconst_0 55: istore 8 57: iload 8 59: iload 7 61: if_icmpge 85 64: aload 6 66: iload 8 68: aaload 69: astore 9 71: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 74: aload 9 76: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V 79: iinc 8, 1 82: goto 57 85: iinc 4, 1 88: goto 22 91: return LineNumberTable: line 9: 0 line 10: 4 line 11: 11 line 12: 34 line 13: 42 line 14: 71 line 13: 79 line 11: 85 line 17: 91 StackMapTable: number_of_entries = 4 frame_type = 255 /* full_frame */ offset_delta = 22 locals = [ class "[Ljava/lang/String;", class java/lang/Class, class "[Ljava/lang/reflect/Method;", int, int ] stack = [] frame_type = 255 /* full_frame */ offset_delta = 34 locals = [ class "[Ljava/lang/String;", class java/lang/Class, class "[Ljava/lang/reflect/Method;", int, int, class java/lang/reflect/Method, class "[Ljava/lang/annotation/Annotation;", int, int ] stack = [] frame_type = 255 /* full_frame */ offset_delta = 27 locals = [ class "[Ljava/lang/String;", class java/lang/Class, class "[Ljava/lang/reflect/Method;", int, int ] stack = [] frame_type = 248 /* chop */ offset_delta = 5 public void sampleMethod(B); Signature: (LB;)V flags: ACC_PUBLIC LineNumberTable: line 23: 0 Code: stack=0, locals=2, args_size=2 0: return LineNumberTable: line 23: 0 RuntimeVisibleAnnotations: 0: #26() public void sampleMethod(A); Signature: (LA;)V flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC LineNumberTable: line 6: 0 Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 2: checkcast #7 // class B 5: invokevirtual #8 // Method sampleMethod:(LB;)V 8: return LineNumberTable: line 6: 0 RuntimeVisibleAnnotations: 0: #26() } On 23.11.2015 21:41, Alex Buckley wrote: > Enumerating the methods of Main.class shouldn't reveal > sampleMethod(A), since sampleMethod(B) overrides it. I suspect a > bridge method bug is being tickled, probably in Core Reflection rather > than javac. > > What is the full javap output for Main.class as compiled with Oracle > JDK 1.7.0_51 versus Oracle JDK 1.7.0_85 ? (Plain text inline, please.) > > Alex > > On 11/23/2015 5:35 AM, Lukas Magel wrote: >> Hello, >> >> I am currently working on a Java EE web project and have been >> experiencing a compiler behavior which I don't know how to interpret. >> >> In our code we define interfaces like the following: >> >> public interface SampleInterface { >> >> public void sampleMethod(T t); >> >> } >> >> as well as an implementing class: >> >> public class Main implements SampleInterface { >> >> @SampleAnnotation >> public void sampleMethod(B t) { >> >> } >> } >> >> and the corresponding annotation: >> >> @Retention(RetentionPolicy.RUNTIME) >> @Target(ElementType.METHOD) >> public @interface SampleAnnotation { >> >> } >> >> Where Class B extends A. All classes are compiled using the OpenJDK >> compiler. If I use Reflection to retrieve all methods of the Main class >> at runtime and print each method with its annotations I get the >> following list of methods: >> >> class Main >> >> public void Main.sampleMethod(A) >> @SampleAnnotation() >> >> public void Main.sampleMethod(B) >> @SampleAnnotation() >> >> The compiler will assign the annotation to the method declaration of the >> interface although the annotation is only declared in the implementing >> class. I cannot reproduce this behavior with the Oracle Java Compiler or >> the Eclipse JDT Compiler. If I compile the example with one of the two >> compilers the resulting program will yield the following result: >> >> class annotation.Main >> >> public void Main.sampleMethod(A) >> >> public void Main.sampleMethod(B) >> @SampleAnnotation() >> >> The JRE type (Oracle, OpenJDK) that the program is executed with has no >> influence on the result. >> >> This behavior is reproducible with the following constellations: >> JDK Operating System Hardware >> 1.7.0_85 Ubuntu 14.04.03 x86-64 >> 1.7.0_91 Arch Linux x86-64 >> 1.8.0_66 Arch Linux x86-64 >> >> It is NOT reproducible with the following constellation: >> 1.7.0_51 Ubuntu 13.04 x86-64 >> >> My actual question is whether this behavior is intended or not. It >> causes quite some issues with our Jax-RS REST implementations. All REST >> classes each implement an interface like the one above and are annotated >> with multiple annotations to allow the container to identify endpoints >> at runtime. The Jax-RS framework uses reflection to determine possible >> method candidates at runtime and will happily accept both the generic >> and the special method since both of them carry the annotations. >> >> I can also provide an example project if necessary. >> >> Thanks, >> Lukas From alex.buckley at oracle.com Tue Nov 24 00:09:44 2015 From: alex.buckley at oracle.com (Alex Buckley) Date: Mon, 23 Nov 2015 16:09:44 -0800 Subject: Inverse annotation inheritance issue with generic interfaces In-Reply-To: <56538A17.7000803@oracle.com> References: <56531625.4090708@online.de> <565379F6.3040608@oracle.com> <56538A17.7000803@oracle.com> Message-ID: <5653AAC8.7070508@oracle.com> On 11/23/2015 1:50 PM, Maurizio Cimadamore wrote: > On 23/11/15 20:41, Alex Buckley wrote: >> Enumerating the methods of Main.class shouldn't reveal >> sampleMethod(A), since sampleMethod(B) overrides it. I suspect a >> bridge method bug is being tickled, probably in Core Reflection rather >> than javac. > Not sure what you mean here - as far as I recall, reflection always > listed all methods (bridges included) in a given class. Hard to confirm from the javadoc (as usual), but I imagine you're right. > I think what is being observed is this: > > https://bugs.openjdk.java.net/browse/JDK-669537 > > Which I think was a legitimate fix - the callee probably wants to be > able to retrieve all applicable annotations, regardless of whether it > accidentally hit the bridge doing the reflective lookup. I guess the fix was to emit the RuntimeVisibleAnnotations attribute for the bridge method sampleMethod(A) -- the change from non-emission (in 1.7.0_51) to emission (in 1.7.0_85) is visible in Lukas' javap output. Ah, and here's the thread from exactly two years ago: Annotations on return-overridden methods also end up on bridge methods http://mail.openjdk.java.net/pipermail/compiler-dev/2013-November/008147.html So Lukas, the behavior is intended. See https://bugs.openjdk.java.net/browse/JDK-6695379 for more. Alex > Maurizio >> What is the full javap output for Main.class as compiled with Oracle >> JDK 1.7.0_51 versus Oracle JDK 1.7.0_85 ? (Plain text inline, please.) >> >> Alex >> >> On 11/23/2015 5:35 AM, Lukas Magel wrote: >>> Hello, >>> >>> I am currently working on a Java EE web project and have been >>> experiencing a compiler behavior which I don't know how to interpret. >>> >>> In our code we define interfaces like the following: >>> >>> public interface SampleInterface { >>> >>> public void sampleMethod(T t); >>> >>> } >>> >>> as well as an implementing class: >>> >>> public class Main implements SampleInterface { >>> >>> @SampleAnnotation >>> public void sampleMethod(B t) { >>> >>> } >>> } >>> >>> and the corresponding annotation: >>> >>> @Retention(RetentionPolicy.RUNTIME) >>> @Target(ElementType.METHOD) >>> public @interface SampleAnnotation { >>> >>> } >>> >>> Where Class B extends A. All classes are compiled using the OpenJDK >>> compiler. If I use Reflection to retrieve all methods of the Main class >>> at runtime and print each method with its annotations I get the >>> following list of methods: >>> >>> class Main >>> >>> public void Main.sampleMethod(A) >>> @SampleAnnotation() >>> >>> public void Main.sampleMethod(B) >>> @SampleAnnotation() >>> >>> The compiler will assign the annotation to the method declaration of the >>> interface although the annotation is only declared in the implementing >>> class. I cannot reproduce this behavior with the Oracle Java Compiler or >>> the Eclipse JDT Compiler. If I compile the example with one of the two >>> compilers the resulting program will yield the following result: >>> >>> class annotation.Main >>> >>> public void Main.sampleMethod(A) >>> >>> public void Main.sampleMethod(B) >>> @SampleAnnotation() >>> >>> The JRE type (Oracle, OpenJDK) that the program is executed with has no >>> influence on the result. >>> >>> This behavior is reproducible with the following constellations: >>> JDK Operating System Hardware >>> 1.7.0_85 Ubuntu 14.04.03 x86-64 >>> 1.7.0_91 Arch Linux x86-64 >>> 1.8.0_66 Arch Linux x86-64 >>> >>> It is NOT reproducible with the following constellation: >>> 1.7.0_51 Ubuntu 13.04 x86-64 >>> >>> My actual question is whether this behavior is intended or not. It >>> causes quite some issues with our Jax-RS REST implementations. All REST >>> classes each implement an interface like the one above and are annotated >>> with multiple annotations to allow the container to identify endpoints >>> at runtime. The Jax-RS framework uses reflection to determine possible >>> method candidates at runtime and will happily accept both the generic >>> and the special method since both of them carry the annotations. >>> >>> I can also provide an example project if necessary. >>> >>> Thanks, >>> Lukas > From paul.sandoz at oracle.com Tue Nov 24 14:16:57 2015 From: paul.sandoz at oracle.com (Paul Sandoz) Date: Tue, 24 Nov 2015 15:16:57 +0100 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <564E37DE.4070805@oracle.com> References: <564E37DE.4070805@oracle.com> Message-ID: <962091CF-4D6C-4EFF-8343-53FCD85B55FE@oracle.com> > On 19 Nov 2015, at 21:58, Aleksey Shipilev wrote: > > Hi, > > I would like to have a code pre-review for Indify String Concat changes. > For the reference, the rationale, design constraints, etc. are outlined > in the JEP itself: > https://bugs.openjdk.java.net/browse/JDK-8085796 > > The experimental notes, including the bytecode shapes, benchmark data, > and benchmark analysis, interaction with Compact Strings are here: > http://cr.openjdk.java.net/~shade/8085796/notes.txt > > Javadoc (CCC is in progress): > > http://cr.openjdk.java.net/~shade/8085796/javadocs/StringConcatFactory.html > > > === javac change: > > Webrev: > http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.00/ > I am not a langtools expert but the code made sense to me (as i have dabbled in hacking javac to generate indy) Gen ? 134 if ("inline".equals(concat)) { 135 allowIndyStringConcat = false; 136 indyStringConcatConstants = false; 137 } else if ("indy".equals(concat)) { 138 allowIndyStringConcat = true; 139 indyStringConcatConstants = false; 140 } else if ("indyWithConstants".equals(concat)) { 141 allowIndyStringConcat = true; 142 indyStringConcatConstants = true; 143 } else { 144 Assert.error("Unknown stringConcat: " + concat); 145 throw new IllegalStateException("Unknown stringConcat: " + concat); 146 } If you are in anyway inclined you could use a switch on concat. I have a marginal preference for an enum StringConcatStrategy with StringBuilder, Indy, IndyWithConstants values. But i will defer to other javac reviewers. > A little guide: > > * We cut in at the same two points current javac does the String > concat. But instead of emitting the StringBuilder append chains, we > collect all arguments and hand them over to JDK's > java.lang.invoke.StringConcatFactory. > > * The bytecode flavor is guarded by hidden -XDstringConcat option, with > three possible values: inline, indy, indyWithConstants. > "indyWithConstants" is selected as the default bytecode flavor. > > * Since a String concat expression may contain more operands than any > Java call can manage, we sometimes have to peel the concat in several > back-to-back calls, and concat-ting the results. That peeling is > one-level, and can accommodate 200*200 = 40000 arguments, well beyond > what can be achieved for a singular String concat expression (limited > either by constant pool size, or by method code size). > > > === JDK change: > > Webrev: > http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.00/ > StringConcatFactory ? 187 final String key = "java.lang.invoke.stringConcat.debug"; 188 String str = AccessController.doPrivileged( 189 new GetPropertyAction(key), null, 190 new PropertyPermission(key, "read")); 191 DEBUG = Boolean.valueOf(str); See also Boolean.getBoolean My inclination would be to consolidate all the sys props under one doPriv block. 200 private static final Map CACHE; ConcurrentMap? To make it clearer that this is operated on concurrently. 287 elements = new ArrayList<>(el); 288 Collections.reverse(el); 289 elementsRev = new ArrayList<>(el); elementsRev = e1? It?s mildly surprising that there is no supported way to create a reverse view of a ListIterator. 408 if (DEBUG) { 409 System.out.println("StringConcatFactory " + STRATEGY + " is here for " + argTypes); 410 } No recursion! :-) 530 if (caller == null) { 531 throw new StringConcatException("Lookup is null"); 532 } 533 534 if (name == null) { 535 throw new StringConcatException("Name is null"); 536 } 537 538 if (argTypes == null) { 539 throw new StringConcatException("Argument types are null"); 540 } It?s odd to not see NPEs being used instead. Can the generated class extend from an existing compiled class or reuse static method calls of another class? then it might be possible to move ASM generation of debug code into java source code. Here is a wild thought, i dunno if it makes any difference. U.defineAnonymousClass allows one to patch the constant pool, so the string constants could be patched in. You seem to be hedging your bets about what static strategy to choose. Do you intend to whittle down the strategies over time? Same argument applies to caching. Some time before the JDK 9 release it would be good to reduce the scope. Do you anticipate it might be possible to reduce the scope of the existing JIT optimisations? Paul. > A little guide: > > * The entry point is java.lang.invoke.StringConcatFactory. Its methods > would be used as invokedynamic bootstrap methods, at least in javac. > > * There are multiple concatenation strategies supported by SCF. We > explored the performance characteristics of all factories, chosen one > performing good throughput- and startup-wise. All strategies are fully > functional, covered by tests, and kept as the base for the future work > and fine tuning. > > * Most strategies delegate to public StringBuilder API, which makes > them quite simple, since they are not forced to deal with actual storage > (this got complicated with Compact Strings). > > * The only strategy that builds the String directly is > MH_INLINE_SIZED_EXACT strategy, and thus it is the most complicated of > all. It uses private java.lang.StringConcatHelper class to get access to > package-private (Integer|Long).(stringSize|getChar*) methods; the access > to j.l.SCH is granted by a private lookup. > > * Some tests assume the particular code shape and/or invokedynamic > counts, needed to fix those as well. > > === Build change > > (I don't copy build-dev@ to avoid spamming that list with langtools/jdk > reviews; this section is FYI) > > Webrev: > http://cr.openjdk.java.net/~shade/8085796/webrev.root.00/ > > * This one is simple: we exempt java.base and interim classes from Indy > String Concat to avoid bootstrapping issues. > > > Thanks, > -Aleksey > -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 841 bytes Desc: Message signed with OpenPGP using GPGMail URL: From aleksey.shipilev at oracle.com Tue Nov 24 22:30:19 2015 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Wed, 25 Nov 2015 01:30:19 +0300 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <962091CF-4D6C-4EFF-8343-53FCD85B55FE@oracle.com> References: <564E37DE.4070805@oracle.com> <962091CF-4D6C-4EFF-8343-53FCD85B55FE@oracle.com> Message-ID: <5654E4FB.6070200@oracle.com> Hi Paul, Thanks for the review! Updated webrevs: http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.01/ http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.01/ More reviews, please :) Comments below: On 11/24/2015 05:16 PM, Paul Sandoz wrote: >> On 19 Nov 2015, at 21:58, Aleksey Shipilev wrote: >> Webrev: >> http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.00/ > ? > > 134 if ("inline".equals(concat)) { > 135 allowIndyStringConcat = false; > 136 indyStringConcatConstants = false; > 137 } else if ("indy".equals(concat)) { > 138 allowIndyStringConcat = true; > 139 indyStringConcatConstants = false; > 140 } else if ("indyWithConstants".equals(concat)) { > 141 allowIndyStringConcat = true; > 142 indyStringConcatConstants = true; > 143 } else { > 144 Assert.error("Unknown stringConcat: " + concat); > 145 throw new IllegalStateException("Unknown stringConcat: " + concat); > 146 } > > If you are in anyway inclined you could use a switch on concat. Yes, I was trying not to use (ahem) "new" language features in a language compiler. But it seems javac uses String switches everywhere. Fixed. > I have a marginal preference for an enum StringConcatStrategy with StringBuilder, Indy, IndyWithConstants values. But i will defer to other javac reviewers. I think string values are fine, also because -XD options seem to be Stringly-typed anyhow. >> Webrev: >> http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.00/ >> > My inclination would be to consolidate all the sys props under one doPriv block. Yes, done. > 200 private static final Map CACHE; > > ConcurrentMap? To make it clearer that this is operated on concurrently. Yes. Fixed. > 287 elements = new ArrayList<>(el); > 288 Collections.reverse(el); > 289 elementsRev = new ArrayList<>(el); > > elementsRev = e1? Yes. Fixed. > It?s mildly surprising that there is no supported way to create a reverse view of a ListIterator. > 408 if (DEBUG) { > 409 System.out.println("StringConcatFactory " + STRATEGY + " is here for " + argTypes); > 410 } > > No recursion! :-) Yeah, this code is exempted from Indified String Concat to avoid circularity ;) > > 530 if (caller == null) { > 531 throw new StringConcatException("Lookup is null"); > 532 } > 533 > 534 if (name == null) { > 535 throw new StringConcatException("Name is null"); > 536 } > 537 > 538 if (argTypes == null) { > 539 throw new StringConcatException("Argument types are null"); > 540 } > > It?s odd to not see NPEs being used instead. Yes, should have used Objects.requireNonNull. The NPE exceptions would not ever fire if you invoke BSM through invokedynamic anyhow. Fixed. > Can the generated class extend from an existing compiled class or > reuse static method calls of another class? then it might be possible > to move ASM generation of debug code into java source code. In theory, it can, but I would like to avoid that. The debugging bytecode is not really complicated to warrant moving to a separate Java source file (which should probably required to be public to begin with) and blow up the implementation complexity. MethodHandle-based strategies already do something similar to what you are proposing, but they can use look up private methods. > Here is a wild thought, i dunno if it makes any difference. > U.defineAnonymousClass allows one to patch the constant pool, so the > string constants could be patched in. See! You can experiment with wild ideas like these after the infrastructure lands in JDK. > You seem to be hedging your bets about what static strategy to > choose. Do you intend to whittle down the strategies over time? Same > argument applies to caching. Some time before the JDK 9 release it > would be good to reduce the scope. My rationale for keeping all strategies untouched is based on the premise that most improvements in strategies would probably be some form of existing strategies, and having all strategies handy and tested simplifies improvements. Also, we may have to do a real-life experiments for choosing a better default strategy. > Do you anticipate it might be possible to reduce the scope of the > existing JIT optimisations? Yes, we don't need to extend OptimizeStringConcat heavily anymore, and once all the StringBuilder::append-shaped bytecode phases out of existence, we can drop the compiler optimization on the floor. Thanks, -Aleksey -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From claes.redestad at oracle.com Wed Nov 25 00:07:28 2015 From: claes.redestad at oracle.com (Claes Redestad) Date: Wed, 25 Nov 2015 01:07:28 +0100 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <5654E4FB.6070200@oracle.com> References: <564E37DE.4070805@oracle.com> <962091CF-4D6C-4EFF-8343-53FCD85B55FE@oracle.com> <5654E4FB.6070200@oracle.com> Message-ID: <5654FBC0.7050508@oracle.com> Hi Aleksey, in http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.01/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java.html there are a number of internal strategy classes that will set up a number of MethodHandles in bulk once initialized: 1561 private static final MethodHandle NEW_STRING, NEW_STRING_CHECKED; 1562 private static final MethodHandle NEW_ARRAY; 1563 private static final Map, MethodHandle> PREPENDERS = new HashMap<>(); 1564 private static final Map, MethodHandle> LENGTH_MIXERS = new HashMap<>(); 1565 private static final Map, MethodHandle> CODER_MIXERS = new HashMap<>(); 1580 for (Class ptype : new Class[]{boolean.class, byte.class, char.class, short.class, int.class, long.class, String.class}) { 1581 PREPENDERS.put(ptype, lookupStatic(Lookup.IMPL_LOOKUP, stringHelper, "prepend", int.class, int.class, byte[].class, byte.class, ptype)); 1582 LENGTH_MIXERS.put(ptype, lookupStatic(Lookup.IMPL_LOOKUP, stringHelper, "mixLen", int.class, int.class, ptype)); 1583 CODER_MIXERS.put(ptype, lookupStatic(Lookup.IMPL_LOOKUP, stringHelper, "mixCoder", byte.class, byte.class, ptype)); 1584 } 1585 1586 NEW_STRING = lookupStatic(Lookup.IMPL_LOOKUP, stringHelper, "newString", String.class, byte[].class, byte.class); 1587 NEW_STRING_CHECKED = lookupStatic(Lookup.IMPL_LOOKUP, stringHelper, "newStringChecked", String.class, int.class, byte[].class, byte.class); 1588 NEW_ARRAY = lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleInlineCopyStrategy.class, "newArray", byte[].class, int.class, byte.class); I'm wondering if these could be made more lazily initialized in manners similar to how MethodHandleImpl and BoundMethodHandle were recently updated, e.g.: private static final ConcurrentMap, MethodHandle> PREPENDERS = new ConcurrentHashMap<>(); private static MethodHandle getPrepender(Class ptype) { return PREPENDERS.computeIfAbsent(ptype, new Function, MethodHandle>() { @Override public MethodHandle apply(Class ptype) { // will throw AssertionError if ptype not in {boolean.class, byte.class, char.class, short.class, int.class, long.class, String.class} lookupStatic(Lookup.IMPL_LOOKUP, stringHelper, "prepend", int.class, int.class, byte[].class, byte.class, ptype); } }); } Some variants might be non-existent in a majority of programs, others might not be needed early on, which could help reduce the footprint a bit. Thanks! /Claes On 2015-11-24 23:30, Aleksey Shipilev wrote: > Hi Paul, > > Thanks for the review! > > Updated webrevs: > http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.01/ > http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.01/ > > More reviews, please :) > > Comments below: > > On 11/24/2015 05:16 PM, Paul Sandoz wrote: >>> On 19 Nov 2015, at 21:58, Aleksey Shipilev wrote: >>> Webrev: >>> http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.00/ >> ? >> >> 134 if ("inline".equals(concat)) { >> 135 allowIndyStringConcat = false; >> 136 indyStringConcatConstants = false; >> 137 } else if ("indy".equals(concat)) { >> 138 allowIndyStringConcat = true; >> 139 indyStringConcatConstants = false; >> 140 } else if ("indyWithConstants".equals(concat)) { >> 141 allowIndyStringConcat = true; >> 142 indyStringConcatConstants = true; >> 143 } else { >> 144 Assert.error("Unknown stringConcat: " + concat); >> 145 throw new IllegalStateException("Unknown stringConcat: " + concat); >> 146 } >> >> If you are in anyway inclined you could use a switch on concat. > Yes, I was trying not to use (ahem) "new" language features in a > language compiler. But it seems javac uses String switches everywhere. > Fixed. > >> I have a marginal preference for an enum StringConcatStrategy with > StringBuilder, Indy, IndyWithConstants values. But i will defer to other > javac reviewers. > > I think string values are fine, also because -XD options seem to be > Stringly-typed anyhow. > > >>> Webrev: >>> http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.00/ >>> >> My inclination would be to consolidate all the sys props under one doPriv block. > Yes, done. > > >> 200 private static final Map CACHE; >> >> ConcurrentMap? To make it clearer that this is operated on concurrently. > Yes. Fixed. > > >> 287 elements = new ArrayList<>(el); >> 288 Collections.reverse(el); >> 289 elementsRev = new ArrayList<>(el); >> >> elementsRev = e1? > Yes. Fixed. > > >> It?s mildly surprising that there is no supported way to create a reverse view of a ListIterator. >> 408 if (DEBUG) { >> 409 System.out.println("StringConcatFactory " + STRATEGY + " is here for " + argTypes); >> 410 } >> >> No recursion! :-) > Yeah, this code is exempted from Indified String Concat to avoid > circularity ;) > >> 530 if (caller == null) { >> 531 throw new StringConcatException("Lookup is null"); >> 532 } >> 533 >> 534 if (name == null) { >> 535 throw new StringConcatException("Name is null"); >> 536 } >> 537 >> 538 if (argTypes == null) { >> 539 throw new StringConcatException("Argument types are null"); >> 540 } >> >> It?s odd to not see NPEs being used instead. > Yes, should have used Objects.requireNonNull. The NPE exceptions would > not ever fire if you invoke BSM through invokedynamic anyhow. Fixed. > > >> Can the generated class extend from an existing compiled class or >> reuse static method calls of another class? then it might be possible >> to move ASM generation of debug code into java source code. > In theory, it can, but I would like to avoid that. The debugging > bytecode is not really complicated to warrant moving to a separate Java > source file (which should probably required to be public to begin with) > and blow up the implementation complexity. MethodHandle-based strategies > already do something similar to what you are proposing, but they can use > look up private methods. > > >> Here is a wild thought, i dunno if it makes any difference. >> U.defineAnonymousClass allows one to patch the constant pool, so the >> string constants could be patched in. > See! You can experiment with wild ideas like these after the > infrastructure lands in JDK. > > >> You seem to be hedging your bets about what static strategy to >> choose. Do you intend to whittle down the strategies over time? Same >> argument applies to caching. Some time before the JDK 9 release it >> would be good to reduce the scope. > My rationale for keeping all strategies untouched is based on the > premise that most improvements in strategies would probably be some form > of existing strategies, and having all strategies handy and tested > simplifies improvements. Also, we may have to do a real-life experiments > for choosing a better default strategy. > > >> Do you anticipate it might be possible to reduce the scope of the >> existing JIT optimisations? > Yes, we don't need to extend OptimizeStringConcat heavily anymore, and > once all the StringBuilder::append-shaped bytecode phases out of > existence, we can drop the compiler optimization on the floor. > > Thanks, > -Aleksey > From aleksey.shipilev at oracle.com Wed Nov 25 23:04:50 2015 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Thu, 26 Nov 2015 02:04:50 +0300 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <5654FBC0.7050508@oracle.com> References: <564E37DE.4070805@oracle.com> <962091CF-4D6C-4EFF-8343-53FCD85B55FE@oracle.com> <5654E4FB.6070200@oracle.com> <5654FBC0.7050508@oracle.com> Message-ID: <56563E92.6060009@oracle.com> On 11/25/2015 03:07 AM, Claes Redestad wrote: > Some variants might be non-existent in a majority of programs, others > might not be needed early on, which could help reduce the footprint a bit. Thanks, indeed, it is savvy to make the MH resolution lazier. See the update: http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.02/ http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.01/ http://cr.openjdk.java.net/~shade/8085796/webrev.root.00/ More reviews please :) Especially the langtools part. Thanks, -Aleksey -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From andrej.golovnin at gmail.com Thu Nov 26 08:42:21 2015 From: andrej.golovnin at gmail.com (Andrej Golovnin) Date: Thu, 26 Nov 2015 09:42:21 +0100 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <56563E92.6060009@oracle.com> References: <564E37DE.4070805@oracle.com> <962091CF-4D6C-4EFF-8343-53FCD85B55FE@oracle.com> <5654E4FB.6070200@oracle.com> <5654FBC0.7050508@oracle.com> <56563E92.6060009@oracle.com> Message-ID: Hi Aleksey, > http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.02/ src/java.base/share/classes/java/lang/Integer.java src/java.base/share/classes/java/lang/Long.java I miss JavaDocs for the returned value of the methods #getChars(int, int, byte[]) and #getCharsUTF16(int, int, byte[]). And it would be nice to have JavaDocs for the parameters too. src/java.base/share/classes/java/lang/StringConcatHelper.java src/java.base/share/classes/java/lang/invoke/StringConcatException.java test/java/lang/String/concat/ImplicitStringConcatShapesTestGen.java test/java/lang/String/concat/update-tests.sh The files do not have a copyright header. Best regards, Andrej Golovnin From maurizio.cimadamore at oracle.com Thu Nov 26 11:40:32 2015 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 26 Nov 2015 11:40:32 +0000 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <564E37DE.4070805@oracle.com> References: <564E37DE.4070805@oracle.com> Message-ID: <5656EFB0.2090805@oracle.com> Hi Alex, some comments on the langtools code below: * please remove the new voidClassType constant from Symtab - and use this idiom instead: types.boxedClass(syms.voidType).type; Note that j.l.Void is always created (see call to synthetizeBoxTypeIfMissing(voidType) - but there are (or used to be) corner cases where j.l.Void is not available on certain platforms (i.e. mobile) so we can't rely on it being always there (as it will lead to crashes). The pattern above is safer, as it relies on javac ability to fake a box type if it's missing from the platform. * The code for initializing options in Gen is what we would normally model with an enum. I.e. you need something like: enum StringConcatMode { INLINE, INDY_PLAIN, INDY_CONSTANTS; } And then put some logic inside the enum class to parse the option and to return the right enum constant. The code will get better as you can model two constants (allowIndyStringConcat and indyStringConcatConstants) with a single enum value. * From a design point of view, I see the logic for generating the string concat indy calls as split into two components - one that collects arguments, iterates through the peels and the merges them together; this part is independent from the particular indy strategy used. There's also a second part - the one that generates the list of static/dynamic args (given the flattened args to the string concat) and then generates the final indy call. This latter part is variable, i.e. you get different logic for different indy strategies - which means the code ends up with many if/else blocks. A possible suggestioin is to make the code more object oriented - keep the first part as is, but have an helper class to do the job of mapping an argument into a static arg/recipe and then generate the final indy call. In other wordas, what you need is a builder pattern - you need an object that you can append args to and, when finished, you can call a method to generate the resulting indy call. There will be a builder for each indy strategy. This is just a suggestion on how I would organize the code - it's not a blocking comment - but I see the current strategy not scaling very well if e.g. you start adding more strategies. * I need some confirmation here // Concat the String representation of the constant, except + // for the case it contains special tags, which requires us + // to expose it as detached constant. + String a = arg.type.stringValue(); + if (a.contains(TAG_CONST) || a.contains(TAG_ARG)) { + recipe.append(TAG_CONST); + staticArgs.add(a); + } else { + recipe.append(a); + } My understanding is that your strategy builds a 'recipe' which is basically the result of the concat. Since some of the arguments are dynamic, you need to put special markers in the recipe, to tell the BSM to fetch the dynamic argument and stick it in there. Correct? This in turn creates a problem, as it's possible for a concat _constant_ argument to contain the special values themselves - if that's the case, you use static arguments essentially as an escaping mechanism, right? * I would expect more of a combinatorial test where you check i.e. string concat of different sizes and args - i.e. the dimension of the combinatorial spaces are: - size - how many args to the string concat? This as non obvious consequences in terms of peeling - arg types: constants, dynamic, special constants (i.e. TAG_CONST, TAG_ARG) - strategy used: vanilla, indy_constats, indy_plain - codegen context: assignop vs. binary - target option (-target 8 vs -target 9) There are several combinatorial tests that generate a source and check it on the fly - one example (close to what's needed here) is: http://hg.openjdk.java.net/jdk9/dev/langtools/file/176472b94f2e/test/tools/javac/lambda/bytecode/TestLambdaBytecode.java Maurizio On 19/11/15 20:58, Aleksey Shipilev wrote: > Hi, > > I would like to have a code pre-review for Indify String Concat changes. > For the reference, the rationale, design constraints, etc. are outlined > in the JEP itself: > https://bugs.openjdk.java.net/browse/JDK-8085796 > > The experimental notes, including the bytecode shapes, benchmark data, > and benchmark analysis, interaction with Compact Strings are here: > http://cr.openjdk.java.net/~shade/8085796/notes.txt > > Javadoc (CCC is in progress): > > http://cr.openjdk.java.net/~shade/8085796/javadocs/StringConcatFactory.html > > > === javac change: > > Webrev: > http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.00/ > > A little guide: > > * We cut in at the same two points current javac does the String > concat. But instead of emitting the StringBuilder append chains, we > collect all arguments and hand them over to JDK's > java.lang.invoke.StringConcatFactory. > > * The bytecode flavor is guarded by hidden -XDstringConcat option, with > three possible values: inline, indy, indyWithConstants. > "indyWithConstants" is selected as the default bytecode flavor. > > * Since a String concat expression may contain more operands than any > Java call can manage, we sometimes have to peel the concat in several > back-to-back calls, and concat-ting the results. That peeling is > one-level, and can accommodate 200*200 = 40000 arguments, well beyond > what can be achieved for a singular String concat expression (limited > either by constant pool size, or by method code size). > > > === JDK change: > > Webrev: > http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.00/ > > A little guide: > > * The entry point is java.lang.invoke.StringConcatFactory. Its methods > would be used as invokedynamic bootstrap methods, at least in javac. > > * There are multiple concatenation strategies supported by SCF. We > explored the performance characteristics of all factories, chosen one > performing good throughput- and startup-wise. All strategies are fully > functional, covered by tests, and kept as the base for the future work > and fine tuning. > > * Most strategies delegate to public StringBuilder API, which makes > them quite simple, since they are not forced to deal with actual storage > (this got complicated with Compact Strings). > > * The only strategy that builds the String directly is > MH_INLINE_SIZED_EXACT strategy, and thus it is the most complicated of > all. It uses private java.lang.StringConcatHelper class to get access to > package-private (Integer|Long).(stringSize|getChar*) methods; the access > to j.l.SCH is granted by a private lookup. > > * Some tests assume the particular code shape and/or invokedynamic > counts, needed to fix those as well. > > === Build change > > (I don't copy build-dev@ to avoid spamming that list with langtools/jdk > reviews; this section is FYI) > > Webrev: > http://cr.openjdk.java.net/~shade/8085796/webrev.root.00/ > > * This one is simple: we exempt java.base and interim classes from Indy > String Concat to avoid bootstrapping issues. > > > Thanks, > -Aleksey > -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Thu Nov 26 11:45:09 2015 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 26 Nov 2015 11:45:09 +0000 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <5656EFB0.2090805@oracle.com> References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> Message-ID: <5656F0C5.2010501@oracle.com> On 26/11/15 11:40, Maurizio Cimadamore wrote: > * The code for initializing options in Gen is what we would normally > model with an enum. I.e. you need something like: > > enum StringConcatMode { > INLINE, > INDY_PLAIN, > INDY_CONSTANTS; > } > > And then put some logic inside the enum class to parse the option and > to return the right enum constant. The code will get better as you can > model two constants (allowIndyStringConcat and > indyStringConcatConstants) with a single enum value. Forgot - we have examples of this pattern: http://hg.openjdk.java.net/jdk9/jdk9/langtools/file/8356d7a909a2/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java#l125 Maurizio From aleksey.shipilev at oracle.com Thu Nov 26 13:54:51 2015 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Thu, 26 Nov 2015 16:54:51 +0300 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: References: <564E37DE.4070805@oracle.com> <962091CF-4D6C-4EFF-8343-53FCD85B55FE@oracle.com> <5654E4FB.6070200@oracle.com> <5654FBC0.7050508@oracle.com> <56563E92.6060009@oracle.com> Message-ID: <56570F2B.3050802@oracle.com> Hi Andrej, Thanks for the review, I'll send the updated webrevs once I address Maurizio's review comments. On 11/26/2015 11:42 AM, Andrej Golovnin wrote: >> http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.02/ > > src/java.base/share/classes/java/lang/Integer.java > src/java.base/share/classes/java/lang/Long.java > > I miss JavaDocs for the returned value of the methods #getChars(int, > int, byte[]) and #getCharsUTF16(int, int, byte[]). And it would be > nice to have JavaDocs for the parameters too. Added, thanks! > src/java.base/share/classes/java/lang/StringConcatHelper.java > src/java.base/share/classes/java/lang/invoke/StringConcatException.java > test/java/lang/String/concat/ImplicitStringConcatShapesTestGen.java > test/java/lang/String/concat/update-tests.sh > > The files do not have a copyright header. Oops, good catch, added. Thanks, -Aleksey -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From luke-mail at online.de Thu Nov 26 14:30:12 2015 From: luke-mail at online.de (Lukas Magel) Date: Thu, 26 Nov 2015 15:30:12 +0100 Subject: Inverse annotation inheritance issue with generic interfaces In-Reply-To: <5653AAC8.7070508@oracle.com> References: <56531625.4090708@online.de> <565379F6.3040608@oracle.com> <56538A17.7000803@oracle.com> <5653AAC8.7070508@oracle.com> Message-ID: <56571774.7050902@online.de> Thanks for your help! Since the behavior is intended the issue seems to be a problem with the Jax-RS implementation. I guess I will bring this up again on their mailing list. Maybe they can work out a fix on their end. Lukas On 24.11.2015 01:09, Alex Buckley wrote: > On 11/23/2015 1:50 PM, Maurizio Cimadamore wrote: >> On 23/11/15 20:41, Alex Buckley wrote: >>> Enumerating the methods of Main.class shouldn't reveal >>> sampleMethod(A), since sampleMethod(B) overrides it. I suspect a >>> bridge method bug is being tickled, probably in Core Reflection rather >>> than javac. >> Not sure what you mean here - as far as I recall, reflection always >> listed all methods (bridges included) in a given class. > > Hard to confirm from the javadoc (as usual), but I imagine you're right. > >> I think what is being observed is this: >> >> https://bugs.openjdk.java.net/browse/JDK-669537 >> >> Which I think was a legitimate fix - the callee probably wants to be >> able to retrieve all applicable annotations, regardless of whether it >> accidentally hit the bridge doing the reflective lookup. > > I guess the fix was to emit the RuntimeVisibleAnnotations attribute > for the bridge method sampleMethod(A) -- the change from non-emission > (in 1.7.0_51) to emission (in 1.7.0_85) is visible in Lukas' javap > output. > > Ah, and here's the thread from exactly two years ago: > > Annotations on return-overridden methods also end up on bridge methods > > http://mail.openjdk.java.net/pipermail/compiler-dev/2013-November/008147.html > > > So Lukas, the behavior is intended. See > https://bugs.openjdk.java.net/browse/JDK-6695379 for more. > > Alex > >> Maurizio >>> What is the full javap output for Main.class as compiled with Oracle >>> JDK 1.7.0_51 versus Oracle JDK 1.7.0_85 ? (Plain text inline, please.) >>> >>> Alex >>> >>> On 11/23/2015 5:35 AM, Lukas Magel wrote: >>>> Hello, >>>> >>>> I am currently working on a Java EE web project and have been >>>> experiencing a compiler behavior which I don't know how to interpret. >>>> >>>> In our code we define interfaces like the following: >>>> >>>> public interface SampleInterface { >>>> >>>> public void sampleMethod(T t); >>>> >>>> } >>>> >>>> as well as an implementing class: >>>> >>>> public class Main implements SampleInterface { >>>> >>>> @SampleAnnotation >>>> public void sampleMethod(B t) { >>>> >>>> } >>>> } >>>> >>>> and the corresponding annotation: >>>> >>>> @Retention(RetentionPolicy.RUNTIME) >>>> @Target(ElementType.METHOD) >>>> public @interface SampleAnnotation { >>>> >>>> } >>>> >>>> Where Class B extends A. All classes are compiled using the OpenJDK >>>> compiler. If I use Reflection to retrieve all methods of the Main >>>> class >>>> at runtime and print each method with its annotations I get the >>>> following list of methods: >>>> >>>> class Main >>>> >>>> public void Main.sampleMethod(A) >>>> @SampleAnnotation() >>>> >>>> public void Main.sampleMethod(B) >>>> @SampleAnnotation() >>>> >>>> The compiler will assign the annotation to the method declaration >>>> of the >>>> interface although the annotation is only declared in the implementing >>>> class. I cannot reproduce this behavior with the Oracle Java >>>> Compiler or >>>> the Eclipse JDT Compiler. If I compile the example with one of the two >>>> compilers the resulting program will yield the following result: >>>> >>>> class annotation.Main >>>> >>>> public void Main.sampleMethod(A) >>>> >>>> public void Main.sampleMethod(B) >>>> @SampleAnnotation() >>>> >>>> The JRE type (Oracle, OpenJDK) that the program is executed with >>>> has no >>>> influence on the result. >>>> >>>> This behavior is reproducible with the following constellations: >>>> JDK Operating System Hardware >>>> 1.7.0_85 Ubuntu 14.04.03 x86-64 >>>> 1.7.0_91 Arch Linux x86-64 >>>> 1.8.0_66 Arch Linux x86-64 >>>> >>>> It is NOT reproducible with the following constellation: >>>> 1.7.0_51 Ubuntu 13.04 x86-64 >>>> >>>> My actual question is whether this behavior is intended or not. It >>>> causes quite some issues with our Jax-RS REST implementations. All >>>> REST >>>> classes each implement an interface like the one above and are >>>> annotated >>>> with multiple annotations to allow the container to identify endpoints >>>> at runtime. The Jax-RS framework uses reflection to determine possible >>>> method candidates at runtime and will happily accept both the generic >>>> and the special method since both of them carry the annotations. >>>> >>>> I can also provide an example project if necessary. >>>> >>>> Thanks, >>>> Lukas >> From aleksey.shipilev at oracle.com Fri Nov 27 00:20:13 2015 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Fri, 27 Nov 2015 03:20:13 +0300 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <5656EFB0.2090805@oracle.com> References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> Message-ID: <5657A1BD.2080603@oracle.com> Hi Maurizio, Thanks for the reviews! Updated webrevs: http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.02/ http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.03/ On 11/26/2015 02:40 PM, Maurizio Cimadamore wrote: > types.boxedClass(syms.voidType).type; > > Note that j.l.Void is always created (see call to > synthetizeBoxTypeIfMissing(voidType) - but there are (or used to be) > corner cases where j.l.Void is not available on certain platforms (i.e. > mobile) so we can't rely on it being always there (as it will lead to > crashes). The pattern above is safer, as it relies on javac ability to > fake a box type if it's missing from the platform. Excellent, thanks! Didn't know that nuisance with j.l.Void availability. Removed in favor of the suggested pattern. > * The code for initializing options in Gen is what we would normally > model with an enum. I.e. you need something like: > > enum StringConcatMode { > INLINE, > INDY_PLAIN, > INDY_CONSTANTS; > } > > And then put some logic inside the enum class to parse the option and to > return the right enum constant. The code will get better as you can > model two constants (allowIndyStringConcat and > indyStringConcatConstants) with a single enum value. Yes, indeed, done. > * From a design point of view, I see the logic for generating the string > concat indy calls as split into two components - one that collects > arguments, iterates through the peels and the merges them together; this > part is independent from the particular indy strategy used. There's also > a second part - the one that generates the list of static/dynamic args > (given the flattened args to the string concat) and then generates the > final indy call. This latter part is variable, i.e. you get different > logic for different indy strategies - which means the code ends up with > many if/else blocks. A possible suggestioin is to make the code more > object oriented - keep the first part as is, but have an helper class to > do the job of mapping an argument into a static arg/recipe and then > generate the final indy call. In other wordas, what you need is a > builder pattern - you need an object that you can append args to and, > when finished, you can call a method to generate the resulting indy > call. There will be a builder for each indy strategy. This is just a > suggestion on how I would organize the code - it's not a blocking > comment - but I see the current strategy not scaling very well if e.g. > you start adding more strategies. Yes, I stepped further and created a separate helper class that does all the String concat. Moved all the logic, including the current StringBuilder-based one there, this lets to un-clutter Gen itself. Please see the updated webrevs. I would need to polish langtools changes a bit more, but tell me if the general direction is what you like. > * I need some confirmation here > > // Concat the String representation of the constant, except > + // for the case it contains special tags, which requires us > + // to expose it as detached constant. > + String a = arg.type.stringValue(); > + if (a.contains(TAG_CONST) || a.contains(TAG_ARG)) { > + recipe.append(TAG_CONST); > + staticArgs.add(a); > + } else { > + recipe.append(a); > + } > > > My understanding is that your strategy builds a 'recipe' which is > basically the result of the concat. Since some of the arguments are > dynamic, you need to put special markers in the recipe, to tell the BSM > to fetch the dynamic argument and stick it in there. Correct? This in > turn creates a problem, as it's possible for a concat _constant_ > argument to contain the special values themselves - if that's the case, > you use static arguments essentially as an escaping mechanism, right? Yes, that is a correct understanding. The credit for the idea actually goes to John Rose. This scheme has a nice implication that *most* recipes would have only the recipe string + dynamic arguments, and no other static arguments. Which saves space in constant pool. Also, some compilers may find it easier to avoid building a complicated recipe, and rather pass the String constants untouched. There is a guidance in StringConcatFactory for that: @apiNote Code generators have three distinct ways to process a constant string operand S in a string concatenation expression. First, S can be materialized as a reference (using ldc) and passed as an ordinary argument (recipe '\1'). Or, S can be stored in the constant pool and passed as a constant (recipe '\2') . Finally, if S contains neither of the recipe tag characters ('\1', '\2') then S can be interpolated into the recipe itself, causing its characters to be inserted into the result. > * I would expect more of a combinatorial test where you check i.e. > string concat of different sizes and args - i.e. the dimension of the > combinatorial spaces are: > > - size - how many args to the string concat? This as non obvious > consequences in terms of peeling > - arg types: constants, dynamic, special constants (i.e. TAG_CONST, TAG_ARG) > - strategy used: vanilla, indy_constats, indy_plain > - codegen context: assignop vs. binary > - target option (-target 8 vs -target 9) In fact, we have these tests in jdk/test/java/lang/String concat, see the jdk webrev. The rationale for keeping these tests in jdk: you would want to test the JDK concat code along with those combinatorial tests, and verify the *actual* concatenation result is sane. Simply generating the bytecode and trying to verify it seems to be a half-way approach to the problem (also amenable to bugs in your own bytecode verifier!) Thanks, -Aleksey -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From maurizio.cimadamore at oracle.com Fri Nov 27 01:03:10 2015 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Fri, 27 Nov 2015 01:03:10 +0000 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <5657A1BD.2080603@oracle.com> References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> <5657A1BD.2080603@oracle.com> Message-ID: <5657ABCE.3010106@oracle.com> Thanks! The patch looks better, and having the code all in one place definitively helps. I think there is still something that you can do to improve the code - i.e. all strategies seem to do: * collect arguments (on a JCAssignOp and on a JCBinary) * build indy node Currently you have switches on both collect() and xyzConcat methods; what I was trying to suggest is - instead of doing: switch (cond) { case A: case B } Can we organize the code using a class hierarchy - i.e. abstract class StringConcatHelper { List collectAll(JCAssignOp) { ... } //implemented in terms of collect(JCTree, JCTree, as now) List collectAll(JCBinary) { ... } //implemented in terms of collect(JCTree, JCTree, as now) abstract void emit(List args, JCTree tree, Type type); private List collectAll(JCTree, JCTree) { //as current impl } } and then have a bunch of subclasses: class InlineConcatHelper extends StringConcatHelper { //implements inline emit here } abstract class IndyConcatHelper extends StringConcatHelper { //common logic to all indy-based strategy goes here } class ConstantIndyConcatHelper extends IndyConcatHelper { //constant indy logic here } class PlainIndyConcatHelper extends IndyConcatHelper { //plain indy logic here } Then, all you have to do is to create the right helper given the command line options, and that object will have an API that can be used by Gen to perform string concact effectively, w/o switching and minimizing duplication. What do you think? Maurizio On 27/11/15 00:20, Aleksey Shipilev wrote: > Hi Maurizio, > > Thanks for the reviews! > > Updated webrevs: > http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.02/ > http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.03/ > > > On 11/26/2015 02:40 PM, Maurizio Cimadamore wrote: >> types.boxedClass(syms.voidType).type; >> >> Note that j.l.Void is always created (see call to >> synthetizeBoxTypeIfMissing(voidType) - but there are (or used to be) >> corner cases where j.l.Void is not available on certain platforms (i.e. >> mobile) so we can't rely on it being always there (as it will lead to >> crashes). The pattern above is safer, as it relies on javac ability to >> fake a box type if it's missing from the platform. > Excellent, thanks! Didn't know that nuisance with j.l.Void availability. > Removed in favor of the suggested pattern. > > >> * The code for initializing options in Gen is what we would normally >> model with an enum. I.e. you need something like: >> >> enum StringConcatMode { >> INLINE, >> INDY_PLAIN, >> INDY_CONSTANTS; >> } >> >> And then put some logic inside the enum class to parse the option and to >> return the right enum constant. The code will get better as you can >> model two constants (allowIndyStringConcat and >> indyStringConcatConstants) with a single enum value. > Yes, indeed, done. > > >> * From a design point of view, I see the logic for generating the string >> concat indy calls as split into two components - one that collects >> arguments, iterates through the peels and the merges them together; this >> part is independent from the particular indy strategy used. There's also >> a second part - the one that generates the list of static/dynamic args >> (given the flattened args to the string concat) and then generates the >> final indy call. This latter part is variable, i.e. you get different >> logic for different indy strategies - which means the code ends up with >> many if/else blocks. A possible suggestioin is to make the code more >> object oriented - keep the first part as is, but have an helper class to >> do the job of mapping an argument into a static arg/recipe and then >> generate the final indy call. In other wordas, what you need is a >> builder pattern - you need an object that you can append args to and, >> when finished, you can call a method to generate the resulting indy >> call. There will be a builder for each indy strategy. This is just a >> suggestion on how I would organize the code - it's not a blocking >> comment - but I see the current strategy not scaling very well if e.g. >> you start adding more strategies. > Yes, I stepped further and created a separate helper class that does all > the String concat. Moved all the logic, including the current > StringBuilder-based one there, this lets to un-clutter Gen itself. > > Please see the updated webrevs. I would need to polish langtools changes > a bit more, but tell me if the general direction is what you like. > > >> * I need some confirmation here >> >> // Concat the String representation of the constant, except >> + // for the case it contains special tags, which requires us >> + // to expose it as detached constant. >> + String a = arg.type.stringValue(); >> + if (a.contains(TAG_CONST) || a.contains(TAG_ARG)) { >> + recipe.append(TAG_CONST); >> + staticArgs.add(a); >> + } else { >> + recipe.append(a); >> + } >> >> >> My understanding is that your strategy builds a 'recipe' which is >> basically the result of the concat. Since some of the arguments are >> dynamic, you need to put special markers in the recipe, to tell the BSM >> to fetch the dynamic argument and stick it in there. Correct? This in >> turn creates a problem, as it's possible for a concat _constant_ >> argument to contain the special values themselves - if that's the case, >> you use static arguments essentially as an escaping mechanism, right? > Yes, that is a correct understanding. The credit for the idea actually > goes to John Rose. This scheme has a nice implication that *most* > recipes would have only the recipe string + dynamic arguments, and no > other static arguments. Which saves space in constant pool. Also, some > compilers may find it easier to avoid building a complicated recipe, and > rather pass the String constants untouched. > > There is a guidance in StringConcatFactory for that: > > @apiNote Code generators have three distinct ways to process a constant > string operand S in a string concatenation expression. First, S can be > materialized as a reference (using ldc) and passed as an ordinary > argument (recipe '\1'). Or, S can be stored in the constant pool and > passed as a constant (recipe '\2') . Finally, if S contains neither of > the recipe tag characters ('\1', '\2') then S can be interpolated into > the recipe itself, causing its characters to be inserted into the > result. > > > >> * I would expect more of a combinatorial test where you check i.e. >> string concat of different sizes and args - i.e. the dimension of the >> combinatorial spaces are: >> >> - size - how many args to the string concat? This as non obvious >> consequences in terms of peeling >> - arg types: constants, dynamic, special constants (i.e. TAG_CONST, TAG_ARG) >> - strategy used: vanilla, indy_constats, indy_plain >> - codegen context: assignop vs. binary >> - target option (-target 8 vs -target 9) > In fact, we have these tests in jdk/test/java/lang/String concat, see > the jdk webrev. The rationale for keeping these tests in jdk: you would > want to test the JDK concat code along with those combinatorial tests, > and verify the *actual* concatenation result is sane. Simply generating > the bytecode and trying to verify it seems to be a half-way approach to > the problem (also amenable to bugs in your own bytecode verifier!) > > > Thanks, > -Aleksey > From andrej.golovnin at gmail.com Fri Nov 27 07:47:25 2015 From: andrej.golovnin at gmail.com (Andrej Golovnin) Date: Fri, 27 Nov 2015 08:47:25 +0100 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <5657A1BD.2080603@oracle.com> References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> <5657A1BD.2080603@oracle.com> Message-ID: Hi Aleksey, > http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.02/ test/tools/javac/T5024091/T5024091.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java The files do not have the copyright header. And I have one stupid question to com.sun.tools.javac.jvm.StringConcat: The constants TAG_ARG and TAG_CONST are defined as Strings. From performance standpoint of view, would it be not better to use char instead of String? I understand that: if (a.contains(TAG_CONST) || a.contains(TAG_ARG)) is easier to read than: if (a.indexOf(TAG_CONST) != -1 || a.indexOf(TAG_ARG) != -1) But when you have a huge project to compile, maybe it can help to reduce the compile time. The line 330 in com.sun.tools.javac.jvm.StringConcat: 330 recipe.append("null"); Maybe it is better to rewrite it as: 330 recipe.append((String) null); The first one requires to copy byte values from the "null" String. The second one ends up in the call to AsbtractStringBuilder.appendNull(). Best regards, Andrej Golovnin From aleksey.shipilev at oracle.com Fri Nov 27 11:33:02 2015 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Fri, 27 Nov 2015 14:33:02 +0300 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> <5657A1BD.2080603@oracle.com> Message-ID: <56583F6E.2090107@oracle.com> Hi, Again, I'll post the updates after addressing another round of Maurizio's comments :) On 11/27/2015 10:47 AM, Andrej Golovnin wrote: >> http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.02/ > > test/tools/javac/T5024091/T5024091.java > src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java > > The files do not have the copyright header. Thanks again, added. > And I have one stupid question to com.sun.tools.javac.jvm.StringConcat: > > The constants TAG_ARG and TAG_CONST are defined as Strings. From > performance standpoint of view, would it be not better to use char > instead of String? > > I understand that: > > if (a.contains(TAG_CONST) || a.contains(TAG_ARG)) > > is easier to read than: > > if (a.indexOf(TAG_CONST) != -1 || a.indexOf(TAG_ARG) != -1) > > But when you have a huge project to compile, maybe it can help to > reduce the compile time. Yes, it might makes sense to do this microoptimization. Done. > The line 330 in com.sun.tools.javac.jvm.StringConcat: > > 330 recipe.append("null"); > > Maybe it is better to rewrite it as: > > 330 recipe.append((String) null); > The first one requires to copy byte values from the "null" String. The > second one ends up in the call to AsbtractStringBuilder.appendNull(). Ditto. Thanks, -Aleksey -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From ivan.gerasimov at oracle.com Fri Nov 27 11:33:53 2015 From: ivan.gerasimov at oracle.com (Ivan Gerasimov) Date: Fri, 27 Nov 2015 14:33:53 +0300 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <564E37DE.4070805@oracle.com> References: <564E37DE.4070805@oracle.com> Message-ID: <56583FA1.60202@oracle.com> Hi Alexey! Not a thorough review, but a few of minor comments: 1) As you touch Long.java anyway, could you change 508 while (i <= Integer.MIN_VALUE) { to 508 while (i < Integer.MIN_VALUE) { , which may save us a half of nanosecond on some inputs? And the same on the line# 563. 2) Integer.java and Long.java In the javadoc, just for a sake of accuracy: 550 * @return index of the most significant digit *or minus sign, if present* 3) StringConcatFactory.java 255 acc = new StringBuilder(); wouldn't it be a bit more efficient to do `acc.setLength(0)`? 4) StringConcatFactory.java 586 try { 587 mh = generate(caller, mt, rec); 588 } catch (Throwable t) { 589 if (t instanceof StringConcatException) { 590 throw (StringConcatException)t; 591 } else { 592 throw new StringConcatException("Generator failed", t); 593 } 594 } it seems to be a bit more straight-forward: try { mh = generate(caller, mt, rec); } catch (StringConcatException sce) { throw sce; } catch (Throwable t) { throw new StringConcatException("Generator failed", t); } Sincerely yours, Ivan On 19.11.2015 23:58, Aleksey Shipilev wrote: > Hi, > > I would like to have a code pre-review for Indify String Concat changes. > For the reference, the rationale, design constraints, etc. are outlined > in the JEP itself: > https://bugs.openjdk.java.net/browse/JDK-8085796 > > The experimental notes, including the bytecode shapes, benchmark data, > and benchmark analysis, interaction with Compact Strings are here: > http://cr.openjdk.java.net/~shade/8085796/notes.txt > > Javadoc (CCC is in progress): > > http://cr.openjdk.java.net/~shade/8085796/javadocs/StringConcatFactory.html > > > === javac change: > > Webrev: > http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.00/ > > A little guide: > > * We cut in at the same two points current javac does the String > concat. But instead of emitting the StringBuilder append chains, we > collect all arguments and hand them over to JDK's > java.lang.invoke.StringConcatFactory. > > * The bytecode flavor is guarded by hidden -XDstringConcat option, with > three possible values: inline, indy, indyWithConstants. > "indyWithConstants" is selected as the default bytecode flavor. > > * Since a String concat expression may contain more operands than any > Java call can manage, we sometimes have to peel the concat in several > back-to-back calls, and concat-ting the results. That peeling is > one-level, and can accommodate 200*200 = 40000 arguments, well beyond > what can be achieved for a singular String concat expression (limited > either by constant pool size, or by method code size). > > > === JDK change: > > Webrev: > http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.00/ > > A little guide: > > * The entry point is java.lang.invoke.StringConcatFactory. Its methods > would be used as invokedynamic bootstrap methods, at least in javac. > > * There are multiple concatenation strategies supported by SCF. We > explored the performance characteristics of all factories, chosen one > performing good throughput- and startup-wise. All strategies are fully > functional, covered by tests, and kept as the base for the future work > and fine tuning. > > * Most strategies delegate to public StringBuilder API, which makes > them quite simple, since they are not forced to deal with actual storage > (this got complicated with Compact Strings). > > * The only strategy that builds the String directly is > MH_INLINE_SIZED_EXACT strategy, and thus it is the most complicated of > all. It uses private java.lang.StringConcatHelper class to get access to > package-private (Integer|Long).(stringSize|getChar*) methods; the access > to j.l.SCH is granted by a private lookup. > > * Some tests assume the particular code shape and/or invokedynamic > counts, needed to fix those as well. > > === Build change > > (I don't copy build-dev@ to avoid spamming that list with langtools/jdk > reviews; this section is FYI) > > Webrev: > http://cr.openjdk.java.net/~shade/8085796/webrev.root.00/ > > * This one is simple: we exempt java.base and interim classes from Indy > String Concat to avoid bootstrapping issues. > > > Thanks, > -Aleksey > > From aleksey.shipilev at oracle.com Fri Nov 27 11:49:07 2015 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Fri, 27 Nov 2015 14:49:07 +0300 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <56583FA1.60202@oracle.com> References: <564E37DE.4070805@oracle.com> <56583FA1.60202@oracle.com> Message-ID: <56584333.3040202@oracle.com> Hi Ivan, Thanks for the reviews. Again, I will publish the updated webrevs after rewiring for Maurizio's comments. On 11/27/2015 02:33 PM, Ivan Gerasimov wrote: > 1) As you touch Long.java anyway, could you change > 508 while (i <= Integer.MIN_VALUE) { > to > 508 while (i < Integer.MIN_VALUE) { > , which may save us a half of nanosecond on some inputs? > > And the same on the line# 563. No, I think that deserves a separate round of Long/Integer.getChars cleanups, if any. Let's not clobber the Indy String Concat with a general optimization in the class library. > 2) Integer.java and Long.java > In the javadoc, just for a sake of accuracy: > 550 * @return index of the most significant digit *or minus sign, > if present* Yes, this is good. Fixed. > 3) StringConcatFactory.java > 255 acc = new StringBuilder(); > wouldn't it be a bit more efficient to do `acc.setLength(0)`? Yes, this is good too. Fixed. > 4) StringConcatFactory.java > > 586 try { > 587 mh = generate(caller, mt, rec); > 588 } catch (Throwable t) { > 589 if (t instanceof StringConcatException) { > 590 throw (StringConcatException)t; > 591 } else { > 592 throw new StringConcatException("Generator > failed", t); > 593 } > 594 } > > it seems to be a bit more straight-forward: > try { > mh = generate(caller, mt, rec); > } catch (StringConcatException sce) { > throw sce; > } catch (Throwable t) { > throw new StringConcatException("Generator failed", t); > } Ah, right, this is better, fixed. Thanks, -Aleksey -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From andrej.golovnin at gmail.com Fri Nov 27 12:29:40 2015 From: andrej.golovnin at gmail.com (Andrej Golovnin) Date: Fri, 27 Nov 2015 13:29:40 +0100 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <5657A1BD.2080603@oracle.com> References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> <5657A1BD.2080603@oracle.com> Message-ID: Hi Aleksey, > http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.03/ src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java The inner class Key is final. But the inner classes Recipe and RecipeElement are not final. Why? The #equals method of the Recipe class has this line: 295 return elements.equals(recipe.elements); where elements is a list of RecipeElements. But RecipeElement does not implement the #equals method. Is it intended or a mistake? I think, the RecipeElement class must implement the #equals and #hashCode methods. In other case the cache will not work as expected. Best regards, Andrej Golovnin From aleksey.shipilev at oracle.com Fri Nov 27 17:34:55 2015 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Fri, 27 Nov 2015 20:34:55 +0300 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <5657ABCE.3010106@oracle.com> References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> <5657A1BD.2080603@oracle.com> <5657ABCE.3010106@oracle.com> Message-ID: <5658943F.4040100@oracle.com> Hi Maurizio, Updated webrevs: http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.03/ http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.04/ On 11/27/2015 04:03 AM, Maurizio Cimadamore wrote: > Thanks! The patch looks better, and having the code all in one place > definitively helps. I think there is still something that you can do to > improve the code - i.e. all strategies seem to do: ... > Then, all you have to do is to create the right helper given the command > line options, and that object will have an API that can be used by Gen > to perform string concact effectively, w/o switching and minimizing > duplication. > > What do you think? I agree, these does look better, see the updated webrev. Thanks, -Aleksey -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From aleksey.shipilev at oracle.com Fri Nov 27 17:35:34 2015 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Fri, 27 Nov 2015 20:35:34 +0300 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> <5657A1BD.2080603@oracle.com> Message-ID: <56589466.9020001@oracle.com> Hi Andrej, On 11/27/2015 03:29 PM, Andrej Golovnin wrote: >> http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.03/ > > src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java > > The inner class Key is final. But the inner classes Recipe and > RecipeElement are not final. Why? > > The #equals method of the Recipe class has this line: > > 295 return elements.equals(recipe.elements); > > where elements is a list of RecipeElements. But RecipeElement does not > implement the #equals method. Is it intended or a mistake? > I think, the RecipeElement class must implement the #equals and > #hashCode methods. In other case the cache will not work as expected. Ow! Thanks, these are fixed in the updated webrevs! http://cr.openjdk.java.net/~shade/8085796/ Cheers, -Aleksey -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From maurizio.cimadamore at oracle.com Fri Nov 27 19:13:36 2015 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Fri, 27 Nov 2015 19:13:36 +0000 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <5658943F.4040100@oracle.com> References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> <5657A1BD.2080603@oracle.com> <5657ABCE.3010106@oracle.com> <5658943F.4040100@oracle.com> Message-ID: <5658AB60.3090606@oracle.com> Looks great - the only minor quibble is that now StringConcat looks like a regular javac context class; it even has an instance method - it's therefore best to follow usual initialization pattern for javac components: i.e. protected static final Context.Key concatKey = new Context.Key<>(); public static StringCOncat instance(Context context) { StringConcat instance = context.get(unlambdaKey); if (instance == null) { instance = new StringConcat(context); } return instance; } private StringConcat(Context context) { context.put(concatKey, this); //init all context dependent fields } So, this will make StringConcat a regular javac component that can be instantiated with: StringConcat.instance(context) Which would be done inside Gen. Note that this will mess up with the fact that your helpers extends directly from StringConcat, so you will probably need to separate the internal helper classes from the StringConcat API which will be used form outside. Let me know if you need help in getting this wired up correctly. Regarding the tests - I note that you have a good combo test in the JDK repo; one thing that this type of test doesn't cover is if you accidentally get the right result with a bad bytecode. I'll leave the decision as to whether to cover this to you (since the coverage provided by the JDK test is adequate anyway). MAurizio On 27/11/15 17:34, Aleksey Shipilev wrote: > Hi Maurizio, > > Updated webrevs: > http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.03/ > http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.04/ > > On 11/27/2015 04:03 AM, Maurizio Cimadamore wrote: >> Thanks! The patch looks better, and having the code all in one place >> definitively helps. I think there is still something that you can do to >> improve the code - i.e. all strategies seem to do: > ... > >> Then, all you have to do is to create the right helper given the command >> line options, and that object will have an API that can be used by Gen >> to perform string concact effectively, w/o switching and minimizing >> duplication. >> >> What do you think? > I agree, these does look better, see the updated webrev. > > Thanks, > -Aleksey > -------------- next part -------------- An HTML attachment was scrubbed... URL: From andrej.golovnin at gmail.com Sat Nov 28 09:05:05 2015 From: andrej.golovnin at gmail.com (Andrej Golovnin) Date: Sat, 28 Nov 2015 10:05:05 +0100 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <56589466.9020001@oracle.com> References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> <5657A1BD.2080603@oracle.com> <56589466.9020001@oracle.com> Message-ID: Hi Aleksey, >> http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.04/ src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java 356 ARG, The comma is not needed. 548 // Mock the recipe to reuse the concat generator code 549 StringBuilder sb = new StringBuilder(); 550 for (int c = 0; c < concatType.parameterCount(); c++) { 551 sb.append(TAG_ARG); 552 } 553 recipe = sb.toString(); This can be rewritten as: char[] value = new char[concatType.parameterCount()]; Arrays.fill(value, TAG_ARG); recipe = new String(value); And when you add to the JavaLangAccess interface a new method newStringUnsafe(byte[] value, byte coder), then you can even use the package private constructor String(byte[], byte) to avoid copying of bytes. But I'm not sure if it is worthwhile. 558 int cCount = 0; 559 int oCount = 0; 560 for (int i = 0; i < recipe.length(); i++) { 561 char c = recipe.charAt(i); 562 if (c == TAG_CONST) cCount++; 563 if (c == TAG_ARG) oCount++; 564 } This loop is only needed, when the recipe is already known. When you move the lines 558 and 559 before the line 547 if (generateRecipe) { then you can initialize oCount directly after the line 547: oCount = concatType.parameterCount(); and move the for-loop (lines 560-564) into the else clause of the "if (generateRecipe)" statement. Btw. I would rename the variables cCount and oCount to constCount and argCount. 601 Key key = new Key(mt, rec); 602 MethodHandle mh = CACHE_ENABLE ? CACHE.get(key) : null; If you rewrite this lines as: 601 Key key = null; 602 MethodHandle mh = CACHE_ENABLE ? CACHE.get(key = new Key(mt, rec)) : null; then you can avoid creation of Key objects when caching is disabled. 669 SIZED_EXACT(true, true), The comma is not needed. 672 boolean sized, exact; sized and exact should be final. 1619 private static Class STRING_HELPER; 1620 1621 static { 1622 try { 1623 STRING_HELPER = Class.forName("java.lang.StringConcatHelper"); 1624 } catch (ClassNotFoundException e) { 1625 throw new AssertionError(e); 1626 } Why STRING_HELPER is not final? I have a small question to the Recipe class. Is it really better to create elementsRev instead of using the old-school for-loop and List.get(int) to loop over the list of RecipeElements in the reverse order? If there is any reason, then could you please document it to avoid stupid questions in the future? :-) src/java.base/share/classes/java/lang/invoke/StringConcatException.java 31 private static final long serialVersionUID = 292L + 9L; I see that the pattern for serialVersionUID like this is already used in four other classes (BootstrapMethodError, MethodType, WrongMethodTypeException, LambdaConversioinException). Does it have some special meaning? I'm just curious. Best regards, Andrej Golovnin From aleksey.shipilev at oracle.com Sun Nov 29 15:45:25 2015 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Sun, 29 Nov 2015 18:45:25 +0300 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> <5657A1BD.2080603@oracle.com> <56589466.9020001@oracle.com> Message-ID: <565B1D95.1090304@oracle.com> Thanks again, I'll upload the webrevs after further langtools cleanup. On 11/28/2015 12:05 PM, Andrej Golovnin wrote: >>> http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.04/ > > src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java > > 356 ARG, > > The comma is not needed. Yes. > 548 // Mock the recipe to reuse the concat generator code > 549 StringBuilder sb = new StringBuilder(); > 550 for (int c = 0; c < concatType.parameterCount(); c++) { > 551 sb.append(TAG_ARG); > 552 } > 553 recipe = sb.toString(); > > This can be rewritten as: > > char[] value = new char[concatType.parameterCount()]; > Arrays.fill(value, TAG_ARG); > recipe = new String(value); Yes. > And when you add to the JavaLangAccess interface a new method > newStringUnsafe(byte[] value, byte coder), then you can even use the > package private constructor String(byte[], byte) to avoid copying of > bytes. But I'm not sure if it is worthwhile. Actually, java.lang.StringConcatHelper gains access to that constructor. But this is important only hot path, which is linkage method is hopefully not the part of. > 558 int cCount = 0; > 559 int oCount = 0; > 560 for (int i = 0; i < recipe.length(); i++) { > 561 char c = recipe.charAt(i); > 562 if (c == TAG_CONST) cCount++; > 563 if (c == TAG_ARG) oCount++; > 564 } > > This loop is only needed, when the recipe is already known. When you > move the lines 558 and 559 before the line > > 547 if (generateRecipe) { > > then you can initialize oCount directly after the line 547: > > oCount = concatType.parameterCount(); > > and move the for-loop (lines 560-564) into the else clause of the "if > (generateRecipe)" statement. Yes, okay. > Btw. I would rename the variables cCount and oCount to constCount and argCount. > > 601 Key key = new Key(mt, rec); > 602 MethodHandle mh = CACHE_ENABLE ? CACHE.get(key) : null; > > If you rewrite this lines as: > > 601 Key key = null; > 602 MethodHandle mh = CACHE_ENABLE ? CACHE.get(key = new > Key(mt, rec)) : null; > > then you can avoid creation of Key objects when caching is disabled. I rearranged the code there, so that Key is never needed when caching is disabled. > 669 SIZED_EXACT(true, true), > > The comma is not needed. Yes. > 672 boolean sized, exact; > > sized and exact should be final. Yes. > 1619 private static Class STRING_HELPER; > 1620 > 1621 static { > 1622 try { > 1623 STRING_HELPER = > Class.forName("java.lang.StringConcatHelper"); > 1624 } catch (ClassNotFoundException e) { > 1625 throw new AssertionError(e); > 1626 } > > Why STRING_HELPER is not final? No reason, overlook. Fixed. > I have a small question to the Recipe class. Is it really better to > create elementsRev instead of using the old-school for-loop and > List.get(int) to loop over the list of RecipeElements in the reverse > order? If there is any reason, then could you please document it to > avoid stupid questions in the future? :-) I just think that a for-each loop over a collection is simpler there. > src/java.base/share/classes/java/lang/invoke/StringConcatException.java > > 31 private static final long serialVersionUID = 292L + 9L; > > I see that the pattern for serialVersionUID like this is already used > in four other classes (BootstrapMethodError, MethodType, > WrongMethodTypeException, LambdaConversioinException). Does it have > some special meaning? I'm just curious. I think this means: JSR 292 (invokedynamic) exception, introduces in JDK 9. StringConcatException follows suit. Thanks, -Aleksey -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From aleksey.shipilev at oracle.com Sun Nov 29 18:23:43 2015 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Sun, 29 Nov 2015 21:23:43 +0300 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <5658AB60.3090606@oracle.com> References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> <5657A1BD.2080603@oracle.com> <5657ABCE.3010106@oracle.com> <5658943F.4040100@oracle.com> <5658AB60.3090606@oracle.com> Message-ID: <565B42AF.8060602@oracle.com> Hi Maurizio, Updated webrevs: http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.04/ http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.05/ On 11/27/2015 10:13 PM, Maurizio Cimadamore wrote: > Looks great - the only minor quibble is that now StringConcat looks like > a regular javac context class; it even has an instance method - it's > therefore best to follow usual initialization pattern for javac components: That makes sense. I had a concern that Gen and StringConcat are circularly dependent on each other, but this seems to be handled by exposing the underconstructed Gen early. Thanks, -Aleksey -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From maurizio.cimadamore at oracle.com Sun Nov 29 21:41:53 2015 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Sun, 29 Nov 2015 21:41:53 +0000 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <565B42AF.8060602@oracle.com> References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> <5657A1BD.2080603@oracle.com> <5657ABCE.3010106@oracle.com> <5658943F.4040100@oracle.com> <5658AB60.3090606@oracle.com> <565B42AF.8060602@oracle.com> Message-ID: <565B7121.3000708@oracle.com> Looks great - thanks! Maurizio On 29/11/15 18:23, Aleksey Shipilev wrote: > Hi Maurizio, > > Updated webrevs: > http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.04/ > http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.05/ > > On 11/27/2015 10:13 PM, Maurizio Cimadamore wrote: >> Looks great - the only minor quibble is that now StringConcat looks like >> a regular javac context class; it even has an instance method - it's >> therefore best to follow usual initialization pattern for javac components: > That makes sense. I had a concern that Gen and StringConcat are > circularly dependent on each other, but this seems to be handled by > exposing the underconstructed Gen early. > > Thanks, > -Aleksey > > From andrej.golovnin at gmail.com Mon Nov 30 09:34:02 2015 From: andrej.golovnin at gmail.com (Andrej Golovnin) Date: Mon, 30 Nov 2015 10:34:02 +0100 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <565B42AF.8060602@oracle.com> References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> <5657A1BD.2080603@oracle.com> <5657ABCE.3010106@oracle.com> <5658943F.4040100@oracle.com> <5658AB60.3090606@oracle.com> <565B42AF.8060602@oracle.com> Message-ID: Hi Aleksey, > http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.05/ src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java 669 final boolean sized; 670 final boolean exact; The fields can be declared private. test/java/lang/String/concat/ImplicitStringConcat.java 119 static StringBuffer sb = new StringBuffer(); 120 static { 121 sb.append('a'); 122 } This can be rewritten as: static StringBuffer sb = new StringBuffer().append('a'); or even as: static StringBuffer sb = new StringBuffer("a"); The result should be the same. But it is easier to read. Otherwise looks good. And I think you need now a real reviewer. :-) Best regards, Andrej Golovnin From aleksey.shipilev at oracle.com Mon Nov 30 13:38:17 2015 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Mon, 30 Nov 2015 16:38:17 +0300 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> <5657A1BD.2080603@oracle.com> <5657ABCE.3010106@oracle.com> <5658943F.4040100@oracle.com> <5658AB60.3090606@oracle.com> <565B42AF.8060602@oracle.com> Message-ID: <565C5149.2090200@oracle.com> Yes, thanks for more polishing, I have uploaded the updates to: http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.06/ http://cr.openjdk.java.net/~shade/8085796/webrev.langtools.04/ More reviews, please! Thanks, -Aleksey On 11/30/2015 12:34 PM, Andrej Golovnin wrote: > Hi Aleksey, > >> http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.05/ > > src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java > > 669 final boolean sized; > 670 final boolean exact; > > The fields can be declared private. > > test/java/lang/String/concat/ImplicitStringConcat.java > > 119 static StringBuffer sb = new StringBuffer(); > 120 static { > 121 sb.append('a'); > 122 } > > This can be rewritten as: > > static StringBuffer sb = new StringBuffer().append('a'); > > or even as: > > static StringBuffer sb = new StringBuffer("a"); > > The result should be the same. But it is easier to read. > > Otherwise looks good. And I think you need now a real reviewer. :-) > > Best regards, > Andrej Golovnin > -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From andrej.golovnin at gmail.com Mon Nov 30 14:03:47 2015 From: andrej.golovnin at gmail.com (Andrej Golovnin) Date: Mon, 30 Nov 2015 15:03:47 +0100 Subject: Code (Pre-)Review for JEP 280: Indify String Concat In-Reply-To: <565C5149.2090200@oracle.com> References: <564E37DE.4070805@oracle.com> <5656EFB0.2090805@oracle.com> <5657A1BD.2080603@oracle.com> <5657ABCE.3010106@oracle.com> <5658943F.4040100@oracle.com> <5658AB60.3090606@oracle.com> <565B42AF.8060602@oracle.com> <565C5149.2090200@oracle.com> Message-ID: Hi Aleksey, > Yes, thanks for more polishing, I have uploaded the updates to: > http://cr.openjdk.java.net/~shade/8085796/webrev.jdk.06/ Maybe one more: 1342 Class[] cls = new Class[cnt]; 1343 for (int i = 0; i < cnt; i++) { 1344 cls[i] = int.class; 1345 } The for-loop can be replaced by: Arrays.fill(cls, int.class); Best regards, Andrej Golovnin From jonathan.gibbons at oracle.com Mon Nov 30 21:43:50 2015 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Mon, 30 Nov 2015 13:43:50 -0800 Subject: Using error-types in annotation processors In-Reply-To: References: Message-ID: <565CC316.40000@oracle.com> cc: compiler-dev bcc: anno-pipeline-dev That being said, it seems like this is a bug/rfe that should be filed and fixed. -- Jon On 11/27/2015 05:36 AM, Victor Nazarov wrote: > Hello, > > I hope that this is an appropriate place to write my question. > > To add some context, I'm a developer of [adt4j]( > https://github.com/sviperll/adt4j) project. > > Java compiler pass every reference to unknown classes as an "error" type. > But it can be useful to inspect such error-types in annotation processor to > actually generate missing classes. This somewhat works in latest JDK8, but > not in the special case interesting for adt4j project. > > The way to inspect error type is to use methods provided by > ErrorType-class. There are only two interesting ways to inspect error type: > > errorType.asElement().getSimpleName() --- to get the name of missing class > errorType.getTypeArguments() --- to get type-arguments applied to > type-to-be. > > The problem is that sometimes these methods provide no useful information. > In such situation getSimpleName method returns useless "" string and > no feather processing is possible. > > Suppose that we want to generate class MyClassToGenerate and it is > currently missing. Below are some code snippets. With Example1, Example2 > and Example3 error-type processing works as expected. Example4 doesn't work > as expected and always returns "" string. This looks inconsistent and > I'd be glad if it can be fixed in future versions of Java... > > Example1 > -------------- > class MyClass extends MyClassToGenerate { > } > > Example2 > -------------- > class MyClass extends MyClassToGenerate { > } > > Example3 > -------------- > class MyClass { > void method1(MyClassToGenerate argument) { > } > } > > Example4 > -------------- > class MyClass { > void method1(MyClassToGenerate argument) { > } > } > > -- > Victor Nazarov From varming at gmail.com Mon Nov 30 22:42:26 2015 From: varming at gmail.com (Carsten Varming) Date: Mon, 30 Nov 2015 17:42:26 -0500 Subject: Build failure: langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java:1735 Message-ID: Dear compiler-dev list, I was trying to build the tip of the jdk9-rt forest today and ran into this failure: /home/cvarming/workspace/jdk9-rt/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java:1735: error: cannot find symbol Errors.OverrideIncompatibleRet(Fragments.CantHide(m, m.location(), other, ^ symbol: method CantHide(MethodSymbol,Symbol,MethodSymbol,Symbol) location: class Fragments 1 error If I go back to 3094:3449ae78c6dc in the langtools repo, then everything works, but any later commit is broken. Is this a known issue where I simply need to wait a few days for a fix to appear? Carsten -------------- next part -------------- An HTML attachment was scrubbed... URL: From luke-mail at online.de Thu Nov 12 00:55:41 2015 From: luke-mail at online.de (Lukas Magel) Date: Thu, 12 Nov 2015 00:55:41 -0000 Subject: Inverse annotation inheritance issue with generic interfaces Message-ID: <5643E389.3020003@online.de> Hello, I am currently working on a JAVA EE web project and have been experiencing a compiler behavior which I don't know how to interpret. In our code we define interfaces like the following: public interface SampleInterface { public void sampleMethod(T t); } as well as an implementing class: public class Main implements SampleInterface { @SampleAnnotation public void sampleMethod(B t) { } } and the corresponding annotation: @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface SampleAnnotation { } Where Class B extends A. All classes are compiled using the OpenJDK7 compiler. If I use Reflection to retrieve all methods of the Main class at runtime and print each method with its annotations I get the following list of methods: class Main public void Main.sampleMethod(A) @SampleAnnotation() public void Main.sampleMethod(B) @SampleAnnotation() The compiler will assign the annotation to the method declaration of the interface although the annotation is only declared in the implementing class. I cannot reproduce this behavior with the Oracle Java Compiler or the Eclipse JDT Compiler. If I compile the example with one of the two compilers the resulting program will yield the following result: class annotation.Main public void annotation.Main.sampleMethod(annotation.A) public void annotation.Main.sampleMethod(annotation.B) @annotation.SampleAnnotation() The JRE type (Oracle, OpenJDK) that the program is executed with has no influence on the result. My actual question is whether this behavior is intended or not because it causes quite some issues with our JAXRS REST implementations. All REST classes each implement an interface like the one above and are annotated with multiple annotations to allow the container to identify endpoints at runtime. The JAXRS framework uses reflection to determine possible method candidates at runtime and will happily accept both the generic and the special method since both of the carry the annotations. I can also provide an example project if necessary. Thanks, Lukas