提交 f7bd7bb2 编写于 作者: J jrose

6939134: JSR 292 adjustments to method handle invocation

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