hg: mlvm/mlvm/jdk: meth: add proxy maker for closures

John Rose john.r.rose at oracle.com
Mon May 24 18:22:31 PDT 2010


On May 18, 2010, at 1:18 PM, Charles Oliver Nutter wrote:

> One important question for me is how multi-method interfaces would be
> handled. I had originally tried to use Scala's "Function" interfaces
> in Duby to represent closures, but they all have multiple abstract
> methods that must be handled completely differently.

Right.  Here are the degrees of freedom I see at this point:
 - whether to accept SAM types which are not interfaces (default: yes)
 - whether to allow a query API for recovering a method handle from a proxy (default: yes)
 - whether to allow multiple methods to be associated with multiple MHs (default: no)
 - whether to allow multiple super types in the proxy object (default: no)
 - whether multiple methods must be individually closed, or can be mutually closed over another value

The reason I "stopped at one" is there are more optimization options for the simplified case of one-type-one-method.

Also, the query API in point 2 is harder to get right if you accept the other points.

But I do agree there should be a mechanism supporting the additional degrees of freedom.

It needs to be bulkier, though.  It probably needs multiple phases, like a builder.

Also, the various parts (methods, receivers) can appear at various times.

Here's a two-phase version:
   class InstanceBuilder<T,R> {
     InstanceBuilder(List<Class<? extends T>> supers, List<String> names, List<MethodType> types);
     InstanceBuilder(List<Class<? extends T>> supers, List<String> names, List<MethodType> types, Class<R> receiver);
     InstanceBuilder(List<Class<? extends T>> supers, List<String> names, List<MethodHandle> methods);
     T newInstance(R receiver, MethodHandle... methods);
     T newInstance(MethodHandle... methods); // no bound receiver
     T newInstance(R receiver); // previously specified methods
   }

Here's chained multi-phase version:
   class InstanceBuilder<T,R> {
     InstanceBuilder(List<Class<? extends T>> supers, List<String> names, List<MethodType> types);
     InstanceBuilder bindReceiver(R receiver);
     InstanceBuilder bindMethod(String name, MethodHandle method);
     T newInstance();
   }

And so on...

> I'd need to
> provide my own superclass with default behavior or have a way to
> stitch together N handles for N abstract methods.
> 
> And I agree about the language bridging...plus in the JRuby case, this
> actually makes Ruby to Ruby bridging easier:
> 
> * We need a codebase that works on Java 6
> * ...so we can't move our entire call path to using MethodHandle
> * ...so we need our own abstract "invoker" supertype
> * ...so being able to use that supertype with either generated impls
> or MethodHandle-provided impls makes it easier for us to support both
> indy and non-indy runtimes in the same implementation.

Wrapping method handles adds layers of indirection and boxing hazards as Remi points out.

An unsolved problem with JSR 292 is how to mix method handles in with other supertypes.  An excellent solution would allow you to define your own supertypes and APIs, and have them more or less directly mapped to method handles when method handles were available.  This might increase the number of files which could be reused (just by recompilation or relinking) across JRuby implementations (indy or classic).

I proposed JavaMethodHandle but as a fixed superclass it doesn't give much flexibility (not a mixin!).  And it constrains JVM implementations too much to have an inheritable subtype of MethodHandle.

Another possibility is to ask for an implicit conversion from selected application types X to MethodHandle.  That in effect invents a new type relation: delegation.  So it's no small matter.  It's hard to keep that genie confined to a small bottle.

> Perhaps this also helps Java 7 closures work nicer by making it
> possible to have a generic Closure or Function superclass completely
> independent of java.dyn? Or by making it possible to implement
> (faster) Java reflection with fewer generic frames under the covers
> via a single abstract supertype populated by indy?

The best way I know to accelerate Java reflective invocation is this:
	java.lang.reflect.Method foo = ...;
	try { z = MethodHandles.unreflect(foo).invokeGeneric(a, b, c, ...); }
	catch { ... }

For this to be faster, it assumes there is method handle caching on unreflect, which I haven't done.  But could be done.

For example, you could preserve source compatibility by making a wrapper method to hide MethodHandles.

> Seems like a good addition, in any case, but especially once it's
> faster and more direct than reflect.Proxy :)
> 
> - Charlie
> _______________________________________________
> mlvm-dev mailing list
> mlvm-dev at openjdk.java.net
> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev



More information about the mlvm-dev mailing list