JDK-6567922 : (reflect) Method.invoke() should make a more direct call to its target method
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 7
  • Priority: P2
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2007-06-09
  • Updated: 2018-09-22
Related Reports
Relates :  
Relates :  
Description
1. Each individual java.lang.reflect.Method should directly call its target method.  The current untyped Methods should be replaced by Methods of specialized types.  The only user-visible change would be removing the 'final' modifier from Method.  Since the Method constructor is package-private, this is a safe change.  No subclasses can be made by non-privileged code.

Method.invoke calls are non-dispatching.  In current JIT technology, this leads to a bottleneck.  The problem is with the type profile: Method.invoke contains a large, polluted profile which represents all reflective calls from all places in the system.

Method.invoke then dispatches (delegates) to a method-specific handler, which is a megamorphic call site.  What the JIT would prefer to see is a monomorphic call from the user to a specialized subclass of Method, which then directly invokes the target method.  That could be inlined away.  This only works if different java.lang.reflect.Methods have different subclasses.

This can probably be done without JVM modifications.

For example, the reflected method of Object.equals(Object) would be represented by a Method subclass which works like this:

class Method$123 extends Method {
  public Object invoke(Object receiver, Object... arguments) {
    return receiver.equals(x);
  }
  private boolean invoke0(Object receiver, Object x) {
    return receiver.equals(x);
  }
}

(Various details of type checking and error processing are omitted from the example code.)

2. In addition, Method should define a new accessor which returns a strongly-typed callable handle for the method.  This handle would publicly implement a type-specialized interface with a strongly-typed invoke method.  It would provide direct access to the "unwrapped" version of invoke (called "invoke0" in the example above).  Here is the example updated:

class Method$123 extends Method {
  ...
  public FunctionZLL<Object,Object> getInvoker() {
    return new FunctionZLL<Object,Object>() {
      public boolean invoke(Object receiver, Object x) {
        return invoke0(receiver, x);
      }
    }
  }

} 

3. In addition, Method should define a new accessor setVirtual/isVirtual, which devirtualizes the call.  The synthesized bytecodes would use "invokespecial" instead of "invokevirtual" or "invokeinterface".  This accessor is as dangerous as setAccessible/isAccessible, and so should pass the same safety checks.



See http://groups.google.com/group/jvm-languages , the thread titled "invokenonvirtual opcode", linked from http://groups.google.com/group/jvm-languages/browse_thread/thread/319982bfe1be9487 .
The same goal can also be met if the JVM were to supply "method handles", lightweight direct references to bytecoded methods.  A method handle would possess a single 'invoke' method which, rather than being specified as an override under a class or interface type, would be intrinsically possessed by the method handle, and would have the identical descriptor (type signature) as the underlying bytecoded method.  The type of such method handles is necessarily polymorphic over all method type signatures, and therefore cannot be represented in Java, even with generics.  (Neal Gafter's function type system comes close to representing method types with an infinite scheme of interfaces, but since it has erasure in it it requires implicit casts.)

Given method handles and an 'invokedynamic' instruction for invoking them with the right polymorphism, the code for Method.invoke could be improved without going all the way to a separate subclass of reflect.Method per bytecoded method.

The most straighforward way to do this would be to create an adapter type for each type signature, and store the adapter in the reflect.Method.  The adapter would accept the invoke call with the wrapped argument list and unwrap the arguments and apply them natively to the underlying method handle.  It would also translate return values and exceptions appropriately.  (Probably type erasure could reduce the number of adapter types; this is an implementation detail.)

If the user could be coaxed to extract the method handle and invoke it with 'invokedynamic', the type profile could be used to record the method for later inlining by the JIT.  I think users could be coaxed to do this if they were told it was likely to be 10x faster, especially if they were allowed to discard the reflect.Method and cache only the method handle.  The problem (at least with Java, not the JVM) is with the expressiveness of the language:  How do you write an invocation on a type signature only?

If the user could be coaxed to extract the adapter and invoke it with 'invokeinterface', the type of the adapter could be profiled, and at least the argument shuffling could be inlined.  Additionally, if there is only one method invoked this way for a given fixed signature, then the type profile for that signature's adapter will point directly to that method, and it too will be inlined.  At present, this is roughly what happens in the present system, except that the adapter calls the bytecoded method directly instead of through a (not-yet-existing) method handle.

The performance of the present case could be improved by specializing the type profile to collect profile information on the identity of the receiver, rather than its class, in the case of reflect.Method recievers (or more generally in the case of receivers of final classes).

So I guess I'm asking that this RFE be redirected to make the type profile smarter about reflective calls, and eventually supply a way of extracting a handle from a reflect.Method and calling it with its own preferred signature.  JSR 292 may supply this latter piece of functionality.