From fw at deneb.enyo.de Sat Nov 6 12:38:13 2021 From: fw at deneb.enyo.de (Florian Weimer) Date: Sat, 06 Nov 2021 13:38:13 +0100 Subject: Shortcut for obtaining a MethodHandle for an anonymous code fragment In-Reply-To: <3518e2fd-4e80-4901-0bca-0710165945df@oracle.com> (Vladimir Ivanov's message of "Mon, 11 Jan 2021 19:12:40 +0300") References: <87ft38spvy.fsf@mid.deneb.enyo.de> <3518e2fd-4e80-4901-0bca-0710165945df@oracle.com> Message-ID: <87zgqh5uiy.fsf@mid.deneb.enyo.de> * Vladimir Ivanov: >> Is it true that there is no shortcut for obtaining a method handle for >> some code fragment? >> >> That is, there is no way to write something like this? >> >> MethodHandle repeatIt = (String x) -> x + x; >> >> Instead it's necessary to give the expression a name and put it into a >> static method somewhere, and obtain a MethodHandle for it using >> MethodHandles.lookup(). > > There's no language support for that, but you can write a utility method > to convert a lambda into a method handle: > > wrapRunnable(() -> System.out.println("")); > > static MethodHandle wrapRunnable(Runnable r) { > return RUNNABLE_RUN.bindTo(r); > } > > static final MethodHandle RUNNABLE_RUN; > static { > try { > RUNNABLE_RUN = > MethodHandles.lookup().findVirtual(Runnable.class, "run", > MethodType.methodType(void.class)); > } catch (NoSuchMethodException | IllegalAccessException e) { > throw new InternalError(e); > } > } I poked at the generated method handle with reflection, and it retains a reference to the Runnable object with the synthesized lambda class. Would it be a valid optimization if the lookup cut through to the method implementing the lambda? > Or even a generic version: > > wrap(Runnable.class, () -> System.out.println("")); > > static MethodHandle wrap(Class functionalInterface, T lambda) { > MethodHandle sam = ... // find SAM in a functional interface > return sam.bindTo(lambda); > } This is an interesting use of a comment. Is there even a well-defined concept of a functional interface at the JVM level? I guess it's possible to ignore JLS-level override equivalence and generics, and focus on the generic signatures only. Still it would be nice to have something in the JDK to compute a JVM-level SAM at run time. From chap at anastigmatix.net Mon Nov 8 18:24:37 2021 From: chap at anastigmatix.net (Chapman Flack) Date: Mon, 8 Nov 2021 13:24:37 -0500 Subject: Does FIXME: NYI in MutableCallSite.syncAll connote not yet implemented? Message-ID: <61896B65.6030808@anastigmatix.net> Hello, So I have joined this list many years later than the cool kids, because I have been reading the API docs and considering using SwitchPoint in a design, and I wanted to be sure I understand its properties before blowing too much time on it. The questions I still had after the javadocs sent me on to the OpenJDK GitHub repo to look at the sources, where I saw that SwitchPoint uses MutableCallSite (as indeed its javadoc says "Simple implementations ... may"), so invalidateAll relies on MutableCallSite.syncAll for the magic to happen, and MutableCallSite.syncAll is ... interesting. It has a very long javadoc comment that begins by appearing to make some attractive promises: 1. effect is to force all future readers of each call site's target to accept the most recently stored value 2. may (may??) block until all readers have (somehow) decached all previous versions 3. reader threads may observe previous versions of the target until the syncAll call returns. (Does this mean they may not do so after the syncAll call returns? And if so, wouldn't that imply #2 is really something stronger than "may"?) 4. it "is likely to be expensive" (as the trade-off for having getTarget be as cheap as a plain read, and relying on magic to make the sync work). But the javadoc for syncAll doesn't end there; it forges ahead into Java Memory Model details, where the attractive early promises seem to get renegotiated a bit. In particular, the very first thing it says about "an arbitrary thread T (other than the current thread)" now starts with an "if": "If T executes a synchronization action A after the volatile write" ... *then* it must see the updated target. ... the promise now begins to seem ... a bit ... conditional. And indeed, the code of syncAll begins with the volatile write to STORE_BARRIER (really a lazySet, which these days is documented as the memory effects of setRelease). Then it calls getClass() on all of the call sites, perhaps only to generate the specified NPE for any null value, unless getClass() has some other effect I don't know about. And then after that loop, there seems to be the line with all the magic: // FIXME: NYI And that's all there is to the method. And I see that's the magic line in jdk17 [1] and all the way back to its appearance in jdk7 [2]. I see that I am not the first to notice that, and that the syncAll method has been commented out in Android with a note that it wasn't implemented. [3] (Which seems like it would break SwitchPoint, but then it looks like Android never imported SwitchPoint at all.) So by this point I am quite puzzled. I have spent the morning reviewing the archives of this list, back to the inception of MutableCallSite in late 2010. I read the initial design description by John Rose [4]. I see considerable discussion of using SwitchPoint, not least in the many JRuby posts by Charles Oliver Nutter. Presumably if SwitchPoint didn't reliably switch stuff, that would have been remarked on by now. So what am I missing? Has this emperor got clothes I'm just not seeing? Is part of the promised behavior actually being supplied by the VM or compiler, maybe by treating this class specially, in a way I do not see in the source? Is the key to simply assume that every other thread T someday "executes a synchronization action A" for unrelated reasons, and then sees the update? If so, is there some upper bound that can be stated for how long after syncAll returns that might be? Were the Android developers correct in removing syncAll for being unimplemented? Perhaps because it requires magical support from the VM that is not present in their VM? Or were they just trigger-happy, removing it only because they looked at the source and (like me) failed to convince themselves nothing was missing? If really nothing is missing, would it be worthwhile to remove the // FIXME: NYI in the source, just for the peace of mind of people (like me) who might be looking there to understand the behavior? Thanks for any light you can open my eyes to .... Regards, Chapman Flack [1] https://github.com/openjdk/jdk17u/blob/master/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java#L281 [2] https://github.com/openjdk/jdk7/blob/34cd7bc/jdk/src/share/classes/java/dyn/MutableCallSite.java#L203 [3] https://android.googlesource.com/platform/libcore/+/17162a1%5E!/ojluni/src/main/java/java/lang/invoke/MutableCallSite.java [4] https://groups.google.com/g/jvm-languages/c/nJ0-hPx0VnY