提交 f7bd7bb2 编写于 作者: J jrose

6939134: JSR 292 adjustments to method handle invocation

Summary: split MethodHandle.invoke into invokeExact and invokeGeneric; also clean up JVM-to-Java interfaces
Reviewed-by: twisti
上级 736b748f
/*
* Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2008-2010 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
......@@ -25,25 +25,32 @@
package java.dyn;
import sun.dyn.util.BytecodeName;
import sun.dyn.Access;
import sun.dyn.MemberName;
import sun.dyn.CallSiteImpl;
import sun.dyn.MethodHandleImpl;
/**
* An {@code invokedynamic} call site, as reified by the
* containing class's bootstrap method.
* Every call site object corresponds to a distinct instance
* of the <code>invokedynamic</code> instruction, and vice versa.
* Every call site has one state variable, called the {@code target}.
* It is typed as a {@link MethodHandle}. This state is never null, and
* it is the responsibility of the bootstrap method to produce call sites
* which have been pre-linked to an initial target method.
* A {@code CallSite} reifies an {@code invokedynamic} instruction from bytecode,
* and controls its linkage.
* Every linked {@code CallSite} object corresponds to a distinct instance
* of the {@code invokedynamic} instruction, and vice versa.
* <p>
* (Note: The bootstrap method may elect to produce call sites of a
* Every linked {@code CallSite} object has one state variable,
* a {@link MethodHandle} reference called the {@code target}.
* This reference is never null. Though it can change its value
* successive values must always have exactly the {@link MethodType method type}
* called for by the bytecodes of the associated {@code invokedynamic} instruction
* <p>
* It is the responsibility of each class's
* {@link Linkage#registerBootstrapMethod(Class, MethodHandle) bootstrap method}
* to produce call sites which have been pre-linked to an initial target method.
* The required {@link MethodType type} for the target method is a parameter
* to each bootstrap method call.
* <p>
* The bootstrap method may elect to produce call sites of a
* language-specific subclass of {@code CallSite}. In such a case,
* the subclass may claim responsibility for initializing its target to
* a non-null value, by overriding {@link #initialTarget}.)
* a non-null value, by overriding {@link #initialTarget}.
* <p>
* An {@code invokedynamic} instruction which has not yet been executed
* is said to be <em>unlinked</em>. When an unlinked call site is executed,
......@@ -52,54 +59,139 @@ import sun.dyn.MethodHandleImpl;
* value to the new call site's target variable, the method {@link #initialTarget}
* is called to produce the new call site's first target method.
* <p>
* A freshly-created {@code CallSite} object is not yet in a linked state.
* An unlinked {@code CallSite} object reports null for its {@code callerClass}.
* When the JVM receives a {@code CallSite} object from a bootstrap method,
* it first ensures that its target is non-null and of the correct type.
* The JVM then links the {@code CallSite} object to the call site instruction,
* enabling the {@code callerClass} to return the class in which the instruction occurs.
* <p>
* Next, the JVM links the instruction to the {@code CallSite}, at which point
* any further execution of the {@code invokedynamic} instruction implicitly
* invokes the current target of the {@code CallSite} object.
* After this two-way linkage, both the instruction and the {@code CallSite}
* object are said to be linked.
* <p>
* This state of linkage continues until the method containing the
* dynamic call site is garbage collected, or the dynamic call site
* is invalidated by an explicit request.
* <p>
* Linkage happens once in the lifetime of any given {@code CallSite} object.
* Because of call site invalidation, this linkage can be repeated for
* a single {@code invokedynamic} instruction, with multiple {@code CallSite} objects.
* When a {@code CallSite} is unlinked from an {@code invokedynamic} instruction,
* the instruction is reset so that it is no longer associated with
* the {@code CallSite} object, but the {@code CallSite} does not change
* state.
* <p>
* Here is a sample use of call sites and bootstrap methods which links every
* dynamic call site to print its arguments:
<blockquote><pre><!-- see indy-demo/src/PrintArgsDemo.java -->
private static void printArgs(Object... args) {
System.out.println(java.util.Arrays.deepToString(args));
}
private static final MethodHandle printArgs;
static {
MethodHandles.Lookup lookup = MethodHandles.lookup();
Class thisClass = lookup.lookupClass(); // (who am I?)
printArgs = lookup.findStatic(thisClass,
"printArgs", MethodType.methodType(void.class, Object[].class));
Linkage.registerBootstrapMethod("bootstrapDynamic");
}
private static CallSite bootstrapDynamic(Class caller, String name, MethodType type) {
// ignore caller and name, but match the type:
return new CallSite(MethodHandles.collectArguments(printArgs, type));
}
</pre></blockquote>
* @see Linkage#registerBootstrapMethod(java.lang.Class, java.dyn.MethodHandle)
* @author John Rose, JSR 292 EG
*/
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
private MemberName vmmethod; // supplied by the JVM (ref. to calling method)
private int vmindex; // supplied by the JVM (BCI within calling method)
// The actual payload of this call site:
private MethodHandle target;
final Object caller; // usually a class
final String name;
final MethodType type;
// Remove this field for PFD and delete deprecated methods:
private MemberName calleeNameRemoveForPFD;
/**
* Make a blank call site object.
* Before it is returned from a bootstrap method, this {@code CallSite} object
* must be provided with
* a target method via a call to {@link CallSite#setTarget(MethodHandle) setTarget},
* or by a subclass override of {@link CallSite#initialTarget(Class,String,MethodType) initialTarget}.
*/
public CallSite() {
}
/**
* Make a call site given the parameters from a call to the bootstrap method.
* The resulting call site is in an unlinked state, which means that before
* it is returned from a bootstrap method call it must be provided with
* a target method via a call to {@link CallSite#setTarget}.
* @param caller the class in which the relevant {@code invokedynamic} instruction occurs
* @param name the name specified by the {@code invokedynamic} instruction
* @param type the method handle type derived from descriptor of the {@code invokedynamic} instruction
* Make a blank call site object, possibly equipped with an initial target method handle.
* The initial target reference may be null, in which case the {@code CallSite} object
* must be provided with a target method via a call to {@link CallSite#setTarget},
* or by a subclass override of {@link CallSite#initialTarget}.
* @param target the method handle which will be the initial target of the call site, or null if there is none yet
*/
public CallSite(Object caller, String name, MethodType type) {
super(IMPL_TOKEN, caller, name, type);
public CallSite(MethodHandle target) {
this.target = target;
}
private static void privateInitializeCallSite(CallSite site, int callerMID, int callerBCI) {
site.callerMID = callerMID;
site.callerBCI = callerBCI;
site.ensureTarget();
/** @deprecated transitional form defined in EDR but removed in PFD */
public CallSite(Class<?> caller, String name, MethodType type) {
this.calleeNameRemoveForPFD = new MemberName(caller, name, type);
}
/** @deprecated transitional form defined in EDR but removed in PFD */
public Class<?> callerClass() {
MemberName callee = this.calleeNameRemoveForPFD;
return callee == null ? null : callee.getDeclaringClass();
}
/** @deprecated transitional form defined in EDR but removed in PFD */
public String name() {
MemberName callee = this.calleeNameRemoveForPFD;
return callee == null ? null : callee.getName();
}
/** @deprecated transitional form defined in EDR but removed in PFD */
public MethodType type() {
MemberName callee = this.calleeNameRemoveForPFD;
return callee == null ? (target == null ? null : target.type()) : callee.getMethodType();
}
/** @deprecated transitional form defined in EDR but removed in PFD */
protected MethodHandle initialTarget() {
return initialTarget(callerClass(), name(), type());
}
/** Report if the JVM has linked this {@code CallSite} object to a dynamic call site instruction.
* Once it is linked, it is never unlinked.
*/
private boolean isLinked() {
return vmmethod != null;
}
/** Called from JVM (or low-level Java code) after the BSM returns the newly created CallSite.
* The parameters are JVM-specific.
*/
void initializeFromJVM(String name,
MethodType type,
MemberName callerMethod,
int callerBCI) {
if (this.isLinked()) {
throw new InvokeDynamicBootstrapError("call site has already been linked to an invokedynamic instruction");
}
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
MethodHandle target = this.target;
if (target == null) {
this.target = target = this.initialTarget(callerMethod.getDeclaringClass(), name, type);
}
if (!target.type().equals(type)) {
throw wrongTargetType(target, type);
}
this.vmindex = callerBCI;
this.vmmethod = callerMethod;
assert(this.isLinked());
}
/**
......@@ -108,14 +200,18 @@ public class CallSite
* the method {@code initialTarget} is called to produce an initial
* non-null target. (Live call sites must never have null targets.)
* <p>
* The arguments are the same as those passed to the bootstrap method.
* Thus, a bootstrap method is free to ignore the arguments and simply
* create a "blank" {@code CallSite} object of an appropriate subclass.
* <p>
* If the bootstrap method itself does not initialize the call site,
* this method must be overridden, because it just raises an
* {@code InvokeDynamicBootstrapError}, which in turn causes the
* linkage of the {@code invokedynamic} instruction to terminate
* abnormally.
*/
protected MethodHandle initialTarget() {
throw new InvokeDynamicBootstrapError("target must be initialized before call site is linked: "+this);
protected MethodHandle initialTarget(Class<?> callerClass, String name, MethodType type) {
throw new InvokeDynamicBootstrapError("target must be initialized before call site is linked: "+name+type);
}
/**
......@@ -137,11 +233,11 @@ public class CallSite
* @see #setTarget
*/
public MethodHandle getTarget() {
return super.getTarget();
return target;
}
/**
* Link or relink the call site, by setting its target method.
* Set the target method of this call site.
* <p>
* The interactions of {@code setTarget} with memory are the same
* as of a write to an ordinary variable, such as an array element or a
......@@ -152,96 +248,46 @@ public class CallSite
* Stronger guarantees can be created by putting appropriate operations
* into the bootstrap method and/or the target methods used
* at any given call site.
* @param target the new target, or null if it is to be unlinked
* @param newTarget the new target
* @throws NullPointerException if the proposed new target is null
* @throws WrongMethodTypeException if the proposed new target
* has a method type that differs from the call site's {@link #type()}
* @throws WrongMethodTypeException if the call site is linked and the proposed new target
* has a method type that differs from the previous target
*/
public void setTarget(MethodHandle target) {
checkTarget(target);
super.setTarget(target);
public void setTarget(MethodHandle newTarget) {
MethodType newType = newTarget.type(); // null check!
MethodHandle oldTarget = this.target;
if (oldTarget == null) {
// CallSite is not yet linked.
assert(!isLinked());
this.target = newTarget; // might be null!
return;
}
protected void checkTarget(MethodHandle target) {
target.type(); // provoke NPE
if (!canSetTarget(target))
throw new WrongMethodTypeException(String.valueOf(target)+target.type()+" should be of type "+type());
MethodType oldType = oldTarget.type();
if (!newTarget.type().equals(oldType))
throw wrongTargetType(newTarget, oldType);
if (oldTarget != newTarget)
CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
}
protected boolean canSetTarget(MethodHandle target) {
return (target != null && target.type() == type());
}
/**
* Report the class containing the call site.
* This is an immutable property of the call site, set from the first argument to the constructor.
* @return class containing the call site
*/
public Class<?> callerClass() {
return (Class) caller;
private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
return new WrongMethodTypeException(String.valueOf(target)+target.type()+" should be of type "+type);
}
/**
* Report the method name specified in the {@code invokedynamic} instruction.
* This is an immutable property of the call site, set from the second argument to the constructor.
* <p>
* Note that the name is a JVM bytecode name, and as such can be any
* non-empty string, as long as it does not contain certain "dangerous"
* characters such as slash {@code '/'} and dot {@code '.'}.
* See the Java Virtual Machine specification for more details.
* <p>
* Application such as a language runtimes may need to encode
* arbitrary program element names and other configuration information
* into the name. A standard convention for doing this is
* <a href="http://blogs.sun.com/jrose/entry/symbolic_freedom_in_the_vm">specified here</a>.
* @return method name specified by the call site
/** Produce a printed representation that displays information about this call site
* that may be useful to the human reader.
*/
public String name() {
return name;
}
/**
* Report the method name specified in the {@code invokedynamic} instruction,
* as a series of components, individually demangled according to
* the standard convention
* <a href="http://blogs.sun.com/jrose/entry/symbolic_freedom_in_the_vm">specified here</a>.
* <p>
* Non-empty runs of characters between dangerous characters are demangled.
* Each component is either a completely arbitrary demangled string,
* or else a character constant for a punctuation character, typically ':'.
* (In principle, the character can be any dangerous character that the
* JVM lets through in a method name, such as '$' or ']'.
* Runtime implementors are encouraged to use colon ':' for building
* structured names.)
* <p>
* In the common case where the name contains no dangerous characters,
* the result is an array whose only element array is the demangled
* name at the call site. Such a demangled name can be any sequence
* of any number of any unicode characters.
* @return method name components specified by the call site
*/
public Object[] nameComponents() {
return BytecodeName.parseBytecodeName(name);
}
/**
* Report the resolved result and parameter types of this call site,
* which are derived from its bytecode-level invocation descriptor.
* The types are packaged into a {@link MethodType}.
* Any linked target of this call site must be exactly this method type.
* This is an immutable property of the call site, set from the third argument to the constructor.
* @return method type specified by the call site
*/
public MethodType type() {
return type;
}
@Override
public String toString() {
return "CallSite#"+hashCode()+"["+name+type+" => "+getTarget()+"]";
StringBuilder buf = new StringBuilder("CallSite#");
buf.append(hashCode());
if (!isLinked())
buf.append("[unlinked]");
else
buf.append("[")
.append("from ").append(vmmethod.getDeclaringClass().getName())
.append(" : ").append(getTarget().type())
.append(" => ").append(getTarget())
.append("]");
return buf.toString();
}
// Package-local constant:
static final MethodHandle GET_TARGET = MethodHandleImpl.getLookup(IMPL_TOKEN).
findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
}
......@@ -26,27 +26,25 @@
package java.dyn;
/**
* Syntactic marker to request javac to emit an {@code invokedynamic} instruction.
* An {@code invokedynamic} instruction is a 5-byte bytecoded instruction
* which begins with an opcode byte of value 186 ({@code 0xBA}),
* and is followed by a two-byte index of a {@code NameAndType} constant
* pool entry, then by two zero bytes. The constant pool reference gives
* the method name and argument and return types of the call site; there
* is no other information provided at the call site.
* {@code InvokeDynamic} is a class with neither methods nor instances,
* which serves only as a syntactic marker in Java source code for
* an {@code invokedynamic} instruction.
* (See <a href="package-summary.html#jvm_mods">the package information</a> for specifics on this instruction.)
* <p>
* The {@code invokedynamic} instruction is incomplete without a target method.
* The target method is a property of the reified call site object
* (of type {@link CallSite}) which is in a one-to-one association with each
* corresponding {@code invokedynamic} instruction. The call site object
* is initially produced by a <em>bootstrap method</em> associated with
* the call site, via the various overloadings of {@link Linkage#registerBootstrapMethod}.
* The target method is a property of the reified {@linkplain CallSite call site object}
* which is linked to each active {@code invokedynamic} instruction.
* The call site object is initially produced by a
* {@linkplain java.dyn.Linkage#registerBootstrapMethod(Class, MethodHandle) bootstrap method}
* associated with the class whose bytecodes include the dynamic call site.
* <p>
* The type {@code InvokeDynamic} has no particular meaning as a
* 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.
* It may be viewed as a pure syntactic marker of static calls.
* It may be imported for ease of use.
* <p>
* Here are some examples of usage:
* Here are some examples:
* <p><blockquote><pre>
* Object x; String s; int i;
* x = InvokeDynamic.greet("world"); // greet(Ljava/lang/String;)Ljava/lang/Object;
......@@ -65,6 +63,7 @@ package java.dyn;
* which must be registered by the static initializer of the enclosing class.
* @author John Rose, JSR 292 EG
*/
@MethodHandle.PolymorphicSignature
public final class InvokeDynamic {
private InvokeDynamic() { throw new InternalError(); } // do not instantiate
......
/*
* Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2008-2010 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
......@@ -27,24 +27,29 @@ package java.dyn;
/**
* Thrown to indicate that an {@code invokedynamic} instruction has
* failed to find its bootstrap method, or the bootstrap method has
* failed to provide a call site with a non-null target.
* failed to find its
* {@linkplain Linkage#registerBootstrapMethod(Class, MethodHandle) bootstrap method},
* or the bootstrap method has
* failed to provide a
* {@linkplain CallSite} call site with a non-null {@linkplain MethodHandle target}
* of the correct {@linkplain MethodType method type}.
* <p>
* The boostrap method must have been declared during a class's initialization
* by a call to {@link Linkage#registerBootstrapMethod}.
* The bootstrap method must have been declared during a class's initialization
* by a call to one of the overloadings of
* {@link Linkage#registerBootstrapMethod registerBootstrapMethod}.
*
* @author John Rose, JSR 292 EG
*/
public class InvokeDynamicBootstrapError extends LinkageError {
/**
* Constructs a {@code InvokeDynamicBootstrapError} with no detail message.
* Constructs an {@code InvokeDynamicBootstrapError} with no detail message.
*/
public InvokeDynamicBootstrapError() {
super();
}
/**
* Constructs a {@code InvokeDynamicBootstrapError} with the specified
* Constructs an {@code InvokeDynamicBootstrapError} with the specified
* detail message.
*
* @param s the detail message.
......
......@@ -28,7 +28,8 @@ package java.dyn;
import sun.dyn.Access;
/**
* A Java method handle extends the basic method handle type with additional
* A Java method handle is a deprecated proposal for extending
* the basic method handle type with additional
* programmer defined methods and fields.
* Its behavior as a method handle is determined at instance creation time,
* by providing the new instance with an "entry point" method handle
......@@ -62,11 +63,11 @@ import sun.dyn.Access;
* greeter.run(); // prints "hello, world"
* // Statically typed method handle invocation (most direct):
* MethodHandle mh = greeter;
* mh.&lt;void&gt;invoke(); // also prints "hello, world"
* mh.&lt;void&gt;invokeExact(); // also prints "hello, world"
* // Dynamically typed method handle invocation:
* MethodHandles.invoke(greeter); // also prints "hello, world"
* MethodHandles.invokeExact(greeter); // also prints "hello, world"
* greeter.setGreeting("howdy");
* mh.invoke(); // prints "howdy, world" (object-like mutable behavior)
* mh.invokeExact(); // prints "howdy, world" (object-like mutable behavior)
* </pre></blockquote>
* <p>
* In the example of {@code Greeter}, the method {@code run} provides the entry point.
......@@ -81,7 +82,7 @@ import sun.dyn.Access;
* inner class:
* <p><blockquote><pre>
* // We can also do this with symbolic names and/or inner classes:
* MethodHandles.invoke(new JavaMethodHandle("yow") {
* MethodHandles.invokeExact(new JavaMethodHandle("yow") {
* void yow() { System.out.println("yow, world"); }
* });
* </pre></blockquote>
......@@ -101,7 +102,7 @@ import sun.dyn.Access;
* Greeter greeter = new Greeter("world");
* greeter.run(); // prints "hello, world"
* MethodHandle mh = MethodHanndles.insertArgument(Greeter.RUN, 0, greeter);
* mh.invoke(); // also prints "hello, world"
* mh.invokeExact(); // 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.
......@@ -113,7 +114,7 @@ import sun.dyn.Access;
* MethodHandle greeter = new JavaMethodHandle("run") {
* private void run() { System.out.println("hello, "+greetee); }
* }
* greeter.invoke(); // prints "hello, world"
* greeter.invokeExact(); // prints "hello, world"
* </pre></blockquote>
* <p>
* Here is an abstract parameterized lvalue, efficiently expressed as a subtype of MethodHandle,
......@@ -137,10 +138,12 @@ import sun.dyn.Access;
* 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
* int x = (Integer) stuffPtr.&lt;Number&gt;invokeExact(1L); // 456
* stuffPtr.setter().&lt;void&gt;invokeExact(0L, (Number) 789); // replaces 123 with 789
* </pre></blockquote>
* @see MethodHandle
* @deprecated The JSR 292 EG intends to replace {@code JavaMethodHandle} with
* an interface-based API for mixing method handle behavior with other classes.
* @author John Rose, JSR 292 EG
*/
public abstract class JavaMethodHandle
......
......@@ -25,14 +25,19 @@
package java.dyn;
import java.lang.annotation.Annotation;
import java.dyn.MethodHandles.Lookup;
import java.util.WeakHashMap;
import sun.dyn.Access;
import sun.dyn.MethodHandleImpl;
import sun.reflect.Reflection;
import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege;
import static sun.dyn.MemberName.newIllegalArgumentException;
/**
* Static methods which control the linkage of invokedynamic call sites.
* This class consists exclusively of static methods that control
* the linkage of {@code invokedynamic} instructions, and specifically
* their reification as {@link CallSite} objects.
* @author John Rose, JSR 292 EG
*/
public class Linkage {
......@@ -42,102 +47,137 @@ public class Linkage {
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Register a <em>bootstrap method</em> to use when linking a given caller class.
* It must be a method handle of a type equivalent to {@link CallSite#CallSite}.
* In other words, it must act as a factory method which accepts the arguments
* to {@code CallSite}'s constructor (a class, a string, and a method type),
* Register a <em>bootstrap method</em> to use when linking dynamic call sites within
* a given caller class.
* <p>
* A bootstrap method must be a method handle with a return type of {@link CallSite}
* and the following arguments:
* <ul>
* <li>the class containing the {@code invokedynamic} instruction, for which the bootstrap method was registered
* <li>the name of the method being invoked (a {@link String})
* <li>the type of the method being invoked (a {@link MethodType})
* <li><em>TBD</em> optionally, an unordered array of {@link Annotation}s attached to the call site
* <em>(Until this feature is implemented, this will always receive an empty array.)</em>
* </ul>
* <em>(TBD: The final argument type may be missing from the method handle's type.
* Additional arguments may be added in the future.)</em>
* The bootstrap method acts as a factory method which accepts the given arguments
* and returns a {@code CallSite} object (possibly of a subclass of {@code CallSite}).
* <p>
* The registration will fail with an {@code IllegalStateException} if any of the following conditions hold:
* The registration must take place exactly once, either before the class has begun
* being initialized, or from within the class's static initializer.
* Registration will fail with an exception if any of the following conditions hold:
* <ul>
* <li>The caller of this method is in a different package than the {@code callerClass},
* <li>The immediate caller of this method is in a different package than the given caller class,
* and there is a security manager, and its {@code checkPermission} call throws
* when passed {@link LinkagePermission}("registerBootstrapMethod",callerClass).
* <li>The given class already has a bootstrap method from a previous
* 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.
* <li>The given caller class already has a bootstrap method registered.
* <li>The given caller class is already fully initialized.
* <li>The given caller class is in the process of initialization, in another thread.
* </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
* @exception IllegalArgumentException if the class argument is null or
* a primitive class, or if the bootstrap method is the wrong type
* @exception IllegalStateException if the class already has a bootstrap
* method, or if the its static initializer has already run
* or is already running in another thread
* @exception SecurityException if there is a security manager installed,
* and a {@link LinkagePermission} check fails for "registerBootstrapMethod"
*/
public static
void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) {
Class callc = Reflection.getCallerClass(2);
checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod");
checkBSM(bootstrapMethod);
synchronized (bootstrapMethods) {
if (bootstrapMethods.containsKey(callerClass))
throw new IllegalStateException("bootstrap method already declared in "+callerClass);
bootstrapMethods.put(callerClass, bootstrapMethod);
}
MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
}
static void checkBSM(MethodHandle mh) {
if (mh == null) throw new IllegalArgumentException("null bootstrap method");
if (mh.type() == OLD_BOOTSTRAP_METHOD_TYPE) // FIXME: delete at EDR/PFD
throw new WrongMethodTypeException("bootstrap method must be a CallSite factory");
if (mh.type() != BOOTSTRAP_METHOD_TYPE)
static private void checkBSM(MethodHandle mh) {
if (mh == null) throw newIllegalArgumentException("null bootstrap method");
if (mh.type() == BOOTSTRAP_METHOD_TYPE_2)
// For now, always pass an empty array for the Annotations argument
mh = MethodHandles.insertArguments(mh, BOOTSTRAP_METHOD_TYPE_2.parameterCount()-1,
(Object)NO_ANNOTATIONS);
if (mh.type() == BOOTSTRAP_METHOD_TYPE) return;
throw new WrongMethodTypeException(mh.toString());
}
static private final Annotation[] NO_ANNOTATIONS = { };
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Simplified version of registerBootstrapMethod for self-registration,
* Simplified version of {@code registerBootstrapMethod} for self-registration,
* to be called from a static initializer.
* Finds a static method of the required type in the
* given class, and installs it on the caller.
* @throws IllegalArgumentException if there is no such method
* given runtime class, and installs it on the caller class.
* @throws NoSuchMethodException if there is no such method
* @throws IllegalStateException if the caller class's static initializer
* has already run, or is already running in another thread
*/
public static
void registerBootstrapMethod(Class<?> runtime, String name) {
Class callc = Reflection.getCallerClass(2);
Lookup lookup = new Lookup(IMPL_TOKEN, callc);
MethodHandle bootstrapMethod =
lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE);
// FIXME: exception processing wrong here
checkBSM(bootstrapMethod);
Linkage.registerBootstrapMethod(callc, bootstrapMethod);
Class callerClass = Reflection.getCallerClass(2);
registerBootstrapMethodLookup(callerClass, runtime, name);
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Simplified version of registerBootstrapMethod for self-registration,
* Simplified version of {@code registerBootstrapMethod} for self-registration,
* to be called from a static initializer.
* Finds a static method of the required type in the
* caller's class, and installs it on the caller.
* caller class itself, and installs it on the caller class.
* @throws IllegalArgumentException if there is no such method
* @throws IllegalStateException if the caller class's static initializer
* has already run, or is already running in another thread
*/
public static
void registerBootstrapMethod(String name) {
Class callc = Reflection.getCallerClass(2);
Lookup lookup = new Lookup(IMPL_TOKEN, callc);
MethodHandle bootstrapMethod =
lookup.findStatic(callc, name, BOOTSTRAP_METHOD_TYPE);
// FIXME: exception processing wrong here
Class callerClass = Reflection.getCallerClass(2);
registerBootstrapMethodLookup(callerClass, callerClass, name);
}
private static
void registerBootstrapMethodLookup(Class<?> callerClass, Class<?> runtime, String name) {
Lookup lookup = new Lookup(IMPL_TOKEN, callerClass);
MethodHandle bootstrapMethod;
// Try both types. TBD
try {
bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE_2);
} catch (NoAccessException ex) {
bootstrapMethod = null;
}
if (bootstrapMethod == null) {
try {
bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE);
} catch (NoAccessException ex) {
throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex);
}
}
checkBSM(bootstrapMethod);
Linkage.registerBootstrapMethod(callc, bootstrapMethod);
MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Report the bootstrap method registered for a given class.
* Report the bootstrap method registered for a given caller class.
* 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.
* @exception IllegalArgumentException if the argument is null or
* a primitive class
* @exception SecurityException if there is a security manager installed,
* and the immediate caller of this method is not in the same
* package as the caller class
* and a {@link LinkagePermission} check fails for "getBootstrapMethod"
*/
public static
MethodHandle getBootstrapMethod(Class callerClass) {
Class callc = Reflection.getCallerClass(2);
checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod");
synchronized (bootstrapMethods) {
return bootstrapMethods.get(callerClass);
}
checkBootstrapPrivilege(callc, callerClass, "getBootstrapMethod");
return MethodHandleImpl.getBootstrap(IMPL_TOKEN, callerClass);
}
/**
......@@ -148,13 +188,10 @@ public class Linkage {
public static final MethodType BOOTSTRAP_METHOD_TYPE
= MethodType.methodType(CallSite.class,
Class.class, String.class, MethodType.class);
private static final MethodType OLD_BOOTSTRAP_METHOD_TYPE
= MethodType.methodType(Object.class,
CallSite.class, Object[].class);
private static final WeakHashMap<Class, MethodHandle> bootstrapMethods =
new WeakHashMap<Class, MethodHandle>();
static final MethodType BOOTSTRAP_METHOD_TYPE_2
= MethodType.methodType(CallSite.class,
Class.class, String.class, MethodType.class,
Annotation[].class);
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
......@@ -182,10 +219,8 @@ public class Linkage {
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Invalidate all <code>invokedynamic</code> call sites in the bytecodes
* Invalidate all {@code invokedynamic} 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>
* When this method returns, every matching <code>invokedynamic</code>
* instruction will invoke its bootstrap method on next call.
......@@ -201,18 +236,4 @@ public class Linkage {
}
throw new UnsupportedOperationException("NYI");
}
private static Object doNotBootstrap(CallSite site, Object... arguments) {
throw new UnsupportedOperationException("call site must not have null target: "+site);
}
private static final MethodHandle DO_NOT_BOOTSTRAP =
MethodHandles.Lookup.IMPL_LOOKUP.findStatic(Linkage.class, "doNotBootstrap",
OLD_BOOTSTRAP_METHOD_TYPE);
// Up-call from the JVM. Obsolete. FIXME: Delete from VM then from here.
static
MethodHandle findBootstrapMethod(Class callerClass, Class searchBootstrapClass) {
return DO_NOT_BOOTSTRAP;
}
}
......@@ -31,23 +31,17 @@ import java.util.Hashtable;
import java.util.StringTokenizer;
/**
* This class is for runtime permissions. A RuntimePermission
* contains a name (also referred to as a "target name") but
* This class is for managing runtime permission checking for
* operations performed by methods in the {@link Linkage} class.
* Like a {@link RuntimePermission}, on which it is modeled,
* a {@code LinkagePermission} contains a target name but
* no actions list; you either have the named permission
* or you don't.
*
* <P>
* The target name is the name of the runtime permission (see below). The
* naming convention follows the hierarchical property naming convention.
* Also, an asterisk
* may appear at the end of the name, following a ".", or by itself, to
* signify a wildcard match. For example: "loadLibrary.*" or "*" is valid,
* "*loadLibrary" or "a*b" is not valid.
* <P>
* The following table lists all the possible RuntimePermission target names,
* <p>
* The following table lists all the possible {@code LinkagePermission} target names,
* and for each provides a description of what the permission allows
* and a discussion of the risks of granting code the permission.
* <P>
* <p>
*
* <table border=1 cellpadding=5 summary="permission target name,
* what the target allows,and associated risks">
......@@ -59,15 +53,17 @@ import java.util.StringTokenizer;
*
* <tr>
* <td>registerBootstrapMethod.{class name}</td>
* <td>Specifying a bootstrap method for invokedynamic, within a class of the given name</td>
* <td>Specifying a bootstrap method for {@code invokedynamic} instructions within a class of the given name</td>
* <td>An attacker could attempt to attach a bootstrap method to a class which
* has just been loaded, thus gaining control of its invokedynamic calls.</td>
* has just been loaded, thus gaining control of its {@code invokedynamic} calls.</td>
* </tr>
*
* <tr>
* <td>invalidateAll</td>
* <td>Force the relinking of invokedynamic call sites everywhere.</td>
* <td>This could allow an attacker to slow down the system, or perhaps surface timing bugs in a dynamic language implementations, by forcing redundant relinking operations.</td>
* <td>This could allow an attacker to slow down the system,
* or perhaps expose timing bugs in a dynamic language implementations,
* by forcing redundant relinking operations.</td>
* </tr>
*
*
......@@ -78,7 +74,7 @@ import java.util.StringTokenizer;
* </tr>
* </table>
*
* @see java.security.BasicPermission
* @see java.security.RuntimePermission
* @see java.lang.SecurityManager
*
* @author John Rose, JSR 292 EG
......
......@@ -34,32 +34,34 @@ 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.
* A method handle is a typed, directly executable reference to a method,
* constructor, field, or similar low-level operation, with optional
* conversion or substitution of arguments or return values.
* <p>
* Method handles are strongly typed according to signature.
* They are not distinguished by method name or enclosing class.
* A method handle must be invoked under a signature which exactly matches
* the method handle's own type.
* the method handle's own {@link MethodType method type}.
* <p>
* Every method handle confesses its type via the <code>type</code> accessor.
* Every method handle confesses its type via the {@code type} accessor.
* The structure of this type is a series of classes, one of which is
* the return type of the method (or <code>void.class</code> if none).
* the return type of the method (or {@code void.class} if none).
* <p>
* Every method handle appears as an object containing a method named
* <code>invoke</code>, whose signature exactly matches
* {@code invoke}, whose signature exactly matches
* the method handle's type.
* A Java method call expression, which compiles to an
* <code>invokevirtual</code> instruction,
* {@code invokevirtual} 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.
* (The type is specified in the <code>invokevirtual</code> instruction,
* (The type is specified in the {@code invokevirtual} instruction,
* via a {@code CONSTANT_NameAndType} constant pool entry.)
* The call looks within the receiver object for a method
* named <code>invoke</code> of the intended method type.
* named {@code invoke} of the intended method type.
* The call fails with a {@link WrongMethodTypeException}
* if the method does not exist, even if there is an <code>invoke</code>
* if the method does not exist, even if there is an {@code invoke}
* method of a closely similar signature.
* As with other kinds
* of methods in the JVM, signature matching during method linkage
......@@ -76,13 +78,13 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* They should not be passed to untrusted code.
* <p>
* Bytecode in an extended JVM can directly call a method handle's
* <code>invoke</code> from an <code>invokevirtual</code> instruction.
* The receiver class type must be <code>MethodHandle</code> and the method name
* must be <code>invoke</code>. The signature of the invocation
* {@code invoke} from an {@code invokevirtual} instruction.
* The receiver class type must be {@code MethodHandle} and the method name
* must be {@code invoke}. The signature of the invocation
* (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},
* Every {@code invoke} 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),
......@@ -92,11 +94,11 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* 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
* <code>CONSTANT_InterfaceMethodref</code> constant pool entry.
* for any accessible method from a {@code ldc} instruction
* which refers to a {@code CONSTANT_Methodref} or
* {@code CONSTANT_InterfaceMethodref} constant pool entry.
* <p>
* All JVMs can also use a reflective API called <code>MethodHandles</code>
* All JVMs can also use a reflective API called {@code MethodHandles}
* for creating and calling method handles.
* <p>
* A method reference may refer either to a static or non-static method.
......@@ -104,7 +106,7 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* receiver argument, prepended before any other arguments.
* In the method handle's type, the initial receiver argument is typed
* according to the class under which the method was initially requested.
* (E.g., if a non-static method handle is obtained via <code>ldc</code>,
* (E.g., if a non-static method handle is obtained via {@code ldc},
* the type of the receiver is the class named in the constant pool entry.)
* <p>
* When a method handle to a virtual method is invoked, the method is
......@@ -113,38 +115,38 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* A non-virtual method handles to a specific virtual method implementation
* 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.
* an {@code invokespecial} 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);
Object x, y; String s; int i;
MethodType mt; MethodHandle mh;
MethodHandles.Lookup lookup = MethodHandles.lookup();
// mt is {(char,char) =&gt; String}
mt = MethodType.methodType(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;invokeExact("daddy",'d','n');
assert(s.equals("nanny"));
// weakly typed invocation (using MHs.invoke)
s = (String) mh.invokeVarargs("sappy", 'p', 'v');
assert(s.equals("savvy"));
// mt is {Object[] =&gt; List}
mt = MethodType.methodType(java.util.List.class, Object[].class);
mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
// mt is {(Object,Object,Object) =&gt; Object}
mt = MethodType.genericMethodType(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.invokeExact((Object)1, (Object)2, (Object)3);
assert(x.equals(java.util.Arrays.asList(1,2,3)));
// mt is { =&gt; int}
mt = MethodType.methodType(int.class);
mh = lookup.findVirtual(java.util.List.class, "size", mt);
// (Ljava/util/List;)I
i = mh.&lt;int&gt;invokeExact(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.
......@@ -167,6 +169,14 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* those of multiple arities. It is impossible to represent such
* genericity with a Java type parameter.</li>
* </ol>
* Signature polymorphic methods in this class appear to be documented
* as having type parameters for return types and a parameter, but that is
* merely a documentation convention. These type parameters do
* not play a role in type-checking method handle invocations.
* <p>
* Note: Like classes and strings, method handles that correspond directly
* to fields and methods can be represented directly as constants to be
* loaded by {@code ldc} bytecodes.
*
* @see MethodType
* @see MethodHandles
......@@ -180,7 +190,15 @@ public abstract class MethodHandle
private static Access IMPL_TOKEN = Access.getToken();
// interface MethodHandle<R throws X extends Exception,A...>
// { MethodType<R throws X,A...> type(); public R invoke(A...) throws X; }
// { MethodType<R throws X,A...> type(); public R invokeExact(A...) throws X; }
/**
* Internal marker interface which distinguishes (to the Java compiler)
* those methods which are signature polymorphic.
*/
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD,java.lang.annotation.ElementType.TYPE})
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS)
@interface PolymorphicSignature { }
private MethodType type;
......@@ -232,85 +250,38 @@ public abstract class MethodHandle
return MethodHandleImpl.getNameString(IMPL_TOKEN, this);
}
//// First draft of the "Method Handle Kernel API" discussed at the JVM Language Summit, 9/2009.
//// This is 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
* Invoke the method handle, allowing any caller signature, but requiring an exact signature match.
* 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");
}
public final native @PolymorphicSignature <R,A> R invokeExact(A... args) throws Throwable;
// FIXME: remove this transitional form
/** @deprecated transitional form defined in EDR but removed in PFD */
public final native @PolymorphicSignature <R,A> R invoke(A... args) throws Throwable;
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Perform a generic invocation. The signature at the call site of {@code invokeExact} must
* Invoke the method handle, allowing any caller signature,
* and performing simple conversions for arguments and return types.
* The signature at the call site of {@code invokeGeneric} 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);
}
public final native @PolymorphicSignature <R,A> R invokeGeneric(A... args) throws Throwable;
// ?? public final native @PolymorphicSignature <R,A,V> R invokeVarargs(A args, V[] varargs) throws Throwable;
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
......@@ -341,47 +312,47 @@ public abstract class MethodHandle
* 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);
* Object result = invoker.invokeExact(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 {
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,
case 0: return invoker.invokeExact(this);
case 1: return invoker.invokeExact(this,
arguments[0]);
case 2: return invoker.invoke(this,
case 2: return invoker.invokeExact(this,
arguments[0], arguments[1]);
case 3: return invoker.invoke(this,
case 3: return invoker.invokeExact(this,
arguments[0], arguments[1], arguments[2]);
case 4: return invoker.invoke(this,
case 4: return invoker.invokeExact(this,
arguments[0], arguments[1], arguments[2],
arguments[3]);
case 5: return invoker.invoke(this,
case 5: return invoker.invokeExact(this,
arguments[0], arguments[1], arguments[2],
arguments[3], arguments[4]);
case 6: return invoker.invoke(this,
case 6: return invoker.invokeExact(this,
arguments[0], arguments[1], arguments[2],
arguments[3], arguments[4], arguments[5]);
case 7: return invoker.invoke(this,
case 7: return invoker.invokeExact(this,
arguments[0], arguments[1], arguments[2],
arguments[3], arguments[4], arguments[5],
arguments[6]);
case 8: return invoker.invoke(this,
case 8: return invoker.invokeExact(this,
arguments[0], arguments[1], arguments[2],
arguments[3], arguments[4], arguments[5],
arguments[6], arguments[7]);
case 9: return invoker.invoke(this,
case 9: return invoker.invokeExact(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,
case 10: return invoker.invokeExact(this,
arguments[0], arguments[1], arguments[2],
arguments[3], arguments[4], arguments[5],
arguments[6], arguments[7], arguments[8],
......@@ -391,7 +362,7 @@ public abstract class MethodHandle
// more than ten arguments get boxed in a varargs list:
MethodHandle invoker = MethodHandles.invokers(type).varargsInvoker(0);
return invoker.invoke(this, arguments);
return invoker.invokeExact(this, arguments);
}
/** Equivalent to {@code invokeVarargs(arguments.toArray())}. */
public final Object invokeVarargs(java.util.List<?> arguments) throws Throwable {
......
/*
* Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2008-2010 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
......@@ -44,13 +44,13 @@ import static sun.dyn.MemberName.newIllegalArgumentException;
import static sun.dyn.MemberName.newNoAccessException;
/**
* Fundamental operations and utilities for MethodHandle.
* They fall into several categories:
* This class consists exclusively of static methods that operate on or return
* method handles. They fall into several categories:
* <ul>
* <li>Reifying methods and fields. This is subject to access checks.
* <li>Invoking method handles on dynamically typed arguments and/or varargs arrays.
* <li>Combining or transforming pre-existing method handles into new ones.
* <li>Miscellaneous emulation of common JVM operations or control flow patterns.
* <li>Factory methods which create method handles for methods and fields.
* <li>Invoker methods which can invoke method handles on dynamically typed arguments and/or varargs arrays.
* <li>Combinator methods, which combine or transforming pre-existing method handles into new ones.
* <li>Factory methods which create method handles that emulate other common JVM operations or control flow patterns.
* </ul>
* <p>
* @author John Rose, JSR 292 EG
......@@ -66,36 +66,44 @@ public class MethodHandles {
//// Method handle creation from ordinary methods.
/** Create a {@link Lookup} lookup object on the caller.
*
/**
* Return a {@link Lookup lookup object} on the caller,
* which has the capability to access any method handle that the caller has access to,
* including direct method handles to private fields and methods.
* This lookup object is a <em>capability</em> which may be delegated to trusted agents.
* Do not store it in place where untrusted code can access it.
*/
public static Lookup lookup() {
return new Lookup();
}
/** Version of lookup which is trusted minimally.
/**
* Return a {@link Lookup lookup object} which is trusted minimally.
* It can only be used to create method handles to
* publicly accessible members.
* publicly accessible fields and methods.
*/
public static Lookup publicLookup() {
return Lookup.PUBLIC_LOOKUP;
}
/**
* A factory object for creating method handles, when the creation
* requires access checking. Method handles do not perform
* A <em>lookup object</em> is a factory for creating method handles,
* when the creation requires access checking.
* Method handles do not perform
* access checks when they are called; this is a major difference
* from reflective {@link Method}, which performs access checking
* against every caller, on every call. Method handle access
* restrictions are enforced when a method handle is created.
* against every caller, on every call.
* Therefore, method handle access
* restrictions must be enforced when a method handle is created.
* The caller class against which those restrictions are enforced
* is known as the "lookup class". {@link Lookup} embodies an
* is known as the {@linkplain #lookupClass lookup class}.
* A lookup object embodies an
* authenticated lookup class, and can be used to create any number
* of access-checked method handles, all checked against a single
* lookup class.
* <p>
* A class which needs to create method handles will call
* {@code MethodHandles.lookup()} to create a factory for itself.
* {@link MethodHandles#lookup MethodHandles.lookup} to create a factory for itself.
* It may then use this factory to create method handles on
* all of its methods, including private ones.
* It may also delegate the lookup (e.g., to a metaobject protocol)
......@@ -104,12 +112,13 @@ public class MethodHandles {
* checked against the original lookup class, and not with any higher
* privileges.
* <p>
* Note that access checks only apply to named and reflected methods.
* Other method handle creation methods, such as {@link #convertArguments},
* Access checks only apply to named and reflected methods.
* Other method handle creation methods, such as
* {@link #convertArguments MethodHandles.convertArguments},
* do not require any access checks, and can be done independently
* of any lookup class.
* <p>
* <em>A note about error conditions:<em> A lookup can fail, because
* <h3>How access errors are handled</h3>
* A lookup can fail, because
* the containing class is not accessible to the lookup class, or
* because the desired class member is missing, or because the
* desired class member is not accessible to the lookup class.
......@@ -124,8 +133,25 @@ public class MethodHandles {
*/
public static final
class Lookup {
/** The class on behalf of whom the lookup is being performed. */
private final Class<?> lookupClass;
/** The allowed sorts of members which may be looked up (public, etc.), with STRICT for package. */
private final int allowedModes;
private static final int
PUBLIC = Modifier.PUBLIC,
PACKAGE = Modifier.STRICT,
PROTECTED = Modifier.PROTECTED,
PRIVATE = Modifier.PRIVATE,
ALL_MODES = (PUBLIC | PACKAGE | PROTECTED | PRIVATE),
TRUSTED = -1;
private static int fixmods(int mods) {
mods &= (ALL_MODES - PACKAGE);
return (mods != 0) ? mods : PACKAGE;
}
/** Which class is performing the lookup? It is this class against
* which checks are performed for visibility and access permissions.
* <p>
......@@ -136,57 +162,90 @@ public class MethodHandles {
return lookupClass;
}
// This is just for calling out to MethodHandleImpl.
private Class<?> lookupClassOrNull() {
return (allowedModes == TRUSTED) ? null : lookupClass;
}
/** Which types of members can this lookup object produce?
* The result is a bit-mask of the modifier bits PUBLIC, PROTECTED, PRIVATE, and STRICT.
* The modifier bit STRICT stands in for the (non-existent) package protection mode.
*/
int lookupModes() {
return allowedModes & ALL_MODES;
}
/** Embody the current class (the lookupClass) as a lookup class
* for method handle creation.
* Must be called by from a method in this package,
* which in turn is called by a method not in this package.
* <p>
* Also, don't make it private, lest javac interpose
* an access$N method.
*/
Lookup() {
this(IMPL_TOKEN, getCallerClassAtEntryPoint());
this(getCallerClassAtEntryPoint(), ALL_MODES);
// make sure we haven't accidentally picked up a privileged class:
checkUnprivilegedlookupClass(lookupClass);
}
Lookup(Access token, Class<?> lookupClass) {
// make sure we haven't accidentally picked up a privileged class:
checkUnprivilegedlookupClass(lookupClass);
this(lookupClass, ALL_MODES);
Access.check(token);
}
private Lookup(Class<?> lookupClass, int allowedModes) {
this.lookupClass = lookupClass;
this.allowedModes = allowedModes;
}
/**
* Create a lookup on the specified class.
* The result is guaranteed to have no more access privileges
* than the original.
* Create a lookup on the specified new lookup class.
* The resulting object will report the specified
* class as its own {@link #lookupClass}.
* <p>
* However, the resulting {@code Lookup} object is guaranteed
* to have no more access capabilities than the original.
* In particular:<ul>
* <li>If the new lookup class differs from the old one,
* protected members will not be accessible by virtue of inheritance.
* <li>If the new lookup class is in a different package
* than the old one, protected and default (package) members will not be accessible.
* <li>If the new lookup class is not within the same package member
* as the old one, private members will not be accessible.
* <li>In all cases, public members will continue to be accessible.
* </ul>
*/
public Lookup in(Class<?> newLookupClass) {
if (this == PUBLIC_LOOKUP) return PUBLIC_LOOKUP;
if (newLookupClass == null) return PUBLIC_LOOKUP;
if (newLookupClass == lookupClass) return this;
if (this != IMPL_LOOKUP) {
if (!VerifyAccess.isSamePackage(lookupClass, newLookupClass))
throw newNoAccessException(new MemberName(newLookupClass), this);
checkUnprivilegedlookupClass(newLookupClass);
public Lookup in(Class<?> requestedLookupClass) {
requestedLookupClass.getClass(); // null check
if (allowedModes == TRUSTED) // IMPL_LOOKUP can make any lookup at all
return new Lookup(requestedLookupClass, ALL_MODES);
if (requestedLookupClass == this.lookupClass)
return this; // keep same capabilities
int newModes = (allowedModes & (ALL_MODES & ~PROTECTED));
if ((newModes & PACKAGE) != 0
&& !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) {
newModes &= ~(PACKAGE|PRIVATE);
}
return new Lookup(newLookupClass);
if ((newModes & PRIVATE) != 0
&& !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) {
newModes &= ~PRIVATE;
}
private Lookup(Class<?> lookupClass) {
this.lookupClass = lookupClass;
checkUnprivilegedlookupClass(requestedLookupClass);
return new Lookup(requestedLookupClass, newModes);
}
// Make sure outer class is initialized first.
static { IMPL_TOKEN.getClass(); }
private static final Class<?> PUBLIC_ONLY = sun.dyn.empty.Empty.class;
/** Version of lookup which is trusted minimally.
* It can only be used to create method handles to
* publicly accessible members.
*/
static final Lookup PUBLIC_LOOKUP = new Lookup(PUBLIC_ONLY);
static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, PUBLIC);
/** Package-private version of lookup which is trusted. */
static final Lookup IMPL_LOOKUP = new Lookup(null);
static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED);
static { MethodHandleImpl.initLookup(IMPL_TOKEN, IMPL_LOOKUP); }
private static void checkUnprivilegedlookupClass(Class<?> lookupClass) {
......@@ -195,13 +254,35 @@ public class MethodHandles {
throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
}
/** Display the name of the class.
* If there are restrictions on the access permitted to this lookup,
* display those also.
*/
@Override
public String toString() {
if (lookupClass == PUBLIC_ONLY)
return "public";
if (lookupClass == null)
return "privileged";
return lookupClass.getName();
String modestr;
String cname = lookupClass.getName();
switch (allowedModes) {
case TRUSTED:
return "/trusted";
case PUBLIC:
modestr = "/public";
if (lookupClass == Object.class)
return modestr;
break;
case PUBLIC|PACKAGE:
return cname + "/package";
case 0: // should not happen
return cname + "/empty";
case ALL_MODES:
return cname;
}
StringBuilder buf = new StringBuilder(cname);
if ((allowedModes & PUBLIC) != 0) buf.append("/public");
if ((allowedModes & PACKAGE) != 0) buf.append("/package");
if ((allowedModes & PROTECTED) != 0) buf.append("/protected");
if ((allowedModes & PRIVATE) != 0) buf.append("/private");
return buf.toString();
}
// call this from an entry point method in Lookup with extraFrames=0.
......@@ -219,11 +300,11 @@ public class MethodHandles {
* The type of the method handle will be that of the method.
* (Since static methods do not take receivers, there is no
* additional receiver argument inserted into the method handle type,
* as there would be with {@linkplain #findVirtual} or {@linkplain #findSpecial}.)
* as there would be with {@link #findVirtual} or {@link #findSpecial}.)
* The method and all its argument types must be accessible to the lookup class.
* If the method's class has not yet been initialized, that is done
* immediately, before the method handle is returned.
* @param defc the class from which the method is accessed
* @param refc the class from which the method is accessed
* @param name the name of the method
* @param type the type of the method
* @return the desired method handle
......@@ -231,18 +312,16 @@ public class MethodHandles {
* @exception NoAccessException if the method does not exist or access checking fails
*/
public
MethodHandle findStatic(Class<?> defc, String name, MethodType type) throws NoAccessException {
MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookupClass());
VerifyAccess.checkName(method, this);
checkStatic(true, method, this);
//throw NoSuchMethodException
return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClass());
MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoAccessException {
MemberName method = resolveOrFail(refc, name, type, true);
checkMethod(refc, method, true);
return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClassOrNull());
}
/**
* Produce a method handle for a virtual method.
* The type of the method handle will be that of the method,
* with the receiver type ({@code defc}) prepended.
* with the receiver type (usually {@code refc}) prepended.
* The method and all its argument types must be accessible to the lookup class.
* <p>
* (<em>BUG NOTE:</em> The type {@code Object} may be prepended instead
......@@ -257,18 +336,44 @@ public class MethodHandles {
* implementation to enter.
* (The dispatching action is identical with that performed by an
* {@code invokevirtual} or {@code invokeinterface} instruction.)
* @param defc the class or interface from which the method is accessed
* @param refc the class or interface from which the method is accessed
* @param name the name of the method
* @param type the type of the method, with the receiver argument omitted
* @return the desired method handle
* @exception SecurityException <em>TBD</em>
* @exception NoAccessException if the method does not exist or access checking fails
*/
public MethodHandle findVirtual(Class<?> defc, String name, MethodType type) throws NoAccessException {
MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), true, lookupClass());
VerifyAccess.checkName(method, this);
checkStatic(false, method, this);
return MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass());
public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoAccessException {
MemberName method = resolveOrFail(refc, name, type, false);
checkMethod(refc, method, false);
MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull());
return restrictProtectedReceiver(method, mh);
}
/**
* Produce a method handle which creates an object and initializes it, using
* the constructor of the specified type.
* The parameter types of the method handle will be those of the constructor,
* while the return type will be a reference to the constructor's class.
* The constructor and all its argument types must be accessible to the lookup class.
* If the constructor's class has not yet been initialized, that is done
* immediately, before the method handle is returned.
* <p>
* Note: The requested type must have a return type of {@code void}.
* This is consistent with the JVM's treatment of constructor signatures.
* @param refc the class or interface from which the method is accessed
* @param type the type of the method, with the receiver argument omitted, and a void return type
* @return the desired method handle
* @exception SecurityException <em>TBD</em>
* @exception NoAccessException if the method does not exist or access checking fails
*/
public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoAccessException {
String name = "<init>";
MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull());
assert(ctor.isConstructor());
checkAccess(refc, ctor);
MethodHandle rawMH = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull());
return MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawMH);
}
/**
......@@ -287,27 +392,60 @@ public class MethodHandles {
* <p>
* If the explicitly specified caller class is not identical with the
* lookup class, a security check TBD is performed.
* @param defc the class or interface from which the method is accessed
* @param name the name of the method, or "<init>" for a constructor
* @param refc the class or interface from which the method is accessed
* @param name the name of the method (which must not be "&lt;init&gt;")
* @param type the type of the method, with the receiver argument omitted
* @param specialCaller the proposed calling class to perform the {@code invokespecial}
* @return the desired method handle
* @exception SecurityException <em>TBD</em>
* @exception NoAccessException if the method does not exist or access checking fails
*/
public MethodHandle findSpecial(Class<?> defc, String name, MethodType type,
public MethodHandle findSpecial(Class<?> refc, String name, MethodType type,
Class<?> specialCaller) throws NoAccessException {
checkSpecialCaller(specialCaller, this);
Lookup slookup = this.in(specialCaller);
MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), false, slookup.lookupClass());
VerifyAccess.checkName(method, this);
checkStatic(false, method, this);
if (name.equals("<init>")) {
throw newNoAccessException("cannot directly invoke a constructor", method, null);
} else if (defc.isInterface() || !defc.isAssignableFrom(specialCaller)) {
throw newNoAccessException("method must be in a superclass of lookup class", method, slookup.lookupClass());
checkSpecialCaller(specialCaller);
MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller);
checkMethod(refc, method, false);
MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller);
return restrictReceiver(method, mh, specialCaller);
}
return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, slookup.lookupClass());
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle giving read access to a field.
* The type of the method handle will have a return type of the field's
* value type.
* If the field is static, the method handle will take no arguments.
* Otherwise, its single argument will be the instance containing
* the field.
* Access checking is performed immediately on behalf of the lookup class.
* @param name the field's name
* @param type the field's type
* @param isStatic true if and only if the field is static
* @return a method handle which can load values from the field
* @exception NoAccessException if access checking fails
*/
public MethodHandle findGetter(Class<?> refc, String name, Class<?> type, boolean isStatic) throws NoAccessException {
return makeAccessor(refc, name, type, isStatic, false);
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle giving write access to a reflected field.
* The type of the method handle will have a void return type.
* If the field is static, the method handle will take a single
* argument, of the field's value type, the value to be stored.
* Otherwise, the two arguments will be the instance containing
* the field, and the value to be stored.
* Access checking is performed immediately on behalf of the lookup class.
* @param name the field's name
* @param type the field's type
* @param isStatic true if and only if the field is static
* @return a method handle which can store values into the reflected field
* @exception NoAccessException if access checking fails
*/
public MethodHandle findSetter(Class<?> refc, String name, Class<?> type,
boolean isStatic) throws NoAccessException {
return makeAccessor(refc, name, type, isStatic, true);
}
/**
......@@ -323,7 +461,7 @@ public class MethodHandles {
* <p>
* This is equivalent to the following expression:
* <code>
* {@link #insertArguments}({@link #findVirtual}(defc, name, type), receiver)
* {@link #insertArguments insertArguments}({@link #findVirtual findVirtual}(defc, name, type), receiver)
* </code>
* where {@code defc} is either {@code receiver.getClass()} or a super
* type of that class, in which the requested method is accessible
......@@ -336,15 +474,13 @@ public class MethodHandles {
* @exception NoAccessException if the method does not exist or access checking fails
*/
public MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException {
Class<? extends Object> rcvc = receiver.getClass(); // may get NPE
MemberName reference = new MemberName(rcvc, name, type);
MemberName method = IMPL_NAMES.resolveOrFail(reference, true, lookupClass());
VerifyAccess.checkName(method, this);
checkStatic(false, method, this);
MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass());
Class<? extends Object> refc = receiver.getClass(); // may get NPE
MemberName method = resolveOrFail(refc, name, type, false);
checkMethod(refc, method, false);
MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull());
MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver);
if (bmh == null)
throw newNoAccessException(method, this);
throw newNoAccessException(method, lookupClass());
return bmh;
}
......@@ -364,29 +500,37 @@ public class MethodHandles {
* @exception NoAccessException if access checking fails
*/
public MethodHandle unreflect(Method m) throws NoAccessException {
return unreflectImpl(new MemberName(m), m.isAccessible(), true, false, this);
MemberName method = new MemberName(m);
assert(method.isMethod());
if (!m.isAccessible()) checkMethod(method.getDeclaringClass(), method, method.isStatic());
MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull());
if (!m.isAccessible()) mh = restrictProtectedReceiver(method, mh);
return mh;
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle for a reflected method.
* It will bypass checks for overriding methods on the receiver,
* as if by the {@code invokespecial} instruction.
* as if by a {@code invokespecial} instruction from within the {@code specialCaller}.
* The type of the method handle will be that of the method,
* with the receiver type prepended.
* with the special caller type prepended (and <em>not</em> the receiver of the method).
* If the method's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class,
* as if {@code invokespecial} instruction were being linked.
* @param m the reflected method
* @param specialCaller the class nominally calling the method
* @return a method handle which can invoke the reflected method
* @exception NoAccessException if access checking fails
*/
public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws NoAccessException {
checkSpecialCaller(specialCaller, this);
Lookup slookup = this.in(specialCaller);
MemberName mname = new MemberName(m);
checkStatic(false, mname, this);
return unreflectImpl(mname, m.isAccessible(), false, false, slookup);
checkSpecialCaller(specialCaller);
MemberName method = new MemberName(m);
assert(method.isMethod());
// ignore m.isAccessible: this is a new kind of access
checkMethod(m.getDeclaringClass(), method, false);
MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClassOrNull());
return restrictReceiver(method, mh, specialCaller);
}
/**
......@@ -400,13 +544,16 @@ public class MethodHandles {
* <p>
* If the constructor's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class.
* @param ctor the reflected constructor
* @param c the reflected constructor
* @return a method handle which can invoke the reflected constructor
* @exception NoAccessException if access checking fails
*/
public MethodHandle unreflectConstructor(Constructor ctor) throws NoAccessException {
MemberName m = new MemberName(ctor);
return unreflectImpl(m, ctor.isAccessible(), false, false, this);
public MethodHandle unreflectConstructor(Constructor c) throws NoAccessException {
MemberName ctor = new MemberName(c);
assert(ctor.isConstructor());
if (!c.isAccessible()) checkAccess(c.getDeclaringClass(), ctor);
MethodHandle rawCtor = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull());
return MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawCtor);
}
/**
......@@ -424,8 +571,7 @@ public class MethodHandles {
* @exception NoAccessException if access checking fails
*/
public MethodHandle unreflectGetter(Field f) throws NoAccessException {
MemberName m = new MemberName(f);
return unreflectImpl(m, f.isAccessible(), false, false, this);
return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), false);
}
/**
......@@ -443,75 +589,134 @@ public class MethodHandles {
* @exception NoAccessException if access checking fails
*/
public MethodHandle unreflectSetter(Field f) throws NoAccessException {
MemberName m = new MemberName(f);
return unreflectImpl(m, f.isAccessible(), false, true, this);
return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), true);
}
/// Helper methods, all package-private.
MemberName resolveOrFail(Class<?> refc, String name, Class<?> type, boolean isStatic) {
checkSymbolicClass(refc); // do this before attempting to resolve
int mods = (isStatic ? Modifier.STATIC : 0);
return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull());
}
static /*must not be public*/
MethodHandle findStaticFrom(Lookup lookup,
Class<?> defc, String name, MethodType type) throws NoAccessException {
MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookup.lookupClass());
VerifyAccess.checkName(method, lookup);
checkStatic(true, method, lookup);
return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookup.lookupClass());
MemberName resolveOrFail(Class<?> refc, String name, MethodType type, boolean isStatic) {
checkSymbolicClass(refc); // do this before attempting to resolve
int mods = (isStatic ? Modifier.STATIC : 0);
return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull());
}
static void checkStatic(boolean wantStatic, MemberName m, Lookup lookup) {
if (wantStatic != m.isStatic()) {
String message = wantStatic ? "expected a static method" : "expected a non-static method";
throw newNoAccessException(message, m, lookup.lookupClass());
MemberName resolveOrFail(Class<?> refc, String name, MethodType type, boolean isStatic,
boolean searchSupers, Class<?> specialCaller) {
checkSymbolicClass(refc); // do this before attempting to resolve
int mods = (isStatic ? Modifier.STATIC : 0);
return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), searchSupers, specialCaller);
}
void checkSymbolicClass(Class<?> refc) {
Class<?> caller = lookupClassOrNull();
if (caller != null && !VerifyAccess.isClassAccessible(refc, caller))
throw newNoAccessException("symbolic reference class is not public", new MemberName(refc), caller);
}
static void checkSpecialCaller(Class<?> specialCaller, Lookup lookup) {
if (lookup == Lookup.IMPL_LOOKUP)
return; // privileged action
assert(lookup.lookupClass() != null);
if (!VerifyAccess.isSamePackageMember(specialCaller, lookup.lookupClass()))
throw newNoAccessException("no private access", new MemberName(specialCaller), lookup.lookupClass());
void checkMethod(Class<?> refc, MemberName m, boolean wantStatic) {
String message;
if (m.isConstructor())
message = "expected a method, not a constructor";
else if (!m.isMethod())
message = "expected a method";
else if (wantStatic != m.isStatic())
message = wantStatic ? "expected a static method" : "expected a non-static method";
else
{ checkAccess(refc, m); return; }
throw newNoAccessException(message, m, lookupClass());
}
// Helper for creating handles on reflected methods and constructors.
static MethodHandle unreflectImpl(MemberName m, boolean isAccessible,
boolean doDispatch, boolean isSetter, Lookup lookup) {
MethodType narrowMethodType = null;
void checkAccess(Class<?> refc, MemberName m) {
int allowedModes = this.allowedModes;
if (allowedModes == TRUSTED) return;
int mods = m.getModifiers();
if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers()))
return; // common case
int requestedModes = fixmods(mods); // adjust 0 => PACKAGE
if ((requestedModes & allowedModes) != 0
&& VerifyAccess.isMemberAccessible(refc, m.getDeclaringClass(),
mods, lookupClass()))
return;
if (((requestedModes & ~allowedModes) & PROTECTED) != 0
&& VerifyAccess.isSamePackage(m.getDeclaringClass(), lookupClass()))
// Protected members can also be checked as if they were package-private.
return;
throw newNoAccessException(accessFailedMessage(refc, m), m, lookupClass());
}
String accessFailedMessage(Class<?> refc, MemberName m) {
Class<?> defc = m.getDeclaringClass();
boolean isSpecialInvoke = m.isInvocable() && !doDispatch;
int mods = m.getModifiers();
if (m.isStatic()) {
if (!isAccessible &&
VerifyAccess.isAccessible(defc, mods, lookup.lookupClass(), false) == null)
throw newNoAccessException(m, lookup);
} else {
Class<?> constraint;
if (isAccessible) {
// abbreviated access check for "unlocked" method
constraint = doDispatch ? defc : lookup.lookupClass();
} else {
constraint = VerifyAccess.isAccessible(defc, mods, lookup.lookupClass(), isSpecialInvoke);
}
if (constraint == null) {
throw newNoAccessException(m, lookup);
}
if (constraint != defc && !constraint.isAssignableFrom(defc)) {
if (!defc.isAssignableFrom(constraint))
throw newNoAccessException("receiver must be in caller class", m, lookup.lookupClass());
if (m.isInvocable())
narrowMethodType = m.getInvocationType().changeParameterType(0, constraint);
else if (m.isField())
narrowMethodType = (!isSetter
? MethodType.methodType(m.getFieldType(), constraint)
: MethodType.methodType(void.class, constraint, m.getFieldType()));
}
}
if (m.isInvocable())
return MethodHandleImpl.findMethod(IMPL_TOKEN, m, doDispatch, lookup.lookupClass());
else if (m.isField())
return MethodHandleImpl.accessField(IMPL_TOKEN, m, isSetter, lookup.lookupClass());
if (!VerifyAccess.isClassAccessible(defc, lookupClass()))
return "class is not public";
if (refc != defc && !VerifyAccess.isClassAccessible(refc, lookupClass()))
return "symbolic reference "+refc.getName()+" is not public";
if (Modifier.isPublic(mods))
return "access to public member failed"; // (how?)
else if (allowedModes == PUBLIC)
return "member is not public";
if (Modifier.isPrivate(mods))
return "member is private";
if (Modifier.isProtected(mods))
return "member is protected";
return "member is private to package";
}
void checkSpecialCaller(Class<?> specialCaller) {
if (allowedModes == TRUSTED) return;
if (!VerifyAccess.isSamePackageMember(specialCaller, lookupClass()))
throw newNoAccessException("no private access for invokespecial",
new MemberName(specialCaller), lookupClass());
}
MethodHandle restrictProtectedReceiver(MemberName method, MethodHandle mh) {
// The accessing class only has the right to use a protected member
// on itself or a subclass. Enforce that restriction, from JVMS 5.4.4, etc.
if (!method.isProtected() || method.isStatic()
|| allowedModes == TRUSTED
|| VerifyAccess.isSamePackageMember(method.getDeclaringClass(), lookupClass()))
return mh;
else
throw new InternalError();
return restrictReceiver(method, mh, lookupClass());
}
MethodHandle restrictReceiver(MemberName method, MethodHandle mh, Class<?> caller) {
assert(!method.isStatic());
Class<?> defc = method.getDeclaringClass(); // receiver type of mh is too wide
if (defc.isInterface() || !defc.isAssignableFrom(caller)) {
throw newNoAccessException("caller class must be a subclass below the method", method, caller);
}
MethodType rawType = mh.type();
if (rawType.parameterType(0) == caller) return mh;
MethodType narrowType = rawType.changeParameterType(0, caller);
return MethodHandleImpl.convertArguments(IMPL_TOKEN, mh, narrowType, rawType, null);
}
MethodHandle makeAccessor(Class<?> refc, String name, Class<?> type,
boolean isStatic, boolean isSetter) throws NoAccessException {
MemberName field = resolveOrFail(refc, name, type, isStatic);
if (isStatic != field.isStatic())
throw newNoAccessException(isStatic
? "expected a static field"
: "expected a non-static field",
field, lookupClass());
return makeAccessor(refc, field, false, isSetter);
}
MethodHandle makeAccessor(Class<?> refc, MemberName field,
boolean trusted, boolean isSetter) throws NoAccessException {
assert(field.isField());
if (trusted)
return MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull());
checkAccess(refc, field);
MethodHandle mh = MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull());
return restrictProtectedReceiver(field, mh);
}
}
/**
......@@ -667,10 +872,15 @@ public class MethodHandles {
*/
public static
MethodHandle dynamicInvoker(CallSite site) {
MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, CallSite.GET_TARGET, site);
MethodHandle getCSTarget = GET_TARGET;
if (getCSTarget == null)
GET_TARGET = getCSTarget = Lookup.IMPL_LOOKUP.
findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, getCSTarget, site);
MethodHandle invoker = exactInvoker(site.type());
return foldArguments(invoker, getTarget);
}
private static MethodHandle GET_TARGET = null; // link this lazily, not eagerly
static Invokers invokers(MethodType type) {
return MethodTypeImpl.invokers(IMPL_TOKEN, type);
......@@ -1025,15 +1235,15 @@ public class MethodHandles {
* <p><blockquote><pre>
* MethodHandle cat = MethodHandles.lookup().
* findVirtual(String.class, "concat", String.class, String.class);
* System.out.println(cat.&lt;String&gt;invoke("x", "y")); // xy
* System.out.println(cat.&lt;String&gt;invokeExact("x", "y")); // xy
* MethodHandle d0 = dropArguments(cat, 0, String.class);
* System.out.println(d0.&lt;String&gt;invoke("x", "y", "z")); // xy
* System.out.println(d0.&lt;String&gt;invokeExact("x", "y", "z")); // xy
* MethodHandle d1 = dropArguments(cat, 1, String.class);
* System.out.println(d1.&lt;String&gt;invoke("x", "y", "z")); // xz
* System.out.println(d1.&lt;String&gt;invokeExact("x", "y", "z")); // xz
* MethodHandle d2 = dropArguments(cat, 2, String.class);
* System.out.println(d2.&lt;String&gt;invoke("x", "y", "z")); // yz
* System.out.println(d2.&lt;String&gt;invokeExact("x", "y", "z")); // yz
* MethodHandle d12 = dropArguments(cat, 1, String.class, String.class);
* System.out.println(d12.&lt;String&gt;invoke("w", "x", "y", "z")); // wz
* System.out.println(d12.&lt;String&gt;invokeExact("w", "x", "y", "z")); // wz
* </pre></blockquote>
* @param target the method handle to invoke after the argument is dropped
* @param valueTypes the type(s) of the argument to drop
......@@ -1254,7 +1464,7 @@ public class MethodHandles {
MethodHandle dispatch = compose(choose, test);
// dispatch = \(a...).(test(a...) ? target : fallback)
return combineArguments(invoke, dispatch, 0);
// return \(a...).((test(a...) ? target : fallback).invoke(a...))
// return \(a...).((test(a...) ? target : fallback).invokeExact(a...))
} */
return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback);
}
......@@ -1325,22 +1535,4 @@ public class MethodHandles {
MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) {
return MethodHandleImpl.throwException(IMPL_TOKEN, MethodType.methodType(returnType, exType));
}
/** Alias for {@link MethodType#methodType}. */
@Deprecated // "use MethodType.methodType instead"
public static MethodType methodType(Class<?> rtype) {
return MethodType.methodType(rtype);
}
/** Alias for {@link MethodType#methodType}. */
@Deprecated // "use MethodType.methodType instead"
public static MethodType methodType(Class<?> rtype, Class<?> ptype) {
return MethodType.methodType(rtype, ptype);
}
/** Alias for {@link MethodType#methodType}. */
@Deprecated // "use MethodType.methodType instead"
public static MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
return MethodType.methodType(rtype, ptype0, ptypes);
}
}
......@@ -36,15 +36,24 @@ import sun.dyn.util.BytecodeDescriptor;
import static sun.dyn.MemberName.newIllegalArgumentException;
/**
* Run-time token used to match call sites with method handles.
* A method type represents the arguments and return type accepted and
* returned by a method handle, or the arguments and return type passed
* and expected by a method handle caller. Method types must be properly
* matched between a method handle and all its callers,
* and the JVM's operations enforce this matching at all times.
* <p>
* The structure is a return type accompanied by any number of parameter types.
* The types (primitive, void, and reference) are represented by Class objects.
* <p>
* All instances of <code>MethodType</code> are immutable.
* Two instances are completely interchangeable if they compare equal.
* Equality depends exactly on the return and parameter types.
* Equality depends on pairwise correspondence of the return and parameter types and on nothing else.
* <p>
* This type can be created only by factory methods, which manage interning.
*
* This type can be created only by factory methods.
* All factory methods may cache values, though caching is not guaranteed.
* <p>
* Note: Like classes and strings, method types can be represented directly
* as constants to be loaded by {@code ldc} bytecodes.
* @author John Rose, JSR 292 EG
*/
public final
......@@ -109,7 +118,7 @@ class MethodType {
/** Find or create an instance of the given method type.
* @param rtype the return type
* @param ptypes the parameter types
* @return the interned method type with the given parts
* @return a method type with the given parts
* @throws NullPointerException if rtype or any ptype is null
* @throws IllegalArgumentException if any of the ptypes is void
*/
......@@ -626,7 +635,7 @@ class MethodType {
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* Find or create an instance (interned) of the given method type.
* Find or create an instance 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)}
* on the given loader (or if it is null, on the system class loader).
......
......@@ -27,11 +27,12 @@ package java.dyn;
/**
* Thrown to indicate that a caller has attempted to create a method handle
* which calls a method to which the caller does not have access.
* which accesses a field, method, or class to which the caller does not have access.
* This unchecked exception is analogous to {@link IllegalAccessException},
* which is a checked exception thrown when reflective invocation fails
* because of an access check. With method handles, this same access
* checking is performed on behalf of the method handle creator,
* checking is performed by the {@link MethodHandles.Lookup lookup object}
* on behalf of the method handle creator,
* at the time of creation.
* @author John Rose, JSR 292 EG
*/
......
......@@ -27,6 +27,105 @@
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* This package contains dynamic language support provided directly by
* the Java core class libraries and virtual machine.
* <p>
* Certain types in this package have special relations to dynamic
* language support in the virtual machine:
* <ul>
* <li>In source code, a call to
* {@link java.dyn.MethodHandle#invokeExact MethodHandle.invokeExact} or
* {@link java.dyn.MethodHandle#invokeGeneric MethodHandle.invokeGeneric}
* will compile and link, regardless of the requested type signature.
* As usual, the Java compiler emits an {@code invokevirtual}
* instruction with the given signature against the named method.
* The JVM links any such call (regardless of signature) to a dynamically
* typed method handle invocation. In the case of {@code invokeGeneric},
* argument and return value conversions are applied.
*
* <li>In source code, the class {@link java.dyn.InvokeDynamic} appears to accept
* any static method invocation, of any name and any signature.
* But instead of emitting
* an {@code invokestatic} instruction for such a call, the Java compiler emits
* an {@code invokedynamic} instruction with the given name and signature.
*
* <li>When the JVM links an {@code invokedynamic} instruction, it calls the
* {@linkplain java.dyn.Linkage#registerBootstrapMethod(Class, MethodHandle) bootstrap method}
* of the containing class to obtain a {@linkplain java.dyn.CallSite call site} object through which
* the call site will link its target {@linkplain java.dyn.MethodHandle method handle}.
*
* <li>The JVM bytecode format supports immediate constants of
* the classes {@link java.dyn.MethodHandle} and {@link java.dyn.MethodType}.
* </ul>
*
* <h2><a name="jvm_mods"></a>Corresponding JVM bytecode format changes</h2>
* <em>The following low-level information is presented here as a preview of
* changes being made to the Java Virtual Machine specification for JSR 292.</em>
*
* <h3>{@code invokedynamic} instruction format</h3>
* In bytecode, an {@code invokedynamic} instruction is formatted as five bytes.
* The first byte is the opcode 186 (hexadecimal {@code BA}).
* The next two bytes are a constant pool index (in the same format as for the other {@code invoke} instructions).
* The final two bytes are reserved for future use and required to be zero.
* The constant pool reference is to a entry with tag {@code CONSTANT_NameAndType}
* (decimal 12). It is thus not a method reference of any sort, but merely
* the method name, argument types, and return type of the dynamic call site.
* <em>(TBD: The EG is discussing the possibility of a special constant pool entry type,
* so that other information may be added, such as a per-instruction bootstrap
* method and/or annotations.)</em>
*
* <h3>constant pool entries for {@code MethodType}s</h3>
* If a constant pool entry has the tag {@code CONSTANT_MethodType} (decimal 16),
* it must contain exactly two more bytes, which are an index to a {@code CONSTANT_Utf8}
* entry which represents a method type signature. The JVM will ensure that on first
* execution of an {@code ldc} instruction for this entry, a {@link java.dyn.MethodType}
* will be created which represents the signature.
* Any classes mentioned in the {@code MethodType} will be loaded if necessary,
* but not initialized.
* Access checking and error reporting is performed exactly as it is for
* references by {@code ldc} instructions to {@code CONSTANT_Class} constants.
*
* <h3>constant pool entries for {@code MethodHandle}s</h3>
* If a constant pool entry has the tag {@code CONSTANT_MethodHandle} (decimal 15),
* it must contain exactly three more bytes. The first byte after the tag is a subtag
* value in the range 1 through 9, and the last two are an index to a
* {@code CONSTANT_Fieldref}, {@code CONSTANT_Methodref}, or
* {@code CONSTANT_InterfaceMethodref} entry which represents a field or method
* for which a method handle is to be created.
* The JVM will ensure that on first execution of an {@code ldc} instruction
* for this entry, a {@link java.dyn.MethodHandle} will be created which represents
* the field or method reference, according to the specific mode implied by the subtag.
* <p>
* As with {@code CONSTANT_Class} and {@code CONSTANT_MethodType} constants,
* the {@code Class} or {@code MethodType} object which reifies the field or method's
* type is created. Any classes mentioned in this reificaiton will be loaded if necessary,
* but not initialized, and access checking and error reporting performed as usual.
* <p>
* The method handle itself will have a type and behavior determined by the subtag as follows:
* <code>
* <table border=1 cellpadding=5 summary="CONSTANT_MethodHandle subtypes">
* <tr><th>N</th><th>subtag name</th><th>member</th><th>MH type</th><th>MH behavior</th></tr>
* <tr><td>1</td><td>REF_getField</td><td>C.f:T</td><td>(C)T</td><td>getfield C.f:T</td></tr>
* <tr><td>2</td><td>REF_getStatic</td><td>C.f:T</td><td>(&nbsp;)T</td><td>getstatic C.f:T</td></tr>
* <tr><td>3</td><td>REF_putField</td><td>C.f:T</td><td>(C,T)void</td><td>putfield C.f:T</td></tr>
* <tr><td>4</td><td>REF_putStatic</td><td>C.f:T</td><td>(T)void</td><td>putstatic C.f:T</td></tr>
* <tr><td>5</td><td>REF_invokeVirtual</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokevirtual C.m(A*)T</td></tr>
* <tr><td>6</td><td>REF_invokeStatic</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokestatic C.m(A*)T</td></tr>
* <tr><td>7</td><td>REF_invokeSpecial</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokespecial C.m(A*)T</td></tr>
* <tr><td>8</td><td>REF_newInvokeSpecial</td><td>C.&lt;init&gt;(A*)void</td><td>(A*)C</td><td>new C; dup; invokespecial C.&lt;init&gt;(A*)void</td></tr>
* <tr><td>9</td><td>REF_invokeInterface</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokeinterface C.m(A*)T</td></tr>
* </table>
* </code>
* <p>
* The special names {@code <init>} and {@code <clinit>} are not allowed except for subtag 8 as shown.
* <p>
* The verifier applies the same access checks and restrictions for these references as for the hypothetical
* bytecode instructions specified in the last column of the table. In particular, method handles to
* private and protected members can be created in exactly those classes for which the corresponding
* normal accesses are legal.
* <p>
* None of these constant types force class initialization.
* Method handles for subtags {@code REF_getStatic}, {@code REF_putStatic}, and {@code REF_invokeStatic}
* may force class initialization on their first invocation, just like the corresponding bytecodes.
*
* @author John Rose, JSR 292 EG
*/
......
......@@ -366,7 +366,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
}
private static boolean convOpSupported(int convOp) {
assert(convOp >= 0 && convOp <= CONV_OP_LIMIT);
return ((1<<convOp) & CONV_OP_IMPLEMENTED_MASK) != 0;
return ((1<<convOp) & MethodHandleNatives.CONV_OP_IMPLEMENTED_MASK) != 0;
}
/** One of OP_RETYPE_ONLY, etc. */
......
......@@ -146,6 +146,8 @@ public class BoundMethodHandle extends MethodHandle {
MethodType foundType = null;
MemberName foundMethod = null;
for (MemberName method : methods) {
if (method.getDeclaringClass() == MethodHandle.class)
continue; // ignore methods inherited from MH class itself
MethodType mtype = method.getMethodType();
if (type != null && type.parameterCount() != mtype.parameterCount())
continue;
......
......@@ -26,77 +26,65 @@
package sun.dyn;
import java.dyn.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Parts of CallSite known to the JVM.
* FIXME: Merge all this into CallSite proper.
* @author jrose
*/
public class CallSiteImpl {
// Field used only by the JVM. Do not use or change.
private Object vmmethod;
// Values supplied by the JVM:
protected int callerMID, callerBCI;
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;
}
/** 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;
// this implements the upcall from the JVM, MethodHandleNatives.makeDynamicCallSite:
static CallSite makeSite(MethodHandle bootstrapMethod,
// Callee information:
String name, MethodType type,
// Call-site attributes, if any:
Object info,
// Caller information:
MemberName callerMethod, int callerBCI) {
Class<?> caller = callerMethod.getDeclaringClass();
if (bootstrapMethod == null) {
// If there is no bootstrap method, throw IncompatibleClassChangeError.
// This is a valid generic error type for resolution (JLS 12.3.3).
throw new IncompatibleClassChangeError
("Class "+caller.getName()+" has not declared a bootstrap method for invokedynamic");
}
private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE =
MethodHandleImpl.IMPL_LOOKUP.findStatic(CallSite.class, "privateInitializeCallSite",
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,
int callerMID, int callerBCI) {
MethodHandle bsm = Linkage.getBootstrapMethod(caller);
if (bsm == null)
throw new InvokeDynamicBootstrapError("class has no bootstrap method: "+caller);
CallSite site;
try {
site = bsm.<CallSite>invoke(caller, name, type);
} catch (Throwable ex) {
throw new InvokeDynamicBootstrapError("exception thrown while linking", ex);
}
if (site == null)
if (bootstrapMethod.type().parameterCount() == 3)
site = bootstrapMethod.<CallSite>invokeExact(caller, name, type);
else if (bootstrapMethod.type().parameterCount() == 4)
site = bootstrapMethod.<CallSite>invokeExact(caller, name, type,
!(info instanceof java.lang.annotation.Annotation[]) ? null
: (java.lang.annotation.Annotation[]) info);
else
throw new InternalError("bad BSM: "+bootstrapMethod);
if (!(site instanceof CallSite))
throw new InvokeDynamicBootstrapError("class bootstrap method failed to create a call site: "+caller);
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);
PRIVATE_INITIALIZE_CALL_SITE.<void>invokeExact(site,
name, type,
callerMethod, callerBCI);
assert(site.getTarget() != null);
assert(site.getTarget().type().equals(type));
} catch (Throwable ex) {
throw new InvokeDynamicBootstrapError("call site initialization exception", ex);
InvokeDynamicBootstrapError bex;
if (ex instanceof InvokeDynamicBootstrapError)
bex = (InvokeDynamicBootstrapError) ex;
else
bex = new InvokeDynamicBootstrapError("call site initialization exception", ex);
throw bex;
}
return site;
}
// This method is private in CallSite because it touches private fields in CallSite.
// These private fields (vmmethod, vmindex) are specific to the JVM.
private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE =
MethodHandleImpl.IMPL_LOOKUP.findVirtual(CallSite.class, "initializeFromJVM",
MethodType.methodType(void.class,
String.class, MethodType.class,
MemberName.class, int.class));
public static void setCallSiteTarget(Access token, CallSite site, MethodHandle target) {
Access.check(token);
MethodHandleNatives.setCallSiteTarget(site, target);
}
}
因为 它太大了无法显示 source diff 。你可以改为 查看blob
......@@ -47,8 +47,8 @@ public class FilterOneArgument extends JavaMethodHandle {
}
protected Object invoke(Object argument) throws Throwable {
Object filteredArgument = filter.invoke(argument);
return target.invoke(filteredArgument);
Object filteredArgument = filter.invokeExact(argument);
return target.invokeExact(filteredArgument);
}
private static final MethodHandle INVOKE =
......
......@@ -289,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) 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); }
protected Object convert_L(Object result) throws Throwable { return convert.<Object>invokeExact(result); }
protected Object convert_I(int result) throws Throwable { return convert.<Object>invokeExact(result); }
protected Object convert_J(long result) throws Throwable { return convert.<Object>invokeExact(result); }
protected Object convert_F(float result) throws Throwable { return convert.<Object>invokeExact(result); }
protected Object convert_D(double result) throws Throwable { return convert.<Object>invokeExact(result); }
static private final String CLASS_PREFIX; // "sun.dyn.FromGeneric$"
static {
......@@ -322,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) 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)); }
protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1)); }
protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1)); }
protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1)); }
protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1)); }
protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1)); }
}
// */
......@@ -347,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@) throws Throwable { return convert_@Rc@(invoker.<@R@>invoke(target@av@)); }",
" protected Object invoke_@catN@(@Tvav@) throws Throwable { return convert_@Rc@(invoker.<@R@>invokeExact(target@av@)); }",
" //@end-R@",
" }",
} };
......@@ -503,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() 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)); }
protected Object invoke_L0() throws Throwable { return convert_L(invoker.<Object>invokeExact(target)); }
protected Object invoke_I0() throws Throwable { return convert_I(invoker.<int >invokeExact(target)); }
protected Object invoke_J0() throws Throwable { return convert_J(invoker.<long >invokeExact(target)); }
protected Object invoke_F0() throws Throwable { return convert_F(invoker.<float >invokeExact(target)); }
protected Object invoke_D0() throws Throwable { return convert_D(invoker.<double>invokeExact(target)); }
}
static class A1 extends Adapter {
protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
......@@ -515,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) 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)); }
protected Object invoke_L1(Object a0) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0)); }
protected Object invoke_I1(Object a0) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0)); }
protected Object invoke_J1(Object a0) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0)); }
protected Object invoke_F1(Object a0) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0)); }
protected Object invoke_D1(Object a0) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0)); }
}
static class A2 extends Adapter {
protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
......@@ -527,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) 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)); }
protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1)); }
protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1)); }
protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1)); }
protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1)); }
protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1)); }
}
static class A3 extends Adapter {
protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
......@@ -539,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) 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)); }
protected Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2)); }
protected Object invoke_I3(Object a0, Object a1, Object a2) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2)); }
protected Object invoke_J3(Object a0, Object a1, Object a2) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2)); }
protected Object invoke_F3(Object a0, Object a1, Object a2) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2)); }
protected Object invoke_D3(Object a0, Object a1, Object a2) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2)); }
}
static class A4 extends Adapter {
protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
......@@ -551,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) 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)); }
protected Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2, a3)); }
protected Object invoke_I4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2, a3)); }
protected Object invoke_J4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2, a3)); }
protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2, a3)); }
protected Object invoke_D4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2, a3)); }
}
static class A5 extends Adapter {
protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
......@@ -563,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) 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)); }
protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_L(invoker.<Object>invokeExact(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 >invokeExact(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 >invokeExact(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 >invokeExact(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>invokeExact(target, a0, a1, a2, a3, a4)); }
}
static class A6 extends Adapter {
protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
......@@ -575,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) 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)); }
protected Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_L(invoker.<Object>invokeExact(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 >invokeExact(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 >invokeExact(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 >invokeExact(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>invokeExact(target, a0, a1, a2, a3, a4, a5)); }
}
static class A7 extends Adapter {
protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
......@@ -587,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) 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)); }
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>invokeExact(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 >invokeExact(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 >invokeExact(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 >invokeExact(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>invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
}
static class A8 extends Adapter {
protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
......@@ -599,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) 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)); }
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>invokeExact(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 >invokeExact(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 >invokeExact(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 >invokeExact(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>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
}
static class A9 extends Adapter {
protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
......@@ -611,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) 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)); }
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>invokeExact(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 >invokeExact(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 >invokeExact(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 >invokeExact(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>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
}
static class A10 extends Adapter {
protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
......@@ -623,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) 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)); }
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>invokeExact(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 >invokeExact(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 >invokeExact(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 >invokeExact(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>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
}
}
/*
* Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2008-2010 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
......@@ -40,15 +40,29 @@ import java.util.List;
import static sun.dyn.MethodHandleNatives.Constants.*;
/**
* Compact information which fully characterizes a method or field reference.
* When resolved, it includes a direct pointer to JVM metadata.
* A {@code MemberName} is a compact symbolic datum which fully characterizes
* a method or field reference.
* A member name refers to a field, method, constructor, or member type.
* Every member name has a simple name (a string) and a type (either a Class or MethodType).
* A member name may also have a non-null declaring class, or it may be simply
* a naked name/type pair.
* A member name may also have non-zero modifier flags.
* Finally, a member name may be either resolved or unresolved.
* If it is resolved, the existence of the named
* <p>
* Whether resolved or not, a member name provides no access rights or
* invocation capability to its possessor. It is merely a compact
* representation of all symbolic information necessary to link to
* and properly use the named member.
* <p>
* When resolved, a member name's internal implementation may include references to JVM metadata.
* This representation is stateless and only decriptive.
* It provides no private information and no capability to use the member.
* <p>
* By contrast, a java.lang.reflect.Method contains fuller information
* By contrast, a {@linkplain java.lang.reflect.Method} contains fuller information
* about the internals of a method (except its bytecodes) and also
* allows invocation. A MemberName is much lighter than a reflect.Method,
* since it contains about 7 fields to Method's 16 (plus its sub-arrays),
* allows invocation. A MemberName is much lighter than a Method,
* since it contains about 7 fields to the 16 of Method (plus its sub-arrays),
* and those seven fields omit much of the information in Method.
* @author jrose
*/
......@@ -63,6 +77,9 @@ public final class MemberName implements Member, Cloneable {
{ vmindex = VM_INDEX_UNINITIALIZED; }
/** Return the declaring class of this member.
* In the case of a bare name and type, the declaring class will be null.
*/
public Class<?> getDeclaringClass() {
if (clazz == null && isResolved()) {
expandFromVM();
......@@ -70,10 +87,16 @@ public final class MemberName implements Member, Cloneable {
return clazz;
}
/** Utility method producing the class loader of the declaring class. */
public ClassLoader getClassLoader() {
return clazz.getClassLoader();
}
/** Return the simple name of this member.
* For a type, it is the same as {@link Class#getSimpleName}.
* For a method or field, it is the simple name of the member.
* For a constructor, it is always {@code "&lt;init&gt;"}.
*/
public String getName() {
if (name == null) {
expandFromVM();
......@@ -82,6 +105,9 @@ public final class MemberName implements Member, Cloneable {
return name;
}
/** Return the declared type of this member, which
* must be a method or constructor.
*/
public MethodType getMethodType() {
if (type == null) {
expandFromVM();
......@@ -109,6 +135,10 @@ public final class MemberName implements Member, Cloneable {
throw new InternalError("bad method type "+type);
}
/** Return the actual type under which this method or constructor must be invoked.
* For non-static methods or constructors, this is the type with a leading parameter,
* a reference to declaring class. For static methods, it is the same as the declared type.
*/
public MethodType getInvocationType() {
MethodType itype = getMethodType();
if (!isStatic())
......@@ -116,14 +146,20 @@ public final class MemberName implements Member, Cloneable {
return itype;
}
/** Utility method producing the parameter types of the method type. */
public Class<?>[] getParameterTypes() {
return getMethodType().parameterArray();
}
/** Utility method producing the return type of the method type. */
public Class<?> getReturnType() {
return getMethodType().returnType();
}
/** Return the declared type of this member, which
* must be a field or type.
* If it is a type member, that type itself is returned.
*/
public Class<?> getFieldType() {
if (type == null) {
expandFromVM();
......@@ -144,10 +180,14 @@ public final class MemberName implements Member, Cloneable {
throw new InternalError("bad field type "+type);
}
/** Utility method to produce either the method type or field type of this member. */
public Object getType() {
return (isInvocable() ? getMethodType() : getFieldType());
}
/** Utility method to produce the signature of this member,
* used within the class file format to describe its type.
*/
public String getSignature() {
if (type == null) {
expandFromVM();
......@@ -161,6 +201,9 @@ public final class MemberName implements Member, Cloneable {
return BytecodeDescriptor.unparse(getFieldType());
}
/** Return the modifier flags of this member.
* @see java.lang.reflect.Modifier
*/
public int getModifiers() {
return (flags & RECOGNIZED_MODIFIERS);
}
......@@ -180,21 +223,27 @@ public final class MemberName implements Member, Cloneable {
return !testFlags(mask, 0);
}
/** Utility method to query the modifier flags of this member. */
public boolean isStatic() {
return Modifier.isStatic(flags);
}
/** Utility method to query the modifier flags of this member. */
public boolean isPublic() {
return Modifier.isPublic(flags);
}
/** Utility method to query the modifier flags of this member. */
public boolean isPrivate() {
return Modifier.isPrivate(flags);
}
/** Utility method to query the modifier flags of this member. */
public boolean isProtected() {
return Modifier.isProtected(flags);
}
/** Utility method to query the modifier flags of this member. */
public boolean isFinal() {
return Modifier.isFinal(flags);
}
/** Utility method to query the modifier flags of this member. */
public boolean isAbstract() {
return Modifier.isAbstract(flags);
}
......@@ -206,12 +255,15 @@ public final class MemberName implements Member, Cloneable {
static final int SYNTHETIC = 0x00001000;
static final int ANNOTATION= 0x00002000;
static final int ENUM = 0x00004000;
/** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
public boolean isBridge() {
return testAllFlags(IS_METHOD | BRIDGE);
}
/** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
public boolean isVarargs() {
return testAllFlags(VARARGS) && isInvocable();
}
/** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
public boolean isSynthetic() {
return testAllFlags(SYNTHETIC);
}
......@@ -237,24 +289,31 @@ public final class MemberName implements Member, Cloneable {
static final int IS_FIELD_OR_METHOD = IS_METHOD | IS_FIELD;
static final int SEARCH_ALL_SUPERS = SEARCH_SUPERCLASSES | SEARCH_INTERFACES;
/** Utility method to query whether this member is a method or constructor. */
public boolean isInvocable() {
return testAnyFlags(IS_INVOCABLE);
}
/** Utility method to query whether this member is a method, constructor, or field. */
public boolean isFieldOrMethod() {
return testAnyFlags(IS_FIELD_OR_METHOD);
}
/** Query whether this member is a method. */
public boolean isMethod() {
return testAllFlags(IS_METHOD);
}
/** Query whether this member is a constructor. */
public boolean isConstructor() {
return testAllFlags(IS_CONSTRUCTOR);
}
/** Query whether this member is a field. */
public boolean isField() {
return testAllFlags(IS_FIELD);
}
/** Query whether this member is a type. */
public boolean isType() {
return testAllFlags(IS_TYPE);
}
/** Utility method to query whether this member is neither public, private, nor protected. */
public boolean isPackage() {
return !testAnyFlags(ALL_ACCESS);
}
......@@ -262,8 +321,8 @@ public final class MemberName implements Member, Cloneable {
/** Initialize a query. It is not resolved. */
private void init(Class<?> defClass, String name, Object type, int flags) {
// defining class is allowed to be null (for a naked name/type pair)
name.toString(); // null check
type.equals(type); // null check
//name.toString(); // null check
//type.equals(type); // null check
// fill in fields:
this.clazz = defClass;
this.name = name;
......@@ -285,6 +344,7 @@ public final class MemberName implements Member, Cloneable {
assert((mods & ~RECOGNIZED_MODIFIERS) == 0);
return flags | mods;
}
/** Create a name for the given reflected method. The resulting name will be in a resolved state. */
public MemberName(Method m) {
Object[] typeInfo = { m.getReturnType(), m.getParameterTypes() };
init(m.getDeclaringClass(), m.getName(), typeInfo, flagsMods(IS_METHOD, m.getModifiers()));
......@@ -292,6 +352,7 @@ public final class MemberName implements Member, Cloneable {
MethodHandleNatives.init(this, m);
assert(isResolved());
}
/** Create a name for the given reflected constructor. The resulting name will be in a resolved state. */
public MemberName(Constructor ctor) {
Object[] typeInfo = { void.class, ctor.getParameterTypes() };
init(ctor.getDeclaringClass(), CONSTRUCTOR_NAME, typeInfo, flagsMods(IS_CONSTRUCTOR, ctor.getModifiers()));
......@@ -299,12 +360,14 @@ public final class MemberName implements Member, Cloneable {
MethodHandleNatives.init(this, ctor);
assert(isResolved());
}
/** Create a name for the given reflected field. The resulting name will be in a resolved state. */
public MemberName(Field fld) {
init(fld.getDeclaringClass(), fld.getName(), fld.getType(), flagsMods(IS_FIELD, fld.getModifiers()));
// fill in vmtarget, vmindex while we have fld in hand:
MethodHandleNatives.init(this, fld);
assert(isResolved());
}
/** Create a name for the given class. The resulting name will be in a resolved state. */
public MemberName(Class<?> type) {
init(type.getDeclaringClass(), type.getSimpleName(), type, flagsMods(IS_TYPE, type.getModifiers()));
vmindex = 0; // isResolved
......@@ -326,28 +389,62 @@ public final class MemberName implements Member, Cloneable {
// %%% define equals/hashcode?
// Construction from symbolic parts, for queries:
/** Create a field or type name from the given components: Declaring class, name, type, modifiers.
* The declaring class may be supplied as null if this is to be a bare name and type.
* The resulting name will in an unresolved state.
*/
public MemberName(Class<?> defClass, String name, Class<?> type, int modifiers) {
init(defClass, name, type, IS_FIELD | (modifiers & RECOGNIZED_MODIFIERS));
}
/** Create a field or type name from the given components: Declaring class, name, type.
* The declaring class may be supplied as null if this is to be a bare name and type.
* The modifier flags default to zero.
* The resulting name will in an unresolved state.
*/
public MemberName(Class<?> defClass, String name, Class<?> type) {
this(defClass, name, type, 0);
}
/** Create a method or constructor name from the given components: Declaring class, name, type, modifiers.
* It will be a constructor if and only if the name is {@code "&lt;init&gt;"}.
* The declaring class may be supplied as null if this is to be a bare name and type.
* The resulting name will in an unresolved state.
*/
public MemberName(Class<?> defClass, String name, MethodType type, int modifiers) {
int flagBit = (name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD);
init(defClass, name, type, flagBit | (modifiers & RECOGNIZED_MODIFIERS));
}
/** Create a method or constructor name from the given components: Declaring class, name, type, modifiers.
* It will be a constructor if and only if the name is {@code "&lt;init&gt;"}.
* The declaring class may be supplied as null if this is to be a bare name and type.
* The modifier flags default to zero.
* The resulting name will in an unresolved state.
*/
public MemberName(Class<?> defClass, String name, MethodType type) {
this(defClass, name, type, 0);
}
boolean isResolved() {
/** Query whether this member name is resolved.
* A resolved member name is one for which the JVM has found
* a method, constructor, field, or type binding corresponding exactly to the name.
* (Document?)
*/
public boolean isResolved() {
return (vmindex != VM_INDEX_UNINITIALIZED);
}
/** Query whether this member name is resolved to a non-static, non-final method.
*/
public boolean hasReceiverTypeDispatch() {
return (isMethod() && getVMIndex(Access.TOKEN) >= 0);
}
/** Produce a string form of this member name.
* For types, it is simply the type's own string (as reported by {@code toString}).
* For fields, it is {@code "DeclaringClass.name/type"}.
* For methods and constructors, it is {@code "DeclaringClass.name(ptype...)rtype"}.
* If the declaring class is null, the prefix {@code "DeclaringClass."} is omitted.
* If the member is unresolved, a prefix {@code "*."} is prepended.
*/
@Override
public String toString() {
if (isType())
......@@ -360,9 +457,15 @@ public final class MemberName implements Member, Cloneable {
buf.append(getName(clazz));
buf.append('.');
}
buf.append(getName());
if (!isInvocable()) buf.append('/');
buf.append(getName(getType()));
String name = getName();
buf.append(name == null ? "*" : name);
Object type = getType();
if (!isInvocable()) {
buf.append('/');
buf.append(type == null ? "*" : getName(type));
} else {
buf.append(type == null ? "(*)*" : getName(type));
}
/*
buf.append('/');
// key: Public, private, pRotected, sTatic, Final, sYnchronized,
......@@ -374,7 +477,7 @@ public final class MemberName implements Member, Cloneable {
for (int i = 0; i < modChars.length(); i++) {
if ((flags & (1 << i)) != 0) {
char mc = modChars.charAt(i);
if (mc != '.')
if (mc != '?')
buf.append(mc);
}
}
......@@ -388,6 +491,7 @@ public final class MemberName implements Member, Cloneable {
}
// Queries to the JVM:
/** Document? */
public int getVMIndex(Access token) {
Access.check(token);
if (!isResolved())
......@@ -411,9 +515,6 @@ 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;
......@@ -429,6 +530,9 @@ public final class MemberName implements Member, Cloneable {
public static Factory getFactory() {
return getFactory(Access.getToken());
}
/** A factory type for resolving member names with the help of the VM.
* TBD: Define access-safe public constructors for this factory.
*/
public static class Factory {
private Factory() { } // singleton pattern
static Factory INSTANCE = new Factory();
......@@ -494,6 +598,21 @@ public final class MemberName implements Member, Cloneable {
return result;
}
boolean resolveInPlace(MemberName m, boolean searchSupers, Class<?> lookupClass) {
if (m.name == null || m.type == null) { // find unique non-overloaded name
Class<?> defc = m.getDeclaringClass();
List<MemberName> choices = null;
if (m.isMethod())
choices = getMethods(defc, searchSupers, m.name, (MethodType) m.type, lookupClass);
else if (m.isConstructor())
choices = getConstructors(defc, lookupClass);
else if (m.isField())
choices = getFields(defc, searchSupers, m.name, (Class<?>) m.type, lookupClass);
//System.out.println("resolving "+m+" to "+choices);
if (choices == null || choices.size() != 1)
return false;
if (m.name == null) m.name = choices.get(0).name;
if (m.type == null) m.type = choices.get(0).type;
}
MethodHandleNatives.resolve(m, lookupClass);
if (m.isResolved()) return true;
int matchFlags = m.flags | (searchSupers ? SEARCH_ALL_SUPERS : 0);
......@@ -504,39 +623,82 @@ public final class MemberName implements Member, Cloneable {
if (n != 1) return false;
return m.isResolved();
}
/** Produce a resolved version of the given member.
* Super types are searched (for inherited members) if {@code searchSupers} is true.
* Access checking is performed on behalf of the given {@code lookupClass}.
* If lookup fails or access is not permitted, null is returned.
* Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
*/
public MemberName resolveOrNull(MemberName m, boolean searchSupers, Class<?> lookupClass) {
MemberName result = m.clone();
if (resolveInPlace(result, searchSupers, lookupClass))
return result;
return null;
}
/** Produce a resolved version of the given member.
* Super types are searched (for inherited members) if {@code searchSupers} is true.
* Access checking is performed on behalf of the given {@code lookupClass}.
* If lookup fails or access is not permitted, a {@linkplain NoAccessException} is thrown.
* Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
*/
public MemberName resolveOrFail(MemberName m, boolean searchSupers, Class<?> lookupClass) {
MemberName result = resolveOrNull(m, searchSupers, lookupClass);
if (result != null)
return result;
throw newNoAccessException(m, lookupClass);
}
/** Return a list of all methods defined by the given class.
* Super types are searched (for inherited members) if {@code searchSupers} is true.
* Access checking is performed on behalf of the given {@code lookupClass}.
* Inaccessible members are not added to the last.
*/
public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
Class<?> lookupClass) {
return getMethods(defc, searchSupers, null, null, lookupClass);
}
/** Return a list of matching methods defined by the given class.
* Super types are searched (for inherited members) if {@code searchSupers} is true.
* Returned methods will match the name (if not null) and the type (if not null).
* Access checking is performed on behalf of the given {@code lookupClass}.
* Inaccessible members are not added to the last.
*/
public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
String name, MethodType type, Class<?> lookupClass) {
int matchFlags = IS_METHOD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
return getMembers(defc, name, type, matchFlags, lookupClass);
}
/** Return a list of all constructors defined by the given class.
* Access checking is performed on behalf of the given {@code lookupClass}.
* Inaccessible members are not added to the last.
*/
public List<MemberName> getConstructors(Class<?> defc, Class<?> lookupClass) {
return getMembers(defc, null, null, IS_CONSTRUCTOR, lookupClass);
}
/** Return a list of all fields defined by the given class.
* Super types are searched (for inherited members) if {@code searchSupers} is true.
* Access checking is performed on behalf of the given {@code lookupClass}.
* Inaccessible members are not added to the last.
*/
public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
Class<?> lookupClass) {
return getFields(defc, searchSupers, null, null, lookupClass);
}
/** Return a list of all fields defined by the given class.
* Super types are searched (for inherited members) if {@code searchSupers} is true.
* Returned fields will match the name (if not null) and the type (if not null).
* Access checking is performed on behalf of the given {@code lookupClass}.
* Inaccessible members are not added to the last.
*/
public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
String name, Class<?> type, Class<?> lookupClass) {
int matchFlags = IS_FIELD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
return getMembers(defc, name, type, matchFlags, lookupClass);
}
/** Return a list of all nested types defined by the given class.
* Super types are searched (for inherited members) if {@code searchSupers} is true.
* Access checking is performed on behalf of the given {@code lookupClass}.
* Inaccessible members are not added to the last.
*/
public List<MemberName> getNestedTypes(Class<?> defc, boolean searchSupers,
Class<?> lookupClass) {
int matchFlags = IS_TYPE | (searchSupers ? SEARCH_ALL_SUPERS : 0);
......
/*
* Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2008-2010 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
......@@ -127,7 +127,7 @@ public abstract class MethodHandleImpl {
public static void initLookup(Access token, Lookup lookup) {
Access.check(token);
if (IMPL_LOOKUP_INIT != null || lookup.lookupClass() != null)
if (IMPL_LOOKUP_INIT != null)
throw new InternalError();
IMPL_LOOKUP_INIT = lookup;
}
......@@ -177,28 +177,176 @@ public abstract class MethodHandleImpl {
Access.check(token); // only trusted calls
MethodType mtype = method.getMethodType();
MethodType rtype = mtype;
if (method.isStatic()) {
doDispatch = false;
} else {
if (!method.isStatic()) {
// 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.insertParameterTypes(0, recvType);
if (method.isConstructor())
doDispatch = true;
// FIXME: JVM has trouble building MH.invoke sites for
// classes off the boot class path
rtype = mtype;
if (recvType.getClassLoader() != null)
if (recvType.getClassLoader() != null) {
rtype = rtype.changeParameterType(0, Object.class);
}
}
DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
if (!mh.isValid())
throw newNoAccessException(method, lookupClass);
if (rtype != mtype) {
MethodHandle rmh = AdapterMethodHandle.makePairwiseConvert(token, rtype, mh);
if (rmh == null) throw new InternalError();
return rmh;
}
assert(mh.type() == rtype);
return mh;
}
public static
MethodHandle makeAllocator(Access token, MethodHandle rawConstructor) {
Access.check(token);
MethodType rawConType = rawConstructor.type();
// Wrap the raw (unsafe) constructor with the allocation of a suitable object.
MethodHandle allocator
= AllocateObject.make(token, rawConType.parameterType(0), rawConstructor);
assert(allocator.type()
.equals(rawConType.dropParameterTypes(0, 1).changeReturnType(rawConType.parameterType(0))));
return allocator;
}
static final class AllocateObject<C> extends JavaMethodHandle {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private final Class<C> allocateClass;
private final MethodHandle rawConstructor;
private AllocateObject(MethodHandle invoker,
Class<C> allocateClass, MethodHandle rawConstructor) {
super(invoker);
this.allocateClass = allocateClass;
this.rawConstructor = rawConstructor;
}
static MethodHandle make(Access token,
Class<?> allocateClass, MethodHandle rawConstructor) {
Access.check(token);
MethodType rawConType = rawConstructor.type();
assert(rawConType.parameterType(0) == allocateClass);
MethodType newType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass);
int nargs = rawConType.parameterCount() - 1;
if (nargs < INVOKES.length) {
MethodHandle invoke = INVOKES[nargs];
MethodType conType = CON_TYPES[nargs];
MethodHandle gcon = convertArguments(token, rawConstructor, conType, rawConType, null);
if (gcon == null) return null;
MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
assert(galloc.type() == newType.generic());
return convertArguments(token, galloc, newType, galloc.type(), null);
} else {
MethodHandle invoke = VARARGS_INVOKE;
MethodType conType = CON_TYPES[nargs];
MethodHandle gcon = spreadArguments(token, rawConstructor, conType, 1);
if (gcon == null) return null;
MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
return collectArguments(token, galloc, newType, 1, null);
}
}
@Override
public String toString() {
return allocateClass.getSimpleName();
}
@SuppressWarnings("unchecked")
private C allocate() throws InstantiationException {
return (C) unsafe.allocateInstance(allocateClass);
}
private C invoke_V(Object... av) throws Throwable {
C obj = allocate();
rawConstructor.<void>invokeExact((Object)obj, av);
return obj;
}
private C invoke_L0() throws Throwable {
C obj = allocate();
rawConstructor.<void>invokeExact((Object)obj);
return obj;
}
private C invoke_L1(Object a0) throws Throwable {
C obj = allocate();
rawConstructor.<void>invokeExact((Object)obj, a0);
return obj;
}
private C invoke_L2(Object a0, Object a1) throws Throwable {
C obj = allocate();
rawConstructor.<void>invokeExact((Object)obj, a0, a1);
return obj;
}
private C invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
C obj = allocate();
rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2);
return obj;
}
private C invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
C obj = allocate();
rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2, a3);
return obj;
}
private C invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
C obj = allocate();
rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2, a3, a4);
return obj;
}
private C invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
C obj = allocate();
rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2, a3, a4, a5);
return obj;
}
private C invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
C obj = allocate();
rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2, a3, a4, a5, a6);
return obj;
}
private C invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
C obj = allocate();
rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2, a3, a4, a5, a6, a7);
return obj;
}
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(AllocateObject.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(AllocateObject.class, "invoke_V", MethodType.genericMethodType(0, true));
} catch (NoAccessException ex) {
throw new InternalError("");
}
}
// Corresponding generic constructor types:
static final MethodType[] CON_TYPES = new MethodType[INVOKES.length];
static {
for (int i = 0; i < INVOKES.length; i++)
CON_TYPES[i] = makeConType(INVOKES[i]);
}
static final MethodType VARARGS_CON_TYPE = makeConType(VARARGS_INVOKE);
static MethodType makeConType(MethodHandle invoke) {
MethodType invType = invoke.type();
return invType.changeParameterType(0, Object.class).changeReturnType(void.class);
}
}
public static
MethodHandle accessField(Access token,
......@@ -469,6 +617,7 @@ public abstract class MethodHandleImpl {
MethodType oldType,
int[] permutationOrNull) {
Access.check(token);
assert(oldType.parameterCount() == target.type().parameterCount());
if (permutationOrNull != null) {
int outargs = oldType.parameterCount(), inargs = newType.parameterCount();
if (permutationOrNull.length != outargs)
......@@ -781,69 +930,93 @@ public abstract class MethodHandleImpl {
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,
private GuardWithTest(MethodHandle invoker,
MethodHandle test, MethodHandle target, MethodHandle fallback) {
super(invoker);
this.test = test;
this.target = target;
this.fallback = fallback;
}
static MethodHandle make(Access token,
MethodHandle test, MethodHandle target, MethodHandle fallback) {
Access.check(token);
MethodType type = target.type();
int nargs = type.parameterCount();
if (nargs < INVOKES.length) {
MethodHandle invoke = INVOKES[nargs];
MethodType gtype = type.generic();
assert(invoke.type().dropParameterTypes(0,1) == gtype);
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(invoke, gtest, gtarget, gfallback);
return convertArguments(token, gguard, type, gtype, null);
} else {
MethodHandle invoke = VARARGS_INVOKE;
MethodType gtype = MethodType.genericMethodType(1);
assert(invoke.type().dropParameterTypes(0,1) == gtype);
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(invoke, gtest, gtarget, gfallback);
if (gtest == null || gtarget == null || gfallback == null) return null;
return collectArguments(token, gguard, type, 0, null);
}
}
@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);
if (test.<boolean>invokeExact(av))
return target.<Object>invokeExact(av);
return fallback.<Object>invokeExact(av);
}
private Object invoke_L0() throws Throwable {
if (test.<boolean>invoke())
return target.<Object>invoke();
return fallback.<Object>invoke();
if (test.<boolean>invokeExact())
return target.<Object>invokeExact();
return fallback.<Object>invokeExact();
}
private Object invoke_L1(Object a0) throws Throwable {
if (test.<boolean>invoke(a0))
return target.<Object>invoke(a0);
return fallback.<Object>invoke(a0);
if (test.<boolean>invokeExact(a0))
return target.<Object>invokeExact(a0);
return fallback.<Object>invokeExact(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);
if (test.<boolean>invokeExact(a0, a1))
return target.<Object>invokeExact(a0, a1);
return fallback.<Object>invokeExact(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);
if (test.<boolean>invokeExact(a0, a1, a2))
return target.<Object>invokeExact(a0, a1, a2);
return fallback.<Object>invokeExact(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);
if (test.<boolean>invokeExact(a0, a1, a2, a3))
return target.<Object>invokeExact(a0, a1, a2, a3);
return fallback.<Object>invokeExact(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);
if (test.<boolean>invokeExact(a0, a1, a2, a3, a4))
return target.<Object>invokeExact(a0, a1, a2, a3, a4);
return fallback.<Object>invokeExact(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);
if (test.<boolean>invokeExact(a0, a1, a2, a3, a4, a5))
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5);
return fallback.<Object>invokeExact(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);
if (test.<boolean>invokeExact(a0, a1, a2, a3, a4, a5, a6))
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6);
return fallback.<Object>invokeExact(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);
if (test.<boolean>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7))
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
return fallback.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
}
static MethodHandle[] makeInvokes() {
ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
......@@ -880,26 +1053,7 @@ public abstract class MethodHandleImpl {
MethodHandle test,
MethodHandle target,
MethodHandle fallback) {
Access.check(token);
MethodType type = target.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);
}
return GuardWithTest.make(token, test, target, fallback);
}
private static class GuardWithCatch extends JavaMethodHandle {
......@@ -922,82 +1076,82 @@ public abstract class MethodHandleImpl {
}
private Object invoke_V(Object... av) throws Throwable {
try {
return target.<Object>invoke(av);
return target.<Object>invokeExact(av);
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invoke(t, av);
return catcher.<Object>invokeExact(t, av);
}
}
private Object invoke_L0() throws Throwable {
try {
return target.<Object>invoke();
return target.<Object>invokeExact();
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invoke(t);
return catcher.<Object>invokeExact(t);
}
}
private Object invoke_L1(Object a0) throws Throwable {
try {
return target.<Object>invoke(a0);
return target.<Object>invokeExact(a0);
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invoke(t, a0);
return catcher.<Object>invokeExact(t, a0);
}
}
private Object invoke_L2(Object a0, Object a1) throws Throwable {
try {
return target.<Object>invoke(a0, a1);
return target.<Object>invokeExact(a0, a1);
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invoke(t, a0, a1);
return catcher.<Object>invokeExact(t, a0, a1);
}
}
private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
try {
return target.<Object>invoke(a0, a1, a2);
return target.<Object>invokeExact(a0, a1, a2);
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invoke(t, a0, a1, a2);
return catcher.<Object>invokeExact(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);
return target.<Object>invokeExact(a0, a1, a2, a3);
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invoke(t, a0, a1, a2, a3);
return catcher.<Object>invokeExact(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);
return target.<Object>invokeExact(a0, a1, a2, a3, a4);
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invoke(t, a0, a1, a2, a3, a4);
return catcher.<Object>invokeExact(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);
return target.<Object>invokeExact(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);
return catcher.<Object>invokeExact(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);
return target.<Object>invokeExact(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);
return catcher.<Object>invokeExact(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);
return target.<Object>invokeExact(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);
return catcher.<Object>invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
}
}
static MethodHandle[] makeInvokes() {
......@@ -1106,4 +1260,14 @@ public abstract class MethodHandleImpl {
throw new InternalError("unexpected code "+code+": "+message);
}
}
// Linkage support:
public static void registerBootstrap(Access token, Class<?> callerClass, MethodHandle bootstrapMethod) {
Access.check(token);
MethodHandleNatives.registerBootstrap(callerClass, bootstrapMethod);
}
public static MethodHandle getBootstrap(Access token, Class<?> callerClass) {
Access.check(token);
return MethodHandleNatives.getBootstrap(callerClass);
}
}
/*
* Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2008-2010 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
......@@ -28,12 +28,16 @@ package sun.dyn;
import java.dyn.CallSite;
import java.dyn.MethodHandle;
import java.dyn.MethodType;
import java.dyn.MethodHandles.Lookup;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import static sun.dyn.MethodHandleNatives.Constants.*;
import static sun.dyn.MethodHandleImpl.IMPL_LOOKUP;
/**
* The JVM interface for the method handles package is all here.
* This is an interface internal and private to an implemetantion of JSR 292.
* <em>This class is not part of the JSR 292 standard.</em>
* @author jrose
*/
class MethodHandleNatives {
......@@ -60,8 +64,14 @@ class MethodHandleNatives {
/** Initialize a method type, once per form. */
static native void init(MethodType self);
/** Tell the JVM about a class's bootstrap method. */
static native void registerBootstrap(Class<?> caller, MethodHandle bootstrapMethod);
/** Ask the JVM about a class's bootstrap method. */
static native MethodHandle getBootstrap(Class<?> caller);
/** Tell the JVM that we need to change the target of an invokedynamic. */
static native void linkCallSite(CallSite site, MethodHandle target);
static native void setCallSiteTarget(CallSite site, MethodHandle target);
/** Fetch the vmtarget field.
* It will be sanitized as necessary to avoid exposing non-Java references.
......@@ -114,22 +124,28 @@ class MethodHandleNatives {
*/
static final int JVM_STACK_MOVE_UNIT;
/** Which conv-ops are implemented by the JVM? */
static final int CONV_OP_IMPLEMENTED_MASK;
private static native void registerNatives();
static {
boolean JVM_SUPPORT_;
int JVM_PUSH_LIMIT_;
int JVM_STACK_MOVE_UNIT_;
int CONV_OP_IMPLEMENTED_MASK_;
try {
registerNatives();
JVM_SUPPORT_ = true;
JVM_PUSH_LIMIT_ = getConstant(Constants.GC_JVM_PUSH_LIMIT);
JVM_STACK_MOVE_UNIT_ = getConstant(Constants.GC_JVM_STACK_MOVE_UNIT);
CONV_OP_IMPLEMENTED_MASK_ = getConstant(Constants.GC_CONV_OP_IMPLEMENTED_MASK);
//sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init");
} catch (UnsatisfiedLinkError ee) {
// ignore; if we use init() methods later we'll see linkage errors
JVM_SUPPORT_ = false;
JVM_PUSH_LIMIT_ = 3; // arbitrary
JVM_STACK_MOVE_UNIT_ = -1; // arbitrary
CONV_OP_IMPLEMENTED_MASK_ = 0;
//System.out.println("Warning: Running with JVM_SUPPORT=false");
//System.out.println(ee);
JVM_SUPPORT = JVM_SUPPORT_;
......@@ -140,6 +156,9 @@ class MethodHandleNatives {
JVM_SUPPORT = JVM_SUPPORT_;
JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_;
JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_;
if (CONV_OP_IMPLEMENTED_MASK_ == 0)
CONV_OP_IMPLEMENTED_MASK_ = DEFAULT_CONV_OP_IMPLEMENTED_MASK;
CONV_OP_IMPLEMENTED_MASK = CONV_OP_IMPLEMENTED_MASK_;
}
// All compile-time constants go here.
......@@ -149,7 +168,8 @@ class MethodHandleNatives {
// MethodHandleImpl
static final int // for getConstant
GC_JVM_PUSH_LIMIT = 0,
GC_JVM_STACK_MOVE_UNIT = 1;
GC_JVM_STACK_MOVE_UNIT = 1,
GC_CONV_OP_IMPLEMENTED_MASK = 2;
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)
......@@ -206,9 +226,8 @@ class MethodHandleNatives {
CONV_STACK_MOVE_MASK = (1 << (32 - CONV_STACK_MOVE_SHIFT)) - 1;
/** Which conv-ops are implemented by the JVM? */
static final int CONV_OP_IMPLEMENTED_MASK =
// TODO: The following expression should be replaced by
// a JVM query.
static final int DEFAULT_CONV_OP_IMPLEMENTED_MASK =
// Value to use if the corresponding JVM query fails.
((1<<OP_RETYPE_ONLY)
|(1<<OP_RETYPE_RAW)
|(1<<OP_CHECK_CAST)
......@@ -218,7 +237,7 @@ class MethodHandleNatives {
|(1<<OP_ROT_ARGS)
|(1<<OP_DUP_ARGS)
|(1<<OP_DROP_ARGS)
//|(1<<OP_SPREAD_ARGS) // FIXME: Check JVM assembly code.
//|(1<<OP_SPREAD_ARGS)
);
/**
......@@ -263,4 +282,26 @@ class MethodHandleNatives {
static {
if (JVM_SUPPORT) verifyConstants();
}
// Up-calls from the JVM.
// These must NOT be public.
/**
* The JVM is linking an invokedynamic instruction. Create a reified call site for it.
*/
static CallSite makeDynamicCallSite(MethodHandle bootstrapMethod,
String name, MethodType type,
Object info,
MemberName callerMethod, int callerBCI) {
return CallSiteImpl.makeSite(bootstrapMethod, name, type, info, callerMethod, callerBCI);
}
/**
* The JVM wants a pointer to a MethodType. Oblige it by finding or creating one.
*/
static MethodType findMethodHandleType(Class<?> rtype, Class<?>[] ptypes) {
MethodType.genericMethodType(0); // trigger initialization
return MethodTypeImpl.makeImpl(Access.TOKEN, rtype, ptypes, true);
}
}
......@@ -88,6 +88,11 @@ public class MethodTypeImpl {
}
static private MethodTypeFriend METHOD_TYPE_FRIEND;
static MethodType makeImpl(Access token, Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
Access.check(token);
return METHOD_TYPE_FRIEND.makeImpl(rtype, ptypes, trusted);
}
protected MethodTypeImpl(MethodType erasedType) {
this.erasedType = erasedType;
......@@ -233,8 +238,10 @@ public class MethodTypeImpl {
return primsAtEnd = t;
// known to have a mix of 2 or 3 of ref, int, long
return primsAtEnd = reorderParameters(t, primsAtEndOrder(t), null);
int[] reorder = primsAtEndOrder(t);
ct = reorderParameters(t, reorder, null);
//System.out.println("t="+t+" / reorder="+java.util.Arrays.toString(reorder)+" => "+ct);
return primsAtEnd = ct;
}
/** Compute a new ordering of parameters so that all references
......@@ -273,7 +280,8 @@ public class MethodTypeImpl {
else if (!hasTwoArgSlots(pt)) ord = ifill++;
else ord = lfill++;
if (ord != i) changed = true;
paramOrder[i] = ord;
assert(paramOrder[ord] == 0);
paramOrder[ord] = i;
}
assert(rfill == argc - pac && ifill == argc - lac && lfill == argc);
if (!changed) {
......@@ -292,15 +300,15 @@ public class MethodTypeImpl {
if (newParamOrder == null) return mt; // no-op reordering
Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
Class<?>[] ntypes = new Class<?>[newParamOrder.length];
int ordMax = ptypes.length + (moreParams == null ? 0 : moreParams.length);
int maxParam = ptypes.length + (moreParams == null ? 0 : moreParams.length);
boolean changed = (ntypes.length != ptypes.length);
for (int i = 0; i < newParamOrder.length; i++) {
int ord = newParamOrder[i];
if (ord != i) changed = true;
int param = newParamOrder[i];
if (param != i) changed = true;
Class<?> nt;
if (ord < ptypes.length) nt = ptypes[ord];
else if (ord == ordMax) nt = mt.returnType();
else nt = moreParams[ord - ptypes.length];
if (param < ptypes.length) nt = ptypes[param];
else if (param == maxParam) nt = mt.returnType();
else nt = moreParams[param - ptypes.length];
ntypes[i] = nt;
}
if (!changed) return mt;
......
......@@ -281,12 +281,12 @@ class SpreadGeneric {
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)); }
return target.<Object>invokeExact(a0, a1)); }
protected Object invoke_S1(Object a0, Object av) throws Throwable { av = super.check(av,1);
return target.<Object>invoke(a0,
return target.<Object>invokeExact(a0,
super.select(av,0)); }
protected Object invoke_S2(Object a0, Object av) throws Throwable { av = super.check(av,1);
return target.<Object>invoke(
return target.<Object>invokeExact(
super.select(av,0), super.select(av,1)); }
}
// */
......@@ -304,10 +304,10 @@ class genclasses {
" 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@); }",
" return target.<Object>invokeExact(@av@); }",
" //@each-S@",
" protected Object invoke_S@S@(@Tvav,@Object av) throws Throwable { av = super.check(av, @S@);",
" return target.<Object>invoke(@av,@@sv@); }",
" return target.<Object>invokeExact(@av,@@sv@); }",
" //@end-S@",
" }",
} };
......@@ -418,16 +418,16 @@ class genclasses {
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(); }
return target.<Object>invokeExact(); }
}
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); }
return target.<Object>invokeExact(a0); }
protected Object invoke_S1(Object av) throws Throwable { av = super.check(av, 1);
return target.<Object>invoke(
return target.<Object>invokeExact(
super.select(av,0)); }
}
static class S2 extends Adapter {
......@@ -435,12 +435,12 @@ class genclasses {
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); }
return target.<Object>invokeExact(a0, a1); }
protected Object invoke_S1(Object a0, Object av) throws Throwable { av = super.check(av, 1);
return target.<Object>invoke(a0,
return target.<Object>invokeExact(a0,
super.select(av,0)); }
protected Object invoke_S2(Object av) throws Throwable { av = super.check(av, 2);
return target.<Object>invoke(
return target.<Object>invokeExact(
super.select(av,0), super.select(av,1)); }
}
static class S3 extends Adapter {
......@@ -448,15 +448,15 @@ class genclasses {
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); }
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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(
return target.<Object>invokeExact(
super.select(av,0), super.select(av,1), super.select(av,2)); }
}
static class S4 extends Adapter {
......@@ -464,18 +464,18 @@ class genclasses {
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); }
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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(
return target.<Object>invokeExact(
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
}
static class S5 extends Adapter {
......@@ -483,21 +483,21 @@ class genclasses {
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); }
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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(
return target.<Object>invokeExact(
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4)); }
}
......@@ -506,25 +506,25 @@ class genclasses {
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); }
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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(
return target.<Object>invokeExact(
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5)); }
}
......@@ -533,29 +533,29 @@ class genclasses {
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); }
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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(
return target.<Object>invokeExact(
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)); }
}
......@@ -564,33 +564,33 @@ class genclasses {
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); }
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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(
return target.<Object>invokeExact(
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)); }
}
......@@ -599,37 +599,37 @@ class genclasses {
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); }
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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(
return target.<Object>invokeExact(
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)); }
......@@ -639,42 +639,42 @@ class genclasses {
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); }
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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,
return target.<Object>invokeExact(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(
return target.<Object>invokeExact(
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)); }
......
......@@ -99,12 +99,12 @@ class ToGeneric {
// reordering is required; build on top of a simpler ToGeneric
ToGeneric va2 = ToGeneric.of(primsAtEnd);
this.adapter = va2.adapter;
if (true) throw new UnsupportedOperationException("NYI: primitive parameters must follow references; entryType = "+entryType);
this.entryPoint = MethodHandleImpl.convertArguments(Access.TOKEN,
va2.entryPoint, primsAtEnd, entryType, primsAtEndOrder);
// example: for entryType of (int,Object,Object), the reordered
// type is (Object,Object,int) and the order is {1,2,0},
// and putPAE is (mh,int0,obj1,obj2) => mh.invoke(obj1,obj2,int0)
if (true) throw new UnsupportedOperationException("NYI");
// and putPAE is (mh,int0,obj1,obj2) => mh.invokeExact(obj1,obj2,int0)
return;
}
......@@ -341,7 +341,7 @@ class ToGeneric {
@Override
public String toString() {
return target.toString();
return target == null ? "prototype:"+convert : target.toString();
}
protected boolean isPrototype() { return target == null; }
......@@ -371,33 +371,33 @@ class ToGeneric {
// { return new ThisType(entryPoint, convert, target); }
// Code to run when the arguments (<= 4) have all been boxed.
protected Object target() throws Throwable { return invoker.<Object>invoke(target); }
protected Object target(Object a0) throws Throwable { return invoker.<Object>invoke(target, a0); }
protected Object target() throws Throwable { return invoker.<Object>invokeExact(target); }
protected Object target(Object a0) throws Throwable { return invoker.<Object>invokeExact(target, a0); }
protected Object target(Object a0, Object a1)
throws Throwable { return invoker.<Object>invoke(target, a0, a1); }
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1); }
protected Object target(Object a0, Object a1, Object a2)
throws Throwable { return invoker.<Object>invoke(target, a0, a1, a2); }
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2); }
protected Object target(Object a0, Object a1, Object a2, Object a3)
throws Throwable { return invoker.<Object>invoke(target, a0, a1, a2, a3); }
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3); }
/*
protected Object target_0(Object... av) throws Throwable { return invoker.<Object>invoke(target, av); }
protected Object target_0(Object... av) throws Throwable { return invoker.<Object>invokeExact(target, av); }
protected Object target_1(Object a0, Object... av)
throws Throwable { return invoker.<Object>invoke(target, a0, (Object)av); }
throws Throwable { return invoker.<Object>invokeExact(target, a0, (Object)av); }
protected Object target_2(Object a0, Object a1, Object... av)
throws Throwable { return invoker.<Object>invoke(target, a0, a1, (Object)av); }
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, (Object)av); }
protected Object target_3(Object a0, Object a1, Object a2, Object... av)
throws Throwable { return invoker.<Object>invoke(target, a0, a1, a2, (Object)av); }
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, (Object)av); }
protected Object target_4(Object a0, Object a1, Object a2, Object a3, Object... av)
throws Throwable { return invoker.<Object>invoke(target, a0, a1, a2, a3, (Object)av); }
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, (Object)av); }
// */
// (For more than 4 arguments, generate the code in the adapter itself.)
// Code to run when the generic target has finished and produced a value.
protected Object return_L(Object res) throws Throwable { return convert.<Object>invoke(res); }
protected int return_I(Object res) throws Throwable { return convert.<int >invoke(res); }
protected long return_J(Object res) throws Throwable { return convert.<long >invoke(res); }
protected float return_F(Object res) throws Throwable { return convert.<float >invoke(res); }
protected double return_D(Object res) throws Throwable { return convert.<double>invoke(res); }
protected Object return_L(Object res) throws Throwable { return convert.<Object>invokeExact(res); }
protected int return_I(Object res) throws Throwable { return convert.<int >invokeExact(res); }
protected long return_J(Object res) throws Throwable { return convert.<long >invokeExact(res); }
protected float return_F(Object res) throws Throwable { return convert.<float >invokeExact(res); }
protected double return_D(Object res) throws Throwable { return convert.<double>invokeExact(res); }
static private final String CLASS_PREFIX; // "sun.dyn.ToGeneric$"
static {
......@@ -424,7 +424,7 @@ class ToGeneric {
protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { 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 target(Object a0) throws Throwable { return invoker.<Object>invoke(target, a0); }
protected Object target(Object a0) throws Throwable { return invoker.<Object>invokeExact(target, a0); }
protected Object targetA1(Object a0) throws Throwable { return target(a0); }
protected Object targetA1(int a0) throws Throwable { return target(a0); }
protected Object targetA1(long a0) throws Throwable { return target(a0); }
......@@ -462,7 +462,7 @@ class genclasses {
" protected @cat@(MethodHandle entryPoint) { super(entryPoint); } // to build prototype",
" protected @cat@(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }",
" protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new @cat@(e, i, c, t); }",
" protected Object target(@Ovav@) throws Throwable { return invoker.<Object>invoke(target, @av@); }",
" protected Object target(@Ovav@) throws Throwable { return invoker.<Object>invokeExact(target, @av@); }",
" //@each-Tv@",
" protected Object target@cat@(@Tvav@) throws Throwable { return target(@av@); }",
" //@end-Tv@",
......@@ -622,7 +622,7 @@ class genclasses {
protected A0(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A0(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { 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 target() throws Throwable { return invoker.<Object>invoke(target); }
protected Object target() throws Throwable { return invoker.<Object>invokeExact(target); }
protected Object targetA0() throws Throwable { return target(); }
protected Object invoke_L() throws Throwable { return return_L(targetA0()); }
protected int invoke_I() throws Throwable { return return_I(targetA0()); }
......@@ -634,7 +634,7 @@ class genclasses {
protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { 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 target(Object a0) throws Throwable { return invoker.<Object>invoke(target, a0); }
protected Object target(Object a0) throws Throwable { return invoker.<Object>invokeExact(target, a0); }
protected Object targetA1(Object a0) throws Throwable { return target(a0); }
protected Object targetA1(int a0) throws Throwable { return target(a0); }
protected Object targetA1(long a0) throws Throwable { return target(a0); }
......@@ -658,7 +658,7 @@ class genclasses {
protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { 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 target(Object a0, Object a1) throws Throwable { return invoker.<Object>invoke(target, a0, a1); }
protected Object target(Object a0, Object a1) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1); }
protected Object targetA2(Object a0, Object a1) throws Throwable { return target(a0, a1); }
protected Object targetA2(Object a0, int a1) throws Throwable { return target(a0, a1); }
protected Object targetA2(int a0, int a1) throws Throwable { return target(a0, a1); }
......@@ -694,7 +694,7 @@ class genclasses {
protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A3(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { 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 target(Object a0, Object a1, Object a2) throws Throwable { return invoker.<Object>invoke(target, a0, a1, a2); }
protected Object target(Object a0, Object a1, Object a2) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2); }
protected Object targetA3(Object a0, Object a1, Object a2) throws Throwable { return target(a0, a1, a2); }
protected Object targetA3(Object a0, Object a1, int a2) throws Throwable { return target(a0, a1, a2); }
protected Object targetA3(Object a0, int a1, int a2) throws Throwable { return target(a0, a1, a2); }
......@@ -743,7 +743,7 @@ class genclasses {
protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A4(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { 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 target(Object a0, Object a1, Object a2, Object a3) throws Throwable { return invoker.<Object>invoke(target, a0, a1, a2, a3); }
protected Object target(Object a0, Object a1, Object a2, Object a3) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3); }
protected Object targetA4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return target(a0, a1, a2, a3); }
protected Object targetA4(Object a0, Object a1, Object a2, int a3) throws Throwable { return target(a0, a1, a2, a3); }
protected Object targetA4(Object a0, Object a1, int a2, int a3) throws Throwable { return target(a0, a1, a2, a3); }
......@@ -785,7 +785,7 @@ class genclasses {
protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A5(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { 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 target(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4); }
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4); }
protected Object targetA5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return target(a0, a1, a2, a3, a4); }
protected Object targetA5(Object a0, Object a1, Object a2, Object a3, int a4) throws Throwable { return target(a0, a1, a2, a3, a4); }
protected Object targetA5(Object a0, Object a1, Object a2, int a3, int a4) throws Throwable { return target(a0, a1, a2, a3, a4); }
......@@ -836,7 +836,7 @@ class genclasses {
protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A6(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { 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 target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5); }
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5); }
protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); }
protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); }
protected Object targetA6(Object a0, Object a1, Object a2, Object a3, long a4, long a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); }
......@@ -870,7 +870,7 @@ class genclasses {
protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A7(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { 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 target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6); }
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6); }
protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); }
protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); }
protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); }
......@@ -908,7 +908,7 @@ class genclasses {
protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A8(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { 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 target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7); }
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7); }
protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
......@@ -950,7 +950,7 @@ class genclasses {
protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A9(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { 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 target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8); }
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8); }
protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
......@@ -996,7 +996,7 @@ class genclasses {
protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A10(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { 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 target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return invoker.<Object>invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
......
......@@ -25,10 +25,6 @@
/**
* Implementation details for JSR 292 RI, package java.dyn.
* This particular version is specific to Hotspot.
* There is also a backport version of this sub-package which uses reflection,
* and can therefore run (slowly) on older versions of Java.
* Other JVM vendors may create their own versions of this sub-package.
* @author jrose
*/
......
......@@ -655,7 +655,7 @@ public class ValueConversions {
if (nargs < ARRAYS.length)
return ARRAYS[nargs];
// else need to spin bytecode or do something else fancy
throw new UnsupportedOperationException("NYI");
throw new UnsupportedOperationException("NYI: cannot form a varargs array of length "+nargs);
}
private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
......
......@@ -26,12 +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.MemberName;
import sun.dyn.MethodHandleImpl;
import sun.dyn.empty.Empty;
import static java.lang.reflect.Modifier.*;
/**
* This class centralizes information about the JVM's linkage access control.
......@@ -41,49 +41,105 @@ public class VerifyAccess {
private VerifyAccess() { } // cannot instantiate
private static final int PACKAGE_ONLY = 0;
private static final int ALL_ACCESS_MODES = (PUBLIC|PRIVATE|PROTECTED|PACKAGE_ONLY);
/**
* Evaluate the JVM linkage rules for access to the given method on behalf of caller.
* Return non-null if and only if the given accessing class has at least partial
* privileges to invoke the given method. The return value {@code Object.class}
* denotes unlimited privileges.
* Evaluate the JVM linkage rules for access to the given method
* on behalf of a caller class which proposes to perform the access.
* Return true if the caller class has privileges to invoke a method
* or access a field with the given properties.
* This requires an accessibility check of the referencing class,
* plus an accessibility check of the member within the class,
* which depends on the member's modifier flags.
* <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 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 isSpecialInvoke if true, a non-static method m is checked as if for {@code invokespecial}
* The relevant properties include the defining class ({@code defc})
* of the member, and its modifier flags ({@code mods}).
* Also relevant is the class used to make the initial symbolic reference
* to the member ({@code refc}). If this latter class is not distinguished,
* the defining class should be passed for both arguments ({@code defc == refc}).
* <h3>JVM Specification, 5.4.4 "Access Control"</h3>
* A field or method R is accessible to a class or interface D if
* and only if any of the following conditions is true:<ul>
* <li>R is public.
* <li>R is protected and is declared in a class C, and D is either
* a subclass of C or C itself. Furthermore, if R is not
* static, then the symbolic reference to R must contain a
* symbolic reference to a class T, such that T is either a
* subclass of D, a superclass of D or D itself.
* <li>R is either protected or has default access (that is,
* neither public nor protected nor private), and is declared
* by a class in the same runtime package as D.
* <li>R is private and is declared in D.
* </ul>
* This discussion of access control omits a related restriction
* on the target of a protected field access or method invocation
* (the target must be of class D or a subtype of D). That
* requirement is checked as part of the verification process
* (5.4.1); it is not part of link-time access control.
* @param refc the class used in the symbolic reference to the proposed member
* @param defc the class in which the proposed member is actually defined
* @param mods modifier flags for the proposed member
* @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}
* @return true iff the the accessing class can access such a member
*/
public static Class<?> isAccessible(Class<?> defc, int mods,
Class<?> lookupClass, boolean isSpecialInvoke) {
if (!isAccessible(defc, lookupClass))
return null;
Class<?> constraint = Object.class;
if (isSpecialInvoke && !Modifier.isStatic(mods)) {
constraint = lookupClass;
}
if (Modifier.isPublic(mods))
return constraint;
if (Modifier.isPrivate(mods))
return isSamePackageMember(defc, lookupClass) ? constraint : null;
if (isSamePackage(defc, lookupClass))
return constraint;
if (Modifier.isProtected(mods) && defc.isAssignableFrom(lookupClass))
return constraint;
// else it is private or package scoped, and not close enough
return null;
public static boolean isMemberAccessible(Class<?> refc, // symbolic ref class
Class<?> defc, // actual def class
int mods, // actual member mods
Class<?> lookupClass) {
// Usually refc and defc are the same, but if they differ, verify them both.
if (refc != defc) {
if (!isClassAccessible(refc, lookupClass)) {
// Note that defc is verified in the switch below.
return false;
}
if ((mods & (ALL_ACCESS_MODES|STATIC)) == (PROTECTED|STATIC)) {
// Apply the special rules for refc here.
if (!isRelatedClass(refc, lookupClass))
return isSamePackage(defc, lookupClass);
// If refc == defc, the call to isPublicSuperClass will do
// the whole job, since in that case refc (as defc) will be
// a superclass of the lookup class.
}
}
switch (mods & ALL_ACCESS_MODES) {
case PUBLIC:
if (refc != defc) return true; // already checked above
return isClassAccessible(refc, lookupClass);
case PROTECTED:
return isSamePackage(defc, lookupClass) || isPublicSuperClass(defc, lookupClass);
case PACKAGE_ONLY:
return isSamePackage(defc, lookupClass);
case PRIVATE:
// Loosened rules for privates follows access rules for inner classes.
return isSamePackageMember(defc, lookupClass);
default:
throw new IllegalArgumentException("bad modifiers: "+Modifier.toString(mods));
}
}
static boolean isRelatedClass(Class<?> refc, Class<?> lookupClass) {
return (refc == lookupClass ||
refc.isAssignableFrom(lookupClass) ||
lookupClass.isAssignableFrom(refc));
}
static boolean isPublicSuperClass(Class<?> defc, Class<?> lookupClass) {
return isPublic(defc.getModifiers()) && defc.isAssignableFrom(lookupClass);
}
/**
* Evaluate the JVM linkage rules for access to the given class on behalf of caller.
* <h3>JVM Specification, 5.4.4 "Access Control"</h3>
* A class or interface C is accessible to a class or interface D
* if and only if either of the following conditions are true:<ul>
* <li>C is public.
* <li>C and D are members of the same runtime package.
* </ul>
*/
public static boolean isAccessible(Class<?> refc, Class<?> lookupClass) {
public static boolean isClassAccessible(Class<?> refc, Class<?> lookupClass) {
int mods = refc.getModifiers();
if (Modifier.isPublic(mods))
if (isPublic(mods))
return true;
if (isSamePackage(lookupClass, refc))
return true;
......@@ -170,38 +226,4 @@ 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");
}
}
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2009-2010 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
......@@ -26,19 +26,18 @@
/* @test
* @summary unit tests for java.dyn.MethodHandles
* @compile -XDinvokedynamic MethodHandlesTest.java
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic jdk.java.dyn.MethodHandlesTest
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic test.java.dyn.MethodHandlesTest
*/
package jdk.java.dyn;
package test.java.dyn;
import java.dyn.*;
import java.dyn.MethodHandles.Lookup;
import java.lang.reflect.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.*;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
/**
......@@ -47,7 +46,7 @@ import static org.junit.Assert.*;
*/
public class MethodHandlesTest {
// How much output?
static int verbosity = 1;
static int verbosity = 0;
// Set this true during development if you want to fast-forward to
// a particular new, non-working test. Tests which are known to
......@@ -57,55 +56,79 @@ public class MethodHandlesTest {
// Set true to test more calls. If false, some tests are just
// lookups, without exercising the actual method handle.
static boolean DO_MORE_CALLS = false;
static boolean DO_MORE_CALLS = true;
@Test
public void testFirst() throws Throwable {
verbosity += 9; try {
// left blank for debugging
} finally { verbosity -= 9; }
} finally { printCounts(); verbosity -= 9; }
}
// current failures
@Test @Ignore("failure in call to makeRawRetypeOnly in ToGeneric")
public void testFail_1() throws Throwable {
// AMH.<init>: IllegalArgumentException: bad adapter (conversion=0xfffab300): adapter pushes too many parameters
testSpreadArguments(int.class, 0, 6);
}
@Test @Ignore("failure in JVM when expanding the stack")
@Test @Ignore("failure in JVM when expanding the stack using asm stub for _adapter_spread_args")
public void testFail_2() throws Throwable {
// if CONV_OP_IMPLEMENTED_MASK includes OP_SPREAD_ARGS, this crashes:
testSpreadArguments(Object.class, 0, 2);
}
@Test @Ignore("IllArgEx failure in call to ToGeneric.make")
public void testFail_3() throws Throwable {
// ToGeneric.<init>: UnsupportedOperationException: NYI: primitive parameters must follow references; entryType = (int,java.lang.Object)java.lang.Object
testSpreadArguments(int.class, 1, 2);
}
@Test @Ignore("IllArgEx failure in call to ToGeneric.make")
public void testFail_4() throws Throwable {
// ToGeneric.<init>: UnsupportedOperationException: NYI: primitive parameters must follow references; entryType = (int,java.lang.Object)java.lang.Object
testCollectArguments(int.class, 1, 2);
}
@Test @Ignore("cannot collect leading primitive types")
public void testFail_5() throws Throwable {
// ToGeneric.<init>: UnsupportedOperationException: NYI: primitive parameters must follow references; entryType = (int,java.lang.Object)java.lang.Object
testInvokers(MethodType.genericMethodType(2).changeParameterType(0, int.class));
}
@Test @Ignore("should not insert arguments beyond MethodHandlePushLimit")
public void testFail_6() throws Throwable {
testInsertArguments(0, 0, MAX_ARG_INCREASE+1);
// ValueConversions.varargsArray: UnsupportedOperationException: NYI: cannot form a varargs array of length 13
testInsertArguments(0, 0, MAX_ARG_INCREASE+10);
}
static final int MAX_ARG_INCREASE = 3;
public MethodHandlesTest() {
}
@Before
public void checkImplementedPlatform() {
boolean platformOK = false;
Properties properties = System.getProperties();
String vers = properties.getProperty("java.vm.version");
String name = properties.getProperty("java.vm.name");
String arch = properties.getProperty("os.arch");
if ((arch.equals("i386") || arch.equals("amd64") ||
arch.equals("sparc") || arch.equals("sparcv9")) &&
(name.contains("Client") || name.contains("Server"))
) {
platformOK = true;
} else {
System.err.println("Skipping tests for unsupported platform: "+Arrays.asList(vers, name, arch));
}
assumeTrue(platformOK);
}
String testName;
int posTests, negTests;
@After
public void printCounts() {
if (verbosity >= 1 && (posTests | negTests) != 0) {
if (verbosity >= 2 && (posTests | negTests) != 0) {
System.out.println();
if (posTests != 0) System.out.println("=== "+testName+": "+posTests+" positive test cases run");
if (negTests != 0) System.out.println("=== "+testName+": "+negTests+" negative test cases run");
posTests = negTests = 0;
}
}
void countTest(boolean positive) {
......@@ -115,7 +138,7 @@ public class MethodHandlesTest {
void countTest() { countTest(true); }
void startTest(String name) {
if (testName != null) printCounts();
if (verbosity >= 0)
if (verbosity >= 1)
System.out.println(name);
posTests = negTests = 0;
testName = name;
......@@ -125,7 +148,7 @@ public class MethodHandlesTest {
public static void setUpClass() throws Exception {
calledLog.clear();
calledLog.add(null);
nextArg = 1000000;
nextArgVal = INITIAL_ARG_VAL;
}
@AfterClass
......@@ -144,18 +167,17 @@ public class MethodHandlesTest {
static void assertCalled(String name, Object... args) {
Object expected = logEntry(name, args);
Object actual = calledLog.get(calledLog.size() - 1);
if (expected.equals(actual)) return;
if (expected.equals(actual) && verbosity < 9) return;
System.out.println("assertCalled "+name+":");
System.out.println("expected: "+expected);
System.out.println("actual: "+actual);
System.out.println("ex. types: "+getClasses(expected));
System.out.println("act. types: "+getClasses(actual));
assertEquals("previous method call types", expected, actual);
assertEquals("previous method call", expected, actual);
}
static void printCalled(MethodHandle target, String name, Object... args) {
if (verbosity >= 2)
System.out.println("calling "+logEntry(name, args)+" on "+target);
if (verbosity >= 3)
System.out.println("calling MH="+target+" to "+name+Arrays.toString(args));
}
static Object castToWrapper(Object value, Class<?> dst) {
......@@ -188,11 +210,40 @@ public class MethodHandlesTest {
return null;
}
static int nextArg;
static final int ONE_MILLION = (1000*1000), // first int value
TEN_BILLION = (10*1000*1000*1000), // scale factor to reach upper 32 bits
INITIAL_ARG_VAL = ONE_MILLION << 1; // <<1 makes space for sign bit;
static long nextArgVal;
static long nextArg(boolean moreBits) {
long val = nextArgVal++;
long sign = -(val & 1); // alternate signs
val >>= 1;
if (moreBits)
// Guarantee some bits in the high word.
// In any case keep the decimal representation simple-looking,
// with lots of zeroes, so as not to make the printed decimal
// strings unnecessarily noisy.
val += (val % ONE_MILLION) * TEN_BILLION;
return val ^ sign;
}
static int nextArg() {
// Produce a 32-bit result something like ONE_MILLION+(smallint).
// Example: 1_000_042.
return (int) nextArg(false);
}
static long nextArg(Class<?> kind) {
if (kind == long.class || kind == Long.class ||
kind == double.class || kind == Double.class)
// produce a 64-bit result something like
// ((TEN_BILLION+1) * (ONE_MILLION+(smallint)))
// Example: 10_000_420_001_000_042.
return nextArg(true);
return (long) nextArg();
}
static Object randomArg(Class<?> param) {
Object wrap = castToWrapperOrNull(nextArg, param);
Object wrap = castToWrapperOrNull(nextArg(param), param);
if (wrap != null) {
nextArg++;
return wrap;
}
// import sun.dyn.util.Wrapper;
......@@ -202,7 +253,7 @@ public class MethodHandlesTest {
// if (wrap != Wrapper.OBJECT)
// return wrap.wrap(nextArg++);
if (param.isInterface() || param.isAssignableFrom(String.class))
return "#"+(nextArg++);
return "#"+nextArg();
else
try {
return param.newInstance();
......@@ -277,7 +328,7 @@ public class MethodHandlesTest {
// Subject methods...
static class Example implements IntExample {
final String name;
public Example() { name = "Example#"+(nextArg++); }
public Example() { name = "Example#"+nextArg(); }
protected Example(String name) { this.name = name; }
protected Example(int x) { this(); called("protected <init>", this, x); }
@Override public String toString() { return name; }
......@@ -301,43 +352,56 @@ public class MethodHandlesTest {
public static Object s5(long x, int y) { return called("s5", x, y); }
public static Object s6(int x, long y) { return called("s6", x, y); }
public static Object s7(float x, double y) { return called("s7", x, y); }
static final Lookup EXAMPLE = MethodHandles.lookup(); // for testing findSpecial
}
static final Lookup EXAMPLE = Example.EXAMPLE;
public static class PubExample extends Example {
public PubExample() { super("PubExample#"+nextArg()); }
}
static class SubExample extends Example {
@Override public void v0() { called("Sub/v0", this); }
@Override void pkg_v0() { called("Sub/pkg_v0", this); }
private SubExample(int x) { called("<init>", this, x); }
public SubExample() { super("SubExample#"+(nextArg++)); }
public SubExample() { super("SubExample#"+nextArg()); }
}
public static interface IntExample {
public void v0();
static class Impl implements IntExample {
public void v0() { called("Int/v0", this); }
final String name;
public Impl() { name = "Example#"+(nextArg++); }
public Impl() { name = "Impl#"+nextArg(); }
@Override public String toString() { return name; }
}
}
static final Object[][][] ACCESS_CASES = {
{ { false, PUBLIC }, { false, PACKAGE }, { false, PRIVATE } },
{ { false, PUBLIC }, { false, PACKAGE }, { true, PRIVATE } },
{ { false, PUBLIC }, { true, PACKAGE }, { true, PRIVATE } },
{ { true, PUBLIC }, { true, PACKAGE }, { true, PRIVATE } },
{ { false, PUBLIC }, { false, PACKAGE }, { false, PRIVATE }, { false, EXAMPLE } }, //[0]: all false
{ { false, PUBLIC }, { false, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[1]: only PRIVATE
{ { false, PUBLIC }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[2]: PUBLIC false
{ { true, PUBLIC }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[3]: all true
};
static Object[][] accessCases(Class<?> defc, String name) {
if (name.contains("pri_")) {
return ACCESS_CASES[1]; // PRIVATE only
} else if (name.contains("pkg_")) {
return ACCESS_CASES[2]; // not PUBLIC
static Object[][] accessCases(Class<?> defc, String name, boolean isSpecial) {
Object[][] cases;
if (name.contains("pri_") || isSpecial) {
cases = ACCESS_CASES[1]; // PRIVATE only
} else if (name.contains("pkg_") || !Modifier.isPublic(defc.getModifiers())) {
cases = ACCESS_CASES[2]; // not PUBLIC
} else {
assertTrue(name.indexOf('_') < 0);
boolean pubc = Modifier.isPublic(defc.getModifiers());
if (pubc)
return ACCESS_CASES[3]; // all access levels
return ACCESS_CASES[2]; // PACKAGE but not PUBLIC
cases = ACCESS_CASES[3]; // all access levels
else
cases = ACCESS_CASES[2]; // PACKAGE but not PUBLIC
}
if (defc != Example.class && cases[cases.length-1][1] == EXAMPLE)
cases = Arrays.copyOfRange(cases, 0, cases.length-1);
return cases;
}
static Object[][] accessCases(Class<?> defc, String name) {
return accessCases(defc, name, false);
}
@Test
......@@ -374,12 +438,13 @@ public class MethodHandlesTest {
MethodHandle target = null;
RuntimeException noAccess = null;
try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
target = lookup.findStatic(defc, name, type);
} catch (NoAccessException ex) {
noAccess = ex;
}
if (verbosity >= 2)
System.out.println("findStatic "+lookup+": "+defc+"."+name+"/"+type+" => "+target
if (verbosity >= 3)
System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target
+(noAccess == null ? "" : " !! "+noAccess));
if (positive && noAccess != null) throw noAccess;
assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
......@@ -391,6 +456,7 @@ public class MethodHandlesTest {
printCalled(target, name, args);
target.invokeVarargs(args);
assertCalled(name, args);
if (verbosity >= 1)
System.out.print(':');
}
......@@ -436,21 +502,24 @@ public class MethodHandlesTest {
MethodHandle target = null;
RuntimeException noAccess = null;
try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
target = lookup.findVirtual(defc, methodName, type);
} catch (NoAccessException ex) {
noAccess = ex;
}
if (verbosity >= 2)
System.out.println("findVirtual "+lookup+": "+defc+"."+name+"/"+type+" => "+target
if (verbosity >= 3)
System.out.println("findVirtual "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target
+(noAccess == null ? "" : " !! "+noAccess));
if (positive && noAccess != null) throw noAccess;
assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
if (!positive) return; // negative test failed as expected
Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)defc), params);
MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
MethodType ttype = target.type();
ttype = ttype.changeParameterType(0, defc); // FIXME: test this
assertEquals(typeWithSelf, ttype);
if (defc.getClassLoader() != null) // detune due to 6939196
assertEquals(typeWithSelf.dropParameterTypes(0,1),
target.type().dropParameterTypes(0,1));
else // FIXME: use only this test when 6939196 is fixed
assertEquals(typeWithSelf, target.type());
assertTrue(target.toString().contains(methodName)); // rough check
if (!DO_MORE_CALLS && lookup != PRIVATE) return;
Object[] argsWithSelf = randomArgs(paramsWithSelf);
......@@ -458,6 +527,7 @@ public class MethodHandlesTest {
printCalled(target, name, argsWithSelf);
target.invokeVarargs(argsWithSelf);
assertCalled(name, argsWithSelf);
if (verbosity >= 1)
System.out.print(':');
}
......@@ -465,45 +535,53 @@ public class MethodHandlesTest {
public void testFindSpecial() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("findSpecial");
testFindSpecial(Example.class, void.class, "v0");
testFindSpecial(Example.class, void.class, "pkg_v0");
testFindSpecial(false, PRIVATE, Example.class, void.class, "<init>", int.class);
testFindSpecial(false, PRIVATE, Example.class, void.class, "bogus");
}
void testFindSpecial(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
testFindSpecial(true, PRIVATE, defc, ret, name, params);
testFindSpecial(false, PACKAGE, defc, ret, name, params);
testFindSpecial(false, PUBLIC, defc, ret, name, params);
}
void testFindSpecial(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
testFindSpecial(SubExample.class, Example.class, void.class, "v0");
testFindSpecial(SubExample.class, Example.class, void.class, "pkg_v0");
// Do some negative testing:
for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) {
testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0");
testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", int.class);
testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0");
testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "bogus");
}
}
void testFindSpecial(Class<?> specialCaller,
Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
testFindSpecial(true, EXAMPLE, specialCaller, defc, ret, name, params);
testFindSpecial(true, PRIVATE, specialCaller, defc, ret, name, params);
testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params);
testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);
}
void testFindSpecial(boolean positive, Lookup lookup, Class<?> specialCaller,
Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
countTest(positive);
MethodType type = MethodType.methodType(ret, params);
MethodHandle target = null;
RuntimeException noAccess = null;
try {
target = lookup.findSpecial(defc, name, type, defc);
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
target = lookup.findSpecial(defc, name, type, specialCaller);
} catch (NoAccessException ex) {
noAccess = ex;
}
if (verbosity >= 2)
System.out.println("findSpecial "+defc+"."+name+"/"+type+" => "+target
if (verbosity >= 3)
System.out.println("findSpecial from "+specialCaller.getName()+" to "+defc.getName()+"."+name+"/"+type+" => "+target
+(target == null ? "" : target.type())
+(noAccess == null ? "" : " !! "+noAccess));
if (positive && noAccess != null) throw noAccess;
assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
if (!positive) return; // negative test failed as expected
Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)defc), params);
assertEquals(specialCaller, target.type().parameterType(0));
assertEquals(type, target.type().dropParameterTypes(0,1));
Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)specialCaller), params);
MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
MethodType ttype = target.type();
ttype = ttype.changeParameterType(0, defc); // FIXME: test this
assertEquals(typeWithSelf, ttype);
assertTrue(target.toString().contains(name)); // rough check
if (!DO_MORE_CALLS && lookup != PRIVATE) return;
if (!DO_MORE_CALLS && lookup != PRIVATE && lookup != EXAMPLE) return;
Object[] args = randomArgs(paramsWithSelf);
printCalled(target, name, args);
target.invokeVarargs(args);
assertCalled(name, args);
System.out.print(':');
}
@Test
......@@ -538,11 +616,12 @@ public class MethodHandlesTest {
MethodHandle target = null;
RuntimeException noAccess = null;
try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
target = lookup.bind(receiver, methodName, type);
} catch (NoAccessException ex) {
noAccess = ex;
}
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target
+(noAccess == null ? "" : " !! "+noAccess));
if (positive && noAccess != null) throw noAccess;
......@@ -554,6 +633,7 @@ public class MethodHandlesTest {
target.invokeVarargs(args);
Object[] argsWithReceiver = cat(array(Object[].class, receiver), args);
assertCalled(name, argsWithReceiver);
if (verbosity >= 1)
System.out.print(':');
}
......@@ -567,10 +647,10 @@ public class MethodHandlesTest {
testUnreflect(Example.class, true, Object.class, "s1", Object.class);
testUnreflect(Example.class, true, Object.class, "s2", int.class);
//testUnreflect(Example.class, true, Object.class, "s3", long.class);
//testUnreflect(Example.class, true, Object.class, "s4", int.class, int.class);
//testUnreflect(Example.class, true, Object.class, "s5", long.class, int.class);
//testUnreflect(Example.class, true, Object.class, "s6", int.class, long.class);
testUnreflect(Example.class, true, Object.class, "s3", long.class);
testUnreflect(Example.class, true, Object.class, "s4", int.class, int.class);
testUnreflect(Example.class, true, Object.class, "s5", long.class, int.class);
testUnreflect(Example.class, true, Object.class, "s6", int.class, long.class);
testUnreflect(Example.class, false, void.class, "v0");
testUnreflect(Example.class, false, void.class, "pkg_v0");
......@@ -584,10 +664,17 @@ public class MethodHandlesTest {
void testUnreflect(Class<?> defc, boolean isStatic, Class<?> ret, String name, Class<?>... params) throws Throwable {
for (Object[] ac : accessCases(defc, name)) {
testUnreflect((Boolean)ac[0], (Lookup)ac[1], defc, isStatic, ret, name, params);
testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, (isStatic ? null : defc), ret, name, params);
}
}
void testUnreflect(boolean positive, Lookup lookup, Class<?> defc, boolean isStatic, Class<?> ret, String name, Class<?>... params) throws Throwable {
void testUnreflect(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable {
for (Object[] ac : accessCases(defc, name)) {
testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params);
}
}
void testUnreflectMaybeSpecial(Class<?> specialCaller,
boolean positive, Lookup lookup,
Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable {
countTest(positive);
MethodType type = MethodType.methodType(ret, params);
Method rmethod = null;
......@@ -598,43 +685,71 @@ public class MethodHandlesTest {
} catch (NoSuchMethodException ex) {
throw new NoAccessException(ex);
}
assertEquals(isStatic, Modifier.isStatic(rmethod.getModifiers()));
boolean isStatic = (rcvc == null);
boolean isSpecial = (specialCaller != null);
try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
if (isSpecial)
target = lookup.unreflectSpecial(rmethod, specialCaller);
else
target = lookup.unreflect(rmethod);
} catch (NoAccessException ex) {
noAccess = ex;
}
if (verbosity >= 2)
System.out.println("unreflect "+defc+"."+name+"/"+type+" => "+target
if (verbosity >= 3)
System.out.println("unreflect"+(isSpecial?"Special":"")+" "+defc.getName()+"."+name+"/"+type
+(!isSpecial ? "" : " specialCaller="+specialCaller)
+( isStatic ? "" : " receiver="+rcvc)
+" => "+target
+(noAccess == null ? "" : " !! "+noAccess));
if (positive && noAccess != null) throw noAccess;
assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
if (!positive) return; // negative test failed as expected
assertEquals(isStatic, Modifier.isStatic(rmethod.getModifiers()));
Class<?>[] paramsMaybeWithSelf = params;
if (!isStatic) {
paramsMaybeWithSelf = cat(array(Class[].class, (Class)defc), params);
paramsMaybeWithSelf = cat(array(Class[].class, (Class)rcvc), params);
}
MethodType typeMaybeWithSelf = MethodType.methodType(ret, paramsMaybeWithSelf);
MethodType ttype = target.type();
if (!isStatic)
ttype = ttype.changeParameterType(0, defc); // FIXME: test this
assertEquals(typeMaybeWithSelf, ttype);
if (isStatic) {
assertEquals(typeMaybeWithSelf, target.type());
} else {
if (defc.getClassLoader() != null) // detune due to 6939196
assertEquals(typeMaybeWithSelf.dropParameterTypes(0,1),
target.type().dropParameterTypes(0,1));
else // FIXME: use only this test when 6939196 is fixed
if (isSpecial)
assertEquals(specialCaller, target.type().parameterType(0));
else
assertEquals(defc, target.type().parameterType(0));
assertEquals(typeMaybeWithSelf, target.type().changeParameterType(0, rcvc));
}
Object[] argsMaybeWithSelf = randomArgs(paramsMaybeWithSelf);
printCalled(target, name, argsMaybeWithSelf);
target.invokeVarargs(argsMaybeWithSelf);
assertCalled(name, argsMaybeWithSelf);
if (verbosity >= 1)
System.out.print(':');
}
@Test @Ignore("unimplemented")
void testUnreflectSpecial(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable {
for (Object[] ac : accessCases(defc, name, true)) {
Class<?> specialCaller = rcvc;
testUnreflectMaybeSpecial(specialCaller, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params);
}
}
@Test
public void testUnreflectSpecial() throws Throwable {
Lookup lookup = PRIVATE; // FIXME: test more lookups than this one
if (CAN_SKIP_WORKING) return;
startTest("unreflectSpecial");
Method m = null;
MethodHandle expResult = null;
MethodHandle result = lookup.unreflectSpecial(m, Example.class);
assertEquals(expResult, result);
fail("The test case is a prototype.");
testUnreflectSpecial(Example.class, Example.class, void.class, "v0");
testUnreflectSpecial(Example.class, SubExample.class, void.class, "v0");
testUnreflectSpecial(Example.class, Example.class, void.class, "pkg_v0");
testUnreflectSpecial(Example.class, SubExample.class, void.class, "pkg_v0");
testUnreflectSpecial(Example.class, Example.class, Object.class, "v2", int.class, int.class);
testUnreflectSpecial(Example.class, SubExample.class, Object.class, "v2", int.class, int.class);
testUnreflectMaybeSpecial(Example.class, false, PRIVATE, Example.class, Example.class, void.class, "s0");
}
public static class HasFields {
......@@ -735,14 +850,14 @@ public class MethodHandlesTest {
for (int i = 0; i <= 1; i++) {
if (isStatic) {
if (type == int.class)
sawValue = mh.<int>invoke(); // do these exactly
sawValue = mh.<int>invokeExact(); // do these exactly
else
sawValue = mh.invoke();
sawValue = mh.invokeExact();
} else {
if (type == int.class)
sawValue = mh.<int>invoke((Object) fields);
sawValue = mh.<int>invokeExact((Object) fields);
else
sawValue = mh.invoke((Object) fields);
sawValue = mh.invokeExact((Object) fields);
}
assertEquals(sawValue, expValue);
Object random = randomArg(type);
......@@ -786,14 +901,14 @@ public class MethodHandlesTest {
Object putValue = randomArg(type);
if (isStatic) {
if (type == int.class)
mh.<void>invoke((int)(Integer)putValue); // do these exactly
mh.<void>invokeExact((int)(Integer)putValue); // do these exactly
else
mh.<void>invoke(putValue);
mh.<void>invokeExact(putValue);
} else {
if (type == int.class)
mh.<void>invoke((Object) fields, (int)(Integer)putValue);
mh.<void>invokeExact((Object) fields, (int)(Integer)putValue);
else
mh.<void>invoke((Object) fields, putValue);
mh.<void>invokeExact((Object) fields, putValue);
}
assertEquals(f.get(fields), putValue);
}
......@@ -803,25 +918,31 @@ public class MethodHandlesTest {
@Test
public void testArrayElementGetter() throws Throwable {
startTest("arrayElementGetter");
testArrayElementGetterSetter(new Object[10], false);
testArrayElementGetterSetter(new String[10], false);
testArrayElementGetterSetter(new int[10], false);
// FIXME: Do the other primitive types.
//testArrayElementGetterSetter(new float[10], false);
testArrayElementGetterSetter(false);
}
@Test
public void testArrayElementSetter() throws Throwable {
startTest("arrayElementSetter");
testArrayElementGetterSetter(new Object[10], true);
testArrayElementGetterSetter(new String[10], true);
testArrayElementGetterSetter(new int[10], true);
// FIXME: Do the other primitive types.
//testArrayElementGetterSetter(new float[10], true);
testArrayElementGetterSetter(true);
}
public void testArrayElementGetterSetter(boolean testSetter) throws Throwable {
testArrayElementGetterSetter(new Object[10], testSetter);
testArrayElementGetterSetter(new String[10], testSetter);
testArrayElementGetterSetter(new boolean[10], testSetter);
testArrayElementGetterSetter(new byte[10], testSetter);
testArrayElementGetterSetter(new char[10], testSetter);
testArrayElementGetterSetter(new short[10], testSetter);
testArrayElementGetterSetter(new int[10], testSetter);
testArrayElementGetterSetter(new float[10], testSetter);
testArrayElementGetterSetter(new long[10], testSetter);
testArrayElementGetterSetter(new double[10], testSetter);
}
public void testArrayElementGetterSetter(Object array, boolean testSetter) throws Throwable {
countTest(true);
if (verbosity >= 2) System.out.println("array type = "+array.getClass().getComponentType().getName()+"["+Array.getLength(array)+"]");
Class<?> arrayType = array.getClass();
Class<?> elemType = arrayType.getComponentType();
MethodType expType = !testSetter
......@@ -831,7 +952,19 @@ public class MethodHandlesTest {
? MethodHandles.arrayElementGetter(arrayType)
: MethodHandles.arrayElementSetter(arrayType);
assertSame(mh.type(), expType);
//assertEquals(mh.toString(), f.getName());
if (elemType != int.class && elemType != boolean.class) {
MethodType gtype;
if (true) { // FIXME: remove this path (and remove <void> below in the mh.invokes)
gtype = mh.type().changeParameterType(0, Object.class);
if (testSetter)
gtype = gtype.changeParameterType(2, Object.class);
else
gtype = gtype.changeReturnType(Object.class);
} else
// FIXME: This simpler path hits a bug in convertArguments => ToGeneric
gtype = mh.type().generic().changeParameterType(1, int.class);
mh = MethodHandles.convertArguments(mh, gtype);
}
Object sawValue, expValue;
List<Object> model = array2list(array);
int length = Array.getLength(array);
......@@ -841,22 +974,31 @@ public class MethodHandlesTest {
model.set(i, random);
if (testSetter) {
if (elemType == int.class)
mh.<void>invoke((int[]) array, i, (int)(Integer)random);
mh.<void>invokeExact((int[]) array, i, (int)(Integer)random);
else if (elemType == boolean.class)
mh.<void>invokeExact((boolean[]) array, i, (boolean)(Boolean)random);
else
mh.invokeGeneric(array, i, random);
mh.<void>invokeExact(array, i, random);
assertEquals(model, array2list(array));
} else {
Array.set(array, i, random);
}
if (verbosity >= 5) {
List<Object> array2list = array2list(array);
System.out.println("a["+i+"]="+random+" => "+array2list);
if (!array2list.equals(model))
System.out.println("*** != "+model);
}
// observe array element
sawValue = Array.get(array, i);
if (!testSetter) {
expValue = sawValue;
if (elemType == int.class)
sawValue = mh.<int>invoke((int[]) array, i);
sawValue = mh.<int>invokeExact((int[]) array, i);
else if (elemType == boolean.class)
sawValue = mh.<boolean>invokeExact((boolean[]) array, i);
else
sawValue = mh.invokeGeneric(array, i);
sawValue = mh.invokeExact(array, i);
assertEquals(sawValue, expValue);
assertEquals(model, array2list(array));
}
......@@ -906,6 +1048,8 @@ public class MethodHandlesTest {
testConvert(Callee.ofType(1), null, "id", String.class);
testConvert(Callee.ofType(1), null, "id", Integer.class);
testConvert(Callee.ofType(1), null, "id", short.class);
testConvert(Callee.ofType(1), null, "id", char.class);
testConvert(Callee.ofType(1), null, "id", byte.class);
}
void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
......@@ -943,7 +1087,7 @@ public class MethodHandlesTest {
} catch (RuntimeException ex) {
error = ex;
}
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("convert "+id+ " to "+newType+" => "+target
+(error == null ? "" : " !! "+error));
if (positive && error != null) throw error;
......@@ -954,6 +1098,7 @@ public class MethodHandlesTest {
Object result = target.invokeVarargs(args);
assertCalled(name, convArgs);
assertEquals(convResult, result);
if (verbosity >= 1)
System.out.print(':');
}
......@@ -966,7 +1111,7 @@ public class MethodHandlesTest {
//testPermuteArguments(4, Integer.class, 1, int.class, 6);
}
public void testPermuteArguments(int max, Class<?> type1, int t2c, Class<?> type2, int dilution) throws Throwable {
if (verbosity >= 1)
if (verbosity >= 2)
System.out.println("permuteArguments "+max+"*"+type1.getName()
+(t2c==0?"":"/"+t2c+"*"+type2.getName())
+(dilution > 0 ? " with dilution "+dilution : ""));
......@@ -1054,7 +1199,7 @@ public class MethodHandlesTest {
}
int inargs = args.length, outargs = reorder.length;
assert(inargs == types.length);
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("permuteArguments "+Arrays.toString(reorder));
Object[] permArgs = new Object[outargs];
Class<?>[] permTypes = new Class<?>[outargs];
......@@ -1062,7 +1207,7 @@ public class MethodHandlesTest {
permArgs[i] = args[reorder[i]];
permTypes[i] = types[reorder[i]];
}
if (verbosity >= 3) {
if (verbosity >= 4) {
System.out.println("in args: "+Arrays.asList(args));
System.out.println("out args: "+Arrays.asList(permArgs));
System.out.println("in types: "+Arrays.asList(types));
......@@ -1083,8 +1228,9 @@ public class MethodHandlesTest {
if (CAN_SKIP_WORKING) return;
startTest("spreadArguments");
for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) {
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("spreadArguments "+argType);
// FIXME: enable _adapter_spread_args and fix Fail_2
for (int nargs = 0; nargs < 10; nargs++) {
if (argType == int.class && nargs >= 6) continue; // FIXME Fail_1
for (int pos = 0; pos < nargs; pos++) {
......@@ -1098,7 +1244,7 @@ public class MethodHandlesTest {
countTest();
MethodHandle target = ValueConversions.varargsArray(nargs);
MethodHandle target2 = changeArgTypes(target, argType);
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]");
Object[] args = randomArgs(target2.type().parameterArray());
// make sure the target does what we think it does:
......@@ -1107,15 +1253,15 @@ public class MethodHandlesTest {
assertArrayEquals(args, check);
switch (nargs) {
case 0:
check = target.<Object[]>invoke();
check = target.<Object[]>invokeExact();
assertArrayEquals(args, check);
break;
case 1:
check = target.<Object[]>invoke(args[0]);
check = target.<Object[]>invokeExact(args[0]);
assertArrayEquals(args, check);
break;
case 2:
check = target.<Object[]>invoke(args[0], args[1]);
check = target.<Object[]>invokeExact(args[0], args[1]);
assertArrayEquals(args, check);
break;
}
......@@ -1129,7 +1275,7 @@ public class MethodHandlesTest {
MethodHandle result = MethodHandles.spreadArguments(target2, newType);
Object[] returnValue;
if (pos == 0) {
returnValue = (Object[]) result.invoke(args);
returnValue = (Object[]) result.invokeExact(args);
} else {
Object[] args1 = Arrays.copyOfRange(args, 0, pos+1);
args1[pos] = Arrays.copyOfRange(args, pos, args.length);
......@@ -1143,7 +1289,7 @@ public class MethodHandlesTest {
if (CAN_SKIP_WORKING) return;
startTest("collectArguments");
for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) {
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("collectArguments "+argType);
for (int nargs = 0; nargs < 10; nargs++) {
for (int pos = 0; pos < nargs; pos++) {
......@@ -1167,7 +1313,7 @@ public class MethodHandlesTest {
MethodHandle target = ValueConversions.varargsArray(pos+1);
target = changeArgTypes(target, 0, pos, argType);
target = changeArgTypes(target, pos, pos+1, Object[].class);
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]");
MethodHandle result = MethodHandles.collectArguments(target, newType);
Object[] returnValue = (Object[]) result.invokeVarargs(args);
......@@ -1198,14 +1344,14 @@ public class MethodHandlesTest {
List<Object> resList = Arrays.asList(args);
List<Object> argsToPass = new ArrayList<Object>(resList);
List<Object> argsToInsert = argsToPass.subList(pos, pos + ins);
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("insert: "+argsToInsert+" into "+target);
MethodHandle target2 = MethodHandles.insertArguments(target, pos,
(Object[]) argsToInsert.toArray());
argsToInsert.clear(); // remove from argsToInsert
Object res2 = target2.invokeVarargs(argsToPass);
Object res2List = Arrays.asList((Object[])res2);
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("result: "+res2List);
//if (!resList.equals(res2List))
// System.out.println("*** fail at n/p/i = "+nargs+"/"+pos+"/"+ins+": "+resList+" => "+res2List);
......@@ -1229,17 +1375,17 @@ public class MethodHandlesTest {
MethodHandle filter = ValueConversions.varargsList(1);
filter = MethodHandles.convertArguments(filter, filter.type().generic());
Object[] argsToPass = randomArgs(nargs, Object.class);
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("filter "+target+" at "+pos+" with "+filter);
MethodHandle[] filters = new MethodHandle[pos*2+1];
filters[pos] = filter;
MethodHandle target2 = MethodHandles.filterArguments(target, filters);
// Simulate expected effect of filter on arglist:
Object[] filteredArgs = argsToPass.clone();
filteredArgs[pos] = filter.invoke(filteredArgs[pos]);
filteredArgs[pos] = filter.invokeExact(filteredArgs[pos]);
List<Object> expected = Arrays.asList(filteredArgs);
Object result = target2.invokeVarargs(argsToPass);
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("result: "+result);
if (!expected.equals(result))
System.out.println("*** fail at n/p = "+nargs+"/"+pos+": "+argsToPass+" => "+result);
......@@ -1265,18 +1411,18 @@ public class MethodHandlesTest {
MethodHandle target = ValueConversions.varargsList(1 + nargs);
MethodHandle combine = ValueConversions.varargsList(fold);
List<Object> argsToPass = Arrays.asList(randomArgs(nargs, Object.class));
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("fold "+target+" with "+combine);
MethodHandle target2 = MethodHandles.foldArguments(target, combine);
// Simulate expected effect of combiner on arglist:
List<Object> expected = new ArrayList<Object>(argsToPass);
List<Object> argsToFold = expected.subList(pos, pos + fold);
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("fold: "+argsToFold+" into "+target2);
Object foldedArgs = combine.invokeVarargs(argsToFold);
argsToFold.add(0, foldedArgs);
Object result = target2.invokeVarargs(argsToPass);
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("result: "+result);
if (!expected.equals(result))
System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result);
......@@ -1343,7 +1489,7 @@ public class MethodHandlesTest {
}
public void testInvokers(MethodType type) throws Throwable {
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("test invokers for "+type);
int nargs = type.parameterCount();
boolean testRetCode = type.returnType() != void.class;
......@@ -1373,16 +1519,16 @@ public class MethodHandlesTest {
calledLog.clear();
switch (nargs) {
case 0:
result = inv.invoke(target);
result = inv.invokeExact(target);
break;
case 1:
result = inv.invoke(target, args[0]);
result = inv.invokeExact(target, args[0]);
break;
case 2:
result = inv.invoke(target, args[0], args[1]);
result = inv.invokeExact(target, args[0], args[1]);
break;
case 3:
result = inv.invoke(target, args[0], args[1], args[2]);
result = inv.invokeExact(target, args[0], args[1], args[2]);
break;
}
if (testRetCode) assertEquals(code, result);
......@@ -1395,14 +1541,14 @@ public class MethodHandlesTest {
// varargs invoker #0
calledLog.clear();
inv = MethodHandles.varargsInvoker(type, 0);
result = inv.invoke(target, args);
result = inv.invokeExact(target, args);
if (testRetCode) assertEquals(code, result);
assertCalled("invokee", args);
if (nargs >= 1) {
// varargs invoker #1
calledLog.clear();
inv = MethodHandles.varargsInvoker(type, 1);
result = inv.invoke(target, args[0], Arrays.copyOfRange(args, 1, nargs));
result = inv.invokeExact(target, args[0], Arrays.copyOfRange(args, 1, nargs));
if (testRetCode) assertEquals(code, result);
assertCalled("invokee", args);
}
......@@ -1410,7 +1556,7 @@ public class MethodHandlesTest {
// varargs invoker #2
calledLog.clear();
inv = MethodHandles.varargsInvoker(type, 2);
result = inv.invoke(target, args[0], args[1], Arrays.copyOfRange(args, 2, nargs));
result = inv.invokeExact(target, args[0], args[1], Arrays.copyOfRange(args, 2, nargs));
if (testRetCode) assertEquals(code, result);
assertCalled("invokee", args);
}
......@@ -1418,7 +1564,7 @@ public class MethodHandlesTest {
// varargs invoker #3
calledLog.clear();
inv = MethodHandles.varargsInvoker(type, 3);
result = inv.invoke(target, args[0], args[1], args[2], Arrays.copyOfRange(args, 3, nargs));
result = inv.invokeExact(target, args[0], args[1], args[2], Arrays.copyOfRange(args, 3, nargs));
if (testRetCode) assertEquals(code, result);
assertCalled("invokee", args);
}
......@@ -1523,7 +1669,7 @@ public class MethodHandlesTest {
default: equals = argList[0].equals(argList[1]); break;
}
String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals");
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println(logEntry(willCall, argList));
Object result = mh.invokeVarargs(argList);
assertCalled(willCall, argList);
......@@ -1552,7 +1698,7 @@ public class MethodHandlesTest {
void testCatchException(Class<?> returnType, Throwable thrown, boolean throwIt, int nargs) throws Throwable {
countTest();
if (verbosity >= 2)
if (verbosity >= 3)
System.out.println("catchException rt="+returnType+" throw="+throwIt+" nargs="+nargs);
Class<? extends Throwable> exType = thrown.getClass();
MethodHandle throwOrReturn
......@@ -1594,9 +1740,10 @@ public class MethodHandlesTest {
//System.out.println("throwing with "+target+" : "+thrown);
MethodType expectedType = MethodType.methodType(returnType, exType);
assertEquals(expectedType, target.type());
target = MethodHandles.convertArguments(target, target.type().generic());
Throwable caught = null;
try {
Object res = target.invokeGeneric(thrown);
Object res = target.invokeExact((Object) thrown);
fail("got "+res+" instead of throwing "+thrown);
} catch (Throwable ex) {
if (ex != thrown) {
......@@ -1647,7 +1794,7 @@ public class MethodHandlesTest {
void testCastFailure(String mode, int okCount) throws Throwable {
countTest(false);
if (verbosity > 1) System.out.println("mode="+mode);
if (verbosity > 2) System.out.println("mode="+mode);
Surprise boo = new Surprise();
MethodHandle identity = Surprise.REF_IDENTITY, surprise = boo;
if (mode.endsWith("/return")) {
......@@ -1680,22 +1827,22 @@ public class MethodHandlesTest {
surprise = MethodHandles.convertArguments(surprise, MethodType.genericMethodType(1));
Object x = 42;
for (int i = 0; i < okCount; i++) {
Object y = identity.invoke(x);
Object y = identity.invokeExact(x);
assertEquals(x, y);
Object z = surprise.invoke(x);
Object z = surprise.invokeExact(x);
assertEquals(x, z);
}
boo.boo("Boo!");
Object y = identity.invoke(x);
Object y = identity.invokeExact(x);
assertEquals(x, y);
try {
Object z = surprise.invoke(x);
Object z = surprise.invokeExact(x);
System.out.println("Failed to throw; got z="+z);
assertTrue(false);
} catch (Exception ex) {
if (verbosity > 1)
System.out.println("caught "+ex);
if (verbosity > 2)
System.out.println("caught "+ex);
if (verbosity > 3)
ex.printStackTrace();
assertTrue(ex instanceof ClassCastException
// FIXME: accept only one of the two for any given unit test
......@@ -1766,7 +1913,7 @@ class ValueConversions {
if (nargs < ARRAYS.length)
return ARRAYS[nargs];
// else need to spin bytecode or do something else fancy
throw new UnsupportedOperationException("NYI");
throw new UnsupportedOperationException("NYI: cannot form a varargs array of length "+nargs);
}
private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册