duchess-rs / duchess

Silky smooth Java-Rust interop

Home Page:https://duchess-rs.github.io/duchess/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

implementing native methods

nikomatsakis opened this issue · comments

We should support implementing native methods:

#[duchess::provide_native_fn(foo.Bar::baz)]
fn baz(jvm: &mut Jvm<'_>, arg1: Arg1, arg2: Arg2, ...) { }

This would

  1. generate the user's function unmodified
  2. find the class foo.Bar and, within that, the method named baz (this is leveraging the MethodSelector added in #60)
  3. verify that it is a native method
  4. generate the extern "C" #[no_mangle] function that the JNI will actually call. This can setup the jvm and invoke the user's function, invoking to_rust on each of the argument types or something like that

Some thoughts:

  • Invoking to_rust isn't exactly right. We'll need some kind of trait for either converting to the Java type or to a Rust type.
  • We should probably provide the jvm so permit local references and the like for better efficiency. We have to then prevent people from doing Jvm::with, presumably by setting some sort of flag or acquiring the lock on our own.
  • Alternatively we could not provide jvm and just have people take &Foo for local references. They could then us Jvm::with internally and/or work with global references. This might be nicer. We would want some way for the outer function to "relinquish" it's &mut Jvm during a closure so that, within that closure, Jvm::with can be called. The idea would roughly be that if duchess is started via a JNI callback, it takes the running JVM and installs it as the global one.

Hmm, I'm surprised to find I like the 2nd one. It lets people write foo.to_rust().execute(), which I think will be common. It seems a bit more composable.

This will be awesome---I think there's some good use cases for cache callbacks and webserver hooks here.

One implementation note, we should think through how our Jvm::with lock works in the interleaved case (duchess -> java -> duchess). I'm not seeing a blocker, but I think we'll need to distinguish a top-of-the-stack duchess frame from the Java-invoked frames.

Yes. I have in mind something like this:

  • The "jvm lock" for a thread conceptually can reside either "with the JVM" or in the user's code.
  • When you invoke Jvm::with, you take the lock.
  • When you invoke JNI methods, you give it back to the JVM while they execute.
  • When it calls you, you get it back.

Given that the JNI methods all take an &mut Jvm this is how the user will experience it already. I'm not sure though if we have to do anything on our side. I have to re-read the Jvm launching code, I kind of forget how it works.

Basic support is implemented in #93