-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can Graal handle Method Handlers in the future? #955
Comments
I'm experiencing the same issue and am willing to write code to specifically avoid it, if it is possible. Coding in Java, what I'd like to be able to do (for two classes A and B) is:
My order of preference for how to implement this is:
Which of these three approaches are possible? Are there examples/samples of any of them? |
I've simplified this to a single class:
|
So to rephrase my questions: Can I change this code to use a different type of |
if you change your example to use |
So the old-school |
Yes, we have full support for |
It's working, thanks! So, if I want Graal support I need to use |
I don't think |
That's good to hear. Thanks for all your help. I should be publishing this work as Open Source when it's ready. It should be an interesting application for Graal. Thanks again! |
@christianwimmer any comments regarding the feasibility of a solution for third party code? Even some cumbersome external hint/config mechanism would be OK. I recently saw mention of a runtime tracing tool (of sorts) for Graal that discovers runtime invocation of types to create configurations for Graal (rough description) A solution like that would also be great for this case. Just speculating here, since this is not my field of expertise. |
So IIUC the difficulty in supporting method handles is not the reflective access, as that can be done with the same mechanisms which facilitate core reflection support. The difficulty is in implementing combinators using run-time code generation. Sure, we can't compile method handle combinators ahead of time ... but do we actually need to compile them at all? Why not just do it the inefficient way? As a starting point, the basic user-facing functionality of the method handle API mostly appears as if it could be implemented on top of core reflection. Method handle combinators are basically a declarative API for building an AST, and we could implement them as an interpreter over that AST in plain old Java. In turn this could be AOT compiled like any other Java code, it would just be very slow compared to using method handles on the JVM. The graal native image compiler then translates any occurrences of Are there any critical elements that I'm missing in that analysis? I don't presume I'm offering any new insight here, I only ask to gain a better understanding of the problem and the team's position on it. |
I do feel this is an area where there is bit of mismatch where OpenJDK is heading and where Graal is heading. For each release of Java, MethodHandlers and Lookup objects are pushed more and more as the solution and the future by the various OpenJDK architects. But what good does it do if using MethodHandlers and Lookup object disqualifies you from running your application in Graal. |
There are lots of different use cases for method handles. Some of them are supported, some of them can be supported, and for some of them support is not really possible (unless you build an image that contains Graal as the JIT compiler or are willing to run really slowly). Here is a rough picture of the spectrum:
|
I strongly dispute that slow support is useless. I bet there are plenty of examples of third party libraries / frameworks / etc. out there which use them in places that aren't necessarily going to be performance-critical for the end user. You've received a few bug reports which look like that already, no? As for including Graal in the image, I'm sure lots of people would appreciate that as an option too. Wouldn't this also be necessary for those who want to include dynamic language runtimes like graal.js in native images and have decent performance? For those people, to then also support fast method handles would presumably cost close to nothing. Regardless, seems like a reasonable tradeoff to me. Slow method handles, or fast ones and a larger image. Works either way, get the performance you're willing to pay for. Also out of curiosity, could native images link against libgraal as a shared library? Anyway thanks for the explanation of the state of affairs. |
I'm seeing a related issue with this line of code: https://github.com/scala/scala/pull/8779/files#diff-75c547cedb525c06d7bab20ee470e8eeR25 error output:
The confusing thing to me is that it seems to say that if the MethodHandle is loaded from a static final, it should be okay. Am I misreading that? The field in question is static final. It seems that you can not use native-image with scala 2.12.12 (or likely 2.13 since this was backported from there). I opened this issue: scala/bug#12129 |
relevant issues: oracle/graal#2214 oracle/graal#955 full exception (fixed): {:cognitect.anomalies/category :cognitect.anomalies/fault, :cognitect.aws.client/throwable #error { :cause Invoke with MethodHandle argument could not be reduced to at most a single call or single field access. The method handle must be a compile time constant, e.g., be loaded from a `static final` field. Method that contains the method handle invocation: java.lang.invoke.Invokers$Holder.invoke_MT(Object, Object, Object, Object) :via [{:type com.oracle.svm.core.jdk.UnsupportedFeatureError :message Invoke with MethodHandle argument could not be reduced to at most a single call or single field access. The method handle must be a compile time constant, e.g., be loaded from a `static final` field. Method that contains the method handle invocation: java.lang.invoke.Invokers$Holder.invoke_MT(Object, Object, Object, Object) :at [com.oracle.svm.core.util.VMError unsupportedFeature VMError.java 86]}] :trace [[com.oracle.svm.core.util.VMError unsupportedFeature VMError.java 86] [clojure.lang.Reflector canAccess Reflector.java 49] [clojure.lang.Reflector toAccessibleSuperMethod Reflector.java 84] [clojure.lang.Reflector lambda$invokeInstanceMethod$0 Reflector.java 99] [java.util.stream.ReferencePipeline$3$1 accept ReferencePipeline.java 195] [java.util.ArrayList$ArrayListSpliterator forEachRemaining ArrayList.java 1655] [java.util.stream.AbstractPipeline copyInto AbstractPipeline.java 484] [java.util.stream.AbstractPipeline wrapAndCopyInto AbstractPipeline.java 474] [java.util.stream.ReduceOps$ReduceOp evaluateSequential ReduceOps.java 913] [java.util.stream.AbstractPipeline evaluate AbstractPipeline.java 234] [java.util.stream.ReferencePipeline collect ReferencePipeline.java 578] [clojure.lang.Reflector invokeInstanceMethod Reflector.java 101] [cognitect.aws.protocols.rest$serialize_uri$fn__12861 invoke rest.clj 29] [clojure.string$replace_by invokeStatic string.clj 69] [clojure.string$replace invokeStatic string.clj 106] [cognitect.aws.protocols.rest$serialize_uri invokeStatic rest.clj 22] [cognitect.aws.protocols.rest$serialize_uri invoke rest.clj 22] [clojure.core$update invokeStatic core.clj 6202] [cognitect.aws.protocols.rest$build_http_request invokeStatic rest.clj 174] [cognitect.aws.protocols.rest_xml$fn__12989 invokeStatic rest_xml.clj 11] [cognitect.aws.protocols.rest_xml$fn__12989 invoke rest_xml.clj 11] [clojure.lang.MultiFn invoke MultiFn.java 234] [cognitect.aws.client$send_request$fn__12660$state_machine__7879__auto____12687$fn__12689$fn__12703 invoke client.clj 99] [cognitect.aws.client$send_request$fn__12660$state_machine__7879__auto____12687$fn__12689 invoke client.clj 96] [cognitect.aws.client$send_request$fn__12660$state_machine__7879__auto____12687 invoke client.clj 84] [clojure.core.async.impl.ioc_macros$run_state_machine invokeStatic ioc_macros.clj 978] [clojure.core.async.impl.ioc_macros$run_state_machine_wrapped invokeStatic ioc_macros.clj 980] [cognitect.aws.client$send_request$fn__12660 invoke client.clj 84] [clojure.lang.AFn run AFn.java 22] [java.util.concurrent.ThreadPoolExecutor runWorker ThreadPoolExecutor.java 1128] [java.util.concurrent.ThreadPoolExecutor$Worker run ThreadPoolExecutor.java 628] [clojure.core.async.impl.concurrent$counted_thread_factory$reify__3362$fn__3363 invoke concurrent.clj 29] [clojure.lang.AFn run AFn.java 22] [java.lang.Thread run Thread.java 834] [com.oracle.svm.core.thread.JavaThreads threadStartRoutine JavaThreads.java 517] [com.oracle.svm.core.posix.thread.PosixJavaThreads pthreadStartRoutine PosixJavaThreads.java 192]]}}
|
I appreciate Substrate VM currently lists Method Handles as not supported and I suspect the following exception, which could be found in various issues is due to this reason:
Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Invoke with MethodHandle argument could not be reduced to at most a single call
Is this a limitation by design that cannot be overcome or would it be possible to fix this problem with at least a workaround, if not a complete solution?
For example, I'm seeing this error when trying to build a native image of a simple application that uses Lucene , due to some core classes of Lucene,
This means Lucene and ElasticSearch won't be candidates for native images. I can see what a large (and great!) piece of work Graal is, it would be good to know if some limitations are bound to stay due to design.
The text was updated successfully, but these errors were encountered: