mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-17 17:07:53 +00:00
6914665: update jdk code for JSR 292 (post 6858164)
Fill in missing API implementations, fix numerous bugs, adjust APIs towards EG design. Reviewed-by: twisti
This commit is contained in:
parent
20b837a9e4
commit
020e5501fd
@ -26,6 +26,9 @@
|
||||
package java.dyn;
|
||||
|
||||
import sun.dyn.util.BytecodeName;
|
||||
import sun.dyn.Access;
|
||||
import sun.dyn.CallSiteImpl;
|
||||
import sun.dyn.MethodHandleImpl;
|
||||
|
||||
/**
|
||||
* An {@code invokedynamic} call site, as reified by the
|
||||
@ -52,15 +55,25 @@ import sun.dyn.util.BytecodeName;
|
||||
* @see Linkage#registerBootstrapMethod(java.lang.Class, java.dyn.MethodHandle)
|
||||
* @author John Rose, JSR 292 EG
|
||||
*/
|
||||
public class CallSite {
|
||||
public class CallSite
|
||||
// Note: This is an implementation inheritance hack, and will be removed
|
||||
// with a JVM change which moves the required hidden state onto this class.
|
||||
extends CallSiteImpl
|
||||
{
|
||||
private static final Access IMPL_TOKEN = Access.getToken();
|
||||
|
||||
/*
|
||||
|
||||
// Fields used only by the JVM. Do not use or change.
|
||||
private Object vmmethod;
|
||||
int callerMID, callerBCI; // supplied by the JVM
|
||||
|
||||
MethodHandle target;
|
||||
private MethodHandle target;
|
||||
|
||||
final Object caller; // usually a class
|
||||
final String name;
|
||||
final MethodType type;
|
||||
*/
|
||||
|
||||
/**
|
||||
* Make a call site given the parameters from a call to the bootstrap method.
|
||||
@ -72,16 +85,21 @@ public class CallSite {
|
||||
* @param type the method handle type derived from descriptor of the {@code invokedynamic} instruction
|
||||
*/
|
||||
public CallSite(Object caller, String name, MethodType type) {
|
||||
this.caller = caller;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
super(IMPL_TOKEN, caller, name, type);
|
||||
}
|
||||
|
||||
private static void privateInitializeCallSite(CallSite site, int callerMID, int callerBCI) {
|
||||
site.callerMID = callerMID;
|
||||
site.callerBCI = callerBCI;
|
||||
if (site.target == null)
|
||||
site.setTarget(site.initialTarget());
|
||||
site.ensureTarget();
|
||||
}
|
||||
private void ensureTarget() {
|
||||
// Note use of super, which accesses the field directly,
|
||||
// without deferring to possible subclass overrides.
|
||||
if (super.getTarget() == null) {
|
||||
super.setTarget(this.initialTarget());
|
||||
super.getTarget().type(); // provoke NPE if still null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,10 +120,11 @@ public class CallSite {
|
||||
|
||||
/**
|
||||
* Report the current linkage state of the call site. (This is mutable.)
|
||||
* The value maybe null only if the call site is currently unlinked.
|
||||
* When a linked call site is invoked, the target method is used directly.
|
||||
* When an unlinked call site is invoked, its bootstrap method receives
|
||||
* the call, as if via {@link Linkage#bootstrapInvokeDynamic}.
|
||||
* The value may not be null after the {@code CallSite} object is returned
|
||||
* from the bootstrap method of the {@code invokedynamic} instruction.
|
||||
* When an {@code invokedynamic} instruction is executed, the target method
|
||||
* of its associated {@code call site} object is invoked directly,
|
||||
* as if via {@link MethodHandle}{@code .invoke}.
|
||||
* <p>
|
||||
* The interactions of {@code getTarget} with memory are the same
|
||||
* as of a read from an ordinary variable, such as an array element or a
|
||||
@ -118,7 +137,7 @@ public class CallSite {
|
||||
* @see #setTarget
|
||||
*/
|
||||
public MethodHandle getTarget() {
|
||||
return target;
|
||||
return super.getTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -140,13 +159,13 @@ public class CallSite {
|
||||
*/
|
||||
public void setTarget(MethodHandle target) {
|
||||
checkTarget(target);
|
||||
this.target = target;
|
||||
super.setTarget(target);
|
||||
}
|
||||
|
||||
protected void checkTarget(MethodHandle target) {
|
||||
target.type(); // provoke NPE
|
||||
if (!canSetTarget(target))
|
||||
throw new WrongMethodTypeException(String.valueOf(target));
|
||||
throw new WrongMethodTypeException(String.valueOf(target)+target.type()+" should be of type "+type());
|
||||
}
|
||||
|
||||
protected boolean canSetTarget(MethodHandle target) {
|
||||
@ -219,6 +238,10 @@ public class CallSite {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CallSite#"+hashCode()+"["+name+type+" => "+target+"]";
|
||||
return "CallSite#"+hashCode()+"["+name+type+" => "+getTarget()+"]";
|
||||
}
|
||||
|
||||
// Package-local constant:
|
||||
static final MethodHandle GET_TARGET = MethodHandleImpl.getLookup(IMPL_TOKEN).
|
||||
findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
|
||||
}
|
||||
|
||||
@ -45,6 +45,24 @@ package java.dyn;
|
||||
* class or interface supertype, or an object type; it can never be instantiated.
|
||||
* Logically, it denotes a source of all dynamically typed methods.
|
||||
* It may be viewed as a pure syntactic marker (an importable one) of static calls.
|
||||
* <p>
|
||||
* Here are some examples of usage:
|
||||
* <p><blockquote><pre>
|
||||
* Object x; String s; int i;
|
||||
* x = InvokeDynamic.greet("world"); // greet(Ljava/lang/String;)Ljava/lang/Object;
|
||||
* s = InvokeDynamic.<String>hail(x); // hail(Ljava/lang/Object;)Ljava/lang/String;
|
||||
* InvokeDynamic.<void>cogito(); // cogito()V
|
||||
* i = InvokeDynamic.<int>#"op:+"(2, 3); // "op:+"(II)I
|
||||
* </pre></blockquote>
|
||||
* Each of the above calls generates a single invokedynamic instruction
|
||||
* with the name-and-type descriptors indicated in the comments.
|
||||
* The argument types are taken directly from the actual arguments,
|
||||
* while the return type is taken from the type parameter.
|
||||
* (This type parameter may be a primtive, and it defaults to {@code Object}.)
|
||||
* The final example uses a special syntax for uttering non-Java names.
|
||||
* Any name legal to the JVM may be given between the double quotes.
|
||||
* None of these calls is complete without a bootstrap method,
|
||||
* which must be registered by the static initializer of the enclosing class.
|
||||
* @author John Rose, JSR 292 EG
|
||||
*/
|
||||
public final class InvokeDynamic {
|
||||
|
||||
@ -52,4 +52,16 @@ public class InvokeDynamicBootstrapError extends LinkageError {
|
||||
public InvokeDynamicBootstrapError(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code InvokeDynamicBootstrapError} with the specified
|
||||
* detail message and cause.
|
||||
*
|
||||
* @param s the detail message.
|
||||
* @param cause the cause.
|
||||
*/
|
||||
public InvokeDynamicBootstrapError(String s, Throwable cause) {
|
||||
super(s);
|
||||
this.initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,8 @@
|
||||
|
||||
package java.dyn;
|
||||
|
||||
import sun.dyn.Access;
|
||||
|
||||
/**
|
||||
* A Java method handle extends the basic method handle type with additional
|
||||
* programmer defined methods and fields.
|
||||
@ -39,31 +41,105 @@ package java.dyn;
|
||||
* of the entry point method handle, with the leading parameter type
|
||||
* omitted.
|
||||
* <p>
|
||||
* Here is an example of usage:
|
||||
* Here is an example of usage, creating a hybrid object/functional datum:
|
||||
* <p><blockquote><pre>
|
||||
* class Greeter extends JavaMethodHandle {
|
||||
* public void run() { System.out.println("hello, "+greetee); }
|
||||
* private final String greetee;
|
||||
* Greeter(String greetee) {
|
||||
* super(RUN);
|
||||
* this.greetee = greetee;
|
||||
* }
|
||||
* // the entry point function is computed once:
|
||||
* private static final MethodHandle RUN
|
||||
* = MethodHandles.findVirtual(MyMethodHandle.class, "run",
|
||||
* MethodType.make(void.class));
|
||||
* class Greeter extends JavaMethodHandle {
|
||||
* private String greeting = "hello";
|
||||
* public void setGreeting(String s) { greeting = s; }
|
||||
* public void run() { System.out.println(greeting+", "+greetee); }
|
||||
* private final String greetee;
|
||||
* Greeter(String greetee) {
|
||||
* super(RUN); // alternatively, super("run")
|
||||
* this.greetee = greetee;
|
||||
* }
|
||||
* Greeter greeter = new Greeter("world");
|
||||
* greeter.run(); // prints "hello, world"
|
||||
* MethodHandle mh = greeter;
|
||||
* mh.invoke(); // also prints "hello, world"
|
||||
* // the entry point function is computed once:
|
||||
* private static final MethodHandle RUN
|
||||
* = MethodHandles.lookup().findVirtual(Greeter.class, "run",
|
||||
* MethodType.make(void.class));
|
||||
* }
|
||||
* // class Main { public static void main(String... av) { ...
|
||||
* Greeter greeter = new Greeter("world");
|
||||
* greeter.run(); // prints "hello, world"
|
||||
* // Statically typed method handle invocation (most direct):
|
||||
* MethodHandle mh = greeter;
|
||||
* mh.<void>invoke(); // also prints "hello, world"
|
||||
* // Dynamically typed method handle invocation:
|
||||
* MethodHandles.invoke(greeter); // also prints "hello, world"
|
||||
* greeter.setGreeting("howdy");
|
||||
* mh.invoke(); // prints "howdy, world" (object-like mutable behavior)
|
||||
* </pre></blockquote>
|
||||
* <p>
|
||||
* In this example, the method {@code run} provides the entry point.
|
||||
* In the example of {@code Greeter}, the method {@code run} provides the entry point.
|
||||
* The entry point need not be a constant value; it may be independently
|
||||
* computed in each call to the constructor. The entry point does not
|
||||
* even need to be a method on the Java method handle class, though
|
||||
* even need to be a method on the {@code Greeter} class, though
|
||||
* that is the typical case.
|
||||
* <p>
|
||||
* The entry point may also be provided symbolically, in which case the the
|
||||
* {@code JavaMethodHandle} constructor performs the lookup of the entry point.
|
||||
* This makes it possible to use {@code JavaMethodHandle} to create an anonymous
|
||||
* inner class:
|
||||
* <p><blockquote><pre>
|
||||
* // We can also do this with symbolic names and/or inner classes:
|
||||
* MethodHandles.invoke(new JavaMethodHandle("yow") {
|
||||
* void yow() { System.out.println("yow, world"); }
|
||||
* });
|
||||
* </pre></blockquote>
|
||||
* <p>
|
||||
* Here is similar lower-level code which works in terms of a bound method handle.
|
||||
* <p><blockquote><pre>
|
||||
* class Greeter {
|
||||
* public void run() { System.out.println("hello, "+greetee); }
|
||||
* private final String greetee;
|
||||
* Greeter(String greetee) { this.greetee = greetee; }
|
||||
* // the entry point function is computed once:
|
||||
* private static final MethodHandle RUN
|
||||
* = MethodHandles.findVirtual(Greeter.class, "run",
|
||||
* MethodType.make(void.class));
|
||||
* }
|
||||
* // class Main { public static void main(String... av) { ...
|
||||
* Greeter greeter = new Greeter("world");
|
||||
* greeter.run(); // prints "hello, world"
|
||||
* MethodHandle mh = MethodHanndles.insertArgument(Greeter.RUN, 0, greeter);
|
||||
* mh.invoke(); // also prints "hello, world"
|
||||
* </pre></blockquote>
|
||||
* Note that the method handle must be separately created as a view on the base object.
|
||||
* This increases footprint, complexity, and dynamic indirections.
|
||||
* <p>
|
||||
* Here is a pure functional value expressed most concisely as an anonymous inner class:
|
||||
* <p><blockquote><pre>
|
||||
* // class Main { public static void main(String... av) { ...
|
||||
* final String greetee = "world";
|
||||
* MethodHandle greeter = new JavaMethodHandle("run") {
|
||||
* private void run() { System.out.println("hello, "+greetee); }
|
||||
* }
|
||||
* greeter.invoke(); // prints "hello, world"
|
||||
* </pre></blockquote>
|
||||
* <p>
|
||||
* Here is an abstract parameterized lvalue, efficiently expressed as a subtype of MethodHandle,
|
||||
* and instantiated as an anonymous class. The data structure is a handle to 1-D array,
|
||||
* with a specialized index type (long). It is created by inner class, and uses
|
||||
* signature-polymorphic APIs throughout.
|
||||
* <p><blockquote><pre>
|
||||
* abstract class AssignableMethodHandle extends JavaMethodHandle {
|
||||
* private final MethodHandle setter;
|
||||
* public MethodHandle setter() { return setter; }
|
||||
* public AssignableMethodHandle(String get, String set) {
|
||||
* super(get);
|
||||
* MethodType getType = this.type();
|
||||
* MethodType setType = getType.insertParameterType(getType.parameterCount(), getType.returnType()).changeReturnType(void.class);
|
||||
* this.setter = MethodHandles.publicLookup().bind(this, set, setType);
|
||||
* }
|
||||
* }
|
||||
* // class Main { public static void main(String... av) { ...
|
||||
* final Number[] stuff = { 123, 456 };
|
||||
* AssignableMethodHandle stuffPtr = new AssignableMethodHandle("get", "set") {
|
||||
* public Number get(long i) { return stuff[(int)i]; }
|
||||
* public void set(long i, Object x) { stuff[(int)i] = x; }
|
||||
* }
|
||||
* int x = (Integer) stuffPtr.<Number>invoke(1L); // 456
|
||||
* stuffPtr.setter().<void>invoke(0L, (Number) 789); // replaces 123 with 789
|
||||
* </pre></blockquote>
|
||||
* @see MethodHandle
|
||||
* @author John Rose, JSR 292 EG
|
||||
*/
|
||||
@ -72,12 +148,87 @@ public abstract class JavaMethodHandle
|
||||
// with a JVM change which moves the required hidden behavior onto this class.
|
||||
extends sun.dyn.BoundMethodHandle
|
||||
{
|
||||
private static final Access IMPL_TOKEN = Access.getToken();
|
||||
|
||||
/**
|
||||
* When creating a, pass in {@code entryPoint}, any method handle which
|
||||
* can take the current object
|
||||
* @param entryPoint
|
||||
* When creating a {@code JavaMethodHandle}, the actual method handle
|
||||
* invocation behavior will be delegated to the specified {@code entryPoint}.
|
||||
* This may be any method handle which can take the newly constructed object
|
||||
* as a leading parameter.
|
||||
* <p>
|
||||
* The method handle type of {@code this} (i.e, the fully constructed object)
|
||||
* will be {@code entryPoint}, minus the leading argument.
|
||||
* The leading argument will be bound to {@code this} on every method
|
||||
* handle invocation.
|
||||
* @param entryPoint the method handle to handle calls
|
||||
*/
|
||||
protected JavaMethodHandle(MethodHandle entryPoint) {
|
||||
super(entryPoint, 0);
|
||||
super(entryPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a method handle whose entry point is a non-static method
|
||||
* visible in the exact (most specific) class of
|
||||
* the newly constructed object.
|
||||
* <p>
|
||||
* The method is specified by name and type, as if via this expression:
|
||||
* {@code MethodHandles.lookup().findVirtual(this.getClass(), name, type)}.
|
||||
* The class defining the method might be an anonymous inner class.
|
||||
* <p>
|
||||
* The method handle type of {@code this} (i.e, the fully constructed object)
|
||||
* will be the given method handle type.
|
||||
* A call to {@code this} will invoke the selected method.
|
||||
* The receiver argument will be bound to {@code this} on every method
|
||||
* handle invocation.
|
||||
* <p>
|
||||
* <i>Rationale:</i>
|
||||
* Although this constructor may seem to be a mere luxury,
|
||||
* it is not subsumed by the more general constructor which
|
||||
* takes any {@code MethodHandle} as the entry point argument.
|
||||
* In order to convert an entry point name to a method handle,
|
||||
* the self-class of the object is required (in order to do
|
||||
* the lookup). The self-class, in turn, is generally not
|
||||
* available at the time of the constructor invocation,
|
||||
* due to the rules of Java and the JVM verifier.
|
||||
* One cannot call {@code this.getClass()}, because
|
||||
* the value of {@code this} is inaccessible at the point
|
||||
* of the constructor call. (Changing this would require
|
||||
* change to the Java language, verifiers, and compilers.)
|
||||
* In particular, this constructor allows {@code JavaMethodHandle}s
|
||||
* to be created in combination with the anonymous inner class syntax.
|
||||
* @param entryPointName the name of the entry point method
|
||||
* @param type (optional) the desired type of the method handle
|
||||
*/
|
||||
protected JavaMethodHandle(String entryPointName, MethodType type) {
|
||||
super(entryPointName, type, true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a method handle whose entry point is a non-static method
|
||||
* visible in the exact (most specific) class of
|
||||
* the newly constructed object.
|
||||
* <p>
|
||||
* The method is specified only by name.
|
||||
* There must be exactly one method of that name visible in the object class,
|
||||
* either inherited or locally declared.
|
||||
* (That is, the method must not be overloaded.)
|
||||
* <p>
|
||||
* The method handle type of {@code this} (i.e, the fully constructed object)
|
||||
* will be the same as the type of the selected non-static method.
|
||||
* The receiver argument will be bound to {@code this} on every method
|
||||
* handle invocation.
|
||||
* <p>ISSUE: This signature wildcarding feature does not correspond to
|
||||
* any MethodHandles.Lookup API element. Can we eliminate it?
|
||||
* Alternatively, it is useful for naming non-overloaded methods.
|
||||
* Shall we make type arguments optional in the Lookup methods,
|
||||
* throwing an error in cases of ambiguity?
|
||||
* <p>
|
||||
* For this method's rationale, see the documentation
|
||||
* for {@link #JavaMethodHandle(String,MethodType)}.
|
||||
* @param entryPointName the name of the entry point method
|
||||
*/
|
||||
protected JavaMethodHandle(String entryPointName) {
|
||||
super(entryPointName, (MethodType) null, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,9 @@
|
||||
|
||||
package java.dyn;
|
||||
|
||||
import java.dyn.MethodHandles.Lookup;
|
||||
import java.util.WeakHashMap;
|
||||
import sun.dyn.Access;
|
||||
import sun.reflect.Reflection;
|
||||
import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege;
|
||||
|
||||
@ -34,6 +36,8 @@ import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege;
|
||||
* @author John Rose, JSR 292 EG
|
||||
*/
|
||||
public class Linkage {
|
||||
private static final Access IMPL_TOKEN = Access.getToken();
|
||||
|
||||
private Linkage() {} // do not instantiate
|
||||
|
||||
/**
|
||||
@ -53,19 +57,23 @@ public class Linkage {
|
||||
* call to this method.
|
||||
* <li>The given class is already fully initialized.
|
||||
* <li>The given class is in the process of initialization, in another thread.
|
||||
* <li>The same {@code CallSite} object has already been returned from
|
||||
* a bootstrap method call to another {@code invokedynamic} call site.
|
||||
* </ul>
|
||||
* Because of these rules, a class may install its own bootstrap method in
|
||||
* a static initializer.
|
||||
* @param callerClass a class that may have {@code invokedynamic} sites
|
||||
* @param bootstrapMethod the method to use to bootstrap all such sites
|
||||
*/
|
||||
public static
|
||||
void registerBootstrapMethod(Class callerClass, MethodHandle mh) {
|
||||
void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) {
|
||||
Class callc = Reflection.getCallerClass(2);
|
||||
checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod");
|
||||
checkBSM(mh);
|
||||
checkBSM(bootstrapMethod);
|
||||
synchronized (bootstrapMethods) {
|
||||
if (bootstrapMethods.containsKey(callerClass))
|
||||
throw new IllegalStateException("bootstrap method already declared in "+callerClass);
|
||||
bootstrapMethods.put(callerClass, mh);
|
||||
bootstrapMethods.put(callerClass, bootstrapMethod);
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,8 +96,9 @@ public class Linkage {
|
||||
public static
|
||||
void registerBootstrapMethod(Class<?> runtime, String name) {
|
||||
Class callc = Reflection.getCallerClass(2);
|
||||
Lookup lookup = new Lookup(IMPL_TOKEN, callc);
|
||||
MethodHandle bootstrapMethod =
|
||||
MethodHandles.findStaticFrom(callc, runtime, name, BOOTSTRAP_METHOD_TYPE);
|
||||
lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE);
|
||||
// FIXME: exception processing wrong here
|
||||
checkBSM(bootstrapMethod);
|
||||
Linkage.registerBootstrapMethod(callc, bootstrapMethod);
|
||||
@ -106,8 +115,9 @@ public class Linkage {
|
||||
public static
|
||||
void registerBootstrapMethod(String name) {
|
||||
Class callc = Reflection.getCallerClass(2);
|
||||
Lookup lookup = new Lookup(IMPL_TOKEN, callc);
|
||||
MethodHandle bootstrapMethod =
|
||||
MethodHandles.findStaticFrom(callc, callc, name, BOOTSTRAP_METHOD_TYPE);
|
||||
lookup.findStatic(callc, name, BOOTSTRAP_METHOD_TYPE);
|
||||
// FIXME: exception processing wrong here
|
||||
checkBSM(bootstrapMethod);
|
||||
Linkage.registerBootstrapMethod(callc, bootstrapMethod);
|
||||
@ -116,8 +126,7 @@ public class Linkage {
|
||||
/**
|
||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
||||
* Report the bootstrap method registered for a given class.
|
||||
* Returns null if the class has never yet registered a bootstrap method,
|
||||
* or if the class has explicitly registered a null bootstrap method.
|
||||
* Returns null if the class has never yet registered a bootstrap method.
|
||||
* Only callers privileged to set the bootstrap method may inquire
|
||||
* about it, because a bootstrap method is potentially a back-door entry
|
||||
* point into its class.
|
||||
@ -137,12 +146,12 @@ public class Linkage {
|
||||
* {@code (Class, String, MethodType)} returning a {@code CallSite}.
|
||||
*/
|
||||
public static final MethodType BOOTSTRAP_METHOD_TYPE
|
||||
= MethodType.make(CallSite.class,
|
||||
Class.class, String.class, MethodType.class);
|
||||
= MethodType.methodType(CallSite.class,
|
||||
Class.class, String.class, MethodType.class);
|
||||
|
||||
private static final MethodType OLD_BOOTSTRAP_METHOD_TYPE
|
||||
= MethodType.make(Object.class,
|
||||
CallSite.class, Object[].class);
|
||||
= MethodType.methodType(Object.class,
|
||||
CallSite.class, Object[].class);
|
||||
|
||||
private static final WeakHashMap<Class, MethodHandle> bootstrapMethods =
|
||||
new WeakHashMap<Class, MethodHandle>();
|
||||
@ -173,8 +182,8 @@ public class Linkage {
|
||||
|
||||
/**
|
||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
||||
* Invalidate all <code>invokedynamic</code> call sites associated
|
||||
* with the given class.
|
||||
* Invalidate all <code>invokedynamic</code> call sites in the bytecodes
|
||||
* of any methods of the given class.
|
||||
* (These are exactly those sites which report the given class
|
||||
* via the {@link CallSite#callerClass()} method.)
|
||||
* <p>
|
||||
|
||||
@ -88,7 +88,7 @@ public final class LinkagePermission extends BasicPermission {
|
||||
/**
|
||||
* Create a new LinkagePermission with the given name.
|
||||
* The name is the symbolic name of the LinkagePermission, such as
|
||||
* "registerBootstrapMethod", "invalidateClass.*", etc. An asterisk
|
||||
* "registerBootstrapMethod", "invalidateCallerClass.*", etc. An asterisk
|
||||
* may appear at the end of the name, following a ".", or by itself, to
|
||||
* signify a wildcard match.
|
||||
*
|
||||
|
||||
@ -30,6 +30,9 @@ package java.dyn;
|
||||
import sun.dyn.Access;
|
||||
import sun.dyn.MethodHandleImpl;
|
||||
|
||||
import static java.dyn.MethodHandles.invokers; // package-private API
|
||||
import static sun.dyn.MemberName.newIllegalArgumentException; // utility
|
||||
|
||||
/**
|
||||
* A method handle is a typed reference to the entry point of a method.
|
||||
* <p>
|
||||
@ -45,8 +48,9 @@ import sun.dyn.MethodHandleImpl;
|
||||
* Every method handle appears as an object containing a method named
|
||||
* <code>invoke</code>, whose signature exactly matches
|
||||
* the method handle's type.
|
||||
* A normal Java method call (using the <code>invokevirtual</code> instruction)
|
||||
* can invoke this method from Java source code (if language support is present).
|
||||
* A Java method call expression, which compiles to an
|
||||
* <code>invokevirtual</code> instruction,
|
||||
* can invoke this method from Java source code.
|
||||
* <p>
|
||||
* Every call to a method handle specifies an intended method type,
|
||||
* which must exactly match the type of the method handle.
|
||||
@ -57,6 +61,10 @@ import sun.dyn.MethodHandleImpl;
|
||||
* The call fails with a {@link WrongMethodTypeException}
|
||||
* if the method does not exist, even if there is an <code>invoke</code>
|
||||
* method of a closely similar signature.
|
||||
* As with other kinds
|
||||
* of methods in the JVM, signature matching during method linkage
|
||||
* is exact, and does not allow for language-level implicit conversions
|
||||
* such as {@code String} to {@code Object} or {@code short} to {@code int}.
|
||||
* <p>
|
||||
* A method handle is an unrestricted capability to call a method.
|
||||
* A method handle can be formed on a non-public method by a class
|
||||
@ -74,6 +82,15 @@ import sun.dyn.MethodHandleImpl;
|
||||
* (after resolving symbolic type names) must exactly match the method type
|
||||
* of the target method.
|
||||
* <p>
|
||||
* Every <code>invoke</code> method always throws {@link Exception},
|
||||
* which is to say that there is no static restriction on what a method handle
|
||||
* can throw. Since the JVM does not distinguish between checked
|
||||
* and unchecked exceptions (other than by their class, of course),
|
||||
* there is no particular effect on bytecode shape from ascribing
|
||||
* checked exceptions to method handle invocations. But in Java source
|
||||
* code, methods which perform method handle calls must either explicitly
|
||||
* throw {@code Exception}, or else must catch all checked exceptions locally.
|
||||
* <p>
|
||||
* Bytecode in an extended JVM can directly obtain a method handle
|
||||
* for any accessible method from a <code>ldc</code> instruction
|
||||
* which refers to a <code>CONSTANT_Methodref</code> or
|
||||
@ -97,6 +114,59 @@ import sun.dyn.MethodHandleImpl;
|
||||
* can also be created. These do not perform virtual lookup based on
|
||||
* receiver type. Such a method handle simulates the effect of
|
||||
* an <code>invokespecial</code> instruction to the same method.
|
||||
* <p>
|
||||
* Here are some examples of usage:
|
||||
* <p><blockquote><pre>
|
||||
* Object x, y; String s; int i;
|
||||
* MethodType mt; MethodHandle mh;
|
||||
* MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
* // mt is {(char,char) => String}
|
||||
* mt = MethodType.make(String.class, char.class, char.class);
|
||||
* mh = lookup.findVirtual(String.class, "replace", mt);
|
||||
* // (Ljava/lang/String;CC)Ljava/lang/String;
|
||||
* s = mh.<String>invoke("daddy",'d','n');
|
||||
* assert(s.equals("nanny"));
|
||||
* // weakly typed invocation (using MHs.invoke)
|
||||
* s = (String) MethodHandles.invoke(mh, "sappy", 'p', 'v');
|
||||
* assert(s.equals("savvy"));
|
||||
* // mt is {Object[] => List}
|
||||
* mt = MethodType.make(java.util.List.class, Object[].class);
|
||||
* mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
|
||||
* // mt is {(Object,Object,Object) => Object}
|
||||
* mt = MethodType.makeGeneric(3);
|
||||
* mh = MethodHandles.collectArguments(mh, mt);
|
||||
* // mt is {(Object,Object,Object) => Object}
|
||||
* // (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
* x = mh.invoke((Object)1, (Object)2, (Object)3);
|
||||
* assert(x.equals(java.util.Arrays.asList(1,2,3)));
|
||||
* // mt is { => int}
|
||||
* mt = MethodType.make(int.class);
|
||||
* mh = lookup.findVirtual(java.util.List.class, "size", mt);
|
||||
* // (Ljava/util/List;)I
|
||||
* i = mh.<int>invoke(java.util.Arrays.asList(1,2,3));
|
||||
* assert(i == 3);
|
||||
* </pre></blockquote>
|
||||
* Each of the above calls generates a single invokevirtual instruction
|
||||
* with the name {@code invoke} and the type descriptors indicated in the comments.
|
||||
* The argument types are taken directly from the actual arguments,
|
||||
* while the return type is taken from the type parameter.
|
||||
* (This type parameter may be a primitive, and it defaults to {@code Object}.)
|
||||
* <p>
|
||||
* <em>A note on generic typing:</em> Method handles do not represent
|
||||
* their function types in terms of Java parameterized (generic) types,
|
||||
* because there are three mismatches between function types and parameterized
|
||||
* Java types.
|
||||
* <ol>
|
||||
* <li>Method types range over all possible arities,
|
||||
* from no arguments to an arbitrary number of arguments.
|
||||
* Generics are not variadic, and so cannot represent this.</li>
|
||||
* <li>Method types can specify arguments of primitive types,
|
||||
* which Java generic types cannot range over.</li>
|
||||
* <li>Higher order functions over method handles (combinators) are
|
||||
* often generic across a wide range of function types, including
|
||||
* those of multiple arities. It is impossible to represent such
|
||||
* genericity with a Java type parameter.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @see MethodType
|
||||
* @see MethodHandles
|
||||
@ -107,17 +177,19 @@ public abstract class MethodHandle
|
||||
// with a JVM change which moves the required hidden state onto this class.
|
||||
extends MethodHandleImpl
|
||||
{
|
||||
// interface MethodHandle<T extends MethodType<R,A...>>
|
||||
// { T type(); <R,A...> public R invoke(A...); }
|
||||
private static Access IMPL_TOKEN = Access.getToken();
|
||||
|
||||
final private MethodType type;
|
||||
// interface MethodHandle<R throws X extends Exception,A...>
|
||||
// { MethodType<R throws X,A...> type(); public R invoke(A...) throws X; }
|
||||
|
||||
private MethodType type;
|
||||
|
||||
/**
|
||||
* Report the type of this method handle.
|
||||
* Every invocation of this method handle must exactly match this type.
|
||||
* @return the method handle type
|
||||
*/
|
||||
public MethodType type() {
|
||||
public final MethodType type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -130,6 +202,369 @@ public abstract class MethodHandle
|
||||
*/
|
||||
protected MethodHandle(Access token, MethodType type) {
|
||||
super(token);
|
||||
Access.check(token);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private void initType(MethodType type) {
|
||||
type.getClass(); // elicit NPE
|
||||
if (this.type != null) throw new InternalError();
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
static {
|
||||
// This hack allows the implementation package special access to
|
||||
// the internals of MethodHandle. In particular, the MTImpl has all sorts
|
||||
// of cached information useful to the implementation code.
|
||||
MethodHandleImpl.setMethodHandleFriend(IMPL_TOKEN, new MethodHandleImpl.MethodHandleFriend() {
|
||||
public void initType(MethodHandle mh, MethodType type) { mh.initType(type); }
|
||||
});
|
||||
}
|
||||
|
||||
/** The string of a direct method handle is the simple name of its target method.
|
||||
* The string of an adapter or bound method handle is the string of its
|
||||
* target method handle.
|
||||
* The string of a Java method handle is the string of its entry point method,
|
||||
* unless the Java method handle overrides the toString method.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return MethodHandleImpl.getNameString(IMPL_TOKEN, this);
|
||||
}
|
||||
|
||||
//// First draft of the "Method Handle Kernel API" discussed at the JVM Language Summit, 9/2009.
|
||||
//// Implementations here currently delegate to statics in MethodHandles. Some of those statics
|
||||
//// will be deprecated. Others will be kept as "algorithms" to supply degrees of freedom
|
||||
//// not present in the Kernel API.
|
||||
|
||||
/**
|
||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
||||
* Perform an exact invocation. The signature at the call site of {@code invokeExact} must
|
||||
* exactly match this method handle's {@code type}.
|
||||
* No conversions are allowed on arguments or return values.
|
||||
* <em>This is not yet implemented, pending required compiler and JVM support.</em>
|
||||
*/
|
||||
public final <T> T invokeExact(Object... arguments) throws Throwable {
|
||||
// This is an approximate implementation, which discards the caller's signature and refuses the call.
|
||||
throw new InternalError("not yet implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
||||
* Perform a generic invocation. The signature at the call site of {@code invokeExact} must
|
||||
* have the same arity as this method handle's {@code type}.
|
||||
* The same conversions are allowed on arguments or return values as are supported by
|
||||
* by {@link MethodHandles#convertArguments}.
|
||||
* If the call site signature exactly matches this method handle's {@code type},
|
||||
* the call proceeds as if by {@link #invokeExact}.
|
||||
* <em>This is not fully implemented, pending required compiler and JVM support.</em>
|
||||
*/
|
||||
// This is an approximate implementation, which discards the caller's signature.
|
||||
// When it is made signature polymorphic, the overloadings will disappear.
|
||||
public final <T> T invokeGeneric() throws Throwable {
|
||||
MethodHandle invoker = invokers(this.type()).genericInvoker();
|
||||
return invoker.<T>invoke(this);
|
||||
}
|
||||
public final <T> T invokeGeneric(Object a0) throws Throwable {
|
||||
MethodHandle invoker = invokers(this.type()).genericInvoker();
|
||||
return invoker.<T>invoke(this, a0);
|
||||
}
|
||||
public final <T> T invokeGeneric(Object a0, Object a1) throws Throwable {
|
||||
MethodHandle invoker = invokers(this.type()).genericInvoker();
|
||||
return invoker.<T>invoke(this, a0, a1);
|
||||
}
|
||||
public final <T> T invokeGeneric(Object a0, Object a1, Object a2) throws Throwable {
|
||||
MethodHandle invoker = invokers(this.type()).genericInvoker();
|
||||
return invoker.<T>invoke(this, a0, a1, a2);
|
||||
}
|
||||
public final <T> T invokeGeneric(Object a0, Object a1, Object a2, Object a3) throws Throwable {
|
||||
MethodHandle invoker = invokers(this.type()).genericInvoker();
|
||||
return invoker.<T>invoke(this, a0, a1, a2, a3);
|
||||
}
|
||||
public final <T> T invokeGeneric(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4) throws Throwable {
|
||||
MethodHandle invoker = invokers(this.type()).genericInvoker();
|
||||
return invoker.<T>invoke(this, a0, a1, a2, a3, a4);
|
||||
}
|
||||
public final <T> T invokeGeneric(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4, Object a5) throws Throwable {
|
||||
MethodHandle invoker = invokers(this.type()).genericInvoker();
|
||||
return invoker.<T>invoke(this, a0, a1, a2, a3, a4, a5);
|
||||
}
|
||||
public final <T> T invokeGeneric(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4, Object a5, Object a6) throws Throwable {
|
||||
MethodHandle invoker = invokers(this.type()).genericInvoker();
|
||||
return invoker.<T>invoke(this, a0, a1, a2, a3, a4, a5, a6);
|
||||
}
|
||||
public final <T> T invokeGeneric(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4, Object a5, Object a6, Object a7) throws Throwable {
|
||||
MethodHandle invoker = invokers(this.type()).genericInvoker();
|
||||
return invoker.<T>invoke(this, a0, a1, a2, a3, a4, a5, a6, a7);
|
||||
}
|
||||
public final <T> T invokeGeneric(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable {
|
||||
MethodHandle invoker = invokers(this.type()).genericInvoker();
|
||||
return invoker.<T>invoke(this, a0, a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
}
|
||||
public final <T> T invokeGeneric(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable {
|
||||
MethodHandle invoker = invokers(this.type()).genericInvoker();
|
||||
return invoker.<T>invoke(this, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
|
||||
}
|
||||
|
||||
/**
|
||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
||||
* Perform a varargs invocation, passing the arguments in the given array
|
||||
* to the method handle, as if via {@link #invokeGeneric} from a call site
|
||||
* which mentions only the type {@code Object}, and whose arity is the length
|
||||
* of the argument array.
|
||||
* <p>
|
||||
* The length of the arguments array must equal the parameter count
|
||||
* of the target's type.
|
||||
* The arguments array is spread into separate arguments.
|
||||
* <p>
|
||||
* In order to match the type of the target, the following argument
|
||||
* conversions are applied as necessary:
|
||||
* <ul>
|
||||
* <li>reference casting
|
||||
* <li>unboxing
|
||||
* </ul>
|
||||
* The following conversions are not applied:
|
||||
* <ul>
|
||||
* <li>primitive conversions (e.g., {@code byte} to {@code int}
|
||||
* <li>varargs conversions other than the initial spread
|
||||
* <li>any application-specific conversions (e.g., string to number)
|
||||
* </ul>
|
||||
* The result returned by the call is boxed if it is a primitive,
|
||||
* or forced to null if the return type is void.
|
||||
* <p>
|
||||
* This call is equivalent to the following code:
|
||||
* <p><blockquote><pre>
|
||||
* MethodHandle invoker = MethodHandles.genericInvoker(this.type(), 0, true);
|
||||
* Object result = invoker.invoke(this, arguments);
|
||||
* </pre></blockquote>
|
||||
* @param arguments the arguments to pass to the target
|
||||
* @return the result returned by the target
|
||||
* @see MethodHandles#genericInvoker
|
||||
*/
|
||||
public final Object invokeVarargs(Object[] arguments) throws Throwable {
|
||||
int argc = arguments == null ? 0 : arguments.length;
|
||||
MethodType type = type();
|
||||
if (argc <= 10) {
|
||||
MethodHandle invoker = MethodHandles.invokers(type).genericInvoker();
|
||||
switch (argc) {
|
||||
case 0: return invoker.invoke(this);
|
||||
case 1: return invoker.invoke(this,
|
||||
arguments[0]);
|
||||
case 2: return invoker.invoke(this,
|
||||
arguments[0], arguments[1]);
|
||||
case 3: return invoker.invoke(this,
|
||||
arguments[0], arguments[1], arguments[2]);
|
||||
case 4: return invoker.invoke(this,
|
||||
arguments[0], arguments[1], arguments[2],
|
||||
arguments[3]);
|
||||
case 5: return invoker.invoke(this,
|
||||
arguments[0], arguments[1], arguments[2],
|
||||
arguments[3], arguments[4]);
|
||||
case 6: return invoker.invoke(this,
|
||||
arguments[0], arguments[1], arguments[2],
|
||||
arguments[3], arguments[4], arguments[5]);
|
||||
case 7: return invoker.invoke(this,
|
||||
arguments[0], arguments[1], arguments[2],
|
||||
arguments[3], arguments[4], arguments[5],
|
||||
arguments[6]);
|
||||
case 8: return invoker.invoke(this,
|
||||
arguments[0], arguments[1], arguments[2],
|
||||
arguments[3], arguments[4], arguments[5],
|
||||
arguments[6], arguments[7]);
|
||||
case 9: return invoker.invoke(this,
|
||||
arguments[0], arguments[1], arguments[2],
|
||||
arguments[3], arguments[4], arguments[5],
|
||||
arguments[6], arguments[7], arguments[8]);
|
||||
case 10: return invoker.invoke(this,
|
||||
arguments[0], arguments[1], arguments[2],
|
||||
arguments[3], arguments[4], arguments[5],
|
||||
arguments[6], arguments[7], arguments[8],
|
||||
arguments[9]);
|
||||
}
|
||||
}
|
||||
|
||||
// more than ten arguments get boxed in a varargs list:
|
||||
MethodHandle invoker = MethodHandles.invokers(type).varargsInvoker(0);
|
||||
return invoker.invoke(this, arguments);
|
||||
}
|
||||
/** Equivalent to {@code invokeVarargs(arguments.toArray())}. */
|
||||
public final Object invokeVarargs(java.util.List<?> arguments) throws Throwable {
|
||||
return invokeVarargs(arguments.toArray());
|
||||
}
|
||||
|
||||
/* --- this is intentionally NOT a javadoc yet ---
|
||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
||||
* Produce an adapter method handle which adapts the type of the
|
||||
* current method handle to a new type by pairwise argument conversion.
|
||||
* The original type and new type must have the same number of arguments.
|
||||
* The resulting method handle is guaranteed to confess a type
|
||||
* which is equal to the desired new type.
|
||||
* <p>
|
||||
* If the original type and new type are equal, returns {@code this}.
|
||||
* <p>
|
||||
* The following conversions are applied as needed both to
|
||||
* arguments and return types. Let T0 and T1 be the differing
|
||||
* new and old parameter types (or old and new return types)
|
||||
* for corresponding values passed by the new and old method types.
|
||||
* Given those types T0, T1, one of the following conversions is applied
|
||||
* if possible:
|
||||
* <ul>
|
||||
* <li>If T0 and T1 are references, and T1 is not an interface type,
|
||||
* then a cast to T1 is applied.
|
||||
* (The types do not need to be related in any particular way.)
|
||||
* <li>If T0 and T1 are references, and T1 is an interface type,
|
||||
* then the value of type T0 is passed as a T1 without a cast.
|
||||
* (This treatment of interfaces follows the usage of the bytecode verifier.)
|
||||
* <li>If T0 and T1 are primitives, then a Java casting
|
||||
* conversion (JLS 5.5) is applied, if one exists.
|
||||
* <li>If T0 and T1 are primitives and one is boolean,
|
||||
* the boolean is treated as a one-bit unsigned integer.
|
||||
* (This treatment follows the usage of the bytecode verifier.)
|
||||
* A conversion from another primitive type behaves as if
|
||||
* it first converts to byte, and then masks all but the low bit.
|
||||
* <li>If T0 is a primitive and T1 a reference, a boxing
|
||||
* conversion is applied if one exists, possibly followed by
|
||||
* an reference conversion to a superclass.
|
||||
* T1 must be a wrapper class or a supertype of one.
|
||||
* If T1 is a wrapper class, T0 is converted if necessary
|
||||
* to T1's primitive type by one of the preceding conversions.
|
||||
* Otherwise, T0 is boxed, and its wrapper converted to T1.
|
||||
* <li>If T0 is a reference and T1 a primitive, an unboxing
|
||||
* conversion is applied if one exists, possibly preceded by
|
||||
* a reference conversion to a wrapper class.
|
||||
* T0 must be a wrapper class or a supertype of one.
|
||||
* If T0 is a wrapper class, its primitive value is converted
|
||||
* if necessary to T1 by one of the preceding conversions.
|
||||
* Otherwise, T0 is converted directly to the wrapper type for T1,
|
||||
* which is then unboxed.
|
||||
* <li>If the return type T1 is void, any returned value is discarded
|
||||
* <li>If the return type T0 is void and T1 a reference, a null value is introduced.
|
||||
* <li>If the return type T0 is void and T1 a primitive, a zero value is introduced.
|
||||
* </ul>
|
||||
* <p>
|
||||
*/
|
||||
/**
|
||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
||||
* Produce an adapter method handle which adapts the type of the
|
||||
* current method handle to a new type by pairwise argument conversion.
|
||||
* The original type and new type must have the same number of arguments.
|
||||
* The resulting method handle is guaranteed to confess a type
|
||||
* which is equal to the desired new type.
|
||||
* <p>
|
||||
* If the original type and new type are equal, returns {@code this}.
|
||||
* <p>
|
||||
* This method is equivalent to {@link MethodHandles#convertArguments}.
|
||||
* @param newType the expected type of the new method handle
|
||||
* @return a method handle which delegates to {@code this} after performing
|
||||
* any necessary argument conversions, and arranges for any
|
||||
* necessary return value conversions
|
||||
* @throws IllegalArgumentException if the conversion cannot be made
|
||||
* @see MethodHandles#convertArguments
|
||||
*/
|
||||
public final MethodHandle asType(MethodType newType) {
|
||||
return MethodHandles.convertArguments(this, newType);
|
||||
}
|
||||
|
||||
/**
|
||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
||||
* Produce a method handle which adapts, as its <i>target</i>,
|
||||
* the current method handle. The type of the adapter will be
|
||||
* the same as the type of the target, except that all but the first
|
||||
* {@code keepPosArgs} parameters of the target's type are replaced
|
||||
* by a single array parameter of type {@code Object[]}.
|
||||
* Thus, if {@code keepPosArgs} is zero, the adapter will take all
|
||||
* arguments in a single object array.
|
||||
* <p>
|
||||
* When called, the adapter replaces a trailing array argument
|
||||
* by the array's elements, each as its own argument to the target.
|
||||
* (The order of the arguments is preserved.)
|
||||
* They are converted pairwise by casting and/or unboxing
|
||||
* (as if by {@link MethodHandles#convertArguments})
|
||||
* to the types of the trailing parameters of the target.
|
||||
* Finally the target is called.
|
||||
* What the target eventually returns is returned unchanged by the adapter.
|
||||
* <p>
|
||||
* Before calling the target, the adapter verifies that the array
|
||||
* contains exactly enough elements to provide a correct argument count
|
||||
* to the target method handle.
|
||||
* (The array may also be null when zero elements are required.)
|
||||
* @param keepPosArgs the number of leading positional arguments to preserve
|
||||
* @return a new method handle which spreads its final argument,
|
||||
* before calling the original method handle
|
||||
* @throws IllegalArgumentException if target does not have at least
|
||||
* {@code keepPosArgs} parameter types
|
||||
*/
|
||||
public final MethodHandle asSpreader(int keepPosArgs) {
|
||||
MethodType oldType = type();
|
||||
int nargs = oldType.parameterCount();
|
||||
MethodType newType = oldType.dropParameterTypes(keepPosArgs, nargs);
|
||||
newType = newType.insertParameterTypes(keepPosArgs, Object[].class);
|
||||
return MethodHandles.spreadArguments(this, newType);
|
||||
}
|
||||
|
||||
/**
|
||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
||||
* Produce a method handle which adapts, as its <i>target</i>,
|
||||
* the current method handle. The type of the adapter will be
|
||||
* the same as the type of the target, except that a single trailing
|
||||
* array parameter of type {@code Object[]} is replaced by
|
||||
* {@code spreadArrayArgs} parameters of type {@code Object}.
|
||||
* <p>
|
||||
* When called, the adapter replaces its trailing {@code spreadArrayArgs}
|
||||
* arguments by a single new {@code Object} array, whose elements
|
||||
* comprise (in order) the replaced arguments.
|
||||
* Finally the target is called.
|
||||
* What the target eventually returns is returned unchanged by the adapter.
|
||||
* <p>
|
||||
* (The array may also be a shared constant when {@code spreadArrayArgs} is zero.)
|
||||
* @param spreadArrayArgs the number of arguments to spread from the trailing array
|
||||
* @return a new method handle which collects some trailing argument
|
||||
* into an array, before calling the original method handle
|
||||
* @throws IllegalArgumentException if the last argument of the target
|
||||
* is not {@code Object[]}
|
||||
* @throws IllegalArgumentException if {@code spreadArrayArgs} is not
|
||||
* a legal array size
|
||||
* @deprecated Provisional and unstable; use {@link MethodHandles#collectArguments}.
|
||||
*/
|
||||
public final MethodHandle asCollector(int spreadArrayArgs) {
|
||||
MethodType oldType = type();
|
||||
int nargs = oldType.parameterCount();
|
||||
MethodType newType = oldType.dropParameterTypes(nargs-1, nargs);
|
||||
newType = newType.insertParameterTypes(nargs-1, MethodType.genericMethodType(spreadArrayArgs).parameterArray());
|
||||
return MethodHandles.collectArguments(this, newType);
|
||||
}
|
||||
|
||||
/**
|
||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
||||
* Produce a method handle which binds the given argument
|
||||
* to the current method handle as <i>target</i>.
|
||||
* The type of the bound handle will be
|
||||
* the same as the type of the target, except that a single leading
|
||||
* reference parameter will be omitted.
|
||||
* <p>
|
||||
* When called, the bound handle inserts the given value {@code x}
|
||||
* as a new leading argument to the target. The other arguments are
|
||||
* also passed unchanged.
|
||||
* What the target eventually returns is returned unchanged by the bound handle.
|
||||
* <p>
|
||||
* The reference {@code x} must be convertible to the first parameter
|
||||
* type of the target.
|
||||
* @param x the value to bind to the first argument of the target
|
||||
* @return a new method handle which collects some trailing argument
|
||||
* into an array, before calling the original method handle
|
||||
* @throws IllegalArgumentException if the target does not have a
|
||||
* leading parameter type that is a reference type
|
||||
* @throws ClassCastException if {@code x} cannot be converted
|
||||
* to the leading parameter type of the target
|
||||
* @deprecated Provisional and unstable; use {@link MethodHandles#insertArguments}.
|
||||
*/
|
||||
public final MethodHandle bindTo(Object x) {
|
||||
return MethodHandles.insertArguments(this, 0, x);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -32,7 +32,7 @@ import java.util.List;
|
||||
import sun.dyn.Access;
|
||||
import sun.dyn.Invokers;
|
||||
import sun.dyn.MethodTypeImpl;
|
||||
import sun.dyn.util.BytecodeSignature;
|
||||
import sun.dyn.util.BytecodeDescriptor;
|
||||
import static sun.dyn.MemberName.newIllegalArgumentException;
|
||||
|
||||
/**
|
||||
@ -63,7 +63,7 @@ class MethodType {
|
||||
|
||||
static {
|
||||
// This hack allows the implementation package special access to
|
||||
// the internals of MethodType. In particular, the Form has all sorts
|
||||
// the internals of MethodType. In particular, the MTImpl has all sorts
|
||||
// of cached information useful to the implementation code.
|
||||
MethodTypeImpl.setMethodTypeFriend(IMPL_TOKEN, new MethodTypeImpl.MethodTypeFriend() {
|
||||
public Class<?>[] ptypes(MethodType mt) { return mt.ptypes; }
|
||||
@ -114,51 +114,76 @@ class MethodType {
|
||||
* @throws IllegalArgumentException if any of the ptypes is void
|
||||
*/
|
||||
public static
|
||||
MethodType make(Class<?> rtype, Class<?>[] ptypes) {
|
||||
MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
|
||||
return makeImpl(rtype, ptypes, false);
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. */
|
||||
public static
|
||||
MethodType make(Class<?> rtype, List<? extends Class<?>> ptypes) {
|
||||
return makeImpl(rtype, ptypes.toArray(NO_PTYPES), true);
|
||||
@Deprecated public static
|
||||
MethodType make(Class<?> rtype, Class<?>[] ptypes) {
|
||||
return methodType(rtype, ptypes);
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
|
||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. */
|
||||
public static
|
||||
MethodType methodType(Class<?> rtype, List<? extends Class<?>> ptypes) {
|
||||
boolean notrust = false; // random List impl. could return evil ptypes array
|
||||
return makeImpl(rtype, ptypes.toArray(NO_PTYPES), notrust);
|
||||
}
|
||||
@Deprecated public static
|
||||
MethodType make(Class<?> rtype, List<? extends Class<?>> ptypes) {
|
||||
return methodType(rtype, ptypes);
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||
* The leading parameter type is prepended to the remaining array.
|
||||
*/
|
||||
public static
|
||||
MethodType make(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
|
||||
MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
|
||||
Class<?>[] ptypes1 = new Class<?>[1+ptypes.length];
|
||||
ptypes1[0] = ptype0;
|
||||
System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
|
||||
return makeImpl(rtype, ptypes1, true);
|
||||
}
|
||||
@Deprecated public static
|
||||
MethodType make(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
|
||||
return methodType(rtype, ptype0, ptypes);
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
|
||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||
* The resulting method has no parameter types.
|
||||
*/
|
||||
public static
|
||||
MethodType make(Class<?> rtype) {
|
||||
MethodType methodType(Class<?> rtype) {
|
||||
return makeImpl(rtype, NO_PTYPES, true);
|
||||
}
|
||||
@Deprecated public static
|
||||
MethodType make(Class<?> rtype) {
|
||||
return methodType(rtype);
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
|
||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||
* The resulting method has the single given parameter type.
|
||||
*/
|
||||
public static
|
||||
MethodType make(Class<?> rtype, Class<?> ptype0) {
|
||||
MethodType methodType(Class<?> rtype, Class<?> ptype0) {
|
||||
return makeImpl(rtype, new Class<?>[]{ ptype0 }, true);
|
||||
}
|
||||
@Deprecated public static
|
||||
MethodType make(Class<?> rtype, Class<?> ptype0) {
|
||||
return methodType(rtype, ptype0);
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
|
||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||
* The resulting method has the same parameter types as {@code ptypes},
|
||||
* and the specified return type.
|
||||
*/
|
||||
public static
|
||||
MethodType make(Class<?> rtype, MethodType ptypes) {
|
||||
MethodType methodType(Class<?> rtype, MethodType ptypes) {
|
||||
return makeImpl(rtype, ptypes.ptypes, true);
|
||||
}
|
||||
@Deprecated public static
|
||||
MethodType make(Class<?> rtype, MethodType ptypes) {
|
||||
return methodType(rtype, ptypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sole factory method to find or create an interned method type.
|
||||
@ -202,15 +227,16 @@ class MethodType {
|
||||
private static final MethodType[] objectOnlyTypes = new MethodType[20];
|
||||
|
||||
/**
|
||||
* Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
|
||||
* All parameters and the return type will be Object, except the final varargs parameter if any.
|
||||
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||
* All parameters and the return type will be {@code Object},
|
||||
* except the final varargs parameter if any, which will be {@code Object[]}.
|
||||
* @param objectArgCount number of parameters (excluding the varargs parameter if any)
|
||||
* @param varargs whether there will be a varargs parameter, of type Object[]
|
||||
* @param varargs whether there will be a varargs parameter, of type {@code Object[]}
|
||||
* @return a totally generic method type, given only its count of parameters and varargs
|
||||
* @see #makeGeneric(int)
|
||||
* @see #genericMethodType(int)
|
||||
*/
|
||||
public static
|
||||
MethodType makeGeneric(int objectArgCount, boolean varargs) {
|
||||
MethodType genericMethodType(int objectArgCount, boolean varargs) {
|
||||
MethodType mt;
|
||||
int ivarargs = (!varargs ? 0 : 1);
|
||||
int ootIndex = objectArgCount*2 + ivarargs;
|
||||
@ -227,19 +253,27 @@ class MethodType {
|
||||
}
|
||||
return mt;
|
||||
}
|
||||
@Deprecated public static
|
||||
MethodType makeGeneric(int objectArgCount, boolean varargs) {
|
||||
return genericMethodType(objectArgCount, varargs);
|
||||
}
|
||||
|
||||
/**
|
||||
* All parameters and the return type will be Object.
|
||||
* @param objectArgCount number of parameters
|
||||
* @return a totally generic method type, given only its count of parameters
|
||||
* @see #makeGeneric(int, boolean)
|
||||
* @see #genericMethodType(int, boolean)
|
||||
*/
|
||||
public static
|
||||
MethodType genericMethodType(int objectArgCount) {
|
||||
return genericMethodType(objectArgCount, false);
|
||||
}
|
||||
@Deprecated public static
|
||||
MethodType makeGeneric(int objectArgCount) {
|
||||
return makeGeneric(objectArgCount, false);
|
||||
return genericMethodType(objectArgCount);
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
|
||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||
* @param num the index (zero-based) of the parameter type to change
|
||||
* @param nptype a new parameter type to replace the old one with
|
||||
* @return the same type, except with the selected parameter changed
|
||||
@ -251,11 +285,10 @@ class MethodType {
|
||||
return makeImpl(rtype, nptypes, true);
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
|
||||
* @param num the position (zero-based) of the inserted parameter type
|
||||
* @param nptype a new parameter type to insert into the parameter list
|
||||
* @return the same type, except with the selected parameter inserted
|
||||
/** Convenience method for {@link #insertParameterTypes}.
|
||||
* @deprecated Use {@link #insertParameterTypes} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public MethodType insertParameterType(int num, Class<?> nptype) {
|
||||
int len = ptypes.length;
|
||||
Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+1);
|
||||
@ -264,23 +297,73 @@ class MethodType {
|
||||
return makeImpl(rtype, nptypes, true);
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
|
||||
* @param num the index (zero-based) of the parameter type to remove
|
||||
* @return the same type, except with the selected parameter removed
|
||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||
* @param num the position (zero-based) of the inserted parameter type(s)
|
||||
* @param ptypesToInsert zero or more a new parameter types to insert into the parameter list
|
||||
* @return the same type, except with the selected parameter(s) inserted
|
||||
*/
|
||||
public MethodType dropParameterType(int num) {
|
||||
public MethodType insertParameterTypes(int num, Class<?>... ptypesToInsert) {
|
||||
int len = ptypes.length;
|
||||
if (num < 0 || num > len)
|
||||
throw newIllegalArgumentException("num="+num); //SPECME
|
||||
int ilen = ptypesToInsert.length;
|
||||
if (ilen == 0) return this;
|
||||
Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+ilen);
|
||||
System.arraycopy(nptypes, num, nptypes, num+ilen, len-num);
|
||||
System.arraycopy(ptypesToInsert, 0, nptypes, num, ilen);
|
||||
return makeImpl(rtype, nptypes, true);
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||
* @param num the position (zero-based) of the inserted parameter type(s)
|
||||
* @param ptypesToInsert zero or more a new parameter types to insert into the parameter list
|
||||
* @return the same type, except with the selected parameter(s) inserted
|
||||
*/
|
||||
public MethodType insertParameterTypes(int num, List<Class<?>> ptypesToInsert) {
|
||||
return insertParameterTypes(num, ptypesToInsert.toArray(NO_PTYPES));
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||
* @param start the index (zero-based) of the first parameter type to remove
|
||||
* @param end the index (greater than {@code start}) of the first parameter type after not to remove
|
||||
* @return the same type, except with the selected parameter(s) removed
|
||||
*/
|
||||
public MethodType dropParameterTypes(int start, int end) {
|
||||
int len = ptypes.length;
|
||||
if (!(0 <= start && start <= end && end <= len))
|
||||
throw newIllegalArgumentException("start="+start+" end="+end); //SPECME
|
||||
if (start == end) return this;
|
||||
Class<?>[] nptypes;
|
||||
if (num == 0) {
|
||||
nptypes = Arrays.copyOfRange(ptypes, 1, len);
|
||||
if (start == 0) {
|
||||
if (end == len) {
|
||||
// drop all parameters
|
||||
nptypes = NO_PTYPES;
|
||||
} else {
|
||||
// drop initial parameter(s)
|
||||
nptypes = Arrays.copyOfRange(ptypes, end, len);
|
||||
}
|
||||
} else {
|
||||
nptypes = Arrays.copyOfRange(ptypes, 0, len-1);
|
||||
System.arraycopy(ptypes, num+1, nptypes, num, (len-1)-num);
|
||||
if (end == len) {
|
||||
// drop trailing parameter(s)
|
||||
nptypes = Arrays.copyOfRange(ptypes, 0, start);
|
||||
} else {
|
||||
int tail = len - end;
|
||||
nptypes = Arrays.copyOfRange(ptypes, 0, start + tail);
|
||||
System.arraycopy(ptypes, end, nptypes, start, tail);
|
||||
}
|
||||
}
|
||||
return makeImpl(rtype, nptypes, true);
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}.
|
||||
/** Convenience method for {@link #dropParameterTypes}.
|
||||
* @deprecated Use {@link #dropParameterTypes} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public MethodType dropParameterType(int num) {
|
||||
return dropParameterTypes(num, num+1);
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||
* @param nrtype a return parameter type to replace the old one with
|
||||
* @return the same type, except with the return type change
|
||||
*/
|
||||
@ -291,6 +374,7 @@ class MethodType {
|
||||
|
||||
/** Convenience method.
|
||||
* Report if this type contains a primitive argument or return value.
|
||||
* The return type {@code void} counts as a primitive.
|
||||
* @return true if any of the types are primitives
|
||||
*/
|
||||
public boolean hasPrimitives() {
|
||||
@ -300,39 +384,47 @@ class MethodType {
|
||||
/** Convenience method.
|
||||
* Report if this type contains a wrapper argument or return value.
|
||||
* Wrappers are types which box primitive values, such as {@link Integer}.
|
||||
* The reference type {@code java.lang.Void} counts as a wrapper.
|
||||
* @return true if any of the types are wrappers
|
||||
*/
|
||||
public boolean hasWrappers() {
|
||||
return unwrap() != this;
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
|
||||
* Erase all reference types to Object.
|
||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||
* Erase all reference types to {@code Object}.
|
||||
* All primitive types (including {@code void}) will remain unchanged.
|
||||
* @return a version of the original type with all reference types replaced
|
||||
*/
|
||||
public MethodType erase() {
|
||||
return form.erasedType();
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #makeGeneric(int)}.
|
||||
* Convert all types, both reference and primitive, to Object.
|
||||
/** Convenience method for {@link #genericMethodType(int)}.
|
||||
* Convert all types, both reference and primitive, to {@code Object}.
|
||||
* The expression {@code type.wrap().erase()} produces the same value
|
||||
* as {@code type.generic()}.
|
||||
* @return a version of the original type with all types replaced
|
||||
*/
|
||||
public MethodType generic() {
|
||||
return makeGeneric(parameterCount());
|
||||
return genericMethodType(parameterCount());
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
|
||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||
* Convert all primitive types to their corresponding wrapper types.
|
||||
* All reference types (including wrapper types) will remain unchanged.
|
||||
* A {@code void} return type is changed to the type {@code java.lang.Void}.
|
||||
* The expression {@code type.wrap().erase()} produces the same value
|
||||
* as {@code type.generic()}.
|
||||
* @return a version of the original type with all primitive types replaced
|
||||
*/
|
||||
public MethodType wrap() {
|
||||
return hasPrimitives() ? wrapWithPrims(this) : this;
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
|
||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||
* Convert all wrapper types to their corresponding primitive types.
|
||||
* All primitive types (including {@code void}) will remain unchanged.
|
||||
* A return type of {@code java.lang.Void} is changed to {@code void}.
|
||||
* @return a version of the original type with all wrapper types replaced
|
||||
*/
|
||||
@ -391,6 +483,7 @@ class MethodType {
|
||||
|
||||
/**
|
||||
* Convenience method to present the arguments as an array.
|
||||
* Changes to the array will not result in changes to the type.
|
||||
* @return the parameter types (as a fresh copy if necessary)
|
||||
*/
|
||||
public Class<?>[] parameterArray() {
|
||||
@ -491,7 +584,7 @@ class MethodType {
|
||||
return form.parameterSlotCount();
|
||||
}
|
||||
|
||||
/** Number of JVM stack slots which carry all parameters after
|
||||
/** Number of JVM stack slots which carry all parameters including and after
|
||||
* the given position, which must be in the range of 0 to
|
||||
* {@code parameterCount} inclusive. Successive parameters are
|
||||
* more shallowly stacked, and parameters are indexed in the bytecodes
|
||||
@ -532,7 +625,7 @@ class MethodType {
|
||||
return form.returnSlotCount();
|
||||
}
|
||||
|
||||
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}.
|
||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||
* Find or create an instance (interned) of the given method type.
|
||||
* Any class or interface name embedded in the signature string
|
||||
* will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
|
||||
@ -544,16 +637,16 @@ class MethodType {
|
||||
* <p>
|
||||
* This method is included for the benfit of applications that must
|
||||
* generate bytecodes that process method handles and invokedynamic.
|
||||
* @param bytecodeSignature a bytecode-level signature string "(T...)T"
|
||||
* @param descriptor a bytecode-level signature string "(T...)T"
|
||||
* @param loader the class loader in which to look up the types
|
||||
* @return a method type matching the bytecode-level signature
|
||||
* @throws IllegalArgumentException if the string is not well-formed
|
||||
* @throws TypeNotPresentException if a named type cannot be found
|
||||
*/
|
||||
public static MethodType fromBytecodeString(String bytecodeSignature, ClassLoader loader)
|
||||
public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader)
|
||||
throws IllegalArgumentException, TypeNotPresentException
|
||||
{
|
||||
List<Class<?>> types = BytecodeSignature.parseMethod(bytecodeSignature, loader);
|
||||
List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
|
||||
Class<?> rtype = types.remove(types.size() - 1);
|
||||
Class<?>[] ptypes = types.toArray(NO_PTYPES);
|
||||
return makeImpl(rtype, ptypes, true);
|
||||
@ -565,11 +658,21 @@ class MethodType {
|
||||
* <p>
|
||||
* This method is included for the benfit of applications that must
|
||||
* generate bytecodes that process method handles and invokedynamic.
|
||||
* {@link #fromBytecodeString(java.lang.String, java.lang.ClassLoader)},
|
||||
* {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader)},
|
||||
* because the latter requires a suitable class loader argument.
|
||||
* @return the bytecode signature representation
|
||||
*/
|
||||
public String toMethodDescriptorString() {
|
||||
return BytecodeDescriptor.unparse(this);
|
||||
}
|
||||
|
||||
/** Temporary alias for toMethodDescriptorString; delete after M3. */
|
||||
public String toBytecodeString() {
|
||||
return BytecodeSignature.unparse(this);
|
||||
return toMethodDescriptorString();
|
||||
}
|
||||
/** Temporary alias for fromMethodDescriptorString; delete after M3. */
|
||||
public static MethodType fromBytecodeString(String descriptor, ClassLoader loader)
|
||||
throws IllegalArgumentException, TypeNotPresentException {
|
||||
return fromMethodDescriptorString(descriptor, loader);
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
||||
* This package contains dynamic language support provided directly by
|
||||
* the Java core class libraries and virtual machine.
|
||||
* @author John Rose, JSR 292 EG
|
||||
|
||||
@ -30,7 +30,7 @@ import sun.dyn.util.Wrapper;
|
||||
import java.dyn.*;
|
||||
import java.util.Arrays;
|
||||
import static sun.dyn.MethodHandleNatives.Constants.*;
|
||||
import static sun.dyn.MethodHandleImpl.newIllegalArgumentException;
|
||||
import static sun.dyn.MemberName.newIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* This method handle performs simple conversion or checking of a single argument.
|
||||
@ -302,7 +302,22 @@ public class AdapterMethodHandle extends BoundMethodHandle {
|
||||
*/
|
||||
private static int type2size(int type) {
|
||||
assert(type >= T_BOOLEAN && type <= T_OBJECT);
|
||||
return (type == T_FLOAT || type == T_DOUBLE) ? 2 : 1;
|
||||
return (type == T_LONG || type == T_DOUBLE) ? 2 : 1;
|
||||
}
|
||||
private static int type2size(Class<?> type) {
|
||||
return type2size(basicType(type));
|
||||
}
|
||||
|
||||
/** The given stackMove is the number of slots pushed.
|
||||
* It might be negative. Scale it (multiply) by the
|
||||
* VM's notion of how an address changes with a push,
|
||||
* to get the raw SP change for stackMove.
|
||||
* Then shift and mask it into the correct field.
|
||||
*/
|
||||
private static long insertStackMove(int stackMove) {
|
||||
// following variable must be long to avoid sign extension after '<<'
|
||||
long spChange = stackMove * MethodHandleNatives.JVM_STACK_MOVE_UNIT;
|
||||
return (spChange & CONV_STACK_MOVE_MASK) << CONV_STACK_MOVE_SHIFT;
|
||||
}
|
||||
|
||||
/** Construct an adapter conversion descriptor for a single-argument conversion. */
|
||||
@ -310,16 +325,16 @@ public class AdapterMethodHandle extends BoundMethodHandle {
|
||||
assert(src == (src & 0xF));
|
||||
assert(dest == (dest & 0xF));
|
||||
assert(convOp >= OP_CHECK_CAST && convOp <= OP_PRIM_TO_REF);
|
||||
long stackMove = type2size(dest) - type2size(src);
|
||||
int stackMove = type2size(dest) - type2size(src);
|
||||
return ((long) argnum << 32 |
|
||||
(long) convOp << CONV_OP_SHIFT |
|
||||
(int) src << CONV_SRC_TYPE_SHIFT |
|
||||
(int) dest << CONV_DEST_TYPE_SHIFT |
|
||||
stackMove << CONV_STACK_MOVE_SHIFT
|
||||
insertStackMove(stackMove)
|
||||
);
|
||||
}
|
||||
private static long makeConv(int convOp, int argnum, int stackMove) {
|
||||
assert(convOp >= OP_SWAP_ARGS && convOp <= OP_SPREAD_ARGS);
|
||||
assert(convOp >= OP_DUP_ARGS && convOp <= OP_SPREAD_ARGS);
|
||||
byte src = 0, dest = 0;
|
||||
if (convOp >= OP_COLLECT_ARGS && convOp <= OP_SPREAD_ARGS)
|
||||
src = dest = T_OBJECT;
|
||||
@ -327,12 +342,21 @@ public class AdapterMethodHandle extends BoundMethodHandle {
|
||||
(long) convOp << CONV_OP_SHIFT |
|
||||
(int) src << CONV_SRC_TYPE_SHIFT |
|
||||
(int) dest << CONV_DEST_TYPE_SHIFT |
|
||||
stackMove << CONV_STACK_MOVE_SHIFT
|
||||
insertStackMove(stackMove)
|
||||
);
|
||||
}
|
||||
private static long makeSwapConv(int convOp, int srcArg, byte type, int destSlot) {
|
||||
assert(convOp >= OP_SWAP_ARGS && convOp <= OP_ROT_ARGS);
|
||||
return ((long) srcArg << 32 |
|
||||
(long) convOp << CONV_OP_SHIFT |
|
||||
(int) type << CONV_SRC_TYPE_SHIFT |
|
||||
(int) type << CONV_DEST_TYPE_SHIFT |
|
||||
(int) destSlot << CONV_VMINFO_SHIFT
|
||||
);
|
||||
}
|
||||
private static long makeConv(int convOp) {
|
||||
assert(convOp == OP_RETYPE_ONLY);
|
||||
return (long) convOp << CONV_OP_SHIFT; // stackMove, src, dst, argnum all zero
|
||||
assert(convOp == OP_RETYPE_ONLY || convOp == OP_RETYPE_RAW);
|
||||
return ((long)-1 << 32) | (convOp << CONV_OP_SHIFT); // stackMove, src, dst all zero
|
||||
}
|
||||
private static int convCode(long conv) {
|
||||
return (int)conv;
|
||||
@ -348,16 +372,6 @@ public class AdapterMethodHandle extends BoundMethodHandle {
|
||||
/** One of OP_RETYPE_ONLY, etc. */
|
||||
int conversionOp() { return (conversion & CONV_OP_MASK) >> CONV_OP_SHIFT; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return addTypeString(this, "Adapted[" + basicToString(nonAdapter((MethodHandle)vmtarget)) + "]");
|
||||
}
|
||||
|
||||
private static MethodHandle nonAdapter(MethodHandle mh) {
|
||||
return (MethodHandle)
|
||||
MethodHandleNatives.getTarget(mh, ETF_DIRECT_HANDLE);
|
||||
}
|
||||
|
||||
/* Return one plus the position of the first non-trivial difference
|
||||
* between the given types. This is not a symmetric operation;
|
||||
* we are considering adapting the targetType to adapterType.
|
||||
@ -399,14 +413,14 @@ public class AdapterMethodHandle extends BoundMethodHandle {
|
||||
//if (false) return 1; // never adaptable!
|
||||
return -1; // some significant difference
|
||||
}
|
||||
private static int diffParamTypes(MethodType adapterType, int tstart,
|
||||
MethodType targetType, int astart,
|
||||
private static int diffParamTypes(MethodType adapterType, int astart,
|
||||
MethodType targetType, int tstart,
|
||||
int nargs, boolean raw) {
|
||||
assert(nargs >= 0);
|
||||
int res = 0;
|
||||
for (int i = 0; i < nargs; i++) {
|
||||
Class<?> src = adapterType.parameterType(tstart+i);
|
||||
Class<?> dest = targetType.parameterType(astart+i);
|
||||
Class<?> src = adapterType.parameterType(astart+i);
|
||||
Class<?> dest = targetType.parameterType(tstart+i);
|
||||
if ((!raw
|
||||
? VerifyType.canPassUnchecked(src, dest)
|
||||
: VerifyType.canPassRaw(src, dest)
|
||||
@ -422,7 +436,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
|
||||
|
||||
/** Can a retyping adapter (alone) validly convert the target to newType? */
|
||||
public static boolean canRetypeOnly(MethodType newType, MethodType targetType) {
|
||||
return canRetypeOnly(newType, targetType, false);
|
||||
return canRetype(newType, targetType, false);
|
||||
}
|
||||
/** Can a retyping adapter (alone) convert the target to newType?
|
||||
* It is allowed to widen subword types and void to int, to make bitwise
|
||||
@ -430,14 +444,14 @@ public class AdapterMethodHandle extends BoundMethodHandle {
|
||||
* reference conversions on return. This last feature requires that the
|
||||
* caller be trusted, and perform explicit cast conversions on return values.
|
||||
*/
|
||||
static boolean canRawRetypeOnly(MethodType newType, MethodType targetType) {
|
||||
return canRetypeOnly(newType, targetType, true);
|
||||
public static boolean canRetypeRaw(MethodType newType, MethodType targetType) {
|
||||
return canRetype(newType, targetType, true);
|
||||
}
|
||||
static boolean canRetypeOnly(MethodType newType, MethodType targetType, boolean raw) {
|
||||
if (!convOpSupported(OP_RETYPE_ONLY)) return false;
|
||||
static boolean canRetype(MethodType newType, MethodType targetType, boolean raw) {
|
||||
if (!convOpSupported(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY)) return false;
|
||||
int diff = diffTypes(newType, targetType, raw);
|
||||
// %%% This assert is too strong. Factor diff into VerifyType and reconcile.
|
||||
assert((diff == 0) == VerifyType.isNullConversion(newType, targetType));
|
||||
assert(raw || (diff == 0) == VerifyType.isNullConversion(newType, targetType));
|
||||
return diff == 0;
|
||||
}
|
||||
|
||||
@ -447,19 +461,21 @@ public class AdapterMethodHandle extends BoundMethodHandle {
|
||||
*/
|
||||
public static MethodHandle makeRetypeOnly(Access token,
|
||||
MethodType newType, MethodHandle target) {
|
||||
return makeRetypeOnly(token, newType, target, false);
|
||||
return makeRetype(token, newType, target, false);
|
||||
}
|
||||
public static MethodHandle makeRawRetypeOnly(Access token,
|
||||
public static MethodHandle makeRetypeRaw(Access token,
|
||||
MethodType newType, MethodHandle target) {
|
||||
return makeRetypeOnly(token, newType, target, true);
|
||||
return makeRetype(token, newType, target, true);
|
||||
}
|
||||
static MethodHandle makeRetypeOnly(Access token,
|
||||
static MethodHandle makeRetype(Access token,
|
||||
MethodType newType, MethodHandle target, boolean raw) {
|
||||
Access.check(token);
|
||||
if (!canRetypeOnly(newType, target.type(), raw))
|
||||
MethodType oldType = target.type();
|
||||
if (oldType == newType) return target;
|
||||
if (!canRetype(newType, oldType, raw))
|
||||
return null;
|
||||
// TO DO: clone the target guy, whatever he is, with new type.
|
||||
return new AdapterMethodHandle(target, newType, makeConv(OP_RETYPE_ONLY));
|
||||
return new AdapterMethodHandle(target, newType, makeConv(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY));
|
||||
}
|
||||
|
||||
/** Can a checkcast adapter validly convert the target to newType?
|
||||
@ -492,7 +508,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
|
||||
Access.check(token);
|
||||
if (!canCheckCast(newType, target.type(), arg, castType))
|
||||
return null;
|
||||
long conv = makeConv(OP_CHECK_CAST, arg, 0);
|
||||
long conv = makeConv(OP_CHECK_CAST, arg, T_OBJECT, T_OBJECT);
|
||||
return new AdapterMethodHandle(target, newType, conv, castType);
|
||||
}
|
||||
|
||||
@ -537,10 +553,9 @@ public class AdapterMethodHandle extends BoundMethodHandle {
|
||||
int arg, Class<?> convType) {
|
||||
Access.check(token);
|
||||
MethodType oldType = target.type();
|
||||
Class<?> src = newType.parameterType(arg);
|
||||
Class<?> dst = oldType.parameterType(arg);
|
||||
if (!canPrimCast(newType, oldType, arg, convType))
|
||||
return null;
|
||||
Class<?> src = newType.parameterType(arg);
|
||||
long conv = makeConv(OP_PRIM_TO_PRIM, arg, basicType(src), basicType(convType));
|
||||
return new AdapterMethodHandle(target, newType, conv);
|
||||
}
|
||||
@ -607,8 +622,6 @@ public class AdapterMethodHandle extends BoundMethodHandle {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TO DO: makeSwapArguments, makeRotateArguments, makeDuplicateArguments
|
||||
|
||||
/** Can an adapter simply drop arguments to convert the target to newType? */
|
||||
public static boolean canDropArguments(MethodType newType, MethodType targetType,
|
||||
int dropArgPos, int dropArgCount) {
|
||||
@ -643,26 +656,195 @@ public class AdapterMethodHandle extends BoundMethodHandle {
|
||||
Access.check(token);
|
||||
if (dropArgCount == 0)
|
||||
return makeRetypeOnly(IMPL_TOKEN, newType, target);
|
||||
MethodType mt = target.type();
|
||||
int argCount = mt.parameterCount();
|
||||
if (!canDropArguments(newType, mt, dropArgPos, dropArgCount))
|
||||
if (!canDropArguments(newType, target.type(), dropArgPos, dropArgCount))
|
||||
return null;
|
||||
int dropSlotCount, dropSlotPos;
|
||||
if (dropArgCount >= argCount) {
|
||||
assert(dropArgPos == argCount-1);
|
||||
dropSlotPos = 0;
|
||||
dropSlotCount = mt.parameterSlotCount();
|
||||
// in arglist: [0: ...keep1 | dpos: drop... | dpos+dcount: keep2... ]
|
||||
// out arglist: [0: ...keep1 | dpos: keep2... ]
|
||||
int keep2InPos = dropArgPos + dropArgCount;
|
||||
int dropSlot = newType.parameterSlotDepth(keep2InPos);
|
||||
int keep1InSlot = newType.parameterSlotDepth(dropArgPos);
|
||||
int slotCount = keep1InSlot - dropSlot;
|
||||
assert(slotCount >= dropArgCount);
|
||||
assert(target.type().parameterSlotCount() + slotCount == newType.parameterSlotCount());
|
||||
long conv = makeConv(OP_DROP_ARGS, dropArgPos + dropArgCount - 1, -slotCount);
|
||||
return new AdapterMethodHandle(target, newType, conv);
|
||||
}
|
||||
|
||||
/** Can an adapter duplicate an argument to convert the target to newType? */
|
||||
public static boolean canDupArguments(MethodType newType, MethodType targetType,
|
||||
int dupArgPos, int dupArgCount) {
|
||||
if (!convOpSupported(OP_DUP_ARGS)) return false;
|
||||
if (diffReturnTypes(newType, targetType, false) != 0)
|
||||
return false;
|
||||
int nptypes = newType.parameterCount();
|
||||
if (dupArgCount < 0 || dupArgPos + dupArgCount > nptypes)
|
||||
return false;
|
||||
if (targetType.parameterCount() != nptypes + dupArgCount)
|
||||
return false;
|
||||
// parameter types must be the same up to the duplicated arguments
|
||||
if (diffParamTypes(newType, 0, targetType, 0, nptypes, false) != 0)
|
||||
return false;
|
||||
// duplicated types must be, well, duplicates
|
||||
if (diffParamTypes(newType, dupArgPos, targetType, nptypes, dupArgCount, false) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Factory method: Duplicate the selected argument.
|
||||
* Return null if this is not possible.
|
||||
*/
|
||||
public static MethodHandle makeDupArguments(Access token,
|
||||
MethodType newType, MethodHandle target,
|
||||
int dupArgPos, int dupArgCount) {
|
||||
Access.check(token);
|
||||
if (!canDupArguments(newType, target.type(), dupArgPos, dupArgCount))
|
||||
return null;
|
||||
if (dupArgCount == 0)
|
||||
return target;
|
||||
// in arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... ]
|
||||
// out arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... | dup... ]
|
||||
int keep2InPos = dupArgPos + dupArgCount;
|
||||
int dupSlot = newType.parameterSlotDepth(keep2InPos);
|
||||
int keep1InSlot = newType.parameterSlotDepth(dupArgPos);
|
||||
int slotCount = keep1InSlot - dupSlot;
|
||||
assert(target.type().parameterSlotCount() - slotCount == newType.parameterSlotCount());
|
||||
long conv = makeConv(OP_DUP_ARGS, dupArgPos + dupArgCount - 1, slotCount);
|
||||
return new AdapterMethodHandle(target, newType, conv);
|
||||
}
|
||||
|
||||
/** Can an adapter swap two arguments to convert the target to newType? */
|
||||
public static boolean canSwapArguments(MethodType newType, MethodType targetType,
|
||||
int swapArg1, int swapArg2) {
|
||||
if (!convOpSupported(OP_SWAP_ARGS)) return false;
|
||||
if (diffReturnTypes(newType, targetType, false) != 0)
|
||||
return false;
|
||||
if (swapArg1 >= swapArg2) return false; // caller resp
|
||||
int nptypes = newType.parameterCount();
|
||||
if (targetType.parameterCount() != nptypes)
|
||||
return false;
|
||||
if (swapArg1 < 0 || swapArg2 >= nptypes)
|
||||
return false;
|
||||
if (diffParamTypes(newType, 0, targetType, 0, swapArg1, false) != 0)
|
||||
return false;
|
||||
if (diffParamTypes(newType, swapArg1, targetType, swapArg2, 1, false) != 0)
|
||||
return false;
|
||||
if (diffParamTypes(newType, swapArg1+1, targetType, swapArg1+1, swapArg2-swapArg1-1, false) != 0)
|
||||
return false;
|
||||
if (diffParamTypes(newType, swapArg2, targetType, swapArg1, 1, false) != 0)
|
||||
return false;
|
||||
if (diffParamTypes(newType, swapArg2+1, targetType, swapArg2+1, nptypes-swapArg2-1, false) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Factory method: Swap the selected arguments.
|
||||
* Return null if this is not possible.
|
||||
*/
|
||||
public static MethodHandle makeSwapArguments(Access token,
|
||||
MethodType newType, MethodHandle target,
|
||||
int swapArg1, int swapArg2) {
|
||||
Access.check(token);
|
||||
if (swapArg1 == swapArg2)
|
||||
return target;
|
||||
if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; }
|
||||
if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2))
|
||||
return null;
|
||||
Class<?> swapType = newType.parameterType(swapArg1);
|
||||
// in arglist: [0: ...keep1 | pos1: a1 | pos1+1: keep2... | pos2: a2 | pos2+1: keep3... ]
|
||||
// out arglist: [0: ...keep1 | pos1: a2 | pos1+1: keep2... | pos2: a1 | pos2+1: keep3... ]
|
||||
int swapSlot2 = newType.parameterSlotDepth(swapArg2 + 1);
|
||||
long conv = makeSwapConv(OP_SWAP_ARGS, swapArg1, basicType(swapType), swapSlot2);
|
||||
return new AdapterMethodHandle(target, newType, conv);
|
||||
}
|
||||
|
||||
static int positiveRotation(int argCount, int rotateBy) {
|
||||
assert(argCount > 0);
|
||||
if (rotateBy >= 0) {
|
||||
if (rotateBy < argCount)
|
||||
return rotateBy;
|
||||
return rotateBy % argCount;
|
||||
} else if (rotateBy >= -argCount) {
|
||||
return rotateBy + argCount;
|
||||
} else {
|
||||
// arglist: [0: keep... | dpos: drop... | dpos+dcount: keep... ]
|
||||
int lastDroppedArg = dropArgPos + dropArgCount - 1;
|
||||
int lastKeptArg = dropArgPos - 1; // might be -1, which is OK
|
||||
dropSlotPos = mt.parameterSlotDepth(1+lastDroppedArg);
|
||||
int lastKeptSlot = mt.parameterSlotDepth(1+lastKeptArg);
|
||||
dropSlotCount = lastKeptSlot - dropSlotPos;
|
||||
assert(dropSlotCount >= dropArgCount);
|
||||
return (-1-((-1-rotateBy) % argCount)) + argCount;
|
||||
}
|
||||
long conv = makeConv(OP_DROP_ARGS, dropArgPos, +dropSlotCount);
|
||||
return new AdapterMethodHandle(target, newType, dropSlotCount, conv);
|
||||
}
|
||||
|
||||
final static int MAX_ARG_ROTATION = 1;
|
||||
|
||||
/** Can an adapter rotate arguments to convert the target to newType? */
|
||||
public static boolean canRotateArguments(MethodType newType, MethodType targetType,
|
||||
int firstArg, int argCount, int rotateBy) {
|
||||
if (!convOpSupported(OP_ROT_ARGS)) return false;
|
||||
if (argCount <= 2) return false; // must be a swap, not a rotate
|
||||
rotateBy = positiveRotation(argCount, rotateBy);
|
||||
if (rotateBy == 0) return false; // no rotation
|
||||
if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION)
|
||||
return false; // too many argument positions
|
||||
// Rotate incoming args right N to the out args, N in 1..(argCouunt-1).
|
||||
if (diffReturnTypes(newType, targetType, false) != 0)
|
||||
return false;
|
||||
int nptypes = newType.parameterCount();
|
||||
if (targetType.parameterCount() != nptypes)
|
||||
return false;
|
||||
if (firstArg < 0 || firstArg >= nptypes) return false;
|
||||
int argLimit = firstArg + argCount;
|
||||
if (argLimit > nptypes) return false;
|
||||
if (diffParamTypes(newType, 0, targetType, 0, firstArg, false) != 0)
|
||||
return false;
|
||||
int newChunk1 = argCount - rotateBy, newChunk2 = rotateBy;
|
||||
// swap new chunk1 with target chunk2
|
||||
if (diffParamTypes(newType, firstArg, targetType, argLimit-newChunk1, newChunk1, false) != 0)
|
||||
return false;
|
||||
// swap new chunk2 with target chunk1
|
||||
if (diffParamTypes(newType, firstArg+newChunk1, targetType, firstArg, newChunk2, false) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Factory method: Rotate the selected argument range.
|
||||
* Return null if this is not possible.
|
||||
*/
|
||||
public static MethodHandle makeRotateArguments(Access token,
|
||||
MethodType newType, MethodHandle target,
|
||||
int firstArg, int argCount, int rotateBy) {
|
||||
Access.check(token);
|
||||
rotateBy = positiveRotation(argCount, rotateBy);
|
||||
if (!canRotateArguments(newType, target.type(), firstArg, argCount, rotateBy))
|
||||
return null;
|
||||
// Decide whether it should be done as a right or left rotation,
|
||||
// on the JVM stack. Return the number of stack slots to rotate by,
|
||||
// positive if right, negative if left.
|
||||
int limit = firstArg + argCount;
|
||||
int depth0 = newType.parameterSlotDepth(firstArg);
|
||||
int depth1 = newType.parameterSlotDepth(limit-rotateBy);
|
||||
int depth2 = newType.parameterSlotDepth(limit);
|
||||
int chunk1Slots = depth0 - depth1; assert(chunk1Slots > 0);
|
||||
int chunk2Slots = depth1 - depth2; assert(chunk2Slots > 0);
|
||||
// From here on out, it assumes a single-argument shift.
|
||||
assert(MAX_ARG_ROTATION == 1);
|
||||
int srcArg, dstArg;
|
||||
byte basicType;
|
||||
if (chunk2Slots <= chunk1Slots) {
|
||||
// Rotate right/down N (rotateBy = +N, N small, c2 small):
|
||||
// in arglist: [0: ...keep1 | arg1: c1... | limit-N: c2 | limit: keep2... ]
|
||||
// out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1... | limit: keep2... ]
|
||||
srcArg = limit-1;
|
||||
dstArg = firstArg;
|
||||
basicType = basicType(newType.parameterType(srcArg));
|
||||
assert(chunk2Slots == type2size(basicType));
|
||||
} else {
|
||||
// Rotate left/up N (rotateBy = -N, N small, c1 small):
|
||||
// in arglist: [0: ...keep1 | arg1: c1 | arg1+N: c2... | limit: keep2... ]
|
||||
// out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ]
|
||||
srcArg = firstArg;
|
||||
dstArg = limit-1;
|
||||
basicType = basicType(newType.parameterType(srcArg));
|
||||
assert(chunk1Slots == type2size(basicType));
|
||||
}
|
||||
int dstSlot = newType.parameterSlotDepth(dstArg + 1);
|
||||
long conv = makeSwapConv(OP_ROT_ARGS, srcArg, basicType, dstSlot);
|
||||
return new AdapterMethodHandle(target, newType, conv);
|
||||
}
|
||||
|
||||
/** Can an adapter spread an argument to convert the target to newType? */
|
||||
@ -676,10 +858,10 @@ public class AdapterMethodHandle extends BoundMethodHandle {
|
||||
if (spreadArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, spreadArgPos, false) != 0)
|
||||
return false;
|
||||
int afterPos = spreadArgPos + spreadArgCount;
|
||||
int afterCount = nptypes - afterPos;
|
||||
int afterCount = nptypes - (spreadArgPos + 1);
|
||||
if (spreadArgPos < 0 || spreadArgPos >= nptypes ||
|
||||
spreadArgCount < 0 ||
|
||||
targetType.parameterCount() != nptypes - 1 + spreadArgCount)
|
||||
targetType.parameterCount() != afterPos + afterCount)
|
||||
return false;
|
||||
// parameter types after the spread point must also be the same
|
||||
if (afterCount != 0 && diffParamTypes(newType, spreadArgPos+1, targetType, afterPos, afterCount, false) != 0)
|
||||
@ -697,32 +879,40 @@ public class AdapterMethodHandle extends BoundMethodHandle {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Factory method: Spread selected argument. */
|
||||
public static MethodHandle makeSpreadArguments(Access token,
|
||||
MethodType newType, MethodHandle target,
|
||||
Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
|
||||
Access.check(token);
|
||||
MethodType mt = target.type();
|
||||
int argCount = mt.parameterCount();
|
||||
if (!canSpreadArguments(newType, mt, spreadArgType, spreadArgPos, spreadArgCount))
|
||||
MethodType targetType = target.type();
|
||||
if (!canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount))
|
||||
return null;
|
||||
int spreadSlotCount, spreadSlotPos;
|
||||
if (spreadArgCount >= argCount) {
|
||||
assert(spreadArgPos == argCount-1);
|
||||
spreadSlotPos = 0;
|
||||
spreadSlotCount = mt.parameterSlotCount();
|
||||
} else {
|
||||
// arglist: [0: keep... | dpos: spread... | dpos+dcount: keep... ]
|
||||
int lastSpreadArg = spreadArgPos + spreadArgCount - 1;
|
||||
int lastKeptArg = spreadArgPos - 1; // might be -1, which is OK
|
||||
spreadSlotPos = mt.parameterSlotDepth(1+lastSpreadArg);
|
||||
int lastKeptSlot = mt.parameterSlotDepth(1+lastKeptArg);
|
||||
spreadSlotCount = lastKeptSlot - spreadSlotPos;
|
||||
assert(spreadSlotCount >= spreadArgCount);
|
||||
}
|
||||
long conv = makeConv(OP_SPREAD_ARGS, spreadArgPos, spreadSlotCount);
|
||||
return new AdapterMethodHandle(target, newType, conv, spreadArgType);
|
||||
// in arglist: [0: ...keep1 | spos: spreadArg | spos+1: keep2... ]
|
||||
// out arglist: [0: ...keep1 | spos: spread... | spos+scount: keep2... ]
|
||||
int keep2OutPos = spreadArgPos + spreadArgCount;
|
||||
int spreadSlot = targetType.parameterSlotDepth(keep2OutPos);
|
||||
int keep1OutSlot = targetType.parameterSlotDepth(spreadArgPos);
|
||||
int slotCount = keep1OutSlot - spreadSlot;
|
||||
assert(spreadSlot == newType.parameterSlotDepth(spreadArgPos+1));
|
||||
assert(slotCount >= spreadArgCount);
|
||||
long conv = makeConv(OP_SPREAD_ARGS, spreadArgPos, slotCount-1);
|
||||
MethodHandle res = new AdapterMethodHandle(target, newType, conv, spreadArgType);
|
||||
assert(res.type().parameterType(spreadArgPos) == spreadArgType);
|
||||
return res;
|
||||
}
|
||||
|
||||
// TO DO: makeCollectArguments, makeFlyby, makeRicochet
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return nonAdapter((MethodHandle)vmtarget).toString();
|
||||
}
|
||||
|
||||
private static MethodHandle nonAdapter(MethodHandle mh) {
|
||||
while (mh instanceof AdapterMethodHandle) {
|
||||
mh = (MethodHandle) mh.vmtarget;
|
||||
}
|
||||
return mh;
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +28,10 @@ package sun.dyn;
|
||||
import sun.dyn.util.VerifyType;
|
||||
import sun.dyn.util.Wrapper;
|
||||
import java.dyn.*;
|
||||
import java.util.List;
|
||||
import sun.dyn.MethodHandleNatives.Constants;
|
||||
import static sun.dyn.MethodHandleImpl.IMPL_LOOKUP;
|
||||
import static sun.dyn.MemberName.newIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* The flavor of method handle which emulates an invoke instruction
|
||||
@ -35,18 +39,23 @@ import java.dyn.*;
|
||||
* when the handle is created, not when it is invoked.
|
||||
* @author jrose
|
||||
*/
|
||||
public class BoundMethodHandle extends MethodHandle {
|
||||
public class BoundMethodHandle extends MethodHandle {
|
||||
//MethodHandle vmtarget; // next BMH or final DMH or methodOop
|
||||
private final Object argument; // argument to insert
|
||||
private final int vmargslot; // position at which it is inserted
|
||||
|
||||
private static final Access IMPL_TOKEN = Access.getToken();
|
||||
private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN);
|
||||
|
||||
// Constructors in this class *must* be package scoped or private.
|
||||
// Exception: JavaMethodHandle constructors are protected.
|
||||
// (The link between JMH and BMH is temporary.)
|
||||
|
||||
/** Bind a direct MH to its receiver (or first ref. argument).
|
||||
* The JVM will pre-dispatch the MH if it is not already static.
|
||||
*/
|
||||
BoundMethodHandle(DirectMethodHandle mh, Object argument) {
|
||||
super(Access.TOKEN, mh.type().dropParameterType(0));
|
||||
super(Access.TOKEN, mh.type().dropParameterTypes(0, 1));
|
||||
// check the type now, once for all:
|
||||
this.argument = checkReferenceArgument(argument, mh, 0);
|
||||
this.vmargslot = this.type().parameterSlotCount();
|
||||
@ -56,32 +65,34 @@ public class BoundMethodHandle extends MethodHandle {
|
||||
} else {
|
||||
this.vmtarget = mh;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int REF_ARG = 0, PRIM_ARG = 1, SELF_ARG = 2;
|
||||
}
|
||||
|
||||
/** Insert an argument into an arbitrary method handle.
|
||||
* If argnum is zero, inserts the first argument, etc.
|
||||
* The argument type must be a reference.
|
||||
*/
|
||||
BoundMethodHandle(MethodHandle mh, Object argument, int argnum) {
|
||||
this(mh, argument, argnum, mh.type().parameterType(argnum).isPrimitive() ? PRIM_ARG : REF_ARG);
|
||||
this(mh.type().dropParameterTypes(argnum, argnum+1),
|
||||
mh, argument, argnum);
|
||||
}
|
||||
|
||||
/** Insert an argument into an arbitrary method handle.
|
||||
* If argnum is zero, inserts the first argument, etc.
|
||||
*/
|
||||
BoundMethodHandle(MethodHandle mh, Object argument, int argnum, int whichArg) {
|
||||
super(Access.TOKEN, mh.type().dropParameterType(argnum));
|
||||
if (whichArg == PRIM_ARG)
|
||||
BoundMethodHandle(MethodType type, MethodHandle mh, Object argument, int argnum) {
|
||||
super(Access.TOKEN, type);
|
||||
if (mh.type().parameterType(argnum).isPrimitive())
|
||||
this.argument = bindPrimitiveArgument(argument, mh, argnum);
|
||||
else {
|
||||
if (whichArg == SELF_ARG) argument = this;
|
||||
this.argument = checkReferenceArgument(argument, mh, argnum);
|
||||
}
|
||||
this.vmargslot = this.type().parameterSlotDepth(argnum);
|
||||
this.vmargslot = type.parameterSlotDepth(argnum);
|
||||
initTarget(mh, argnum);
|
||||
}
|
||||
|
||||
private void initTarget(MethodHandle mh, int argnum) {
|
||||
if (MethodHandleNatives.JVM_SUPPORT) {
|
||||
this.vmtarget = null; // maybe updated by JVM
|
||||
this.vmtarget = null; // maybe updated by JVM
|
||||
MethodHandleNatives.init(this, mh, argnum);
|
||||
} else {
|
||||
this.vmtarget = mh;
|
||||
@ -97,29 +108,65 @@ public class BoundMethodHandle extends MethodHandle {
|
||||
assert(this.getClass() == AdapterMethodHandle.class);
|
||||
}
|
||||
|
||||
/** Initialize the current object as a method handle, binding it
|
||||
* as the {@code argnum}th argument of the method handle {@code entryPoint}.
|
||||
* The invocation type of the resulting method handle will be the
|
||||
* same as {@code entryPoint}, except that the {@code argnum}th argument
|
||||
* type will be dropped.
|
||||
*/
|
||||
public BoundMethodHandle(MethodHandle entryPoint, int argnum) {
|
||||
this(entryPoint, null, argnum, SELF_ARG);
|
||||
|
||||
// Note: If the conversion fails, perhaps because of a bad entryPoint,
|
||||
// the MethodHandle.type field will not be filled in, and therefore
|
||||
// no MH.invoke call will ever succeed. The caller may retain a pointer
|
||||
// to the broken method handle, but no harm can be done with it.
|
||||
}
|
||||
|
||||
/** Initialize the current object as a method handle, binding it
|
||||
/** Initialize the current object as a Java method handle, binding it
|
||||
* as the first argument of the method handle {@code entryPoint}.
|
||||
* The invocation type of the resulting method handle will be the
|
||||
* same as {@code entryPoint}, except that the first argument
|
||||
* type will be dropped.
|
||||
*/
|
||||
public BoundMethodHandle(MethodHandle entryPoint) {
|
||||
this(entryPoint, null, 0, SELF_ARG);
|
||||
protected BoundMethodHandle(MethodHandle entryPoint) {
|
||||
super(Access.TOKEN, entryPoint.type().dropParameterTypes(0, 1));
|
||||
this.argument = this; // kludge; get rid of
|
||||
this.vmargslot = this.type().parameterSlotDepth(0);
|
||||
initTarget(entryPoint, 0);
|
||||
assert(this instanceof JavaMethodHandle);
|
||||
}
|
||||
|
||||
/** Initialize the current object as a Java method handle.
|
||||
*/
|
||||
protected BoundMethodHandle(String entryPointName, MethodType type, boolean matchArity) {
|
||||
super(Access.TOKEN, null);
|
||||
MethodHandle entryPoint
|
||||
= findJavaMethodHandleEntryPoint(this.getClass(),
|
||||
entryPointName, type, matchArity);
|
||||
MethodHandleImpl.initType(this, entryPoint.type().dropParameterTypes(0, 1));
|
||||
this.argument = this; // kludge; get rid of
|
||||
this.vmargslot = this.type().parameterSlotDepth(0);
|
||||
initTarget(entryPoint, 0);
|
||||
assert(this instanceof JavaMethodHandle);
|
||||
}
|
||||
|
||||
private static
|
||||
MethodHandle findJavaMethodHandleEntryPoint(Class<?> caller,
|
||||
String name,
|
||||
MethodType type,
|
||||
boolean matchArity) {
|
||||
if (matchArity) type.getClass(); // elicit NPE
|
||||
List<MemberName> methods = IMPL_NAMES.getMethods(caller, true, name, null, caller);
|
||||
MethodType foundType = null;
|
||||
MemberName foundMethod = null;
|
||||
for (MemberName method : methods) {
|
||||
MethodType mtype = method.getMethodType();
|
||||
if (type != null && type.parameterCount() != mtype.parameterCount())
|
||||
continue;
|
||||
else if (foundType == null)
|
||||
foundType = mtype;
|
||||
else if (foundType != mtype)
|
||||
throw newIllegalArgumentException("more than one method named "+name+" in "+caller.getName());
|
||||
// discard overrides
|
||||
if (foundMethod == null)
|
||||
foundMethod = method;
|
||||
else if (foundMethod.getDeclaringClass().isAssignableFrom(method.getDeclaringClass()))
|
||||
foundMethod = method;
|
||||
}
|
||||
if (foundMethod == null)
|
||||
throw newIllegalArgumentException("no method named "+name+" in "+caller.getName());
|
||||
MethodHandle entryPoint = MethodHandleImpl.findMethod(IMPL_TOKEN, foundMethod, true, caller);
|
||||
if (type != null) {
|
||||
MethodType epType = type.insertParameterTypes(0, entryPoint.type().parameterType(0));
|
||||
entryPoint = MethodHandles.convertArguments(entryPoint, epType);
|
||||
}
|
||||
return entryPoint;
|
||||
}
|
||||
|
||||
/** Make sure the given {@code argument} can be used as {@code argnum}-th
|
||||
@ -175,6 +222,24 @@ public class BoundMethodHandle extends MethodHandle {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Bound[" + super.toString() + "]";
|
||||
MethodHandle mh = this;
|
||||
while (mh instanceof BoundMethodHandle) {
|
||||
Object info = MethodHandleNatives.getTargetInfo(mh);
|
||||
if (info instanceof MethodHandle) {
|
||||
mh = (MethodHandle) info;
|
||||
} else {
|
||||
String name = null;
|
||||
if (info instanceof MemberName)
|
||||
name = ((MemberName)info).getName();
|
||||
if (name != null)
|
||||
return name;
|
||||
else
|
||||
return super.toString(); // <unknown>, probably
|
||||
}
|
||||
assert(mh != this);
|
||||
if (mh instanceof JavaMethodHandle)
|
||||
break; // access JMH.toString(), not BMH.toString()
|
||||
}
|
||||
return mh.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,34 +26,51 @@
|
||||
package sun.dyn;
|
||||
|
||||
import java.dyn.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* The CallSite privately created by the JVM at every invokedynamic instruction.
|
||||
* Parts of CallSite known to the JVM.
|
||||
* FIXME: Merge all this into CallSite proper.
|
||||
* @author jrose
|
||||
*/
|
||||
class CallSiteImpl extends CallSite {
|
||||
// Fields used only by the JVM. Do not use or change.
|
||||
public class CallSiteImpl {
|
||||
// Field used only by the JVM. Do not use or change.
|
||||
private Object vmmethod;
|
||||
|
||||
// Values supplied by the JVM:
|
||||
int callerMID, callerBCI;
|
||||
protected int callerMID, callerBCI;
|
||||
|
||||
private CallSiteImpl(Class<?> caller, String name, MethodType type) {
|
||||
super(caller, name, type);
|
||||
private MethodHandle target;
|
||||
protected final Object caller; // usually a class
|
||||
protected final String name;
|
||||
protected final MethodType type;
|
||||
|
||||
/** called only directly from CallSite() */
|
||||
protected CallSiteImpl(Access token, Object caller, String name, MethodType type) {
|
||||
Access.check(token);
|
||||
this.caller = caller;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTarget(MethodHandle mh) {
|
||||
checkTarget(mh);
|
||||
if (MethodHandleNatives.JVM_SUPPORT)
|
||||
MethodHandleNatives.linkCallSite(this, (MethodHandle) mh);
|
||||
else
|
||||
super.setTarget(mh);
|
||||
/** native version of setTarget */
|
||||
protected void setTarget(MethodHandle mh) {
|
||||
//System.out.println("setTarget "+this+" := "+mh);
|
||||
// XXX I don't know how to fix this properly.
|
||||
// if (false && MethodHandleNatives.JVM_SUPPORT) // FIXME: enable this
|
||||
// MethodHandleNatives.linkCallSite(this, mh);
|
||||
// else
|
||||
this.target = mh;
|
||||
}
|
||||
|
||||
protected MethodHandle getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE =
|
||||
MethodHandleImpl.IMPL_LOOKUP.findStatic(CallSite.class, "privateInitializeCallSite",
|
||||
MethodType.make(void.class, CallSite.class, int.class, int.class));
|
||||
MethodType.methodType(void.class, CallSite.class, int.class, int.class));
|
||||
|
||||
// this is the up-call from the JVM:
|
||||
static CallSite makeSite(Class<?> caller, String name, MethodType type,
|
||||
@ -61,10 +78,25 @@ class CallSiteImpl extends CallSite {
|
||||
MethodHandle bsm = Linkage.getBootstrapMethod(caller);
|
||||
if (bsm == null)
|
||||
throw new InvokeDynamicBootstrapError("class has no bootstrap method: "+caller);
|
||||
CallSite site = bsm.<CallSite>invoke(caller, name, type);
|
||||
CallSite site;
|
||||
try {
|
||||
site = bsm.<CallSite>invoke(caller, name, type);
|
||||
} catch (Throwable ex) {
|
||||
throw new InvokeDynamicBootstrapError("exception thrown while linking", ex);
|
||||
}
|
||||
if (site == null)
|
||||
throw new InvokeDynamicBootstrapError("class bootstrap method failed to create a call site: "+caller);
|
||||
PRIVATE_INITIALIZE_CALL_SITE.<void>invoke(site, callerMID, callerBCI);
|
||||
if (site.type() != type)
|
||||
throw new InvokeDynamicBootstrapError("call site type not initialized correctly: "+site);
|
||||
if (site.callerClass() != caller)
|
||||
throw new InvokeDynamicBootstrapError("call site caller not initialized correctly: "+site);
|
||||
if ((Object)site.name() != name)
|
||||
throw new InvokeDynamicBootstrapError("call site name not initialized correctly: "+site);
|
||||
try {
|
||||
PRIVATE_INITIALIZE_CALL_SITE.<void>invoke(site, callerMID, callerBCI);
|
||||
} catch (Throwable ex) {
|
||||
throw new InvokeDynamicBootstrapError("call site initialization exception", ex);
|
||||
}
|
||||
return site;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,6 @@ package sun.dyn;
|
||||
|
||||
import java.dyn.JavaMethodHandle;
|
||||
import java.dyn.MethodHandle;
|
||||
import java.dyn.MethodHandles;
|
||||
import java.dyn.MethodType;
|
||||
|
||||
/**
|
||||
@ -42,16 +41,21 @@ public class FilterOneArgument extends JavaMethodHandle {
|
||||
protected final MethodHandle filter; // Object -> Object
|
||||
protected final MethodHandle target; // Object -> Object
|
||||
|
||||
protected Object entryPoint(Object argument) {
|
||||
Object filteredArgument = filter.<Object>invoke(argument);
|
||||
return target.<Object>invoke(filteredArgument);
|
||||
@Override
|
||||
public String toString() {
|
||||
return target.toString();
|
||||
}
|
||||
|
||||
private static final MethodHandle entryPoint =
|
||||
MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "entryPoint", MethodType.makeGeneric(1));
|
||||
protected Object invoke(Object argument) throws Throwable {
|
||||
Object filteredArgument = filter.invoke(argument);
|
||||
return target.invoke(filteredArgument);
|
||||
}
|
||||
|
||||
private static final MethodHandle INVOKE =
|
||||
MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "invoke", MethodType.genericMethodType(1));
|
||||
|
||||
protected FilterOneArgument(MethodHandle filter, MethodHandle target) {
|
||||
super(entryPoint);
|
||||
super(INVOKE);
|
||||
this.filter = filter;
|
||||
this.target = target;
|
||||
}
|
||||
@ -62,10 +66,6 @@ public class FilterOneArgument extends JavaMethodHandle {
|
||||
return new FilterOneArgument(filter, target);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return filter + "|>" + target;
|
||||
}
|
||||
|
||||
// MethodHandle make(MethodHandle filter1, MethodHandle filter2, MethodHandle target) {
|
||||
// MethodHandle filter = make(filter1, filter2);
|
||||
// return make(filter, target);
|
||||
|
||||
@ -36,8 +36,8 @@ import sun.dyn.util.ValueConversions;
|
||||
import sun.dyn.util.Wrapper;
|
||||
|
||||
/**
|
||||
* Adapters which mediate between incoming calls which are not generic
|
||||
* and outgoing calls which are. Any call can be represented generically
|
||||
* Adapters which mediate between incoming calls which are generic
|
||||
* and outgoing calls which are not. Any call can be represented generically
|
||||
* boxing up its arguments, and (on return) unboxing the return value.
|
||||
* <p>
|
||||
* A call is "generic" (in MethodHandle terms) if its MethodType features
|
||||
@ -50,9 +50,6 @@ import sun.dyn.util.Wrapper;
|
||||
* either binds internally or else takes as a leading argument).
|
||||
* (To stretch the term, adapter-like method handles may have multiple
|
||||
* targets or be polymorphic across multiple call types.)
|
||||
* <p>
|
||||
* This adapter can sometimes be more directly implemented
|
||||
* by the JVM's built-in OP_SPREAD_ARGS adapter.
|
||||
* @author jrose
|
||||
*/
|
||||
class FromGeneric {
|
||||
@ -99,7 +96,7 @@ class FromGeneric {
|
||||
}
|
||||
this.internalType = internalType0;
|
||||
this.adapter = ad;
|
||||
MethodType tepType = targetType.insertParameterType(0, adapter.getClass());
|
||||
MethodType tepType = targetType.insertParameterTypes(0, adapter.getClass());
|
||||
this.entryPoint = ad.prototypeEntryPoint();
|
||||
this.returnConversion = computeReturnConversion(targetType, internalType0);
|
||||
this.unboxingInvoker = computeUnboxingInvoker(targetType, internalType0);
|
||||
@ -146,7 +143,7 @@ class FromGeneric {
|
||||
if (fixArgs == null)
|
||||
throw new InternalError("bad fixArgs");
|
||||
// reinterpret the calling sequence as raw:
|
||||
MethodHandle retyper = AdapterMethodHandle.makeRawRetypeOnly(Access.TOKEN,
|
||||
MethodHandle retyper = AdapterMethodHandle.makeRetypeRaw(Access.TOKEN,
|
||||
Invokers.invokerType(internalType), fixArgs);
|
||||
if (retyper == null)
|
||||
throw new InternalError("bad retyper");
|
||||
@ -226,7 +223,10 @@ class FromGeneric {
|
||||
// Produce an instance configured as a prototype.
|
||||
return ctor.newInstance(entryPoint);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
} catch (InvocationTargetException ex) {
|
||||
} catch (InvocationTargetException wex) {
|
||||
Throwable ex = wex.getTargetException();
|
||||
if (ex instanceof Error) throw (Error)ex;
|
||||
if (ex instanceof RuntimeException) throw (RuntimeException)ex;
|
||||
} catch (InstantiationException ex) {
|
||||
} catch (IllegalAccessException ex) {
|
||||
}
|
||||
@ -260,6 +260,11 @@ class FromGeneric {
|
||||
protected final MethodHandle convert; // raw(R) => Object
|
||||
protected final MethodHandle target; // (any**N) => R
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return target.toString();
|
||||
}
|
||||
|
||||
protected boolean isPrototype() { return target == null; }
|
||||
protected Adapter(MethodHandle entryPoint) {
|
||||
this(entryPoint, null, entryPoint, null);
|
||||
@ -284,11 +289,11 @@ class FromGeneric {
|
||||
// { return new ThisType(entryPoint, convert, target); }
|
||||
|
||||
/// Conversions on the value returned from the target.
|
||||
protected Object convert_L(Object result) { return convert.<Object>invoke(result); }
|
||||
protected Object convert_I(int result) { return convert.<Object>invoke(result); }
|
||||
protected Object convert_J(long result) { return convert.<Object>invoke(result); }
|
||||
protected Object convert_F(float result) { return convert.<Object>invoke(result); }
|
||||
protected Object convert_D(double result) { return convert.<Object>invoke(result); }
|
||||
protected Object convert_L(Object result) throws Throwable { return convert.<Object>invoke(result); }
|
||||
protected Object convert_I(int result) throws Throwable { return convert.<Object>invoke(result); }
|
||||
protected Object convert_J(long result) throws Throwable { return convert.<Object>invoke(result); }
|
||||
protected Object convert_F(float result) throws Throwable { return convert.<Object>invoke(result); }
|
||||
protected Object convert_D(double result) throws Throwable { return convert.<Object>invoke(result); }
|
||||
|
||||
static private final String CLASS_PREFIX; // "sun.dyn.FromGeneric$"
|
||||
static {
|
||||
@ -317,11 +322,11 @@ class FromGeneric {
|
||||
{ super(e, i, c, t); }
|
||||
protected xA2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||
{ return new xA2(e, i, c, t); }
|
||||
protected Object invoke_L2(Object a0, Object a1) { return convert_L(invoker.<Object>invoke(target, a0, a1)); }
|
||||
protected Object invoke_I2(Object a0, Object a1) { return convert_I(invoker.<int >invoke(target, a0, a1)); }
|
||||
protected Object invoke_J2(Object a0, Object a1) { return convert_J(invoker.<long >invoke(target, a0, a1)); }
|
||||
protected Object invoke_F2(Object a0, Object a1) { return convert_F(invoker.<float >invoke(target, a0, a1)); }
|
||||
protected Object invoke_D2(Object a0, Object a1) { return convert_D(invoker.<double>invoke(target, a0, a1)); }
|
||||
protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L(invoker.<Object>invoke(target, a0, a1)); }
|
||||
protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I(invoker.<int >invoke(target, a0, a1)); }
|
||||
protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J(invoker.<long >invoke(target, a0, a1)); }
|
||||
protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F(invoker.<float >invoke(target, a0, a1)); }
|
||||
protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D(invoker.<double>invoke(target, a0, a1)); }
|
||||
}
|
||||
// */
|
||||
|
||||
@ -342,7 +347,7 @@ class genclasses {
|
||||
" protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)",
|
||||
" { return new @cat@(e, i, c, t); }",
|
||||
" //@each-R@",
|
||||
" protected Object invoke_@catN@(@Tvav@) { return convert_@Rc@(invoker.<@R@>invoke(target@av@)); }",
|
||||
" protected Object invoke_@catN@(@Tvav@) throws Throwable { return convert_@Rc@(invoker.<@R@>invoke(target@av@)); }",
|
||||
" //@end-R@",
|
||||
" }",
|
||||
} };
|
||||
@ -498,11 +503,11 @@ class genclasses {
|
||||
{ super(e, i, c, t); }
|
||||
protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||
{ return new A0(e, i, c, t); }
|
||||
protected Object invoke_L0() { return convert_L(invoker.<Object>invoke(target)); }
|
||||
protected Object invoke_I0() { return convert_I(invoker.<int >invoke(target)); }
|
||||
protected Object invoke_J0() { return convert_J(invoker.<long >invoke(target)); }
|
||||
protected Object invoke_F0() { return convert_F(invoker.<float >invoke(target)); }
|
||||
protected Object invoke_D0() { return convert_D(invoker.<double>invoke(target)); }
|
||||
protected Object invoke_L0() throws Throwable { return convert_L(invoker.<Object>invoke(target)); }
|
||||
protected Object invoke_I0() throws Throwable { return convert_I(invoker.<int >invoke(target)); }
|
||||
protected Object invoke_J0() throws Throwable { return convert_J(invoker.<long >invoke(target)); }
|
||||
protected Object invoke_F0() throws Throwable { return convert_F(invoker.<float >invoke(target)); }
|
||||
protected Object invoke_D0() throws Throwable { return convert_D(invoker.<double>invoke(target)); }
|
||||
}
|
||||
static class A1 extends Adapter {
|
||||
protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||
@ -510,11 +515,11 @@ class genclasses {
|
||||
{ super(e, i, c, t); }
|
||||
protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||
{ return new A1(e, i, c, t); }
|
||||
protected Object invoke_L1(Object a0) { return convert_L(invoker.<Object>invoke(target, a0)); }
|
||||
protected Object invoke_I1(Object a0) { return convert_I(invoker.<int >invoke(target, a0)); }
|
||||
protected Object invoke_J1(Object a0) { return convert_J(invoker.<long >invoke(target, a0)); }
|
||||
protected Object invoke_F1(Object a0) { return convert_F(invoker.<float >invoke(target, a0)); }
|
||||
protected Object invoke_D1(Object a0) { return convert_D(invoker.<double>invoke(target, a0)); }
|
||||
protected Object invoke_L1(Object a0) throws Throwable { return convert_L(invoker.<Object>invoke(target, a0)); }
|
||||
protected Object invoke_I1(Object a0) throws Throwable { return convert_I(invoker.<int >invoke(target, a0)); }
|
||||
protected Object invoke_J1(Object a0) throws Throwable { return convert_J(invoker.<long >invoke(target, a0)); }
|
||||
protected Object invoke_F1(Object a0) throws Throwable { return convert_F(invoker.<float >invoke(target, a0)); }
|
||||
protected Object invoke_D1(Object a0) throws Throwable { return convert_D(invoker.<double>invoke(target, a0)); }
|
||||
}
|
||||
static class A2 extends Adapter {
|
||||
protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||
@ -522,11 +527,11 @@ class genclasses {
|
||||
{ super(e, i, c, t); }
|
||||
protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||
{ return new A2(e, i, c, t); }
|
||||
protected Object invoke_L2(Object a0, Object a1) { return convert_L(invoker.<Object>invoke(target, a0, a1)); }
|
||||
protected Object invoke_I2(Object a0, Object a1) { return convert_I(invoker.<int >invoke(target, a0, a1)); }
|
||||
protected Object invoke_J2(Object a0, Object a1) { return convert_J(invoker.<long >invoke(target, a0, a1)); }
|
||||
protected Object invoke_F2(Object a0, Object a1) { return convert_F(invoker.<float >invoke(target, a0, a1)); }
|
||||
protected Object invoke_D2(Object a0, Object a1) { return convert_D(invoker.<double>invoke(target, a0, a1)); }
|
||||
protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L(invoker.<Object>invoke(target, a0, a1)); }
|
||||
protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I(invoker.<int >invoke(target, a0, a1)); }
|
||||
protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J(invoker.<long >invoke(target, a0, a1)); }
|
||||
protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F(invoker.<float >invoke(target, a0, a1)); }
|
||||
protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D(invoker.<double>invoke(target, a0, a1)); }
|
||||
}
|
||||
static class A3 extends Adapter {
|
||||
protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||
@ -534,11 +539,11 @@ class genclasses {
|
||||
{ super(e, i, c, t); }
|
||||
protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||
{ return new A3(e, i, c, t); }
|
||||
protected Object invoke_L3(Object a0, Object a1, Object a2) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2)); }
|
||||
protected Object invoke_I3(Object a0, Object a1, Object a2) { return convert_I(invoker.<int >invoke(target, a0, a1, a2)); }
|
||||
protected Object invoke_J3(Object a0, Object a1, Object a2) { return convert_J(invoker.<long >invoke(target, a0, a1, a2)); }
|
||||
protected Object invoke_F3(Object a0, Object a1, Object a2) { return convert_F(invoker.<float >invoke(target, a0, a1, a2)); }
|
||||
protected Object invoke_D3(Object a0, Object a1, Object a2) { return convert_D(invoker.<double>invoke(target, a0, a1, a2)); }
|
||||
protected Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable { return convert_L(invoker.<Object>invoke(target, a0, a1, a2)); }
|
||||
protected Object invoke_I3(Object a0, Object a1, Object a2) throws Throwable { return convert_I(invoker.<int >invoke(target, a0, a1, a2)); }
|
||||
protected Object invoke_J3(Object a0, Object a1, Object a2) throws Throwable { return convert_J(invoker.<long >invoke(target, a0, a1, a2)); }
|
||||
protected Object invoke_F3(Object a0, Object a1, Object a2) throws Throwable { return convert_F(invoker.<float >invoke(target, a0, a1, a2)); }
|
||||
protected Object invoke_D3(Object a0, Object a1, Object a2) throws Throwable { return convert_D(invoker.<double>invoke(target, a0, a1, a2)); }
|
||||
}
|
||||
static class A4 extends Adapter {
|
||||
protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||
@ -546,11 +551,11 @@ class genclasses {
|
||||
{ super(e, i, c, t); }
|
||||
protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||
{ return new A4(e, i, c, t); }
|
||||
protected Object invoke_L4(Object a0, Object a1, Object a2, Object a3) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3)); }
|
||||
protected Object invoke_I4(Object a0, Object a1, Object a2, Object a3) { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3)); }
|
||||
protected Object invoke_J4(Object a0, Object a1, Object a2, Object a3) { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3)); }
|
||||
protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3)); }
|
||||
protected Object invoke_D4(Object a0, Object a1, Object a2, Object a3) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3)); }
|
||||
protected Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3)); }
|
||||
protected Object invoke_I4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3)); }
|
||||
protected Object invoke_J4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3)); }
|
||||
protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3)); }
|
||||
protected Object invoke_D4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3)); }
|
||||
}
|
||||
static class A5 extends Adapter {
|
||||
protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||
@ -558,11 +563,11 @@ class genclasses {
|
||||
{ super(e, i, c, t); }
|
||||
protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||
{ return new A5(e, i, c, t); }
|
||||
protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4)); }
|
||||
protected Object invoke_I5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4)); }
|
||||
protected Object invoke_J5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4)); }
|
||||
protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4)); }
|
||||
protected Object invoke_D5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4)); }
|
||||
protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4)); }
|
||||
protected Object invoke_I5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4)); }
|
||||
protected Object invoke_J5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4)); }
|
||||
protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4)); }
|
||||
protected Object invoke_D5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4)); }
|
||||
}
|
||||
static class A6 extends Adapter {
|
||||
protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||
@ -570,11 +575,11 @@ class genclasses {
|
||||
{ super(e, i, c, t); }
|
||||
protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||
{ return new A6(e, i, c, t); }
|
||||
protected Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5)); }
|
||||
protected Object invoke_I6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4, a5)); }
|
||||
protected Object invoke_J6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4, a5)); }
|
||||
protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5)); }
|
||||
protected Object invoke_D6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5)); }
|
||||
protected Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5)); }
|
||||
protected Object invoke_I6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4, a5)); }
|
||||
protected Object invoke_J6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4, a5)); }
|
||||
protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5)); }
|
||||
protected Object invoke_D6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5)); }
|
||||
}
|
||||
static class A7 extends Adapter {
|
||||
protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||
@ -582,11 +587,11 @@ class genclasses {
|
||||
{ super(e, i, c, t); }
|
||||
protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||
{ return new A7(e, i, c, t); }
|
||||
protected Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
|
||||
protected Object invoke_I7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
|
||||
protected Object invoke_J7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
|
||||
protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
|
||||
protected Object invoke_D7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
|
||||
protected Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
|
||||
protected Object invoke_I7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
|
||||
protected Object invoke_J7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
|
||||
protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
|
||||
protected Object invoke_D7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6)); }
|
||||
}
|
||||
static class A8 extends Adapter {
|
||||
protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||
@ -594,11 +599,11 @@ class genclasses {
|
||||
{ super(e, i, c, t); }
|
||||
protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||
{ return new A8(e, i, c, t); }
|
||||
protected Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
||||
protected Object invoke_I8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
||||
protected Object invoke_J8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
||||
protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
||||
protected Object invoke_D8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
||||
protected Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
||||
protected Object invoke_I8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
||||
protected Object invoke_J8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
||||
protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
||||
protected Object invoke_D8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
||||
}
|
||||
static class A9 extends Adapter {
|
||||
protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||
@ -606,11 +611,11 @@ class genclasses {
|
||||
{ super(e, i, c, t); }
|
||||
protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||
{ return new A9(e, i, c, t); }
|
||||
protected Object invoke_L9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
||||
protected Object invoke_I9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
||||
protected Object invoke_J9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
||||
protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
||||
protected Object invoke_D9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
||||
protected Object invoke_L9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
||||
protected Object invoke_I9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
||||
protected Object invoke_J9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
||||
protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
||||
protected Object invoke_D9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
||||
}
|
||||
static class A10 extends Adapter {
|
||||
protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||
@ -618,10 +623,10 @@ class genclasses {
|
||||
{ super(e, i, c, t); }
|
||||
protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||
{ return new A10(e, i, c, t); }
|
||||
protected Object invoke_L10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
||||
protected Object invoke_I10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
||||
protected Object invoke_J10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
||||
protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
||||
protected Object invoke_D10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
||||
protected Object invoke_L10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_L(invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
||||
protected Object invoke_I10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_I(invoker.<int >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
||||
protected Object invoke_J10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_J(invoker.<long >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
||||
protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_F(invoker.<float >invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
||||
protected Object invoke_D10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_D(invoker.<double>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,16 +44,20 @@ public class Invokers {
|
||||
// generic (untyped) invoker for the outgoing call
|
||||
private /*lazy*/ MethodHandle genericInvoker;
|
||||
|
||||
// generic (untyped) invoker for the outgoing call; accepts a single Object[]
|
||||
private final /*lazy*/ MethodHandle[] varargsInvokers;
|
||||
|
||||
/** Compute and cache information common to all collecting adapters
|
||||
* that implement members of the erasure-family of the given erased type.
|
||||
*/
|
||||
public Invokers(Access token, MethodType targetType) {
|
||||
Access.check(token);
|
||||
this.targetType = targetType;
|
||||
this.varargsInvokers = new MethodHandle[targetType.parameterCount()+1];
|
||||
}
|
||||
|
||||
public static MethodType invokerType(MethodType targetType) {
|
||||
return targetType.insertParameterType(0, MethodHandle.class);
|
||||
return targetType.insertParameterTypes(0, MethodHandle.class);
|
||||
}
|
||||
|
||||
public MethodHandle exactInvoker() {
|
||||
@ -76,8 +80,14 @@ public class Invokers {
|
||||
return invoker;
|
||||
}
|
||||
|
||||
public MethodHandle varargsInvoker() {
|
||||
throw new UnsupportedOperationException("NYI");
|
||||
public MethodHandle varargsInvoker(int objectArgCount) {
|
||||
MethodHandle vaInvoker = varargsInvokers[objectArgCount];
|
||||
if (vaInvoker != null) return vaInvoker;
|
||||
MethodHandle gInvoker = genericInvoker();
|
||||
MethodType vaType = MethodType.genericMethodType(objectArgCount, true);
|
||||
vaInvoker = MethodHandles.spreadArguments(gInvoker, invokerType(vaType));
|
||||
varargsInvokers[objectArgCount] = vaInvoker;
|
||||
return vaInvoker;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
|
||||
package sun.dyn;
|
||||
|
||||
import sun.dyn.util.BytecodeSignature;
|
||||
import sun.dyn.util.BytecodeDescriptor;
|
||||
import java.dyn.*;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
@ -33,6 +33,7 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@ -93,7 +94,7 @@ public final class MemberName implements Member, Cloneable {
|
||||
}
|
||||
if (type instanceof String) {
|
||||
String sig = (String) type;
|
||||
MethodType res = MethodType.fromBytecodeString(sig, getClassLoader());
|
||||
MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader());
|
||||
this.type = res;
|
||||
return res;
|
||||
}
|
||||
@ -101,7 +102,7 @@ public final class MemberName implements Member, Cloneable {
|
||||
Object[] typeInfo = (Object[]) type;
|
||||
Class<?>[] ptypes = (Class<?>[]) typeInfo[1];
|
||||
Class<?> rtype = (Class<?>) typeInfo[0];
|
||||
MethodType res = MethodType.make(rtype, ptypes);
|
||||
MethodType res = MethodType.methodType(rtype, ptypes);
|
||||
this.type = res;
|
||||
return res;
|
||||
}
|
||||
@ -111,7 +112,7 @@ public final class MemberName implements Member, Cloneable {
|
||||
public MethodType getInvocationType() {
|
||||
MethodType itype = getMethodType();
|
||||
if (!isStatic())
|
||||
itype = itype.insertParameterType(0, clazz);
|
||||
itype = itype.insertParameterTypes(0, clazz);
|
||||
return itype;
|
||||
}
|
||||
|
||||
@ -135,7 +136,7 @@ public final class MemberName implements Member, Cloneable {
|
||||
}
|
||||
if (type instanceof String) {
|
||||
String sig = (String) type;
|
||||
MethodType mtype = MethodType.fromBytecodeString("()"+sig, getClassLoader());
|
||||
MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader());
|
||||
Class<?> res = mtype.returnType();
|
||||
this.type = res;
|
||||
return res;
|
||||
@ -155,9 +156,9 @@ public final class MemberName implements Member, Cloneable {
|
||||
if (type instanceof String)
|
||||
return (String) type;
|
||||
if (isInvocable())
|
||||
return BytecodeSignature.unparse(getMethodType());
|
||||
return BytecodeDescriptor.unparse(getMethodType());
|
||||
else
|
||||
return BytecodeSignature.unparse(getFieldType());
|
||||
return BytecodeDescriptor.unparse(getFieldType());
|
||||
}
|
||||
|
||||
public int getModifiers() {
|
||||
@ -353,6 +354,8 @@ public final class MemberName implements Member, Cloneable {
|
||||
return type.toString(); // class java.lang.String
|
||||
// else it is a field, method, or constructor
|
||||
StringBuilder buf = new StringBuilder();
|
||||
if (!isResolved())
|
||||
buf.append("*.");
|
||||
if (getDeclaringClass() != null) {
|
||||
buf.append(getName(clazz));
|
||||
buf.append('.');
|
||||
@ -381,7 +384,7 @@ public final class MemberName implements Member, Cloneable {
|
||||
private static String getName(Object obj) {
|
||||
if (obj instanceof Class<?>)
|
||||
return ((Class<?>)obj).getName();
|
||||
return obj.toString();
|
||||
return String.valueOf(obj);
|
||||
}
|
||||
|
||||
// Queries to the JVM:
|
||||
@ -408,6 +411,9 @@ public final class MemberName implements Member, Cloneable {
|
||||
public static NoAccessException newNoAccessException(MemberName name, Class<?> lookupClass) {
|
||||
return newNoAccessException("cannot access", name, lookupClass);
|
||||
}
|
||||
public static NoAccessException newNoAccessException(MemberName name, MethodHandles.Lookup lookup) {
|
||||
return newNoAccessException(name, lookup.lookupClass());
|
||||
}
|
||||
public static NoAccessException newNoAccessException(String message,
|
||||
MemberName name, Class<?> lookupClass) {
|
||||
message += ": " + name;
|
||||
@ -436,7 +442,7 @@ public final class MemberName implements Member, Cloneable {
|
||||
matchFlags &= ALLOWED_FLAGS;
|
||||
String matchSig = null;
|
||||
if (matchType != null) {
|
||||
matchSig = BytecodeSignature.unparse(matchType);
|
||||
matchSig = BytecodeDescriptor.unparse(matchType);
|
||||
if (matchSig.startsWith("("))
|
||||
matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE);
|
||||
else
|
||||
@ -447,17 +453,18 @@ public final class MemberName implements Member, Cloneable {
|
||||
MemberName[] buf = newMemberBuffer(len1);
|
||||
int totalCount = 0;
|
||||
ArrayList<MemberName[]> bufs = null;
|
||||
int bufCount = 0;
|
||||
for (;;) {
|
||||
int bufCount = MethodHandleNatives.getMembers(defc,
|
||||
bufCount = MethodHandleNatives.getMembers(defc,
|
||||
matchName, matchSig, matchFlags,
|
||||
lookupClass,
|
||||
totalCount, buf);
|
||||
if (bufCount <= buf.length) {
|
||||
if (bufCount >= 0)
|
||||
totalCount += bufCount;
|
||||
if (bufCount < 0) bufCount = 0;
|
||||
totalCount += bufCount;
|
||||
break;
|
||||
}
|
||||
// JVM returned tp us with an intentional overflow!
|
||||
// JVM returned to us with an intentional overflow!
|
||||
totalCount += buf.length;
|
||||
int excess = bufCount - buf.length;
|
||||
if (bufs == null) bufs = new ArrayList<MemberName[]>(1);
|
||||
@ -473,7 +480,7 @@ public final class MemberName implements Member, Cloneable {
|
||||
Collections.addAll(result, buf0);
|
||||
}
|
||||
}
|
||||
Collections.addAll(result, buf);
|
||||
result.addAll(Arrays.asList(buf).subList(0, bufCount));
|
||||
// Signature matching is not the same as type matching, since
|
||||
// one signature might correspond to several types.
|
||||
// So if matchType is a Class or MethodType, refilter the results.
|
||||
|
||||
@ -25,12 +25,25 @@
|
||||
|
||||
package sun.dyn;
|
||||
|
||||
import java.dyn.JavaMethodHandle;
|
||||
import java.dyn.MethodHandle;
|
||||
import java.dyn.MethodHandles;
|
||||
import java.dyn.MethodHandles.Lookup;
|
||||
import java.dyn.MethodType;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import sun.dyn.util.VerifyType;
|
||||
import java.dyn.NoAccessException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import sun.dyn.empty.Empty;
|
||||
import sun.dyn.util.ValueConversions;
|
||||
import sun.dyn.util.Wrapper;
|
||||
import sun.misc.Unsafe;
|
||||
import static sun.dyn.MemberName.newIllegalArgumentException;
|
||||
import static sun.dyn.MemberName.newNoAccessException;
|
||||
|
||||
@ -57,6 +70,25 @@ public abstract class MethodHandleImpl {
|
||||
static final int INT_FIELD = 0;
|
||||
static final long LONG_FIELD = 0;
|
||||
|
||||
/** Access methods for the internals of MethodHandle, supplied to
|
||||
* MethodHandleImpl as a trusted agent.
|
||||
*/
|
||||
static public interface MethodHandleFriend {
|
||||
void initType(MethodHandle mh, MethodType type);
|
||||
}
|
||||
public static void setMethodHandleFriend(Access token, MethodHandleFriend am) {
|
||||
Access.check(token);
|
||||
if (METHOD_HANDLE_FRIEND != null)
|
||||
throw new InternalError(); // just once
|
||||
METHOD_HANDLE_FRIEND = am;
|
||||
}
|
||||
static private MethodHandleFriend METHOD_HANDLE_FRIEND;
|
||||
|
||||
// NOT public
|
||||
static void initType(MethodHandle mh, MethodType type) {
|
||||
METHOD_HANDLE_FRIEND.initType(mh, type);
|
||||
}
|
||||
|
||||
// type is defined in java.dyn.MethodHandle, which is platform-independent
|
||||
|
||||
// vmentry (a void* field) is used *only* by by the JVM.
|
||||
@ -106,8 +138,8 @@ public abstract class MethodHandleImpl {
|
||||
}
|
||||
|
||||
static {
|
||||
// Force initialization:
|
||||
Lookup.PUBLIC_LOOKUP.lookupClass();
|
||||
// Force initialization of Lookup, so it calls us back as initLookup:
|
||||
MethodHandles.publicLookup();
|
||||
if (IMPL_LOOKUP_INIT == null)
|
||||
throw new InternalError();
|
||||
}
|
||||
@ -151,7 +183,7 @@ public abstract class MethodHandleImpl {
|
||||
// adjust the advertised receiver type to be exactly the one requested
|
||||
// (in the case of invokespecial, this will be the calling class)
|
||||
Class<?> recvType = method.getDeclaringClass();
|
||||
mtype = mtype.insertParameterType(0, recvType);
|
||||
mtype = mtype.insertParameterTypes(0, recvType);
|
||||
if (method.isConstructor())
|
||||
doDispatch = true;
|
||||
// FIXME: JVM has trouble building MH.invoke sites for
|
||||
@ -170,21 +202,223 @@ public abstract class MethodHandleImpl {
|
||||
|
||||
public static
|
||||
MethodHandle accessField(Access token,
|
||||
MemberName member, boolean isSetter,
|
||||
Class<?> lookupClass) {
|
||||
MemberName member, boolean isSetter,
|
||||
Class<?> lookupClass) {
|
||||
Access.check(token);
|
||||
// FIXME: Use sun.misc.Unsafe to dig up the dirt on the field.
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
// Use sun. misc.Unsafe to dig up the dirt on the field.
|
||||
MethodHandle mh = new FieldAccessor(token, member, isSetter);
|
||||
return mh;
|
||||
}
|
||||
|
||||
public static
|
||||
MethodHandle accessArrayElement(Access token,
|
||||
Class<?> arrayClass, boolean isSetter) {
|
||||
Class<?> arrayClass, boolean isSetter) {
|
||||
Access.check(token);
|
||||
if (!arrayClass.isArray())
|
||||
throw newIllegalArgumentException("not an array: "+arrayClass);
|
||||
// FIXME: Use sun.misc.Unsafe to dig up the dirt on the array.
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
Class<?> elemClass = arrayClass.getComponentType();
|
||||
MethodHandle[] mhs = FieldAccessor.ARRAY_CACHE.get(elemClass);
|
||||
if (mhs == null) {
|
||||
if (!FieldAccessor.doCache(elemClass))
|
||||
return FieldAccessor.ahandle(arrayClass, isSetter);
|
||||
mhs = new MethodHandle[] {
|
||||
FieldAccessor.ahandle(arrayClass, false),
|
||||
FieldAccessor.ahandle(arrayClass, true)
|
||||
};
|
||||
if (mhs[0].type().parameterType(0) == Class.class) {
|
||||
mhs[0] = MethodHandles.insertArguments(mhs[0], 0, elemClass);
|
||||
mhs[1] = MethodHandles.insertArguments(mhs[1], 0, elemClass);
|
||||
}
|
||||
synchronized (FieldAccessor.ARRAY_CACHE) {} // memory barrier
|
||||
FieldAccessor.ARRAY_CACHE.put(elemClass, mhs);
|
||||
}
|
||||
return mhs[isSetter ? 1 : 0];
|
||||
}
|
||||
|
||||
static final class FieldAccessor<C,V> extends JavaMethodHandle {
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
final Object base; // for static refs only
|
||||
final long offset;
|
||||
final String name;
|
||||
|
||||
public FieldAccessor(Access token, MemberName field, boolean isSetter) {
|
||||
super(fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic()));
|
||||
this.offset = (long) field.getVMIndex(token);
|
||||
this.name = field.getName();
|
||||
this.base = staticBase(field);
|
||||
}
|
||||
public String toString() { return name; }
|
||||
|
||||
int getFieldI(C obj) { return unsafe.getInt(obj, offset); }
|
||||
void setFieldI(C obj, int x) { unsafe.putInt(obj, offset, x); }
|
||||
long getFieldJ(C obj) { return unsafe.getLong(obj, offset); }
|
||||
void setFieldJ(C obj, long x) { unsafe.putLong(obj, offset, x); }
|
||||
float getFieldF(C obj) { return unsafe.getFloat(obj, offset); }
|
||||
void setFieldF(C obj, float x) { unsafe.putFloat(obj, offset, x); }
|
||||
double getFieldD(C obj) { return unsafe.getDouble(obj, offset); }
|
||||
void setFieldD(C obj, double x) { unsafe.putDouble(obj, offset, x); }
|
||||
boolean getFieldZ(C obj) { return unsafe.getBoolean(obj, offset); }
|
||||
void setFieldZ(C obj, boolean x) { unsafe.putBoolean(obj, offset, x); }
|
||||
byte getFieldB(C obj) { return unsafe.getByte(obj, offset); }
|
||||
void setFieldB(C obj, byte x) { unsafe.putByte(obj, offset, x); }
|
||||
short getFieldS(C obj) { return unsafe.getShort(obj, offset); }
|
||||
void setFieldS(C obj, short x) { unsafe.putShort(obj, offset, x); }
|
||||
char getFieldC(C obj) { return unsafe.getChar(obj, offset); }
|
||||
void setFieldC(C obj, char x) { unsafe.putChar(obj, offset, x); }
|
||||
@SuppressWarnings("unchecked")
|
||||
V getFieldL(C obj) { return (V) unsafe.getObject(obj, offset); }
|
||||
@SuppressWarnings("unchecked")
|
||||
void setFieldL(C obj, V x) { unsafe.putObject(obj, offset, x); }
|
||||
// cast (V) is OK here, since we wrap convertArguments around the MH.
|
||||
|
||||
static Object staticBase(MemberName field) {
|
||||
if (!field.isStatic()) return null;
|
||||
Class c = field.getDeclaringClass();
|
||||
java.lang.reflect.Field f;
|
||||
try {
|
||||
// FIXME: Should not have to create 'f' to get this value.
|
||||
f = c.getDeclaredField(field.getName());
|
||||
return unsafe.staticFieldBase(f);
|
||||
} catch (Exception ee) {
|
||||
Error e = new InternalError();
|
||||
e.initCause(ee);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
int getStaticI() { return unsafe.getInt(base, offset); }
|
||||
void setStaticI(int x) { unsafe.putInt(base, offset, x); }
|
||||
long getStaticJ() { return unsafe.getLong(base, offset); }
|
||||
void setStaticJ(long x) { unsafe.putLong(base, offset, x); }
|
||||
float getStaticF() { return unsafe.getFloat(base, offset); }
|
||||
void setStaticF(float x) { unsafe.putFloat(base, offset, x); }
|
||||
double getStaticD() { return unsafe.getDouble(base, offset); }
|
||||
void setStaticD(double x) { unsafe.putDouble(base, offset, x); }
|
||||
boolean getStaticZ() { return unsafe.getBoolean(base, offset); }
|
||||
void setStaticZ(boolean x) { unsafe.putBoolean(base, offset, x); }
|
||||
byte getStaticB() { return unsafe.getByte(base, offset); }
|
||||
void setStaticB(byte x) { unsafe.putByte(base, offset, x); }
|
||||
short getStaticS() { return unsafe.getShort(base, offset); }
|
||||
void setStaticS(short x) { unsafe.putShort(base, offset, x); }
|
||||
char getStaticC() { return unsafe.getChar(base, offset); }
|
||||
void setStaticC(char x) { unsafe.putChar(base, offset, x); }
|
||||
V getStaticL() { return (V) unsafe.getObject(base, offset); }
|
||||
void setStaticL(V x) { unsafe.putObject(base, offset, x); }
|
||||
|
||||
static String fname(Class<?> vclass, boolean isSetter, boolean isStatic) {
|
||||
String stem;
|
||||
if (!isStatic)
|
||||
stem = (!isSetter ? "getField" : "setField");
|
||||
else
|
||||
stem = (!isSetter ? "getStatic" : "setStatic");
|
||||
return stem + Wrapper.basicTypeChar(vclass);
|
||||
}
|
||||
static MethodType ftype(Class<?> cclass, Class<?> vclass, boolean isSetter, boolean isStatic) {
|
||||
MethodType type;
|
||||
if (!isStatic) {
|
||||
if (!isSetter)
|
||||
return MethodType.methodType(vclass, cclass);
|
||||
else
|
||||
return MethodType.methodType(void.class, cclass, vclass);
|
||||
} else {
|
||||
if (!isSetter)
|
||||
return MethodType.methodType(vclass);
|
||||
else
|
||||
return MethodType.methodType(void.class, vclass);
|
||||
}
|
||||
}
|
||||
static MethodHandle fhandle(Class<?> cclass, Class<?> vclass, boolean isSetter, boolean isStatic) {
|
||||
String name = FieldAccessor.fname(vclass, isSetter, isStatic);
|
||||
if (cclass.isPrimitive()) throw newIllegalArgumentException("primitive "+cclass);
|
||||
Class<?> ecclass = Object.class; //erase this type
|
||||
Class<?> evclass = vclass;
|
||||
if (!evclass.isPrimitive()) evclass = Object.class;
|
||||
MethodType type = FieldAccessor.ftype(ecclass, evclass, isSetter, isStatic);
|
||||
MethodHandle mh;
|
||||
try {
|
||||
mh = IMPL_LOOKUP.findVirtual(FieldAccessor.class, name, type);
|
||||
} catch (NoAccessException ee) {
|
||||
Error e = new InternalError("name,type="+name+type);
|
||||
e.initCause(ee);
|
||||
throw e;
|
||||
}
|
||||
if (evclass != vclass || (!isStatic && ecclass != cclass)) {
|
||||
MethodType strongType = FieldAccessor.ftype(cclass, vclass, isSetter, isStatic);
|
||||
strongType = strongType.insertParameterTypes(0, FieldAccessor.class);
|
||||
mh = MethodHandles.convertArguments(mh, strongType);
|
||||
}
|
||||
return mh;
|
||||
}
|
||||
|
||||
/// Support for array element access
|
||||
static final HashMap<Class<?>, MethodHandle[]> ARRAY_CACHE =
|
||||
new HashMap<Class<?>, MethodHandle[]>();
|
||||
// FIXME: Cache on the classes themselves, not here.
|
||||
static boolean doCache(Class<?> elemClass) {
|
||||
if (elemClass.isPrimitive()) return true;
|
||||
ClassLoader cl = elemClass.getClassLoader();
|
||||
return cl == null || cl == ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
static int getElementI(int[] a, int i) { return a[i]; }
|
||||
static void setElementI(int[] a, int i, int x) { a[i] = x; }
|
||||
static long getElementJ(long[] a, int i) { return a[i]; }
|
||||
static void setElementJ(long[] a, int i, long x) { a[i] = x; }
|
||||
static float getElementF(float[] a, int i) { return a[i]; }
|
||||
static void setElementF(float[] a, int i, float x) { a[i] = x; }
|
||||
static double getElementD(double[] a, int i) { return a[i]; }
|
||||
static void setElementD(double[] a, int i, double x) { a[i] = x; }
|
||||
static boolean getElementZ(boolean[] a, int i) { return a[i]; }
|
||||
static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; }
|
||||
static byte getElementB(byte[] a, int i) { return a[i]; }
|
||||
static void setElementB(byte[] a, int i, byte x) { a[i] = x; }
|
||||
static short getElementS(short[] a, int i) { return a[i]; }
|
||||
static void setElementS(short[] a, int i, short x) { a[i] = x; }
|
||||
static char getElementC(char[] a, int i) { return a[i]; }
|
||||
static void setElementC(char[] a, int i, char x) { a[i] = x; }
|
||||
static Object getElementL(Object[] a, int i) { return a[i]; }
|
||||
static void setElementL(Object[] a, int i, Object x) { a[i] = x; }
|
||||
static <V> V getElementL(Class<V[]> aclass, V[] a, int i) { return aclass.cast(a)[i]; }
|
||||
static <V> void setElementL(Class<V[]> aclass, V[] a, int i, V x) { aclass.cast(a)[i] = x; }
|
||||
|
||||
static String aname(Class<?> aclass, boolean isSetter) {
|
||||
Class<?> vclass = aclass.getComponentType();
|
||||
if (vclass == null) throw new IllegalArgumentException();
|
||||
return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(vclass);
|
||||
}
|
||||
static MethodType atype(Class<?> aclass, boolean isSetter) {
|
||||
Class<?> vclass = aclass.getComponentType();
|
||||
if (!isSetter)
|
||||
return MethodType.methodType(vclass, aclass, int.class);
|
||||
else
|
||||
return MethodType.methodType(void.class, aclass, int.class, vclass);
|
||||
}
|
||||
static MethodHandle ahandle(Class<?> aclass, boolean isSetter) {
|
||||
Class<?> vclass = aclass.getComponentType();
|
||||
String name = FieldAccessor.aname(aclass, isSetter);
|
||||
Class<?> caclass = null;
|
||||
if (!vclass.isPrimitive() && vclass != Object.class) {
|
||||
caclass = aclass;
|
||||
aclass = Object[].class;
|
||||
vclass = Object.class;
|
||||
}
|
||||
MethodType type = FieldAccessor.atype(aclass, isSetter);
|
||||
if (caclass != null)
|
||||
type = type.insertParameterTypes(0, Class.class);
|
||||
MethodHandle mh;
|
||||
try {
|
||||
mh = IMPL_LOOKUP.findStatic(FieldAccessor.class, name, type);
|
||||
} catch (NoAccessException ee) {
|
||||
Error e = new InternalError("name,type="+name+type);
|
||||
e.initCause(ee);
|
||||
throw e;
|
||||
}
|
||||
if (caclass != null) {
|
||||
MethodType strongType = FieldAccessor.atype(caclass, isSetter);
|
||||
mh = MethodHandles.insertArguments(mh, 0, caclass);
|
||||
mh = MethodHandles.convertArguments(mh, strongType);
|
||||
}
|
||||
return mh;
|
||||
}
|
||||
}
|
||||
|
||||
/** Bind a predetermined first argument to the given direct method handle.
|
||||
@ -203,8 +437,11 @@ public abstract class MethodHandleImpl {
|
||||
if (info instanceof DirectMethodHandle) {
|
||||
DirectMethodHandle dmh = (DirectMethodHandle) info;
|
||||
if (receiver == null ||
|
||||
dmh.type().parameterType(0).isAssignableFrom(receiver.getClass()))
|
||||
target = dmh;
|
||||
dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
|
||||
MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0);
|
||||
MethodType newType = target.type().dropParameterTypes(0, 1);
|
||||
return convertArguments(token, bmh, newType, bmh.type(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (target instanceof DirectMethodHandle)
|
||||
@ -223,7 +460,7 @@ public abstract class MethodHandleImpl {
|
||||
MethodHandle bindArgument(Access token,
|
||||
MethodHandle target, int argnum, Object receiver) {
|
||||
Access.check(token);
|
||||
throw new UnsupportedOperationException("NYI");
|
||||
return new BoundMethodHandle(target, receiver, argnum);
|
||||
}
|
||||
|
||||
public static MethodHandle convertArguments(Access token,
|
||||
@ -232,6 +469,189 @@ public abstract class MethodHandleImpl {
|
||||
MethodType oldType,
|
||||
int[] permutationOrNull) {
|
||||
Access.check(token);
|
||||
if (permutationOrNull != null) {
|
||||
int outargs = oldType.parameterCount(), inargs = newType.parameterCount();
|
||||
if (permutationOrNull.length != outargs)
|
||||
throw newIllegalArgumentException("wrong number of arguments in permutation");
|
||||
// Make the individual outgoing argument types match up first.
|
||||
Class<?>[] callTypeArgs = new Class<?>[outargs];
|
||||
for (int i = 0; i < outargs; i++)
|
||||
callTypeArgs[i] = newType.parameterType(permutationOrNull[i]);
|
||||
MethodType callType = MethodType.methodType(oldType.returnType(), callTypeArgs);
|
||||
target = convertArguments(token, target, callType, oldType, null);
|
||||
assert(target != null);
|
||||
oldType = target.type();
|
||||
List<Integer> goal = new ArrayList<Integer>(); // i*TOKEN
|
||||
List<Integer> state = new ArrayList<Integer>(); // i*TOKEN
|
||||
List<Integer> drops = new ArrayList<Integer>(); // not tokens
|
||||
List<Integer> dups = new ArrayList<Integer>(); // not tokens
|
||||
final int TOKEN = 10; // to mark items which are symbolic only
|
||||
// state represents the argument values coming into target
|
||||
for (int i = 0; i < outargs; i++) {
|
||||
state.add(permutationOrNull[i] * TOKEN);
|
||||
}
|
||||
// goal represents the desired state
|
||||
for (int i = 0; i < inargs; i++) {
|
||||
if (state.contains(i * TOKEN)) {
|
||||
goal.add(i * TOKEN);
|
||||
} else {
|
||||
// adapter must initially drop all unused arguments
|
||||
drops.add(i);
|
||||
}
|
||||
}
|
||||
// detect duplications
|
||||
while (state.size() > goal.size()) {
|
||||
for (int i2 = 0; i2 < state.size(); i2++) {
|
||||
int arg1 = state.get(i2);
|
||||
int i1 = state.indexOf(arg1);
|
||||
if (i1 != i2) {
|
||||
// found duplicate occurrence at i2
|
||||
int arg2 = (inargs++) * TOKEN;
|
||||
state.set(i2, arg2);
|
||||
dups.add(goal.indexOf(arg1));
|
||||
goal.add(arg2);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(state.size() == goal.size());
|
||||
int size = goal.size();
|
||||
while (!state.equals(goal)) {
|
||||
// Look for a maximal sequence of adjacent misplaced arguments,
|
||||
// and try to rotate them into place.
|
||||
int bestRotArg = -10 * TOKEN, bestRotLen = 0;
|
||||
int thisRotArg = -10 * TOKEN, thisRotLen = 0;
|
||||
for (int i = 0; i < size; i++) {
|
||||
int arg = state.get(i);
|
||||
// Does this argument match the current run?
|
||||
if (arg == thisRotArg + TOKEN) {
|
||||
thisRotArg = arg;
|
||||
thisRotLen += 1;
|
||||
if (bestRotLen < thisRotLen) {
|
||||
bestRotLen = thisRotLen;
|
||||
bestRotArg = thisRotArg;
|
||||
}
|
||||
} else {
|
||||
// The old sequence (if any) stops here.
|
||||
thisRotLen = 0;
|
||||
thisRotArg = -10 * TOKEN;
|
||||
// But maybe a new one starts here also.
|
||||
int wantArg = goal.get(i);
|
||||
final int MAX_ARG_ROTATION = AdapterMethodHandle.MAX_ARG_ROTATION;
|
||||
if (arg != wantArg &&
|
||||
arg >= wantArg - TOKEN * MAX_ARG_ROTATION &&
|
||||
arg <= wantArg + TOKEN * MAX_ARG_ROTATION) {
|
||||
thisRotArg = arg;
|
||||
thisRotLen = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bestRotLen >= 2) {
|
||||
// Do a rotation if it can improve argument positioning
|
||||
// by at least 2 arguments. This is not always optimal,
|
||||
// but it seems to catch common cases.
|
||||
int dstEnd = state.indexOf(bestRotArg);
|
||||
int srcEnd = goal.indexOf(bestRotArg);
|
||||
int rotBy = dstEnd - srcEnd;
|
||||
int dstBeg = dstEnd - (bestRotLen - 1);
|
||||
int srcBeg = srcEnd - (bestRotLen - 1);
|
||||
assert((dstEnd | dstBeg | srcEnd | srcBeg) >= 0); // no negs
|
||||
// Make a span which covers both source and destination.
|
||||
int rotBeg = Math.min(dstBeg, srcBeg);
|
||||
int rotEnd = Math.max(dstEnd, srcEnd);
|
||||
int score = 0;
|
||||
for (int i = rotBeg; i <= rotEnd; i++) {
|
||||
if ((int)state.get(i) != (int)goal.get(i))
|
||||
score += 1;
|
||||
}
|
||||
List<Integer> rotSpan = state.subList(rotBeg, rotEnd+1);
|
||||
Collections.rotate(rotSpan, -rotBy); // reverse direction
|
||||
for (int i = rotBeg; i <= rotEnd; i++) {
|
||||
if ((int)state.get(i) != (int)goal.get(i))
|
||||
score -= 1;
|
||||
}
|
||||
if (score >= 2) {
|
||||
// Improved at least two argument positions. Do it.
|
||||
List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
|
||||
Collections.rotate(ptypes.subList(rotBeg, rotEnd+1), -rotBy);
|
||||
MethodType rotType = MethodType.methodType(oldType.returnType(), ptypes);
|
||||
MethodHandle nextTarget
|
||||
= AdapterMethodHandle.makeRotateArguments(token, rotType, target,
|
||||
rotBeg, rotSpan.size(), rotBy);
|
||||
if (nextTarget != null) {
|
||||
//System.out.println("Rot: "+rotSpan+" by "+rotBy);
|
||||
target = nextTarget;
|
||||
oldType = rotType;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Else de-rotate, and drop through to the swap-fest.
|
||||
Collections.rotate(rotSpan, rotBy);
|
||||
}
|
||||
|
||||
// Now swap like the wind!
|
||||
List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
|
||||
for (int i = 0; i < size; i++) {
|
||||
// What argument do I want here?
|
||||
int arg = goal.get(i);
|
||||
if (arg != state.get(i)) {
|
||||
// Where is it now?
|
||||
int j = state.indexOf(arg);
|
||||
Collections.swap(ptypes, i, j);
|
||||
MethodType swapType = MethodType.methodType(oldType.returnType(), ptypes);
|
||||
target = AdapterMethodHandle.makeSwapArguments(token, swapType, target, i, j);
|
||||
if (target == null) throw newIllegalArgumentException("cannot swap");
|
||||
assert(target.type() == swapType);
|
||||
oldType = swapType;
|
||||
Collections.swap(state, i, j);
|
||||
}
|
||||
}
|
||||
// One pass of swapping must finish the job.
|
||||
assert(state.equals(goal));
|
||||
}
|
||||
while (!dups.isEmpty()) {
|
||||
// Grab a contiguous trailing sequence of dups.
|
||||
int grab = dups.size() - 1;
|
||||
int dupArgPos = dups.get(grab), dupArgCount = 1;
|
||||
while (grab - 1 >= 0) {
|
||||
int dup0 = dups.get(grab - 1);
|
||||
if (dup0 != dupArgPos - 1) break;
|
||||
dupArgPos -= 1;
|
||||
dupArgCount += 1;
|
||||
grab -= 1;
|
||||
}
|
||||
//if (dupArgCount > 1) System.out.println("Dup: "+dups.subList(grab, dups.size()));
|
||||
dups.subList(grab, dups.size()).clear();
|
||||
// In the new target type drop that many args from the tail:
|
||||
List<Class<?>> ptypes = oldType.parameterList();
|
||||
ptypes = ptypes.subList(0, ptypes.size() - dupArgCount);
|
||||
MethodType dupType = MethodType.methodType(oldType.returnType(), ptypes);
|
||||
target = AdapterMethodHandle.makeDupArguments(token, dupType, target, dupArgPos, dupArgCount);
|
||||
if (target == null)
|
||||
throw newIllegalArgumentException("cannot dup");
|
||||
oldType = target.type();
|
||||
}
|
||||
while (!drops.isEmpty()) {
|
||||
// Grab a contiguous initial sequence of drops.
|
||||
int dropArgPos = drops.get(0), dropArgCount = 1;
|
||||
while (dropArgCount < drops.size()) {
|
||||
int drop1 = drops.get(dropArgCount);
|
||||
if (drop1 != dropArgPos + dropArgCount) break;
|
||||
dropArgCount += 1;
|
||||
}
|
||||
//if (dropArgCount > 1) System.out.println("Drop: "+drops.subList(0, dropArgCount));
|
||||
drops.subList(0, dropArgCount).clear();
|
||||
List<Class<?>> dropTypes = newType.parameterList()
|
||||
.subList(dropArgPos, dropArgPos + dropArgCount);
|
||||
MethodType dropType = oldType.insertParameterTypes(dropArgPos, dropTypes);
|
||||
target = AdapterMethodHandle.makeDropArguments(token, dropType, target, dropArgPos, dropArgCount);
|
||||
if (target == null) throw newIllegalArgumentException("cannot drop");
|
||||
oldType = target.type();
|
||||
}
|
||||
}
|
||||
if (newType == oldType)
|
||||
return target;
|
||||
if (oldType.parameterCount() != newType.parameterCount())
|
||||
throw newIllegalArgumentException("mismatched parameter count");
|
||||
MethodHandle res = AdapterMethodHandle.makePairwiseConvert(token, newType, target);
|
||||
if (res != null)
|
||||
return res;
|
||||
@ -241,7 +661,7 @@ public abstract class MethodHandleImpl {
|
||||
// Use a heavier method: Convert all the arguments to Object,
|
||||
// then back to the desired types. We might have to use Java-based
|
||||
// method handles to do this.
|
||||
MethodType objType = MethodType.makeGeneric(argc);
|
||||
MethodType objType = MethodType.genericMethodType(argc);
|
||||
MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(token, objType, target);
|
||||
if (objTarget == null)
|
||||
objTarget = FromGeneric.make(target);
|
||||
@ -272,83 +692,386 @@ public abstract class MethodHandleImpl {
|
||||
Class<?>[] ptypes = oldType.parameterArray();
|
||||
for (int i = 0; i < spreadCount; i++)
|
||||
ptypes[spreadArg + i] = VerifyType.spreadArgElementType(spreadType, i);
|
||||
MethodType midType = MethodType.make(newType.returnType(), ptypes);
|
||||
MethodType midType = MethodType.methodType(newType.returnType(), ptypes);
|
||||
// after spreading, some arguments may need further conversion
|
||||
target = convertArguments(token, target, midType, oldType, null);
|
||||
if (target == null)
|
||||
MethodHandle target2 = convertArguments(token, target, midType, oldType, null);
|
||||
if (target2 == null)
|
||||
throw new UnsupportedOperationException("NYI: convert "+midType+" =calls=> "+oldType);
|
||||
res = AdapterMethodHandle.makeSpreadArguments(token, newType, target, spreadArgType, spreadArg, spreadCount);
|
||||
res = AdapterMethodHandle.makeSpreadArguments(token, newType, target2, spreadArgType, spreadArg, spreadCount);
|
||||
if (res != null)
|
||||
return res;
|
||||
res = SpreadGeneric.make(target2, spreadCount);
|
||||
if (res != null)
|
||||
res = convertArguments(token, res, newType, res.type(), null);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static MethodHandle collectArguments(Access token,
|
||||
MethodHandle target,
|
||||
MethodType newType,
|
||||
int collectArg) {
|
||||
if (collectArg > 0)
|
||||
throw new UnsupportedOperationException("NYI");
|
||||
throw new UnsupportedOperationException("NYI");
|
||||
int collectArg,
|
||||
MethodHandle collector) {
|
||||
MethodType oldType = target.type(); // (a...,c)=>r
|
||||
if (collector == null) {
|
||||
int numCollect = newType.parameterCount() - oldType.parameterCount() + 1;
|
||||
collector = ValueConversions.varargsArray(numCollect);
|
||||
}
|
||||
// newType // (a..., b...)=>r
|
||||
MethodType colType = collector.type(); // (b...)=>c
|
||||
// oldType // (a..., b...)=>r
|
||||
assert(newType.parameterCount() == collectArg + colType.parameterCount());
|
||||
assert(oldType.parameterCount() == collectArg + 1);
|
||||
MethodHandle gtarget = convertArguments(token, target, oldType.generic(), oldType, null);
|
||||
MethodHandle gcollector = convertArguments(token, collector, colType.generic(), colType, null);
|
||||
if (gtarget == null || gcollector == null) return null;
|
||||
MethodHandle gresult = FilterGeneric.makeArgumentCollector(gcollector, gtarget);
|
||||
MethodHandle result = convertArguments(token, gresult, newType, gresult.type(), null);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static MethodHandle filterArgument(Access token,
|
||||
MethodHandle target,
|
||||
int pos,
|
||||
MethodHandle filter) {
|
||||
Access.check(token);
|
||||
MethodType ttype = target.type(), gttype = ttype.generic();
|
||||
if (ttype != gttype) {
|
||||
target = convertArguments(token, target, gttype, ttype, null);
|
||||
ttype = gttype;
|
||||
}
|
||||
MethodType ftype = filter.type(), gftype = ftype.generic();
|
||||
if (ftype.parameterCount() != 1)
|
||||
throw new InternalError();
|
||||
if (ftype != gftype) {
|
||||
filter = convertArguments(token, filter, gftype, ftype, null);
|
||||
ftype = gftype;
|
||||
}
|
||||
if (ftype == ttype) {
|
||||
// simple unary case
|
||||
return FilterOneArgument.make(filter, target);
|
||||
}
|
||||
return FilterGeneric.makeArgumentFilter(pos, filter, target);
|
||||
}
|
||||
|
||||
public static MethodHandle foldArguments(Access token,
|
||||
MethodHandle target,
|
||||
MethodType newType,
|
||||
MethodHandle combiner) {
|
||||
Access.check(token);
|
||||
MethodType oldType = target.type();
|
||||
MethodType ctype = combiner.type();
|
||||
MethodHandle gtarget = convertArguments(token, target, oldType.generic(), oldType, null);
|
||||
MethodHandle gcombiner = convertArguments(token, combiner, ctype.generic(), ctype, null);
|
||||
if (gtarget == null || gcombiner == null) return null;
|
||||
MethodHandle gresult = FilterGeneric.makeArgumentFolder(gcombiner, gtarget);
|
||||
MethodHandle result = convertArguments(token, gresult, newType, gresult.type(), null);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static
|
||||
MethodHandle dropArguments(Access token, MethodHandle target,
|
||||
MethodType newType, int argnum) {
|
||||
Access.check(token);
|
||||
int drops = newType.parameterCount() - target.type().parameterCount();
|
||||
MethodHandle res = AdapterMethodHandle.makeDropArguments(token, newType, target, argnum, drops);
|
||||
if (res != null)
|
||||
return res;
|
||||
throw new UnsupportedOperationException("NYI");
|
||||
}
|
||||
|
||||
private static class GuardWithTest extends JavaMethodHandle {
|
||||
private final MethodHandle test, target, fallback;
|
||||
public GuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback) {
|
||||
this(INVOKES[target.type().parameterCount()], test, target, fallback);
|
||||
}
|
||||
public GuardWithTest(MethodHandle invoker,
|
||||
MethodHandle test, MethodHandle target, MethodHandle fallback) {
|
||||
super(invoker);
|
||||
this.test = test;
|
||||
this.target = target;
|
||||
this.fallback = fallback;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return target.toString();
|
||||
}
|
||||
private Object invoke_V(Object... av) throws Throwable {
|
||||
if (test.<boolean>invoke(av))
|
||||
return target.<Object>invoke(av);
|
||||
return fallback.<Object>invoke(av);
|
||||
}
|
||||
private Object invoke_L0() throws Throwable {
|
||||
if (test.<boolean>invoke())
|
||||
return target.<Object>invoke();
|
||||
return fallback.<Object>invoke();
|
||||
}
|
||||
private Object invoke_L1(Object a0) throws Throwable {
|
||||
if (test.<boolean>invoke(a0))
|
||||
return target.<Object>invoke(a0);
|
||||
return fallback.<Object>invoke(a0);
|
||||
}
|
||||
private Object invoke_L2(Object a0, Object a1) throws Throwable {
|
||||
if (test.<boolean>invoke(a0, a1))
|
||||
return target.<Object>invoke(a0, a1);
|
||||
return fallback.<Object>invoke(a0, a1);
|
||||
}
|
||||
private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
|
||||
if (test.<boolean>invoke(a0, a1, a2))
|
||||
return target.<Object>invoke(a0, a1, a2);
|
||||
return fallback.<Object>invoke(a0, a1, a2);
|
||||
}
|
||||
private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
|
||||
if (test.<boolean>invoke(a0, a1, a2, a3))
|
||||
return target.<Object>invoke(a0, a1, a2, a3);
|
||||
return fallback.<Object>invoke(a0, a1, a2, a3);
|
||||
}
|
||||
private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
|
||||
if (test.<boolean>invoke(a0, a1, a2, a3, a4))
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4);
|
||||
return fallback.<Object>invoke(a0, a1, a2, a3, a4);
|
||||
}
|
||||
private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
|
||||
if (test.<boolean>invoke(a0, a1, a2, a3, a4, a5))
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5);
|
||||
return fallback.<Object>invoke(a0, a1, a2, a3, a4, a5);
|
||||
}
|
||||
private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
|
||||
if (test.<boolean>invoke(a0, a1, a2, a3, a4, a5, a6))
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6);
|
||||
return fallback.<Object>invoke(a0, a1, a2, a3, a4, a5, a6);
|
||||
}
|
||||
private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
|
||||
if (test.<boolean>invoke(a0, a1, a2, a3, a4, a5, a6, a7))
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6, a7);
|
||||
return fallback.<Object>invoke(a0, a1, a2, a3, a4, a5, a6, a7);
|
||||
}
|
||||
static MethodHandle[] makeInvokes() {
|
||||
ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
|
||||
MethodHandles.Lookup lookup = IMPL_LOOKUP;
|
||||
for (;;) {
|
||||
int nargs = invokes.size();
|
||||
String name = "invoke_L"+nargs;
|
||||
MethodHandle invoke = null;
|
||||
try {
|
||||
invoke = lookup.findVirtual(GuardWithTest.class, name, MethodType.genericMethodType(nargs));
|
||||
} catch (NoAccessException ex) {
|
||||
}
|
||||
if (invoke == null) break;
|
||||
invokes.add(invoke);
|
||||
}
|
||||
assert(invokes.size() == 9); // current number of methods
|
||||
return invokes.toArray(new MethodHandle[0]);
|
||||
};
|
||||
static final MethodHandle[] INVOKES = makeInvokes();
|
||||
// For testing use this:
|
||||
//static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
|
||||
static final MethodHandle VARARGS_INVOKE;
|
||||
static {
|
||||
try {
|
||||
VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithTest.class, "invoke_V", MethodType.genericMethodType(0, true));
|
||||
} catch (NoAccessException ex) {
|
||||
throw new InternalError("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static
|
||||
MethodHandle makeGuardWithTest(Access token,
|
||||
final MethodHandle test,
|
||||
final MethodHandle target,
|
||||
final MethodHandle fallback) {
|
||||
MethodHandle test,
|
||||
MethodHandle target,
|
||||
MethodHandle fallback) {
|
||||
Access.check(token);
|
||||
// %%% This is just a sketch. It needs to be de-boxed.
|
||||
// Adjust the handles to accept varargs lists.
|
||||
MethodType type = target.type();
|
||||
Class<?> rtype = type.returnType();
|
||||
if (type.parameterCount() != 1 || type.parameterType(0).isPrimitive()) {
|
||||
MethodType vatestType = MethodType.make(boolean.class, Object[].class);
|
||||
MethodType vatargetType = MethodType.make(rtype, Object[].class);
|
||||
MethodHandle vaguard = makeGuardWithTest(token,
|
||||
MethodHandles.spreadArguments(test, vatestType),
|
||||
MethodHandles.spreadArguments(target, vatargetType),
|
||||
MethodHandles.spreadArguments(fallback, vatargetType));
|
||||
return MethodHandles.collectArguments(vaguard, type);
|
||||
int nargs = type.parameterCount();
|
||||
if (nargs < GuardWithTest.INVOKES.length) {
|
||||
MethodType gtype = type.generic();
|
||||
MethodHandle gtest = convertArguments(token, test, gtype.changeReturnType(boolean.class), test.type(), null);
|
||||
MethodHandle gtarget = convertArguments(token, target, gtype, type, null);
|
||||
MethodHandle gfallback = convertArguments(token, fallback, gtype, type, null);
|
||||
if (gtest == null || gtarget == null || gfallback == null) return null;
|
||||
MethodHandle gguard = new GuardWithTest(gtest, gtarget, gfallback);
|
||||
return convertArguments(token, gguard, type, gtype, null);
|
||||
} else {
|
||||
MethodType gtype = MethodType.genericMethodType(0, true);
|
||||
MethodHandle gtest = spreadArguments(token, test, gtype.changeReturnType(boolean.class), 0);
|
||||
MethodHandle gtarget = spreadArguments(token, target, gtype, 0);
|
||||
MethodHandle gfallback = spreadArguments(token, fallback, gtype, 0);
|
||||
MethodHandle gguard = new GuardWithTest(GuardWithTest.VARARGS_INVOKE, gtest, gtarget, gfallback);
|
||||
if (gtest == null || gtarget == null || gfallback == null) return null;
|
||||
return collectArguments(token, gguard, type, 0, null);
|
||||
}
|
||||
if (rtype.isPrimitive()) {
|
||||
MethodType boxtype = type.changeReturnType(Object.class);
|
||||
MethodHandle boxguard = makeGuardWithTest(token,
|
||||
test,
|
||||
MethodHandles.convertArguments(target, boxtype),
|
||||
MethodHandles.convertArguments(fallback, boxtype));
|
||||
return MethodHandles.convertArguments(boxguard, type);
|
||||
}
|
||||
|
||||
private static class GuardWithCatch extends JavaMethodHandle {
|
||||
private final MethodHandle target;
|
||||
private final Class<? extends Throwable> exType;
|
||||
private final MethodHandle catcher;
|
||||
public GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
|
||||
this(INVOKES[target.type().parameterCount()], target, exType, catcher);
|
||||
}
|
||||
// Got here? Reduced calling sequence to Object(Object).
|
||||
class Guarder {
|
||||
Object invoke(Object x) {
|
||||
// If javac supports MethodHandle.invoke directly:
|
||||
//z = vatest.invoke<boolean>(arguments);
|
||||
// If javac does not support direct MH.invoke calls:
|
||||
boolean z = (Boolean) MethodHandles.invoke_1(test, x);
|
||||
MethodHandle mh = (z ? target : fallback);
|
||||
return MethodHandles.invoke_1(mh, x);
|
||||
}
|
||||
MethodHandle handle() {
|
||||
MethodType invokeType = MethodType.makeGeneric(0, true);
|
||||
MethodHandle vh = IMPL_LOOKUP.bind(this, "invoke", invokeType);
|
||||
return MethodHandles.collectArguments(vh, target.type());
|
||||
public GuardWithCatch(MethodHandle invoker,
|
||||
MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
|
||||
super(invoker);
|
||||
this.target = target;
|
||||
this.exType = exType;
|
||||
this.catcher = catcher;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return target.toString();
|
||||
}
|
||||
private Object invoke_V(Object... av) throws Throwable {
|
||||
try {
|
||||
return target.<Object>invoke(av);
|
||||
} catch (Throwable t) {
|
||||
if (!exType.isInstance(t)) throw t;
|
||||
return catcher.<Object>invoke(t, av);
|
||||
}
|
||||
}
|
||||
return new Guarder().handle();
|
||||
private Object invoke_L0() throws Throwable {
|
||||
try {
|
||||
return target.<Object>invoke();
|
||||
} catch (Throwable t) {
|
||||
if (!exType.isInstance(t)) throw t;
|
||||
return catcher.<Object>invoke(t);
|
||||
}
|
||||
}
|
||||
private Object invoke_L1(Object a0) throws Throwable {
|
||||
try {
|
||||
return target.<Object>invoke(a0);
|
||||
} catch (Throwable t) {
|
||||
if (!exType.isInstance(t)) throw t;
|
||||
return catcher.<Object>invoke(t, a0);
|
||||
}
|
||||
}
|
||||
private Object invoke_L2(Object a0, Object a1) throws Throwable {
|
||||
try {
|
||||
return target.<Object>invoke(a0, a1);
|
||||
} catch (Throwable t) {
|
||||
if (!exType.isInstance(t)) throw t;
|
||||
return catcher.<Object>invoke(t, a0, a1);
|
||||
}
|
||||
}
|
||||
private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
|
||||
try {
|
||||
return target.<Object>invoke(a0, a1, a2);
|
||||
} catch (Throwable t) {
|
||||
if (!exType.isInstance(t)) throw t;
|
||||
return catcher.<Object>invoke(t, a0, a1, a2);
|
||||
}
|
||||
}
|
||||
private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
|
||||
try {
|
||||
return target.<Object>invoke(a0, a1, a2, a3);
|
||||
} catch (Throwable t) {
|
||||
if (!exType.isInstance(t)) throw t;
|
||||
return catcher.<Object>invoke(t, a0, a1, a2, a3);
|
||||
}
|
||||
}
|
||||
private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
|
||||
try {
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4);
|
||||
} catch (Throwable t) {
|
||||
if (!exType.isInstance(t)) throw t;
|
||||
return catcher.<Object>invoke(t, a0, a1, a2, a3, a4);
|
||||
}
|
||||
}
|
||||
private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
|
||||
try {
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5);
|
||||
} catch (Throwable t) {
|
||||
if (!exType.isInstance(t)) throw t;
|
||||
return catcher.<Object>invoke(t, a0, a1, a2, a3, a4, a5);
|
||||
}
|
||||
}
|
||||
private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
|
||||
try {
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6);
|
||||
} catch (Throwable t) {
|
||||
if (!exType.isInstance(t)) throw t;
|
||||
return catcher.<Object>invoke(t, a0, a1, a2, a3, a4, a5, a6);
|
||||
}
|
||||
}
|
||||
private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
|
||||
try {
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6, a7);
|
||||
} catch (Throwable t) {
|
||||
if (!exType.isInstance(t)) throw t;
|
||||
return catcher.<Object>invoke(t, a0, a1, a2, a3, a4, a5, a6, a7);
|
||||
}
|
||||
}
|
||||
static MethodHandle[] makeInvokes() {
|
||||
ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
|
||||
MethodHandles.Lookup lookup = IMPL_LOOKUP;
|
||||
for (;;) {
|
||||
int nargs = invokes.size();
|
||||
String name = "invoke_L"+nargs;
|
||||
MethodHandle invoke = null;
|
||||
try {
|
||||
invoke = lookup.findVirtual(GuardWithCatch.class, name, MethodType.genericMethodType(nargs));
|
||||
} catch (NoAccessException ex) {
|
||||
}
|
||||
if (invoke == null) break;
|
||||
invokes.add(invoke);
|
||||
}
|
||||
assert(invokes.size() == 9); // current number of methods
|
||||
return invokes.toArray(new MethodHandle[0]);
|
||||
};
|
||||
static final MethodHandle[] INVOKES = makeInvokes();
|
||||
// For testing use this:
|
||||
//static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
|
||||
static final MethodHandle VARARGS_INVOKE;
|
||||
static {
|
||||
try {
|
||||
VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true));
|
||||
} catch (NoAccessException ex) {
|
||||
throw new InternalError("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static
|
||||
MethodHandle makeGuardWithCatch(Access token,
|
||||
MethodHandle target,
|
||||
Class<? extends Throwable> exType,
|
||||
MethodHandle catcher) {
|
||||
Access.check(token);
|
||||
MethodType type = target.type();
|
||||
MethodType ctype = catcher.type();
|
||||
int nargs = type.parameterCount();
|
||||
if (nargs < GuardWithCatch.INVOKES.length) {
|
||||
MethodType gtype = type.generic();
|
||||
MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
|
||||
MethodHandle gtarget = convertArguments(token, target, gtype, type, null);
|
||||
MethodHandle gcatcher = convertArguments(token, catcher, gcatchType, ctype, null);
|
||||
MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
|
||||
if (gtarget == null || gcatcher == null || gguard == null) return null;
|
||||
return convertArguments(token, gguard, type, gtype, null);
|
||||
} else {
|
||||
MethodType gtype = MethodType.genericMethodType(0, true);
|
||||
MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
|
||||
MethodHandle gtarget = spreadArguments(token, target, gtype, 0);
|
||||
MethodHandle gcatcher = spreadArguments(token, catcher, gcatchType, 1);
|
||||
MethodHandle gguard = new GuardWithCatch(GuardWithCatch.VARARGS_INVOKE, gtarget, exType, gcatcher);
|
||||
if (gtarget == null || gcatcher == null || gguard == null) return null;
|
||||
return collectArguments(token, gguard, type, 0, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static
|
||||
MethodHandle combineArguments(Access token, MethodHandle target, MethodHandle checker, int pos) {
|
||||
MethodHandle throwException(Access token, MethodType type) {
|
||||
Access.check(token);
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
return AdapterMethodHandle.makeRetypeRaw(token, type, THROW_EXCEPTION);
|
||||
}
|
||||
|
||||
protected static String basicToString(MethodHandle target) {
|
||||
static final MethodHandle THROW_EXCEPTION
|
||||
= IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
|
||||
MethodType.methodType(Empty.class, Throwable.class));
|
||||
static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
|
||||
|
||||
public static String getNameString(Access token, MethodHandle target) {
|
||||
Access.check(token);
|
||||
MemberName name = null;
|
||||
if (target != null)
|
||||
name = MethodHandleNatives.getMethodName(target);
|
||||
@ -357,17 +1080,30 @@ public abstract class MethodHandleImpl {
|
||||
return name.getName();
|
||||
}
|
||||
|
||||
protected static String addTypeString(MethodHandle target, String name) {
|
||||
if (target == null) return name;
|
||||
return name+target.type();
|
||||
}
|
||||
static RuntimeException newIllegalArgumentException(String string) {
|
||||
return new IllegalArgumentException(string);
|
||||
public static String addTypeString(MethodHandle target) {
|
||||
if (target == null) return "null";
|
||||
return target.toString() + target.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
MethodHandle self = (MethodHandle) this;
|
||||
return addTypeString(self, basicToString(self));
|
||||
public static void checkSpreadArgument(Object av, int n) {
|
||||
if (av == null ? n != 0 : ((Object[])av).length != n)
|
||||
throw newIllegalArgumentException("Array is not of length "+n);
|
||||
}
|
||||
|
||||
public static void raiseException(int code, Object actual, Object required) {
|
||||
String message;
|
||||
// disregard the identity of the actual object, if it is not a class:
|
||||
if (!(actual instanceof Class) && !(actual instanceof MethodType))
|
||||
actual = actual.getClass();
|
||||
if (actual != null)
|
||||
message = "required "+required+" but encountered "+actual;
|
||||
else
|
||||
message = "required "+required;
|
||||
switch (code) {
|
||||
case 192: // checkcast
|
||||
throw new ClassCastException(message);
|
||||
default:
|
||||
throw new InternalError("unexpected code "+code+": "+message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
package sun.dyn;
|
||||
|
||||
import java.dyn.CallSite;
|
||||
import java.dyn.MethodHandle;
|
||||
import java.dyn.MethodType;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
@ -60,7 +61,7 @@ class MethodHandleNatives {
|
||||
static native void init(MethodType self);
|
||||
|
||||
/** Tell the JVM that we need to change the target of an invokedynamic. */
|
||||
static native void linkCallSite(CallSiteImpl site, MethodHandle target);
|
||||
static native void linkCallSite(CallSite site, MethodHandle target);
|
||||
|
||||
/** Fetch the vmtarget field.
|
||||
* It will be sanitized as necessary to avoid exposing non-Java references.
|
||||
@ -84,8 +85,7 @@ class MethodHandleNatives {
|
||||
}
|
||||
|
||||
/** Fetch the target of this method handle.
|
||||
* If it directly targets a method, return a tuple of method info.
|
||||
* The info is of the form new Object[]{defclass, name, sig, refclass}.
|
||||
* If it directly targets a method, return a MemberName for the method.
|
||||
* If it is chained to another method handle, return that handle.
|
||||
*/
|
||||
static Object getTargetInfo(MethodHandle self) {
|
||||
@ -123,7 +123,7 @@ class MethodHandleNatives {
|
||||
registerNatives();
|
||||
JVM_SUPPORT_ = true;
|
||||
JVM_PUSH_LIMIT_ = getConstant(Constants.GC_JVM_PUSH_LIMIT);
|
||||
JVM_STACK_MOVE_UNIT_ = getConstant(Constants.GC_JVM_STACK_MOVE_LIMIT);
|
||||
JVM_STACK_MOVE_UNIT_ = getConstant(Constants.GC_JVM_STACK_MOVE_UNIT);
|
||||
//sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init");
|
||||
} catch (UnsatisfiedLinkError ee) {
|
||||
// ignore; if we use init() methods later we'll see linkage errors
|
||||
@ -149,7 +149,7 @@ class MethodHandleNatives {
|
||||
// MethodHandleImpl
|
||||
static final int // for getConstant
|
||||
GC_JVM_PUSH_LIMIT = 0,
|
||||
GC_JVM_STACK_MOVE_LIMIT = 1;
|
||||
GC_JVM_STACK_MOVE_UNIT = 1;
|
||||
static final int
|
||||
ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method)
|
||||
ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self)
|
||||
@ -178,19 +178,20 @@ class MethodHandleNatives {
|
||||
*/
|
||||
static final int
|
||||
OP_RETYPE_ONLY = 0x0, // no argument changes; straight retype
|
||||
OP_CHECK_CAST = 0x1, // ref-to-ref conversion; requires a Class argument
|
||||
OP_PRIM_TO_PRIM = 0x2, // converts from one primitive to another
|
||||
OP_REF_TO_PRIM = 0x3, // unboxes a wrapper to produce a primitive
|
||||
OP_PRIM_TO_REF = 0x4, // boxes a primitive into a wrapper (NYI)
|
||||
OP_SWAP_ARGS = 0x5, // swap arguments (vminfo is 2nd arg)
|
||||
OP_ROT_ARGS = 0x6, // rotate arguments (vminfo is displaced arg)
|
||||
OP_DUP_ARGS = 0x7, // duplicates one or more arguments (at TOS)
|
||||
OP_DROP_ARGS = 0x8, // remove one or more argument slots
|
||||
OP_COLLECT_ARGS = 0x9, // combine one or more arguments into a varargs (NYI)
|
||||
OP_SPREAD_ARGS = 0xA, // expand in place a varargs array (of known size)
|
||||
OP_FLYBY = 0xB, // operate first on reified argument list (NYI)
|
||||
OP_RICOCHET = 0xC, // run an adapter chain on the return value (NYI)
|
||||
CONV_OP_LIMIT = 0xD; // limit of CONV_OP enumeration
|
||||
OP_RETYPE_RAW = 0x1, // no argument changes; straight retype
|
||||
OP_CHECK_CAST = 0x2, // ref-to-ref conversion; requires a Class argument
|
||||
OP_PRIM_TO_PRIM = 0x3, // converts from one primitive to another
|
||||
OP_REF_TO_PRIM = 0x4, // unboxes a wrapper to produce a primitive
|
||||
OP_PRIM_TO_REF = 0x5, // boxes a primitive into a wrapper (NYI)
|
||||
OP_SWAP_ARGS = 0x6, // swap arguments (vminfo is 2nd arg)
|
||||
OP_ROT_ARGS = 0x7, // rotate arguments (vminfo is displaced arg)
|
||||
OP_DUP_ARGS = 0x8, // duplicates one or more arguments (at TOS)
|
||||
OP_DROP_ARGS = 0x9, // remove one or more argument slots
|
||||
OP_COLLECT_ARGS = 0xA, // combine one or more arguments into a varargs (NYI)
|
||||
OP_SPREAD_ARGS = 0xB, // expand in place a varargs array (of known size)
|
||||
OP_FLYBY = 0xC, // operate first on reified argument list (NYI)
|
||||
OP_RICOCHET = 0xD, // run an adapter chain on the return value (NYI)
|
||||
CONV_OP_LIMIT = 0xE; // limit of CONV_OP enumeration
|
||||
/** Shift and mask values for decoding the AMH.conversion field.
|
||||
* These numbers are shared with the JVM for creating AMHs.
|
||||
*/
|
||||
@ -209,6 +210,7 @@ class MethodHandleNatives {
|
||||
// TODO: The following expression should be replaced by
|
||||
// a JVM query.
|
||||
((1<<OP_RETYPE_ONLY)
|
||||
|(1<<OP_RETYPE_RAW)
|
||||
|(1<<OP_CHECK_CAST)
|
||||
|(1<<OP_PRIM_TO_PRIM)
|
||||
|(1<<OP_REF_TO_PRIM)
|
||||
@ -216,6 +218,7 @@ class MethodHandleNatives {
|
||||
|(1<<OP_ROT_ARGS)
|
||||
|(1<<OP_DUP_ARGS)
|
||||
|(1<<OP_DROP_ARGS)
|
||||
//|(1<<OP_SPREAD_ARGS) // FIXME: Check JVM assembly code.
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@ -27,6 +27,7 @@ package sun.dyn;
|
||||
|
||||
import java.dyn.*;
|
||||
import sun.dyn.util.Wrapper;
|
||||
import static sun.dyn.MemberName.newIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Shared information for a group of method types, which differ
|
||||
@ -56,8 +57,8 @@ public class MethodTypeImpl {
|
||||
// Cached adapter information:
|
||||
/*lazy*/ ToGeneric toGeneric; // convert cs. with prims to w/o
|
||||
/*lazy*/ FromGeneric fromGeneric; // convert cs. w/o prims to with
|
||||
/*lazy*/ SpreadGeneric[] spreadGeneric; // expand one argument to many
|
||||
/*lazy*/ FilterGeneric filterGeneric; // convert argument(s) on the fly
|
||||
///*lazy*/ Invokers invokers; // cache of handy higher-order adapters
|
||||
|
||||
public MethodType erasedType() {
|
||||
return erasedType;
|
||||
@ -68,7 +69,7 @@ public class MethodTypeImpl {
|
||||
}
|
||||
|
||||
/** Access methods for the internals of MethodType, supplied to
|
||||
* MethodTypeForm as a trusted agent.
|
||||
* MethodTypeImpl as a trusted agent.
|
||||
*/
|
||||
static public interface MethodTypeFriend {
|
||||
Class<?>[] ptypes(MethodType mt);
|
||||
@ -150,7 +151,7 @@ public class MethodTypeImpl {
|
||||
this.argToSlotTable = argToSlotTab;
|
||||
this.slotToArgTable = slotToArgTab;
|
||||
|
||||
if (pslotCount >= 256) throw new IllegalArgumentException("too many arguments");
|
||||
if (pslotCount >= 256) throw newIllegalArgumentException("too many arguments");
|
||||
|
||||
// send a few bits down to the JVM:
|
||||
this.vmslots = parameterSlotCount();
|
||||
@ -378,10 +379,10 @@ public class MethodTypeImpl {
|
||||
static MethodTypeImpl findForm(MethodType mt) {
|
||||
MethodType erased = canonicalize(mt, ERASE, ERASE);
|
||||
if (erased == null) {
|
||||
// It is already erased. Make a new MethodTypeForm.
|
||||
// It is already erased. Make a new MethodTypeImpl.
|
||||
return METHOD_TYPE_FRIEND.newMethodTypeForm(mt);
|
||||
} else {
|
||||
// Share the MethodTypeForm with the erased version.
|
||||
// Share the MethodTypeImpl with the erased version.
|
||||
return METHOD_TYPE_FRIEND.form(erased);
|
||||
}
|
||||
}
|
||||
|
||||
682
jdk/src/share/classes/sun/dyn/SpreadGeneric.java
Normal file
682
jdk/src/share/classes/sun/dyn/SpreadGeneric.java
Normal file
@ -0,0 +1,682 @@
|
||||
/*
|
||||
* Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package sun.dyn;
|
||||
|
||||
import java.dyn.JavaMethodHandle;
|
||||
import java.dyn.MethodHandle;
|
||||
import java.dyn.MethodHandles;
|
||||
import java.dyn.MethodType;
|
||||
import java.dyn.NoAccessException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import sun.dyn.util.ValueConversions;
|
||||
import static sun.dyn.MemberName.newIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Generic spread adapter.
|
||||
* Expands a final argument into multiple (zero or more) arguments, keeping the others the same.
|
||||
* @author jrose
|
||||
*/
|
||||
class SpreadGeneric {
|
||||
// type for the outgoing call
|
||||
private final MethodType targetType;
|
||||
// number of arguments to spread
|
||||
private final int spreadCount;
|
||||
// prototype adapter (clone and customize for each new target!)
|
||||
private final Adapter adapter;
|
||||
// entry point for adapter (Adapter mh, a...) => ...
|
||||
private final MethodHandle entryPoint;
|
||||
|
||||
/** Compute and cache information common to all spreading adapters
|
||||
* that accept calls of the given (generic) type.
|
||||
*/
|
||||
private SpreadGeneric(MethodType targetType, int spreadCount) {
|
||||
assert(targetType == targetType.generic());
|
||||
this.targetType = targetType;
|
||||
this.spreadCount = spreadCount;
|
||||
// the target invoker will generally need casts on reference arguments
|
||||
MethodHandle[] ep = { null };
|
||||
Adapter ad = findAdapter(this, ep);
|
||||
if (ad != null) {
|
||||
this.adapter = ad;
|
||||
this.entryPoint = ep[0];
|
||||
return;
|
||||
}
|
||||
this.adapter = buildAdapterFromBytecodes(targetType, spreadCount, ep);
|
||||
this.entryPoint = ep[0];
|
||||
}
|
||||
|
||||
/** From targetType remove the last spreadCount arguments, and instead
|
||||
* append a simple Object argument.
|
||||
*/
|
||||
static MethodType preSpreadType(MethodType targetType, int spreadCount) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<Class<?>> params = new ArrayList(targetType.parameterList());
|
||||
int outargs = params.size();
|
||||
params.subList(outargs - spreadCount, outargs).clear();
|
||||
params.add(Object.class);
|
||||
return MethodType.methodType(targetType.returnType(), params);
|
||||
}
|
||||
|
||||
MethodHandle makeInstance(MethodHandle target) {
|
||||
MethodType type = target.type();
|
||||
if (type != targetType) {
|
||||
throw new UnsupportedOperationException("NYI type="+type);
|
||||
}
|
||||
return adapter.makeInstance(this, target);
|
||||
}
|
||||
|
||||
/** Build an adapter of the given generic type, which invokes typedTarget
|
||||
* on the incoming arguments, after unboxing as necessary.
|
||||
* The return value is boxed if necessary.
|
||||
* @param genericType the required type of the result
|
||||
* @param typedTarget the target
|
||||
* @return an adapter method handle
|
||||
*/
|
||||
public static MethodHandle make(MethodHandle target, int spreadCount) {
|
||||
MethodType type = target.type();
|
||||
MethodType gtype = type.generic();
|
||||
if (type == gtype) {
|
||||
return SpreadGeneric.of(type, spreadCount).makeInstance(target);
|
||||
} else {
|
||||
MethodHandle gtarget = FromGeneric.make(target);
|
||||
assert(gtarget.type() == gtype);
|
||||
MethodHandle gspread = SpreadGeneric.of(gtype, spreadCount).makeInstance(gtarget);
|
||||
return ToGeneric.make(preSpreadType(type, spreadCount), gspread);
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the adapter information for this type's erasure. */
|
||||
static SpreadGeneric of(MethodType targetType, int spreadCount) {
|
||||
if (targetType != targetType.generic())
|
||||
throw new UnsupportedOperationException("NYI type="+targetType);
|
||||
MethodTypeImpl form = MethodTypeImpl.of(targetType);
|
||||
int outcount = form.parameterCount();
|
||||
assert(spreadCount <= outcount);
|
||||
SpreadGeneric[] spreadGens = form.spreadGeneric;
|
||||
if (spreadGens == null)
|
||||
form.spreadGeneric = spreadGens = new SpreadGeneric[outcount+1];
|
||||
SpreadGeneric spreadGen = spreadGens[spreadCount];
|
||||
if (spreadGen == null)
|
||||
spreadGens[spreadCount] = spreadGen = new SpreadGeneric(form.erasedType(), spreadCount);
|
||||
return spreadGen;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getClass().getSimpleName()+targetType+"["+spreadCount+"]";
|
||||
}
|
||||
|
||||
// This mini-api is called from an Adapter to manage the spread.
|
||||
/** A check/coercion that happens once before any selections. */
|
||||
protected Object check(Object av, int n) {
|
||||
MethodHandleImpl.checkSpreadArgument(av, n);
|
||||
return av;
|
||||
}
|
||||
|
||||
/** The selection operator for spreading; note that it takes Object not Object[]. */
|
||||
protected Object select(Object av, int n) {
|
||||
return ((Object[])av)[n];
|
||||
}
|
||||
/*
|
||||
protected int select_I(Object av, int n) {
|
||||
// maybe return ((int[])select)[n]
|
||||
throw new UnsupportedOperationException("subclass resp.");
|
||||
}
|
||||
protected int select_J(Object av, int n) {
|
||||
// maybe return ((long[])select)[n]
|
||||
throw new UnsupportedOperationException("subclass resp.");
|
||||
}
|
||||
// */
|
||||
|
||||
/* Create an adapter that handles spreading calls for the given type. */
|
||||
static Adapter findAdapter(SpreadGeneric outer, MethodHandle[] ep) {
|
||||
MethodType targetType = outer.targetType;
|
||||
int spreadCount = outer.spreadCount;
|
||||
int outargs = targetType.parameterCount();
|
||||
int inargs = outargs - spreadCount;
|
||||
if (inargs < 0) return null;
|
||||
MethodType entryType = MethodType.genericMethodType(inargs + 1); // 1 for av
|
||||
String cname1 = "S" + outargs;
|
||||
String[] cnames = { cname1 };
|
||||
String iname = "invoke_S"+spreadCount;
|
||||
// e.g., D5I2, D5, L5I2, L5; invoke_D5
|
||||
for (String cname : cnames) {
|
||||
Class<? extends Adapter> acls = Adapter.findSubClass(cname);
|
||||
if (acls == null) continue;
|
||||
// see if it has the required invoke method
|
||||
MethodHandle entryPoint = null;
|
||||
try {
|
||||
entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
|
||||
} catch (NoAccessException ex) {
|
||||
}
|
||||
if (entryPoint == null) continue;
|
||||
Constructor<? extends Adapter> ctor = null;
|
||||
try {
|
||||
ctor = acls.getDeclaredConstructor(SpreadGeneric.class);
|
||||
} catch (NoSuchMethodException ex) {
|
||||
} catch (SecurityException ex) {
|
||||
}
|
||||
if (ctor == null) continue;
|
||||
try {
|
||||
// Produce an instance configured as a prototype.
|
||||
Adapter ad = ctor.newInstance(outer);
|
||||
ep[0] = entryPoint;
|
||||
return ad;
|
||||
} catch (IllegalArgumentException ex) {
|
||||
} catch (InvocationTargetException wex) {
|
||||
Throwable ex = wex.getTargetException();
|
||||
if (ex instanceof Error) throw (Error)ex;
|
||||
if (ex instanceof RuntimeException) throw (RuntimeException)ex;
|
||||
} catch (InstantiationException ex) {
|
||||
} catch (IllegalAccessException ex) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static Adapter buildAdapterFromBytecodes(MethodType targetType,
|
||||
int spreadCount, MethodHandle[] ep) {
|
||||
throw new UnsupportedOperationException("NYI");
|
||||
}
|
||||
|
||||
/**
|
||||
* This adapter takes some untyped arguments, and returns an untyped result.
|
||||
* Internally, it applies the invoker to the target, which causes the
|
||||
* objects to be unboxed; the result is a raw type in L/I/J/F/D.
|
||||
* This result is passed to convert, which is responsible for
|
||||
* converting the raw result into a boxed object.
|
||||
* The invoker is kept separate from the target because it can be
|
||||
* generated once per type erasure family, and reused across adapters.
|
||||
*/
|
||||
static abstract class Adapter extends JavaMethodHandle {
|
||||
/*
|
||||
* class X<<R,int M,int N>> extends Adapter {
|
||||
* (Object**N)=>R target;
|
||||
* static int S = N-M;
|
||||
* Object invoke(Object**M a, Object v) = target(a..., v[0]...v[S-1]);
|
||||
* }
|
||||
*/
|
||||
protected final SpreadGeneric outer;
|
||||
protected final MethodHandle target; // (any**N) => R
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return target.toString();
|
||||
}
|
||||
|
||||
static final MethodHandle NO_ENTRY = ValueConversions.identity();
|
||||
|
||||
protected boolean isPrototype() { return target == null; }
|
||||
protected Adapter(SpreadGeneric outer) {
|
||||
super(NO_ENTRY);
|
||||
this.outer = outer;
|
||||
this.target = null;
|
||||
assert(isPrototype());
|
||||
}
|
||||
|
||||
protected Adapter(SpreadGeneric outer, MethodHandle target) {
|
||||
super(outer.entryPoint);
|
||||
this.outer = outer;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/** Make a copy of self, with new fields. */
|
||||
protected abstract Adapter makeInstance(SpreadGeneric outer, MethodHandle target);
|
||||
// { return new ThisType(outer, target); }
|
||||
|
||||
protected Object check(Object av, int n) {
|
||||
return outer.check(av, n);
|
||||
}
|
||||
protected Object select(Object av, int n) {
|
||||
return outer.select(av, n);
|
||||
}
|
||||
|
||||
static private final String CLASS_PREFIX; // "sun.dyn.SpreadGeneric$"
|
||||
static {
|
||||
String aname = Adapter.class.getName();
|
||||
String sname = Adapter.class.getSimpleName();
|
||||
if (!aname.endsWith(sname)) throw new InternalError();
|
||||
CLASS_PREFIX = aname.substring(0, aname.length() - sname.length());
|
||||
}
|
||||
/** Find a sibing class of Adapter. */
|
||||
static Class<? extends Adapter> findSubClass(String name) {
|
||||
String cname = Adapter.CLASS_PREFIX + name;
|
||||
try {
|
||||
return Class.forName(cname).asSubclass(Adapter.class);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
return null;
|
||||
} catch (ClassCastException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* generated classes follow this pattern:
|
||||
static class xS2 extends Adapter {
|
||||
protected xS2(SpreadGeneric outer) { super(outer); } // to build prototype
|
||||
protected xS2(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||
protected xS2 makeInstance(SpreadGeneric outer, MethodHandle t) { return new xS2(outer, t); }
|
||||
protected Object invoke_S0(Object a0, Object a1, Object av) throws Throwable { av = super.check(av,0);
|
||||
return target.<Object>invoke(a0, a1)); }
|
||||
protected Object invoke_S1(Object a0, Object av) throws Throwable { av = super.check(av,1);
|
||||
return target.<Object>invoke(a0,
|
||||
super.select(av,0)); }
|
||||
protected Object invoke_S2(Object a0, Object av) throws Throwable { av = super.check(av,1);
|
||||
return target.<Object>invoke(
|
||||
super.select(av,0), super.select(av,1)); }
|
||||
}
|
||||
// */
|
||||
|
||||
/*
|
||||
: SHELL; n=SpreadGeneric; cp -p $n.java $n.java-; sed < $n.java- > $n.java+ -e '/{{*{{/,/}}*}}/w /tmp/genclasses.java' -e '/}}*}}/q'; (cd /tmp; javac -d . genclasses.java; java -cp . genclasses) >> $n.java+; echo '}' >> $n.java+; mv $n.java+ $n.java; mv $n.java- $n.java~
|
||||
//{{{
|
||||
import java.util.*;
|
||||
class genclasses {
|
||||
static String[][] TEMPLATES = { {
|
||||
"@for@ N=0..10",
|
||||
" //@each-cat@",
|
||||
" static class @cat@ extends Adapter {",
|
||||
" protected @cat@(SpreadGeneric outer) { super(outer); } // to build prototype",
|
||||
" protected @cat@(SpreadGeneric outer, MethodHandle t) { super(outer, t); }",
|
||||
" protected @cat@ makeInstance(SpreadGeneric outer, MethodHandle t) { return new @cat@(outer, t); }",
|
||||
" protected Object invoke_S0(@Tvav,@Object av) throws Throwable { av = super.check(av, 0);",
|
||||
" return target.<Object>invoke(@av@); }",
|
||||
" //@each-S@",
|
||||
" protected Object invoke_S@S@(@Tvav,@Object av) throws Throwable { av = super.check(av, @S@);",
|
||||
" return target.<Object>invoke(@av,@@sv@); }",
|
||||
" //@end-S@",
|
||||
" }",
|
||||
} };
|
||||
static final String NEWLINE_INDENT = "\n ";
|
||||
enum VAR {
|
||||
cat, N, S, av, av_, Tvav_, sv;
|
||||
public final String pattern = "@"+toString().replace('_','.')+"@";
|
||||
public String binding = toString();
|
||||
static void makeBindings(boolean topLevel, int outargs, int spread) {
|
||||
int inargs = outargs - spread;
|
||||
VAR.cat.binding = "S"+outargs;
|
||||
VAR.N.binding = String.valueOf(outargs); // outgoing arg count
|
||||
VAR.S.binding = String.valueOf(spread); // spread count
|
||||
String[] av = new String[inargs];
|
||||
String[] Tvav = new String[inargs];
|
||||
for (int i = 0; i < inargs; i++) {
|
||||
av[i] = arg(i);
|
||||
Tvav[i] = param("Object", av[i]);
|
||||
}
|
||||
VAR.av.binding = comma(av);
|
||||
VAR.av_.binding = comma(av, ", ");
|
||||
VAR.Tvav_.binding = comma(Tvav, ", ");
|
||||
String[] sv = new String[spread];
|
||||
for (int i = 0; i < spread; i++) {
|
||||
String spc = "";
|
||||
if (i % 4 == 0) spc = NEWLINE_INDENT;
|
||||
sv[i] = spc+"super.select(av,"+i+")";
|
||||
}
|
||||
VAR.sv.binding = comma(sv);
|
||||
}
|
||||
static String arg(int i) { return "a"+i; }
|
||||
static String param(String t, String a) { return t+" "+a; }
|
||||
static String comma(String[] v) { return comma(v, ""); }
|
||||
static String comma(String[] v, String sep) {
|
||||
if (v.length == 0) return "";
|
||||
String res = v[0];
|
||||
for (int i = 1; i < v.length; i++) res += ", "+v[i];
|
||||
return res + sep;
|
||||
}
|
||||
static String transform(String string) {
|
||||
for (VAR var : values())
|
||||
string = string.replaceAll(var.pattern, var.binding);
|
||||
return string;
|
||||
}
|
||||
}
|
||||
static String[] stringsIn(String[] strings, int beg, int end) {
|
||||
return Arrays.copyOfRange(strings, beg, Math.min(end, strings.length));
|
||||
}
|
||||
static String[] stringsBefore(String[] strings, int pos) {
|
||||
return stringsIn(strings, 0, pos);
|
||||
}
|
||||
static String[] stringsAfter(String[] strings, int pos) {
|
||||
return stringsIn(strings, pos, strings.length);
|
||||
}
|
||||
static int indexAfter(String[] strings, int pos, String tag) {
|
||||
return Math.min(indexBefore(strings, pos, tag) + 1, strings.length);
|
||||
}
|
||||
static int indexBefore(String[] strings, int pos, String tag) {
|
||||
for (int i = pos, end = strings.length; ; i++) {
|
||||
if (i == end || strings[i].endsWith(tag)) return i;
|
||||
}
|
||||
}
|
||||
static int MIN_ARITY, MAX_ARITY;
|
||||
public static void main(String... av) {
|
||||
for (String[] template : TEMPLATES) {
|
||||
int forLinesLimit = indexBefore(template, 0, "@each-cat@");
|
||||
String[] forLines = stringsBefore(template, forLinesLimit);
|
||||
template = stringsAfter(template, forLinesLimit);
|
||||
for (String forLine : forLines)
|
||||
expandTemplate(forLine, template);
|
||||
}
|
||||
}
|
||||
static void expandTemplate(String forLine, String[] template) {
|
||||
String[] params = forLine.split("[^0-9]+");
|
||||
if (params[0].length() == 0) params = stringsAfter(params, 1);
|
||||
System.out.println("//params="+Arrays.asList(params));
|
||||
int pcur = 0;
|
||||
MIN_ARITY = Integer.valueOf(params[pcur++]);
|
||||
MAX_ARITY = Integer.valueOf(params[pcur++]);
|
||||
if (pcur != params.length) throw new RuntimeException("bad extra param: "+forLine);
|
||||
for (int outargs = MIN_ARITY; outargs <= MAX_ARITY; outargs++) {
|
||||
expandTemplate(template, true, outargs, 0);
|
||||
}
|
||||
}
|
||||
static void expandTemplate(String[] template, boolean topLevel, int outargs, int spread) {
|
||||
VAR.makeBindings(topLevel, outargs, spread);
|
||||
for (int i = 0; i < template.length; i++) {
|
||||
String line = template[i];
|
||||
if (line.endsWith("@each-cat@")) {
|
||||
// ignore
|
||||
} else if (line.endsWith("@each-S@")) {
|
||||
int blockEnd = indexAfter(template, i, "@end-S@");
|
||||
String[] block = stringsIn(template, i+1, blockEnd-1);
|
||||
for (int spread1 = spread+1; spread1 <= outargs; spread1++)
|
||||
expandTemplate(block, false, outargs, spread1);
|
||||
VAR.makeBindings(topLevel, outargs, spread);
|
||||
i = blockEnd-1; continue;
|
||||
} else {
|
||||
System.out.println(VAR.transform(line));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//}}} */
|
||||
//params=[0, 10]
|
||||
static class S0 extends Adapter {
|
||||
protected S0(SpreadGeneric outer) { super(outer); } // to build prototype
|
||||
protected S0(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||
protected S0 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S0(outer, t); }
|
||||
protected Object invoke_S0(Object av) throws Throwable { av = super.check(av, 0);
|
||||
return target.<Object>invoke(); }
|
||||
}
|
||||
static class S1 extends Adapter {
|
||||
protected S1(SpreadGeneric outer) { super(outer); } // to build prototype
|
||||
protected S1(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||
protected S1 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S1(outer, t); }
|
||||
protected Object invoke_S0(Object a0, Object av) throws Throwable { av = super.check(av, 0);
|
||||
return target.<Object>invoke(a0); }
|
||||
protected Object invoke_S1(Object av) throws Throwable { av = super.check(av, 1);
|
||||
return target.<Object>invoke(
|
||||
super.select(av,0)); }
|
||||
}
|
||||
static class S2 extends Adapter {
|
||||
protected S2(SpreadGeneric outer) { super(outer); } // to build prototype
|
||||
protected S2(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||
protected S2 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S2(outer, t); }
|
||||
protected Object invoke_S0(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 0);
|
||||
return target.<Object>invoke(a0, a1); }
|
||||
protected Object invoke_S1(Object a0, Object av) throws Throwable { av = super.check(av, 1);
|
||||
return target.<Object>invoke(a0,
|
||||
super.select(av,0)); }
|
||||
protected Object invoke_S2(Object av) throws Throwable { av = super.check(av, 2);
|
||||
return target.<Object>invoke(
|
||||
super.select(av,0), super.select(av,1)); }
|
||||
}
|
||||
static class S3 extends Adapter {
|
||||
protected S3(SpreadGeneric outer) { super(outer); } // to build prototype
|
||||
protected S3(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||
protected S3 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S3(outer, t); }
|
||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 0);
|
||||
return target.<Object>invoke(a0, a1, a2); }
|
||||
protected Object invoke_S1(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 1);
|
||||
return target.<Object>invoke(a0, a1,
|
||||
super.select(av,0)); }
|
||||
protected Object invoke_S2(Object a0, Object av) throws Throwable { av = super.check(av, 2);
|
||||
return target.<Object>invoke(a0,
|
||||
super.select(av,0), super.select(av,1)); }
|
||||
protected Object invoke_S3(Object av) throws Throwable { av = super.check(av, 3);
|
||||
return target.<Object>invoke(
|
||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||
}
|
||||
static class S4 extends Adapter {
|
||||
protected S4(SpreadGeneric outer) { super(outer); } // to build prototype
|
||||
protected S4(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||
protected S4 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S4(outer, t); }
|
||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 0);
|
||||
return target.<Object>invoke(a0, a1, a2, a3); }
|
||||
protected Object invoke_S1(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 1);
|
||||
return target.<Object>invoke(a0, a1, a2,
|
||||
super.select(av,0)); }
|
||||
protected Object invoke_S2(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 2);
|
||||
return target.<Object>invoke(a0, a1,
|
||||
super.select(av,0), super.select(av,1)); }
|
||||
protected Object invoke_S3(Object a0, Object av) throws Throwable { av = super.check(av, 3);
|
||||
return target.<Object>invoke(a0,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||
protected Object invoke_S4(Object av) throws Throwable { av = super.check(av, 4);
|
||||
return target.<Object>invoke(
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
||||
}
|
||||
static class S5 extends Adapter {
|
||||
protected S5(SpreadGeneric outer) { super(outer); } // to build prototype
|
||||
protected S5(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||
protected S5 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S5(outer, t); }
|
||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 0);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4); }
|
||||
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 1);
|
||||
return target.<Object>invoke(a0, a1, a2, a3,
|
||||
super.select(av,0)); }
|
||||
protected Object invoke_S2(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 2);
|
||||
return target.<Object>invoke(a0, a1, a2,
|
||||
super.select(av,0), super.select(av,1)); }
|
||||
protected Object invoke_S3(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 3);
|
||||
return target.<Object>invoke(a0, a1,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||
protected Object invoke_S4(Object a0, Object av) throws Throwable { av = super.check(av, 4);
|
||||
return target.<Object>invoke(a0,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
||||
protected Object invoke_S5(Object av) throws Throwable { av = super.check(av, 5);
|
||||
return target.<Object>invoke(
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4)); }
|
||||
}
|
||||
static class S6 extends Adapter {
|
||||
protected S6(SpreadGeneric outer) { super(outer); } // to build prototype
|
||||
protected S6(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||
protected S6 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S6(outer, t); }
|
||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 0);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5); }
|
||||
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 1);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4,
|
||||
super.select(av,0)); }
|
||||
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 2);
|
||||
return target.<Object>invoke(a0, a1, a2, a3,
|
||||
super.select(av,0), super.select(av,1)); }
|
||||
protected Object invoke_S3(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 3);
|
||||
return target.<Object>invoke(a0, a1, a2,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||
protected Object invoke_S4(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 4);
|
||||
return target.<Object>invoke(a0, a1,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
||||
protected Object invoke_S5(Object a0, Object av) throws Throwable { av = super.check(av, 5);
|
||||
return target.<Object>invoke(a0,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4)); }
|
||||
protected Object invoke_S6(Object av) throws Throwable { av = super.check(av, 6);
|
||||
return target.<Object>invoke(
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4), super.select(av,5)); }
|
||||
}
|
||||
static class S7 extends Adapter {
|
||||
protected S7(SpreadGeneric outer) { super(outer); } // to build prototype
|
||||
protected S7(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||
protected S7 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S7(outer, t); }
|
||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 0);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6); }
|
||||
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 1);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5,
|
||||
super.select(av,0)); }
|
||||
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 2);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4,
|
||||
super.select(av,0), super.select(av,1)); }
|
||||
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 3);
|
||||
return target.<Object>invoke(a0, a1, a2, a3,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||
protected Object invoke_S4(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 4);
|
||||
return target.<Object>invoke(a0, a1, a2,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
||||
protected Object invoke_S5(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 5);
|
||||
return target.<Object>invoke(a0, a1,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4)); }
|
||||
protected Object invoke_S6(Object a0, Object av) throws Throwable { av = super.check(av, 6);
|
||||
return target.<Object>invoke(a0,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4), super.select(av,5)); }
|
||||
protected Object invoke_S7(Object av) throws Throwable { av = super.check(av, 7);
|
||||
return target.<Object>invoke(
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4), super.select(av,5), super.select(av,6)); }
|
||||
}
|
||||
static class S8 extends Adapter {
|
||||
protected S8(SpreadGeneric outer) { super(outer); } // to build prototype
|
||||
protected S8(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||
protected S8 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S8(outer, t); }
|
||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object av) throws Throwable { av = super.check(av, 0);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6, a7); }
|
||||
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 1);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6,
|
||||
super.select(av,0)); }
|
||||
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 2);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5,
|
||||
super.select(av,0), super.select(av,1)); }
|
||||
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 3);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||
protected Object invoke_S4(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 4);
|
||||
return target.<Object>invoke(a0, a1, a2, a3,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
||||
protected Object invoke_S5(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 5);
|
||||
return target.<Object>invoke(a0, a1, a2,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4)); }
|
||||
protected Object invoke_S6(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 6);
|
||||
return target.<Object>invoke(a0, a1,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4), super.select(av,5)); }
|
||||
protected Object invoke_S7(Object a0, Object av) throws Throwable { av = super.check(av, 7);
|
||||
return target.<Object>invoke(a0,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4), super.select(av,5), super.select(av,6)); }
|
||||
protected Object invoke_S8(Object av) throws Throwable { av = super.check(av, 8);
|
||||
return target.<Object>invoke(
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7)); }
|
||||
}
|
||||
static class S9 extends Adapter {
|
||||
protected S9(SpreadGeneric outer) { super(outer); } // to build prototype
|
||||
protected S9(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||
protected S9 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S9(outer, t); }
|
||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object av) throws Throwable { av = super.check(av, 0);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
|
||||
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object av) throws Throwable { av = super.check(av, 1);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6, a7,
|
||||
super.select(av,0)); }
|
||||
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 2);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6,
|
||||
super.select(av,0), super.select(av,1)); }
|
||||
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 3);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||
protected Object invoke_S4(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 4);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
||||
protected Object invoke_S5(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 5);
|
||||
return target.<Object>invoke(a0, a1, a2, a3,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4)); }
|
||||
protected Object invoke_S6(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 6);
|
||||
return target.<Object>invoke(a0, a1, a2,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4), super.select(av,5)); }
|
||||
protected Object invoke_S7(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 7);
|
||||
return target.<Object>invoke(a0, a1,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4), super.select(av,5), super.select(av,6)); }
|
||||
protected Object invoke_S8(Object a0, Object av) throws Throwable { av = super.check(av, 8);
|
||||
return target.<Object>invoke(a0,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7)); }
|
||||
protected Object invoke_S9(Object av) throws Throwable { av = super.check(av, 9);
|
||||
return target.<Object>invoke(
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7),
|
||||
super.select(av,8)); }
|
||||
}
|
||||
static class S10 extends Adapter {
|
||||
protected S10(SpreadGeneric outer) { super(outer); } // to build prototype
|
||||
protected S10(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||
protected S10 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S10(outer, t); }
|
||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9, Object av) throws Throwable { av = super.check(av, 0);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
|
||||
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object av) throws Throwable { av = super.check(av, 1);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8,
|
||||
super.select(av,0)); }
|
||||
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object av) throws Throwable { av = super.check(av, 2);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6, a7,
|
||||
super.select(av,0), super.select(av,1)); }
|
||||
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 3);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||
protected Object invoke_S4(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 4);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4, a5,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
||||
protected Object invoke_S5(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 5);
|
||||
return target.<Object>invoke(a0, a1, a2, a3, a4,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4)); }
|
||||
protected Object invoke_S6(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 6);
|
||||
return target.<Object>invoke(a0, a1, a2, a3,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4), super.select(av,5)); }
|
||||
protected Object invoke_S7(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 7);
|
||||
return target.<Object>invoke(a0, a1, a2,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4), super.select(av,5), super.select(av,6)); }
|
||||
protected Object invoke_S8(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 8);
|
||||
return target.<Object>invoke(a0, a1,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7)); }
|
||||
protected Object invoke_S9(Object a0, Object av) throws Throwable { av = super.check(av, 9);
|
||||
return target.<Object>invoke(a0,
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7),
|
||||
super.select(av,8)); }
|
||||
protected Object invoke_S10(Object av) throws Throwable { av = super.check(av, 10);
|
||||
return target.<Object>invoke(
|
||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7),
|
||||
super.select(av,8), super.select(av,9)); }
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,10 @@ package sun.dyn.empty;
|
||||
* An empty class in an empty package.
|
||||
* Used as a proxy for unprivileged code, since making access checks
|
||||
* against it will only succeed against public methods in public types.
|
||||
* <p>
|
||||
* This class also stands (internally to sun.dyn) for the type of a
|
||||
* value that cannot be produced, because the expression of this type
|
||||
* always returns abnormally. (Cf. Nothing in the closures proposal.)
|
||||
* @author jrose
|
||||
*/
|
||||
public class Empty {
|
||||
|
||||
@ -33,9 +33,9 @@ import java.util.List;
|
||||
* Utility routines for dealing with bytecode-level signatures.
|
||||
* @author jrose
|
||||
*/
|
||||
public class BytecodeSignature {
|
||||
public class BytecodeDescriptor {
|
||||
|
||||
private BytecodeSignature() { } // cannot instantiate
|
||||
private BytecodeDescriptor() { } // cannot instantiate
|
||||
|
||||
public static List<Class<?>> parseMethod(String bytecodeSignature, ClassLoader loader) {
|
||||
return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader);
|
||||
@ -298,6 +298,8 @@ public class BytecodeName {
|
||||
* The name {@code <init>} will be parsed into { '<', "init", '>'}}
|
||||
* The name {@code foo/bar$:baz} will be parsed into
|
||||
* {@code {"foo", '/', "bar", '$', ':', "baz"}}.
|
||||
* The name {@code ::\=:foo:\=bar\!baz} will be parsed into
|
||||
* {@code {':', ':', "", ':', "foo", ':', "bar:baz"}}.
|
||||
*/
|
||||
public static Object[] parseBytecodeName(String s) {
|
||||
int slen = s.length();
|
||||
@ -315,7 +317,7 @@ public class BytecodeName {
|
||||
if (lasti < i) {
|
||||
// normal component
|
||||
if (pass != 0)
|
||||
res[fillp] = s.substring(lasti, i);
|
||||
res[fillp] = toSourceName(s.substring(lasti, i));
|
||||
fillp++;
|
||||
lasti = i+1;
|
||||
}
|
||||
@ -323,13 +325,14 @@ public class BytecodeName {
|
||||
if (pass != 0)
|
||||
res[fillp] = DANGEROUS_CHARS_CA[whichDC];
|
||||
fillp++;
|
||||
lasti = i+1;
|
||||
}
|
||||
}
|
||||
if (pass != 0) break;
|
||||
// between passes, build the result array
|
||||
res = new String[fillp];
|
||||
if (fillp <= 1) {
|
||||
if (fillp != 0) res[0] = s;
|
||||
res = new Object[fillp];
|
||||
if (fillp <= 1 && lasti == 0) {
|
||||
if (fillp != 0) res[0] = toSourceName(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -348,9 +351,19 @@ public class BytecodeName {
|
||||
* @throws NullPointerException if any component is null
|
||||
*/
|
||||
public static String unparseBytecodeName(Object[] components) {
|
||||
for (Object c : components) {
|
||||
if (c instanceof String)
|
||||
checkSafeBytecodeName((String) c); // may fail
|
||||
Object[] components0 = components;
|
||||
for (int i = 0; i < components.length; i++) {
|
||||
Object c = components[i];
|
||||
if (c instanceof String) {
|
||||
String mc = toBytecodeName((String) c);
|
||||
if (i == 0 && components.length == 1)
|
||||
return mc; // usual case
|
||||
if ((Object)mc != c) {
|
||||
if (components == components0)
|
||||
components = components.clone();
|
||||
components[i] = c = mc;
|
||||
}
|
||||
}
|
||||
}
|
||||
return appendAll(components);
|
||||
}
|
||||
@ -381,6 +394,14 @@ public class BytecodeName {
|
||||
* If the bytecode name contains dangerous characters,
|
||||
* assume that they are being used as punctuation,
|
||||
* and pass them through unchanged.
|
||||
* Non-empty runs of non-dangerous characters are demangled
|
||||
* if necessary, and the resulting names are quoted if
|
||||
* they are not already valid Java identifiers, or if
|
||||
* they contain a dangerous character (i.e., dollar sign "$").
|
||||
* Single quotes are used when quoting.
|
||||
* Within quoted names, embedded single quotes and backslashes
|
||||
* are further escaped by prepended backslashes.
|
||||
*
|
||||
* @param s the original bytecode name (which may be qualified)
|
||||
* @return a human-readable presentation
|
||||
*/
|
||||
@ -389,10 +410,10 @@ public class BytecodeName {
|
||||
for (int i = 0; i < components.length; i++) {
|
||||
if (!(components[i] instanceof String))
|
||||
continue;
|
||||
String c = (String) components[i];
|
||||
// pretty up the name by demangling it
|
||||
String sn = toSourceName(c);
|
||||
if ((Object)sn != c || !isJavaIdent(sn)) {
|
||||
String sn = (String) components[i];
|
||||
// note that the name is already demangled!
|
||||
//sn = toSourceName(sn);
|
||||
if (!isJavaIdent(sn) || sn.indexOf('$') >=0 ) {
|
||||
components[i] = quoteDisplay(sn);
|
||||
}
|
||||
}
|
||||
@ -401,10 +422,10 @@ public class BytecodeName {
|
||||
private static boolean isJavaIdent(String s) {
|
||||
int slen = s.length();
|
||||
if (slen == 0) return false;
|
||||
if (!Character.isUnicodeIdentifierStart(s.charAt(0)))
|
||||
if (!Character.isJavaIdentifierStart(s.charAt(0)))
|
||||
return false;
|
||||
for (int i = 1; i < slen; i++) {
|
||||
if (!Character.isUnicodeIdentifierPart(s.charAt(0)))
|
||||
if (!Character.isJavaIdentifierPart(s.charAt(i)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -602,110 +623,5 @@ public class BytecodeName {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// test driver
|
||||
static void main(String[] av) {
|
||||
// If verbose is enabled, quietly check everything.
|
||||
// Otherwise, print the output for the user to check.
|
||||
boolean verbose = false;
|
||||
|
||||
int maxlen = 0;
|
||||
|
||||
while (av.length > 0 && av[0].startsWith("-")) {
|
||||
String flag = av[0].intern();
|
||||
av = java.util.Arrays.copyOfRange(av, 1, av.length); // Java 1.6 or later
|
||||
if (flag == "-" || flag == "--") break;
|
||||
else if (flag == "-q")
|
||||
verbose = false;
|
||||
else if (flag == "-v")
|
||||
verbose = true;
|
||||
else if (flag.startsWith("-l"))
|
||||
maxlen = Integer.valueOf(flag.substring(2));
|
||||
else
|
||||
throw new Error("Illegal flag argument: "+flag);
|
||||
}
|
||||
|
||||
if (maxlen == 0)
|
||||
maxlen = (verbose ? 2 : 4);
|
||||
if (verbose) System.out.println("Note: maxlen = "+maxlen);
|
||||
|
||||
switch (av.length) {
|
||||
case 0: av = new String[] {
|
||||
DANGEROUS_CHARS.substring(0) +
|
||||
REPLACEMENT_CHARS.substring(0, 1) +
|
||||
NULL_ESCAPE + "x"
|
||||
}; // and fall through:
|
||||
case 1:
|
||||
char[] cv = av[0].toCharArray();
|
||||
av = new String[cv.length];
|
||||
int avp = 0;
|
||||
for (char c : cv) {
|
||||
String s = String.valueOf(c);
|
||||
if (c == 'x') s = "foo"; // tradition...
|
||||
av[avp++] = s;
|
||||
}
|
||||
}
|
||||
if (verbose)
|
||||
System.out.println("Note: Verbose output mode enabled. Use '-q' to suppress.");
|
||||
Tester t = new Tester();
|
||||
t.maxlen = maxlen;
|
||||
t.verbose = verbose;
|
||||
t.tokens = av;
|
||||
t.test("", 0);
|
||||
}
|
||||
|
||||
static class Tester {
|
||||
boolean verbose;
|
||||
int maxlen;
|
||||
java.util.Map<String,String> map = new java.util.HashMap<String,String>();
|
||||
String[] tokens;
|
||||
|
||||
void test(String stringSoFar, int tokensSoFar) {
|
||||
test(stringSoFar);
|
||||
if (tokensSoFar <= maxlen) {
|
||||
for (String token : tokens) {
|
||||
if (token.length() == 0) continue; // skip empty tokens
|
||||
if (stringSoFar.indexOf(token) != stringSoFar.lastIndexOf(token))
|
||||
continue; // there are already two occs. of this token
|
||||
if (token.charAt(0) == ESCAPE_C && token.length() == 1 && maxlen < 4)
|
||||
test(stringSoFar+token, tokensSoFar); // want lots of \'s
|
||||
else if (tokensSoFar < maxlen)
|
||||
test(stringSoFar+token, tokensSoFar+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test(String s) {
|
||||
// for small batches, do not test the null string
|
||||
if (s.length() == 0 && maxlen >=1 && maxlen <= 2) return;
|
||||
String bn = testSourceName(s);
|
||||
if (bn == null) return;
|
||||
if (bn == s) {
|
||||
//if (verbose) System.out.println(s+" == id");
|
||||
} else {
|
||||
if (verbose) System.out.println(s+" => "+bn+" "+toDisplayName(bn));
|
||||
String bnbn = testSourceName(bn);
|
||||
if (bnbn == null) return;
|
||||
if (verbose) System.out.println(bn+" => "+bnbn+" "+toDisplayName(bnbn));
|
||||
/*
|
||||
String bn3 = testSourceName(bnbn);
|
||||
if (bn3 == null) return;
|
||||
if (verbose) System.out.println(bnbn+" => "+bn3);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
String testSourceName(String s) {
|
||||
if (map.containsKey(s)) return null;
|
||||
String bn = toBytecodeName(s);
|
||||
map.put(s, bn);
|
||||
String sn = toSourceName(bn);
|
||||
if (!sn.equals(s)) {
|
||||
String bad = (s+" => "+bn+" != "+sn);
|
||||
if (!verbose) throw new Error("Bad mangling: "+bad);
|
||||
System.out.println("*** "+bad);
|
||||
return null;
|
||||
}
|
||||
return bn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,7 +27,10 @@ package sun.dyn.util;
|
||||
|
||||
import java.dyn.*;
|
||||
import java.dyn.MethodHandles.Lookup;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import sun.dyn.Access;
|
||||
import sun.dyn.AdapterMethodHandle;
|
||||
import sun.dyn.MethodHandleImpl;
|
||||
@ -37,6 +40,7 @@ public class ValueConversions {
|
||||
private static final Lookup IMPL_LOOKUP = MethodHandleImpl.getLookup(IMPL_TOKEN);
|
||||
|
||||
private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {
|
||||
@SuppressWarnings("unchecked")
|
||||
EnumMap<Wrapper, MethodHandle>[] caches
|
||||
= (EnumMap<Wrapper, MethodHandle>[]) new EnumMap[n]; // unchecked warning expected here
|
||||
for (int i = 0; i < n; i++)
|
||||
@ -114,7 +118,7 @@ public class ValueConversions {
|
||||
}
|
||||
|
||||
private static MethodType unboxType(Wrapper wrap, boolean raw) {
|
||||
return MethodType.make(rawWrapper(wrap, raw).primitiveType(), wrap.wrapperType());
|
||||
return MethodType.methodType(rawWrapper(wrap, raw).primitiveType(), wrap.wrapperType());
|
||||
}
|
||||
|
||||
private static final EnumMap<Wrapper, MethodHandle>[]
|
||||
@ -240,7 +244,7 @@ public class ValueConversions {
|
||||
private static MethodType boxType(Wrapper wrap, boolean raw) {
|
||||
// be exact, since return casts are hard to compose
|
||||
Class<?> boxType = wrap.wrapperType();
|
||||
return MethodType.make(boxType, rawWrapper(wrap, raw).primitiveType());
|
||||
return MethodType.methodType(boxType, rawWrapper(wrap, raw).primitiveType());
|
||||
}
|
||||
|
||||
private static Wrapper rawWrapper(Wrapper wrap, boolean raw) {
|
||||
@ -305,29 +309,47 @@ public class ValueConversions {
|
||||
|
||||
/// Kludges for when raw values get accidentally boxed.
|
||||
|
||||
static int unboxRawInteger(Object x) {
|
||||
if (x instanceof Integer)
|
||||
return unboxInteger(x);
|
||||
else
|
||||
return (int) unboxLong(x);
|
||||
}
|
||||
|
||||
static Integer reboxRawInteger(Object x) {
|
||||
if (x instanceof Integer)
|
||||
return (Integer) x;
|
||||
else
|
||||
return (int) unboxLong(x);
|
||||
}
|
||||
|
||||
static Byte reboxRawByte(Object x) {
|
||||
if (x instanceof Byte) return (Byte) x;
|
||||
return boxByteRaw(unboxInteger(x));
|
||||
return boxByteRaw(unboxRawInteger(x));
|
||||
}
|
||||
|
||||
static Short reboxRawShort(Object x) {
|
||||
if (x instanceof Short) return (Short) x;
|
||||
return boxShortRaw(unboxInteger(x));
|
||||
return boxShortRaw(unboxRawInteger(x));
|
||||
}
|
||||
|
||||
static Boolean reboxRawBoolean(Object x) {
|
||||
if (x instanceof Boolean) return (Boolean) x;
|
||||
return boxBooleanRaw(unboxInteger(x));
|
||||
return boxBooleanRaw(unboxRawInteger(x));
|
||||
}
|
||||
|
||||
static Character reboxRawCharacter(Object x) {
|
||||
if (x instanceof Character) return (Character) x;
|
||||
return boxCharacterRaw(unboxInteger(x));
|
||||
return boxCharacterRaw(unboxRawInteger(x));
|
||||
}
|
||||
|
||||
static Float reboxRawFloat(Object x) {
|
||||
if (x instanceof Float) return (Float) x;
|
||||
return boxFloatRaw(unboxInteger(x));
|
||||
return boxFloatRaw(unboxRawInteger(x));
|
||||
}
|
||||
|
||||
static Long reboxRawLong(Object x) {
|
||||
return (Long) x; //never a rebox
|
||||
}
|
||||
|
||||
static Double reboxRawDouble(Object x) {
|
||||
@ -337,12 +359,21 @@ public class ValueConversions {
|
||||
|
||||
private static MethodType reboxType(Wrapper wrap) {
|
||||
Class<?> boxType = wrap.wrapperType();
|
||||
return MethodType.make(boxType, Object.class);
|
||||
return MethodType.methodType(boxType, Object.class);
|
||||
}
|
||||
|
||||
private static final EnumMap<Wrapper, MethodHandle>[]
|
||||
REBOX_CONVERSIONS = newWrapperCaches(2);
|
||||
|
||||
/**
|
||||
* Becase we normalize primitive types to reduce the number of signatures,
|
||||
* primitives are sometimes manipulated under an "erased" type,
|
||||
* either int (for types other than long/double) or long (for all types).
|
||||
* When the erased primitive value is then boxed into an Integer or Long,
|
||||
* the final boxed primitive is sometimes required. This transformation
|
||||
* is called a "rebox". It takes an Integer or Long and produces some
|
||||
* other boxed value.
|
||||
*/
|
||||
public static MethodHandle rebox(Wrapper wrap, boolean exact) {
|
||||
EnumMap<Wrapper, MethodHandle> cache = REBOX_CONVERSIONS[exact?1:0];
|
||||
MethodHandle mh = cache.get(wrap);
|
||||
@ -355,9 +386,6 @@ public class ValueConversions {
|
||||
mh = IDENTITY; break;
|
||||
case VOID:
|
||||
throw new IllegalArgumentException("cannot rebox a void");
|
||||
case INT: case LONG:
|
||||
mh = cast(wrap.wrapperType(), exact);
|
||||
break;
|
||||
}
|
||||
if (mh != null) {
|
||||
cache.put(wrap, mh);
|
||||
@ -384,13 +412,21 @@ public class ValueConversions {
|
||||
/// Width-changing conversions between int and long.
|
||||
|
||||
static long widenInt(int x) {
|
||||
return x;
|
||||
return (long) x;
|
||||
}
|
||||
|
||||
static Long widenBoxedInt(Integer x) {
|
||||
return (long)(int)x;
|
||||
}
|
||||
|
||||
static int narrowLong(long x) {
|
||||
return (int) x;
|
||||
}
|
||||
|
||||
static Integer narrowBoxedLong(Long x) {
|
||||
return (int)(long) x;
|
||||
}
|
||||
|
||||
/// Constant functions
|
||||
|
||||
static void ignore(Object x) {
|
||||
@ -432,7 +468,7 @@ public class ValueConversions {
|
||||
return mh;
|
||||
}
|
||||
// slow path
|
||||
MethodType type = MethodType.make(wrap.primitiveType());
|
||||
MethodType type = MethodType.methodType(wrap.primitiveType());
|
||||
switch (wrap) {
|
||||
case VOID:
|
||||
mh = EMPTY;
|
||||
@ -500,11 +536,11 @@ public class ValueConversions {
|
||||
private static final MethodHandle IDENTITY, CAST_REFERENCE, ALWAYS_NULL, ALWAYS_ZERO, ZERO_OBJECT, IGNORE, EMPTY;
|
||||
static {
|
||||
try {
|
||||
MethodType idType = MethodType.makeGeneric(1);
|
||||
MethodType castType = idType.insertParameterType(0, Class.class);
|
||||
MethodType idType = MethodType.genericMethodType(1);
|
||||
MethodType castType = idType.insertParameterTypes(0, Class.class);
|
||||
MethodType alwaysZeroType = idType.changeReturnType(int.class);
|
||||
MethodType ignoreType = idType.changeReturnType(void.class);
|
||||
MethodType zeroObjectType = MethodType.makeGeneric(0);
|
||||
MethodType zeroObjectType = MethodType.genericMethodType(0);
|
||||
IDENTITY = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", idType);
|
||||
//CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
|
||||
CAST_REFERENCE = IMPL_LOOKUP.findStatic(ValueConversions.class, "castReference", castType);
|
||||
@ -512,7 +548,7 @@ public class ValueConversions {
|
||||
ALWAYS_ZERO = IMPL_LOOKUP.findStatic(ValueConversions.class, "alwaysZero", alwaysZeroType);
|
||||
ZERO_OBJECT = IMPL_LOOKUP.findStatic(ValueConversions.class, "zeroObject", zeroObjectType);
|
||||
IGNORE = IMPL_LOOKUP.findStatic(ValueConversions.class, "ignore", ignoreType);
|
||||
EMPTY = IMPL_LOOKUP.findStatic(ValueConversions.class, "empty", ignoreType.dropParameterType(0));
|
||||
EMPTY = IMPL_LOOKUP.findStatic(ValueConversions.class, "empty", ignoreType.dropParameterTypes(0, 1));
|
||||
} catch (RuntimeException ex) {
|
||||
throw ex;
|
||||
}
|
||||
@ -543,10 +579,10 @@ public class ValueConversions {
|
||||
else if (VerifyType.isNullType(type))
|
||||
mh = ALWAYS_NULL;
|
||||
else
|
||||
mh = MethodHandles.insertArgument(CAST_REFERENCE, 0, type);
|
||||
mh = MethodHandles.insertArguments(CAST_REFERENCE, 0, type);
|
||||
if (exact) {
|
||||
MethodType xmt = MethodType.make(type, Object.class);
|
||||
mh = AdapterMethodHandle.makeRawRetypeOnly(IMPL_TOKEN, xmt, mh);
|
||||
MethodType xmt = MethodType.methodType(type, Object.class);
|
||||
mh = AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, xmt, mh);
|
||||
}
|
||||
if (cache != null)
|
||||
cache.put(wrap, mh);
|
||||
@ -560,4 +596,127 @@ public class ValueConversions {
|
||||
private static MethodHandle retype(MethodType type, MethodHandle mh) {
|
||||
return AdapterMethodHandle.makeRetypeOnly(IMPL_TOKEN, type, mh);
|
||||
}
|
||||
|
||||
private static final Object[] NO_ARGS_ARRAY = {};
|
||||
private static Object[] makeArray(Object... args) { return args; }
|
||||
private static Object[] array() { return NO_ARGS_ARRAY; }
|
||||
private static Object[] array(Object a0)
|
||||
{ return makeArray(a0); }
|
||||
private static Object[] array(Object a0, Object a1)
|
||||
{ return makeArray(a0, a1); }
|
||||
private static Object[] array(Object a0, Object a1, Object a2)
|
||||
{ return makeArray(a0, a1, a2); }
|
||||
private static Object[] array(Object a0, Object a1, Object a2, Object a3)
|
||||
{ return makeArray(a0, a1, a2, a3); }
|
||||
private static Object[] array(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4)
|
||||
{ return makeArray(a0, a1, a2, a3, a4); }
|
||||
private static Object[] array(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4, Object a5)
|
||||
{ return makeArray(a0, a1, a2, a3, a4, a5); }
|
||||
private static Object[] array(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4, Object a5, Object a6)
|
||||
{ return makeArray(a0, a1, a2, a3, a4, a5, a6); }
|
||||
private static Object[] array(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4, Object a5, Object a6, Object a7)
|
||||
{ return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
|
||||
private static Object[] array(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4, Object a5, Object a6, Object a7,
|
||||
Object a8)
|
||||
{ return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
|
||||
private static Object[] array(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4, Object a5, Object a6, Object a7,
|
||||
Object a8, Object a9)
|
||||
{ return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
|
||||
static MethodHandle[] makeArrays() {
|
||||
ArrayList<MethodHandle> arrays = new ArrayList<MethodHandle>();
|
||||
MethodHandles.Lookup lookup = IMPL_LOOKUP;
|
||||
for (;;) {
|
||||
int nargs = arrays.size();
|
||||
MethodType type = MethodType.genericMethodType(nargs).changeReturnType(Object[].class);
|
||||
String name = "array";
|
||||
MethodHandle array = null;
|
||||
try {
|
||||
array = lookup.findStatic(ValueConversions.class, name, type);
|
||||
} catch (NoAccessException ex) {
|
||||
}
|
||||
if (array == null) break;
|
||||
arrays.add(array);
|
||||
}
|
||||
assert(arrays.size() == 11); // current number of methods
|
||||
return arrays.toArray(new MethodHandle[0]);
|
||||
}
|
||||
static final MethodHandle[] ARRAYS = makeArrays();
|
||||
|
||||
/** Return a method handle that takes the indicated number of Object
|
||||
* arguments and returns an Object array of them, as if for varargs.
|
||||
*/
|
||||
public static MethodHandle varargsArray(int nargs) {
|
||||
if (nargs < ARRAYS.length)
|
||||
return ARRAYS[nargs];
|
||||
// else need to spin bytecode or do something else fancy
|
||||
throw new UnsupportedOperationException("NYI");
|
||||
}
|
||||
|
||||
private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
|
||||
private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
|
||||
private static List<Object> list() { return NO_ARGS_LIST; }
|
||||
private static List<Object> list(Object a0)
|
||||
{ return makeList(a0); }
|
||||
private static List<Object> list(Object a0, Object a1)
|
||||
{ return makeList(a0, a1); }
|
||||
private static List<Object> list(Object a0, Object a1, Object a2)
|
||||
{ return makeList(a0, a1, a2); }
|
||||
private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
|
||||
{ return makeList(a0, a1, a2, a3); }
|
||||
private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4)
|
||||
{ return makeList(a0, a1, a2, a3, a4); }
|
||||
private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4, Object a5)
|
||||
{ return makeList(a0, a1, a2, a3, a4, a5); }
|
||||
private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4, Object a5, Object a6)
|
||||
{ return makeList(a0, a1, a2, a3, a4, a5, a6); }
|
||||
private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4, Object a5, Object a6, Object a7)
|
||||
{ return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
|
||||
private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4, Object a5, Object a6, Object a7,
|
||||
Object a8)
|
||||
{ return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
|
||||
private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
|
||||
Object a4, Object a5, Object a6, Object a7,
|
||||
Object a8, Object a9)
|
||||
{ return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
|
||||
static MethodHandle[] makeLists() {
|
||||
ArrayList<MethodHandle> arrays = new ArrayList<MethodHandle>();
|
||||
MethodHandles.Lookup lookup = IMPL_LOOKUP;
|
||||
for (;;) {
|
||||
int nargs = arrays.size();
|
||||
MethodType type = MethodType.genericMethodType(nargs).changeReturnType(List.class);
|
||||
String name = "list";
|
||||
MethodHandle array = null;
|
||||
try {
|
||||
array = lookup.findStatic(ValueConversions.class, name, type);
|
||||
} catch (NoAccessException ex) {
|
||||
}
|
||||
if (array == null) break;
|
||||
arrays.add(array);
|
||||
}
|
||||
assert(arrays.size() == 11); // current number of methods
|
||||
return arrays.toArray(new MethodHandle[0]);
|
||||
}
|
||||
static final MethodHandle[] LISTS = makeLists();
|
||||
|
||||
/** Return a method handle that takes the indicated number of Object
|
||||
* arguments and returns List.
|
||||
*/
|
||||
public static MethodHandle varargsList(int nargs) {
|
||||
if (nargs < LISTS.length)
|
||||
return LISTS[nargs];
|
||||
// else need to spin bytecode or do something else fancy
|
||||
throw new UnsupportedOperationException("NYI");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -26,8 +26,12 @@
|
||||
package sun.dyn.util;
|
||||
|
||||
import java.dyn.LinkagePermission;
|
||||
import java.dyn.MethodHandles.Lookup;
|
||||
import java.dyn.NoAccessException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import sun.dyn.Access;
|
||||
import sun.dyn.MemberName;
|
||||
import sun.dyn.MethodHandleImpl;
|
||||
import sun.dyn.empty.Empty;
|
||||
|
||||
/**
|
||||
* This class centralizes information about the JVM's linkage access control.
|
||||
@ -45,21 +49,21 @@ public class VerifyAccess {
|
||||
* <p>
|
||||
* Some circumstances require an additional check on the
|
||||
* leading parameter (the receiver) of the method, if it is non-static.
|
||||
* In the case of {@code invokespecial} ({@code doDispatch} is false),
|
||||
* In the case of {@code invokespecial} ({@code isSpecialInvoke} is true),
|
||||
* the leading parameter must be the accessing class or a subclass.
|
||||
* In the case of a call to a {@code protected} method outside the same
|
||||
* package, the same constraint applies.
|
||||
* @param m the proposed callee
|
||||
* @param doDispatch if false, a non-static m will be invoked as if by {@code invokespecial}
|
||||
* @param isSpecialInvoke if true, a non-static method m is checked as if for {@code invokespecial}
|
||||
* @param lookupClass the class for which the access check is being made
|
||||
* @return null if the method is not accessible, else a receiver type constraint, else {@code Object.class}
|
||||
*/
|
||||
public static Class<?> isAccessible(Class<?> defc, int mods,
|
||||
boolean doDispatch, Class<?> lookupClass) {
|
||||
Class<?> lookupClass, boolean isSpecialInvoke) {
|
||||
if (!isAccessible(defc, lookupClass))
|
||||
return null;
|
||||
Class<?> constraint = Object.class;
|
||||
if (!doDispatch && !Modifier.isStatic(mods)) {
|
||||
if (isSpecialInvoke && !Modifier.isStatic(mods)) {
|
||||
constraint = lookupClass;
|
||||
}
|
||||
if (Modifier.isPublic(mods))
|
||||
@ -166,4 +170,38 @@ public class VerifyAccess {
|
||||
if (isSamePackage(requestingClass, subjectClass)) return;
|
||||
security.checkPermission(new LinkagePermission(permissionName, requestingClass));
|
||||
}
|
||||
|
||||
private static RuntimeException checkNameFailed(MemberName self, Lookup lookup, String comment) {
|
||||
return new NoAccessException("cannot access from "+lookup+": "+self.toString()+": "+comment);
|
||||
}
|
||||
public static void checkName(MemberName self, Lookup lookup) {
|
||||
Class<?> lc = lookup.lookupClass();
|
||||
if (lc == null) return; // lookup is privileged
|
||||
Class<?> dc = self.getDeclaringClass();
|
||||
int samepkg = 0;
|
||||
// First check the containing class. Must be public or local.
|
||||
if (!Modifier.isPublic(dc.getModifiers())) {
|
||||
if (lc != Empty.class)
|
||||
samepkg = (isSamePackage(dc, lc) ? 1 : -1);
|
||||
if (samepkg <= 0)
|
||||
throw checkNameFailed(self, lookup, "class is not public");
|
||||
}
|
||||
// At this point dc is known to be accessible.
|
||||
if (self.isPublic()) {
|
||||
return;
|
||||
} else if (lc == Empty.class) {
|
||||
throw checkNameFailed(self, lookup, "member is not public");
|
||||
} else if (self.isProtected()) {
|
||||
if (dc.isAssignableFrom(lc)) return;
|
||||
} else if (self.isPrivate()) {
|
||||
if (isSamePackageMember(dc, lc)) return;
|
||||
throw checkNameFailed(self, lookup, "member is private");
|
||||
}
|
||||
// Fall-through handles the package-private and protected cases.
|
||||
if (samepkg == 0)
|
||||
samepkg = (isSamePackage(dc, lc) ? 1 : -1);
|
||||
if (samepkg > 0) return;
|
||||
throw checkNameFailed(self, lookup,
|
||||
self.isProtected() ? "member is protected" : "member is private to package");
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
package sun.dyn.util;
|
||||
|
||||
import java.dyn.MethodType;
|
||||
import sun.dyn.empty.Empty;
|
||||
|
||||
/**
|
||||
* This class centralizes information about the JVM verifier
|
||||
@ -73,29 +74,28 @@ public class VerifyType {
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the given type either java.lang.Void or java.lang.Null?
|
||||
* These types serve as markers for bare nulls and therefore
|
||||
* may be promoted to any type. This is secure, since
|
||||
* Is the given type java.lang.Null or an equivalent null-only type?
|
||||
*/
|
||||
public static boolean isNullType(Class<?> type) {
|
||||
if (type == null) return false;
|
||||
return type == NULL_CLASS_1 || type == NULL_CLASS_2;
|
||||
return type == NULL_CLASS
|
||||
// This one may also be used as a null type.
|
||||
// TO DO: Decide if we really want to legitimize it here.
|
||||
// Probably we do, unless java.lang.Null really makes it into Java 7
|
||||
//|| type == Void.class
|
||||
// Locally known null-only class:
|
||||
|| type == Empty.class
|
||||
;
|
||||
}
|
||||
private static final Class<?> NULL_CLASS_1, NULL_CLASS_2;
|
||||
private static final Class<?> NULL_CLASS;
|
||||
static {
|
||||
Class<?> nullClass1 = null, nullClass2 = null;
|
||||
Class<?> nullClass = null;
|
||||
try {
|
||||
nullClass1 = Class.forName("java.lang.Null");
|
||||
nullClass = Class.forName("java.lang.Null");
|
||||
} catch (ClassNotFoundException ex) {
|
||||
// OK, we'll cope
|
||||
}
|
||||
NULL_CLASS_1 = nullClass1;
|
||||
|
||||
// This one may also be used as a null type.
|
||||
// TO DO: Decide if we really want to legitimize it here.
|
||||
// Probably we do, unless java.lang.Null really makes it into Java 7
|
||||
nullClass2 = Void.class;
|
||||
NULL_CLASS_2 = nullClass2;
|
||||
NULL_CLASS = nullClass;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,6 +191,11 @@ public class VerifyType {
|
||||
// to be captured as a garbage int.
|
||||
// Caller promises that the actual value will be disregarded.
|
||||
return dst == int.class ? 1 : 0;
|
||||
if (isNullType(src))
|
||||
// Special permission for raw conversions: allow a null
|
||||
// to be reinterpreted as anything. For objects, it is safe,
|
||||
// and for primitives you get a garbage value (probably zero).
|
||||
return 1;
|
||||
if (!src.isPrimitive())
|
||||
return 0;
|
||||
Wrapper sw = Wrapper.forPrimitiveType(src);
|
||||
|
||||
@ -141,13 +141,19 @@ public enum Wrapper {
|
||||
* @throws IllegalArgumentException for unexpected types
|
||||
*/
|
||||
public static Wrapper forPrimitiveType(Class<?> type) {
|
||||
Wrapper w = findPrimitiveType(type);
|
||||
if (w != null) return w;
|
||||
if (type.isPrimitive())
|
||||
throw new InternalError(); // redo hash function
|
||||
throw newIllegalArgumentException("not primitive: "+type);
|
||||
}
|
||||
|
||||
static Wrapper findPrimitiveType(Class<?> type) {
|
||||
Wrapper w = FROM_PRIM[hashPrim(type)];
|
||||
if (w != null && w.primitiveType == type) {
|
||||
return w;
|
||||
}
|
||||
if (type.isPrimitive())
|
||||
throw new InternalError(); // redo hash function
|
||||
throw newIllegalArgumentException("not primitive: "+type);
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Return the wrapper that wraps values into the given wrapper type.
|
||||
@ -160,7 +166,7 @@ public enum Wrapper {
|
||||
Wrapper w = findWrapperType(type);
|
||||
if (w != null) return w;
|
||||
for (Wrapper x : values())
|
||||
if (w.wrapperType == type)
|
||||
if (x.wrapperType == type)
|
||||
throw new InternalError(); // redo hash function
|
||||
throw newIllegalArgumentException("not wrapper: "+type);
|
||||
}
|
||||
@ -244,8 +250,10 @@ public enum Wrapper {
|
||||
public Class<?> wrapperType() { return wrapperType; }
|
||||
|
||||
/** What is the wrapper type for this wrapper?
|
||||
* The example type must be the wrapper type,
|
||||
* Otherwise, the example type must be the wrapper type,
|
||||
* or the corresponding primitive type.
|
||||
* (For {@code OBJECT}, the example type can be any non-primitive,
|
||||
* and is normalized to {@code Object.class}.)
|
||||
* The resulting class type has the same type parameter.
|
||||
*/
|
||||
public <T> Class<T> wrapperType(Class<T> exampleType) {
|
||||
@ -290,6 +298,16 @@ public enum Wrapper {
|
||||
return type.isPrimitive();
|
||||
}
|
||||
|
||||
/** What is the bytecode signature character for this type?
|
||||
* All non-primitives, including array types, report as 'L', the signature character for references.
|
||||
*/
|
||||
public static char basicTypeChar(Class<?> type) {
|
||||
if (!type.isPrimitive())
|
||||
return 'L';
|
||||
else
|
||||
return forPrimitiveType(type).basicTypeChar();
|
||||
}
|
||||
|
||||
/** What is the bytecode signature character for this wrapper's
|
||||
* primitive type?
|
||||
*/
|
||||
@ -309,7 +327,7 @@ public enum Wrapper {
|
||||
/** Cast a wrapped value to the given type, which may be either a primitive or wrapper type.
|
||||
* Performs standard primitive conversions, including truncation and float conversions.
|
||||
* The given type must be compatible with this wrapper. That is, it must either
|
||||
* be the wrapper type (or a subtype, in the case of {@code OBJECT} or else
|
||||
* be the wrapper type (or a subtype, in the case of {@code OBJECT}) or else
|
||||
* it must be the wrapper's primitive type.
|
||||
* @throws ClassCastException if the given type is not compatible with this wrapper
|
||||
*/
|
||||
@ -326,9 +344,17 @@ public enum Wrapper {
|
||||
* If the target type is a primitive, change it to a wrapper.
|
||||
*/
|
||||
static <T> Class<T> forceType(Class<?> type, Class<T> exampleType) {
|
||||
boolean z = (type == exampleType ||
|
||||
type.isPrimitive() && forPrimitiveType(type) == findWrapperType(exampleType) ||
|
||||
exampleType.isPrimitive() && forPrimitiveType(exampleType) == findWrapperType(type) ||
|
||||
type == Object.class && !exampleType.isPrimitive());
|
||||
if (!z)
|
||||
System.out.println(type+" <= "+exampleType);
|
||||
assert(type == exampleType ||
|
||||
type == asWrapperType(exampleType) ||
|
||||
type == Object.class && exampleType.isInterface());
|
||||
type.isPrimitive() && forPrimitiveType(type) == findWrapperType(exampleType) ||
|
||||
exampleType.isPrimitive() && forPrimitiveType(exampleType) == findWrapperType(type) ||
|
||||
type == Object.class && !exampleType.isPrimitive());
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<T> result = (Class<T>) type; // unchecked warning is expected here
|
||||
return result;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user