From vladimir.x.ivanov at oracle.com Thu Mar 1 22:17:35 2018 From: vladimir.x.ivanov at oracle.com (Vladimir Ivanov) Date: Fri, 2 Mar 2018 01:17:35 +0300 Subject: Error, Java 8, lambda form compilation In-Reply-To: References: <2655fbc6-6c47-2b78-9bbe-b7c93522855f@oracle.com> Message-ID: <6b645969-e001-e084-53b9-4c12bfbb9c52@oracle.com> On 2/28/18 11:52 PM, Charles Oliver Nutter wrote: > Ah-ha...I added some logging, which of course made the error go > away...but about ten tests later I got a metaspace OOM. That makes sense. BTW there's another source of exceptions during MethodHandle construction (e.g., JDK-8086252 [1]): java.lang.VirtualMachineError: Out of space in CodeCache for adapters > Could be this was all just a memory issue, but it would be nice if the > error didn't get swallowed. It's not swallowed, but wrapped in InternalError before rethrowing. Do you have control over test harness to print the whole exception chain? Best regards, Vladimir Ivanov [1] https://bugs.openjdk.java.net/browse/JDK-8086252 > On Wed, Feb 28, 2018 at 12:40 PM Charles Oliver Nutter > > wrote: > > Hey, I'm still not sure how best to deal with this, but we've been > consistently getting a similar error at the same place. It has kept > JRuby master CI red for many weeks. > > The problem does not reproduce when running in isolation...only in a > long test run, and so far only on Travis CI (Ubuntu 16.something, > Java 8u151). > > Looking at the code, it appears the dropArguments call below (called > from MethodHandles.guardWithTest:3018) was replaced with some new > code and dropArgumentsToMatch in 9. I have not read through logs to > see if that change might be related. > > Unhandled Java exception: java.lang.InternalError: exactInvoker=Lambda(a0:L/SpeciesData,a1:L,a2:L)=>{ > [exec] t3:L=BoundMethodHandle$Species_LL.argL1(a0:L); > [exec] t4:L=MethodHandle.invokeBasic(t3:L); > [exec] t5:L=BoundMethodHandle$Species_LL.argL0(a0:L); > [exec] t6:V=Invokers.checkExactType(t4:L,t5:L); > [exec] t7:V=Invokers.checkCustomized(t4:L); > [exec] t8:I=MethodHandle.invokeBasic(t4:L);t8:I} > [exec] java.lang.InternalError: exactInvoker=Lambda(a0:L/SpeciesData,a1:L,a2:L)=>{ > [exec] t3:L=BoundMethodHandle$Species_LL.argL1(a0:L); > [exec] t4:L=MethodHandle.invokeBasic(t3:L); > [exec] t5:L=BoundMethodHandle$Species_LL.argL0(a0:L); > [exec] t6:V=Invokers.checkExactType(t4:L,t5:L); > [exec] t7:V=Invokers.checkCustomized(t4:L); > [exec] t8:I=MethodHandle.invokeBasic(t4:L);t8:I} > [exec] newInternalError at java/lang/invoke/MethodHandleStatics.java:127 > [exec] compileToBytecode at java/lang/invoke/LambdaForm.java:660 > [exec] prepare at java/lang/invoke/LambdaForm.java:635 > [exec] at java/lang/invoke/MethodHandle.java:461 > [exec] at java/lang/invoke/BoundMethodHandle.java:58 > [exec] at java/lang/invoke/Species_LL:-1 > [exec] copyWith at java/lang/invoke/Species_LL:-1 > [exec] dropArguments at java/lang/invoke/MethodHandles.java:2465 > [exec] guardWithTest at java/lang/invoke/MethodHandles.java:3018 > [exec] guardWithTest at java/lang/invoke/SwitchPoint.java:173 > [exec] searchConst at org/jruby/ir/targets/ConstantLookupSite.java:103 > > > On Fri, Jan 12, 2018 at 9:54 AM Charles Oliver Nutter > > wrote: > > I wish I could provide more info here. Just got another one in CI: > > [exec] [1603/8763] TestBenchmark#test_benchmark_makes_extra_calcultations_with_an_Array_at_the_end_of_the_benchmark_and_show_the_resultUnhandled Java exception: java.lang.BootstrapMethodError: call site initialization exception > [exec] java.lang.BootstrapMethodError: call site initialization exception > [exec] makeSite at java/lang/invoke/CallSite.java:341 > [exec] linkCallSiteImpl at java/lang/invoke/MethodHandleNatives.java:307 > [exec] linkCallSite at java/lang/invoke/MethodHandleNatives.java:297 > [exec] block in autorun at /home/travis/build/jruby/jruby/test/mri/lib/test/unit.rb:935 > [exec] callDirect at org/jruby/runtime/CompiledIRBlockBody.java:151 > [exec] call at org/jruby/runtime/IRBlockBody.java:77 > [exec] call at org/jruby/runtime/Block.java:124 > [exec] call at org/jruby/RubyProc.java:288 > [exec] call at org/jruby/RubyProc.java:272 > [exec] tearDown at org/jruby/Ruby.java:3276 > [exec] tearDown at org/jruby/Ruby.java:3249 > [exec] internalRun at org/jruby/Main.java:309 > [exec] run at org/jruby/Main.java:232 > [exec] main at org/jruby/Main.java:204 > [exec] > [exec] Caused by: > [exec] java.lang.InternalError: BMH.reinvoke=Lambda(a0:L/SpeciesData,a1:L,a2:L,a3:L)=>{ > [exec] t4:L=Species_L.argL0(a0:L); > [exec] t5:L=MethodHandle.invokeBasic(t4:L,a1:L,a2:L,a3:L);t5:L} > [exec] newInternalError at java/lang/invoke/MethodHandleStatics.java:127 > [exec] compileToBytecode at java/lang/invoke/LambdaForm.java:660 > [exec] prepare at java/lang/invoke/LambdaForm.java:635 > [exec] at java/lang/invoke/MethodHandle.java:461 > [exec] at java/lang/invoke/BoundMethodHandle.java:58 > [exec] at java/lang/invoke/BoundMethodHandle.java:211 > [exec] make at java/lang/invoke/BoundMethodHandle.java:224 > [exec] makeReinvoker at java/lang/invoke/BoundMethodHandle.java:141 > [exec] rebind at java/lang/invoke/DirectMethodHandle.java:130 > [exec] insertArguments at java/lang/invoke/MethodHandles.java:2371 > [exec] up at com/headius/invokebinder/transform/Insert.java:99 > > > On Tue, Jan 9, 2018 at 12:18 PM Vladimir Ivanov > > wrote: > > Thanks, Charlie. > > Unfortunately, it doesn't give much info without the > exception which > caused it. > > jdk/src/share/classes/java/lang/invoke/LambdaForm.java: > ? ? 659? ? ? ? ?} catch (Error | Exception ex) { > ? ? 660? ? ? ? ? ? ?throw newInternalError(this.toString(), > ex); > ? ? 661? ? ? ? ?} > > Best regards, > Vladimir Ivanov > > On 1/9/18 9:10 PM, Charles Oliver Nutter wrote: > > Unfortunately this just happened in one build, but I > thought I'd post it > > here for posterity. > > > > Unhandled Java exception: java.lang.InternalError: > identity_L=Lambda(a0:L/SpeciesData,a1:L,a2:L)=>{ > >? ? ? ?[exec]? ? ?t3:L=Species_L.argL0(a0:L);t3:L} > >? ? ? ?[exec] java.lang.InternalError: > identity_L=Lambda(a0:L/SpeciesData,a1:L,a2:L)=>{ > >? ? ? ?[exec]? ? ?t3:L=Species_L.argL0(a0:L);t3:L} > >? ? ? ?[exec]? ? newInternalError at > java/lang/invoke/MethodHandleStatics.java:127 > >? ? ? ?[exec]? ?compileToBytecode at > java/lang/invoke/LambdaForm.java:660 > >? ? ? ?[exec]? ? ? ? ? ? ?prepare at > java/lang/invoke/LambdaForm.java:635 > >? ? ? ?[exec]? ? ? ? ? ? ? at > java/lang/invoke/MethodHandle.java:461 > >? ? ? ?[exec]? ? ? ? ? ? ? at > java/lang/invoke/BoundMethodHandle.java:58 > >? ? ? ?[exec]? ? ? ? ? ? ? at > java/lang/invoke/BoundMethodHandle.java:211 > >? ? ? ?[exec]? ? ? ? ? ? copyWith at > java/lang/invoke/BoundMethodHandle.java:228 > >? ? ? ?[exec]? ? ? ?dropArguments at > java/lang/invoke/MethodHandles.java:2465 > >? ? ? ?[exec]? ? ? ?dropArguments at > java/lang/invoke/MethodHandles.java:2535 > >? ? ? ?[exec]? ? ? ? ? ? ? ? ? up at > com/headius/invokebinder/transform/Drop.java:39 > >? ? ? ?[exec]? ? ? ? ? ? ? invoke at > com/headius/invokebinder/Binder.java:1143 > >? ? ? ?[exec]? ? ? ? ? ? constant at > com/headius/invokebinder/Binder.java:1116 > >? ? ? ?[exec]? ? ? ? ?searchConst at > org/jruby/ir/targets/ConstantLookupSite.java:98 > >? ? ? ?[exec]? ? block in autorun at > /home/travis/build/jruby/jruby/test/mri/lib/test/unit.rb:935 > >? ? ? ?[exec]? ? ? ? ? callDirect at > org/jruby/runtime/CompiledIRBlockBody.java:151 > >? ? ? ?[exec]? ? ? ? ? ? ? ? call at > org/jruby/runtime/IRBlockBody.java:77 > >? ? ? ?[exec]? ? ? ? ? ? ? ? call at > org/jruby/runtime/Block.java:124 > >? ? ? ?[exec]? ? ? ? ? ? ? ? call at > org/jruby/RubyProc.java:288 > >? ? ? ?[exec]? ? ? ? ? ? ? ? call at > org/jruby/RubyProc.java:272 > >? ? ? ?[exec]? ? ? ? ? ? tearDown at org/jruby/Ruby.java:3276 > >? ? ? ?[exec]? ? ? ? ? ? tearDown at org/jruby/Ruby.java:3249 > >? ? ? ?[exec]? ? ? ? ?internalRun at org/jruby/Main.java:309 > >? ? ? ?[exec]? ? ? ? ? ? ? ? ?run at org/jruby/Main.java:232 > >? ? ? ?[exec]? ? ? ? ? ? ? ? main at org/jruby/Main.java:204 > > > > - Charlie > > > > > > > > _______________________________________________ > > mlvm-dev mailing list > > mlvm-dev at openjdk.java.net > > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev > > > > -- > > - Charlie (mobile) > > -- > > - Charlie (mobile) > From john.r.rose at oracle.com Fri Mar 2 01:47:21 2018 From: john.r.rose at oracle.com (John Rose) Date: Thu, 1 Mar 2018 17:47:21 -0800 Subject: Strange observation: MethodHandle.invokeWithArguments() would not work, whereas Method.invoke() would with the very same arguments In-Reply-To: References: Message-ID: <7CA6C6AC-CBFC-4851-A80A-22A863D4E38F@oracle.com> On Feb 12, 2018, at 11:59 AM, Rony G. Flatscher wrote: > > While testing a rather complex one (an adaption of the JavaFX address book example enhanced with a > BarChart, [1]), that exhibits a very strange behavior: when setting the values for the CategoryAxis > supplying an ObservableList of the month names in the current Locale, using a MethodHandle and > invoking it with invokeWithArguments() would yield (debug output): I just happened to see your message about your adventures with method handle: http://mail.openjdk.java.net/pipermail/jigsaw-dev/2018-February/013603.html This isn't really a jigsaw question, so I'm replying to mlvm-dev. It looks like you are mixing or interconverting arrays of strings with lists of strings. The print statements and CCE show that you are passing an array of strings into a place which expects a single string, and the print statements suggest you are in fact passing a list containing a string array into a place which expects a list of strings. Either way there are too many brackets in your actual argument. The prime suspect when the number of brackets is off by one is varargs. You code might be failing because of surprises in the overload resolution of invokeWA, which accepts a varargs Object array *and* a single List. Is your runtime invoke mechanism treating invokeWA as an ordinary method? It is rather extraordinary, and may warrant a second look. String str; Object obj; Object[] aobj; String[] astr; List lst; plain single arity invocations: 1 mh.invokeWithArguments(str) => new Object[] { str } 2 mh.invokeWithArguments(obj) => new Object[] { obj } and yet: 3 mh.invokeWithArguments(aobj) => aobj (multiple args) 4 mh.invokeWithArguments(astr) => astr (multiple args again!) 5 mh.invokeWithArguments(lst) => lst.toArray() (multiple args again!) but again, a cast removes varargs: 6 mh.invokeWithArguments((Object) aobj) => new Object[] { aobj } 7 mh.invokeWithArguments((Object) astr) => new Object[] { astr } 8 mh.invokeWithArguments((Object) lst) => new Object[] { lst } Your bug looks like a confusion between two of these, perhaps 5 and 8. Regards, ? John -------------- next part -------------- An HTML attachment was scrubbed... URL: From vladimir.x.ivanov at oracle.com Fri Mar 2 18:10:36 2018 From: vladimir.x.ivanov at oracle.com (Vladimir Ivanov) Date: Fri, 2 Mar 2018 21:10:36 +0300 Subject: ClassValue rooting objects after it goes away? In-Reply-To: References: <3A83C9E2-184B-47D7-8F66-D817E98295DC@oracle.com> <55DE2455.3000006@gmx.org> <2048864869.651852.1440629650730.JavaMail.zimbra@u-pem.fr> <55DEDE5D.1090405@gmx.org> <55DEF5B1.8080501@gmx.org> Message-ID: <82b69feb-1f9a-09fb-b0c1-023c6dc88263@oracle.com> Charlie, Does it look similar to the following bugs? https://bugs.openjdk.java.net/browse/JDK-8136353 https://bugs.openjdk.java.net/browse/JDK-8169425 If that's the same (and it seems so to me [1]), then speak up and persuade Paul it's an important edge case (as stated in JDK-8169425). Best regards, Vladimir Ivanov [1] new RubyClass(Ruby.this) in public static class Ruby { private ClassValue cache = new ClassValue() { protected RubyClass computeValue(Class type) { return new RubyClass(Ruby.this); } }; On 3/1/18 2:25 AM, Charles Oliver Nutter wrote: > So I don't think we ever closed the loop here. Did anyone on the JDK > side confirm this, file an issue, or fix it? > > We still have ClassValue disabled in JRuby because of the rooting issues > described here and in https://github.com/jruby/jruby/pull/3228. > > - Charlie > > On Thu, Aug 27, 2015 at 7:04 AM Jochen Theodorou > wrote: > > One more thing... > > Remi, I tried your link with my simplified scenario and it does there > not stop the collection of the classloader > > Am 27.08.2015 11:54, schrieb Jochen Theodorou: > > Hi, > > > > In trying to reproduce the problem outside of Groovy I stumbled > over a > > case case which I think should work > > > > public class MyClassValue extends ClassValue { > >? ? ? protected Object computeValue(Class type) { > >? ? ? ? ? Dummy ret = new Dummy(); > >? ? ? ? ? Dummy.l.add (this); > >? ? ? ? ? return ret; > >? ? ? } > > } > > > >? ?class Dummy { > >? ? ? ?static final ArrayList l = new ArrayList(); > >? ?} > > > > basically this means there will be a hard reference on the ClassValue > > somewhere. It can be in a static or non-static field, direct or > > indirect. But this won't collect. If I put for example a > WeakReference > > in between it works again. > > > > Finally I also tested to put the hard reference in a third class > > instead, to avoid this self reference. But it can still not collect. > > > > So I currently have the impression that if anything holds a hard > > reference on the class value that the classloader cannot be collected > > anymore. > > > > Unless I misunderstand something here I see that as a bug > > > > bye blackdrag > > > > > -- > Jochen "blackdrag" Theodorou > blog: http://blackdragsview.blogspot.com/ > > _______________________________________________ > mlvm-dev mailing list > mlvm-dev at openjdk.java.net > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev > > -- > > - Charlie (mobile) > > > > _______________________________________________ > mlvm-dev mailing list > mlvm-dev at openjdk.java.net > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev > From headius at headius.com Fri Mar 2 20:13:36 2018 From: headius at headius.com (Charles Oliver Nutter) Date: Fri, 02 Mar 2018 20:13:36 +0000 Subject: ClassValue rooting objects after it goes away? In-Reply-To: <82b69feb-1f9a-09fb-b0c1-023c6dc88263@oracle.com> References: <3A83C9E2-184B-47D7-8F66-D817E98295DC@oracle.com> <55DE2455.3000006@gmx.org> <2048864869.651852.1440629650730.JavaMail.zimbra@u-pem.fr> <55DEDE5D.1090405@gmx.org> <55DEF5B1.8080501@gmx.org> <82b69feb-1f9a-09fb-b0c1-023c6dc88263@oracle.com> Message-ID: Yes, it may be the same bug. In my case, the ClassValue is held by a utility object used for our Java integration. That utility object has to live somewhere, so it's held by the JRuby runtime instance. There's a strong reference chain leading to the ClassValue. The value is a Ruby representation of the class, with reflected methods parsed out and turned into Ruby endpoints. Obviously, the value also references the class, either directly or indirectly through reflected members. The Ruby class wrapper is only hard referenced directly if there's an instance of the object live and moving through JRuby. It may be referenced indirectly through inline caches. However...I do not believe this should prevent collection of the class associated with the ClassValue. The value referenced in the ClassValue should not constitute a hard reference. If it is alive *only* because of its associate with a given class, that should not be enough to root either the object or the class. ClassValue should work like ThreadLocal. If the Thread associated with a value goes away, the value reference goes away. ThreadLocal does nothing prevent it from being collected. If the Class associated with a Value goes away, the same should happen to that Value and it should be collectable once all other hard references are gone. Perhaps I've misunderstood? - Charlie On Fri, Mar 2, 2018 at 12:16 PM Vladimir Ivanov < vladimir.x.ivanov at oracle.com> wrote: > Charlie, > > Does it look similar to the following bugs? > https://bugs.openjdk.java.net/browse/JDK-8136353 > https://bugs.openjdk.java.net/browse/JDK-8169425 > > If that's the same (and it seems so to me [1]), then speak up and > persuade Paul it's an important edge case (as stated in JDK-8169425). > > Best regards, > Vladimir Ivanov > > [1] new RubyClass(Ruby.this) in > > public static class Ruby { > private ClassValue cache = new ClassValue() > { > protected RubyClass computeValue(Class type) { > return new RubyClass(Ruby.this); > } > }; > > On 3/1/18 2:25 AM, Charles Oliver Nutter wrote: > > So I don't think we ever closed the loop here. Did anyone on the JDK > > side confirm this, file an issue, or fix it? > > > > We still have ClassValue disabled in JRuby because of the rooting issues > > described here and in https://github.com/jruby/jruby/pull/3228. > > > > - Charlie > > > > On Thu, Aug 27, 2015 at 7:04 AM Jochen Theodorou > > wrote: > > > > One more thing... > > > > Remi, I tried your link with my simplified scenario and it does there > > not stop the collection of the classloader > > > > Am 27.08.2015 11:54, schrieb Jochen Theodorou: > > > Hi, > > > > > > In trying to reproduce the problem outside of Groovy I stumbled > > over a > > > case case which I think should work > > > > > > public class MyClassValue extends ClassValue { > > > protected Object computeValue(Class type) { > > > Dummy ret = new Dummy(); > > > Dummy.l.add (this); > > > return ret; > > > } > > > } > > > > > > class Dummy { > > > static final ArrayList l = new ArrayList(); > > > } > > > > > > basically this means there will be a hard reference on the > ClassValue > > > somewhere. It can be in a static or non-static field, direct or > > > indirect. But this won't collect. If I put for example a > > WeakReference > > > in between it works again. > > > > > > Finally I also tested to put the hard reference in a third class > > > instead, to avoid this self reference. But it can still not > collect. > > > > > > So I currently have the impression that if anything holds a hard > > > reference on the class value that the classloader cannot be > collected > > > anymore. > > > > > > Unless I misunderstand something here I see that as a bug > > > > > > bye blackdrag > > > > > > > > > -- > > Jochen "blackdrag" Theodorou > > blog: http://blackdragsview.blogspot.com/ > > > > _______________________________________________ > > mlvm-dev mailing list > > mlvm-dev at openjdk.java.net > > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev > > > > -- > > > > - Charlie (mobile) > > > > > > > > _______________________________________________ > > mlvm-dev mailing list > > mlvm-dev at openjdk.java.net > > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev > > > -- - Charlie (mobile) -------------- next part -------------- An HTML attachment was scrubbed... URL: From headius at headius.com Fri Mar 2 20:19:35 2018 From: headius at headius.com (Charles Oliver Nutter) Date: Fri, 02 Mar 2018 20:19:35 +0000 Subject: ClassValue rooting objects after it goes away? In-Reply-To: References: <3A83C9E2-184B-47D7-8F66-D817E98295DC@oracle.com> <55DE2455.3000006@gmx.org> <2048864869.651852.1440629650730.JavaMail.zimbra@u-pem.fr> <55DEDE5D.1090405@gmx.org> <55DEF5B1.8080501@gmx.org> <82b69feb-1f9a-09fb-b0c1-023c6dc88263@oracle.com> Message-ID: I have posted a modified version of my description to the main bug report. TLDR: ClassValue should not root objects. - Charlie On Fri, Mar 2, 2018 at 2:13 PM Charles Oliver Nutter wrote: > Yes, it may be the same bug. > > In my case, the ClassValue is held by a utility object used for our Java > integration. That utility object has to live somewhere, so it's held by the > JRuby runtime instance. There's a strong reference chain leading to the > ClassValue. > > The value is a Ruby representation of the class, with reflected methods > parsed out and turned into Ruby endpoints. Obviously, the value also > references the class, either directly or indirectly through reflected > members. > > The Ruby class wrapper is only hard referenced directly if there's an > instance of the object live and moving through JRuby. It may be referenced > indirectly through inline caches. > > However...I do not believe this should prevent collection of the class > associated with the ClassValue. > > The value referenced in the ClassValue should not constitute a hard > reference. If it is alive *only* because of its associate with a given > class, that should not be enough to root either the object or the class. > > ClassValue should work like ThreadLocal. If the Thread associated with a > value goes away, the value reference goes away. ThreadLocal does nothing > prevent it from being collected. If the Class associated with a Value goes > away, the same should happen to that Value and it should be collectable > once all other hard references are gone. > > Perhaps I've misunderstood? > > - Charlie > > On Fri, Mar 2, 2018 at 12:16 PM Vladimir Ivanov < > vladimir.x.ivanov at oracle.com> wrote: > >> Charlie, >> >> Does it look similar to the following bugs? >> https://bugs.openjdk.java.net/browse/JDK-8136353 >> https://bugs.openjdk.java.net/browse/JDK-8169425 >> >> If that's the same (and it seems so to me [1]), then speak up and >> persuade Paul it's an important edge case (as stated in JDK-8169425). >> >> Best regards, >> Vladimir Ivanov >> >> [1] new RubyClass(Ruby.this) in >> >> public static class Ruby { >> private ClassValue cache = new >> ClassValue() { >> protected RubyClass computeValue(Class type) { >> return new RubyClass(Ruby.this); >> } >> }; >> >> On 3/1/18 2:25 AM, Charles Oliver Nutter wrote: >> > So I don't think we ever closed the loop here. Did anyone on the JDK >> > side confirm this, file an issue, or fix it? >> > >> > We still have ClassValue disabled in JRuby because of the rooting issues >> > described here and in https://github.com/jruby/jruby/pull/3228. >> > >> > - Charlie >> > >> > On Thu, Aug 27, 2015 at 7:04 AM Jochen Theodorou > > > wrote: >> > >> > One more thing... >> > >> > Remi, I tried your link with my simplified scenario and it does >> there >> > not stop the collection of the classloader >> > >> > Am 27.08.2015 11:54, schrieb Jochen Theodorou: >> > > Hi, >> > > >> > > In trying to reproduce the problem outside of Groovy I stumbled >> > over a >> > > case case which I think should work >> > > >> > > public class MyClassValue extends ClassValue { >> > > protected Object computeValue(Class type) { >> > > Dummy ret = new Dummy(); >> > > Dummy.l.add (this); >> > > return ret; >> > > } >> > > } >> > > >> > > class Dummy { >> > > static final ArrayList l = new ArrayList(); >> > > } >> > > >> > > basically this means there will be a hard reference on the >> ClassValue >> > > somewhere. It can be in a static or non-static field, direct or >> > > indirect. But this won't collect. If I put for example a >> > WeakReference >> > > in between it works again. >> > > >> > > Finally I also tested to put the hard reference in a third class >> > > instead, to avoid this self reference. But it can still not >> collect. >> > > >> > > So I currently have the impression that if anything holds a hard >> > > reference on the class value that the classloader cannot be >> collected >> > > anymore. >> > > >> > > Unless I misunderstand something here I see that as a bug >> > > >> > > bye blackdrag >> > > >> > >> > >> > -- >> > Jochen "blackdrag" Theodorou >> > blog: http://blackdragsview.blogspot.com/ >> > >> > _______________________________________________ >> > mlvm-dev mailing list >> > mlvm-dev at openjdk.java.net >> > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev >> > >> > -- >> > >> > - Charlie (mobile) >> > >> > >> > >> > _______________________________________________ >> > mlvm-dev mailing list >> > mlvm-dev at openjdk.java.net >> > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev >> > >> > -- > > - Charlie (mobile) > -- - Charlie (mobile) -------------- next part -------------- An HTML attachment was scrubbed... URL: From headius at headius.com Fri Mar 2 20:22:52 2018 From: headius at headius.com (Charles Oliver Nutter) Date: Fri, 02 Mar 2018 20:22:52 +0000 Subject: ClassValue rooting objects after it goes away? In-Reply-To: References: <3A83C9E2-184B-47D7-8F66-D817E98295DC@oracle.com> <55DE2455.3000006@gmx.org> <2048864869.651852.1440629650730.JavaMail.zimbra@u-pem.fr> <55DEDE5D.1090405@gmx.org> <55DEF5B1.8080501@gmx.org> <82b69feb-1f9a-09fb-b0c1-023c6dc88263@oracle.com> Message-ID: Put it another way: does a static reference from a class to itself prevent that class from being garbage collected? Of course not. ClassValue is intended to be a way to inject pseudo-static data into either a class or a Class. Injecting that data, even if it has a reference back to the class, should not prevent the class from being collected. On Fri, Mar 2, 2018 at 2:19 PM Charles Oliver Nutter wrote: > I have posted a modified version of my description to the main bug report. > > TLDR: ClassValue should not root objects. > > - Charlie > > On Fri, Mar 2, 2018 at 2:13 PM Charles Oliver Nutter > wrote: > >> Yes, it may be the same bug. >> >> In my case, the ClassValue is held by a utility object used for our Java >> integration. That utility object has to live somewhere, so it's held by the >> JRuby runtime instance. There's a strong reference chain leading to the >> ClassValue. >> >> The value is a Ruby representation of the class, with reflected methods >> parsed out and turned into Ruby endpoints. Obviously, the value also >> references the class, either directly or indirectly through reflected >> members. >> >> The Ruby class wrapper is only hard referenced directly if there's an >> instance of the object live and moving through JRuby. It may be referenced >> indirectly through inline caches. >> >> However...I do not believe this should prevent collection of the class >> associated with the ClassValue. >> >> The value referenced in the ClassValue should not constitute a hard >> reference. If it is alive *only* because of its associate with a given >> class, that should not be enough to root either the object or the class. >> >> ClassValue should work like ThreadLocal. If the Thread associated with a >> value goes away, the value reference goes away. ThreadLocal does nothing >> prevent it from being collected. If the Class associated with a Value goes >> away, the same should happen to that Value and it should be collectable >> once all other hard references are gone. >> >> Perhaps I've misunderstood? >> >> - Charlie >> >> On Fri, Mar 2, 2018 at 12:16 PM Vladimir Ivanov < >> vladimir.x.ivanov at oracle.com> wrote: >> >>> Charlie, >>> >>> Does it look similar to the following bugs? >>> https://bugs.openjdk.java.net/browse/JDK-8136353 >>> https://bugs.openjdk.java.net/browse/JDK-8169425 >>> >>> If that's the same (and it seems so to me [1]), then speak up and >>> persuade Paul it's an important edge case (as stated in JDK-8169425). >>> >>> Best regards, >>> Vladimir Ivanov >>> >>> [1] new RubyClass(Ruby.this) in >>> >>> public static class Ruby { >>> private ClassValue cache = new >>> ClassValue() { >>> protected RubyClass computeValue(Class type) { >>> return new RubyClass(Ruby.this); >>> } >>> }; >>> >>> On 3/1/18 2:25 AM, Charles Oliver Nutter wrote: >>> > So I don't think we ever closed the loop here. Did anyone on the JDK >>> > side confirm this, file an issue, or fix it? >>> > >>> > We still have ClassValue disabled in JRuby because of the rooting >>> issues >>> > described here and in https://github.com/jruby/jruby/pull/3228. >>> > >>> > - Charlie >>> > >>> > On Thu, Aug 27, 2015 at 7:04 AM Jochen Theodorou >> > > wrote: >>> > >>> > One more thing... >>> > >>> > Remi, I tried your link with my simplified scenario and it does >>> there >>> > not stop the collection of the classloader >>> > >>> > Am 27.08.2015 11:54, schrieb Jochen Theodorou: >>> > > Hi, >>> > > >>> > > In trying to reproduce the problem outside of Groovy I stumbled >>> > over a >>> > > case case which I think should work >>> > > >>> > > public class MyClassValue extends ClassValue { >>> > > protected Object computeValue(Class type) { >>> > > Dummy ret = new Dummy(); >>> > > Dummy.l.add (this); >>> > > return ret; >>> > > } >>> > > } >>> > > >>> > > class Dummy { >>> > > static final ArrayList l = new ArrayList(); >>> > > } >>> > > >>> > > basically this means there will be a hard reference on the >>> ClassValue >>> > > somewhere. It can be in a static or non-static field, direct or >>> > > indirect. But this won't collect. If I put for example a >>> > WeakReference >>> > > in between it works again. >>> > > >>> > > Finally I also tested to put the hard reference in a third class >>> > > instead, to avoid this self reference. But it can still not >>> collect. >>> > > >>> > > So I currently have the impression that if anything holds a hard >>> > > reference on the class value that the classloader cannot be >>> collected >>> > > anymore. >>> > > >>> > > Unless I misunderstand something here I see that as a bug >>> > > >>> > > bye blackdrag >>> > > >>> > >>> > >>> > -- >>> > Jochen "blackdrag" Theodorou >>> > blog: http://blackdragsview.blogspot.com/ >>> > >>> > _______________________________________________ >>> > mlvm-dev mailing list >>> > mlvm-dev at openjdk.java.net >>> > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev >>> > >>> > -- >>> > >>> > - Charlie (mobile) >>> > >>> > >>> > >>> > _______________________________________________ >>> > mlvm-dev mailing list >>> > mlvm-dev at openjdk.java.net >>> > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev >>> > >>> >> -- >> >> - Charlie (mobile) >> > -- > > - Charlie (mobile) > -- - Charlie (mobile) -------------- next part -------------- An HTML attachment was scrubbed... URL: From Rony.Flatscher at wu.ac.at Sat Mar 3 18:02:55 2018 From: Rony.Flatscher at wu.ac.at (Rony G. Flatscher) Date: Sat, 3 Mar 2018 19:02:55 +0100 Subject: Strange observation: MethodHandle.invokeWithArguments() would not work, whereas Method.invoke() would with the very same arguments In-Reply-To: <7CA6C6AC-CBFC-4851-A80A-22A863D4E38F@oracle.com> References: <7CA6C6AC-CBFC-4851-A80A-22A863D4E38F@oracle.com> Message-ID: John, thank you very much for your kind reply and hints! On 02.03.2018 02:47, John Rose wrote: > On Feb 12, 2018, at 11:59 AM, Rony G. Flatscher > wrote: >> >> While testing a rather complex one (an adaption of the JavaFX address book example enhanced with a >> BarChart, [1]), that exhibits a very strange behavior: when setting the values for the CategoryAxis >> supplying an ObservableList of the month names in the current Locale, using a MethodHandle and >> invoking it with invokeWithArguments() would yield (debug output): > > I just happened to see your message about your adventures with method handle: > > http://mail.openjdk.java.net/pipermail/jigsaw-dev/2018-February/013603.html > > This isn't really a jigsaw question, so I'm replying to mlvm-dev. Yes, I just was not sure where to post such an e-mail (as on jigsaw MethodHandle's were suggested I posted it there). > It looks like you are mixing or interconverting arrays of strings > with lists of strings. ?The print statements and CCE show that > you are passing an array of strings into a place which expects > a single string, and the print statements suggest you are > in fact passing a list containing a string array into a place > which expects a list of strings. ?Either way there are too > many brackets in your actual argument. > > The prime suspect when the number of brackets is off by one > is varargs. ?You code might be failing because of surprises > in the overload resolution of invokeWA, which accepts > a varargs Object array *and* a single List. > > Is your runtime invoke mechanism treating invokeWA as an ordinary > method? ?It is rather extraordinary, and may warrant a second look. > > String str; > Object obj; > Object[] aobj; > String[] astr; > List lst; > > plain single arity invocations: > > 1 mh.invokeWithArguments(str) => new Object[] { str } > 2 mh.invokeWithArguments(obj) => new Object[] { obj } > > and yet: > > 3 mh.invokeWithArguments(aobj) => aobj (multiple args) > 4 mh.invokeWithArguments(astr) => astr (multiple args again!) > 5 mh.invokeWithArguments(lst) => lst.toArray() (multiple args again!) > > but again, a cast removes varargs: > > 6 mh.invokeWithArguments((Object) aobj) => new Object[] { aobj } > 7 mh.invokeWithArguments((Object) astr) => new Object[] { astr } > 8 mh.invokeWithArguments((Object) lst) => new Object[] { lst } > > Your bug looks like a confusion between two of these, > perhaps 5 and 8. The invocation occurs with an aobj kind of argument (an array of coerced arguments matching the types of the parameterTypes array), defined as "Object [] coercedArgs=..."); nevertheless will make sure to cast explicitly everywhere invokeWithArguments() gets used (there are MethodHandle.invoke(...) as well, which I will replace with invokeWithArguments instead, just to have everything use the same invocation method consistently in case arguments need to be supplied; also foregoing bindTo().invoke(...), replacing it with appropriate invokeWithArguments() for consistency). ---rony P.S.: After having rewritten the Java reflection (adding caching of Field, Method, Constructor objects together with their corresponding MethodHandle objects) part I also rewrote some of the core ooRexx/C++/JNI stuff to remove old-standing (18+ years) code with modern ooRexx-4.x-API code, which allows to forgo many of the old restrictions, and improving speed in those corners as well (still some cleanup to do). After getting the test units to pass, I turned to this application, and that problem using MethodHandle invocations only does not surface anymore!? -------------- next part -------------- An HTML attachment was scrubbed... URL: From Rony.Flatscher at wu.ac.at Sun Mar 4 18:05:56 2018 From: Rony.Flatscher at wu.ac.at (Rony G. Flatscher) Date: Sun, 4 Mar 2018 19:05:56 +0100 Subject: Strange observation: MethodHandle.invokeWithArguments() would not work, whereas Method.invoke() would with the very same arguments In-Reply-To: References: <7CA6C6AC-CBFC-4851-A80A-22A863D4E38F@oracle.com> Message-ID: <52c27332-9154-06fb-b05d-bf7447626ae1@wu.ac.at> OK, went back to do the changes (making sure to cast invokeWithArguments(...) to (Object[]) and discovered that I forgot a hard-coded override to use core reflection in all cases. Removing that hard-coded flag to use MethodHandles instead made the problem reappear, so I once more went after it in the past hours and think I can now explain this more exact: the case in question is a sequence of the following (transcribed to Java) statements that are executed in the BSF4ooRexx bridge on behalf of the Rexx program (which itself was transcribed from a Java example found on the Internet): * "javafx.collections.FXCollections.observableArrayList()" returns an object that implements the interface "javafx.collections.ObservableList", actually an instance of the non-exported "com.sun.javafx.collections.ObservableListWrapper" class, * a String array of month names gets turned into an ArrayList using "java.util.Arrays.asList(monthNames)" returning listOfMonthNames (a "java.util.Arrays$ArrayList") * "ObservableList.addAll(listOfMonthNames)" gets invoked, * supplying the resulting ObservableListWrapper as an argument to "javafx.scene.chart.CategoryAxis.setCategories(javafx.collections.ObservableList)" works when invoked via core reflection, but causes an exception if invoked via a MethodHandle (the exception being: "java.lang.ClassCastException: java.base/[Ljava.lang.String; cannot be cast to java.base/java.lang.String")! The problem, it turns out is the use of "addAll(listOfMonthNames)" which causes the ObservableList to contain a single list member "java.util.Arrays$ArrayList at xxx" (toString() yielding "[Ljava.lang.String;@yyy"). The core reflection invocations work without an error, the MethodHandle.invokeWithArguments(...) version causes the above exception. Changing the code to use the String array monthNames (not its list version) as an argument (hence: "ObservableList.addAll(monthNames)" ) makes it run with both, the core reflection and the MethodHandle invocation versions. ---rony On 03.03.2018 19:02, Rony G. Flatscher wrote: > John, thank you very much for your kind reply and hints! > > On 02.03.2018 02:47, John Rose wrote: >> On Feb 12, 2018, at 11:59 AM, Rony G. Flatscher > > wrote: >>> >>> While testing a rather complex one (an adaption of the JavaFX address book example enhanced with a >>> BarChart, [1]), that exhibits a very strange behavior: when setting the values for the CategoryAxis >>> supplying an ObservableList of the month names in the current Locale, using a MethodHandle and >>> invoking it with invokeWithArguments() would yield (debug output): >> >> I just happened to see your message about your adventures with method handle: >> >> http://mail.openjdk.java.net/pipermail/jigsaw-dev/2018-February/013603.html >> >> This isn't really a jigsaw question, so I'm replying to mlvm-dev. > Yes, I just was not sure where to post such an e-mail (as on jigsaw MethodHandle's were suggested > I posted it there). > >> It looks like you are mixing or interconverting arrays of strings >> with lists of strings. ?The print statements and CCE show that >> you are passing an array of strings into a place which expects >> a single string, and the print statements suggest you are >> in fact passing a list containing a string array into a place >> which expects a list of strings. ?Either way there are too >> many brackets in your actual argument. >> >> The prime suspect when the number of brackets is off by one >> is varargs. ?You code might be failing because of surprises >> in the overload resolution of invokeWA, which accepts >> a varargs Object array *and* a single List. >> >> Is your runtime invoke mechanism treating invokeWA as an ordinary >> method? ?It is rather extraordinary, and may warrant a second look. >> >> String str; >> Object obj; >> Object[] aobj; >> String[] astr; >> List lst; >> >> plain single arity invocations: >> >> 1 mh.invokeWithArguments(str) => new Object[] { str } >> 2 mh.invokeWithArguments(obj) => new Object[] { obj } >> >> and yet: >> >> 3 mh.invokeWithArguments(aobj) => aobj (multiple args) >> 4 mh.invokeWithArguments(astr) => astr (multiple args again!) >> 5 mh.invokeWithArguments(lst) => lst.toArray() (multiple args again!) >> >> but again, a cast removes varargs: >> >> 6 mh.invokeWithArguments((Object) aobj) => new Object[] { aobj } >> 7 mh.invokeWithArguments((Object) astr) => new Object[] { astr } >> 8 mh.invokeWithArguments((Object) lst) => new Object[] { lst } >> >> Your bug looks like a confusion between two of these, >> perhaps 5 and 8. > The invocation occurs with an aobj kind of argument (an array of coerced arguments matching the > types of the parameterTypes array), defined as "Object [] coercedArgs=..."); nevertheless will > make sure to cast explicitly everywhere invokeWithArguments() gets used (there are > MethodHandle.invoke(...) as well, which I will replace with invokeWithArguments instead, just to > have everything use the same invocation method consistently in case arguments need to be supplied; > also foregoing bindTo().invoke(...), replacing it with appropriate invokeWithArguments() for > consistency). > > ---rony > > P.S.: After having rewritten the Java reflection (adding caching of Field, Method, Constructor > objects together with their corresponding MethodHandle objects) part I also rewrote some of the > core ooRexx/C++/JNI stuff to remove old-standing (18+ years) code with modern ooRexx-4.x-API code, > which allows to forgo many of the old restrictions, and improving speed in those corners as well > (still some cleanup to do). After getting the test units to pass, I turned to this application, > and that problem using MethodHandle invocations only does not surface anymore!? -------------- next part -------------- An HTML attachment was scrubbed... URL: From Rony.Flatscher at wu.ac.at Thu Mar 8 17:42:56 2018 From: Rony.Flatscher at wu.ac.at (Rony G. Flatscher) Date: Thu, 8 Mar 2018 18:42:56 +0100 Subject: Strange observation: MethodHandle.invokeWithArguments() would not work, whereas Method.invoke() would with the very same arguments In-Reply-To: <52c27332-9154-06fb-b05d-bf7447626ae1@wu.ac.at> References: <7CA6C6AC-CBFC-4851-A80A-22A863D4E38F@oracle.com> <52c27332-9154-06fb-b05d-bf7447626ae1@wu.ac.at> Message-ID: <5d1c0363-c948-e594-6e55-eaf099c9a62a@wu.ac.at> Hmm, I ran into another such problem, where using core reflection invoke(...) succeeds whereas using MethodHandle.invokeWithArguments(...) does not. The problem is also linked to the resulting object from Arrays.asList(T... a), this time in the context of a stream example causing a list that contains a single String array, instead of a list that contains the String array elements as its individual list elements. Here is the ooRexx code (the tilde '~' is the explicit message operator, Rexx is caseless and dynamically typed), which was originally transcribed 1:1 from a Java example and which works with core reflection: -- define a Rexx string containing letter 'k' in some of its words wordstring="Just a bunch of words to test for killer items containing a k" -- turn Rexx-string into a Java-string: this allows us to use Java's String methods refWordString=.bsf~new("java.lang.String", wordstring) -- convert the Java string into a Java List (a Collection): alist=bsf.loadClass("java.util.Arrays")~asList(refWordString~split(" ")) -- create a RexxProxy of our Worker class which implements the two functional interface -- methods that we use rexxWorker=BsfCreateRexxProxy(.worker~new, , "java.util.function.Predicate", "java.util.function.Consumer") -- now run a filter stream operation on the list -- (the filter just selects words containing the letter 'k' or 'K') sa=alist~stream~filter(rexxWorker)~toArray -- "filter" employs the Predicate interface -- print the results for verification: loop y over sa say y end say "-----------------------" - now run a foreach operation on a stream -- the consumer here just prints inputs with some surrounding brackets alist~stream~foreach(rexxWorker) -- "forEach" employs the Consumer interface ::requires BSF.CLS -- get access to the Java bridge ::class Worker -- define Rexx class that implements the functional methods -- implements the interface java.util.function.Predicate ::method test -- will return .true for strings containing 'k' or 'K', .false else use arg s -- fetch argument (from Java) return s~caselessPos('k')>0 -- implements the interface java.util.function.Consumer ::method accept -- will show each string use arg s -- fetch argument (from Java) say ">>"s"<<" -- show argument The solution here was the same as already described earlier: in order to use MethodHandle.invokeWithArguments() do not use the result of Arrays.asList(array) and apply stream() on it , but rather create the stream directly with Arrays.stream(array) each time a stream is needed. It is as if the object returned by Arrays.asList(...) is being handled differently if using the core reflection invoke(...) compared to using MethodHandle.invokeWithArguments(...) for unknown reasons (the arguments are processed the same in both cases). ---rony On 04.03.2018 19:05, Rony G. Flatscher wrote: > > OK, went back to do the changes (making sure to cast invokeWithArguments(...) to (Object[]) and > discovered that I forgot a hard-coded override to use core reflection in all cases. > > Removing that hard-coded flag to use MethodHandles instead made the problem reappear, so I once > more went after it in the past hours and think I can now explain this more exact: the case in > question is a sequence of the following (transcribed to Java) statements that are executed in the > BSF4ooRexx bridge on behalf of the Rexx program (which itself was transcribed from a Java example > found on the Internet): > > * "javafx.collections.FXCollections.observableArrayList()" returns an object that implements the > interface "javafx.collections.ObservableList", actually an instance of the non-exported > "com.sun.javafx.collections.ObservableListWrapper" class, > * a String array of month names gets turned into an ArrayList using > "java.util.Arrays.asList(monthNames)" returning listOfMonthNames (a "java.util.Arrays$ArrayList") > * "ObservableList.addAll(listOfMonthNames)" gets invoked, > * supplying the resulting ObservableListWrapper as an argument to > "javafx.scene.chart.CategoryAxis.setCategories(javafx.collections.ObservableList)" works when > invoked via core reflection, but causes an exception if invoked via a MethodHandle (the > exception being: "java.lang.ClassCastException: java.base/[Ljava.lang.String; cannot be cast > to java.base/java.lang.String")! > > The problem, it turns out is the use of "addAll(listOfMonthNames)" which causes the ObservableList > to contain a single list member "java.util.Arrays$ArrayList at xxx" (toString() yielding > "[Ljava.lang.String;@yyy"). The core reflection invocations work without an error, the > MethodHandle.invokeWithArguments(...) version causes the above exception. > > Changing the code to use the String array monthNames (not its list version) as an argument (hence: > "ObservableList.addAll(monthNames)" ) makes it run with both, the core reflection and the > MethodHandle invocation versions. > > ---rony > > > > > > On 03.03.2018 19:02, Rony G. Flatscher wrote: >> John, thank you very much for your kind reply and hints! >> >> On 02.03.2018 02:47, John Rose wrote: >>> On Feb 12, 2018, at 11:59 AM, Rony G. Flatscher >> > wrote: >>>> >>>> While testing a rather complex one (an adaption of the JavaFX address book example enhanced with a >>>> BarChart, [1]), that exhibits a very strange behavior: when setting the values for the CategoryAxis >>>> supplying an ObservableList of the month names in the current Locale, using a MethodHandle and >>>> invoking it with invokeWithArguments() would yield (debug output): >>> >>> I just happened to see your message about your adventures with method handle: >>> >>> http://mail.openjdk.java.net/pipermail/jigsaw-dev/2018-February/013603.html >>> >>> This isn't really a jigsaw question, so I'm replying to mlvm-dev. >> Yes, I just was not sure where to post such an e-mail (as on jigsaw MethodHandle's were suggested >> I posted it there). >> >>> It looks like you are mixing or interconverting arrays of strings >>> with lists of strings. ?The print statements and CCE show that >>> you are passing an array of strings into a place which expects >>> a single string, and the print statements suggest you are >>> in fact passing a list containing a string array into a place >>> which expects a list of strings. ?Either way there are too >>> many brackets in your actual argument. >>> >>> The prime suspect when the number of brackets is off by one >>> is varargs. ?You code might be failing because of surprises >>> in the overload resolution of invokeWA, which accepts >>> a varargs Object array *and* a single List. >>> >>> Is your runtime invoke mechanism treating invokeWA as an ordinary >>> method? ?It is rather extraordinary, and may warrant a second look. >>> >>> String str; >>> Object obj; >>> Object[] aobj; >>> String[] astr; >>> List lst; >>> >>> plain single arity invocations: >>> >>> 1 mh.invokeWithArguments(str) => new Object[] { str } >>> 2 mh.invokeWithArguments(obj) => new Object[] { obj } >>> >>> and yet: >>> >>> 3 mh.invokeWithArguments(aobj) => aobj (multiple args) >>> 4 mh.invokeWithArguments(astr) => astr (multiple args again!) >>> 5 mh.invokeWithArguments(lst) => lst.toArray() (multiple args again!) >>> >>> but again, a cast removes varargs: >>> >>> 6 mh.invokeWithArguments((Object) aobj) => new Object[] { aobj } >>> 7 mh.invokeWithArguments((Object) astr) => new Object[] { astr } >>> 8 mh.invokeWithArguments((Object) lst) => new Object[] { lst } >>> >>> Your bug looks like a confusion between two of these, >>> perhaps 5 and 8. >> The invocation occurs with an aobj kind of argument (an array of coerced arguments matching the >> types of the parameterTypes array), defined as "Object [] coercedArgs=..."); nevertheless will >> make sure to cast explicitly everywhere invokeWithArguments() gets used (there are >> MethodHandle.invoke(...) as well, which I will replace with invokeWithArguments instead, just to >> have everything use the same invocation method consistently in case arguments need to be >> supplied; also foregoing bindTo().invoke(...), replacing it with appropriate >> invokeWithArguments() for consistency). >> >> ---rony >> >> P.S.: After having rewritten the Java reflection (adding caching of Field, Method, Constructor >> objects together with their corresponding MethodHandle objects) part I also rewrote some of the >> core ooRexx/C++/JNI stuff to remove old-standing (18+ years) code with modern ooRexx-4.x-API >> code, which allows to forgo many of the old restrictions, and improving speed in those corners as >> well (still some cleanup to do). After getting the test units to pass, I turned to this >> application, and that problem using MethodHandle invocations only does not surface anymore!? -------------- next part -------------- An HTML attachment was scrubbed... URL: From Rony.Flatscher at wu.ac.at Sun Mar 11 19:22:45 2018 From: Rony.Flatscher at wu.ac.at (Rony G. Flatscher) Date: Sun, 11 Mar 2018 20:22:45 +0100 Subject: A pure Java example with reflective access behaving differently with invokeWithArguments() compared to core reflection's invoke() (Re: Strange observation: MethodHandle.invokeWithArguments() would not work, whereas Method.invoke() would with the very same arguments In-Reply-To: <5d1c0363-c948-e594-6e55-eaf099c9a62a@wu.ac.at> References: <7CA6C6AC-CBFC-4851-A80A-22A863D4E38F@oracle.com> <52c27332-9154-06fb-b05d-bf7447626ae1@wu.ac.at> <5d1c0363-c948-e594-6e55-eaf099c9a62a@wu.ac.at> Message-ID: Well, still trying to find out what the reason is, that core reflection's invoke behaves differently to MethodHandle's invokeWithArguments in one single case so far (using the method java.utli.Arrays.asList(...)). Here is a little Java program that excercises reflective access to "java.util.Arrays.asList?(T...?a)" using core reflection, i.e. "Method.invoke?(Object obj, Object... args)" and "MethodHandle.invokeWithArguments?(Object... arguments)": import java.util.*; import java.lang.reflect.*; import java.lang.invoke.*; class DemoAsListProblem { public static void main (String args[]) { String arrNames[]=new String[] { "anne", "bert", "celine"}; System.out.println("[1] (main) arrNames=\""+arrNames+"\", .toString()=\""+arrNames.toString()+"\""); List listNames=Arrays.asList(arrNames); System.out.println("[2] (main) after invoking Arrays.asList(arrNames), listNames=\""+listNames+"\""); System.out.println("\ninvoking testReflective() ...\n"); testReflective(); } public static void testReflective() { String arrNames[]=new String[] { "anne", "bert", "celine"}; System.out.println("[3] (testReflective) arrNames=\""+arrNames+"\", .toString()=\""+arrNames.toString()+"\""); Method methAsList=null; List listNames=null; try { Class paramTypes[]=new Class[] { (new Object[0]).getClass() }; methAsList=Arrays.class.getDeclaredMethod("asList", paramTypes); System.out.println("--- (core reflection) Method object asList: "+methAsList); System.out.println("\n--- (core reflection) now invoking Arrays.asList() via Method.invoke(...):"); listNames=(List) methAsList.invoke( null, (Object[]) new Object[]{arrNames} ); // static method System.out.println("[4a] --- (CR) methAsList.invoke( null, (Object[]) new Object[]{arrNames} ) -> listNames=\""+listNames+"\""); listNames=(List) methAsList.invoke( null, (Object) new Object[]{arrNames} ); // static method System.out.println("[4b] --- (CR) methAsList.invoke( null, (Object) new Object[]{arrNames} ) -> listNames=\""+listNames+"\""); // "java.lang.IllegalArgumentException: wrong number of arguments": // listNames=(List) methAsList.invoke( null, (Object[]) arrNames ); // static method // System.out.println("[5a] --- (CR) methAsList.invoke( null, (Object[]) arrNames ) -> listNames=\""+listNames+"\""); listNames=(List) methAsList.invoke( null, (Object) arrNames ); // static method System.out.println("[5b] --- (CR) methAsList.invoke( null, (Object) arrNames ) -> listNames=\""+listNames+"\""); } catch (Throwable t) { System.err.println("oops #1: "+t); t.printStackTrace(); System.exit(-1); } System.out.println("\n--- (MH) now invoking Arrays.asList() via MethodHandle.invokeWithArguments(...):"); MethodHandles.Lookup lookup=MethodHandles.lookup(); MethodHandle mh=null; try { mh=lookup.unreflect(methAsList); System.out.println("--- (MH) unreflected MethodHandle mh: "+mh); listNames=(List) mh.invokeWithArguments( (Object[]) new Object[]{arrNames} ); System.out.println("[6a] --- (MH) mh.invokeWithArguments( (Object[]) new Object[]{arrNames} ) -> listNames=\""+listNames+"\""); listNames=(List) mh.invokeWithArguments( (Object) new Object[]{arrNames} ); System.out.println("[6b] --- (MH) mh.invokeWithArguments( (Object) new Object[]{arrNames} ) -> listNames=\""+listNames+"\""); listNames=(List) mh.invokeWithArguments( (Object[]) arrNames ); System.out.println("[7a] --- (MH) mh.invokeWithArguments( (Object[]) arrNames ) -> listNames=\""+listNames+"\""); listNames=(List) mh.invokeWithArguments( (Object) arrNames ); System.out.println("[7b] --- (MH) mh.invokeWithArguments( (Object) arrNames ) -> listNames=\""+listNames+"\""); } catch (Throwable t) { System.err.println("oops #2: "+t); t.printStackTrace(); System.exit(-2); } } } Compiling and running it under 9.0.4 yields the following output: [1] (main) arrNames="[Ljava.lang.String;@27ddd392", .toString()="[Ljava.lang.String;@27ddd392" [2] (main) after invoking Arrays.asList(arrNames), listNames="[anne, bert, celine]" invoking testReflective() ... [3] (testReflective) arrNames="[Ljava.lang.String;@2a18f23c", .toString()="[Ljava.lang.String;@2a18f23c" --- (core reflection) Method object asList: public static java.util.List java.util.Arrays.asList(java.lang.Object[]) --- (core reflection) now invoking Arrays.asList() via Method.invoke(...): [4a] --- (CR) methAsList.invoke( null, (Object[]) new Object[]{arrNames} ) -> listNames="[anne, bert, celine]" [4b] --- (CR) methAsList.invoke( null, (Object) new Object[]{arrNames} ) -> listNames="[[Ljava.lang.String;@2a18f23c]" [5b] --- (CR) methAsList.invoke( null, (Object) arrNames ) -> listNames="[anne, bert, celine]" --- (MH) now invoking Arrays.asList() via MethodHandle.invokeWithArguments(...): --- (MH) unreflected MethodHandle mh: MethodHandle(Object[])List [6a] --- (MH) mh.invokeWithArguments( (Object[]) new Object[]{arrNames} ) -> listNames="[[Ljava.lang.String;@2a18f23c]" [6b] --- (MH) mh.invokeWithArguments( (Object) new Object[]{arrNames} ) -> listNames="[[Ljava.lang.Object;@13a57a3b]" [7a] --- (MH) mh.invokeWithArguments( (Object[]) arrNames ) -> listNames="[anne, bert, celine]" [7b] --- (MH) mh.invokeWithArguments( (Object) arrNames ) -> listNames="[[Ljava.lang.String;@2a18f23c]" So a String array is turned into a List using Arrays.asList(strArray). Doing it with core reflection yields different results to doing it with invokeWithArguments(). I would have expected that [4a] and [6a] would behave the same. Using reflective invoke() and invokeWithArguments() has been working for my bridge for all the test units (using literally the same arguments in both cases) interchangeably, the one exception is Arrays.asList(). Maybe I am not seeing the obvious (having done too much "close-up tests" for quite some time now). So any hint, insight, help would be really appreciated! ---rony -------------- next part -------------- An HTML attachment was scrubbed... URL: From peter.levart at gmail.com Wed Mar 28 12:42:35 2018 From: peter.levart at gmail.com (Peter Levart) Date: Wed, 28 Mar 2018 14:42:35 +0200 Subject: ClassValue rooting objects after it goes away? In-Reply-To: References: <3A83C9E2-184B-47D7-8F66-D817E98295DC@oracle.com> <55DE2455.3000006@gmx.org> <2048864869.651852.1440629650730.JavaMail.zimbra@u-pem.fr> <55DEDE5D.1090405@gmx.org> <55DEF5B1.8080501@gmx.org> <82b69feb-1f9a-09fb-b0c1-023c6dc88263@oracle.com> Message-ID: <14f86996-b1d9-24a7-fb5b-6aa12dfff3ba@gmail.com> Hi Charles, On 03/02/2018 09:22 PM, Charles Oliver Nutter wrote: > Put it another way: does a static reference from a class to itself > prevent that class from being garbage collected? Of course not. > ClassValue is intended to be a way to inject pseudo-static data into > either a class or a Class. Injecting that data, even if it has a > reference back to the class, should not prevent the class from being > collected. And it should not with ClassValue either. The problem is when you associate values with "system" classes (such as Object, String, etc.). Such values become strongly reachable from Object.class, String.class, etc., respectively. It's like injecting an instance field into Class class and assigning Object.class.myField = myValue, String.class.myField = myValue, ... or equivalently injecting static fields into Object, String, etc class(es) and assigning Object.myField = myValue, String.myField = myValue, ... This would not in itself be a problem if myValue was composed only of objects of system classes (like String, Integer, HashMap, ArrayList, etc..), but you probably have your own Ruby runtime classes to maintain the data structure behind myValue. And each of those custom objects maintains an implicit reference to its runtime class, which is a Ruby runtime class, loaded by whichever ClassLoader loaded the Ruby runtime, so the chain of strong references extends from system class loader to Ruby runtime class loader, effectively preventing it from being unloaded. If you don't need to use ClassValue.remove() in your code, you could try using the following wrapper above ClassValue. The overhead of its get() method compared to ClassValue's should not be to big - just another lookup into a ThreadLocal and a reference comparison with null (in the general fast-path case): /** ?* {@link ClassValue} makes mapped values strongly reachable from {@link Class}(es) ?* they are associated with while they are not reachable directly from {@link ClassValue}(s). ?* This is some times desirable, but other times not. This wrapper provides a ?* ClassValue-like API where the roles are reversed - associated values are not strongly ?* reachable from Class(es) but from WeakClassValue(s) they are associated with. ?* ?* @param they type of associated values ?*/ public abstract class WeakClassValue { ??? // temporary holder of a Node computed in embedded cv.computeValue() so we ??? // can later find out whether the embedded WeakReference has been installed into ??? // ClassValueMap or not by comparing it to instance returned from cv.get() ??? private static final ThreadLocal NODE_TL = new ThreadLocal<>(); ??? // head of doubly-linked list of nodes, keeping associated values reachable from ??? // WeakClassValue instance ??? private final Node head = new Node(null, null, null, null, null); ??? // a single reference queue for all Node(s) to get enqueued when their referents ??? // (Class instances) get GCed... ??? private static final ReferenceQueue> queue = new ReferenceQueue<>(); ??? // Node is a PhantomReference tracking reachability of associated Class. ??? // it also holds the associated value, WeakReference to it, and prev/next pointers into the list ??? private static final class Node extends PhantomReference> { ??????? private final Node head; ??????? private Node prev, next; ??????? private Object value; ??????? WeakReference ref; ??????? Node(Class type, ReferenceQueue> queue, ???????????? Node head, Object value, WeakReference ref) { ??????????? super(type, queue); ??????????? this.value = value; ??????????? this.ref = ref; ??????????? if (head == null) { ??????????????? // constructing head node ??????????????? this.prev = this.next = this; ??????????????? this.head = null; ??????????? } else { ??????????????? // link node into list anchored by head ??????????????? synchronized (head) { ??????????????????? this.prev = head; ??????????????????? this.next = head.next; ??????????????????? this.head = head; // remember where we belong to ??????????????????? head.next.prev = this; ??????????????????? head.next = this; ??????????????? } ??????????? } ??????? } ??????? // unlink the node from the list using right head as a lock ??????? void unlink() { ??????????? synchronized (head) { ??????????????? prev.next = next; ??????????????? next.prev = prev; ??????????????? next = prev = null; ??????????????? value = null; ??????????????? ref.clear(); ??????????????? ref = null; ??????????? } ??????? } ??? } ??? // work is delegated to embedded ClassValue instance ??? private final ClassValue> cv = new ClassValue<>() { ??????? @SuppressWarnings("unchecked") ??????? @Override ??????? protected WeakReference computeValue(Class type) { ??????????? T value = WeakClassValue.this.computeValue(type); ??????????? WeakReference ref = new WeakReference<>(value); ??????????? // link the value into a doubly-linked list rooted at ??????????? // WeakClassValue instance so it is kept alive ??????????? Node node = new Node(type, queue, head, value, ref); ??????????? // assign the node temporarily to NODE_TL thread-local so we can ??????????? // check later if embedded WeakReference got installed into ??????????? // ClassValueMap or not (depends on concurrent activity) ??????????? NODE_TL.set(node); ??????????? return ref; ??????? } ??? }; ??? /** ???? * Computes the given class's derived value for this {@code WeakClassValue}. ???? */ ??? protected abstract T computeValue(Class type); ??? /** ???? * Returns the value for the given class. ???? * If no value has yet been computed, it is obtained by ???? * an invocation of the {@link #computeValue computeValue} method. ???? */ ??? public T get(Class type) { ??????? WeakReference ref = cv.get(type); ??????? Node node = NODE_TL.get(); ??????? if (node != null) { ??????????? if (ref != node.ref) { ??????????????? // some other thread has beaten us installing its WeakReference ??????????????? // into type's ClassValueMap. We must unlink our Node from list ??????????????? // to release our stale value ??????????????? node.unlink(); ??????????? } ??????????? NODE_TL.set(null); ??????? } ??????? try { ??????????? return ref.get(); ??????? } finally { ??????????? // keep type and this reachable as those are guarantees that ??????????? // the value is reachable too before it is get() from 'ref' ??????????? Reference.reachabilityFence(type); ??????????? Reference.reachabilityFence(this); ??????? } ??? } ??? /** ???? * Removes any stale nodes from doubly-linked list(s) holding values that ???? * were associated with classes that have been GCed. You cal call this ???? * explicitly to expedite removal of stale data if new values are not ???? * computed for some time ???? */ ??? public static void removeStaleValues() { ??????? Node n; ??????? while ((n = (Node) queue.poll()) != null) { ??????????? n.unlink(); ??????? } ??? } } You may freely use this code in Ruby or anywhere else if you find fit. Regards, Peter > > On Fri, Mar 2, 2018 at 2:19 PM Charles Oliver Nutter > > wrote: > > I have posted a modified version of my description to the main bug > report. > > TLDR: ClassValue should not root objects. > > - Charlie > > On Fri, Mar 2, 2018 at 2:13 PM Charles Oliver Nutter > > wrote: > > Yes, it may be the same bug. > > In my case, the ClassValue is held by a utility object used > for our Java integration. That utility object has to live > somewhere, so it's held by the JRuby runtime instance. There's > a strong reference chain leading to the ClassValue. > > The value is a Ruby representation of the class, with > reflected methods parsed out and turned into Ruby endpoints. > Obviously, the value also references the class, either > directly or indirectly through reflected members. > > The Ruby class wrapper is only hard referenced directly if > there's an instance of the object live and moving through > JRuby. It may be referenced indirectly through inline caches. > > However...I do not believe this should prevent collection of > the class associated with the ClassValue. > > The value referenced in the ClassValue should not constitute a > hard reference. If it is alive *only* because of its associate > with a given class, that should not be enough to root either > the object or the class. > > ClassValue should work like ThreadLocal. If the Thread > associated with a value goes away, the value reference goes > away. ThreadLocal does nothing prevent it from being > collected. If the Class associated with a Value goes away, the > same should happen to that Value and it should be collectable > once all other hard references are gone. > > Perhaps I've misunderstood? > > - Charlie > > On Fri, Mar 2, 2018 at 12:16 PM Vladimir Ivanov > > wrote: > > Charlie, > > Does it look similar to the following bugs? > https://bugs.openjdk.java.net/browse/JDK-8136353 > https://bugs.openjdk.java.net/browse/JDK-8169425 > > If that's the same (and it seems so to me [1]), then speak > up and > persuade Paul it's an important edge case (as stated in > JDK-8169425). > > Best regards, > Vladimir Ivanov > > [1] new RubyClass(Ruby.this) in > > ? ? ?public static class Ruby { > ? ? ? ? ?private ClassValue cache = new > ClassValue() { > ? ? ? ? ? ? ?protected RubyClass computeValue(Class type) { > ? ? ? ? ? ? ? ? ?return new RubyClass(Ruby.this); > ? ? ? ? ? ? ?} > ? ? ? ? ?}; > > On 3/1/18 2:25 AM, Charles Oliver Nutter wrote: > > So I don't think we ever closed the loop here. Did > anyone on the JDK > > side confirm this, file an issue, or fix it? > > > > We still have ClassValue disabled in JRuby because of > the rooting issues > > described here and in > https://github.com/jruby/jruby/pull/3228. > > > > - Charlie > > > > On Thu, Aug 27, 2015 at 7:04 AM Jochen Theodorou > > > >> > wrote: > > > >? ? ?One more thing... > > > >? ? ?Remi, I tried your link with my simplified scenario > and it does there > >? ? ?not stop the collection of the classloader > > > >? ? ?Am 27.08.2015 11:54, schrieb Jochen Theodorou: > >? ? ? > Hi, > >? ? ? > > >? ? ? > In trying to reproduce the problem outside of > Groovy I stumbled > >? ? ?over a > >? ? ? > case case which I think should work > >? ? ? > > >? ? ? > public class MyClassValue extends ClassValue { > >? ? ? >? ? ? protected Object computeValue(Class type) { > >? ? ? >? ? ? ? ? Dummy ret = new Dummy(); > >? ? ? >? ? ? ? ? Dummy.l.add (this); > >? ? ? >? ? ? ? ? return ret; > >? ? ? >? ? ? } > >? ? ? > } > >? ? ? > > >? ? ? >? ?class Dummy { > >? ? ? >? ? ? ?static final ArrayList l = new ArrayList(); > >? ? ? >? ?} > >? ? ? > > >? ? ? > basically this means there will be a hard > reference on the ClassValue > >? ? ? > somewhere. It can be in a static or non-static > field, direct or > >? ? ? > indirect. But this won't collect. If I put for > example a > >? ? ?WeakReference > >? ? ? > in between it works again. > >? ? ? > > >? ? ? > Finally I also tested to put the hard reference > in a third class > >? ? ? > instead, to avoid this self reference. But it can > still not collect. > >? ? ? > > >? ? ? > So I currently have the impression that if > anything holds a hard > >? ? ? > reference on the class value that the classloader > cannot be collected > >? ? ? > anymore. > >? ? ? > > >? ? ? > Unless I misunderstand something here I see that > as a bug > >? ? ? > > >? ? ? > bye blackdrag > >? ? ? > > > > > > >? ? ?-- > >? ? ?Jochen "blackdrag" Theodorou > >? ? ?blog: http://blackdragsview.blogspot.com/ > > > > ?_______________________________________________ > >? ? ?mlvm-dev mailing list > > mlvm-dev at openjdk.java.net > > > > > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev > > > > -- > > > > - Charlie (mobile) > > > > > > > > _______________________________________________ > > mlvm-dev mailing list > > mlvm-dev at openjdk.java.net > > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev > > > > -- > > - Charlie (mobile) > > -- > > - Charlie (mobile) > > -- > > - Charlie (mobile) > > > > _______________________________________________ > mlvm-dev mailing list > mlvm-dev at openjdk.java.net > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev -------------- next part -------------- An HTML attachment was scrubbed... URL: From szegedia at gmail.com Wed Mar 28 16:55:29 2018 From: szegedia at gmail.com (Attila Szegedi) Date: Wed, 28 Mar 2018 18:55:29 +0200 Subject: ClassValue rooting objects after it goes away? In-Reply-To: <14f86996-b1d9-24a7-fb5b-6aa12dfff3ba@gmail.com> References: <3A83C9E2-184B-47D7-8F66-D817E98295DC@oracle.com> <55DE2455.3000006@gmx.org> <2048864869.651852.1440629650730.JavaMail.zimbra@u-pem.fr> <55DEDE5D.1090405@gmx.org> <55DEF5B1.8080501@gmx.org> <82b69feb-1f9a-09fb-b0c1-023c6dc88263@oracle.com> <14f86996-b1d9-24a7-fb5b-6aa12dfff3ba@gmail.com> Message-ID: I had some similar concerns with some data structures I maintain in Dynalink; I specifically have a utility method to check if classes from two class loaders are allowed to keep strong references to each other (jdk.dynalink.internal.InternalTypeUtilities.canReferenceDirectly if you want to look it up). It?s used in few places to either choose between strong references and weak references, or to forgo some caching for unrelated classes entirely lest it creates an unwanted strong reference between class loaders. Attila. > On 2018. Mar 28., at 14:42, Peter Levart wrote: > > Hi Charles, > > On 03/02/2018 09:22 PM, Charles Oliver Nutter wrote: >> Put it another way: does a static reference from a class to itself prevent that class from being garbage collected? Of course not. ClassValue is intended to be a way to inject pseudo-static data into either a class or a Class. Injecting that data, even if it has a reference back to the class, should not prevent the class from being collected. > > And it should not with ClassValue either. The problem is when you associate values with "system" classes (such as Object, String, etc.). Such values become strongly reachable from Object.class, String.class, etc., respectively. It's like injecting an instance field into Class class and assigning Object.class.myField = myValue, String.class.myField = myValue, ... or equivalently injecting static fields into Object, String, etc class(es) and assigning Object.myField = myValue, String.myField = myValue, ... > > This would not in itself be a problem if myValue was composed only of objects of system classes (like String, Integer, HashMap, ArrayList, etc..), but you probably have your own Ruby runtime classes to maintain the data structure behind myValue. And each of those custom objects maintains an implicit reference to its runtime class, which is a Ruby runtime class, loaded by whichever ClassLoader loaded the Ruby runtime, so the chain of strong references extends from system class loader to Ruby runtime class loader, effectively preventing it from being unloaded. > > If you don't need to use ClassValue.remove() in your code, you could try using the following wrapper above ClassValue. The overhead of its get() method compared to ClassValue's should not be to big - just another lookup into a ThreadLocal and a reference comparison with null (in the general fast-path case): > > > /** > * {@link ClassValue} makes mapped values strongly reachable from {@link Class}(es) > * they are associated with while they are not reachable directly from {@link ClassValue}(s). > * This is some times desirable, but other times not. This wrapper provides a > * ClassValue-like API where the roles are reversed - associated values are not strongly > * reachable from Class(es) but from WeakClassValue(s) they are associated with. > * > * @param they type of associated values > */ > public abstract class WeakClassValue { > > // temporary holder of a Node computed in embedded cv.computeValue() so we > // can later find out whether the embedded WeakReference has been installed into > // ClassValueMap or not by comparing it to instance returned from cv.get() > private static final ThreadLocal NODE_TL = new ThreadLocal<>(); > > // head of doubly-linked list of nodes, keeping associated values reachable from > // WeakClassValue instance > private final Node head = new Node(null, null, null, null, null); > > // a single reference queue for all Node(s) to get enqueued when their referents > // (Class instances) get GCed... > private static final ReferenceQueue> queue = new ReferenceQueue<>(); > > // Node is a PhantomReference tracking reachability of associated Class. > // it also holds the associated value, WeakReference to it, and prev/next pointers into the list > private static final class Node extends PhantomReference> { > private final Node head; > private Node prev, next; > private Object value; > WeakReference ref; > > Node(Class type, ReferenceQueue> queue, > Node head, Object value, WeakReference ref) { > super(type, queue); > this.value = value; > this.ref = ref; > if (head == null) { > // constructing head node > this.prev = this.next = this; > this.head = null; > } else { > // link node into list anchored by head > synchronized (head) { > this.prev = head; > this.next = head.next; > this.head = head; // remember where we belong to > head.next.prev = this; > head.next = this; > } > } > } > > // unlink the node from the list using right head as a lock > void unlink() { > synchronized (head) { > prev.next = next; > next.prev = prev; > next = prev = null; > value = null; > ref.clear(); > ref = null; > } > } > } > > // work is delegated to embedded ClassValue instance > private final ClassValue> cv = new ClassValue<>() { > @SuppressWarnings("unchecked") > @Override > protected WeakReference computeValue(Class type) { > T value = WeakClassValue.this.computeValue(type); > WeakReference ref = new WeakReference<>(value); > // link the value into a doubly-linked list rooted at > // WeakClassValue instance so it is kept alive > Node node = new Node(type, queue, head, value, ref); > // assign the node temporarily to NODE_TL thread-local so we can > // check later if embedded WeakReference got installed into > // ClassValueMap or not (depends on concurrent activity) > NODE_TL.set(node); > return ref; > } > }; > > /** > * Computes the given class's derived value for this {@code WeakClassValue}. > */ > protected abstract T computeValue(Class type); > > /** > * Returns the value for the given class. > * If no value has yet been computed, it is obtained by > * an invocation of the {@link #computeValue computeValue} method. > */ > public T get(Class type) { > WeakReference ref = cv.get(type); > Node node = NODE_TL.get(); > > if (node != null) { > if (ref != node.ref) { > // some other thread has beaten us installing its WeakReference > // into type's ClassValueMap. We must unlink our Node from list > // to release our stale value > node.unlink(); > } > NODE_TL.set(null); > } > > try { > return ref.get(); > } finally { > // keep type and this reachable as those are guarantees that > // the value is reachable too before it is get() from 'ref' > Reference.reachabilityFence(type); > Reference.reachabilityFence(this); > } > } > > /** > * Removes any stale nodes from doubly-linked list(s) holding values that > * were associated with classes that have been GCed. You cal call this > * explicitly to expedite removal of stale data if new values are not > * computed for some time > */ > public static void removeStaleValues() { > Node n; > while ((n = (Node) queue.poll()) != null) { > n.unlink(); > } > } > } > > > You may freely use this code in Ruby or anywhere else if you find fit. > > Regards, Peter > >> >> On Fri, Mar 2, 2018 at 2:19 PM Charles Oliver Nutter wrote: >> I have posted a modified version of my description to the main bug report. >> >> TLDR: ClassValue should not root objects. >> >> - Charlie >> >> On Fri, Mar 2, 2018 at 2:13 PM Charles Oliver Nutter wrote: >> Yes, it may be the same bug. >> >> In my case, the ClassValue is held by a utility object used for our Java integration. That utility object has to live somewhere, so it's held by the JRuby runtime instance. There's a strong reference chain leading to the ClassValue. >> >> The value is a Ruby representation of the class, with reflected methods parsed out and turned into Ruby endpoints. Obviously, the value also references the class, either directly or indirectly through reflected members. >> >> The Ruby class wrapper is only hard referenced directly if there's an instance of the object live and moving through JRuby. It may be referenced indirectly through inline caches. >> >> However...I do not believe this should prevent collection of the class associated with the ClassValue. >> >> The value referenced in the ClassValue should not constitute a hard reference. If it is alive *only* because of its associate with a given class, that should not be enough to root either the object or the class. >> >> ClassValue should work like ThreadLocal. If the Thread associated with a value goes away, the value reference goes away. ThreadLocal does nothing prevent it from being collected. If the Class associated with a Value goes away, the same should happen to that Value and it should be collectable once all other hard references are gone. >> >> Perhaps I've misunderstood? >> >> - Charlie >> >> On Fri, Mar 2, 2018 at 12:16 PM Vladimir Ivanov wrote: >> Charlie, >> >> Does it look similar to the following bugs? >> https://bugs.openjdk.java.net/browse/JDK-8136353 >> https://bugs.openjdk.java.net/browse/JDK-8169425 >> >> If that's the same (and it seems so to me [1]), then speak up and >> persuade Paul it's an important edge case (as stated in JDK-8169425). >> >> Best regards, >> Vladimir Ivanov >> >> [1] new RubyClass(Ruby.this) in >> >> public static class Ruby { >> private ClassValue cache = new ClassValue() { >> protected RubyClass computeValue(Class type) { >> return new RubyClass(Ruby.this); >> } >> }; >> >> On 3/1/18 2:25 AM, Charles Oliver Nutter wrote: >> > So I don't think we ever closed the loop here. Did anyone on the JDK >> > side confirm this, file an issue, or fix it? >> > >> > We still have ClassValue disabled in JRuby because of the rooting issues >> > described here and in https://github.com/jruby/jruby/pull/3228. >> > >> > - Charlie >> > >> > On Thu, Aug 27, 2015 at 7:04 AM Jochen Theodorou > > > wrote: >> > >> > One more thing... >> > >> > Remi, I tried your link with my simplified scenario and it does there >> > not stop the collection of the classloader >> > >> > Am 27.08.2015 11:54, schrieb Jochen Theodorou: >> > > Hi, >> > > >> > > In trying to reproduce the problem outside of Groovy I stumbled >> > over a >> > > case case which I think should work >> > > >> > > public class MyClassValue extends ClassValue { >> > > protected Object computeValue(Class type) { >> > > Dummy ret = new Dummy(); >> > > Dummy.l.add (this); >> > > return ret; >> > > } >> > > } >> > > >> > > class Dummy { >> > > static final ArrayList l = new ArrayList(); >> > > } >> > > >> > > basically this means there will be a hard reference on the ClassValue >> > > somewhere. It can be in a static or non-static field, direct or >> > > indirect. But this won't collect. If I put for example a >> > WeakReference >> > > in between it works again. >> > > >> > > Finally I also tested to put the hard reference in a third class >> > > instead, to avoid this self reference. But it can still not collect. >> > > >> > > So I currently have the impression that if anything holds a hard >> > > reference on the class value that the classloader cannot be collected >> > > anymore. >> > > >> > > Unless I misunderstand something here I see that as a bug >> > > >> > > bye blackdrag >> > > >> > >> > >> > -- >> > Jochen "blackdrag" Theodorou >> > blog: http://blackdragsview.blogspot.com/ >> > >> > _______________________________________________ >> > mlvm-dev mailing list >> > mlvm-dev at openjdk.java.net >> > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev >> > >> > -- >> > >> > - Charlie (mobile) >> > >> > >> > >> > _______________________________________________ >> > mlvm-dev mailing list >> > mlvm-dev at openjdk.java.net >> > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev >> > >> -- >> - Charlie (mobile) >> >> -- >> - Charlie (mobile) >> >> -- >> - Charlie (mobile) >> >> >> >> _______________________________________________ >> mlvm-dev mailing list >> >> mlvm-dev at openjdk.java.net >> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev > > _______________________________________________ > mlvm-dev mailing list > mlvm-dev at openjdk.java.net > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev From blackdrag at gmx.org Sat Mar 31 16:47:18 2018 From: blackdrag at gmx.org (Jochen Theodorou) Date: Sat, 31 Mar 2018 18:47:18 +0200 Subject: MethodHandle accessing private method of outer class Message-ID: <45ee128f-e176-e474-4e5e-92a31b006217@gmx.org> Hi all, I just noticed something I would like to know if that is correct and as specified (before I start using that in my application logic) using java 9.0.4 > public class Application { > public Lookup foo() { > Supplier s = new Supplier() { > public Lookup get() { return MethodHandles.lookup); } > } > return s.get(); > } > } what I noticed is that the lookup object returned by the call to foo is one with full access rights for the inner class of Application, but it seems I am also having full access rights on Application itself. I can for example call a private method in Application using a handle created using this lookup object. Is this really as intended? I am asking because Java would realize this afaik with a helper method (at least in the past). Was this always possible with MethodHandles, or did this change? bye Jochen From david.holmes at oracle.com Sat Mar 31 23:51:54 2018 From: david.holmes at oracle.com (David Holmes) Date: Sun, 1 Apr 2018 09:51:54 +1000 Subject: MethodHandle accessing private method of outer class In-Reply-To: <45ee128f-e176-e474-4e5e-92a31b006217@gmx.org> References: <45ee128f-e176-e474-4e5e-92a31b006217@gmx.org> Message-ID: <27696697-7911-79e4-0e0a-679e35707fd5@oracle.com> On 1/04/2018 2:47 AM, Jochen Theodorou wrote: > Hi all, > > I just noticed something I would like to know if that is correct and as > specified (before I start using that in my application logic) using java > 9.0.4 > >> public class Application { >> ? public Lookup foo() { >> ??? Supplier s = new Supplier() { >> ????? public Lookup get() { return MethodHandles.lookup); } >> ??? } >> ??? return s.get(); >> ? } >> } > > what I noticed is that the lookup object returned by the call to foo is > one with full access rights for the inner class of Application, but it > seems I am also having full access rights on Application itself. I can > for example call a private method in Application using a handle created > using this lookup object. > > Is this really as intended? I am asking because Java would realize this > afaik with a helper method (at least in the past). > Was this always possible with MethodHandles, or did this change? The Java language has always permitted this. But at the source level it is achieved through helper methods as the VM does not allow it (yet). Core reflection does not allow it (but by spec should). But MethodHandles went to a lot of trouble to allow the same accesses as the language permits (though sometimes needing to use special mechanisms like Lookup.in). I can't say for sure MH has "always" allowed this (sometimes the implementation has lagged when it comes to private method access, particularly when private interface methods were introduced) - though it would be easy to check. Going forward, for JDK 11 we expect JEP 181 "Nestmates" to be in place, which implements the language access semantics consistently across the VM, MH and core reflection. So yes a nested type has full access to its enclosing types, and full access to all other nested types in the same nest (ie all types directly or indirectly nested in a given top-level class). Cheers, David > bye Jochen > _______________________________________________ > mlvm-dev mailing list > mlvm-dev at openjdk.java.net > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev