This commit is contained in:
Erik Trimble 2010-12-16 20:51:55 -08:00
commit 0f8bafe829
40 changed files with 5406 additions and 1904 deletions

View File

@ -36,9 +36,7 @@ AUTO_FILES_JAVA_DIRS = java/dyn sun/dyn
LANGUAGE_VERSION = -source 7
CLASS_VERSION = -target 7
# Actually, it will be less disruptive to compile with the same
# -target option as the rest of the system, and just turn on
# the specific compiler option we need here:
OTHER_JAVACFLAGS = -XDinvokedynamic
# Tell the compiler not to accept transitional forms.
OTHER_JAVACFLAGS = -XDallowTransitionalJSR292=no
include $(BUILDDIR)/common/Classes.gmk

View File

@ -1,82 +0,0 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.dyn;
import java.lang.annotation.*;
/**
* Annotation on InvokeDynamic method calls which requests the JVM to use a specific
* <a href="package-summary.html#bsm">bootstrap method</a>
* to link the call. This annotation is not retained as such in the class file,
* but is transformed into a constant-pool entry for the invokedynamic instruction which
* specifies the desired bootstrap method.
* <p>
* If only the <code>value</code> is given, it must name a subclass of {@link CallSite}
* with a constructor which accepts a class, string, and method type.
* If the <code>value</code> and <code>name</code> are both given, there must be
* a static method in the given class of the given name which accepts a class, string,
* and method type, and returns a reference coercible to {@link CallSite}.
* <p>
* This annotation can be placed either on the return type of a single {@link InvokeDynamic}
* call (see examples) or else it can be placed on an enclosing class or method, where it
* determines a default bootstrap method for any {@link InvokeDynamic} calls which are not
* specifically annotated with a bootstrap method.
* Every {@link InvokeDynamic} call must be given a bootstrap method.
* <p>
* Examples:
<blockquote><pre>
&#064;BootstrapMethod(value=MyLanguageRuntime.class, name="bootstrapDynamic")
String x = (String) InvokeDynamic.greet();
//BSM => MyLanguageRuntime.bootstrapDynamic(Here.class, "greet", methodType(String.class))
&#064;BootstrapMethod(MyCallSite.class)
void example() throws Throwable {
InvokeDynamic.greet();
//BSM => new MyCallSite(Here.class, "greet", methodType(void.class))
}
</pre></blockquote>
* <p>
*/
@Target({ElementType.TYPE_USE,
// For defaulting every indy site within a class or method; cf. @SuppressWarnings:
ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR
})
@Retention(RetentionPolicy.SOURCE)
public @interface BootstrapMethod {
/** The class containing the bootstrap method. */
Class<?> value();
/** The name of the bootstrap method.
* If this is the empty string, an instance of the bootstrap class is created,
* and a constructor is invoked.
* Otherwise, there must be a static method of the required name.
*/
String name() default ""; // empty string denotes a constructor with 'new'
/** The argument types of the bootstrap method, as passed out by the JVM.
* There is usually no reason to override the default.
*/
Class<?>[] arguments() default {Class.class, String.class, MethodType.class};
}

View File

@ -26,40 +26,45 @@
package java.dyn;
import sun.dyn.*;
import sun.dyn.empty.Empty;
import sun.misc.Unsafe;
import java.util.Collection;
/**
* A {@code CallSite} is a holder for a variable {@link MethodHandle},
* which is called its {@code target}.
* Every call to a {@code CallSite} is delegated to the site's current target.
* An {@code invokedynamic} instruction linked to a {@code CallSite} delegates
* all calls to the site's current target.
* A {@code CallSite} may be associated with several {@code invokedynamic}
* instructions, or it may be "free floating", associated with none.
* In any case, it may be invoked through an associated method handle
* called its {@linkplain #dynamicInvoker dynamic invoker}.
* <p>
* A call site is initially created in an <em>unlinked</em> state,
* which is distinguished by a null target variable.
* Before the call site may be invoked (and before certain other
* operations are attempted), the call site must be linked to
* a non-null target.
* {@code CallSite} is an abstract class which does not allow
* direct subclassing by users. It has three immediate,
* concrete subclasses that may be either instantiated or subclassed.
* <ul>
* <li>If a mutable target is not required, an {@code invokedynamic} instruction
* may be permanently bound by means of a {@linkplain ConstantCallSite constant call site}.
* <li>If a mutable target is required which has volatile variable semantics,
* because updates to the target must be immediately and reliably witnessed by other threads,
* a {@linkplain VolatileCallSite volatile call site} may be used.
* <li>Otherwise, if a mutable target is required,
* a {@linkplain MutableCallSite mutable call site} may be used.
* </ul>
* <p>
* A call site may be <em>relinked</em> by changing its target.
* The new target must be non-null and must have the same
* {@linkplain MethodHandle#type() type}
* A non-constant call site may be <em>relinked</em> by changing its target.
* The new target must have the same {@linkplain MethodHandle#type() type}
* as the previous target.
* Thus, though a call site can be relinked to a series of
* successive targets, it cannot change its type.
* <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 -->
&#064;BootstrapMethod(value=PrintArgsDemo.class, name="bootstrapDynamic")
static void test() throws Throwable {
InvokeDynamic.baz("baz arg", 2, 3.14);
// THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION
InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
}
private static void printArgs(Object... args) {
System.out.println(java.util.Arrays.deepToString(args));
@ -71,16 +76,15 @@ static {
printArgs = lookup.findStatic(thisClass,
"printArgs", MethodType.methodType(void.class, Object[].class));
}
private static CallSite bootstrapDynamic(Class caller, String name, MethodType type) {
private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) {
// ignore caller and name, but match the type:
return new CallSite(MethodHandles.collectArguments(printArgs, type));
return new ConstantCallSite(MethodHandles.collectArguments(printArgs, type));
}
</pre></blockquote>
* @author John Rose, JSR 292 EG
*/
public class CallSite
implements MethodHandleProvider
{
abstract
public class CallSite {
private static final Access IMPL_TOKEN = Access.getToken();
// Fields used only by the JVM. Do not use or change.
@ -88,61 +92,47 @@ public class CallSite
private int vmindex; // supplied by the JVM (BCI within calling method)
// The actual payload of this call site:
private MethodHandle target;
/*package-private*/
MethodHandle target;
// Remove this field for PFD and delete deprecated methods:
private MemberName calleeNameRemoveForPFD;
/**
* Make a blank call site object.
* Before it is returned from a bootstrap method, this {@code CallSite} object
* must be provided with
* a target method via a call to {@link CallSite#setTarget(MethodHandle) setTarget},
* or by a subclass override of {@link CallSite#initialTarget(Class,String,MethodType) initialTarget}.
* Make a blank call site object with the given method type.
* An initial target method is supplied which will throw
* an {@link IllegalStateException} if called.
* <p>
* Before this {@code CallSite} object is returned from a bootstrap method,
* it is usually provided with a more useful target method,
* via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
* @throws NullPointerException if the proposed type is null
*/
public CallSite() {
/*package-private*/
CallSite(MethodType type) {
target = MethodHandles.invokers(type).uninitializedCallSite();
}
/**
* Make a blank call site object, possibly equipped with an initial target method handle.
* The initial target reference may be null, in which case the {@code CallSite} object
* must be provided with a target method via a call to {@link CallSite#setTarget},
* or by a subclass override of {@link CallSite#initialTarget}.
* @param target the method handle which will be the initial target of the call site, or null if there is none yet
* @param target the method handle which will be the initial target of the call site
* @throws NullPointerException if the proposed target is null
*/
public CallSite(MethodHandle target) {
/*package-private*/
CallSite(MethodHandle target) {
target.type(); // null check
this.target = target;
}
/** @deprecated transitional form defined in EDR but removed in PFD */
public CallSite(Class<?> caller, String name, MethodType type) {
this.calleeNameRemoveForPFD = new MemberName(caller, name, type);
}
/** @deprecated transitional form defined in EDR but removed in PFD */
public Class<?> callerClass() {
MemberName callee = this.calleeNameRemoveForPFD;
return callee == null ? null : callee.getDeclaringClass();
}
/** @deprecated transitional form defined in EDR but removed in PFD */
public String name() {
MemberName callee = this.calleeNameRemoveForPFD;
return callee == null ? null : callee.getName();
}
/** @deprecated transitional form defined in EDR but removed in PFD */
public MethodType type() {
MemberName callee = this.calleeNameRemoveForPFD;
return callee == null ? (target == null ? null : target.type()) : callee.getMethodType();
}
/** @deprecated transitional form defined in EDR but removed in PFD */
protected MethodHandle initialTarget() {
return initialTarget(callerClass(), name(), type());
}
/** Report if the JVM has linked this {@code CallSite} object to a dynamic call site instruction.
* Once it is linked, it is never unlinked.
/**
* Report the type of this call site's target.
* Although targets may change, the call site's type can never change.
* The {@code setTarget} method enforces this invariant by refusing any new target that does
* not have the previous target's type.
* @return the type of the current target, which is also the type of any future target
*/
private boolean isLinked() {
return vmmethod != null;
public MethodType type() {
return target.type();
}
/** Called from JVM (or low-level Java code) after the BSM returns the newly created CallSite.
@ -152,68 +142,66 @@ public class CallSite
MethodType type,
MemberName callerMethod,
int callerBCI) {
if (this.isLinked()) {
if (this.vmmethod != null) {
// FIXME
throw new InvokeDynamicBootstrapError("call site has already been linked to an invokedynamic instruction");
}
MethodHandle target = this.target;
if (target == null) {
this.target = target = this.initialTarget(callerMethod.getDeclaringClass(), name, type);
}
if (!target.type().equals(type)) {
if (!this.type().equals(type)) {
throw wrongTargetType(target, type);
}
this.vmindex = callerBCI;
this.vmmethod = callerMethod;
assert(this.isLinked());
}
/**
* Just after a call site is created by a bootstrap method handle,
* if the target has not been initialized by the factory method itself,
* the method {@code initialTarget} is called to produce an initial
* non-null target. (Live call sites must never have null targets.)
* Report the current linkage state of the call site, a value which may change over time.
* <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.
* If a {@code CallSite} object is returned
* from the bootstrap method of the {@code invokedynamic} instruction,
* the {@code CallSite} is permanently bound to that instruction.
* When the {@code invokedynamic} instruction is executed, the target method
* of its associated call site object is invoked directly.
* It is as if the instruction calls {@code getTarget} and then
* calls {@link MethodHandle#invokeExact invokeExact} on the result.
* <p>
* If the bootstrap method itself does not initialize the call site,
* this method must be overridden, because it just raises an
* {@code InvokeDynamicBootstrapError}, which in turn causes the
* linkage of the {@code invokedynamic} instruction to terminate
* abnormally.
* @deprecated transitional form defined in EDR but removed in PFD
*/
protected MethodHandle initialTarget(Class<?> callerClass, String name, MethodType type) {
throw new InvokeDynamicBootstrapError("target must be initialized before call site is linked: "+name+type);
}
/**
* Report the current linkage state of the call site. (This is mutable.)
* The value may not be null after the {@code CallSite} object is returned
* from the bootstrap method of the {@code invokedynamic} instruction.
* When an {@code invokedynamic} instruction is executed, the target method
* of its associated {@code call site} object is invoked directly,
* as if via {@link MethodHandle}{@code .invoke}.
* <p>
* The interactions of {@code getTarget} with memory are the same
* Unless specified differently by a subclass,
* the interactions of {@code getTarget} with memory are the same
* as of a read from an ordinary variable, such as an array element or a
* non-volatile, non-final field.
* <p>
* In particular, the current thread may choose to reuse the result
* of a previous read of the target from memory, and may fail to see
* a recent update to the target by another thread.
* @return the current linkage state of the call site
* <p>
* In a {@linkplain ConstantCallSite constant call site}, the {@code getTarget} method behaves
* like a read from a {@code final} field of the {@code CallSite}.
* <p>
* In a {@linkplain VolatileCallSite volatile call site}, the {@code getTarget} method behaves
* like a read from a {@code volatile} field of the {@code CallSite}.
* <p>
* This method may not be overridden by application code.
* @return the current linkage state of the call site, its target method handle
* @see ConstantCallSite
* @see VolatileCallSite
* @see #setTarget
*/
public MethodHandle getTarget() {
public final MethodHandle getTarget() {
return getTarget0();
}
/**
* Privileged implementations can override this to force final or volatile semantics on getTarget.
*/
/*package-private*/
MethodHandle getTarget0() {
return target;
}
/**
* Set the target method of this call site.
* <p>
* The interactions of {@code setTarget} with memory are the same
* Unless a subclass of CallSite documents otherwise,
* 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
* non-volatile, non-final field.
* <p>
@ -224,43 +212,32 @@ public class CallSite
* at any given call site.
* @param newTarget the new target
* @throws NullPointerException if the proposed new target is null
* @throws WrongMethodTypeException if the call site is linked and the proposed new target
* @throws WrongMethodTypeException if the proposed new target
* has a method type that differs from the previous target
* @throws UnsupportedOperationException if the call site is
* in fact a {@link ConstantCallSite}
*/
public void setTarget(MethodHandle newTarget) {
MethodType newType = newTarget.type(); // null check!
MethodHandle oldTarget = this.target;
if (oldTarget == null) {
// CallSite is not yet linked.
assert(!isLinked());
this.target = newTarget; // might be null!
return;
}
checkTargetChange(this.target, newTarget);
setTargetNormal(newTarget);
}
void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) {
MethodType oldType = oldTarget.type();
if (!newTarget.type().equals(oldType))
MethodType newType = newTarget.type(); // null check!
if (!newType.equals(oldType))
throw wrongTargetType(newTarget, oldType);
if (oldTarget != newTarget)
CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
}
private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
return new WrongMethodTypeException(String.valueOf(target)+target.type()+" should be of type "+type);
}
/** Produce a printed representation that displays information about this call site
* that may be useful to the human reader.
*/
@Override
public String toString() {
return "CallSite"+(target == null ? "" : target.type());
return new WrongMethodTypeException(String.valueOf(target)+" should be of type "+type);
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle equivalent to an invokedynamic instruction
* which has been linked to this call site.
* <p>If this call site is a {@link ConstantCallSite}, this method
* simply returns the call site's target, since that will not change.
* <p>If this call site is a {@linkplain ConstantCallSite constant call site},
* this method simply returns the call site's target, since that will never change.
* <p>Otherwise, this method is equivalent to the following code:
* <p><blockquote><pre>
* MethodHandle getTarget, invoker, result;
@ -271,8 +248,9 @@ public class CallSite
* @return a method handle which always invokes this call site's current target
*/
public final MethodHandle dynamicInvoker() {
if (this instanceof ConstantCallSite)
return getTarget(); // will not change dynamically
if (this instanceof ConstantCallSite) {
return getTarget0(); // will not change dynamically
}
MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, GET_TARGET, this);
MethodHandle invoker = MethodHandles.exactInvoker(this.type());
return MethodHandles.foldArguments(invoker, getTarget);
@ -287,9 +265,34 @@ public class CallSite
}
}
/** Implementation of {@link MethodHandleProvider} which returns {@code this.dynamicInvoker()}. */
public final MethodHandle asMethodHandle() { return dynamicInvoker(); }
/** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
/*package-private*/
static Empty uninitializedCallSite() {
throw new IllegalStateException("uninitialized call site");
}
/** Implementation of {@link MethodHandleProvider}, which returns {@code this.dynamicInvoker().asType(type)}. */
public final MethodHandle asMethodHandle(MethodType type) { return dynamicInvoker().asType(type); }
// unsafe stuff:
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long TARGET_OFFSET;
static {
try {
TARGET_OFFSET = unsafe.objectFieldOffset(CallSite.class.getDeclaredField("target"));
} catch (Exception ex) { throw new Error(ex); }
}
/*package-private*/
void setTargetNormal(MethodHandle newTarget) {
target = newTarget;
//CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
}
/*package-private*/
MethodHandle getTargetVolatile() {
return (MethodHandle) unsafe.getObjectVolatile(this, TARGET_OFFSET);
}
/*package-private*/
void setTargetVolatile(MethodHandle newTarget) {
unsafe.putObjectVolatile(this, TARGET_OFFSET, newTarget);
//CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
}
}

View File

@ -28,44 +28,78 @@ package java.dyn;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.lang.reflect.UndeclaredThrowableException;
/**
* Lazily associate a computed value with (potentially) every class.
* @author John Rose, JSR 292 EG
*/
public abstract class ClassValue<T> {
public class ClassValue<T> {
/**
* Compute the given class's derived value for this {@code ClassValue}.
* <p>
* This method will be invoked within the first thread that accesses
* the value with the {@link #get}.
* the value with the {@link #get get} method.
* <p>
* Normally, this method is invoked at most once per class,
* but it may be invoked again in case of subsequent invocations
* of {@link #remove} followed by {@link #get}.
* but it may be invoked again if there has been a call to
* {@link #remove remove}.
* <p>
* If there is no override from a subclass, this method returns
* the result of applying the {@code ClassValue}'s {@code computeValue}
* method handle, which was supplied at construction time.
*
* @return the computed value for this thread-local
* @return the newly computed value associated with this {@code ClassValue}, for the given class or interface
* @throws UndeclaredThrowableException if the {@code computeValue} method handle invocation throws something other than a {@code RuntimeException} or {@code Error}
* @throws UnsupportedOperationException if the {@code computeValue} method handle is null (subclasses must override)
*/
protected abstract T computeValue(Class<?> type);
protected T computeValue(Class<?> type) {
if (computeValue == null)
return null;
try {
return (T) (Object) computeValue.invokeGeneric(type);
} catch (Throwable ex) {
if (ex instanceof Error) throw (Error) ex;
if (ex instanceof RuntimeException) throw (RuntimeException) ex;
throw new UndeclaredThrowableException(ex);
}
}
private final MethodHandle computeValue;
/**
* Creates a new class value.
* Subclasses which use this constructor must override
* the {@link #computeValue computeValue} method,
* since the default {@code computeValue} method requires a method handle,
* which this constructor does not provide.
*/
protected ClassValue() {
this.computeValue = null;
}
/**
* Creates a new class value, whose {@link #computeValue computeValue} method
* will return the result of {@code computeValue.invokeGeneric(type)}.
* @throws NullPointerException if the method handle parameter is null
*/
public ClassValue(MethodHandle computeValue) {
computeValue.getClass(); // trigger NPE if null
this.computeValue = computeValue;
}
/**
* Returns the value for the given class.
* If no value has yet been computed, it is obtained by
* by an invocation of the {@link #computeValue} method.
* by an invocation of the {@link #computeValue computeValue} method.
* <p>
* The actual installation of the value on the class
* is performed while the class's synchronization lock
* is held. At that point, if racing threads have
* is performed atomically.
* At that point, if racing threads have
* computed values, one is chosen, and returned to
* all the racing threads.
*
* @return the current thread's value of this thread-local
* @return the current value associated with this {@code ClassValue}, for the given class or interface
*/
public T get(Class<?> type) {
ClassValueMap map = getMap(type);
@ -81,9 +115,16 @@ public abstract class ClassValue<T> {
/**
* Removes the associated value for the given class.
* If this value is subsequently {@linkplain #get read} for the same class,
* its value will be reinitialized by invoking its {@link #computeValue} method.
* its value will be reinitialized by invoking its {@link #computeValue computeValue} method.
* This may result in an additional invocation of the
* {@code computeValue} method for the given class.
* {@code computeValue computeValue} method for the given class.
* <p>
* If racing threads perform a combination of {@code get} and {@code remove} calls,
* the calls are serialized.
* A value produced by a call to {@code computeValue} will be discarded, if
* the corresponding {@code get} call was followed by a {@code remove} call
* before the {@code computeValue} could complete.
* In such a case, the {@code get} call will re-invoke {@code computeValue}.
*/
public void remove(Class<?> type) {
ClassValueMap map = getMap(type);
@ -118,6 +159,7 @@ public abstract class ClassValue<T> {
// Warm up the table with a null entry.
map.preInitializeEntry(this);
}
STORE_BARRIER.lazySet(0);
// All stores pending from table expansion are completed.
synchronized (map) {
value = (T) map.initializeEntry(this, value);

View File

@ -27,17 +27,21 @@ package java.dyn;
/**
* A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
* The only way to relink an {@code invokedynamic} instruction bound to a {@code ConstantCallSite} is
* to invalidate the instruction as a whole.
* An {@code invokedynamic} instruction linked to a {@code ConstantCallSite} is permanently
* bound to the call site's target.
* @author John Rose, JSR 292 EG
*/
public class ConstantCallSite extends CallSite {
/** Create a call site with a permanent target. */
/** Create a call site with a permanent target.
* @throws NullPointerException if the proposed target is null
*/
public ConstantCallSite(MethodHandle target) {
super(target);
}
/** Throw an {@link IllegalArgumentException}, because this kind of call site cannot change its target. */
/**
* Throw an {@link UnsupportedOperationException}, because this kind of call site cannot change its target.
*/
@Override public final void setTarget(MethodHandle ignore) {
throw new IllegalArgumentException("ConstantCallSite");
throw new UnsupportedOperationException("ConstantCallSite");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,55 +26,8 @@
package java.dyn;
/**
* {@code InvokeDynamic} is a class with neither methods nor instances,
* which serves only as a syntactic marker in Java source code for
* an {@code invokedynamic} instruction.
* (See <a href="package-summary.html#jvm_mods">the package information</a> for specifics on this instruction.)
* <p>
* The {@code invokedynamic} instruction is incomplete without a target method.
* The target method is a property of the reified {@linkplain CallSite call site object}
* which is linked to each active {@code invokedynamic} instruction.
* The call site object is initially produced by a
* {@linkplain BootstrapMethod bootstrap method}
* associated with the class whose bytecodes include the dynamic call site.
* <p>
* The type {@code InvokeDynamic} has no particular meaning as a
* class or interface supertype, or an object type; it can never be instantiated.
* Logically, it denotes a source of all dynamically typed methods.
* It may be viewed as a pure syntactic marker of static calls.
* It may be imported for ease of use.
* <p>
* Here are some examples:
<blockquote><pre><!-- see indy-demo/src/JavaDocExamples.java -->
&#064;BootstrapMethod(value=Here.class, name="bootstrapDynamic")
static void example() throws Throwable {
Object x; String s; int i;
x = InvokeDynamic.greet("world"); // greet(Ljava/lang/String;)Ljava/lang/Object;
s = (String) InvokeDynamic.hail(x); // hail(Ljava/lang/Object;)Ljava/lang/String;
InvokeDynamic.cogito(); // cogito()V
i = (int) InvokeDynamic.#"op:+"(2, 3); // "op:+"(II)I
}
static MethodHandle bootstrapDynamic(Class caller, String name, MethodType type) { ... }
</pre></blockquote>
* Each of the above calls generates a single invokedynamic instruction
* with the name-and-type descriptors indicated in the comments.
* <p>
* The argument types are taken directly from the actual arguments,
* while the return type corresponds to the target of the assignment.
* (Currently, the return type must be given as a false type parameter.
* This type parameter is an irregular use of the generic type syntax,
* and is likely to change in favor of a convention based on target typing.)
* <p>
* The final example uses a special syntax for uttering non-Java names.
* Any name legal to the JVM may be given between the double quotes.
* <p>
* None of these calls is complete without a bootstrap method,
* which must be declared for the enclosing class or method.
* @author John Rose, JSR 292 EG
* This is a place-holder class. Some HotSpot implementations need to see it.
*/
@MethodHandle.PolymorphicSignature
public final class InvokeDynamic {
final class InvokeDynamic {
private InvokeDynamic() { throw new InternalError(); } // do not instantiate
// no statically defined static methods
}

View File

@ -67,4 +67,16 @@ public class InvokeDynamicBootstrapError extends LinkageError {
public InvokeDynamicBootstrapError(String s, Throwable cause) {
super(s, cause);
}
/**
* Constructs a {@code InvokeDynamicBootstrapError} with the specified
* cause.
*
* @param cause the cause, may be {@code null}.
*/
public InvokeDynamicBootstrapError(Throwable cause) {
// cf. Throwable(Throwable cause) constructor.
super(cause == null ? null : cause.toString());
initCause(cause);
}
}

View File

@ -29,15 +29,16 @@ import java.dyn.MethodHandles.Lookup;
import java.util.WeakHashMap;
import sun.dyn.Access;
import sun.dyn.MethodHandleImpl;
import sun.dyn.util.VerifyAccess;
import sun.reflect.Reflection;
import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege;
import static sun.dyn.MemberName.newIllegalArgumentException;
/**
* This class consists exclusively of static methods that control
* the linkage of {@code invokedynamic} instructions, and specifically
* their reification as {@link CallSite} objects.
* <em>CLASS WILL BE REMOVED FOR PFD:</em>
* Static routines for controlling invokedynamic behavior.
* Replaced by non-static APIs.
* @author John Rose, JSR 292 EG
* @deprecated This class will be removed in the Public Final Draft.
*/
public class Linkage {
private static final Access IMPL_TOKEN = Access.getToken();
@ -45,68 +46,24 @@ public class Linkage {
private Linkage() {} // do not instantiate
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Register a <em>bootstrap method</em> to use when linking dynamic call sites within
* a given caller class.
* <p>
* A bootstrap method must be a method handle with a return type of {@link CallSite}
* and the following arguments:
* <ul>
* <li>the class containing the {@code invokedynamic} instruction, for which the bootstrap method was registered
* <li>the name of the method being invoked (a {@link String})
* <li>the type of the method being invoked (a {@link MethodType})
* </ul>
* The bootstrap method acts as a factory method which accepts the given arguments
* and returns a {@code CallSite} object (possibly of a subclass of {@code CallSite}).
* <p>
* The registration must take place exactly once, either before the class has begun
* being initialized, or from within the class's static initializer.
* Registration will fail with an exception if any of the following conditions hold:
* <ul>
* <li>The immediate caller of this method is in a different package than the given caller class,
* and there is a security manager, and its {@code checkPermission} call throws
* when passed {@link LinkagePermission}("registerBootstrapMethod",callerClass).
* <li>The given caller class already has a bootstrap method registered.
* <li>The given caller class is already fully initialized.
* <li>The given caller class is in the process of initialization, in another thread.
* </ul>
* Because of these rules, a class may install its own bootstrap method in
* a static initializer.
* @param callerClass a class that may have {@code invokedynamic} sites
* @param bootstrapMethod the method to use to bootstrap all such sites
* @exception IllegalArgumentException if the class argument is null or
* a primitive class, or if the bootstrap method is the wrong type
* @exception IllegalStateException if the class already has a bootstrap
* method, or if the its static initializer has already run
* or is already running in another thread
* @exception SecurityException if there is a security manager installed,
* and a {@link LinkagePermission} check fails for "registerBootstrapMethod"
* @deprecated Use @{@link BootstrapMethod} annotations instead
* @deprecated Use @{@link BootstrapMethod} annotations instead.
*/
public static
void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) {
Class callc = Reflection.getCallerClass(2);
checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod");
checkBSM(bootstrapMethod);
if (callc != null && !VerifyAccess.isSamePackage(callerClass, callc))
throw new IllegalArgumentException("cannot set bootstrap method on "+callerClass);
MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
}
static private void checkBSM(MethodHandle mh) {
if (mh == null) throw newIllegalArgumentException("null bootstrap method");
if (mh.type() == BOOTSTRAP_METHOD_TYPE) return;
throw new WrongMethodTypeException(mh.toString());
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Simplified version of {@code registerBootstrapMethod} for self-registration,
* to be called from a static initializer.
* Finds a static method of the required type in the
* given runtime class, and installs it on the caller class.
* @throws NoSuchMethodException if there is no such method
* @throws IllegalStateException if the caller class's static initializer
* has already run, or is already running in another thread
* @deprecated Use @{@link BootstrapMethod} annotations instead
* @deprecated Use @{@link BootstrapMethod} annotations instead.
*/
public static
void registerBootstrapMethod(Class<?> runtime, String name) {
@ -115,15 +72,9 @@ public class Linkage {
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Simplified version of {@code registerBootstrapMethod} for self-registration,
* to be called from a static initializer.
* Finds a static method of the required type in the
* caller class itself, and installs it on the caller class.
* @throws IllegalArgumentException if there is no such method
* @throws IllegalStateException if the caller class's static initializer
* has already run, or is already running in another thread
* @deprecated Use @{@link BootstrapMethod} annotations instead
* @deprecated Use @{@link BootstrapMethod} annotations instead.
*/
public static
void registerBootstrapMethod(String name) {
@ -140,82 +91,33 @@ public class Linkage {
} catch (NoAccessException ex) {
throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex);
}
checkBSM(bootstrapMethod);
MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Report the bootstrap method registered for a given caller class.
* Returns null if the class has never yet registered a bootstrap method.
* Only callers privileged to set the bootstrap method may inquire
* about it, because a bootstrap method is potentially a back-door entry
* point into its class.
* @exception IllegalArgumentException if the argument is null or
* a primitive class
* @exception SecurityException if there is a security manager installed,
* and the immediate caller of this method is not in the same
* package as the caller class
* and a {@link LinkagePermission} check fails for "getBootstrapMethod"
* @deprecated
*/
public static
MethodHandle getBootstrapMethod(Class callerClass) {
Class callc = Reflection.getCallerClass(2);
checkBootstrapPrivilege(callc, callerClass, "getBootstrapMethod");
return MethodHandleImpl.getBootstrap(IMPL_TOKEN, callerClass);
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* The type of any bootstrap method is a three-argument method
* {@code (Class, String, MethodType)} returning a {@code CallSite}.
*/
public static final MethodType BOOTSTRAP_METHOD_TYPE
private static final MethodType BOOTSTRAP_METHOD_TYPE
= MethodType.methodType(CallSite.class,
Class.class, String.class, MethodType.class);
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Invalidate all <code>invokedynamic</code> call sites everywhere.
* <p>
* When this method returns, every <code>invokedynamic</code> instruction
* will invoke its bootstrap method on next call.
* <p>
* It is unspecified whether call sites already known to the Java
* code will continue to be associated with <code>invokedynamic</code>
* instructions. If any call site is still so associated, its
* {@link CallSite#getTarget()} method is guaranteed to return null
* the invalidation operation completes.
* <p>
* Invalidation operations are likely to be slow. Use them sparingly.
* @deprecated Use {@linkplain CallSite#setTarget call site target setting}
* and {@link VolatileCallSite#invalidateAll call site invalidation} instead.
*/
public static
Object invalidateAll() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(new LinkagePermission("invalidateAll"));
}
throw new UnsupportedOperationException("NYI");
throw new UnsupportedOperationException();
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Invalidate all {@code invokedynamic} call sites in the bytecodes
* of any methods of the given class.
* <p>
* When this method returns, every matching <code>invokedynamic</code>
* instruction will invoke its bootstrap method on next call.
* <p>
* For additional semantics of call site invalidation,
* see {@link #invalidateAll()}.
* @deprecated Use {@linkplain CallSite#setTarget call site target setting}
* and {@link VolatileCallSite#invalidateAll call site invalidation} instead.
*/
public static
Object invalidateCallerClass(Class<?> callerClass) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(new LinkagePermission("invalidateAll", callerClass));
}
throw new UnsupportedOperationException("NYI");
throw new UnsupportedOperationException();
}
}

View File

@ -1,104 +0,0 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.dyn;
import java.security.*;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* This class is for managing runtime permission checking for
* operations performed by methods in the {@link Linkage} class.
* Like a {@link RuntimePermission}, on which it is modeled,
* a {@code LinkagePermission} contains a target name but
* no actions list; you either have the named permission
* or you don't.
* <p>
* The following table lists all the possible {@code LinkagePermission} target names,
* and for each provides a description of what the permission allows
* and a discussion of the risks of granting code the permission.
* <p>
*
* <table border=1 cellpadding=5 summary="permission target name,
* what the target allows,and associated risks">
* <tr>
* <th>Permission Target Name</th>
* <th>What the Permission Allows</th>
* <th>Risks of Allowing this Permission</th>
* </tr>
*
* <tr>
* <td>invalidateAll</td>
* <td>Force the relinking of invokedynamic call sites everywhere.</td>
* <td>This could allow an attacker to slow down the system,
* or perhaps expose timing bugs in a dynamic language implementations,
* by forcing redundant relinking operations.</td>
* </tr>
*
*
* <tr>
* <td>invalidateCallerClass.{class name}</td>
* <td>Force the relinking of invokedynamic call sites in the given class.</td>
* <td>See {@code invalidateAll}.</td>
* </tr>
* </table>
* <p>ISSUE: Is this still needed?
*
* @see java.lang.RuntimePermission
* @see java.lang.SecurityManager
*
* @author John Rose, JSR 292 EG
*/
public final class LinkagePermission extends BasicPermission {
private static final long serialVersionUID = 292L;
/**
* Create a new LinkagePermission with the given name.
* The name is the symbolic name of the LinkagePermission, such as
* "invalidateCallerClass.*", etc. An asterisk
* may appear at the end of the name, following a ".", or by itself, to
* signify a wildcard match.
*
* @param name the name of the LinkagePermission
*/
public LinkagePermission(String name) {
super(name);
}
/**
* Create a new LinkagePermission with the given name on the given class.
* Equivalent to {@code LinkagePermission(name+"."+clazz.getName())}.
*
* @param name the name of the LinkagePermission
* @param clazz the class affected by the permission
*/
public LinkagePermission(String name, Class<?> clazz) {
super(name + "." + clazz.getName());
}
}

View File

@ -37,20 +37,29 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* A method handle is a typed, directly executable reference to a method,
* constructor, field, or similar low-level operation, with optional
* transformations of arguments or return values.
* (These transformations include conversion, insertion, deletion,
* substitution. See the methods of this class and of {@link MethodHandles}.)
* These transformations are quite general, and include such patterns as
* {@linkplain #asType conversion},
* {@linkplain #bindTo insertion},
* {@linkplain java.dyn.MethodHandles#dropArguments deletion},
* and {@linkplain java.dyn.MethodHandles#filterArguments substitution}.
* <p>
* <em>Note: The super-class of MethodHandle is Object.
* Any other super-class visible in the Reference Implementation
* will be removed before the Proposed Final Draft.
* Also, the final version will not include any public or
* protected constructors.</em>
* <p>
* Method handles are strongly typed according to signature.
* They are not distinguished by method name or enclosing class.
* A method handle must be invoked under a signature which matches
* the method handle's own {@link MethodType method type}.
* the method handle's own {@linkplain MethodType method type}.
* <p>
* Every method handle confesses its type via the {@code type} accessor.
* Every method handle reports its type via the {@link #type type} accessor.
* The structure of this type is a series of classes, one of which is
* the return type of the method (or {@code void.class} if none).
* <p>
* Every method handle appears as an object containing a method named
* {@code invoke}, whose signature exactly matches
* {@link #invokeExact invokeExact}, whose signature exactly matches
* the method handle's type.
* A Java method call expression, which compiles to an
* {@code invokevirtual} instruction,
@ -61,15 +70,29 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* (The type is specified in the {@code invokevirtual} instruction,
* via a {@code CONSTANT_NameAndType} constant pool entry.)
* The call looks within the receiver object for a method
* named {@code invoke} of the intended method type.
* named {@code invokeExact} of the intended method type.
* The call fails with a {@link WrongMethodTypeException}
* if the method does not exist, even if there is an {@code invoke}
* if the method does not exist, even if there is an {@code invokeExact}
* method of a closely similar signature.
* As with other kinds
* of methods in the JVM, signature matching during method linkage
* is exact, and does not allow for language-level implicit conversions
* such as {@code String} to {@code Object} or {@code short} to {@code int}.
* <p>
* Each individual method handle also contains a method named
* {@link #invokeGeneric invokeGeneric}, whose type is the same
* as {@code invokeExact}, and is therefore also reported by
* the {@link #type type} accessor.
* A call to {@code invokeGeneric} works the same as a call to
* {@code invokeExact}, if the signature specified by the caller
* exactly matches the method handle's own type.
* If there is a type mismatch, {@code invokeGeneric} attempts
* to adjust the type of the target method handle
* (as if by a call to {@link #asType asType})
* to obtain an exactly invokable target.
* This allows a more powerful negotiation of method type
* between caller and callee.
* <p>
* A method handle is an unrestricted capability to call a method.
* A method handle can be formed on a non-public method by a class
* that has access to that method; the resulting handle can be used
@ -77,31 +100,47 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* checking is performed when the method handle is created, not
* (as in reflection) every time it is called. Handles to non-public
* methods, or in non-public classes, should generally be kept secret.
* They should not be passed to untrusted code.
* They should not be passed to untrusted code unless their use from
* the untrusted code would be harmless.
* <p>
* Bytecode in an extended JVM can directly call a method handle's
* {@code invoke} from an {@code invokevirtual} instruction.
* Bytecode in the JVM can directly call a method handle's
* {@code invokeExact} method from an {@code invokevirtual} instruction.
* The receiver class type must be {@code MethodHandle} and the method name
* must be {@code invoke}. The signature of the invocation
* must be {@code invokeExact}. The signature of the invocation
* (after resolving symbolic type names) must exactly match the method type
* of the target method.
* Similarly, bytecode can directly call a method handle's {@code invokeGeneric}
* method. The signature of the invocation (after resolving symbolic type names)
* must either exactly match the method type or be a valid argument to
* the target's {@link #asType asType} method.
* <p>
* Every {@code invoke} method always throws {@link Exception},
* Every {@code invokeExact} and {@code invokeGeneric} method always
* throws {@link java.lang.Throwable Throwable},
* which is to say that there is no static restriction on what a method handle
* can throw. Since the JVM does not distinguish between checked
* and unchecked exceptions (other than by their class, of course),
* there is no particular effect on bytecode shape from ascribing
* checked exceptions to method handle invocations. But in Java source
* code, methods which perform method handle calls must either explicitly
* throw {@code Exception}, or else must catch all checked exceptions locally.
* throw {@code java.lang.Throwable Throwable}, or else must catch all
* throwables locally, rethrowing only those which are legal in the context,
* and wrapping ones which are illegal.
* <p>
* Bytecode in an extended JVM can directly obtain a method handle
* Bytecode in the JVM can directly obtain a method handle
* for any accessible method from a {@code ldc} instruction
* which refers to a {@code CONSTANT_Methodref} or
* {@code CONSTANT_InterfaceMethodref} constant pool entry.
* which refers to a {@code CONSTANT_MethodHandle} constant pool entry.
* (Each such entry refers directly to a {@code CONSTANT_Methodref},
* {@code CONSTANT_InterfaceMethodref}, or {@code CONSTANT_Fieldref}
* constant pool entry.
* For more details, see the <a href="package-summary.html#mhcon">package summary</a>.)
* <p>
* All JVMs can also use a reflective API called {@code MethodHandles}
* Java code can also use a reflective API called
* {@link java.dyn.MethodHandles.Lookup MethodHandles.Lookup}
* for creating and calling method handles.
* For example, a static method handle can be obtained
* from {@link java.dyn.MethodHandles.Lookup#findStatic Lookup.findStatic}.
* There are also bridge methods from Core Reflection API objects,
* such as {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.ureflect}.
* <p>
* A method reference may refer either to a static or non-static method.
* In the non-static case, the method handle type includes an explicit
@ -128,10 +167,10 @@ MethodHandles.Lookup lookup = MethodHandles.lookup();
mt = MethodType.methodType(String.class, char.class, char.class);
mh = lookup.findVirtual(String.class, "replace", mt);
// (Ljava/lang/String;CC)Ljava/lang/String;
s = mh.&lt;String&gt;invokeExact("daddy",'d','n');
s = (String) mh.invokeExact("daddy",'d','n');
assert(s.equals("nanny"));
// weakly typed invocation (using MHs.invoke)
s = (String) mh.invokeVarargs("sappy", 'p', 'v');
s = (String) mh.invokeWithArguments("sappy", 'p', 'v');
assert(s.equals("savvy"));
// mt is {Object[] =&gt; List}
mt = MethodType.methodType(java.util.List.class, Object[].class);
@ -147,14 +186,22 @@ assert(x.equals(java.util.Arrays.asList(1,2,3)));
mt = MethodType.methodType(int.class);
mh = lookup.findVirtual(java.util.List.class, "size", mt);
// (Ljava/util/List;)I
i = mh.&lt;int&gt;invokeExact(java.util.Arrays.asList(1,2,3));
i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
assert(i == 3);
mt = MethodType.methodType(void.class, String.class);
mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt);
mh.invokeExact(System.out, "Hello, world.");
// (Ljava/io/PrintStream;Ljava/lang/String;)V
* </pre></blockquote>
* Each of the above calls generates a single invokevirtual instruction
* with the name {@code invoke} and the type descriptors indicated in the comments.
* The argument types are taken directly from the actual arguments,
* while the return type is taken from the type parameter.
* (This type parameter may be a primitive, and it defaults to {@code Object}.)
* while the return type is taken from the cast immediately applied to the call.
* This cast may be to a primitive.
* If it is missing, the type defaults to {@code Object} if the call
* occurs in a context which uses the return value.
* If the call occurs as a statement, a cast is impossible,
* and there is no return type; the call is {@code void}.
* <p>
* <em>A note on generic typing:</em> Method handles do not represent
* their function types in terms of Java parameterized (generic) types,
@ -162,7 +209,7 @@ assert(i == 3);
* Java types.
* <ol>
* <li>Method types range over all possible arities,
* from no arguments to an arbitrary number of arguments.
* from no arguments to up to 255 of arguments (a limit imposed by the JVM).
* Generics are not variadic, and so cannot represent this.</li>
* <li>Method types can specify arguments of primitive types,
* which Java generic types cannot range over.</li>
@ -180,6 +227,19 @@ assert(i == 3);
* fields, methods, and constructors can be represented directly
* in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
* Loading such a constant causes the component classes of its type to be loaded as necessary.
* <p>
* Method handles cannot be subclassed by the user.
* Implementations may (or may not) create internal subclasses of {@code MethodHandle}
* which may be visible via the {@code java.lang.Object#getClass Object.getClass}
* operation. The programmer should not draw conclusions about a method handle
* from its specific class, as the method handle class hierarchy (if any)
* may change from time to time or across implementations from different vendors.
* <p>
* With respect to the Java Memory Model, any method handle will behave
* as if all of its fields are final variables. This means that any method
* handle made visible to the application will always be fully formed.
* This is true even if the method handle is published through a shared
* variables in a data race.
*
* @see MethodType
* @see MethodHandles
@ -189,7 +249,6 @@ public abstract class MethodHandle
// 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 MethodHandleImpl
implements MethodHandleProvider
{
private static Access IMPL_TOKEN = Access.getToken();
@ -208,7 +267,7 @@ public abstract class MethodHandle
/**
* Report the type of this method handle.
* Every invocation of this method handle must exactly match this type.
* Every invocation of this method handle via {@code invokeExact} must exactly match this type.
* @return the method handle type
*/
public final MethodType type() {
@ -216,12 +275,16 @@ public abstract class MethodHandle
}
/**
* The constructor for MethodHandle may only be called by privileged code.
* Subclasses may be in other packages, but must possess
* a token which they obtained from MH with a security check.
* @param token non-null object which proves access permission
* @param type type (permanently assigned) of the new method handle
* <em>CONSTRUCTOR WILL BE REMOVED FOR PFD:</em>
* Temporary constructor in early versions of the Reference Implementation.
* Method handle inheritance (if any) will be contained completely within
* the {@code java.dyn} package.
*/
// The constructor for MethodHandle may only be called by privileged code.
// Subclasses may be in other packages, but must possess
// a token which they obtained from MH with a security check.
// @param token non-null object which proves access permission
// @param type type (permanently assigned) of the new method handle
protected MethodHandle(Access token, MethodType type) {
super(token);
Access.check(token);
@ -243,92 +306,116 @@ public abstract class MethodHandle
});
}
/** The string of a direct method handle is the simple name of its target method.
* The string of an adapter or bound method handle is the string of its
* target method handle.
* The string of a Java method handle is the string of its entry point method,
* unless the Java method handle overrides the toString method.
/**
* Returns a string representation of the method handle,
* starting with the string {@code "MethodHandle"} and
* ending with the string representation of the method handle's type.
* In other words, this method returns a string equal to the value of:
* <blockquote><pre>
* "MethodHandle" + type().toString()
* </pre></blockquote>
* <p>
* Note: Future releases of this API may add further information
* to the string representation.
* Therefore, the present syntax should not be parsed by applications.
*
* @return a string representation of the method handle
*/
@Override
public String toString() {
return MethodHandleImpl.getNameString(IMPL_TOKEN, this);
}
//// This is the "Method Handle Kernel API" discussed at the JVM Language Summit, 9/2009.
//// Implementations here currently delegate to statics in MethodHandles. Some of those statics
//// will be deprecated. Others will be kept as "algorithms" to supply degrees of freedom
//// not present in the Kernel API.
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* 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 {@link #type type}.
* No conversions are allowed on arguments or return values.
* @throws WrongMethodTypeException if the target's type is not identical with the caller's type signature
* @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
*/
public final native @PolymorphicSignature <R,A> R invokeExact(A... args) throws Throwable;
// FIXME: remove this transitional form
/** @deprecated transitional form defined in EDR but removed in PFD */
public final native @PolymorphicSignature <R,A> R invoke(A... args) throws Throwable;
public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable;
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* 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}.
* and optionally performing conversions for arguments and return types.
* <p>
* If the call site signature exactly matches this method handle's {@code type},
* the call proceeds as if by {@link #invokeExact}.
* If the call site signature exactly matches this method handle's {@link #type type},
* the call proceeds as if by {@link #invokeExact invokeExact}.
* <p>
* Otherwise, the call proceeds as if this method handle were first
* adjusted by calling {@link #asType} to adjust this method handle
* adjusted by calling {@link #asType asType} to adjust this method handle
* to the required type, and then the call proceeds as if by
* {@link #invokeExact} on the adjusted method handle.
* {@link #invokeExact invokeExact} on the adjusted method handle.
* <p>
* There is no guarantee that the {@code asType} call is actually made.
* If the JVM can predict the results of making the call, it may perform
* adaptations directly on the caller's arguments,
* and call the target method handle according to its own exact type.
* <p>
* If the method handle is equipped with a
* {@linkplain #withTypeHandler type handler}, the handler must produce
* an entry point of the call site's exact type.
* Otherwise, the signature at the call site of {@code invokeGeneric} must
* be a valid argument to the standard {@code asType} method.
* In particular, the caller must specify the same argument arity
* as the callee's type.
* @throws WrongMethodTypeException if the target's type cannot be adjusted to the caller's type signature
* @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
*/
public final native @PolymorphicSignature <R,A> R invokeGeneric(A... args) throws Throwable;
// ?? public final native @PolymorphicSignature <R,A,V> R invokeVarargs(A args, V[] varargs) throws Throwable;
public final native @PolymorphicSignature Object invokeGeneric(Object... args) throws Throwable;
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Perform a varargs invocation, passing the arguments in the given array
* to the method handle, as if via {@link #invokeGeneric} from a call site
* to the method handle, as if via {@link #invokeGeneric invokeGeneric} from a call site
* which mentions only the type {@code Object}, and whose arity is the length
* of the argument array.
* <p>
* The length of the arguments array must equal the parameter count
* of the target's type.
* The arguments array is spread into separate arguments.
* Specifically, execution proceeds as if by the following steps,
* although the methods are not guaranteed to be called if the JVM
* can predict their effects.
* <ul>
* <li>Determine the length of the argument array as {@code N}.
* For a null reference, {@code N=0}. </li>
* <li>Determine the generic type {@code TN} of {@code N} arguments as
* as {@code TN=MethodType.genericMethodType(N)}.</li>
* <li>Force the original target method handle {@code MH0} to the
* required type, as {@code MH1 = MH0.asType(TN)}. </li>
* <li>Spread the array into {@code N} separate arguments {@code A0, ...}. </li>
* <li>Invoke the type-adjusted method handle on the unpacked arguments:
* MH1.invokeExact(A0, ...). </li>
* <li>Take the return value as an {@code Object} reference. </li>
* </ul>
* <p>
* In order to match the type of the target, the following argument
* Because of the action of the {@code asType} step, the following argument
* conversions are applied as necessary:
* <ul>
* <li>reference casting
* <li>unboxing
* <li>widening primitive conversions
* </ul>
* The following conversions are not applied:
* <ul>
* <li>primitive conversions (e.g., {@code byte} to {@code int}
* <li>varargs conversions other than the initial spread
* <li>any application-specific conversions (e.g., string to number)
* </ul>
* <p>
* The result returned by the call is boxed if it is a primitive,
* or forced to null if the return type is void.
* <p>
* This call is equivalent to the following code:
* <p><blockquote><pre>
* MethodHandle invoker = MethodHandles.genericInvoker(this.type(), 0, true);
* Object result = invoker.invokeExact(this, arguments);
* MethodHandle invoker = MethodHandles.varargsInvoker(this.type(), 0);
* Object result = invoker.invokeExact(this, arguments);
* </pre></blockquote>
* @param arguments the arguments to pass to the target
* @return the result returned by the target
* @see MethodHandles#genericInvoker
* @throws WrongMethodTypeException if the target's type cannot be adjusted to take the arguments
* @throws Throwable anything thrown by the target method invocation
* @see MethodHandles#varargsInvoker
*/
public final Object invokeVarargs(Object... arguments) throws Throwable {
public final Object invokeWithArguments(Object... arguments) throws Throwable {
int argc = arguments == null ? 0 : arguments.length;
MethodType type = type();
if (type.parameterCount() != argc) {
// simulate invokeGeneric
return asType(MethodType.genericMethodType(argc)).invokeWithArguments(arguments);
}
if (argc <= 10) {
MethodHandle invoker = MethodHandles.invokers(type).genericInvoker();
switch (argc) {
@ -372,99 +459,70 @@ public abstract class MethodHandle
MethodHandle invoker = MethodHandles.invokers(type).varargsInvoker(0);
return invoker.invokeExact(this, arguments);
}
/** Equivalent to {@code invokeVarargs(arguments.toArray())}. */
/** Equivalent to {@code invokeWithArguments(arguments.toArray())}. */
public final Object invokeWithArguments(java.util.List<?> arguments) throws Throwable {
return invokeWithArguments(arguments.toArray());
}
@Deprecated
public final Object invokeVarargs(Object... arguments) throws Throwable {
return invokeWithArguments(arguments);
}
@Deprecated
public final Object invokeVarargs(java.util.List<?> arguments) throws Throwable {
return invokeVarargs(arguments.toArray());
return invokeWithArguments(arguments.toArray());
}
/* --- this is intentionally NOT a javadoc yet ---
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce an adapter method handle which adapts the type of the
* current method handle to a new type by pairwise argument conversion.
* The original type and new type must have the same number of arguments.
* The resulting method handle is guaranteed to confess a type
* which is equal to the desired new type.
* <p>
* If the original type and new type are equal, returns {@code this}.
* <p>
* The following conversions are applied as needed both to
* arguments and return types. Let T0 and T1 be the differing
* new and old parameter types (or old and new return types)
* for corresponding values passed by the new and old method types.
* Given those types T0, T1, one of the following conversions is applied
* if possible:
* <ul>
* <li>If T0 and T1 are references, and T1 is not an interface type,
* then a cast to T1 is applied.
* (The types do not need to be related in any particular way.)
* <li>If T0 and T1 are references, and T1 is an interface type,
* then the value of type T0 is passed as a T1 without a cast.
* (This treatment of interfaces follows the usage of the bytecode verifier.)
* <li>If T0 and T1 are primitives, then a Java casting
* conversion (JLS 5.5) is applied, if one exists.
* <li>If T0 and T1 are primitives and one is boolean,
* the boolean is treated as a one-bit unsigned integer.
* (This treatment follows the usage of the bytecode verifier.)
* A conversion from another primitive type behaves as if
* it first converts to byte, and then masks all but the low bit.
* <li>If T0 is a primitive and T1 a reference, a boxing
* conversion is applied if one exists, possibly followed by
* an reference conversion to a superclass.
* T1 must be a wrapper class or a supertype of one.
* If T1 is a wrapper class, T0 is converted if necessary
* to T1's primitive type by one of the preceding conversions.
* Otherwise, T0 is boxed, and its wrapper converted to T1.
* <li>If T0 is a reference and T1 a primitive, an unboxing
* conversion is applied if one exists, possibly preceded by
* a reference conversion to a wrapper class.
* T0 must be a wrapper class or a supertype of one.
* If T0 is a wrapper class, its primitive value is converted
* if necessary to T1 by one of the preceding conversions.
* Otherwise, T0 is converted directly to the wrapper type for T1,
* which is then unboxed.
* <li>If the return type T1 is void, any returned value is discarded
* <li>If the return type T0 is void and T1 a reference, a null value is introduced.
* <li>If the return type T0 is void and T1 a primitive, a zero value is introduced.
* </ul>
* <p>
*/
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce an adapter method handle which adapts the type of the
* current method handle to a new type by pairwise argument conversion.
* The original type and new type must have the same number of arguments.
* The resulting method handle is guaranteed to confess a type
* current method handle to a new type
* The resulting method handle is guaranteed to report a type
* which is equal to the desired new type.
* <p>
* If the original type and new type are equal, returns {@code this}.
* <p>
* This method is equivalent to {@link MethodHandles#convertArguments}.
* This method provides the crucial behavioral difference between
* {@link #invokeExact invokeExact} and {@link #invokeGeneric invokeGeneric}. The two methods
* perform the same steps when the caller's type descriptor is identical
* with the callee's, but when the types differ, {@link #invokeGeneric invokeGeneric}
* also calls {@code asType} (or some internal equivalent) in order
* to match up the caller's and callee's types.
* <p>
* This method is equivalent to {@link MethodHandles#convertArguments convertArguments},
* except for method handles produced by {@link #withTypeHandler withTypeHandler},
* in which case the specified type handler is used for calls to {@code asType}.
* <p>
* Note that the default behavior of {@code asType} only performs
* pairwise argument conversion and return value conversion.
* Because of this, unless the method handle has a type handler,
* the original type and new type must have the same number of arguments.
*
* @param newType the expected type of the new method handle
* @return a method handle which delegates to {@code this} after performing
* any necessary argument conversions, and arranges for any
* necessary return value conversions
* @throws IllegalArgumentException if the conversion cannot be made
* @throws WrongMethodTypeException if the conversion cannot be made
* @see MethodHandles#convertArguments
*/
public final MethodHandle asType(MethodType newType) {
public MethodHandle asType(MethodType newType) {
return MethodHandles.convertArguments(this, newType);
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle which adapts, as its <i>target</i>,
* the current method handle. The type of the adapter will be
* the same as the type of the target, except that all but the first
* {@code keepPosArgs} parameters of the target's type are replaced
* by a single array parameter of type {@code Object[]}.
* Thus, if {@code keepPosArgs} is zero, the adapter will take all
* arguments in a single object array.
* the same as the type of the target, except that the final
* {@code arrayLength} parameters of the target's type are replaced
* by a single array parameter of type {@code arrayType}.
* <p>
* If the array element type differs from any of the corresponding
* argument types on original target,
* the original target is adapted to take the array elements directly,
* as if by a call to {@link #asType asType}.
* <p>
* When called, the adapter replaces a trailing array argument
* by the array's elements, each as its own argument to the target.
* (The order of the arguments is preserved.)
* They are converted pairwise by casting and/or unboxing
* (as if by {@link MethodHandles#convertArguments})
* to the types of the trailing parameters of the target.
* Finally the target is called.
* What the target eventually returns is returned unchanged by the adapter.
@ -473,54 +531,67 @@ public abstract class MethodHandle
* contains exactly enough elements to provide a correct argument count
* to the target method handle.
* (The array may also be null when zero elements are required.)
* @param keepPosArgs the number of leading positional arguments to preserve
* @return a new method handle which spreads its final argument,
* @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
* @param arrayLength the number of arguments to spread from an incoming array argument
* @return a new method handle which spreads its final array argument,
* before calling the original method handle
* @throws IllegalArgumentException if {@code arrayType} is not an array type
* @throws IllegalArgumentException if target does not have at least
* {@code keepPosArgs} parameter types
* {@code arrayLength} parameter types
* @throws WrongMethodTypeException if the implied {@code asType} call fails
*/
public final MethodHandle asSpreader(int keepPosArgs) {
public final MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
Class<?> arrayElement = arrayType.getComponentType();
if (arrayElement == null) throw newIllegalArgumentException("not an array type");
MethodType oldType = type();
int nargs = oldType.parameterCount();
if (nargs < arrayLength) throw newIllegalArgumentException("bad spread array length");
int keepPosArgs = nargs - arrayLength;
MethodType newType = oldType.dropParameterTypes(keepPosArgs, nargs);
newType = newType.insertParameterTypes(keepPosArgs, Object[].class);
newType = newType.insertParameterTypes(keepPosArgs, arrayType);
return MethodHandles.spreadArguments(this, newType);
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle which adapts, as its <i>target</i>,
* the current method handle. The type of the adapter will be
* the same as the type of the target, except that a single trailing
* array parameter of type {@code Object[]} is replaced by
* {@code spreadArrayArgs} parameters of type {@code Object}.
* parameter (usually of type {@code arrayType}) is replaced by
* {@code arrayLength} parameters whose type is element type of {@code arrayType}.
* <p>
* When called, the adapter replaces its trailing {@code spreadArrayArgs}
* arguments by a single new {@code Object} array, whose elements
* If the array type differs from the final argument type on original target,
* the original target is adapted to take the array type directly,
* as if by a call to {@link #asType asType}.
* <p>
* When called, the adapter replaces its trailing {@code arrayLength}
* arguments by a single new array of type {@code arrayType}, whose elements
* comprise (in order) the replaced arguments.
* Finally the target is called.
* What the target eventually returns is returned unchanged by the adapter.
* <p>
* (The array may also be a shared constant when {@code spreadArrayArgs} is zero.)
* @param spreadArrayArgs the number of arguments to spread from the trailing array
* (The array may also be a shared constant when {@code arrayLength} is zero.)
* @param arrayType usually {@code Object[]}, the type of the array argument which will collect the arguments
* @param arrayLength the number of arguments to collect into a new array argument
* @return a new method handle which collects some trailing argument
* into an array, before calling the original method handle
* @throws IllegalArgumentException if the last argument of the target
* is not {@code Object[]}
* @throws IllegalArgumentException if {@code spreadArrayArgs} is not
* @throws IllegalArgumentException if {@code arrayType} is not an array type
or {@code arrayType} is not assignable to this method handle's trailing parameter type
* @throws IllegalArgumentException if {@code arrayLength} is not
* a legal array size
* @deprecated Provisional and unstable; use {@link MethodHandles#collectArguments}.
* @throws WrongMethodTypeException if the implied {@code asType} call fails
*/
public final MethodHandle asCollector(int spreadArrayArgs) {
public final MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
Class<?> arrayElement = arrayType.getComponentType();
if (arrayElement == null) throw newIllegalArgumentException("not an array type");
MethodType oldType = type();
int nargs = oldType.parameterCount();
MethodType newType = oldType.dropParameterTypes(nargs-1, nargs);
newType = newType.insertParameterTypes(nargs-1, MethodType.genericMethodType(spreadArrayArgs).parameterArray());
newType = newType.insertParameterTypes(nargs-1,
java.util.Collections.<Class<?>>nCopies(arrayLength, arrayElement));
return MethodHandles.collectArguments(this, newType);
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle which binds the given argument
* to the current method handle as <i>target</i>.
* The type of the bound handle will be
@ -541,15 +612,81 @@ public abstract class MethodHandle
* leading parameter type that is a reference type
* @throws ClassCastException if {@code x} cannot be converted
* to the leading parameter type of the target
* @deprecated Provisional and unstable; use {@link MethodHandles#insertArguments}.
* @see MethodHandles#insertArguments
*/
public final MethodHandle bindTo(Object x) {
return MethodHandles.insertArguments(this, 0, x);
}
/** Implementation of {@link MethodHandleProvider}, which returns {@code this}. */
public final MethodHandle asMethodHandle() { return this; }
/** Implementation of {@link MethodHandleProvider}, which returns {@code this.asType(type)}. */
public final MethodHandle asMethodHandle(MethodType type) { return this.asType(type); }
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Create a new method handle with the same type as this one,
* but whose {@code asType} method invokes the given
* {@code typeHandler} on this method handle,
* instead of the standard {@code MethodHandles.convertArguments}.
* <p>
* The new method handle will have the same behavior as the
* old one when invoked by {@code invokeExact}.
* For {@code invokeGeneric} calls which exactly match
* the method type, the two method handles will also
* have the same behavior.
* For other {@code invokeGeneric} calls, the {@code typeHandler}
* will control the behavior of the new method handle.
* <p>
* Thus, a method handle with an {@code asType} handler can
* be configured to accept more than one arity of {@code invokeGeneric}
* call, and potentially every possible arity.
* It can also be configured to supply default values for
* optional arguments, when the caller does not specify them.
* <p>
* The given method handle must take two arguments and return
* one result. The result it returns must be a method handle
* of exactly the requested type. If the result returned by
* the target is null, a {@link NullPointerException} is thrown,
* else if the type of the target does not exactly match
* the requested type, a {@link WrongMethodTypeException} is thrown.
* <p>
* A method handle's type handler is not guaranteed to be called every
* time its {@code asType} or {@code invokeGeneric} method is called.
* If the implementation is faced is able to prove that an equivalent
* type handler call has already occurred (on the same two arguments),
* it may substitute the result of that previous invocation, without
* making a new invocation. Thus, type handlers should not (in general)
* perform significant side effects.
* <p>
* Therefore, the type handler is invoked as if by this code:
* <blockquote><pre>
* MethodHandle target = this; // original method handle
* MethodHandle adapter = ...; // adapted method handle
* MethodType requestedType = ...; // argument to asType()
* if (type().equals(requestedType))
* return adapter;
* MethodHandle result = (MethodHandle)
* typeHandler.invokeGeneric(target, requestedType);
* if (!result.type().equals(requestedType))
* throw new WrongMethodTypeException();
* return result;
* </pre></blockquote>
* <p>
* For example, here is a list-making variable-arity method handle:
* <blockquote><pre>
MethodHandle makeEmptyList = MethodHandles.constant(List.class, Arrays.asList());
MethodHandle asList = lookup()
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
static MethodHandle collectingTypeHandler(MethodHandle base, MethodType newType) {
return asList.asCollector(Object[].class, newType.parameterCount()).asType(newType);
}
MethodHandle collectingTypeHandler = lookup()
.findStatic(lookup().lookupClass(), "collectingTypeHandler",
methodType(MethodHandle.class, MethodHandle.class, MethodType.class));
MethodHandle makeAnyList = makeEmptyList.withTypeHandler(collectingTypeHandler);
assertEquals("[]", makeAnyList.invokeGeneric().toString());
assertEquals("[1]", makeAnyList.invokeGeneric(1).toString());
assertEquals("[two, too]", makeAnyList.invokeGeneric("two", "too").toString());
* <pre><blockquote>
*/
public MethodHandle withTypeHandler(MethodHandle typeHandler) {
return MethodHandles.withTypeHandler(this, typeHandler);
}
}

View File

@ -1,80 +0,0 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.dyn;
/**
* An interface for an object to provide a target {@linkplain MethodHandle method handle} to a {@code invokedynamic} instruction.
* There are many function-like objects in various Java APIs.
* This interface provides a standard way for such function-like objects to be bound
* to a dynamic call site, by providing a view of their behavior in the form of a low-level method handle.
* <p>
* The type {@link MethodHandle} is a concrete class whose implementation
* hierarchy (if any) may be tightly coupled to the underlying JVM implementation.
* It cannot also serve as a base type for user-defined functional APIs.
* For this reason, {@code MethodHandle} cannot be subclassed to add new
* behavior to method handles. But this interface can be used to provide
* a link between a user-defined function and the {@code invokedynamic}
* instruction and the method handle API.
*/
public interface MethodHandleProvider {
/** Produce a method handle which will serve as a behavioral proxy for the current object.
* The type and invocation behavior of the proxy method handle are user-defined,
* and should have some relation to the intended meaning of the original object itself.
* <p>
* The current object may have a changeable behavior.
* For example, {@link CallSite} has a {@code setTarget} method which changes its invocation.
* In such a case, it is <em>incorrect</em> for {@code asMethodHandle} to return
* a method handle whose behavior may diverge from that of the current object.
* Rather, the returned method handle must stably and permanently access
* the behavior of the current object, even if that behavior is changeable.
* <p>
* The reference identity of the proxy method handle is not guaranteed to
* have any particular relation to the reference identity of the object.
* In particular, several objects with the same intended meaning could
* share a common method handle, or the same object could return different
* method handles at different times. In the latter case, the different
* method handles should have the same type and invocation behavior,
* and be usable from any thread at any time.
* In particular, if a MethodHandleProvider is bound to an <code>invokedynamic</code>
* call site, the proxy method handle extracted at the time of binding
* will be used for an unlimited time, until the call site is rebound.
* <p>
* The type {@link MethodHandle} itself implements {@code MethodHandleProvider}, and
* for this method simply returns {@code this}.
*/
public MethodHandle asMethodHandle();
/** Produce a method handle of a given type which will serve as a behavioral proxy for the current object.
* As for the no-argument version {@link #asMethodHandle()}, the invocation behavior of the
* proxy method handle is user-defined. But the type must be the given type,
* or else a {@link WrongMethodTypeException} must be thrown.
* <p>
* If the current object somehow represents a variadic or overloaded behavior,
* the method handle returned for a given type might represent only a subset of
* the current object's repertoire of behaviors, which correspond to that type.
*/
public MethodHandle asMethodHandle(MethodType type) throws WrongMethodTypeException;
}

File diff suppressed because it is too large Load Diff

View File

@ -56,21 +56,33 @@ import static sun.dyn.MemberName.newIllegalArgumentException;
* <p>
* This type can be created only by factory methods.
* All factory methods may cache values, though caching is not guaranteed.
* Some factory methods are static, while others are virtual methods which
* modify precursor method types, e.g., by changing a selected parameter.
* <p>
* Factory methods which operate on groups of parameter types
* are systematically presented in two versions, so that both Java arrays and
* Java lists can be used to work with groups of parameter types.
* The query methods {@code parameterArray} and {@code parameterList}
* also provide a choice between arrays and lists.
* <p>
* {@code MethodType} objects are sometimes derived from bytecode instructions
* such as {@code invokedynamic}, specifically from the type descriptor strings associated
* with the instructions in a class file's constant pool.
* When this occurs, any classes named in the descriptor strings must be loaded.
* (But they need not be initialized.)
* This loading may occur at any time before the {@code MethodType} object is first derived.
* <p>
* Like classes and strings, method types can be represented directly
* in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
* Loading such a constant causes its component classes to be loaded as necessary.
* Like classes and strings, method types can also be represented directly
* in a class file's constant pool as constants. The may be loaded by an {@code ldc}
* instruction which refers to a suitable {@code CONSTANT_MethodType} constant pool entry.
* The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
* For more details, see the <a href="package-summary.html#mtcon">package summary</a>.
* <p>
* When the JVM materializes a {@code MethodType} from a descriptor string,
* all classes named in the descriptor must be accessible, and will be loaded.
* (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
* This loading may occur at any time before the {@code MethodType} object is first derived.
* @author John Rose, JSR 292 EG
*/
public final
class MethodType implements java.lang.reflect.Type {
class MethodType {
private final Class<?> rtype;
private final Class<?>[] ptypes;
private MethodTypeForm form; // erased form, plus cached data about primitives
@ -119,7 +131,7 @@ class MethodType implements java.lang.reflect.Type {
for (Class<?> ptype : ptypes) {
ptype.equals(ptype); // null check
if (ptype == void.class)
throw newIllegalArgumentException("void parameter: "+this);
throw newIllegalArgumentException("parameter type cannot be void");
}
}
@ -139,10 +151,6 @@ class MethodType implements java.lang.reflect.Type {
MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
return makeImpl(rtype, ptypes, false);
}
@Deprecated public static
MethodType make(Class<?> rtype, Class<?>[] ptypes) {
return methodType(rtype, ptypes);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. */
public static
@ -150,10 +158,6 @@ class MethodType implements java.lang.reflect.Type {
boolean notrust = false; // random List impl. could return evil ptypes array
return makeImpl(rtype, ptypes.toArray(NO_PTYPES), notrust);
}
@Deprecated public static
MethodType make(Class<?> rtype, List<? extends Class<?>> ptypes) {
return methodType(rtype, ptypes);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* The leading parameter type is prepended to the remaining array.
@ -165,10 +169,6 @@ class MethodType implements java.lang.reflect.Type {
System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
return makeImpl(rtype, ptypes1, true);
}
@Deprecated public static
MethodType make(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
return methodType(rtype, ptype0, ptypes);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* The resulting method has no parameter types.
@ -177,10 +177,6 @@ class MethodType implements java.lang.reflect.Type {
MethodType methodType(Class<?> rtype) {
return makeImpl(rtype, NO_PTYPES, true);
}
@Deprecated public static
MethodType make(Class<?> rtype) {
return methodType(rtype);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* The resulting method has the single given parameter type.
@ -189,10 +185,6 @@ class MethodType implements java.lang.reflect.Type {
MethodType methodType(Class<?> rtype, Class<?> ptype0) {
return makeImpl(rtype, new Class<?>[]{ ptype0 }, true);
}
@Deprecated public static
MethodType make(Class<?> rtype, Class<?> ptype0) {
return methodType(rtype, ptype0);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* The resulting method has the same parameter types as {@code ptypes},
@ -202,10 +194,6 @@ class MethodType implements java.lang.reflect.Type {
MethodType methodType(Class<?> rtype, MethodType ptypes) {
return makeImpl(rtype, ptypes.ptypes, true);
}
@Deprecated public static
MethodType make(Class<?> rtype, MethodType ptypes) {
return methodType(rtype, ptypes);
}
/**
* Sole factory method to find or create an interned method type.
@ -275,10 +263,6 @@ class MethodType implements java.lang.reflect.Type {
}
return mt;
}
@Deprecated public static
MethodType makeGeneric(int objectArgCount, boolean varargs) {
return genericMethodType(objectArgCount, varargs);
}
/**
* All parameters and the return type will be Object.
@ -290,10 +274,6 @@ class MethodType implements java.lang.reflect.Type {
MethodType genericMethodType(int objectArgCount) {
return genericMethodType(objectArgCount, false);
}
@Deprecated public static
MethodType makeGeneric(int objectArgCount) {
return genericMethodType(objectArgCount);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param num the index (zero-based) of the parameter type to change
@ -307,18 +287,6 @@ class MethodType implements java.lang.reflect.Type {
return makeImpl(rtype, nptypes, true);
}
/** Convenience method for {@link #insertParameterTypes}.
* @deprecated Use {@link #insertParameterTypes} instead.
*/
@Deprecated
public MethodType insertParameterType(int num, Class<?> nptype) {
int len = ptypes.length;
Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+1);
System.arraycopy(nptypes, num, nptypes, num+1, len-num);
nptypes[num] = nptype;
return makeImpl(rtype, nptypes, true);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param num the position (zero-based) of the inserted parameter type(s)
* @param ptypesToInsert zero or more a new parameter types to insert into the parameter list
@ -336,6 +304,22 @@ class MethodType implements java.lang.reflect.Type {
return makeImpl(rtype, nptypes, true);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param ptypesToInsert zero or more a new parameter types to insert after the end of the parameter list
* @return the same type, except with the selected parameter(s) appended
*/
public MethodType appendParameterTypes(Class<?>... ptypesToInsert) {
return insertParameterTypes(parameterCount(), ptypesToInsert);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param ptypesToInsert zero or more a new parameter types to insert after the end of the parameter list
* @return the same type, except with the selected parameter(s) appended
*/
public MethodType appendParameterTypes(List<Class<?>> ptypesToInsert) {
return insertParameterTypes(parameterCount(), ptypesToInsert);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param num the position (zero-based) of the inserted parameter type(s)
* @param ptypesToInsert zero or more a new parameter types to insert into the parameter list
@ -377,14 +361,6 @@ class MethodType implements java.lang.reflect.Type {
return makeImpl(rtype, nptypes, true);
}
/** Convenience method for {@link #dropParameterTypes}.
* @deprecated Use {@link #dropParameterTypes} instead.
*/
@Deprecated
public MethodType dropParameterType(int num) {
return dropParameterTypes(num, num+1);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param nrtype a return parameter type to replace the old one with
* @return the same type, except with the return type change
@ -552,7 +528,9 @@ class MethodType implements java.lang.reflect.Type {
* parenthesis enclosed, comma separated list of type names,
* followed immediately by the return type.
* <p>
* If a type name is array, it the base type followed
* Each type is represented by its
* {@link java.lang.Class#getSimpleName simple name}.
* If a type name name is array, it the base type followed
* by [], rather than the Class.getName of the array type.
*/
@Override
@ -561,35 +539,13 @@ class MethodType implements java.lang.reflect.Type {
sb.append("(");
for (int i = 0; i < ptypes.length; i++) {
if (i > 0) sb.append(",");
putName(sb, ptypes[i]);
sb.append(ptypes[i].getSimpleName());
}
sb.append(")");
putName(sb, rtype);
sb.append(rtype.getSimpleName());
return sb.toString();
}
static void putName(StringBuilder sb, Class<?> cls) {
int brackets = 0;
while (cls.isArray()) {
cls = cls.getComponentType();
brackets++;
}
String n = cls.getName();
/*
if (n.startsWith("java.lang.")) {
String nb = n.substring("java.lang.".length());
if (nb.indexOf('.') < 0) n = nb;
} else if (n.indexOf('.') < 0) {
n = "."+n; // anonymous package
}
*/
sb.append(n);
while (brackets > 0) {
sb.append("[]");
brackets--;
}
}
/// Queries which have to do with the bytecode architecture
/** The number of JVM stack slots required to invoke a method
@ -690,14 +646,4 @@ class MethodType implements java.lang.reflect.Type {
public String toMethodDescriptorString() {
return BytecodeDescriptor.unparse(this);
}
/** Temporary alias for toMethodDescriptorString; delete after M3. */
public String toBytecodeString() {
return toMethodDescriptorString();
}
/** Temporary alias for fromMethodDescriptorString; delete after M3. */
public static MethodType fromBytecodeString(String descriptor, ClassLoader loader)
throws IllegalArgumentException, TypeNotPresentException {
return fromMethodDescriptorString(descriptor, loader);
}
}

View File

@ -0,0 +1,206 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.dyn;
import sun.dyn.*;
import sun.dyn.empty.Empty;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A {@code MutableCallSite} is a {@link CallSite} whose target variable
* behaves like an ordinary field.
* An {@code invokedynamic} instruction linked to a {@code MutableCallSite} delegates
* all calls to the site's current target.
* The {@linkplain CallSite#dynamicInvoker dynamic invoker} of a mutable call site
* also delegates each call to the site's current target.
* <p>
* Here is an example of a mutable call site which introduces a
* state variable into a method handle chain.
* <blockquote><pre>
MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
MethodHandle MH_name = name.dynamicInvoker();
MethodType MT_str2 = MethodType.methodType(String.class, String.class);
MethodHandle MH_upcase = MethodHandles.lookup()
.findVirtual(String.class, "toUpperCase", MT_str2);
MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
name.setTarget(MethodHandles.constant(String.class, "Rocky"));
assertEquals("ROCKY", (String) worker1.invokeExact());
name.setTarget(MethodHandles.constant(String.class, "Fred"));
assertEquals("FRED", (String) worker1.invokeExact());
// (mutation can be continued indefinitely)
* </pre></blockquote>
* <p>
* The same call site may be used in several places at once.
* <blockquote><pre>
MethodHandle MH_dear = MethodHandles.lookup()
.findVirtual(String.class, "concat", MT_str2).bindTo(", dear?");
MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
assertEquals("Fred, dear?", (String) worker2.invokeExact());
name.setTarget(MethodHandles.constant(String.class, "Wilma"));
assertEquals("WILMA", (String) worker1.invokeExact());
assertEquals("Wilma, dear?", (String) worker2.invokeExact());
* </pre></blockquote>
* <p>
* <em>Non-synchronization of target values:</em>
* A write to a mutable call site's target does not force other threads
* to become aware of the updated value. Threads which do not perform
* suitable synchronization actions relative to the updated call site
* may cache the old target value and delay their use of the new target
* value indefinitely.
* (This is a normal consequence of the Java Memory Model as applied
* to object fields.)
* <p>
* The {@link #sync sync} operation provides a way to force threads
* to accept a new target value, even if there is no other synchronization.
* <p>
* For target values which will be frequently updated, consider using
* a {@linkplain VolatileCallSite volatile call site} instead.
* @author John Rose, JSR 292 EG
*/
public class MutableCallSite extends CallSite {
/**
* Make a blank call site object with the given method type.
* An initial target method is supplied which will throw
* an {@link IllegalStateException} if called.
* <p>
* Before this {@code CallSite} object is returned from a bootstrap method,
* it is usually provided with a more useful target method,
* via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
* @throws NullPointerException if the proposed type is null
*/
public MutableCallSite(MethodType type) {
super(type);
}
/**
* Make a blank call site object, possibly equipped with an initial target method handle.
* @param target the method handle which will be the initial target of the call site
* @throws NullPointerException if the proposed target is null
*/
public MutableCallSite(MethodHandle target) {
super(target);
}
/**
* Perform a synchronization operation on each call site in the given array,
* forcing all other threads to throw away any cached values previously
* loaded from the target of any of the call sites.
* <p>
* This operation does not reverse any calls that have already started
* on an old target value.
* (Java supports {@linkplain java.lang.Object#wait() forward time travel} only.)
* <p>
* The overall effect is to force all future readers of each call site's target
* to accept the most recently stored value.
* ("Most recently" is reckoned relative to the {@code sync} itself.)
* Conversely, the {@code sync} call may block until all readers have
* (somehow) decached all previous versions of each call site's target.
* <p>
* To avoid race conditions, calls to {@code setTarget} and {@code sync}
* should generally be performed under some sort of mutual exclusion.
* Note that reader threads may observe an updated target as early
* as the {@code setTarget} call that install the value
* (and before the {@code sync} that confirms the value).
* On the other hand, reader threads may observe previous versions of
* the target until the {@code sync} call returns
* (and after the {@code setTarget} that attempts to convey the updated version).
* <p>
* In terms of the Java Memory Model, this operation performs a synchronization
* action which is comparable in effect to the writing of a volatile variable
* by the current thread, and an eventual volatile read by every other thread
* that may access one of the affected call sites.
* <p>
* The following effects are apparent, for each individual call site {@code S}:
* <ul>
* <li>A new volatile variable {@code V} is created, and written by the current thread.
* As defined by the JMM, this write is a global synchronization event.
* <li>As is normal with thread-local ordering of write events,
* every action already performed by the current thread is
* taken to happen before the volatile write to {@code V}.
* (In some implementations, this means that the current thread
* performs a global release operation.)
* <li>Specifically, the write to the current target of {@code S} is
* taken to happen before the volatile write to {@code V}.
* <li>The volatile write to {@code V} is placed
* (in an implementation specific manner)
* in the global synchronization order.
* <li>Consider an arbitrary thread {@code T} (other than the current thread).
* If {@code T} executes a synchronization action {@code A}
* after the volatile write to {@code V} (in the global synchronization order),
* it is therefore required to see either the current target
* of {@code S}, or a later write to that target,
* if it executes a read on the target of {@code S}.
* (This constraint is called "synchronization-order consistency".)
* <li>The JMM specifically allows optimizing compilers to elide
* reads or writes of variables that are known to be useless.
* Such elided reads and writes have no effect on the happens-before
* relation. Regardless of this fact, the volatile {@code V}
* will not be elided, even though its written value is
* indeterminate and its read value is not used.
* </ul>
* Because of the last point, the implementation behaves as if a
* volatile read of {@code V} were performed by {@code T}
* immediately after its action {@code A}. In the local ordering
* of actions in {@code T}, this read happens before any future
* read of the target of {@code S}. It is as if the
* implementation arbitrarily picked a read of {@code S}'s target
* by {@code T}, and forced a read of {@code V} to precede it,
* thereby ensuring communication of the new target value.
* <p>
* As long as the constraints of the Java Memory Model are obeyed,
* implementations may delay the completion of a {@code sync}
* operation while other threads ({@code T} above) continue to
* use previous values of {@code S}'s target.
* However, implementations are (as always) encouraged to avoid
* livelock, and to eventually require all threads to take account
* of the updated target.
* <p>
* This operation is likely to be expensive and should be used sparingly.
* If possible, it should be buffered for batch processing on sets of call sites.
* <p style="font-size:smaller;">
* (This is a static method on a set of call sites, not a
* virtual method on a single call site, for performance reasons.
* Some implementations may incur a large fixed overhead cost
* for processing one or more synchronization operations,
* but a small incremental cost for each additional call site.
* In any case, this operation is likely to be costly, since
* other threads may have to be somehow interrupted
* in order to make them notice the updated target value.
* However, it may be observed that a single call to synchronize
* several sites has the same formal effect as many calls,
* each on just one of the sites.)
* <p>
* Simple implementations of {@code MutableCallSite} may use
* a volatile variable for the target of a mutable call site.
* In such an implementation, the {@code sync} method can be a no-op,
* and yet it will conform to the JMM behavior documented above.
*/
public static void sync(MutableCallSite[] sites) {
STORE_BARRIER.lazySet(0);
// FIXME: NYI
}
private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.dyn;
/**
* <p>
* A {@code Switcher} is an object which can publish state transitions to other threads.
* A switcher is initially in the <em>valid</em> state, but may at any time be
* changed to the <em>invalid</em> state. Invalidation cannot be reversed.
* <p>
* A single switcher may be used to create any number of guarded method handle pairs.
* Each guarded pair is wrapped in a new method handle {@code M},
* which is permanently associated with the switcher that created it.
* Each pair consists of a target {@code T} and a fallback {@code F}.
* While the switcher is valid, invocations to {@code M} are delegated to {@code T}.
* After it is invalidated, invocations are delegated to {@code F}.
* <p>
* Invalidation is global and immediate, as if the switcher contained a
* volatile boolean variable consulted on every call to {@code M}.
* The invalidation is also permanent, which means the switcher
* can change state only once.
* <p>
* Here is an example of a switcher in action:
* <blockquote><pre>
MethodType MT_str2 = MethodType.methodType(String.class, String.class);
MethodHandle MH_strcat = MethodHandles.lookup()
.findVirtual(String.class, "concat", MT_str2);
Switcher switcher = new Switcher();
// the following steps may be repeated to re-use the same switcher:
MethodHandle worker1 = strcat;
MethodHandle worker2 = MethodHandles.permuteArguments(strcat, MT_str2, 1, 0);
MethodHandle worker = switcher.guardWithTest(worker1, worker2);
assertEquals("method", (String) worker.invokeExact("met", "hod"));
switcher.invalidate();
assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
* </pre></blockquote>
* <p>
* <em>Implementation Note:</em>
* A switcher behaves as if implemented on top of {@link MutableCallSite},
* approximately as follows:
* <blockquote><pre>
public class Switcher {
private static final MethodHandle
K_true = MethodHandles.constant(boolean.class, true),
K_false = MethodHandles.constant(boolean.class, false);
private final MutableCallSite mcs;
private final MethodHandle mcsInvoker;
public Switcher() {
this.mcs = new MutableCallSite(K_true);
this.mcsInvoker = mcs.dynamicInvoker();
}
public MethodHandle guardWithTest(
MethodHandle target, MethodHandle fallback) {
// Note: mcsInvoker is of type boolean().
// Target and fallback may take any arguments, but must have the same type.
return MethodHandles.guardWithTest(this.mcsInvoker, target, fallback);
}
public static void invalidateAll(Switcher[] switchers) {
List<MutableCallSite> mcss = new ArrayList<>();
for (Switcher s : switchers) mcss.add(s.mcs);
for (MutableCallSite mcs : mcss) mcs.setTarget(K_false);
MutableCallSite.sync(mcss.toArray(new MutableCallSite[0]));
}
}
* </pre></blockquote>
* @author Remi Forax, JSR 292 EG
*/
public class Switcher {
private static final MethodHandle
K_true = MethodHandles.constant(boolean.class, true),
K_false = MethodHandles.constant(boolean.class, false);
private final MutableCallSite mcs;
private final MethodHandle mcsInvoker;
/** Create a switcher. */
public Switcher() {
this.mcs = new MutableCallSite(K_true);
this.mcsInvoker = mcs.dynamicInvoker();
}
/**
* Return a method handle which always delegates either to the target or the fallback.
* The method handle will delegate to the target exactly as long as the switcher is valid.
* After that, it will permanently delegate to the fallback.
* <p>
* The target and fallback must be of exactly the same method type,
* and the resulting combined method handle will also be of this type.
* @see MethodHandles#guardWithTest
*/
public MethodHandle guardWithTest(MethodHandle target, MethodHandle fallback) {
if (mcs.getTarget() == K_false)
return fallback; // already invalid
return MethodHandles.guardWithTest(mcsInvoker, target, fallback);
}
/** Set all of the given switchers into the invalid state. */
public static void invalidateAll(Switcher[] switchers) {
MutableCallSite[] sites = new MutableCallSite[switchers.length];
int fillp = 0;
for (Switcher switcher : switchers) {
sites[fillp++] = switcher.mcs;
switcher.mcs.setTarget(K_false);
}
MutableCallSite.sync(sites);
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.dyn;
import java.util.List;
/**
* A {@code VolatileCallSite} is a {@link CallSite} whose target acts like a volatile variable.
* An {@code invokedynamic} instruction linked to a {@code VolatileCallSite} sees updates
* to its call site target immediately, even if the update occurs in another thread.
* There may be a performance penalty for such tight coupling between threads.
* <p>
* Unlike {@code MutableCallSite}, there is no
* {@linkplain MutableCallSite#sync sync operation} on volatile
* call sites, since every write to a volatile variable is implicitly
* synchronized with reader threads.
* <p>
* In other respects, a {@code VolatileCallSite} is interchangeable
* with {@code MutableCallSite}.
* @see MutableCallSite
* @author John Rose, JSR 292 EG
*/
public class VolatileCallSite extends CallSite {
/** Create a call site with a volatile target.
* The initial target is set to a method handle
* of the given type which will throw {@code IllegalStateException}.
* @throws NullPointerException if the proposed type is null
*/
public VolatileCallSite(MethodType type) {
super(type);
}
/** Create a call site with a volatile target.
* The target is set to the given value.
* @throws NullPointerException if the proposed target is null
*/
public VolatileCallSite(MethodHandle target) {
super(target);
}
/** Internal override to nominally final getTarget. */
@Override
MethodHandle getTarget0() {
return getTargetVolatile();
}
/**
* Set the target method of this call site, as a volatile variable.
* Has the same effect as {@link CallSite#setTarget CallSite.setTarget}, with the additional
* effects associated with volatiles, in the Java Memory Model.
*/
@Override public void setTarget(MethodHandle newTarget) {
checkTargetChange(getTargetVolatile(), newTarget);
setTargetVolatile(newTarget);
}
}

View File

@ -24,7 +24,6 @@
*/
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* This package contains dynamic language support provided directly by
* the Java core class libraries and virtual machine.
* <p>
@ -42,13 +41,6 @@
* argument and return value conversions are applied.
* </li>
*
* <li>In source code, the class {@link java.dyn.InvokeDynamic 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>
*
* <li>The JVM bytecode format supports immediate constants of
* the classes {@link java.dyn.MethodHandle MethodHandle} and {@link java.dyn.MethodType MethodType}.
* </li>
@ -56,51 +48,68 @@
*
* <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>
* changes being made to the Java Virtual Machine specification for JSR 292.
* This information will be incorporated in a future version of the JVM specification.</em>
*
* <h3>{@code invokedynamic} instruction format</h3>
* <h3><a name="indyinsn"></a>{@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 of an {@code invokedynamic} instruction is to a entry
* with tag {@code CONSTANT_InvokeDynamic} (decimal 17). See below for its format.
* The entry specifies the bootstrap method (a {@link java.dyn.MethodHandle MethodHandle} constant),
* the dynamic invocation name, and the argument types and return type of the call.
* with tag {@code CONSTANT_InvokeDynamic} (decimal 18). See below for its format.
* (The tag value 17 is also temporarily allowed. See below.)
* The entry specifies the following information:
* <ul>
* <li>a bootstrap method (a {@link java.dyn.MethodHandle MethodHandle} constant)</li>
* <li>the dynamic invocation name (a UTF8 string)</li>
* <li>the argument and return types of the call (encoded as a signature in a UTF8 string)</li>
* <li>optionally, a sequence of additional <em>static arguments</em> to the bootstrap method ({@code ldc}-type constants)</li>
* </ul>
* <p>
* Each instance of an {@code invokedynamic} instruction is called a <em>dynamic call site</em>.
* Multiple instances of an {@code invokedynamic} instruction can share a single
* {@code CONSTANT_InvokeDynamic} entry.
* In any case, distinct call sites always have distinct linkage state.
* <p>
* Moreover, for the purpose of distinguishing dynamic call sites,
* the JVM is allowed (but not required) to make internal copies
* of {@code invokedynamic} instructions, each one
* constituting a separate dynamic call site with its own linkage state.
* Such copying, if it occurs, cannot be observed except indirectly via
* execution of bootstrap methods and target methods.
* <p>
* A dynamic call site is originally in an unlinked state. In this state, there is
* no target method for the call site to invoke.
* A dynamic call site is linked by means of a bootstrap method,
* as <a href="#bsm">described below</a>.
* <p>
* <em>(Historic Note: Some older JVMs may allow the index of a {@code CONSTANT_NameAndType}
* instead of a {@code CONSTANT_InvokeDynamic}. In earlier, obsolete versions of this API, the
* bootstrap method was specified dynamically, in a per-class basis, during class initialization.)</em>
*
* <h3>constant pool entries for {@code invokedynamic} instructions</h3>
* If a constant pool entry has the tag {@code CONSTANT_InvokeDynamic} (decimal 17),
* it must contain exactly four more bytes.
* The first two bytes after the tag must be an index to a {@code CONSTANT_MethodHandle}
* entry, and the second two bytes must be an index to a {@code CONSTANT_NameAndType}.
* <p style="font-size:smaller;">
* (Historic Note: Some older JVMs may allow the index of a {@code CONSTANT_NameAndType}
* instead of a {@code CONSTANT_InvokeDynamic}. In earlier, obsolete versions of this API, the
* bootstrap method was specified dynamically, in a per-class basis, during class initialization.)
*
* <h3><a name="indycon"></a>constant pool entries for {@code invokedynamic} instructions</h3>
* If a constant pool entry has the tag {@code CONSTANT_InvokeDynamic} (decimal 18),
* it must contain exactly four more bytes after the tag.
* These bytes are interpreted as two 16-bit indexes, in the usual {@code u2} format.
* The first pair of bytes after the tag must be an index into a side table called the
* <em>bootstrap method table</em>, which is stored in the {@code BootstrapMethods}
* attribute as <a href="#bsmattr">described below</a>.
* The second pair of bytes must be an index to a {@code CONSTANT_NameAndType}.
* This table is not part of the constant pool. Instead, it is stored
* in a class attribute named {@code BootstrapMethods}, described below.
* <p>
* The first index specifies a bootstrap method used by the associated dynamic call sites.
* The second index specifies the method name, argument types, and return type of the dynamic call site.
* The structure of such an entry is therefore analogous to a {@code CONSTANT_Methodref},
* except that the {@code CONSTANT_Class} reference in a {@code CONSTANT_Methodref} entry
* is replaced by a bootstrap method reference.
* except that the bootstrap method specifier reference replaces
* the {@code CONSTANT_Class} reference of a {@code CONSTANT_Methodref} entry.
* <p>
* Some older JVMs may allow an older constant pool entry tag of decimal 17.
* The format and behavior of a constant pool entry with this tag is identical to
* an entry with a tag of decimal 18, except that the first index refers directly
* to a {@code CONSTANT_MethodHandle} to use as the bootstrap method.
* This format does not require the bootstrap method table.
*
* <h3>constant pool entries for {@code MethodType}s</h3>
* <p style="font-size:smaller;">
* <em>(Note: The Proposed Final Draft of this specification is likely to support
* only the tag 18, not the tag 17.)</em>
*
* <h3><a name="mtcon"></a>constant pool entries for {@linkplain java.dyn.MethodType method types}</h3>
* If a constant pool entry has the tag {@code CONSTANT_MethodType} (decimal 16),
* it must contain exactly two more bytes, which must be an index to a {@code CONSTANT_Utf8}
* entry which represents a method type signature.
@ -113,7 +122,7 @@
* 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>
* <h3><a name="mhcon"></a>constant pool entries for {@linkplain java.dyn.MethodHandle method handles}</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 which must be in the range 1 through 9, and the last two must be an index to a
@ -129,7 +138,7 @@
* <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,
* type is created. Any classes mentioned in this reification 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:
@ -148,16 +157,45 @@
* </table>
* </code>
* <p>
* The special names {@code <init>} and {@code <clinit>} are not allowed except for subtag 8 as shown.
* The special name {@code <clinit>} is not allowed.
* The special name {@code <init>} is 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
* The JVM verifier and linker apply 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}
* A constant may refer to a method or constructor with the {@code varargs}
* bit (hexadecimal {@code 80}) set in its modifier bitmask.
* The method handle constant produced for such a method behaves the same
* as if the {@code varargs} bit were not set.
* The argument-collecting behavior of {@code varargs} can be emulated by
* adapting the method handle constant with
* {@link java.dyn.MethodHandle#asCollector asCollector}.
* There is no provision for doing this automatically.
* <p>
* Although the {@code CONSTANT_MethodHandle} and {@code CONSTANT_MethodType} constant types
* resolve class names, they do not force class initialization.
* Method handle constants 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.
* <p>
* The rules of section 5.4.3 of the
* <a href="http://java.sun.com/docs/books/jvms/second_edition/html/ConstantPool.doc.html#73492">JVM Specification</a>
* apply to the resolution of {@code CONSTANT_MethodType}, {@code CONSTANT_MethodHandle},
* and {@code CONSTANT_InvokeDynamic} constants,
* by the execution of {@code invokedynamic} and {@code ldc} instructions.
* (Roughly speaking, this means that every use of a constant pool entry
* must lead to the same outcome.
* If the resoultion succeeds, the same object reference is produced
* by every subsequent execution of the same instruction.
* If the resolution of the constant causes an error to occur,
* the same error will be re-thrown on every subsequent attempt
* to use this particular constant.)
* <p>
* Constants created by the resolution of these constant pool types are not necessarily
* interned. Except for {@link CONSTANT_Class} and {@link CONSTANT_String} entries,
* two distinct constant pool entries might not resolve to the same reference
* even if they contain the same symbolic reference.
*
* <h2><a name="bsm"></a>Bootstrap Methods</h2>
* Before the JVM can execute a dynamic call site (an {@code invokedynamic} instruction),
@ -181,24 +219,36 @@
* call site execution.
* Linkage does not trigger class initialization.
* <p>
* Next, the bootstrap method call is started, with four values being stacked:
* Next, the bootstrap method call is started, with four or five values being stacked:
* <ul>
* <li>a {@code MethodHandle}, the resolved bootstrap method itself </li>
* <li>a {@code Class}, the <em>caller class</em> in which dynamic call site occurs </li>
* <li>a {@code MethodHandles.Lookup}, a lookup object on the <em>caller class</em> in which dynamic call site occurs </li>
* <li>a {@code String}, the method name mentioned in the call site </li>
* <li>a {@code MethodType}, the resolved type signature of the call </li>
* <li>optionally, a single object representing one or more <a href="#args">additional static arguments</a> </li>
* </ul>
* The method handle is then applied to the other values as if by
* {@linkplain java.dyn.MethodHandle#invokeGeneric the <code>invokeGeneric</code> method}.
* The returned result must be a {@link java.dyn.CallSite CallSite}, a {@link java.dyn.MethodHandle MethodHandle},
* or another {@link java.dyn.MethodHandleProvider MethodHandleProvider} value.
* The method {@linkplain java.dyn.MethodHandleProvider#asMethodHandle asMethodHandle}
* is then called on the returned value. The result of that second
* call is the {@code MethodHandle} which becomes the
* permanent binding for the dynamic call site.
* That method handle's type must be exactly equal to the type
* {@link java.dyn.MethodHandle#invokeGeneric invokeGeneric}.
* The returned result must be a {@link java.dyn.CallSite CallSite} (or a subclass).
* The type of the call site's target must be exactly equal to the type
* derived from the dynamic call site signature and passed to
* the bootstrap method.
* The call site then becomes permanently linked to the dynamic call site.
* <p>
* As long as each bootstrap method can be correctly invoked
* by <code>invokeGeneric</code>, its detailed type is arbitrary.
* For example, the first argument could be {@code Object}
* instead of {@code MethodHandles.Lookup}, and the return type
* could also be {@code Object} instead of {@code CallSite}.
* <p>
* As with any method handle constant, a {@code varargs} modifier bit
* on the bootstrap method is ignored.
* <p>
* Note that the first argument of the bootstrap method cannot be
* a simple {@code Class} reference. (This is a change from earlier
* versions of this specification. If the caller class is needed,
* it is easy to {@linkplain java.dyn.MethodHandles.Lookup#lookupClass() extract it}
* from the {@code Lookup} object.)
* <p>
* After resolution, the linkage process may fail in a variety of ways.
* All failures are reported by an {@link java.dyn.InvokeDynamicBootstrapError InvokeDynamicBootstrapError},
@ -206,81 +256,209 @@
* site execution.
* The following circumstances will cause this:
* <ul>
* <li>the index to the bootstrap method specifier is out of range </li>
* <li>the bootstrap method cannot be resolved </li>
* <li>the {@code MethodType} to pass to the bootstrap method cannot be resolved </li>
* <li>a static argument to the bootstrap method cannot be resolved
* (i.e., a {@code CONSTANT_Class}, {@code CONSTANT_MethodType},
* or {@code CONSTANT_MethodHandle} argument cannot be linked) </li>
* <li>the bootstrap method has the wrong arity,
* causing {@code invokeGeneric} to throw {@code WrongMethodTypeException} </li>
* <li>the bootstrap method has a wrong argument or return type </li>
* <li>the bootstrap method invocation completes abnormally </li>
* <li>the result from the bootstrap invocation is not a reference to
* an object of type {@link java.dyn.MethodHandleProvider MethodHandleProvider} </li>
* <li>the call to {@code asMethodHandle} completes abnormally </li>
* <li>the call to {@code asMethodHandle} fails to return a reference to
* an object of type {@link java.dyn.MethodHandle MethodHandle} </li>
* <li>the method handle produced by {@code asMethodHandle} does not have
* an object of type {@link java.dyn.CallSite CallSite} </li>
* <li>the target of the {@code CallSite} does not have a target of
* the expected {@code MethodType} </li>
* </ul>
* <h3>timing of linkage</h3>
*
* <h3><a name="linktime"></a>timing of linkage</h3>
* A dynamic call site is linked just before its first execution.
* The bootstrap method call implementing the linkage occurs within
* a thread that is attempting a first execution.
* <p>
* If there are several such threads, the JVM picks one thread
* and runs the bootstrap method while the others wait for the
* invocation to terminate normally or abnormally.
* <p>
* After a bootstrap method is called and a method handle target
* successfully extracted, the JVM attempts to link the instruction
* being executed to the target method handle.
* This may fail if there has been intervening linkage
* or invalidation event for the same instruction.
* If such a failure occurs, the dynamic call site must be
* re-executed from the beginning, either re-linking it
* (if it has been invalidated) or invoking the target
* (if it the instruction has been linked by some other means).
* <p>
* If the instruction is linked successfully, the target method
* handle is invoked to complete the instruction execution.
* The 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,
* such as {@link java.dyn.Linkage#invalidateCallerClass Linkage.invalidateCallerClass}.
* If there are several such threads, the bootstrap method may be
* invoked in several threads concurrently.
* Therefore, bootstrap methods which access global application
* data must take the usual precautions against race conditions.
* In any case, every {@code invokedynamic} instruction is either
* unlinked or linked to a unique {@code CallSite} object.
* <p>
* In an application which requires dynamic call sites with individually
* mutable behaviors, their bootstrap methods should produce distinct
* {@link java.dyn.CallSite CallSite} objects, one for each linkage request.
* <p>
* If a class containing {@code invokedynamic} instructions
* is {@linkplain java.dyn.Linkage#invalidateCallerClass(Class) invalidated},
* subsequent execution of those {@code invokedynamic} instructions
* will require linking.
* It is as if they had never been executed in the first place.
* (However, invalidation does not cause constant pool entries to be
* resolved a second time.)
* <p>
* Invalidation events and bootstrap method calls for a particular
* dynamic call site are globally ordered relative to each other.
* When an invokedynamic instruction is invalidated, if there is
* simultaneously a bootstrap method invocation in process
* (in the same thread or a different thread), the result
* eventually returned must not be used to link the call site.
* Put another way, when a call site is invalidated, its
* subsequent linkage (if any) must be performed by a bootstrap method
* call initiated after the invalidation occurred.
* Alternatively, an application can link a single {@code CallSite} object
* to several {@code invokedynamic} instructions, in which case
* a change to the target method will become visible at each of
* the instructions.
* <p>
* If several threads simultaneously execute a bootstrap method for a single dynamic
* call site, the JVM must choose one target object and installs it visibly to
* call site, the JVM must choose one {@code CallSite} object and install it visibly to
* all threads. Any other bootstrap method calls are allowed to complete, but their
* results are ignored, and their dynamic call site invocations proceed with the originally
* chosen target object.
*
* <p style="font-size:smaller;">
* (Historic Note: Unlike some previous versions of this specification,
* these rules do not enable the JVM to duplicate dynamic call sites,
* or to issue &ldquo;causeless&rdquo; bootstrap method calls.
* Every dynamic call site transitions at most once from unlinked to linked,
* just before its first invocation.)
*
* <h3><a name="bsmattr">the {@code BootstrapMethods} attribute </h3>
* Each {@code CONSTANT_InvokeDynamic} entry contains an index which references
* a bootstrap method specifier; all such specifiers are contained in a separate array.
* This array is defined by a class attribute named {@code BootstrapMethods}.
* The body of this attribute consists of a sequence of byte pairs, all interpreted as
* as 16-bit counts or constant pool indexes, in the {@code u2} format.
* The attribute body starts with a count of bootstrap method specifiers,
* which is immediately followed by the sequence of specifiers.
* <p>
* The JVM is free to duplicate dynamic call sites.
* This means that, even if a class contains just one {@code invokedynamic}
* instruction, its bootstrap method may be executed several times,
* once for each duplicate. Thus, bootstrap method code should not
* assume an exclusive one-to-one correspondence between particular occurrences
* of {@code invokedynamic} bytecodes in class files and linkage events.
* Each bootstrap method specifier contains an index to a
* {@code CONSTANT_MethodHandle} constant, which is the bootstrap
* method itself.
* This is followed by a count, and then a sequence (perhaps empty) of
* indexes to <a href="#args">additional static arguments</a>
* for the bootstrap method.
* <p>
* In principle, each individual execution of an {@code invokedynamic}
* instruction could be deemed (by a conforming implementation) to be a separate
* duplicate, requiring its own execution of the bootstrap method.
* However, implementations are expected to perform code duplication
* (if at all) in order to improve performance, not make it worse.
* During class loading, the verifier must check the structure of the
* {@code BootstrapMethods} attribute. In particular, each constant
* pool index must be of the correct type. A bootstrap method index
* must refer to a {@code CONSTANT_MethodHandle} (tag 15).
* Every other index must refer to a valid operand of an
* {@code ldc_w} or {@code ldc2_w} instruction (tag 3..8 or 15..16).
*
* <h3><a name="args">static arguments to the bootstrap method</h3>
* An {@code invokedynamic} instruction specifies at least three arguments
* to pass to its bootstrap method:
* The caller class (expressed as a {@link java.dyn.MethodHandles.Lookup Lookup object},
* the name (extracted from the {@code CONSTANT_NameAndType} entry),
* and the type (also extracted from the {@code CONSTANT_NameAndType} entry).
* The {@code invokedynamic} instruction may specify additional metadata values
* to pass to its bootstrap method.
* Collectively, these values are called <em>static arguments</em> to the
* {@code invokedynamic} instruction, because they are used once at link
* time to determine the instruction's behavior on subsequent sets of
* <em>dynamic arguments</em>.
* <p>
* Static arguments are used to communicate application-specific meta-data
* to the bootstrap method.
* Drawn from the constant pool, they may include references to classes, method handles,
* strings, or numeric data that may be relevant to the task of linking that particular call site.
* <p>
* Static arguments are specified constant pool indexes stored in the {@code BootstrapMethods} attribute.
* Before the bootstrap method is invoked, each index is used to compute an {@code Object}
* reference to the indexed value in the constant pool.
* If the value is a primitive type, it is converted to a reference by boxing conversion.
* The valid constant pool entries are listed in this table:
* <code>
* <table border=1 cellpadding=5 summary="Static argument types">
* <tr><th>entry type</th><th>argument type</th><th>argument value</th></tr>
* <tr><td>CONSTANT_String</td><td><code>java.lang.String</code></td><td>the indexed string literal</td></tr>
* <tr><td>CONSTANT_Class</td><td><code>java.lang.Class</code></td><td>the indexed class, resolved</td></tr>
* <tr><td>CONSTANT_Integer</td><td><code>java.lang.Integer</code></td><td>the indexed int value</td></tr>
* <tr><td>CONSTANT_Long</td><td><code>java.lang.Long</code></td><td>the indexed long value</td></tr>
* <tr><td>CONSTANT_Float</td><td><code>java.lang.Float</code></td><td>the indexed float value</td></tr>
* <tr><td>CONSTANT_Double</td><td><code>java.lang.Double</code></td><td>the indexed double value</td></tr>
* <tr><td>CONSTANT_MethodHandle</td><td><code>java.dyn.MethodHandle</code></td><td>the indexed method handle constant</td></tr>
* <tr><td>CONSTANT_MethodType</td><td><code>java.dyn.MethodType</code></td><td>the indexed method type constant</td></tr>
* </table>
* </code>
* <p>
* If a given {@code invokedynamic} instruction specifies no static arguments,
* the instruction's bootstrap method will be invoked on three arguments,
* conveying the instruction's caller class, name, and method type.
* If the {@code invokedynamic} instruction specifies one or more static arguments,
* a fourth argument will be passed to the bootstrap argument,
* either an {@code Object} reference to the sole extra argument (if there is one)
* or an {@code Object} array of references to all the arguments (if there are two or more),
* as if the bootstrap method is a variable-arity method.
* <code>
* <table border=1 cellpadding=5 summary="Static argument types">
* <tr><th>N</th><th>sample bootstrap method</th></tr>
* <tr><td>0</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type)</code></td></tr>
* <tr><td>1</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, Object arg)</code></td></tr>
* <tr><td>2</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)</code></td></tr>
* </table>
* </code>
* <p>
* The argument and return types listed here are used by the {@code invokeGeneric}
* call to the bootstrap method.
* As noted above, the actual method type of the bootstrap method can vary.
* For example, the fourth argument could be {@code MethodHandle},
* if that is the type of the corresponding constant in
* the {@code CONSTANT_InvokeDynamic} entry.
* In that case, the {@code invokeGeneric} call will pass the extra method handle
* constant as an {@code Object}, but the type matching machinery of {@code invokeGeneric}
* will cast the reference back to {@code MethodHandle} before invoking the bootstrap method.
* (If a string constant were passed instead, by badly generated code, that cast would then fail.)
* <p>
* If the fourth argument is an array, the array element type must be {@code Object},
* since object arrays (as produced by the JVM at this point) cannot be converted
* to other array types.
* <p>
* If an array is provided, it will appear to be freshly allocated.
* That is, the same array will not appear to two bootstrap method calls.
* <p>
* Extra bootstrap method arguments are intended to allow language implementors
* to safely and compactly encode metadata.
* In principle, the name and extra arguments are redundant,
* since each call site could be given its own unique bootstrap method.
* Such a practice is likely to produce large class files and constant pools.
*
* <p style="font-size:smaller;">
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* (Usage Note: There is no mechanism for specifying five or more positional arguments to the bootstrap method.
* If there are two or more arguments, the Java code of the bootstrap method is required to extract them from
* a varargs-style object array.
* This design uses varargs because it anticipates some use cases where bootstrap arguments
* contribute components of variable-length structures, such as virtual function tables
* or interpreter token streams.
* Such parameters would be awkward or impossible to manage if represented
* as normal positional method arguments,
* since there would need to be one Java method per length.
* On balance, leaving out the varargs feature would cause more trouble to users than keeping it.
* Also, this design allows bootstrap methods to be called in a limited JVM stack depth.
* At both the user and JVM level, the difference between varargs and non-varargs
* calling sequences can easily be bridged via the
* {@link java.dyn.MethodHandle#asSpreader asSpreader}
* and {@link java.dyn.MethodHandle#asSpreader asCollector} methods.)
*
* <h2><a name="structs"></a>Structure Summary</h2>
* <blockquote><pre>// summary of constant and attribute structures
struct CONSTANT_MethodHandle_info {
u1 tag = 15;
u1 reference_kind; // 1..8 (one of REF_invokeVirtual, etc.)
u2 reference_index; // index to CONSTANT_Fieldref or *Methodref
}
struct CONSTANT_MethodType_info {
u1 tag = 16;
u2 descriptor_index; // index to CONSTANT_Utf8, as in NameAndType
}
struct CONSTANT_InvokeDynamic_17_info {
u1 tag = 17;
u2 bootstrap_method_index; // index to CONSTANT_MethodHandle
u2 name_and_type_index; // same as for CONSTANT_Methodref, etc.
}
struct CONSTANT_InvokeDynamic_info {
u1 tag = 18;
u2 bootstrap_method_attr_index; // index into BootstrapMethods_attr
u2 name_and_type_index; // index to CONSTANT_NameAndType, as in Methodref
}
struct BootstrapMethods_attr {
u2 name; // CONSTANT_Utf8 = "BootstrapMethods"
u4 size;
u2 bootstrap_method_count;
struct bootstrap_method_specifier {
u2 bootstrap_method_ref; // index to CONSTANT_MethodHandle
u2 bootstrap_argument_count;
u2 bootstrap_arguments[bootstrap_argument_count]; // constant pool indexes
} bootstrap_methods[bootstrap_method_count];
}
* </pre></blockquote>
* <p>
* <em>Note: The Proposed Final Draft of JSR 292 may remove the constant tag 17,
* for the sake of simplicity.</em>
*
* @author John Rose, JSR 292 EG
*/

View File

@ -478,6 +478,39 @@ public class AdapterMethodHandle extends BoundMethodHandle {
return new AdapterMethodHandle(target, newType, makeConv(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY));
}
static MethodHandle makeTypeHandler(Access token,
MethodHandle target, MethodHandle typeHandler) {
Access.check(token);
return new WithTypeHandler(target, typeHandler);
}
static class WithTypeHandler extends AdapterMethodHandle {
final MethodHandle target, typeHandler;
WithTypeHandler(MethodHandle target, MethodHandle typeHandler) {
super(target, target.type(), makeConv(OP_RETYPE_ONLY));
this.target = target;
this.typeHandler = typeHandler.asType(TYPE_HANDLER_TYPE);
}
public MethodHandle asType(MethodType newType) {
if (this.type() == newType)
return this;
try {
MethodHandle retyped = (MethodHandle) typeHandler.invokeExact(target, newType);
// Contract: Must return the desired type, or throw WMT
if (retyped.type() != newType)
throw new WrongMethodTypeException(retyped.toString());
return retyped;
} catch (Throwable ex) {
if (ex instanceof Error) throw (Error)ex;
if (ex instanceof RuntimeException) throw (RuntimeException)ex;
throw new RuntimeException(ex);
}
}
private static final MethodType TYPE_HANDLER_TYPE
= MethodType.methodType(MethodHandle.class, MethodHandle.class, MethodType.class);
}
/** Can a checkcast adapter validly convert the target to newType?
* The JVM supports all kind of reference casts, even silly ones.
*/

View File

@ -103,21 +103,20 @@ public class BoundMethodHandle extends MethodHandle {
super(Access.TOKEN, type);
this.argument = argument;
this.vmargslot = vmargslot;
assert(this.getClass() == AdapterMethodHandle.class);
assert(this instanceof AdapterMethodHandle);
}
/** Initialize the current object as a Java method handle, binding it
/** Initialize the current object as a self-bound method handle, binding it
* as the first argument of the method handle {@code entryPoint}.
* The invocation type of the resulting method handle will be the
* same as {@code entryPoint}, except that the first argument
* type will be dropped.
*/
protected BoundMethodHandle(MethodHandle entryPoint) {
super(Access.TOKEN, entryPoint.type().dropParameterTypes(0, 1));
protected BoundMethodHandle(Access token, MethodHandle entryPoint) {
super(token, entryPoint.type().dropParameterTypes(0, 1));
this.argument = this; // kludge; get rid of
this.vmargslot = this.type().parameterSlotDepth(0);
initTarget(entryPoint, 0);
assert(this instanceof JavaMethodHandle);
}
/** Make sure the given {@code argument} can be used as {@code argnum}-th
@ -173,6 +172,11 @@ public class BoundMethodHandle extends MethodHandle {
@Override
public String toString() {
return MethodHandleImpl.addTypeString(baseName(), this);
}
/** Component of toString() before the type string. */
protected String baseName() {
MethodHandle mh = this;
while (mh instanceof BoundMethodHandle) {
Object info = MethodHandleNatives.getTargetInfo(mh);
@ -185,12 +189,16 @@ public class BoundMethodHandle extends MethodHandle {
if (name != null)
return name;
else
return super.toString(); // <unknown>, probably
return noParens(super.toString()); // "invoke", probably
}
assert(mh != this);
if (mh instanceof JavaMethodHandle)
break; // access JMH.toString(), not BMH.toString()
}
return mh.toString();
return noParens(mh.toString());
}
private static String noParens(String str) {
int paren = str.indexOf('(');
if (paren >= 0) str = str.substring(0, paren);
return str;
}
}

View File

@ -41,31 +41,45 @@ public class CallSiteImpl {
Object info,
// Caller information:
MemberName callerMethod, int callerBCI) {
Class<?> caller = callerMethod.getDeclaringClass();
Class<?> callerClass = callerMethod.getDeclaringClass();
Object caller;
if (bootstrapMethod.type().parameterType(0) == Class.class)
caller = callerClass; // remove for PFD
else
caller = MethodHandleImpl.IMPL_LOOKUP.in(callerClass);
if (bootstrapMethod == null) {
// If there is no bootstrap method, throw IncompatibleClassChangeError.
// This is a valid generic error type for resolution (JLS 12.3.3).
throw new IncompatibleClassChangeError
("Class "+caller.getName()+" has not declared a bootstrap method for invokedynamic");
("Class "+callerClass.getName()+" has not declared a bootstrap method for invokedynamic");
}
CallSite site;
try {
Object binding;
if (false) // switch when invokeGeneric works
binding = bootstrapMethod.invokeGeneric(caller, name, type);
else
binding = bootstrapMethod.invokeVarargs(new Object[]{ caller, name, type });
if (info == null) {
if (false) // switch when invokeGeneric works
binding = bootstrapMethod.invokeGeneric(caller, name, type);
else
binding = bootstrapMethod.invokeVarargs(new Object[]{ caller, name, type });
} else {
info = maybeReBox(info);
if (false) // switch when invokeGeneric works
binding = bootstrapMethod.invokeGeneric(caller, name, type, info);
else
binding = bootstrapMethod.invokeVarargs(new Object[]{ caller, name, type, info });
}
//System.out.println("BSM for "+name+type+" => "+binding);
if (binding instanceof CallSite) {
site = (CallSite) binding;
} else if (binding instanceof MethodHandleProvider) {
MethodHandle target = ((MethodHandleProvider) binding).asMethodHandle();
} else if (binding instanceof MethodHandle) {
// Transitional!
MethodHandle target = (MethodHandle) binding;
site = new ConstantCallSite(target);
} else {
throw new ClassCastException("bootstrap method failed to produce a MethodHandle or CallSite");
}
PRIVATE_INITIALIZE_CALL_SITE.<void>invokeExact(site, name, type,
callerMethod, callerBCI);
PRIVATE_INITIALIZE_CALL_SITE.invokeExact(site, name, type,
callerMethod, callerBCI);
assert(site.getTarget() != null);
assert(site.getTarget().type().equals(type));
} catch (Throwable ex) {
@ -79,6 +93,24 @@ public class CallSiteImpl {
return site;
}
private static Object maybeReBox(Object x) {
if (x instanceof Integer) {
int xi = (int) x;
if (xi == (byte) xi)
x = xi; // must rebox; see JLS 5.1.7
return x;
} else if (x instanceof Object[]) {
Object[] xa = (Object[]) x;
for (int i = 0; i < xa.length; i++) {
if (xa[i] instanceof Integer)
xa[i] = maybeReBox(xa[i]);
}
return xa;
} else {
return x;
}
}
// 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;

View File

@ -115,7 +115,7 @@ class FilterGeneric {
static MethodHandle make(Kind kind, int pos, MethodHandle filter, MethodHandle target) {
FilterGeneric fgen = of(kind, pos, filter.type(), target.type());
return fgen.makeInstance(kind, pos, filter, target).asMethodHandle();
return fgen.makeInstance(kind, pos, filter, target);
}
/** Return the adapter information for this target and filter type. */
@ -225,13 +225,13 @@ class FilterGeneric {
* The invoker is kept separate from the target because it can be
* generated once per type erasure family, and reused across adapters.
*/
static abstract class Adapter extends JavaMethodHandle {
static abstract class Adapter extends BoundMethodHandle {
protected final MethodHandle filter; // transforms one or more arguments
protected final MethodHandle target; // ultimate target
@Override
public String toString() {
return target.toString();
return MethodHandleImpl.addTypeString(target, this);
}
protected boolean isPrototype() { return target == null; }
@ -246,7 +246,7 @@ class FilterGeneric {
protected Adapter(MethodHandle entryPoint,
MethodHandle filter, MethodHandle target) {
super(entryPoint);
super(Access.TOKEN, entryPoint);
this.filter = filter;
this.target = target;
}
@ -303,7 +303,7 @@ class FilterGeneric {
protected Object invoke_C0(Object a0) { return target.invokeExact(filter.invokeExact(a0)); }
protected Object invoke_C1(Object a0) { return target.invokeExact(a0, filter.invokeExact()); }
protected Object invoke_Y0(Object a0) { Object[] av = { a0 };
filter.<void>invokeExact(av); return target.invokeExact(av[0]); }
filter.invokeExact(av); return target.invokeExact(av[0]); }
}
static class F2X extends Adapter {
protected F2X(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
@ -320,7 +320,7 @@ class FilterGeneric {
protected Object invoke_C1(Object a0, Object a1) { return target.invokeExact(a0, filter.invokeExact(a1)); }
protected Object invoke_C2(Object a0, Object a1) { return target.invokeExact(a0, a1, filter.invokeExact()); }
protected Object invoke_Y0(Object a0, Object a1) { Object[] av = { a0, a1 };
filter.<void>invokeExact(av); return target.invokeExact(av[0], av[1]); }
filter.invokeExact(av); return target.invokeExact(av[0], av[1]); }
}
// */
@ -337,7 +337,7 @@ class FilterGeneric {
return target.invokeExact(filter.invokeExact()); }
static final Object[] NO_ARGS = { };
protected Object invoke_Y0() throws Throwable {
filter.<void>invokeExact(NO_ARGS); // make the flyby
filter.invokeExact(NO_ARGS); // make the flyby
return target.invokeExact(); }
}
@ -375,7 +375,7 @@ class genclasses {
" return target.invokeExact(@av@, filter.invokeExact()); }",
" protected Object invoke_Y0(@Tvav@) throws Throwable {",
" Object[] av = { @av@ };",
" filter.<void>invokeExact(av); // make the flyby",
" filter.invokeExact(av); // make the flyby",
" return target.invokeExact(@av[i]@); }",
" }",
} };
@ -518,7 +518,7 @@ class genclasses {
return target.invokeExact(a0, filter.invokeExact()); }
protected Object invoke_Y0(Object a0) throws Throwable {
Object[] av = { a0 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0]); }
}
static class F2 extends Adapter {
@ -548,7 +548,7 @@ class genclasses {
return target.invokeExact(a0, a1, filter.invokeExact()); }
protected Object invoke_Y0(Object a0, Object a1) throws Throwable {
Object[] av = { a0, a1 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1]); }
}
static class F3 extends Adapter {
@ -585,7 +585,7 @@ class genclasses {
return target.invokeExact(a0, a1, a2, filter.invokeExact()); }
protected Object invoke_Y0(Object a0, Object a1, Object a2) throws Throwable {
Object[] av = { a0, a1, a2 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2]); }
}
static class F4 extends Adapter {
@ -629,7 +629,7 @@ class genclasses {
return target.invokeExact(a0, a1, a2, a3, filter.invokeExact()); }
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3) throws Throwable {
Object[] av = { a0, a1, a2, a3 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3]); }
}
static class F5 extends Adapter {
@ -698,7 +698,7 @@ class genclasses {
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
Object a4) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4]); }
}
static class F6 extends Adapter {
@ -777,7 +777,7 @@ class genclasses {
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
Object a4, Object a5) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5]); }
}
static class F7 extends Adapter {
@ -866,7 +866,7 @@ class genclasses {
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
Object a4, Object a5, Object a6) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6]); }
}
static class F8 extends Adapter {
@ -965,7 +965,7 @@ class genclasses {
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
Object a4, Object a5, Object a6, Object a7) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7]); }
}
static class F9 extends Adapter {
@ -1104,7 +1104,7 @@ class genclasses {
Object a4, Object a5, Object a6, Object a7,
Object a8) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8]); }
}
static class F10 extends Adapter {
@ -1256,7 +1256,7 @@ class genclasses {
Object a4, Object a5, Object a6, Object a7,
Object a8, Object a9) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9]); }
}
static class F11 extends Adapter {
@ -1442,7 +1442,7 @@ class genclasses {
Object a4, Object a5, Object a6, Object a7,
Object a8, Object a9, Object a10) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10]); }
}
static class F12 extends Adapter {
@ -1644,7 +1644,7 @@ class genclasses {
Object a4, Object a5, Object a6, Object a7,
Object a8, Object a9, Object a10, Object a11) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11]); }
}
static class F13 extends Adapter {
@ -1904,7 +1904,7 @@ class genclasses {
Object a8, Object a9, Object a10, Object a11,
Object a12) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12]); }
}
static class F14 extends Adapter {
@ -2183,7 +2183,7 @@ class genclasses {
Object a8, Object a9, Object a10, Object a11,
Object a12, Object a13) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13]); }
}
static class F15 extends Adapter {
@ -2481,7 +2481,7 @@ class genclasses {
Object a8, Object a9, Object a10, Object a11,
Object a12, Object a13, Object a14) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14]); }
}
static class F16 extends Adapter {
@ -2798,7 +2798,7 @@ class genclasses {
Object a8, Object a9, Object a10, Object a11,
Object a12, Object a13, Object a14, Object a15) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15]); }
}
static class F17 extends Adapter {
@ -3188,7 +3188,7 @@ class genclasses {
Object a12, Object a13, Object a14, Object a15,
Object a16) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16]); }
}
static class F18 extends Adapter {
@ -3600,7 +3600,7 @@ class genclasses {
Object a12, Object a13, Object a14, Object a15,
Object a16, Object a17) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16], av[17]); }
}
static class F19 extends Adapter {
@ -4034,7 +4034,7 @@ class genclasses {
Object a12, Object a13, Object a14, Object a15,
Object a16, Object a17, Object a18) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16], av[17], av[18]); }
}
static class F20 extends Adapter {
@ -4490,7 +4490,7 @@ class genclasses {
Object a12, Object a13, Object a14, Object a15,
Object a16, Object a17, Object a18, Object a19) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16], av[17], av[18], av[19]); }
}
}

View File

@ -36,7 +36,7 @@ import static sun.dyn.MemberName.uncaughtException;
* final method type is the responsibility of a JVM-level adapter.
* @author jrose
*/
public class FilterOneArgument extends JavaMethodHandle {
public class FilterOneArgument extends BoundMethodHandle {
protected final MethodHandle filter; // Object -> Object
protected final MethodHandle target; // Object -> Object
@ -62,7 +62,7 @@ public class FilterOneArgument extends JavaMethodHandle {
}
protected FilterOneArgument(MethodHandle filter, MethodHandle target) {
super(INVOKE);
super(Access.TOKEN, INVOKE);
this.filter = filter;
this.target = target;
}

View File

@ -241,7 +241,7 @@ class FromGeneric {
* The invoker is kept separate from the target because it can be
* generated once per type erasure family, and reused across adapters.
*/
static abstract class Adapter extends JavaMethodHandle {
static abstract class Adapter extends BoundMethodHandle {
/*
* class X<<R,int N>> extends Adapter {
* (MH, Object**N)=>raw(R) invoker;
@ -256,7 +256,7 @@ class FromGeneric {
@Override
public String toString() {
return target.toString();
return MethodHandleImpl.addTypeString(target, this);
}
protected boolean isPrototype() { return target == null; }
@ -271,7 +271,7 @@ class FromGeneric {
protected Adapter(MethodHandle entryPoint,
MethodHandle invoker, MethodHandle convert, MethodHandle target) {
super(entryPoint);
super(Access.TOKEN, entryPoint);
this.invoker = invoker;
this.convert = convert;
this.target = target;
@ -283,11 +283,11 @@ class FromGeneric {
// { return new ThisType(entryPoint, convert, target); }
/// Conversions on the value returned from the target.
protected Object convert_L(Object result) throws Throwable { return convert.<Object>invokeExact(result); }
protected Object convert_I(int result) throws Throwable { return convert.<Object>invokeExact(result); }
protected Object convert_J(long result) throws Throwable { return convert.<Object>invokeExact(result); }
protected Object convert_F(float result) throws Throwable { return convert.<Object>invokeExact(result); }
protected Object convert_D(double result) throws Throwable { return convert.<Object>invokeExact(result); }
protected Object convert_L(Object result) throws Throwable { return convert.invokeExact(result); }
protected Object convert_I(int result) throws Throwable { return convert.invokeExact(result); }
protected Object convert_J(long result) throws Throwable { return convert.invokeExact(result); }
protected Object convert_F(float result) throws Throwable { return convert.invokeExact(result); }
protected Object convert_D(double result) throws Throwable { return convert.invokeExact(result); }
static private final String CLASS_PREFIX; // "sun.dyn.FromGeneric$"
static {
@ -316,11 +316,11 @@ class FromGeneric {
{ super(e, i, c, t); }
protected xA2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new xA2(e, i, c, t); }
protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1)); }
protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1)); }
protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1)); }
protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1)); }
protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1)); }
protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1)); }
protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1)); }
protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1)); }
protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1)); }
protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1)); }
}
// */
@ -329,7 +329,8 @@ class FromGeneric {
//{{{
import java.util.*;
class genclasses {
static String[] TYPES = { "Object", "int ", "long ", "float ", "double" };
static String[] TYPES = { "Object", "int ", "long ", "float ", "double" };
static String[] WRAPS = { " ", "(Integer)", "(Long) ", "(Float) ", "(Double) " };
static String[] TCHARS = { "L", "I", "J", "F", "D", "A" };
static String[][] TEMPLATES = { {
"@for@ arity=0..10 rcat<=4 nrefs<=99 nints=0 nlongs=0",
@ -341,13 +342,13 @@ class genclasses {
" protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)",
" { return new @cat@(e, i, c, t); }",
" //@each-R@",
" protected Object invoke_@catN@(@Tvav@) throws Throwable { return convert_@Rc@(invoker.<@R@>invokeExact(target@av@)); }",
" protected Object invoke_@catN@(@Tvav@) throws Throwable { return convert_@Rc@((@R@)@W@invoker.invokeExact(target@av@)); }",
" //@end-R@",
" }",
} };
static final String NEWLINE_INDENT = "\n ";
enum VAR {
cat, catN, R, Rc, av, Tvav, Ovav;
cat, catN, R, Rc, W, av, Tvav, Ovav;
public final String pattern = "@"+toString().replace('_','.')+"@";
public String binding;
static void makeBindings(boolean topLevel, int rcat, int nrefs, int nints, int nlongs) {
@ -357,6 +358,7 @@ class genclasses {
VAR.catN.binding = catstr(rcat, nrefs, nints, nlongs);
VAR.R.binding = TYPES[rcat];
VAR.Rc.binding = TCHARS[rcat];
VAR.W.binding = WRAPS[rcat];
String[] Tv = new String[nargs];
String[] av = new String[nargs];
String[] Tvav = new String[nargs];
@ -497,11 +499,11 @@ class genclasses {
{ super(e, i, c, t); }
protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A0(e, i, c, t); }
protected Object invoke_L0() throws Throwable { return convert_L(invoker.<Object>invokeExact(target)); }
protected Object invoke_I0() throws Throwable { return convert_I(invoker.<int >invokeExact(target)); }
protected Object invoke_J0() throws Throwable { return convert_J(invoker.<long >invokeExact(target)); }
protected Object invoke_F0() throws Throwable { return convert_F(invoker.<float >invokeExact(target)); }
protected Object invoke_D0() throws Throwable { return convert_D(invoker.<double>invokeExact(target)); }
protected Object invoke_L0() throws Throwable { return convert_L((Object)invoker.invokeExact(target)); }
protected Object invoke_I0() throws Throwable { return convert_I((int) invoker.invokeExact(target)); }
protected Object invoke_J0() throws Throwable { return convert_J((long) invoker.invokeExact(target)); }
protected Object invoke_F0() throws Throwable { return convert_F((float) invoker.invokeExact(target)); }
protected Object invoke_D0() throws Throwable { return convert_D((double)invoker.invokeExact(target)); }
}
static class A1 extends Adapter {
protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
@ -509,11 +511,11 @@ class genclasses {
{ super(e, i, c, t); }
protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A1(e, i, c, t); }
protected Object invoke_L1(Object a0) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0)); }
protected Object invoke_I1(Object a0) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0)); }
protected Object invoke_J1(Object a0) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0)); }
protected Object invoke_F1(Object a0) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0)); }
protected Object invoke_D1(Object a0) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0)); }
protected Object invoke_L1(Object a0) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0)); }
protected Object invoke_I1(Object a0) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0)); }
protected Object invoke_J1(Object a0) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0)); }
protected Object invoke_F1(Object a0) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0)); }
protected Object invoke_D1(Object a0) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0)); }
}
static class A2 extends Adapter {
protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
@ -521,11 +523,11 @@ class genclasses {
{ super(e, i, c, t); }
protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A2(e, i, c, t); }
protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1)); }
protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1)); }
protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1)); }
protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1)); }
protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1)); }
protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1)); }
protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1)); }
protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1)); }
protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1)); }
protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1)); }
}
static class A3 extends Adapter {
protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
@ -533,11 +535,11 @@ class genclasses {
{ super(e, i, c, t); }
protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A3(e, i, c, t); }
protected Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2)); }
protected Object invoke_I3(Object a0, Object a1, Object a2) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2)); }
protected Object invoke_J3(Object a0, Object a1, Object a2) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2)); }
protected Object invoke_F3(Object a0, Object a1, Object a2) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2)); }
protected Object invoke_D3(Object a0, Object a1, Object a2) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2)); }
protected Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2)); }
protected Object invoke_I3(Object a0, Object a1, Object a2) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2)); }
protected Object invoke_J3(Object a0, Object a1, Object a2) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2)); }
protected Object invoke_F3(Object a0, Object a1, Object a2) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2)); }
protected Object invoke_D3(Object a0, Object a1, Object a2) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2)); }
}
static class A4 extends Adapter {
protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
@ -545,11 +547,11 @@ class genclasses {
{ super(e, i, c, t); }
protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A4(e, i, c, t); }
protected Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2, a3)); }
protected Object invoke_I4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2, a3)); }
protected Object invoke_J4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2, a3)); }
protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2, a3)); }
protected Object invoke_D4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2, a3)); }
protected Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2, a3)); }
protected Object invoke_I4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2, a3)); }
protected Object invoke_J4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2, a3)); }
protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2, a3)); }
protected Object invoke_D4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2, a3)); }
}
static class A5 extends Adapter {
protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
@ -557,11 +559,11 @@ class genclasses {
{ super(e, i, c, t); }
protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A5(e, i, c, t); }
protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4)); }
protected Object invoke_I5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2, a3, a4)); }
protected Object invoke_J5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2, a3, a4)); }
protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2, a3, a4)); }
protected Object invoke_D5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2, a3, a4)); }
protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_L((Object)invoker.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((int) invoker.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((long) invoker.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((float) invoker.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((double)invoker.invokeExact(target, a0, a1, a2, a3, a4)); }
}
static class A6 extends Adapter {
protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
@ -569,11 +571,11 @@ class genclasses {
{ super(e, i, c, t); }
protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A6(e, i, c, t); }
protected Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5)); }
protected Object invoke_I6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2, a3, a4, a5)); }
protected Object invoke_J6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2, a3, a4, a5)); }
protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2, a3, a4, a5)); }
protected Object invoke_D6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2, a3, a4, a5)); }
protected Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_L((Object)invoker.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((int) invoker.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((long) invoker.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((float) invoker.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((double)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5)); }
}
static class A7 extends Adapter {
protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
@ -581,11 +583,11 @@ class genclasses {
{ super(e, i, c, t); }
protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A7(e, i, c, t); }
protected Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
protected Object invoke_I7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
protected Object invoke_J7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
protected Object invoke_D7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
protected Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_L((Object)invoker.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((int) invoker.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((long) invoker.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((float) invoker.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((double)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
}
static class A8 extends Adapter {
protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
@ -593,11 +595,11 @@ class genclasses {
{ super(e, i, c, t); }
protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A8(e, i, c, t); }
protected Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
protected Object invoke_I8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
protected Object invoke_J8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
protected Object invoke_D8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
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((Object)invoker.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((int) invoker.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((long) invoker.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((float) invoker.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((double)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
}
static class A9 extends Adapter {
protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
@ -605,11 +607,11 @@ class genclasses {
{ super(e, i, c, t); }
protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A9(e, i, c, t); }
protected Object invoke_L9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
protected Object invoke_I9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
protected Object invoke_J9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
protected Object invoke_D9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
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((Object)invoker.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((int) invoker.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((long) invoker.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((float) invoker.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((double)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
}
static class A10 extends Adapter {
protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
@ -617,10 +619,10 @@ class genclasses {
{ super(e, i, c, t); }
protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A10(e, i, c, t); }
protected Object invoke_L10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
protected Object invoke_I10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
protected Object invoke_J10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
protected Object invoke_D10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
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((Object)invoker.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((int) invoker.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((long) invoker.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((float) invoker.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((double)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
}
}

View File

@ -0,0 +1,160 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.dyn;
import java.dyn.*;
import java.lang.reflect.*;
import sun.dyn.util.*;
/**
* Adapters which manage MethodHanndle.invokeGeneric calls.
* The JVM calls one of these when the exact type match fails.
* @author jrose
*/
class InvokeGeneric {
// erased type for the call, which originates from an invokeGeneric site
private final MethodType erasedCallerType;
// an invoker of type (MT, MH; A...) -> R
private final MethodHandle initialInvoker;
/** Compute and cache information for this adapter, so that it can
* call out to targets of the erasure-family of the given erased type.
*/
private InvokeGeneric(MethodType erasedCallerType) throws NoAccessException {
this.erasedCallerType = erasedCallerType;
this.initialInvoker = makeInitialInvoker();
assert initialInvoker.type().equals(erasedCallerType
.insertParameterTypes(0, MethodType.class, MethodHandle.class))
: initialInvoker.type();
}
private static MethodHandles.Lookup lookup() {
return MethodHandleImpl.IMPL_LOOKUP;
}
/** Return the adapter information for this type's erasure. */
static MethodHandle genericInvokerOf(MethodType type) {
MethodTypeImpl form = MethodTypeImpl.of(type);
MethodHandle genericInvoker = form.genericInvoker;
if (genericInvoker == null) {
try {
InvokeGeneric gen = new InvokeGeneric(form.erasedType());
form.genericInvoker = genericInvoker = gen.initialInvoker;
} catch (NoAccessException ex) {
throw new RuntimeException(ex);
}
}
return genericInvoker;
}
private MethodHandle makeInitialInvoker() throws NoAccessException {
// postDispatch = #(MH'; MT, MH; A...){MH'(MT, MH; A)}
MethodHandle postDispatch = makePostDispatchInvoker();
MethodHandle invoker;
if (returnConversionPossible()) {
invoker = MethodHandles.foldArguments(postDispatch,
dispatcher("dispatchWithConversion"));
} else {
invoker = MethodHandles.foldArguments(postDispatch, dispatcher("dispatch"));
}
return invoker;
}
private static final Class<?>[] EXTRA_ARGS = { MethodType.class, MethodHandle.class };
private MethodHandle makePostDispatchInvoker() {
// Take (MH'; MT, MH; A...) and run MH'(MT, MH; A...).
MethodType invokerType = erasedCallerType.insertParameterTypes(0, EXTRA_ARGS);
return MethodHandles.exactInvoker(invokerType);
}
private MethodHandle dropDispatchArguments(MethodHandle targetInvoker) {
assert(targetInvoker.type().parameterType(0) == MethodHandle.class);
return MethodHandles.dropArguments(targetInvoker, 1, EXTRA_ARGS);
}
private MethodHandle dispatcher(String dispatchName) throws NoAccessException {
return lookup().bind(this, dispatchName,
MethodType.methodType(MethodHandle.class,
MethodType.class, MethodHandle.class));
}
static final boolean USE_AS_TYPE_PATH = true;
/** Return a method handle to invoke on the callerType, target, and remaining arguments.
* The method handle must finish the call.
* This is the first look at the caller type and target.
*/
private MethodHandle dispatch(MethodType callerType, MethodHandle target) {
MethodType targetType = target.type();
if (USE_AS_TYPE_PATH || target instanceof AdapterMethodHandle.WithTypeHandler) {
MethodHandle newTarget = target.asType(callerType);
targetType = callerType;
Invokers invokers = MethodTypeImpl.invokers(Access.TOKEN, targetType);
MethodHandle invoker = invokers.erasedInvokerWithDrops;
if (invoker == null) {
invokers.erasedInvokerWithDrops = invoker =
dropDispatchArguments(invokers.erasedInvoker());
}
return invoker.bindTo(newTarget);
}
throw new RuntimeException("NYI");
}
private MethodHandle dispatchWithConversion(MethodType callerType, MethodHandle target) {
MethodHandle finisher = dispatch(callerType, target);
if (returnConversionNeeded(callerType, target))
finisher = addReturnConversion(finisher, callerType.returnType()); //FIXME: slow
return finisher;
}
private boolean returnConversionPossible() {
Class<?> needType = erasedCallerType.returnType();
return !needType.isPrimitive();
}
private boolean returnConversionNeeded(MethodType callerType, MethodHandle target) {
Class<?> needType = callerType.returnType();
if (needType == erasedCallerType.returnType())
return false; // no conversions possible, since must be primitive or Object
Class<?> haveType = target.type().returnType();
if (VerifyType.isNullConversion(haveType, needType))
return false;
return true;
}
private MethodHandle addReturnConversion(MethodHandle target, Class<?> type) {
if (true) throw new RuntimeException("NYI");
// FIXME: This is slow because it creates a closure node on every call that requires a return cast.
MethodType targetType = target.type();
MethodHandle caster = ValueConversions.identity(type);
caster = caster.asType(MethodType.methodType(type, targetType.returnType()));
// Drop irrelevant arguments, because we only care about the return value:
caster = MethodHandles.dropArguments(caster, 1, targetType.parameterList());
MethodHandle result = MethodHandles.foldArguments(caster, target);
return result.asType(target.type());
}
public String toString() {
return "InvokeGeneric"+erasedCallerType;
}
}

View File

@ -26,6 +26,7 @@
package sun.dyn;
import java.dyn.*;
import sun.dyn.empty.Empty;
/**
* Construction and caching of often-used invokers.
@ -38,12 +39,19 @@ public class Invokers {
// exact invoker for the outgoing call
private /*lazy*/ MethodHandle exactInvoker;
// erased (partially untyped but with primitives) invoker for the outgoing call
private /*lazy*/ MethodHandle erasedInvoker;
/*lazy*/ MethodHandle erasedInvokerWithDrops; // for InvokeGeneric
// generic (untyped) invoker for the outgoing call
private /*lazy*/ MethodHandle genericInvoker;
// generic (untyped) invoker for the outgoing call; accepts a single Object[]
private final /*lazy*/ MethodHandle[] varargsInvokers;
// invoker for an unbound callsite
private /*lazy*/ MethodHandle uninitializedCallSite;
/** Compute and cache information common to all collecting adapters
* that implement members of the erasure-family of the given erased type.
*/
@ -80,6 +88,19 @@ public class Invokers {
return invoker;
}
public MethodHandle erasedInvoker() {
MethodHandle invoker1 = exactInvoker();
MethodHandle invoker = erasedInvoker;
if (invoker != null) return invoker;
MethodType erasedType = targetType.erase();
if (erasedType == targetType.generic())
invoker = genericInvoker();
else
invoker = MethodHandles.convertArguments(invoker1, invokerType(erasedType));
erasedInvoker = invoker;
return invoker;
}
public MethodHandle varargsInvoker(int objectArgCount) {
MethodHandle vaInvoker = varargsInvokers[objectArgCount];
if (vaInvoker != null) return vaInvoker;
@ -90,6 +111,35 @@ public class Invokers {
return vaInvoker;
}
private static MethodHandle THROW_UCS = null;
public MethodHandle uninitializedCallSite() {
MethodHandle invoker = uninitializedCallSite;
if (invoker != null) return invoker;
if (targetType.parameterCount() > 0) {
MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount());
Invokers invokers0 = MethodTypeImpl.invokers(Access.TOKEN, type0);
invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(),
0, targetType.parameterList());
assert(invoker.type().equals(targetType));
uninitializedCallSite = invoker;
return invoker;
}
if (THROW_UCS == null) {
try {
THROW_UCS = MethodHandleImpl.IMPL_LOOKUP
.findStatic(CallSite.class, "uninitializedCallSite",
MethodType.methodType(Empty.class));
} catch (NoAccessException ex) {
throw new RuntimeException(ex);
}
}
invoker = AdapterMethodHandle.makeRetypeRaw(Access.TOKEN, targetType, THROW_UCS);
assert(invoker.type().equals(targetType));
uninitializedCallSite = invoker;
return invoker;
}
public String toString() {
return "Invokers"+targetType;
}

View File

@ -1,172 +0,0 @@
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.dyn;
import java.dyn.*;
import sun.dyn.Access;
/**
* A Java method handle is a deprecated proposal for extending
* the basic method handle type with additional
* programmer defined methods and fields.
* Its behavior as a method handle is determined at instance creation time,
* by providing the new instance with an "entry point" method handle
* to handle calls. This entry point must accept a leading argument
* whose type is the Java method handle itself or a supertype, and the
* entry point is always called with the Java method handle itself as
* the first argument. This is similar to ordinary virtual methods, which also
* accept the receiver object {@code this} as an implicit leading argument.
* The {@code MethodType} of the Java method handle is the same as that
* of the entry point method handle, with the leading parameter type
* omitted.
* <p>
* Here is an example of usage, creating a hybrid object/functional datum:
* <p><blockquote><pre>
* class Greeter extends JavaMethodHandle {
* private String greeting = "hello";
* public void setGreeting(String s) { greeting = s; }
* public void run() { System.out.println(greeting+", "+greetee); }
* private final String greetee;
* Greeter(String greetee) {
* super(RUN); // alternatively, super("run")
* this.greetee = greetee;
* }
* // the entry point function is computed once:
* private static final MethodHandle RUN
* = MethodHandles.lookup().findVirtual(Greeter.class, "run",
* MethodType.make(void.class));
* }
* // class Main { public static void main(String... av) { ...
* Greeter greeter = new Greeter("world");
* greeter.run(); // prints "hello, world"
* // Statically typed method handle invocation (most direct):
* MethodHandle mh = greeter;
* mh.&lt;void&gt;invokeExact(); // also prints "hello, world"
* // Dynamically typed method handle invocation:
* MethodHandles.invokeExact(greeter); // also prints "hello, world"
* greeter.setGreeting("howdy");
* mh.invokeExact(); // prints "howdy, world" (object-like mutable behavior)
* </pre></blockquote>
* <p>
* In the example of {@code Greeter}, the method {@code run} provides the entry point.
* The entry point need not be a constant value; it may be independently
* computed in each call to the constructor. The entry point does not
* even need to be a method on the {@code Greeter} class, though
* that is the typical case.
* <p>
* The entry point may also be provided symbolically, in which case the the
* {@code JavaMethodHandle} constructor performs the lookup of the entry point.
* This makes it possible to use {@code JavaMethodHandle} to create an anonymous
* inner class:
* <p><blockquote><pre>
* // We can also do this with symbolic names and/or inner classes:
* MethodHandles.invokeExact(new JavaMethodHandle("yow") {
* void yow() { System.out.println("yow, world"); }
* });
* </pre></blockquote>
* <p>
* Here is similar lower-level code which works in terms of a bound method handle.
* <p><blockquote><pre>
* class Greeter {
* public void run() { System.out.println("hello, "+greetee); }
* private final String greetee;
* Greeter(String greetee) { this.greetee = greetee; }
* // the entry point function is computed once:
* private static final MethodHandle RUN
* = MethodHandles.findVirtual(Greeter.class, "run",
* MethodType.make(void.class));
* }
* // class Main { public static void main(String... av) { ...
* Greeter greeter = new Greeter("world");
* greeter.run(); // prints "hello, world"
* MethodHandle mh = MethodHanndles.insertArgument(Greeter.RUN, 0, greeter);
* mh.invokeExact(); // also prints "hello, world"
* </pre></blockquote>
* Note that the method handle must be separately created as a view on the base object.
* This increases footprint, complexity, and dynamic indirections.
* <p>
* Here is a pure functional value expressed most concisely as an anonymous inner class:
* <p><blockquote><pre>
* // class Main { public static void main(String... av) { ...
* final String greetee = "world";
* MethodHandle greeter = new JavaMethodHandle("run") {
* private void run() { System.out.println("hello, "+greetee); }
* }
* greeter.invokeExact(); // prints "hello, world"
* </pre></blockquote>
* <p>
* Here is an abstract parameterized lvalue, efficiently expressed as a subtype of MethodHandle,
* and instantiated as an anonymous class. The data structure is a handle to 1-D array,
* with a specialized index type (long). It is created by inner class, and uses
* signature-polymorphic APIs throughout.
* <p><blockquote><pre>
* abstract class AssignableMethodHandle extends JavaMethodHandle {
* private final MethodHandle setter;
* public MethodHandle setter() { return setter; }
* public AssignableMethodHandle(String get, String set) {
* super(get);
* MethodType getType = this.type();
* MethodType setType = getType.insertParameterType(getType.parameterCount(), getType.returnType()).changeReturnType(void.class);
* this.setter = MethodHandles.publicLookup().bind(this, set, setType);
* }
* }
* // class Main { public static void main(String... av) { ...
* final Number[] stuff = { 123, 456 };
* AssignableMethodHandle stuffPtr = new AssignableMethodHandle("get", "set") {
* public Number get(long i) { return stuff[(int)i]; }
* public void set(long i, Object x) { stuff[(int)i] = x; }
* }
* int x = (Integer) stuffPtr.&lt;Number&gt;invokeExact(1L); // 456
* stuffPtr.setter().&lt;void&gt;invokeExact(0L, (Number) 789); // replaces 123 with 789
* </pre></blockquote>
* @see MethodHandle
* @deprecated The JSR 292 EG intends to replace {@code JavaMethodHandle} with
* an interface-based API for mixing method handle behavior with other classes.
* @author John Rose, JSR 292 EG
*/
public abstract class JavaMethodHandle
// Note: This is an implementation inheritance hack, and will be removed
// with a JVM change which moves the required hidden behavior onto this class.
extends sun.dyn.BoundMethodHandle
{
private static final Access IMPL_TOKEN = Access.getToken();
/**
* When creating a {@code JavaMethodHandle}, the actual method handle
* invocation behavior will be delegated to the specified {@code entryPoint}.
* This may be any method handle which can take the newly constructed object
* as a leading parameter.
* <p>
* The method handle type of {@code this} (i.e, the fully constructed object)
* will be {@code entryPoint}, minus the leading argument.
* The leading argument will be bound to {@code this} on every method
* handle invocation.
* @param entryPoint the method handle to handle calls
*/
protected JavaMethodHandle(MethodHandle entryPoint) {
super(entryPoint);
}
}

View File

@ -199,7 +199,7 @@ public abstract class MethodHandleImpl {
return allocator;
}
static final class AllocateObject<C> extends JavaMethodHandle {
static final class AllocateObject<C> extends BoundMethodHandle {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private final Class<C> allocateClass;
@ -207,7 +207,7 @@ public abstract class MethodHandleImpl {
private AllocateObject(MethodHandle invoker,
Class<C> allocateClass, MethodHandle rawConstructor) {
super(invoker);
super(Access.TOKEN, invoker);
this.allocateClass = allocateClass;
this.rawConstructor = rawConstructor;
}
@ -237,7 +237,7 @@ public abstract class MethodHandleImpl {
}
@Override
public String toString() {
return allocateClass.getSimpleName();
return addTypeString(allocateClass.getSimpleName(), this);
}
@SuppressWarnings("unchecked")
private C allocate() throws InstantiationException {
@ -245,52 +245,52 @@ public abstract class MethodHandleImpl {
}
private C invoke_V(Object... av) throws Throwable {
C obj = allocate();
rawConstructor.<void>invokeExact((Object)obj, av);
rawConstructor.invokeExact((Object)obj, av);
return obj;
}
private C invoke_L0() throws Throwable {
C obj = allocate();
rawConstructor.<void>invokeExact((Object)obj);
rawConstructor.invokeExact((Object)obj);
return obj;
}
private C invoke_L1(Object a0) throws Throwable {
C obj = allocate();
rawConstructor.<void>invokeExact((Object)obj, a0);
rawConstructor.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);
rawConstructor.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);
rawConstructor.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);
rawConstructor.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);
rawConstructor.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);
rawConstructor.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);
rawConstructor.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);
rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4, a5, a6, a7);
return obj;
}
static MethodHandle[] makeInvokes() {
@ -369,19 +369,19 @@ public abstract class MethodHandleImpl {
return mhs[isSetter ? 1 : 0];
}
static final class FieldAccessor<C,V> extends JavaMethodHandle {
static final class FieldAccessor<C,V> extends BoundMethodHandle {
private static final Unsafe unsafe = Unsafe.getUnsafe();
final Object base; // for static refs only
final long offset;
final String name;
public FieldAccessor(Access token, MemberName field, boolean isSetter) {
super(fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic()));
super(Access.TOKEN, fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic()));
this.offset = (long) field.getVMIndex(token);
this.name = field.getName();
this.base = staticBase(field);
}
public String toString() { return name; }
public String toString() { return addTypeString(name, this); }
int getFieldI(C obj) { return unsafe.getInt(obj, offset); }
void setFieldI(C obj, int x) { unsafe.putInt(obj, offset, x); }
@ -560,7 +560,9 @@ public abstract class MethodHandleImpl {
MethodHandle bindReceiver(Access token,
MethodHandle target, Object receiver) {
Access.check(token);
if (target instanceof AdapterMethodHandle) {
if (target instanceof AdapterMethodHandle &&
((AdapterMethodHandle)target).conversionOp() == MethodHandleNatives.Constants.OP_RETYPE_ONLY
) {
Object info = MethodHandleNatives.getTargetInfo(target);
if (info instanceof DirectMethodHandle) {
DirectMethodHandle dmh = (DirectMethodHandle) info;
@ -908,11 +910,11 @@ public abstract class MethodHandleImpl {
throw new UnsupportedOperationException("NYI");
}
private static class GuardWithTest extends JavaMethodHandle {
private static class GuardWithTest extends BoundMethodHandle {
private final MethodHandle test, target, fallback;
private GuardWithTest(MethodHandle invoker,
MethodHandle test, MethodHandle target, MethodHandle fallback) {
super(invoker);
super(Access.TOKEN, invoker);
this.test = test;
this.target = target;
this.fallback = fallback;
@ -946,57 +948,57 @@ public abstract class MethodHandleImpl {
}
@Override
public String toString() {
return target.toString();
return addTypeString(target, this);
}
private Object invoke_V(Object... av) throws Throwable {
if (test.<boolean>invokeExact(av))
return target.<Object>invokeExact(av);
return fallback.<Object>invokeExact(av);
if ((boolean) test.invokeExact(av))
return target.invokeExact(av);
return fallback.invokeExact(av);
}
private Object invoke_L0() throws Throwable {
if (test.<boolean>invokeExact())
return target.<Object>invokeExact();
return fallback.<Object>invokeExact();
if ((boolean) test.invokeExact())
return target.invokeExact();
return fallback.invokeExact();
}
private Object invoke_L1(Object a0) throws Throwable {
if (test.<boolean>invokeExact(a0))
return target.<Object>invokeExact(a0);
return fallback.<Object>invokeExact(a0);
if ((boolean) test.invokeExact(a0))
return target.invokeExact(a0);
return fallback.invokeExact(a0);
}
private Object invoke_L2(Object a0, Object a1) throws Throwable {
if (test.<boolean>invokeExact(a0, a1))
return target.<Object>invokeExact(a0, a1);
return fallback.<Object>invokeExact(a0, a1);
if ((boolean) test.invokeExact(a0, a1))
return target.invokeExact(a0, a1);
return fallback.invokeExact(a0, a1);
}
private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
if (test.<boolean>invokeExact(a0, a1, a2))
return target.<Object>invokeExact(a0, a1, a2);
return fallback.<Object>invokeExact(a0, a1, a2);
if ((boolean) test.invokeExact(a0, a1, a2))
return target.invokeExact(a0, a1, a2);
return fallback.invokeExact(a0, a1, a2);
}
private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
if (test.<boolean>invokeExact(a0, a1, a2, a3))
return target.<Object>invokeExact(a0, a1, a2, a3);
return fallback.<Object>invokeExact(a0, a1, a2, a3);
if ((boolean) test.invokeExact(a0, a1, a2, a3))
return target.invokeExact(a0, a1, a2, a3);
return fallback.invokeExact(a0, a1, a2, a3);
}
private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
if (test.<boolean>invokeExact(a0, a1, a2, a3, a4))
return target.<Object>invokeExact(a0, a1, a2, a3, a4);
return fallback.<Object>invokeExact(a0, a1, a2, a3, a4);
if ((boolean) test.invokeExact(a0, a1, a2, a3, a4))
return target.invokeExact(a0, a1, a2, a3, a4);
return fallback.invokeExact(a0, a1, a2, a3, a4);
}
private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
if (test.<boolean>invokeExact(a0, a1, a2, a3, a4, a5))
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5);
return fallback.<Object>invokeExact(a0, a1, a2, a3, a4, a5);
if ((boolean) test.invokeExact(a0, a1, a2, a3, a4, a5))
return target.invokeExact(a0, a1, a2, a3, a4, a5);
return fallback.invokeExact(a0, a1, a2, a3, a4, a5);
}
private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
if (test.<boolean>invokeExact(a0, a1, a2, a3, a4, a5, a6))
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6);
return fallback.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6);
if ((boolean) test.invokeExact(a0, a1, a2, a3, a4, a5, a6))
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
return fallback.invokeExact(a0, a1, a2, a3, a4, a5, a6);
}
private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
if (test.<boolean>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7))
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
return fallback.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
if ((boolean) test.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7))
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
return fallback.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
}
static MethodHandle[] makeInvokes() {
ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
@ -1036,7 +1038,7 @@ public abstract class MethodHandleImpl {
return GuardWithTest.make(token, test, target, fallback);
}
private static class GuardWithCatch extends JavaMethodHandle {
private static class GuardWithCatch extends BoundMethodHandle {
private final MethodHandle target;
private final Class<? extends Throwable> exType;
private final MethodHandle catcher;
@ -1045,93 +1047,93 @@ public abstract class MethodHandleImpl {
}
public GuardWithCatch(MethodHandle invoker,
MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
super(invoker);
super(Access.TOKEN, invoker);
this.target = target;
this.exType = exType;
this.catcher = catcher;
}
@Override
public String toString() {
return target.toString();
return addTypeString(target, this);
}
private Object invoke_V(Object... av) throws Throwable {
try {
return target.<Object>invokeExact(av);
return target.invokeExact(av);
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invokeExact(t, av);
return catcher.invokeExact(t, av);
}
}
private Object invoke_L0() throws Throwable {
try {
return target.<Object>invokeExact();
return target.invokeExact();
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invokeExact(t);
return catcher.invokeExact(t);
}
}
private Object invoke_L1(Object a0) throws Throwable {
try {
return target.<Object>invokeExact(a0);
return target.invokeExact(a0);
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invokeExact(t, a0);
return catcher.invokeExact(t, a0);
}
}
private Object invoke_L2(Object a0, Object a1) throws Throwable {
try {
return target.<Object>invokeExact(a0, a1);
return target.invokeExact(a0, a1);
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invokeExact(t, a0, a1);
return catcher.invokeExact(t, a0, a1);
}
}
private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
try {
return target.<Object>invokeExact(a0, a1, a2);
return target.invokeExact(a0, a1, a2);
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invokeExact(t, a0, a1, a2);
return catcher.invokeExact(t, a0, a1, a2);
}
}
private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
try {
return target.<Object>invokeExact(a0, a1, a2, a3);
return target.invokeExact(a0, a1, a2, a3);
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invokeExact(t, a0, a1, a2, a3);
return catcher.invokeExact(t, a0, a1, a2, a3);
}
}
private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
try {
return target.<Object>invokeExact(a0, a1, a2, a3, a4);
return target.invokeExact(a0, a1, a2, a3, a4);
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invokeExact(t, a0, a1, a2, a3, a4);
return catcher.invokeExact(t, a0, a1, a2, a3, a4);
}
}
private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
try {
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5);
return target.invokeExact(a0, a1, a2, a3, a4, a5);
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invokeExact(t, a0, a1, a2, a3, a4, a5);
return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5);
}
}
private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
try {
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6);
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
}
}
private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
try {
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
} catch (Throwable t) {
if (!exType.isInstance(t)) throw t;
return catcher.<Object>invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
}
}
static MethodHandle[] makeInvokes() {
@ -1217,21 +1219,24 @@ public abstract class MethodHandleImpl {
if (target != null)
name = MethodHandleNatives.getMethodName(target);
if (name == null)
return "<unknown>";
return name.getName();
return "invoke" + target.type();
return name.getName() + target.type();
}
public static String addTypeString(MethodHandle target) {
if (target == null) return "null";
return target.toString() + target.type();
static String addTypeString(Object obj, MethodHandle target) {
String str = String.valueOf(obj);
if (target == null) return str;
int paren = str.indexOf('(');
if (paren >= 0) str = str.substring(0, paren);
return str + target.type();
}
public static void checkSpreadArgument(Object av, int n) {
static void checkSpreadArgument(Object av, int n) {
if (av == null ? n != 0 : ((Object[])av).length != n)
throw newIllegalArgumentException("Array is not of length "+n);
}
public static void raiseException(int code, Object actual, Object required) {
static void raiseException(int code, Object actual, Object required) {
String message;
// disregard the identity of the actual object, if it is not a class:
if (!(actual instanceof Class) && !(actual instanceof MethodType))
@ -1257,4 +1262,9 @@ public abstract class MethodHandleImpl {
Access.check(token);
return MethodHandleNatives.getBootstrap(callerClass);
}
public static MethodHandle withTypeHandler(Access token, MethodHandle target, MethodHandle typeHandler) {
Access.check(token);
return AdapterMethodHandle.makeTypeHandler(token, target, typeHandler);
}
}

View File

@ -316,6 +316,20 @@ class MethodHandleNatives {
return MethodTypeImpl.makeImpl(Access.TOKEN, rtype, ptypes, true);
}
/**
* The JVM wants to use a MethodType with invokeGeneric. Give the runtime fair warning.
*/
static void notifyGenericMethodType(MethodType type) {
try {
// Trigger adapter creation.
InvokeGeneric.genericInvokerOf(type);
} catch (Exception ex) {
Error err = new InternalError("Exception while resolving invokeGeneric");
err.initCause(ex);
throw err;
}
}
/**
* The JVM is resolving a CONSTANT_MethodHandle CP entry. And it wants our help.
* It will make an up-call to this method. (Do not change the name or signature.)

View File

@ -48,6 +48,7 @@ public class MethodTypeImpl {
final long primCounts; // packed prim & double counts
final int vmslots; // total number of parameter slots
final MethodType erasedType; // the canonical erasure
/*lazy*/ MethodType primsAsBoxes; // replace prims by wrappers
/*lazy*/ MethodType primArgsAsBoxes; // wrap args only; make raw return
/*lazy*/ MethodType primsAsInts; // replace prims by int/long
@ -59,6 +60,7 @@ public class MethodTypeImpl {
/*lazy*/ FromGeneric fromGeneric; // convert cs. w/o prims to with
/*lazy*/ SpreadGeneric[] spreadGeneric; // expand one argument to many
/*lazy*/ FilterGeneric filterGeneric; // convert argument(s) on the fly
/*lazy*/ MethodHandle genericInvoker; // hook for invokeGeneric
public MethodType erasedType() {
return erasedType;

View File

@ -208,7 +208,7 @@ class SpreadGeneric {
* The invoker is kept separate from the target because it can be
* generated once per type erasure family, and reused across adapters.
*/
static abstract class Adapter extends JavaMethodHandle {
static abstract class Adapter extends BoundMethodHandle {
/*
* class X<<R,int M,int N>> extends Adapter {
* (Object**N)=>R target;
@ -221,21 +221,21 @@ class SpreadGeneric {
@Override
public String toString() {
return target.toString();
return MethodHandleImpl.addTypeString(target, this);
}
static final MethodHandle NO_ENTRY = ValueConversions.identity();
protected boolean isPrototype() { return target == null; }
protected Adapter(SpreadGeneric outer) {
super(NO_ENTRY);
super(Access.TOKEN, NO_ENTRY);
this.outer = outer;
this.target = null;
assert(isPrototype());
}
protected Adapter(SpreadGeneric outer, MethodHandle target) {
super(outer.entryPoint);
super(Access.TOKEN, outer.entryPoint);
this.outer = outer;
this.target = target;
}
@ -277,12 +277,12 @@ class SpreadGeneric {
protected xS2(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
protected xS2 makeInstance(SpreadGeneric outer, MethodHandle t) { return new xS2(outer, t); }
protected Object invoke_S0(Object a0, Object a1, Object av) throws Throwable { av = super.check(av,0);
return target.<Object>invokeExact(a0, a1)); }
return target.invokeExact(a0, a1)); }
protected Object invoke_S1(Object a0, Object av) throws Throwable { av = super.check(av,1);
return target.<Object>invokeExact(a0,
return target.invokeExact(a0,
super.select(av,0)); }
protected Object invoke_S2(Object a0, Object av) throws Throwable { av = super.check(av,1);
return target.<Object>invokeExact(
return target.invokeExact(
super.select(av,0), super.select(av,1)); }
}
// */
@ -300,10 +300,10 @@ class genclasses {
" protected @cat@(SpreadGeneric outer, MethodHandle t) { super(outer, t); }",
" protected @cat@ makeInstance(SpreadGeneric outer, MethodHandle t) { return new @cat@(outer, t); }",
" protected Object invoke_S0(@Tvav,@Object av) throws Throwable { av = super.check(av, 0);",
" return target.<Object>invokeExact(@av@); }",
" return target.invokeExact(@av@); }",
" //@each-S@",
" protected Object invoke_S@S@(@Tvav,@Object av) throws Throwable { av = super.check(av, @S@);",
" return target.<Object>invokeExact(@av,@@sv@); }",
" return target.invokeExact(@av,@@sv@); }",
" //@end-S@",
" }",
} };
@ -414,16 +414,16 @@ class genclasses {
protected S0(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
protected S0 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S0(outer, t); }
protected Object invoke_S0(Object av) throws Throwable { av = super.check(av, 0);
return target.<Object>invokeExact(); }
return target.invokeExact(); }
}
static class S1 extends Adapter {
protected S1(SpreadGeneric outer) { super(outer); } // to build prototype
protected S1(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
protected S1 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S1(outer, t); }
protected Object invoke_S0(Object a0, Object av) throws Throwable { av = super.check(av, 0);
return target.<Object>invokeExact(a0); }
return target.invokeExact(a0); }
protected Object invoke_S1(Object av) throws Throwable { av = super.check(av, 1);
return target.<Object>invokeExact(
return target.invokeExact(
super.select(av,0)); }
}
static class S2 extends Adapter {
@ -431,12 +431,12 @@ class genclasses {
protected S2(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
protected S2 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S2(outer, t); }
protected Object invoke_S0(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 0);
return target.<Object>invokeExact(a0, a1); }
return target.invokeExact(a0, a1); }
protected Object invoke_S1(Object a0, Object av) throws Throwable { av = super.check(av, 1);
return target.<Object>invokeExact(a0,
return target.invokeExact(a0,
super.select(av,0)); }
protected Object invoke_S2(Object av) throws Throwable { av = super.check(av, 2);
return target.<Object>invokeExact(
return target.invokeExact(
super.select(av,0), super.select(av,1)); }
}
static class S3 extends Adapter {
@ -444,15 +444,15 @@ class genclasses {
protected S3(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
protected S3 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S3(outer, t); }
protected Object invoke_S0(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 0);
return target.<Object>invokeExact(a0, a1, a2); }
return target.invokeExact(a0, a1, a2); }
protected Object invoke_S1(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 1);
return target.<Object>invokeExact(a0, a1,
return target.invokeExact(a0, a1,
super.select(av,0)); }
protected Object invoke_S2(Object a0, Object av) throws Throwable { av = super.check(av, 2);
return target.<Object>invokeExact(a0,
return target.invokeExact(a0,
super.select(av,0), super.select(av,1)); }
protected Object invoke_S3(Object av) throws Throwable { av = super.check(av, 3);
return target.<Object>invokeExact(
return target.invokeExact(
super.select(av,0), super.select(av,1), super.select(av,2)); }
}
static class S4 extends Adapter {
@ -460,18 +460,18 @@ class genclasses {
protected S4(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
protected S4 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S4(outer, t); }
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 0);
return target.<Object>invokeExact(a0, a1, a2, a3); }
return target.invokeExact(a0, a1, a2, a3); }
protected Object invoke_S1(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 1);
return target.<Object>invokeExact(a0, a1, a2,
return target.invokeExact(a0, a1, a2,
super.select(av,0)); }
protected Object invoke_S2(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 2);
return target.<Object>invokeExact(a0, a1,
return target.invokeExact(a0, a1,
super.select(av,0), super.select(av,1)); }
protected Object invoke_S3(Object a0, Object av) throws Throwable { av = super.check(av, 3);
return target.<Object>invokeExact(a0,
return target.invokeExact(a0,
super.select(av,0), super.select(av,1), super.select(av,2)); }
protected Object invoke_S4(Object av) throws Throwable { av = super.check(av, 4);
return target.<Object>invokeExact(
return target.invokeExact(
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
}
static class S5 extends Adapter {
@ -479,21 +479,21 @@ class genclasses {
protected S5(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
protected S5 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S5(outer, t); }
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 0);
return target.<Object>invokeExact(a0, a1, a2, a3, a4); }
return target.invokeExact(a0, a1, a2, a3, a4); }
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 1);
return target.<Object>invokeExact(a0, a1, a2, a3,
return target.invokeExact(a0, a1, a2, a3,
super.select(av,0)); }
protected Object invoke_S2(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 2);
return target.<Object>invokeExact(a0, a1, a2,
return target.invokeExact(a0, a1, a2,
super.select(av,0), super.select(av,1)); }
protected Object invoke_S3(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 3);
return target.<Object>invokeExact(a0, a1,
return target.invokeExact(a0, a1,
super.select(av,0), super.select(av,1), super.select(av,2)); }
protected Object invoke_S4(Object a0, Object av) throws Throwable { av = super.check(av, 4);
return target.<Object>invokeExact(a0,
return target.invokeExact(a0,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
protected Object invoke_S5(Object av) throws Throwable { av = super.check(av, 5);
return target.<Object>invokeExact(
return target.invokeExact(
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4)); }
}
@ -502,25 +502,25 @@ class genclasses {
protected S6(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
protected S6 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S6(outer, t); }
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 0);
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5); }
return target.invokeExact(a0, a1, a2, a3, a4, a5); }
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 1);
return target.<Object>invokeExact(a0, a1, a2, a3, a4,
return target.invokeExact(a0, a1, a2, a3, a4,
super.select(av,0)); }
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 2);
return target.<Object>invokeExact(a0, a1, a2, a3,
return target.invokeExact(a0, a1, a2, a3,
super.select(av,0), super.select(av,1)); }
protected Object invoke_S3(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 3);
return target.<Object>invokeExact(a0, a1, a2,
return target.invokeExact(a0, a1, a2,
super.select(av,0), super.select(av,1), super.select(av,2)); }
protected Object invoke_S4(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 4);
return target.<Object>invokeExact(a0, a1,
return target.invokeExact(a0, a1,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
protected Object invoke_S5(Object a0, Object av) throws Throwable { av = super.check(av, 5);
return target.<Object>invokeExact(a0,
return target.invokeExact(a0,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4)); }
protected Object invoke_S6(Object av) throws Throwable { av = super.check(av, 6);
return target.<Object>invokeExact(
return target.invokeExact(
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5)); }
}
@ -529,29 +529,29 @@ class genclasses {
protected S7(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
protected S7 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S7(outer, t); }
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 0);
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6); }
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6); }
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 1);
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5,
return target.invokeExact(a0, a1, a2, a3, a4, a5,
super.select(av,0)); }
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 2);
return target.<Object>invokeExact(a0, a1, a2, a3, a4,
return target.invokeExact(a0, a1, a2, a3, a4,
super.select(av,0), super.select(av,1)); }
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 3);
return target.<Object>invokeExact(a0, a1, a2, a3,
return target.invokeExact(a0, a1, a2, a3,
super.select(av,0), super.select(av,1), super.select(av,2)); }
protected Object invoke_S4(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 4);
return target.<Object>invokeExact(a0, a1, a2,
return target.invokeExact(a0, a1, a2,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
protected Object invoke_S5(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 5);
return target.<Object>invokeExact(a0, a1,
return target.invokeExact(a0, a1,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4)); }
protected Object invoke_S6(Object a0, Object av) throws Throwable { av = super.check(av, 6);
return target.<Object>invokeExact(a0,
return target.invokeExact(a0,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5)); }
protected Object invoke_S7(Object av) throws Throwable { av = super.check(av, 7);
return target.<Object>invokeExact(
return target.invokeExact(
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5), super.select(av,6)); }
}
@ -560,33 +560,33 @@ class genclasses {
protected S8(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
protected S8 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S8(outer, t); }
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object av) throws Throwable { av = super.check(av, 0);
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7); }
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7); }
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 1);
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6,
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6,
super.select(av,0)); }
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 2);
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5,
return target.invokeExact(a0, a1, a2, a3, a4, a5,
super.select(av,0), super.select(av,1)); }
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 3);
return target.<Object>invokeExact(a0, a1, a2, a3, a4,
return target.invokeExact(a0, a1, a2, a3, a4,
super.select(av,0), super.select(av,1), super.select(av,2)); }
protected Object invoke_S4(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 4);
return target.<Object>invokeExact(a0, a1, a2, a3,
return target.invokeExact(a0, a1, a2, a3,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
protected Object invoke_S5(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 5);
return target.<Object>invokeExact(a0, a1, a2,
return target.invokeExact(a0, a1, a2,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4)); }
protected Object invoke_S6(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 6);
return target.<Object>invokeExact(a0, a1,
return target.invokeExact(a0, a1,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5)); }
protected Object invoke_S7(Object a0, Object av) throws Throwable { av = super.check(av, 7);
return target.<Object>invokeExact(a0,
return target.invokeExact(a0,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5), super.select(av,6)); }
protected Object invoke_S8(Object av) throws Throwable { av = super.check(av, 8);
return target.<Object>invokeExact(
return target.invokeExact(
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7)); }
}
@ -595,37 +595,37 @@ class genclasses {
protected S9(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
protected S9 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S9(outer, t); }
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object av) throws Throwable { av = super.check(av, 0);
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object av) throws Throwable { av = super.check(av, 1);
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7,
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7,
super.select(av,0)); }
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 2);
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6,
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6,
super.select(av,0), super.select(av,1)); }
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 3);
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5,
return target.invokeExact(a0, a1, a2, a3, a4, a5,
super.select(av,0), super.select(av,1), super.select(av,2)); }
protected Object invoke_S4(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 4);
return target.<Object>invokeExact(a0, a1, a2, a3, a4,
return target.invokeExact(a0, a1, a2, a3, a4,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
protected Object invoke_S5(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 5);
return target.<Object>invokeExact(a0, a1, a2, a3,
return target.invokeExact(a0, a1, a2, a3,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4)); }
protected Object invoke_S6(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 6);
return target.<Object>invokeExact(a0, a1, a2,
return target.invokeExact(a0, a1, a2,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5)); }
protected Object invoke_S7(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 7);
return target.<Object>invokeExact(a0, a1,
return target.invokeExact(a0, a1,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5), super.select(av,6)); }
protected Object invoke_S8(Object a0, Object av) throws Throwable { av = super.check(av, 8);
return target.<Object>invokeExact(a0,
return target.invokeExact(a0,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7)); }
protected Object invoke_S9(Object av) throws Throwable { av = super.check(av, 9);
return target.<Object>invokeExact(
return target.invokeExact(
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7),
super.select(av,8)); }
@ -635,42 +635,42 @@ class genclasses {
protected S10(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
protected S10 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S10(outer, t); }
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9, Object av) throws Throwable { av = super.check(av, 0);
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object av) throws Throwable { av = super.check(av, 1);
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7, a8,
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7, a8,
super.select(av,0)); }
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object av) throws Throwable { av = super.check(av, 2);
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7,
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7,
super.select(av,0), super.select(av,1)); }
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 3);
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6,
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6,
super.select(av,0), super.select(av,1), super.select(av,2)); }
protected Object invoke_S4(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 4);
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5,
return target.invokeExact(a0, a1, a2, a3, a4, a5,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
protected Object invoke_S5(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 5);
return target.<Object>invokeExact(a0, a1, a2, a3, a4,
return target.invokeExact(a0, a1, a2, a3, a4,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4)); }
protected Object invoke_S6(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 6);
return target.<Object>invokeExact(a0, a1, a2, a3,
return target.invokeExact(a0, a1, a2, a3,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5)); }
protected Object invoke_S7(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 7);
return target.<Object>invokeExact(a0, a1, a2,
return target.invokeExact(a0, a1, a2,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5), super.select(av,6)); }
protected Object invoke_S8(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 8);
return target.<Object>invokeExact(a0, a1,
return target.invokeExact(a0, a1,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7)); }
protected Object invoke_S9(Object a0, Object av) throws Throwable { av = super.check(av, 9);
return target.<Object>invokeExact(a0,
return target.invokeExact(a0,
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7),
super.select(av,8)); }
protected Object invoke_S10(Object av) throws Throwable { av = super.check(av, 10);
return target.<Object>invokeExact(
return target.invokeExact(
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7),
super.select(av,8), super.select(av,9)); }

View File

@ -323,7 +323,7 @@ class ToGeneric {
* via another method handle {@code convert}, which is responsible for
* converting the object result into the raw return value.
*/
static abstract class Adapter extends JavaMethodHandle {
static abstract class Adapter extends BoundMethodHandle {
/*
* class X<<R,A...>> extends Adapter {
* Object...=>Object target;
@ -337,13 +337,13 @@ class ToGeneric {
@Override
public String toString() {
return target == null ? "prototype:"+convert : target.toString();
return target == null ? "prototype:"+convert : MethodHandleImpl.addTypeString(target, this);
}
protected boolean isPrototype() { return target == null; }
/* Prototype constructor. */
protected Adapter(MethodHandle entryPoint) {
super(entryPoint);
super(Access.TOKEN, entryPoint);
this.invoker = null;
this.convert = entryPoint;
this.target = null;
@ -355,7 +355,7 @@ class ToGeneric {
}
protected Adapter(MethodHandle entryPoint, MethodHandle invoker, MethodHandle convert, MethodHandle target) {
super(entryPoint);
super(Access.TOKEN, entryPoint);
this.invoker = invoker;
this.convert = convert;
this.target = target;
@ -367,33 +367,33 @@ class ToGeneric {
// { return new ThisType(entryPoint, convert, target); }
// Code to run when the arguments (<= 4) have all been boxed.
protected Object target() throws Throwable { return invoker.<Object>invokeExact(target); }
protected Object target(Object a0) throws Throwable { return invoker.<Object>invokeExact(target, a0); }
protected Object target() throws Throwable { return invoker.invokeExact(target); }
protected Object target(Object a0) throws Throwable { return invoker.invokeExact(target, a0); }
protected Object target(Object a0, Object a1)
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1); }
throws Throwable { return invoker.invokeExact(target, a0, a1); }
protected Object target(Object a0, Object a1, Object a2)
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2); }
throws Throwable { return invoker.invokeExact(target, a0, a1, a2); }
protected Object target(Object a0, Object a1, Object a2, Object a3)
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3); }
throws Throwable { return invoker.invokeExact(target, a0, a1, a2, a3); }
/*
protected Object target_0(Object... av) throws Throwable { return invoker.<Object>invokeExact(target, av); }
protected Object target_0(Object... av) throws Throwable { return invoker.invokeExact(target, av); }
protected Object target_1(Object a0, Object... av)
throws Throwable { return invoker.<Object>invokeExact(target, a0, (Object)av); }
throws Throwable { return invoker.invokeExact(target, a0, (Object)av); }
protected Object target_2(Object a0, Object a1, Object... av)
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, (Object)av); }
throws Throwable { return invoker.invokeExact(target, a0, a1, (Object)av); }
protected Object target_3(Object a0, Object a1, Object a2, Object... av)
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, (Object)av); }
throws Throwable { return invoker.invokeExact(target, a0, a1, a2, (Object)av); }
protected Object target_4(Object a0, Object a1, Object a2, Object a3, Object... av)
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, (Object)av); }
throws Throwable { return invoker.invokeExact(target, a0, a1, a2, a3, (Object)av); }
// */
// (For more than 4 arguments, generate the code in the adapter itself.)
// Code to run when the generic target has finished and produced a value.
protected Object return_L(Object res) throws Throwable { return convert.<Object>invokeExact(res); }
protected int return_I(Object res) throws Throwable { return convert.<int >invokeExact(res); }
protected long return_J(Object res) throws Throwable { return convert.<long >invokeExact(res); }
protected float return_F(Object res) throws Throwable { return convert.<float >invokeExact(res); }
protected double return_D(Object res) throws Throwable { return convert.<double>invokeExact(res); }
protected Object return_L(Object res) throws Throwable { return (Object)convert.invokeExact(res); }
protected int return_I(Object res) throws Throwable { return (int) convert.invokeExact(res); }
protected long return_J(Object res) throws Throwable { return (long) convert.invokeExact(res); }
protected float return_F(Object res) throws Throwable { return (float) convert.invokeExact(res); }
protected double return_D(Object res) throws Throwable { return (double)convert.invokeExact(res); }
static private final String CLASS_PREFIX; // "sun.dyn.ToGeneric$"
static {
@ -420,7 +420,7 @@ class ToGeneric {
protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); }
protected Object target(Object a0) throws Throwable { return invoker.<Object>invokeExact(target, a0); }
protected Object target(Object a0) throws Throwable { return invoker.invokeExact(target, a0); }
protected Object targetA1(Object a0) throws Throwable { return target(a0); }
protected Object targetA1(int a0) throws Throwable { return target(a0); }
protected Object targetA1(long a0) throws Throwable { return target(a0); }
@ -458,7 +458,7 @@ class genclasses {
" protected @cat@(MethodHandle entryPoint) { super(entryPoint); } // to build prototype",
" protected @cat@(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }",
" protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new @cat@(e, i, c, t); }",
" protected Object target(@Ovav@) throws Throwable { return invoker.<Object>invokeExact(target, @av@); }",
" protected Object target(@Ovav@) throws Throwable { return invoker.invokeExact(target, @av@); }",
" //@each-Tv@",
" protected Object target@cat@(@Tvav@) throws Throwable { return target(@av@); }",
" //@end-Tv@",
@ -618,7 +618,7 @@ class genclasses {
protected A0(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A0(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A0(e, i, c, t); }
protected Object target() throws Throwable { return invoker.<Object>invokeExact(target); }
protected Object target() throws Throwable { return invoker.invokeExact(target); }
protected Object targetA0() throws Throwable { return target(); }
protected Object invoke_L() throws Throwable { return return_L(targetA0()); }
protected int invoke_I() throws Throwable { return return_I(targetA0()); }
@ -630,7 +630,7 @@ class genclasses {
protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); }
protected Object target(Object a0) throws Throwable { return invoker.<Object>invokeExact(target, a0); }
protected Object target(Object a0) throws Throwable { return invoker.invokeExact(target, a0); }
protected Object targetA1(Object a0) throws Throwable { return target(a0); }
protected Object targetA1(int a0) throws Throwable { return target(a0); }
protected Object targetA1(long a0) throws Throwable { return target(a0); }
@ -654,7 +654,7 @@ class genclasses {
protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A2(e, i, c, t); }
protected Object target(Object a0, Object a1) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1); }
protected Object target(Object a0, Object a1) throws Throwable { return invoker.invokeExact(target, a0, a1); }
protected Object targetA2(Object a0, Object a1) throws Throwable { return target(a0, a1); }
protected Object targetA2(Object a0, int a1) throws Throwable { return target(a0, a1); }
protected Object targetA2(int a0, int a1) throws Throwable { return target(a0, a1); }
@ -690,7 +690,7 @@ class genclasses {
protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A3(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A3(e, i, c, t); }
protected Object target(Object a0, Object a1, Object a2) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2); }
protected Object target(Object a0, Object a1, Object a2) throws Throwable { return invoker.invokeExact(target, a0, a1, a2); }
protected Object targetA3(Object a0, Object a1, Object a2) throws Throwable { return target(a0, a1, a2); }
protected Object targetA3(Object a0, Object a1, int a2) throws Throwable { return target(a0, a1, a2); }
protected Object targetA3(Object a0, int a1, int a2) throws Throwable { return target(a0, a1, a2); }
@ -739,7 +739,7 @@ class genclasses {
protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A4(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A4(e, i, c, t); }
protected Object target(Object a0, Object a1, Object a2, Object a3) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3); }
protected Object target(Object a0, Object a1, Object a2, Object a3) throws Throwable { return invoker.invokeExact(target, a0, a1, a2, a3); }
protected Object targetA4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return target(a0, a1, a2, a3); }
protected Object targetA4(Object a0, Object a1, Object a2, int a3) throws Throwable { return target(a0, a1, a2, a3); }
protected Object targetA4(Object a0, Object a1, int a2, int a3) throws Throwable { return target(a0, a1, a2, a3); }
@ -781,7 +781,7 @@ class genclasses {
protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A5(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A5(e, i, c, t); }
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4); }
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return invoker.invokeExact(target, a0, a1, a2, a3, a4); }
protected Object targetA5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return target(a0, a1, a2, a3, a4); }
protected Object targetA5(Object a0, Object a1, Object a2, Object a3, int a4) throws Throwable { return target(a0, a1, a2, a3, a4); }
protected Object targetA5(Object a0, Object a1, Object a2, int a3, int a4) throws Throwable { return target(a0, a1, a2, a3, a4); }
@ -832,7 +832,7 @@ class genclasses {
protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A6(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A6(e, i, c, t); }
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return invoker.<Object>invokeExact(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.invokeExact(target, a0, a1, a2, a3, a4, a5); }
protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); }
protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); }
protected Object targetA6(Object a0, Object a1, Object a2, Object a3, long a4, long a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); }
@ -866,7 +866,7 @@ class genclasses {
protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A7(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A7(e, i, c, t); }
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return invoker.<Object>invokeExact(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.invokeExact(target, a0, a1, a2, a3, a4, a5, a6); }
protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); }
protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); }
protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); }
@ -904,7 +904,7 @@ class genclasses {
protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A8(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A8(e, i, c, t); }
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return invoker.<Object>invokeExact(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.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7); }
protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
@ -946,7 +946,7 @@ class genclasses {
protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A9(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A9(e, i, c, t); }
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return invoker.<Object>invokeExact(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.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8); }
protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
@ -992,7 +992,7 @@ class genclasses {
protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A10(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A10(e, i, c, t); }
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return invoker.<Object>invokeExact(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.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }

View File

@ -377,7 +377,7 @@ public class ValueConversions {
REBOX_CONVERSIONS = newWrapperCaches(2);
/**
* Becase we normalize primitive types to reduce the number of signatures,
* Because we normalize primitive types to reduce the number of signatures,
* primitives are sometimes manipulated under an "erased" type,
* either int (for types other than long/double) or long (for all types).
* When the erased primitive value is then boxed into an Integer or Long,
@ -475,10 +475,10 @@ public class ValueConversions {
}
private static final EnumMap<Wrapper, MethodHandle>[]
ZERO_CONSTANT_FUNCTIONS = newWrapperCaches(1);
CONSTANT_FUNCTIONS = newWrapperCaches(2);
public static MethodHandle zeroConstantFunction(Wrapper wrap) {
EnumMap<Wrapper, MethodHandle> cache = ZERO_CONSTANT_FUNCTIONS[0];
EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[0];
MethodHandle mh = cache.get(wrap);
if (mh != null) {
return mh;
@ -543,6 +543,24 @@ public class ValueConversions {
return x;
}
/**
* Identity function on ints.
* @param x an arbitrary int value
* @return the same value x
*/
static int identity(int x) {
return x;
}
/**
* Identity function on longs.
* @param x an arbitrary long value
* @return the same value x
*/
static long identity(long x) {
return x;
}
/**
* Identity function, with reference cast.
* @param t an arbitrary reference type
@ -553,7 +571,7 @@ public class ValueConversions {
return t.cast(x);
}
private static final MethodHandle IDENTITY, CAST_REFERENCE, ALWAYS_NULL, ALWAYS_ZERO, ZERO_OBJECT, IGNORE, EMPTY;
private static final MethodHandle IDENTITY, IDENTITY_I, IDENTITY_J, CAST_REFERENCE, ALWAYS_NULL, ALWAYS_ZERO, ZERO_OBJECT, IGNORE, EMPTY;
static {
try {
MethodType idType = MethodType.genericMethodType(1);
@ -562,6 +580,8 @@ public class ValueConversions {
MethodType ignoreType = idType.changeReturnType(void.class);
MethodType zeroObjectType = MethodType.genericMethodType(0);
IDENTITY = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", idType);
IDENTITY_I = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", MethodType.methodType(int.class, int.class));
IDENTITY_J = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", MethodType.methodType(long.class, long.class));
//CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
CAST_REFERENCE = IMPL_LOOKUP.findStatic(ValueConversions.class, "castReference", castType);
ALWAYS_NULL = IMPL_LOOKUP.findStatic(ValueConversions.class, "alwaysNull", idType);
@ -613,8 +633,53 @@ public class ValueConversions {
return IDENTITY;
}
public static MethodHandle identity(Class<?> type) {
if (type == Object.class)
return IDENTITY;
else if (!type.isPrimitive())
return retype(MethodType.methodType(type, type), IDENTITY);
else
return identity(Wrapper.forPrimitiveType(type));
}
static MethodHandle identity(Wrapper wrap) {
EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[1];
MethodHandle mh = cache.get(wrap);
if (mh != null) {
return mh;
}
// slow path
MethodType type = MethodType.methodType(wrap.primitiveType());
if (wrap != Wrapper.VOID)
type = type.appendParameterTypes(wrap.primitiveType());
try {
mh = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", type);
} catch (NoAccessException ex) {
mh = null;
}
if (mh == null && wrap == Wrapper.VOID) {
mh = EMPTY; // #(){} : #()void
}
if (mh != null) {
cache.put(wrap, mh);
return mh;
}
// use a raw conversion
if (wrap.isSingleWord() && wrap != Wrapper.INT) {
mh = retype(type, identity(Wrapper.INT));
} else if (wrap.isDoubleWord() && wrap != Wrapper.LONG) {
mh = retype(type, identity(Wrapper.LONG));
}
if (mh != null) {
cache.put(wrap, mh);
return mh;
}
throw new IllegalArgumentException("cannot find identity for " + wrap);
}
private static MethodHandle retype(MethodType type, MethodHandle mh) {
return AdapterMethodHandle.makeRetypeOnly(IMPL_TOKEN, type, mh);
return AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, type, mh);
}
private static final Object[] NO_ARGS_ARRAY = {};

View File

@ -25,7 +25,6 @@
package sun.dyn.util;
import java.dyn.LinkagePermission;
import java.dyn.NoAccessException;
import java.lang.reflect.Modifier;
import sun.dyn.MemberName;
@ -43,6 +42,7 @@ public class VerifyAccess {
private static final int PACKAGE_ONLY = 0;
private static final int ALL_ACCESS_MODES = (PUBLIC|PRIVATE|PROTECTED|PACKAGE_ONLY);
private static final boolean ALLOW_NESTMATE_ACCESS = false;
/**
* Evaluate the JVM linkage rules for access to the given method
@ -102,6 +102,8 @@ public class VerifyAccess {
// a superclass of the lookup class.
}
}
if (defc == lookupClass)
return true; // easy check; all self-access is OK
switch (mods & ALL_ACCESS_MODES) {
case PUBLIC:
if (refc != defc) return true; // already checked above
@ -112,7 +114,8 @@ public class VerifyAccess {
return isSamePackage(defc, lookupClass);
case PRIVATE:
// Loosened rules for privates follows access rules for inner classes.
return isSamePackageMember(defc, lookupClass);
return (ALLOW_NESTMATE_ACCESS &&
isSamePackageMember(defc, lookupClass));
default:
throw new IllegalArgumentException("bad modifiers: "+Modifier.toString(mods));
}
@ -206,24 +209,4 @@ public class VerifyAccess {
}
return false;
}
/**
* Ensure the requesting class have privileges to perform invokedynamic
* linkage operations on subjectClass. True if requestingClass is
* Access.class (meaning the request originates from the JVM) or if the
* classes are in the same package and have consistent class loaders.
* (The subject class loader must be identical with or be a child of
* the requesting class loader.)
* @param requestingClass
* @param subjectClass
*/
public static void checkBootstrapPrivilege(Class requestingClass, Class subjectClass,
String permissionName) {
if (requestingClass == null) return;
if (requestingClass == subjectClass) return;
SecurityManager security = System.getSecurityManager();
if (security == null) return; // open season
if (isSamePackage(requestingClass, subjectClass)) return;
security.checkPermission(new LinkagePermission(permissionName, requestingClass));
}
}

View File

@ -26,17 +26,19 @@
package sun.dyn.util;
public enum Wrapper {
INT(Integer.class, int.class, 'I', (Integer)(int)0, Format.signed(32)),
LONG(Long.class, long.class, 'J', (Long)(long)0, Format.signed(64)),
BOOLEAN(Boolean.class, boolean.class, 'Z', (Boolean)false, Format.unsigned(1)),
// These must be in the order defined for widening primitive conversions in JLS 5.1.2
BYTE(Byte.class, byte.class, 'B', (Byte)(byte)0, Format.signed(8)),
SHORT(Short.class, short.class, 'S', (Short)(short)0, Format.signed(16)),
CHAR(Character.class, char.class, 'C', (Character)(char)0, Format.unsigned(16)),
BOOLEAN(Boolean.class, boolean.class, 'Z', (Boolean)false, Format.unsigned(1)),
INT(Integer.class, int.class, 'I', (Integer)(int)0, Format.signed(32)),
LONG(Long.class, long.class, 'J', (Long)(long)0, Format.signed(64)),
FLOAT(Float.class, float.class, 'F', (Float)(float)0, Format.floating(32)),
DOUBLE(Double.class, double.class, 'D', (Double)(double)0, Format.floating(64)),
VOID(Void.class, void.class, 'V', null, Format.other(0)),
//NULL(Null.class, null.class, 'N', null, Format.other(1)),
OBJECT(Object.class, Object.class, 'L', null, Format.other(1)),
// VOID must be the last type, since it is "assignable" from any other type:
VOID(Void.class, void.class, 'V', null, Format.other(0)),
;
private final Class<?> wrapperType;
@ -76,9 +78,11 @@ public enum Wrapper {
false);
return kind | (size << SIZE_SHIFT) | (slots << SLOT_SHIFT);
}
static int
static final int
INT = SIGNED | (32 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
SHORT = SIGNED | (16 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
BOOLEAN = UNSIGNED | (1 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
CHAR = UNSIGNED | (16 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
FLOAT = FLOATING | (32 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
VOID = UNSIGNED | (0 << SIZE_SHIFT) | (0 << SLOT_SHIFT),
NUM_MASK = (-1) << SIZE_SHIFT;
@ -111,6 +115,29 @@ public enum Wrapper {
/** Is the wrapped type either float or double? */
public boolean isFloating() { return format >= Format.FLOAT; }
/** Does the JVM verifier allow a variable of this wrapper's
* primitive type to be assigned from a value of the given wrapper's primitive type?
* Cases:
* <ul>
* <li>unboxing followed by widening primitive conversion
* <li>any type converted to {@code void}
* <li>boxing conversion followed by widening reference conversion to {@code Object}
* <li>conversion of {@code boolean} to any type
* </ul>
*/
public boolean isConvertibleFrom(Wrapper source) {
if (this == source) return true;
if (this.compareTo(source) < 0) {
// At best, this is a narrowing conversion.
return false;
}
if ((this.format ^ source.format) == (Format.SHORT ^ Format.CHAR)) {
assert (this == SHORT && source == CHAR) || (this == CHAR && source == SHORT);
return false;
}
return true;
}
/** Produce a zero value for the given wrapper type.
* This will be a numeric zero for a number or character,
* false for a boolean, and null for a reference or void.
@ -122,10 +149,10 @@ public enum Wrapper {
public Object zero() { return zero; }
/** Produce a zero value for the given wrapper type T.
* The optinoal argument must a type compatible with this wrapper.
* The optional argument must a type compatible with this wrapper.
* Equivalent to {@code this.cast(this.zero(), type)}.
*/
public <T> T zero(Class<T> type) { return cast(zero, type); }
public <T> T zero(Class<T> type) { return convert(zero, type); }
// /** Produce a wrapper for the given wrapper or primitive type. */
// public static Wrapper valueOf(Class<?> type) {
@ -264,7 +291,11 @@ public enum Wrapper {
exampleType.isInterface()) {
return forceType(wrapperType, exampleType);
}
throw new ClassCastException(exampleType + " not <:" + wrapperType);
throw newClassCastException(exampleType, primitiveType);
}
private static ClassCastException newClassCastException(Class<?> actual, Class<?> expected) {
return new ClassCastException(actual + " is not compatible with " + expected);
}
/** If {@code type} is a primitive type, return the corresponding
@ -325,17 +356,55 @@ public enum Wrapper {
// }
/** Cast a wrapped value to the given type, which may be either a primitive or wrapper type.
* The given target type must be this wrapper's primitive or wrapper type.
* If this wrapper is OBJECT, the target type may also be an interface, perform no runtime check.
* Performs standard primitive conversions, including truncation and float conversions.
* The given type must be compatible with this wrapper. That is, it must either
* be the wrapper type (or a subtype, in the case of {@code OBJECT}) or else
* it must be the wrapper's primitive type.
* Primitive conversions are only performed if the given type is itself a primitive.
* @throws ClassCastException if the given type is not compatible with this wrapper
*/
public <T> T cast(Object x, Class<T> type) {
return convert(x, type, true);
}
/** Convert a wrapped value to the given type.
* The given target type must be this wrapper's primitive or wrapper type.
* This is equivalent to {@link #cast}, except that it refuses to perform
* narrowing primitive conversions.
*/
public <T> T convert(Object x, Class<T> type) {
return convert(x, type, false);
}
private <T> T convert(Object x, Class<T> type, boolean isCast) {
if (this == OBJECT) {
// If the target wrapper is OBJECT, just do a reference cast.
// If the target type is an interface, perform no runtime check.
// (This loophole is safe, and is allowed by the JVM verifier.)
// If the target type is a primitive, change it to a wrapper.
@SuppressWarnings("unchecked")
T result = (T) x; // unchecked warning is expected here
return result;
}
Class<T> wtype = wrapperType(type);
if (wtype.isInstance(x))
return wtype.cast(x);
return wtype.cast(wrap(x));
if (wtype.isInstance(x)) {
@SuppressWarnings("unchecked")
T result = (T) x; // unchecked warning is expected here
return result;
}
Class<?> sourceType = x.getClass(); // throw NPE if x is null
if (!isCast) {
Wrapper source = findWrapperType(sourceType);
if (source == null || !this.isConvertibleFrom(source)) {
throw newClassCastException(wtype, sourceType);
}
}
@SuppressWarnings("unchecked")
T result = (T) wrap(x); // unchecked warning is expected here
assert result.getClass() == wtype;
return result;
}
/** Cast a reference type to another reference type.

View File

@ -53,12 +53,13 @@ public class ClassValueTest {
return "CV1:" + type.getName();
}
static int countForCV1;
static final ClassValue<String> CV1 = new ClassValue<String>() {
static final ClassValue<String> CV1 = new CV1();
private static class CV1 extends ClassValue<String> {
protected String computeValue(Class<?> type) {
countForCV1++;
return nameForCV1(type);
}
};
}
static final Class[] CLASSES = {
String.class,

View File

@ -0,0 +1,172 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @summary smoke test for invokedynamic instructions
* @library indify
* @compile InvokeDynamicPrintArgs.java
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic
* indify.Indify
* --verify-specifier-count=3 --transitionalJSR292=false
* --expand-properties --classpath ${test.classes}
* --java InvokeDynamicPrintArgs --check-output
*/
import java.util.*;
import java.io.*;
import java.dyn.*;
import static java.dyn.MethodHandles.*;
import static java.dyn.MethodType.*;
public class InvokeDynamicPrintArgs {
public static void main(String... av) throws Throwable {
if (av.length > 0) openBuf(); // --check-output mode
System.out.println("Printing some argument lists, starting with a empty one:");
INDY_nothing().invokeExact(); // BSM specifier #0 = {bsm}
INDY_bar().invokeExact("bar arg", 1); // BSM specifier #1 = {bsm2, Void.class, "void type"}
INDY_bar2().invokeExact("bar2 arg", 222); // BSM specifier #1 = (same)
INDY_baz().invokeExact("baz arg", 2, 3.14); // BSM specifier #2 = {bsm2, 1234.5}
INDY_foo().invokeExact("foo arg"); // BSM specifier #0 = (same)
// Hence, BSM specifier count should be 3. See "--verify-specifier-count=3" above.
System.out.println("Done printing argument lists.");
closeBuf();
}
private static PrintStream oldOut;
private static ByteArrayOutputStream buf;
private static void openBuf() {
oldOut = System.out;
buf = new ByteArrayOutputStream();
System.setOut(new PrintStream(buf));
}
private static void closeBuf() {
if (buf == null) return;
System.out.flush();
System.setOut(oldOut);
String[] haveLines = new String(buf.toByteArray()).split("[\n\r]+");
for (String line : haveLines) System.out.println(line);
Iterator<String> iter = Arrays.asList(haveLines).iterator();
for (String want : EXPECT_OUTPUT) {
String have = iter.hasNext() ? iter.next() : "[EOF]";
if (want.equals(have)) continue;
System.err.println("want line: "+want);
System.err.println("have line: "+have);
throw new AssertionError("unexpected output: "+have);
}
if (iter.hasNext())
throw new AssertionError("unexpected output: "+iter.next());
}
private static final String[] EXPECT_OUTPUT = {
"Printing some argument lists, starting with a empty one:",
"[InvokeDynamicPrintArgs, nothing, ()void][]",
"[InvokeDynamicPrintArgs, bar, (java.lang.String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar arg, 1]",
"[InvokeDynamicPrintArgs, bar2, (java.lang.String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar2 arg, 222]",
"[InvokeDynamicPrintArgs, baz, (java.lang.String,int,double)void, 1234.5][baz arg, 2, 3.14]",
"[InvokeDynamicPrintArgs, foo, (java.lang.String)void][foo arg]",
"Done printing argument lists."
};
private static void printArgs(Object bsmInfo, Object... args) {
System.out.println(bsmInfo+Arrays.deepToString(args));
}
private static MethodHandle MH_printArgs() throws ReflectiveOperationException {
shouldNotCallThis();
return lookup().findStatic(lookup().lookupClass(),
"printArgs", methodType(void.class, Object.class, Object[].class));
}
private static CallSite bsm(Lookup caller, String name, MethodType type) throws ReflectiveOperationException {
// ignore caller and name, but match the type:
Object bsmInfo = Arrays.asList(caller, name, type);
return new ConstantCallSite(MH_printArgs().bindTo(bsmInfo).asCollector(Object[].class, type.parameterCount()).asType(type));
}
private static MethodType MT_bsm() {
shouldNotCallThis();
return methodType(CallSite.class, Lookup.class, String.class, MethodType.class);
}
private static MethodHandle MH_bsm() throws ReflectiveOperationException {
shouldNotCallThis();
return lookup().findStatic(lookup().lookupClass(), "bsm", MT_bsm());
}
private static CallSite bsm2(Lookup caller, String name, MethodType type, Object arg) throws ReflectiveOperationException {
// ignore caller and name, but match the type:
List<Object> bsmInfo = new ArrayList<>(Arrays.asList(caller, name, type));
if (arg instanceof Object[])
bsmInfo.addAll(Arrays.asList((Object[])arg));
else
bsmInfo.add(arg);
return new ConstantCallSite(MH_printArgs().bindTo(bsmInfo).asCollector(Object[].class, type.parameterCount()).asType(type));
}
private static MethodType MT_bsm2() {
shouldNotCallThis();
return methodType(CallSite.class, Lookup.class, String.class, MethodType.class, Object.class);
}
private static MethodHandle MH_bsm2() throws ReflectiveOperationException {
shouldNotCallThis();
return lookup().findStatic(lookup().lookupClass(), "bsm2", MT_bsm2());
}
private static MethodHandle INDY_nothing() throws Throwable {
shouldNotCallThis();
return ((CallSite) MH_bsm().invokeGeneric(lookup(),
"nothing", methodType(void.class)
)).dynamicInvoker();
}
private static MethodHandle INDY_foo() throws Throwable {
shouldNotCallThis();
return ((CallSite) MH_bsm().invokeGeneric(lookup(),
"foo", methodType(void.class, String.class)
)).dynamicInvoker();
}
private static MethodHandle INDY_bar() throws Throwable {
shouldNotCallThis();
return ((CallSite) MH_bsm2().invokeGeneric(lookup(),
"bar", methodType(void.class, String.class, int.class)
, new Object[] { Void.class, "void type!",
1, 234.5F, 67.5, (long)89 }
)).dynamicInvoker();
}
private static MethodHandle INDY_bar2() throws Throwable {
shouldNotCallThis();
return ((CallSite) MH_bsm2().invokeGeneric(lookup(),
"bar2", methodType(void.class, String.class, int.class)
, new Object[] { Void.class, "void type!",
1, 234.5F, 67.5, (long)89 }
)).dynamicInvoker();
}
private static MethodHandle INDY_baz() throws Throwable {
shouldNotCallThis();
return ((CallSite) MH_bsm2().invokeGeneric(lookup(),
"baz", methodType(void.class, String.class, int.class, double.class)
, 1234.5
)).dynamicInvoker();
}
private static void shouldNotCallThis() {
// if this gets called, the transformation has not taken place
if (System.getProperty("InvokeDynamicPrintArgs.allow-untransformed") != null) return;
throw new AssertionError("this code should be statically transformed away by Indify");
}
}

View File

@ -0,0 +1,484 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @summary unit tests for java.dyn.MethodHandle.invokeGeneric
* @compile -XDallowTransitionalJSR292=no -target 7 InvokeGenericTest.java
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.InvokeGenericTest
*/
package test.java.dyn;
import java.dyn.*;
import static java.dyn.MethodHandles.*;
import static java.dyn.MethodType.*;
import java.lang.reflect.*;
import java.util.*;
import org.junit.*;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
/**
*
* @author jrose
*/
public class InvokeGenericTest {
// How much output?
static int verbosity = 0;
static {
String vstr = System.getProperty("test.java.dyn.InvokeGenericTest.verbosity");
if (vstr != null) verbosity = Integer.parseInt(vstr);
}
@Test
public void testFirst() throws Throwable {
verbosity += 9; try {
// left blank for debugging
} finally { printCounts(); verbosity -= 9; }
}
public InvokeGenericTest() {
}
@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("amd64") || arch.equals("i386") || arch.equals("x86") ||
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;
static int allPosTests, allNegTests;
int posTests, negTests;
@After
public void printCounts() {
if (verbosity >= 2 && (posTests | negTests) != 0) {
System.out.println();
if (posTests != 0) System.out.println("=== "+testName+": "+posTests+" positive test cases run");
if (negTests != 0) System.out.println("=== "+testName+": "+negTests+" negative test cases run");
allPosTests += posTests;
allNegTests += negTests;
posTests = negTests = 0;
}
}
void countTest(boolean positive) {
if (positive) ++posTests;
else ++negTests;
}
void countTest() { countTest(true); }
void startTest(String name) {
if (testName != null) printCounts();
if (verbosity >= 1)
System.out.println(name);
posTests = negTests = 0;
testName = name;
}
@BeforeClass
public static void setUpClass() throws Exception {
calledLog.clear();
calledLog.add(null);
nextArgVal = INITIAL_ARG_VAL;
}
@AfterClass
public static void tearDownClass() throws Exception {
int posTests = allPosTests, negTests = allNegTests;
if (verbosity >= 2 && (posTests | negTests) != 0) {
System.out.println();
if (posTests != 0) System.out.println("=== "+posTests+" total positive test cases");
if (negTests != 0) System.out.println("=== "+negTests+" total negative test cases");
}
}
static List<Object> calledLog = new ArrayList<Object>();
static Object logEntry(String name, Object... args) {
return Arrays.asList(name, Arrays.asList(args));
}
static Object called(String name, Object... args) {
Object entry = logEntry(name, args);
calledLog.add(entry);
return entry;
}
static void assertCalled(String name, Object... args) {
Object expected = logEntry(name, args);
Object actual = calledLog.get(calledLog.size() - 1);
if (expected.equals(actual) && verbosity < 9) return;
System.out.println("assertCalled "+name+":");
System.out.println("expected: "+expected);
System.out.println("actual: "+actual);
System.out.println("ex. types: "+getClasses(expected));
System.out.println("act. types: "+getClasses(actual));
assertEquals("previous method call", expected, actual);
}
static void printCalled(MethodHandle target, String name, Object... args) {
if (verbosity >= 3)
System.out.println("calling MH="+target+" to "+name+Arrays.toString(args));
}
static Object castToWrapper(Object value, Class<?> dst) {
Object wrap = null;
if (value instanceof Number)
wrap = castToWrapperOrNull(((Number)value).longValue(), dst);
if (value instanceof Character)
wrap = castToWrapperOrNull((char)(Character)value, dst);
if (wrap != null) return wrap;
return dst.cast(value);
}
static Object castToWrapperOrNull(long value, Class<?> dst) {
if (dst == int.class || dst == Integer.class)
return (int)(value);
if (dst == long.class || dst == Long.class)
return (long)(value);
if (dst == char.class || dst == Character.class)
return (char)(value);
if (dst == short.class || dst == Short.class)
return (short)(value);
if (dst == float.class || dst == Float.class)
return (float)(value);
if (dst == double.class || dst == Double.class)
return (double)(value);
if (dst == byte.class || dst == Byte.class)
return (byte)(value);
if (dst == boolean.class || dst == boolean.class)
return ((value % 29) & 1) == 0;
return null;
}
static final int ONE_MILLION = (1000*1000), // first int value
TEN_BILLION = (10*1000*1000*1000), // scale factor to reach upper 32 bits
INITIAL_ARG_VAL = ONE_MILLION << 1; // <<1 makes space for sign bit;
static long nextArgVal;
static long nextArg(boolean moreBits) {
long val = nextArgVal++;
long sign = -(val & 1); // alternate signs
val >>= 1;
if (moreBits)
// Guarantee some bits in the high word.
// In any case keep the decimal representation simple-looking,
// with lots of zeroes, so as not to make the printed decimal
// strings unnecessarily noisy.
val += (val % ONE_MILLION) * TEN_BILLION;
return val ^ sign;
}
static int nextArg() {
// Produce a 32-bit result something like ONE_MILLION+(smallint).
// Example: 1_000_042.
return (int) nextArg(false);
}
static long nextArg(Class<?> kind) {
if (kind == long.class || kind == Long.class ||
kind == double.class || kind == Double.class)
// produce a 64-bit result something like
// ((TEN_BILLION+1) * (ONE_MILLION+(smallint)))
// Example: 10_000_420_001_000_042.
return nextArg(true);
return (long) nextArg();
}
static Object randomArg(Class<?> param) {
Object wrap = castToWrapperOrNull(nextArg(param), param);
if (wrap != null) {
return wrap;
}
// import sun.dyn.util.Wrapper;
// Wrapper wrap = Wrapper.forBasicType(dst);
// if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst))
// wrap = Wrapper.forWrapperType(dst);
// if (wrap != Wrapper.OBJECT)
// return wrap.wrap(nextArg++);
if (param.isInterface()) {
for (Class<?> c : param.getClasses()) {
if (param.isAssignableFrom(c) && !c.isInterface())
{ param = c; break; }
}
}
if (param.isInterface() || param.isAssignableFrom(String.class))
return "#"+nextArg();
else
try {
return param.newInstance();
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
}
return null; // random class not Object, String, Integer, etc.
}
static Object[] randomArgs(Class<?>... params) {
Object[] args = new Object[params.length];
for (int i = 0; i < args.length; i++)
args[i] = randomArg(params[i]);
return args;
}
static Object[] randomArgs(int nargs, Class<?> param) {
Object[] args = new Object[nargs];
for (int i = 0; i < args.length; i++)
args[i] = randomArg(param);
return args;
}
static final Object ANON_OBJ = new Object();
static Object zeroArg(Class<?> param) {
Object x = castToWrapperOrNull(0L, param);
if (x != null) return x;
if (param.isInterface() || param.isAssignableFrom(String.class)) return "\"\"";
if (param == Object.class) return ANON_OBJ;
if (param.getComponentType() != null) return Array.newInstance(param.getComponentType(), 0);
return null;
}
static Object[] zeroArgs(Class<?>... params) {
Object[] args = new Object[params.length];
for (int i = 0; i < args.length; i++)
args[i] = zeroArg(params[i]);
return args;
}
static Object[] zeroArgs(List<Class<?>> params) {
return zeroArgs(params.toArray(new Class<?>[0]));
}
static <T, E extends T> T[] array(Class<T[]> atype, E... a) {
return Arrays.copyOf(a, a.length, atype);
}
static <T> T[] cat(T[] a, T... b) {
int alen = a.length, blen = b.length;
if (blen == 0) return a;
T[] c = Arrays.copyOf(a, alen + blen);
System.arraycopy(b, 0, c, alen, blen);
return c;
}
static Integer[] boxAll(int... vx) {
Integer[] res = new Integer[vx.length];
for (int i = 0; i < res.length; i++) {
res[i] = vx[i];
}
return res;
}
static Object getClasses(Object x) {
if (x == null) return x;
if (x instanceof String) return x; // keep the name
if (x instanceof List) {
// recursively report classes of the list elements
Object[] xa = ((List)x).toArray();
for (int i = 0; i < xa.length; i++)
xa[i] = getClasses(xa[i]);
return Arrays.asList(xa);
}
return x.getClass().getSimpleName();
}
static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) {
return changeArgTypes(target, 0, 999, argType);
}
static MethodHandle changeArgTypes(MethodHandle target,
int beg, int end, Class<?> argType) {
MethodType targetType = target.type();
end = Math.min(end, targetType.parameterCount());
ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>(targetType.parameterList());
Collections.fill(argTypes.subList(beg, end), argType);
MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);
return MethodHandles.convertArguments(target, ttype2);
}
// This lookup is good for all members in and under InvokeGenericTest.
static final Lookup LOOKUP = MethodHandles.lookup();
Map<List<Class<?>>, MethodHandle> CALLABLES = new HashMap<List<Class<?>>, MethodHandle>();
MethodHandle callable(List<Class<?>> params) {
MethodHandle mh = CALLABLES.get(params);
if (mh == null) {
mh = collectArguments(collector_MH, methodType(Object.class, params));
CALLABLES.put(params, mh);
}
return mh;
}
MethodHandle callable(Class<?>... params) {
return callable(Arrays.asList(params));
}
private static Object collector(Object... args) {
return Arrays.asList(args);
}
private static final MethodHandle collector_MH;
static {
try {
collector_MH
= LOOKUP.findStatic(LOOKUP.lookupClass(),
"collector",
methodType(Object.class, Object[].class));
} catch (NoAccessException ex) {
throw new RuntimeException(ex);
}
}
@Test
public void testSimple() throws Throwable {
startTest("testSimple");
countTest();
String[] args = { "one", "two" };
MethodHandle mh = callable(Object.class, String.class);
Object res; List resl;
res = resl = (List) mh.invokeGeneric((String)args[0], (Object)args[1]);
//System.out.println(res);
assertEquals(Arrays.asList(args), res);
}
@Test
public void testWrongArgumentCount() throws Throwable {
startTest("testWrongArgumentCount");
for (int i = 0; i <= 10; i++) {
testWrongArgumentCount(Collections.<Class<?>>nCopies(i, Integer.class));
if (i <= 4) {
testWrongArgumentCount(Collections.<Class<?>>nCopies(i, int.class));
testWrongArgumentCount(Collections.<Class<?>>nCopies(i, long.class));
}
}
}
public void testWrongArgumentCount(List<Class<?>> params) throws Throwable {
int max = params.size();
for (int i = 0; i < max; i++) {
List<Class<?>> params2 = params.subList(0, i);
for (int k = 0; k <= 2; k++) {
if (k == 1) params = methodType(Object.class, params).generic().parameterList();
if (k == 2) params2 = methodType(Object.class, params2).generic().parameterList();
testWrongArgumentCount(params, params2);
testWrongArgumentCount(params2, params);
}
}
}
public void testWrongArgumentCount(List<Class<?>> expect, List<Class<?>> observe) throws Throwable {
countTest(false);
if (expect.equals(observe))
assert(false);
MethodHandle target = callable(expect);
Object[] args = zeroArgs(observe);
Object junk;
try {
switch (args.length) {
case 0:
junk = target.invokeGeneric(); break;
case 1:
junk = target.invokeGeneric(args[0]); break;
case 2:
junk = target.invokeGeneric(args[0], args[1]); break;
case 3:
junk = target.invokeGeneric(args[0], args[1], args[2]); break;
case 4:
junk = target.invokeGeneric(args[0], args[1], args[2], args[3]); break;
default:
junk = target.invokeWithArguments(args); break;
}
} catch (WrongMethodTypeException ex) {
return;
} catch (Exception ex) {
throw new RuntimeException("wrong exception calling "+target+target.type()+" on "+Arrays.asList(args)+" : "+ex);
}
throw new RuntimeException("bad success calling "+target+target.type()+" on "+Arrays.asList(args));
}
/** Make a list of all combinations of the given types, with the given arities.
* A void return type is possible iff the first type is void.class.
*/
static List<MethodType> allMethodTypes(int minargc, int maxargc, Class<?>... types) {
ArrayList<MethodType> result = new ArrayList<MethodType>();
if (types.length > 0) {
ArrayList<MethodType> argcTypes = new ArrayList<MethodType>();
// build arity-zero types first
for (Class<?> rtype : types) {
argcTypes.add(MethodType.methodType(rtype));
}
if (types[0] == void.class)
// void is not an argument type
types = Arrays.copyOfRange(types, 1, types.length);
for (int argc = 0; argc <= maxargc; argc++) {
if (argc >= minargc)
result.addAll(argcTypes);
if (argc >= maxargc)
break;
ArrayList<MethodType> prevTypes = argcTypes;
argcTypes = new ArrayList<MethodType>();
for (MethodType prevType : prevTypes) {
for (Class<?> ptype : types) {
argcTypes.add(prevType.insertParameterTypes(argc, ptype));
}
}
}
}
return Collections.unmodifiableList(result);
}
static List<MethodType> allMethodTypes(int argc, Class<?>... types) {
return allMethodTypes(argc, argc, types);
}
interface RandomInterface { }
MethodHandle toString_MH;
@Test
public void testReferenceConversions() throws Throwable {
startTest("testReferenceConversions");
toString_MH = LOOKUP.
findVirtual(Object.class, "toString", MethodType.methodType(String.class));
String[] args = { "one", "two" };
for (MethodType type : allMethodTypes(2, Object.class, String.class, RandomInterface.class)) {
testReferenceConversions(type, args);
}
}
public void testReferenceConversions(MethodType type, Object... args) throws Throwable {
countTest();
if (verbosity > 3) System.out.println("target type: "+type);
MethodHandle mh = callable(type.parameterList());
MethodHandle tsdrop = MethodHandles.dropArguments(toString_MH, 1, type.parameterList());
mh = MethodHandles.foldArguments(tsdrop, mh);
mh = mh.asType(type);
Object res = mh.invokeGeneric((String)args[0], (Object)args[1]);
//System.out.println(res);
assertEquals(Arrays.asList(args).toString(), res);
}
@Test @Ignore("known failure pending 6939861")
public void testBoxConversions() throws Throwable {
startTest("testBoxConversions");
countTest();
Integer[] args = { 1, 2 };
MethodHandle mh = callable(Object.class, int.class);
Object res; List resl;
res = resl = (List) mh.invokeGeneric((int)args[0], (Object)args[1]);
//System.out.println(res);
assertEquals(Arrays.asList(args), res);
}
}

View File

@ -25,18 +25,18 @@
/* @test
* @summary example code used in javadoc for java.dyn API
* @compile -XDallowTransitionalJSR292=no JavaDocExamples.java
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.JavaDocExamples
* @compile -XDallowTransitionalJSR292=no JavaDocExamplesTest.java
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.JavaDocExamplesTest
*/
/*
---- To run outside jtreg:
$ $JAVA7X_HOME/bin/javac -cp $JUNIT4_JAR -d /tmp/Classes \
$DAVINCI/sources/jdk/test/java/dyn/JavaDocExamples.java
$DAVINCI/sources/jdk/test/java/dyn/JavaDocExamplesTest.java
$ $JAVA7X_HOME/bin/java -cp $JUNIT4_JAR:/tmp/Classes \
-XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles \
-Dtest.java.dyn.JavaDocExamples.verbosity=1 \
test.java.dyn.JavaDocExamples
-Dtest.java.dyn.JavaDocExamplesTest.verbosity=1 \
test.java.dyn.JavaDocExamplesTest
----
*/
@ -57,15 +57,15 @@ import static org.junit.Assume.*;
/**
* @author jrose
*/
public class JavaDocExamples {
public class JavaDocExamplesTest {
/** Wrapper for running the JUnit tests in this module.
* Put JUnit on the classpath!
*/
public static void main(String... ignore) {
org.junit.runner.JUnitCore.runClasses(JavaDocExamples.class);
org.junit.runner.JUnitCore.runClasses(JavaDocExamplesTest.class);
}
// How much output?
static int verbosity = Integer.getInteger("test.java.dyn.JavaDocExamples.verbosity", 0);
static int verbosity = Integer.getInteger("test.java.dyn.JavaDocExamplesTest.verbosity", 0);
{}
static final private Lookup LOOKUP = lookup();
@ -95,11 +95,11 @@ MethodHandle CONCAT_3 = LOOKUP.findVirtual(String.class,
MethodHandle HASHCODE_3 = LOOKUP.findVirtual(Object.class,
"hashCode", methodType(int.class));
//assertEquals("xy", (String) CONCAT_1.invokeExact("x", "y"));
assertEquals("xy", (String) CONCAT_2.<String>invokeExact("x", "y"));
assertEquals("xy", (String) CONCAT_3.<String>invokeExact("x", "y"));
//assertEquals("xy".hashCode(), (int) HASHCODE_1.<int>invokeExact((Object)"xy"));
assertEquals("xy".hashCode(), (int) HASHCODE_2.<int>invokeExact((Object)"xy"));
assertEquals("xy".hashCode(), (int) HASHCODE_3.<int>invokeExact((Object)"xy"));
assertEquals("xy", (String) CONCAT_2.invokeExact("x", "y"));
assertEquals("xy", (String) CONCAT_3.invokeExact("x", "y"));
//assertEquals("xy".hashCode(), (int) HASHCODE_1.invokeExact((Object)"xy"));
assertEquals("xy".hashCode(), (int) HASHCODE_2.invokeExact((Object)"xy"));
assertEquals("xy".hashCode(), (int) HASHCODE_3.invokeExact((Object)"xy"));
{}
}
@Test public void testDropArguments() throws Throwable {
@ -107,16 +107,32 @@ assertEquals("xy".hashCode(), (int) HASHCODE_3.<int>invokeExact((Object)"xy"));
{} /// JAVADOC
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
cat = cat.asType(methodType(Object.class, String.class, String.class)); /*(String)*/
assertEquals("xy", /*(String)*/ cat.invokeExact("x", "y"));
assertEquals("xy", (String) cat.invokeExact("x", "y"));
MethodHandle d0 = dropArguments(cat, 0, String.class);
assertEquals("yz", /*(String)*/ d0.invokeExact("x", "y", "z"));
assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
MethodHandle d1 = dropArguments(cat, 1, String.class);
assertEquals("xz", /*(String)*/ d1.invokeExact("x", "y", "z"));
assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
MethodHandle d2 = dropArguments(cat, 2, String.class);
assertEquals("xy", /*(String)*/ d2.invokeExact("x", "y", "z"));
assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
assertEquals("xz", /*(String)*/ d12.invokeExact("x", 12, true, "z"));
assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
}}
}
@Test public void testFilterArguments() throws Throwable {
{{
{} /// JAVADOC
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
MethodHandle upcase = lookup().findVirtual(String.class,
"toUpperCase", methodType(String.class));
assertEquals("xy", (String) cat.invokeExact("x", "y"));
MethodHandle f0 = filterArguments(cat, 0, upcase);
assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy
MethodHandle f1 = filterArguments(cat, 1, upcase);
assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
}}
}
@ -125,4 +141,38 @@ assertEquals("xz", /*(String)*/ d12.invokeExact("x", 12, true, "z"));
System.out.println("result: "+act);
Assert.assertEquals(exp, act);
}
static MethodHandle asList;
@Test public void testWithTypeHandler() throws Throwable {
{{
{} /// JAVADOC
MethodHandle makeEmptyList = MethodHandles.constant(List.class, Arrays.asList());
MethodHandle asList = lookup()
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
JavaDocExamplesTest.asList = asList;
/*
static MethodHandle collectingTypeHandler(MethodHandle base, MethodType newType) {
return asList.asCollector(Object[].class, newType.parameterCount()).asType(newType);
}
*/
MethodHandle collectingTypeHandler = lookup()
.findStatic(lookup().lookupClass(), "collectingTypeHandler",
methodType(MethodHandle.class, MethodHandle.class, MethodType.class));
MethodHandle makeAnyList = makeEmptyList.withTypeHandler(collectingTypeHandler);
assertEquals("[]", makeAnyList.invokeGeneric().toString());
assertEquals("[1]", makeAnyList.invokeGeneric(1).toString());
assertEquals("[two, too]", makeAnyList.invokeGeneric("two", "too").toString());
}}
}
static MethodHandle collectingTypeHandler(MethodHandle base, MethodType newType) {
//System.out.println("Converting "+asList+" to "+newType);
MethodHandle conv = asList.asCollector(Object[].class, newType.parameterCount()).asType(newType);
//System.out.println(" =>"+conv);
return conv;
}
}

View File

@ -25,8 +25,8 @@
/* @test
* @summary unit tests for java.dyn.MethodHandles
* @compile -XDinvokedynamic MethodHandlesTest.java
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic test.java.dyn.MethodHandlesTest
* @compile -source 7 -target 7 -XDallowTransitionalJSR292=no MethodHandlesTest.java
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.MethodHandlesTest
*/
package test.java.dyn;
@ -62,7 +62,6 @@ public class MethodHandlesTest {
// lookups, without exercising the actual method handle.
static boolean DO_MORE_CALLS = true;
@Test
public void testFirst() throws Throwable {
verbosity += 9; try {
@ -458,7 +457,7 @@ public class MethodHandlesTest {
Exception noAccess = null;
try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
target = lookup.findStatic(defc, name, type);
target = lookup.in(defc).findStatic(defc, name, type);
} catch (NoAccessException ex) {
noAccess = ex;
}
@ -469,16 +468,22 @@ public class MethodHandlesTest {
assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
if (!positive) return; // negative test failed as expected
assertEquals(type, target.type());
assertTrue(target.toString().contains(name)); // rough check
assertNameStringContains(target, name);
if (!DO_MORE_CALLS && lookup != PRIVATE) return;
Object[] args = randomArgs(params);
printCalled(target, name, args);
target.invokeVarargs(args);
target.invokeWithArguments(args);
assertCalled(name, args);
if (verbosity >= 1)
System.out.print(':');
}
// rough check of name string
static void assertNameStringContains(Object x, String s) {
if (x.toString().contains(s)) return;
assertEquals(s, x);
}
@Test
public void testFindVirtual() throws Throwable {
if (CAN_SKIP_WORKING) return;
@ -522,7 +527,7 @@ public class MethodHandlesTest {
Exception noAccess = null;
try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
target = lookup.findVirtual(defc, methodName, type);
target = lookup.in(defc).findVirtual(defc, methodName, type);
} catch (NoAccessException ex) {
noAccess = ex;
}
@ -535,12 +540,12 @@ public class MethodHandlesTest {
Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)defc), params);
MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
assertEquals(typeWithSelf, target.type());
assertTrue(target.toString().contains(methodName)); // rough check
assertNameStringContains(target, methodName);
if (!DO_MORE_CALLS && lookup != PRIVATE) return;
Object[] argsWithSelf = randomArgs(paramsWithSelf);
if (rcvc != defc) argsWithSelf[0] = randomArg(rcvc);
printCalled(target, name, argsWithSelf);
target.invokeVarargs(argsWithSelf);
target.invokeWithArguments(argsWithSelf);
assertCalled(name, argsWithSelf);
if (verbosity >= 1)
System.out.print(':');
@ -576,7 +581,8 @@ public class MethodHandlesTest {
Exception noAccess = null;
try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
target = lookup.findSpecial(defc, name, type, specialCaller);
if (verbosity >= 5) System.out.println(" lookup => "+lookup.in(specialCaller));
target = lookup.in(specialCaller).findSpecial(defc, name, type, specialCaller);
} catch (NoAccessException ex) {
noAccess = ex;
}
@ -591,11 +597,11 @@ public class MethodHandlesTest {
assertEquals(type, target.type().dropParameterTypes(0,1));
Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)specialCaller), params);
MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
assertTrue(target.toString().contains(name)); // rough check
assertNameStringContains(target, name);
if (!DO_MORE_CALLS && lookup != PRIVATE && lookup != EXAMPLE) return;
Object[] args = randomArgs(paramsWithSelf);
printCalled(target, name, args);
target.invokeVarargs(args);
target.invokeWithArguments(args);
assertCalled(name, args);
}
@ -632,7 +638,7 @@ public class MethodHandlesTest {
Exception noAccess = null;
try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
target = lookup.bind(receiver, methodName, type);
target = lookup.in(defc).bind(receiver, methodName, type);
} catch (NoAccessException ex) {
noAccess = ex;
}
@ -645,7 +651,7 @@ public class MethodHandlesTest {
assertEquals(type, target.type());
Object[] args = randomArgs(params);
printCalled(target, name, args);
target.invokeVarargs(args);
target.invokeWithArguments(args);
Object[] argsWithReceiver = cat(array(Object[].class, receiver), args);
assertCalled(name, argsWithReceiver);
if (verbosity >= 1)
@ -705,9 +711,9 @@ public class MethodHandlesTest {
try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
if (isSpecial)
target = lookup.unreflectSpecial(rmethod, specialCaller);
target = lookup.in(specialCaller).unreflectSpecial(rmethod, specialCaller);
else
target = lookup.unreflect(rmethod);
target = lookup.in(defc).unreflect(rmethod);
} catch (NoAccessException ex) {
noAccess = ex;
}
@ -737,7 +743,7 @@ public class MethodHandlesTest {
}
Object[] argsMaybeWithSelf = randomArgs(paramsMaybeWithSelf);
printCalled(target, name, argsMaybeWithSelf);
target.invokeVarargs(argsMaybeWithSelf);
target.invokeWithArguments(argsMaybeWithSelf);
assertCalled(name, argsMaybeWithSelf);
if (verbosity >= 1)
System.out.print(':');
@ -875,7 +881,7 @@ public class MethodHandlesTest {
if (isStatic) expType = expType.dropParameterTypes(0, 1);
MethodHandle mh = lookup.unreflectGetter(f);
assertSame(mh.type(), expType);
assertEquals(mh.toString(), fname);
assertNameStringContains(mh, fname);
HasFields fields = new HasFields();
Object sawValue;
Class<?> rtype = type;
@ -885,12 +891,12 @@ public class MethodHandlesTest {
for (int i = 0; i <= 1; i++) {
if (isStatic) {
if (type == int.class)
sawValue = mh.<int>invokeExact(); // do these exactly
sawValue = (int) mh.invokeExact(); // do these exactly
else
sawValue = mh.invokeExact();
} else {
if (type == int.class)
sawValue = mh.<int>invokeExact((Object) fields);
sawValue = (int) mh.invokeExact((Object) fields);
else
sawValue = mh.invokeExact((Object) fields);
}
@ -947,7 +953,7 @@ public class MethodHandlesTest {
mh = lookup.findStaticSetter(fclass, fname, ftype);
else throw new InternalError();
assertSame(mh.type(), expType);
assertEquals(mh.toString(), fname);
assertNameStringContains(mh, fname);
HasFields fields = new HasFields();
Object sawValue;
Class<?> vtype = type;
@ -959,14 +965,14 @@ public class MethodHandlesTest {
Object putValue = randomArg(type);
if (isStatic) {
if (type == int.class)
mh.<void>invokeExact((int)(Integer)putValue); // do these exactly
mh.invokeExact((int)putValue); // do these exactly
else
mh.<void>invokeExact(putValue);
mh.invokeExact(putValue);
} else {
if (type == int.class)
mh.<void>invokeExact((Object) fields, (int)(Integer)putValue);
mh.invokeExact((Object) fields, (int)putValue);
else
mh.<void>invokeExact((Object) fields, putValue);
mh.invokeExact((Object) fields, putValue);
}
assertEquals(f.get(fields), putValue);
}
@ -1032,11 +1038,11 @@ public class MethodHandlesTest {
model.set(i, random);
if (testSetter) {
if (elemType == int.class)
mh.<void>invokeExact((int[]) array, i, (int)(Integer)random);
mh.invokeExact((int[]) array, i, (int)random);
else if (elemType == boolean.class)
mh.<void>invokeExact((boolean[]) array, i, (boolean)(Boolean)random);
mh.invokeExact((boolean[]) array, i, (boolean)random);
else
mh.<void>invokeExact(array, i, random);
mh.invokeExact(array, i, random);
assertEquals(model, array2list(array));
} else {
Array.set(array, i, random);
@ -1052,9 +1058,9 @@ public class MethodHandlesTest {
if (!testSetter) {
expValue = sawValue;
if (elemType == int.class)
sawValue = mh.<int>invokeExact((int[]) array, i);
sawValue = (int) mh.invokeExact((int[]) array, i);
else if (elemType == boolean.class)
sawValue = mh.<boolean>invokeExact((boolean[]) array, i);
sawValue = (boolean) mh.invokeExact((boolean[]) array, i);
else
sawValue = mh.invokeExact(array, i);
assertEquals(sawValue, expValue);
@ -1102,6 +1108,18 @@ public class MethodHandlesTest {
}
}
static MethodHandle typeHandler2(MethodHandle target, MethodType newType) {
MethodType oldType = target.type();
int oldArity = oldType.parameterCount();
int newArity = newType.parameterCount();
if (newArity < oldArity)
return MethodHandles.insertArguments(target, oldArity, "OPTIONAL");
else if (newArity > oldArity)
return MethodHandles.dropArguments(target, oldArity-1, newType.parameterType(oldArity-1));
else
return target; // attempt no further conversions
}
@Test
public void testConvertArguments() throws Throwable {
if (CAN_SKIP_WORKING) return;
@ -1115,10 +1133,29 @@ public class MethodHandlesTest {
}
void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
testConvert(true, id, rtype, name, params);
testConvert(true, false, id, rtype, name, params);
testConvert(true, true, id, rtype, name, params);
}
void testConvert(boolean positive, MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
@Test
public void testTypeHandler() throws Throwable {
MethodHandle id = Callee.ofType(1);
MethodHandle th2 = PRIVATE.findStatic(MethodHandlesTest.class, "typeHandler2",
MethodType.methodType(MethodHandle.class, MethodHandle.class, MethodType.class));
MethodHandle id2 = id.withTypeHandler(th2);
testConvert(true, false, id2, null, "id", Object.class);
testConvert(true, true, id2, null, "id", Object.class);
if (true) return; //FIXME
testConvert(true, false, id2, null, "id", String.class); // FIXME: throws WMT
testConvert(false, true, id2, null, "id", String.class); // FIXME: should not succeed
testConvert(false, false, id2, null, "id", Object.class, String.class); //FIXME: array[1] line 1164
testConvert(true, true, id2, null, "id", Object.class, String.class);
testConvert(false, false, id2, null, "id");
testConvert(true, true, id2, null, "id");
}
void testConvert(boolean positive, boolean useAsType,
MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
countTest(positive);
MethodType idType = id.type();
if (rtype == null) rtype = idType.returnType();
@ -1135,7 +1172,7 @@ public class MethodHandlesTest {
if (src != dst)
convArgs[i] = castToWrapper(convArgs[i], dst);
}
Object convResult = id.invokeVarargs(convArgs);
Object convResult = id.invokeWithArguments(convArgs);
{
Class<?> dst = newType.returnType();
Class<?> src = idType.returnType();
@ -1145,7 +1182,10 @@ public class MethodHandlesTest {
MethodHandle target = null;
RuntimeException error = null;
try {
target = MethodHandles.convertArguments(id, newType);
if (useAsType)
target = MethodHandles.convertArguments(id, newType);
else
target = id.asType(newType);
} catch (RuntimeException ex) {
error = ex;
}
@ -1157,7 +1197,7 @@ public class MethodHandlesTest {
if (!positive) return; // negative test failed as expected
assertEquals(newType, target.type());
printCalled(target, id.toString(), args);
Object result = target.invokeVarargs(args);
Object result = target.invokeWithArguments(args);
assertCalled(name, convArgs);
assertEquals(convResult, result);
if (verbosity >= 1)
@ -1279,7 +1319,7 @@ public class MethodHandlesTest {
MethodType outType = MethodType.methodType(Object.class, permTypes);
MethodHandle target = MethodHandles.convertArguments(ValueConversions.varargsList(outargs), outType);
MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder);
Object result = newTarget.invokeVarargs(args);
Object result = newTarget.invokeWithArguments(args);
Object expected = Arrays.asList(permArgs);
assertEquals(expected, result);
}
@ -1311,19 +1351,19 @@ public class MethodHandlesTest {
Object[] args = randomArgs(target2.type().parameterArray());
// make sure the target does what we think it does:
if (pos == 0 && nargs < 5) {
Object[] check = (Object[]) target.invokeVarargs(args);
Object[] check = (Object[]) target.invokeWithArguments(args);
assertArrayEquals(args, check);
switch (nargs) {
case 0:
check = target.<Object[]>invokeExact();
check = (Object[]) target.invokeExact();
assertArrayEquals(args, check);
break;
case 1:
check = target.<Object[]>invokeExact(args[0]);
check = (Object[]) target.invokeExact(args[0]);
assertArrayEquals(args, check);
break;
case 2:
check = target.<Object[]>invokeExact(args[0], args[1]);
check = (Object[]) target.invokeExact(args[0], args[1]);
assertArrayEquals(args, check);
break;
}
@ -1337,12 +1377,15 @@ public class MethodHandlesTest {
MethodHandle result = MethodHandles.spreadArguments(target2, newType);
Object[] returnValue;
if (pos == 0) {
Object rawRetVal = result.invokeExact(args);
returnValue = (Object[]) rawRetVal;
// In the following line, the first cast implies
// normal Object return value for the MH call (Object[])->Object,
// while the second cast dynamically converts to an Object array.
// Such a double cast is typical of MH.invokeExact.
returnValue = (Object[]) (Object) result.invokeExact(args);
} else {
Object[] args1 = Arrays.copyOfRange(args, 0, pos+1);
args1[pos] = Arrays.copyOfRange(args, pos, args.length);
returnValue = (Object[]) result.invokeVarargs(args1);
returnValue = (Object[]) result.invokeWithArguments(args1);
}
assertArrayEquals(args, returnValue);
}
@ -1379,7 +1422,7 @@ public class MethodHandlesTest {
if (verbosity >= 3)
System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]");
MethodHandle result = MethodHandles.collectArguments(target, newType);
Object[] returnValue = (Object[]) result.invokeVarargs(args);
Object[] returnValue = (Object[]) result.invokeWithArguments(args);
// assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]);
// returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]);
// collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]);
@ -1412,7 +1455,7 @@ public class MethodHandlesTest {
MethodHandle target2 = MethodHandles.insertArguments(target, pos,
(Object[]) argsToInsert.toArray());
argsToInsert.clear(); // remove from argsToInsert
Object res2 = target2.invokeVarargs(argsToPass);
Object res2 = target2.invokeWithArguments(argsToPass);
Object res2List = Arrays.asList((Object[])res2);
if (verbosity >= 3)
System.out.println("result: "+res2List);
@ -1440,14 +1483,12 @@ public class MethodHandlesTest {
Object[] argsToPass = randomArgs(nargs, Object.class);
if (verbosity >= 3)
System.out.println("filter "+target+" at "+pos+" with "+filter);
MethodHandle[] filters = new MethodHandle[pos*2+1];
filters[pos] = filter;
MethodHandle target2 = MethodHandles.filterArguments(target, filters);
MethodHandle target2 = MethodHandles.filterArguments(target, pos, filter);
// Simulate expected effect of filter on arglist:
Object[] filteredArgs = argsToPass.clone();
filteredArgs[pos] = filter.invokeExact(filteredArgs[pos]);
List<Object> expected = Arrays.asList(filteredArgs);
Object result = target2.invokeVarargs(argsToPass);
Object result = target2.invokeWithArguments(argsToPass);
if (verbosity >= 3)
System.out.println("result: "+result);
if (!expected.equals(result))
@ -1472,7 +1513,7 @@ public class MethodHandlesTest {
if (pos != 0) return; // can fold only at pos=0 for now
countTest();
MethodHandle target = ValueConversions.varargsList(1 + nargs);
MethodHandle combine = ValueConversions.varargsList(fold);
MethodHandle combine = ValueConversions.varargsList(fold).asType(MethodType.genericMethodType(fold));
List<Object> argsToPass = Arrays.asList(randomArgs(nargs, Object.class));
if (verbosity >= 3)
System.out.println("fold "+target+" with "+combine);
@ -1482,9 +1523,9 @@ public class MethodHandlesTest {
List<Object> argsToFold = expected.subList(pos, pos + fold);
if (verbosity >= 3)
System.out.println("fold: "+argsToFold+" into "+target2);
Object foldedArgs = combine.invokeVarargs(argsToFold);
Object foldedArgs = combine.invokeWithArguments(argsToFold);
argsToFold.add(0, foldedArgs);
Object result = target2.invokeVarargs(argsToPass);
Object result = target2.invokeWithArguments(argsToPass);
if (verbosity >= 3)
System.out.println("result: "+result);
if (!expected.equals(result))
@ -1516,7 +1557,7 @@ public class MethodHandlesTest {
for (int i = drop; i > 0; i--) {
argsToDrop.add(pos, "blort#"+i);
}
Object res2 = target2.invokeVarargs(argsToDrop);
Object res2 = target2.invokeWithArguments(argsToDrop);
Object res2List = Arrays.asList((Object[])res2);
//if (!resList.equals(res2List))
// System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List);
@ -1572,7 +1613,7 @@ public class MethodHandlesTest {
countTest();
calledLog.clear();
inv = MethodHandles.exactInvoker(type);
result = inv.invokeVarargs(targetPlusArgs);
result = inv.invokeWithArguments(targetPlusArgs);
if (testRetCode) assertEquals(code, result);
assertCalled("invokee", args);
// generic invoker
@ -1598,7 +1639,7 @@ public class MethodHandlesTest {
assertCalled("invokee", args);
}
calledLog.clear();
result = inv.invokeVarargs(targetPlusArgs);
result = inv.invokeWithArguments(targetPlusArgs);
if (testRetCode) assertEquals(code, result);
assertCalled("invokee", args);
// varargs invoker #0
@ -1640,17 +1681,29 @@ public class MethodHandlesTest {
List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs);
Object[] tail = tailList.toArray();
tailList.clear(); tailList.add(tail);
result = inv.invokeVarargs(targetPlusVarArgs);
result = inv.invokeWithArguments(targetPlusVarArgs);
if (testRetCode) assertEquals(code, result);
assertCalled("invokee", args);
}
// dynamic invoker
countTest();
CallSite site = new CallSite(MethodHandlesTest.class, "foo", type);
inv = MethodHandles.dynamicInvoker(site);
CallSite site = new MutableCallSite(type);
inv = site.dynamicInvoker();
// see if we get the result of the original target:
try {
result = inv.invokeWithArguments(args);
assertTrue("should not reach here", false);
} catch (IllegalStateException ex) {
String msg = ex.getMessage();
assertTrue(msg, msg.contains("site"));
}
// set new target after invoker is created, to make sure we track target
site.setTarget(target);
calledLog.clear();
result = inv.invokeVarargs(args);
result = inv.invokeWithArguments(args);
if (testRetCode) assertEquals(code, result);
assertCalled("invokee", args);
}
@ -1734,7 +1787,7 @@ public class MethodHandlesTest {
String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals");
if (verbosity >= 3)
System.out.println(logEntry(willCall, argList));
Object result = mh.invokeVarargs(argList);
Object result = mh.invokeWithArguments(argList);
assertCalled(willCall, argList);
}
}
@ -1767,16 +1820,17 @@ public class MethodHandlesTest {
MethodHandle throwOrReturn
= PRIVATE.findStatic(MethodHandlesTest.class, "throwOrReturn",
MethodType.methodType(Object.class, Object.class, Throwable.class));
MethodHandle thrower = throwOrReturn;
MethodHandle thrower = throwOrReturn.asType(MethodType.genericMethodType(2));
while (thrower.type().parameterCount() < nargs)
thrower = MethodHandles.dropArguments(thrower, thrower.type().parameterCount(), Object.class);
MethodHandle catcher = ValueConversions.varargsList(1+nargs).asType(MethodType.genericMethodType(1+nargs));
MethodHandle target = MethodHandles.catchException(thrower,
thrown.getClass(), ValueConversions.varargsList(1+nargs));
thrown.getClass(), catcher);
assertEquals(thrower.type(), target.type());
//System.out.println("catching with "+target+" : "+throwOrReturn);
Object[] args = randomArgs(nargs, Object.class);
args[1] = (throwIt ? thrown : null);
Object returned = target.invokeVarargs(args);
Object returned = target.invokeWithArguments(args);
//System.out.println("return from "+target+" : "+returned);
if (!throwIt) {
assertSame(args[0], returned);
@ -1828,13 +1882,10 @@ public class MethodHandlesTest {
testCastFailure("unbox/return", 11000);
}
static class Surprise implements MethodHandleProvider {
static class Surprise {
public MethodHandle asMethodHandle() {
return VALUE.bindTo(this);
}
public MethodHandle asMethodHandle(MethodType type) {
return asMethodHandle().asType(type);
}
Object value(Object x) {
trace("value", x);
if (boo != null) return boo;
@ -1896,8 +1947,8 @@ public class MethodHandlesTest {
}
if (callee != null) {
callee = MethodHandles.convertArguments(callee, MethodType.genericMethodType(1));
surprise = MethodHandles.filterArguments(callee, surprise);
identity = MethodHandles.filterArguments(callee, identity);
surprise = MethodHandles.filterArguments(callee, 0, surprise);
identity = MethodHandles.filterArguments(callee, 0, identity);
}
}
assertNotSame(mode, surprise, surprise0);
@ -1949,7 +2000,7 @@ public class MethodHandlesTest {
assertEquals(mt, mh.type());
assertEquals(Example.class, mh.type().returnType());
args = randomArgs(mh.type().parameterArray());
mh.invokeVarargs(args);
mh.invokeWithArguments(args);
assertCalled(name, args);
// Try a virtual method.
@ -1959,7 +2010,7 @@ public class MethodHandlesTest {
assertEquals(mt, mh.type().dropParameterTypes(0,1));
assertTrue(mh.type().parameterList().contains(Example.class));
args = randomArgs(mh.type().parameterArray());
mh.invokeVarargs(args);
mh.invokeWithArguments(args);
assertCalled(name, args);
}

File diff suppressed because it is too large Load Diff