mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-23 05:10:57 +00:00
Merge
This commit is contained in:
commit
f3779adaed
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. 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 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.
|
||||
* 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(Object caller, String name, MethodType type) {
|
||||
super(IMPL_TOKEN, caller, name, type);
|
||||
public CallSite() {
|
||||
}
|
||||
|
||||
private static void privateInitializeCallSite(CallSite site, int callerMID, int callerBCI) {
|
||||
site.callerMID = callerMID;
|
||||
site.callerBCI = callerBCI;
|
||||
site.ensureTarget();
|
||||
/**
|
||||
* 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(MethodHandle target) {
|
||||
this.target = target;
|
||||
}
|
||||
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
|
||||
|
||||
/** @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");
|
||||
}
|
||||
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;
|
||||
}
|
||||
MethodType oldType = oldTarget.type();
|
||||
if (!newTarget.type().equals(oldType))
|
||||
throw wrongTargetType(newTarget, oldType);
|
||||
if (oldTarget != newTarget)
|
||||
CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
|
||||
}
|
||||
|
||||
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());
|
||||
private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
|
||||
return new WrongMethodTypeException(String.valueOf(target)+target.type()+" should be of type "+type);
|
||||
}
|
||||
|
||||
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
|
||||
/** Produce a printed representation that displays information about this call site
|
||||
* that may be useful to the human reader.
|
||||
*/
|
||||
public Class<?> callerClass() {
|
||||
return (Class) caller;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. 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.<void>invoke(); // also prints "hello, world"
|
||||
* mh.<void>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.<Number>invoke(1L); // 456
|
||||
* stuffPtr.setter().<void>invoke(0L, (Number) 789); // replaces 123 with 789
|
||||
* int x = (Integer) stuffPtr.<Number>invokeExact(1L); // 456
|
||||
* stuffPtr.setter().<void>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)
|
||||
throw new WrongMethodTypeException(mh.toString());
|
||||
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) => String}
|
||||
* mt = MethodType.make(String.class, char.class, char.class);
|
||||
* mh = lookup.findVirtual(String.class, "replace", mt);
|
||||
* // (Ljava/lang/String;CC)Ljava/lang/String;
|
||||
* s = mh.<String>invoke("daddy",'d','n');
|
||||
* assert(s.equals("nanny"));
|
||||
* // weakly typed invocation (using MHs.invoke)
|
||||
* s = (String) MethodHandles.invoke(mh, "sappy", 'p', 'v');
|
||||
* assert(s.equals("savvy"));
|
||||
* // mt is {Object[] => List}
|
||||
* mt = MethodType.make(java.util.List.class, Object[].class);
|
||||
* mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
|
||||
* // mt is {(Object,Object,Object) => Object}
|
||||
* mt = MethodType.makeGeneric(3);
|
||||
* mh = MethodHandles.collectArguments(mh, mt);
|
||||
* // mt is {(Object,Object,Object) => Object}
|
||||
* // (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
* x = mh.invoke((Object)1, (Object)2, (Object)3);
|
||||
* assert(x.equals(java.util.Arrays.asList(1,2,3)));
|
||||
* // mt is { => int}
|
||||
* mt = MethodType.make(int.class);
|
||||
* mh = lookup.findVirtual(java.util.List.class, "size", mt);
|
||||
* // (Ljava/util/List;)I
|
||||
* i = mh.<int>invoke(java.util.Arrays.asList(1,2,3));
|
||||
* assert(i == 3);
|
||||
Object x, y; String s; int i;
|
||||
MethodType mt; MethodHandle mh;
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
// mt is {(char,char) => 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.<String>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[] => List}
|
||||
mt = MethodType.methodType(java.util.List.class, Object[].class);
|
||||
mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
|
||||
// mt is {(Object,Object,Object) => Object}
|
||||
mt = MethodType.genericMethodType(3);
|
||||
mh = MethodHandles.collectArguments(mh, mt);
|
||||
// mt is {(Object,Object,Object) => Object}
|
||||
// (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
x = mh.invokeExact((Object)1, (Object)2, (Object)3);
|
||||
assert(x.equals(java.util.Arrays.asList(1,2,3)));
|
||||
// mt is { => int}
|
||||
mt = MethodType.methodType(int.class);
|
||||
mh = lookup.findVirtual(java.util.List.class, "size", mt);
|
||||
// (Ljava/util/List;)I
|
||||
i = mh.<int>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 {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. 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.
|
||||
* It can only be used to create method handles to
|
||||
* publicly accessible members.
|
||||
/**
|
||||
* Return a {@link Lookup lookup object} which is trusted minimally.
|
||||
* It can only be used to create method handles to
|
||||
* 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);
|
||||
}
|
||||
|
||||
private Lookup(Class<?> lookupClass) {
|
||||
this.lookupClass = lookupClass;
|
||||
if ((newModes & PRIVATE) != 0
|
||||
&& !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) {
|
||||
newModes &= ~PRIVATE;
|
||||
}
|
||||
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 "<init>")
|
||||
* @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());
|
||||
}
|
||||
return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* <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.
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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, 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 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());
|
||||
}
|
||||
|
||||
// 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;
|
||||
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()));
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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();
|
||||
int mods = m.getModifiers();
|
||||
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
|
||||
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);
|
||||
}
|
||||
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());
|
||||
else
|
||||
throw new InternalError();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -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.<String>invoke("x", "y")); // xy
|
||||
* System.out.println(cat.<String>invokeExact("x", "y")); // xy
|
||||
* MethodHandle d0 = dropArguments(cat, 0, String.class);
|
||||
* System.out.println(d0.<String>invoke("x", "y", "z")); // xy
|
||||
* System.out.println(d0.<String>invokeExact("x", "y", "z")); // xy
|
||||
* MethodHandle d1 = dropArguments(cat, 1, String.class);
|
||||
* System.out.println(d1.<String>invoke("x", "y", "z")); // xz
|
||||
* System.out.println(d1.<String>invokeExact("x", "y", "z")); // xz
|
||||
* MethodHandle d2 = dropArguments(cat, 2, String.class);
|
||||
* System.out.println(d2.<String>invoke("x", "y", "z")); // yz
|
||||
* System.out.println(d2.<String>invokeExact("x", "y", "z")); // yz
|
||||
* MethodHandle d12 = dropArguments(cat, 1, String.class, String.class);
|
||||
* System.out.println(d12.<String>invoke("w", "x", "y", "z")); // wz
|
||||
* System.out.println(d12.<String>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>( )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.<init>(A*)void</td><td>(A*)C</td><td>new C; dup; invokespecial C.<init>(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;
|
||||
}
|
||||
|
||||
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);
|
||||
// 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");
|
||||
}
|
||||
CallSite site;
|
||||
try {
|
||||
site = bsm.<CallSite>invoke(caller, name, type);
|
||||
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);
|
||||
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("exception thrown while linking", ex);
|
||||
}
|
||||
if (site == null)
|
||||
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);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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)); }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. 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 "<init>"}.
|
||||
*/
|
||||
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 "<init>"}.
|
||||
* 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 "<init>"}.
|
||||
* 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);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. 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;
|
||||
}
|
||||
@ -176,28 +176,164 @@ public abstract class MethodHandleImpl {
|
||||
boolean doDispatch, Class<?> lookupClass) {
|
||||
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)
|
||||
rtype = rtype.changeParameterType(0, Object.class);
|
||||
}
|
||||
DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
|
||||
if (!mh.isValid())
|
||||
throw newNoAccessException(method, lookupClass);
|
||||
MethodHandle rmh = AdapterMethodHandle.makePairwiseConvert(token, rtype, mh);
|
||||
if (rmh == null) throw new InternalError();
|
||||
return rmh;
|
||||
assert(mh.type() == mtype);
|
||||
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
|
||||
@ -469,6 +605,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 +918,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,
|
||||
MethodHandle test, MethodHandle target, MethodHandle fallback) {
|
||||
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 +1041,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 +1064,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 +1248,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. 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;
|
||||
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.
|
||||
}
|
||||
}
|
||||
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;
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user