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:
John R Rose 2010-01-07 16:16:45 -08:00
parent 20b837a9e4
commit 020e5501fd
31 changed files with 9587 additions and 1567 deletions

View File

@ -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));
}

View File

@ -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.&lt;String&gt;hail(x); // hail(Ljava/lang/Object;)Ljava/lang/String;
* InvokeDynamic.&lt;void&gt;cogito(); // cogito()V
* i = InvokeDynamic.&lt;int&gt;#"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 {

View File

@ -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);
}
}

View File

@ -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.&lt;void&gt;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.&lt;Number&gt;invoke(1L); // 456
* stuffPtr.setter().&lt;void&gt;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);
}
}

View File

@ -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>

View File

@ -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.
*

View File

@ -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) =&gt; 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.&lt;String&gt;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[] =&gt; List}
* mt = MethodType.make(java.util.List.class, Object[].class);
* mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
* // mt is {(Object,Object,Object) =&gt; Object}
* mt = MethodType.makeGeneric(3);
* mh = MethodHandles.collectArguments(mh, mt);
* // mt is {(Object,Object,Object) =&gt; 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 { =&gt; int}
* mt = MethodType.make(int.class);
* mh = lookup.findVirtual(java.util.List.class, "size", mt);
* // (Ljava/util/List;)I
* i = mh.&lt;int&gt;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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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

View File

@ -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);

View File

@ -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)); }
}
}

View File

@ -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() {

View File

@ -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.

View File

@ -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);
}
}
}

View File

@ -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.
);
/**

View File

@ -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);
}
}

View 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

View File

@ -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 {

View File

@ -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);

View File

@ -298,6 +298,8 @@ public class BytecodeName {
* The name {@code &lt;init&gt;} will be parsed into { '&lt;', "init", '&gt;'}}
* 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;
}
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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);

View File

@ -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