diff --git a/make/java/dyn/Makefile b/make/java/dyn/Makefile index af7bec9d24f9644e27ac7e6e03f56a812051e021..a85b51681269027fb5adf100730dabb02c3624d0 100644 --- a/make/java/dyn/Makefile +++ b/make/java/dyn/Makefile @@ -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 diff --git a/src/share/classes/java/dyn/BootstrapMethod.java b/src/share/classes/java/dyn/BootstrapMethod.java deleted file mode 100644 index a5c41b4854be591e0bd5900b8575f04f644b9618..0000000000000000000000000000000000000000 --- a/src/share/classes/java/dyn/BootstrapMethod.java +++ /dev/null @@ -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 - * bootstrap method - * 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. - *
- * If only the value is given, it must name a subclass of {@link CallSite}
- * with a constructor which accepts a class, string, and method type.
- * If the value and name 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}.
- *
- * 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. - *
- * Examples: -
-@BootstrapMethod(value=MyLanguageRuntime.class, name="bootstrapDynamic")
-String x = (String) InvokeDynamic.greet();
-//BSM => MyLanguageRuntime.bootstrapDynamic(Here.class, "greet", methodType(String.class))
-@BootstrapMethod(MyCallSite.class)
-void example() throws Throwable {
- InvokeDynamic.greet();
- //BSM => new MyCallSite(Here.class, "greet", methodType(void.class))
-}
-
- * - */ -@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}; -} diff --git a/src/share/classes/java/dyn/CallSite.java b/src/share/classes/java/dyn/CallSite.java index 7c4ed52ea68d371ba77fb98b8b91df30dfe8d859..2290aa84e2b4cf23f94067d97ea570f4684d4511 100644 --- a/src/share/classes/java/dyn/CallSite.java +++ b/src/share/classes/java/dyn/CallSite.java @@ -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}. *
- * A call site is initially created in an unlinked 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. + *
- * A call site may be relinked 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 relinked 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. *
- * 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. - *
* Here is a sample use of call sites and bootstrap methods which links every * dynamic call site to print its arguments:
-@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));
}
* @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.
+ * + * 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.) - *
- * 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. + * Report the current linkage state of the call site, a value which may change over time. *
- * 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}. + * 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. *
- * 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. *
* 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 + *
+ * In a {@linkplain ConstantCallSite constant call site}, the {@code getTarget} method behaves + * like a read from a {@code final} field of the {@code CallSite}. + *
+ * In a {@linkplain VolatileCallSite volatile call site}, the {@code getTarget} method behaves + * like a read from a {@code volatile} field of the {@code CallSite}. + *
+ * 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. *
- * 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. *
@@ -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); } /** - * PROVISIONAL API, WORK IN PROGRESS: * Produce a method handle equivalent to an invokedynamic instruction * which has been linked to this call site. - *
If this call site is a {@link ConstantCallSite}, this method - * simply returns the call site's target, since that will not change. + *
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. *
Otherwise, this method is equivalent to the following code: *
* 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");
+ }
+
+ // 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); }
+ }
- /** Implementation of {@link MethodHandleProvider}, which returns {@code this.dynamicInvoker().asType(type)}. */
- public final MethodHandle asMethodHandle(MethodType type) { return dynamicInvoker().asType(type); }
+ /*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);
+ }
}
diff --git a/src/share/classes/java/dyn/ClassValue.java b/src/share/classes/java/dyn/ClassValue.java
index 325d55e0742ad43759563fb06dbf06ed6456bc06..7b00a727d07091a45de63bbf434d8eaff32b5b32 100644
--- a/src/share/classes/java/dyn/ClassValue.java
+++ b/src/share/classes/java/dyn/ClassValue.java
@@ -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 {
+public class ClassValue {
/**
* Compute the given class's derived value for this {@code ClassValue}.
*
* 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.
*
* 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}.
+ *
+ * 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.
*
* 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 {
/**
* 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.
+ *
+ * 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 {
// 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);
diff --git a/src/share/classes/java/dyn/ConstantCallSite.java b/src/share/classes/java/dyn/ConstantCallSite.java
index e03fa8d3368772af2a35b429064ad1a3492e6be9..585fdc712cef9352ecacff7657f9d89cc68a0d8c 100644
--- a/src/share/classes/java/dyn/ConstantCallSite.java
+++ b/src/share/classes/java/dyn/ConstantCallSite.java
@@ -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");
}
}
diff --git a/src/share/classes/java/dyn/InvokeDynamic.java b/src/share/classes/java/dyn/InvokeDynamic.java
index 4406363a9908cdff3b68089211bea0334091d12d..9c3ede1ee367cdb5f35e8a7eaba1833fc2aa2fd8 100644
--- a/src/share/classes/java/dyn/InvokeDynamic.java
+++ b/src/share/classes/java/dyn/InvokeDynamic.java
@@ -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 the package information for specifics on this instruction.)
- *
- * 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.
- *
- * 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.
- *
- * Here are some examples:
-
-@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) { ... }
-
- * Each of the above calls generates a single invokedynamic instruction
- * with the name-and-type descriptors indicated in the comments.
- *
- * The argument types are taken directly from the actual arguments,
- * while the return type 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.)
- *
- * The final example uses a special syntax for uttering non-Java names.
- * Any name legal to the JVM may be given between the double quotes.
- *
- * None of these calls is complete without a bootstrap method,
- * which must be 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
}
diff --git a/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java b/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
index 3820e94c7747a40fbc48f825ae76117d300df822..1fe1af02b45901516845354e05dc9811174f12be 100644
--- a/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
+++ b/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
@@ -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);
+ }
}
diff --git a/src/share/classes/java/dyn/Linkage.java b/src/share/classes/java/dyn/Linkage.java
index 98eedbbabfbba4781e3b6e54f5d6e46d2f9610fa..76abe2430a3ba2276bf9baa5a056b3c204dc7370 100644
--- a/src/share/classes/java/dyn/Linkage.java
+++ b/src/share/classes/java/dyn/Linkage.java
@@ -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.
+ * CLASS WILL BE REMOVED FOR PFD:
+ * 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
/**
- * PROVISIONAL API, WORK IN PROGRESS:
+ * METHOD WILL BE REMOVED FOR PFD:
* Register a bootstrap method to use when linking dynamic call sites within
* a given caller class.
- *
- * A bootstrap method must be a method handle with a return type of {@link CallSite}
- * and the following arguments:
- *
- * - the class containing the {@code invokedynamic} instruction, for which the bootstrap method was registered
- *
- the name of the method being invoked (a {@link String})
- *
- the type of the method being invoked (a {@link MethodType})
- *
- * 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}).
- *
- * 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:
- *
- * - 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).
- *
- The given caller class already has a bootstrap method registered.
- *
- The given caller class is already fully initialized.
- *
- The given caller class is in the process of initialization, in another thread.
- *
- * 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());
- }
-
/**
- * PROVISIONAL API, WORK IN PROGRESS:
+ * METHOD WILL BE REMOVED FOR PFD:
* 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 {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
+ * METHOD WILL BE REMOVED FOR PFD:
* 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);
}
- /**
- * PROVISIONAL API, WORK IN PROGRESS:
- * 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);
- }
-
- /**
- * PROVISIONAL API, WORK IN PROGRESS:
- * 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);
/**
- * PROVISIONAL API, WORK IN PROGRESS:
+ * METHOD WILL BE REMOVED FOR PFD:
* Invalidate all invokedynamic call sites everywhere.
- *
- * When this method returns, every invokedynamic instruction
- * will invoke its bootstrap method on next call.
- *
- * It is unspecified whether call sites already known to the Java
- * code will continue to be associated with invokedynamic
- * instructions. If any call site is still so associated, its
- * {@link CallSite#getTarget()} method is guaranteed to return null
- * the invalidation operation completes.
- *
- * 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();
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
+ * METHOD WILL BE REMOVED FOR PFD:
* Invalidate all {@code invokedynamic} call sites in the bytecodes
* of any methods of the given class.
- *
- * When this method returns, every matching invokedynamic
- * instruction will invoke its bootstrap method on next call.
- *
- * 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();
}
}
diff --git a/src/share/classes/java/dyn/LinkagePermission.java b/src/share/classes/java/dyn/LinkagePermission.java
deleted file mode 100644
index 9861843918d151f8ac1928cb1d48fd58fe6fdfb6..0000000000000000000000000000000000000000
--- a/src/share/classes/java/dyn/LinkagePermission.java
+++ /dev/null
@@ -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;
-
-/**
- * PROVISIONAL API, WORK IN PROGRESS:
- * 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.
- *
- * 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.
- *
- *
- *
- *
- * Permission Target Name
- * What the Permission Allows
- * Risks of Allowing this Permission
- *
- *
- *
- * invalidateAll
- * Force the relinking of invokedynamic call sites everywhere.
- * 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.
- *
- *
- *
- *
- * invalidateCallerClass.{class name}
- * Force the relinking of invokedynamic call sites in the given class.
- * See {@code invalidateAll}.
- *
- *
- * 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());
- }
-}
diff --git a/src/share/classes/java/dyn/MethodHandle.java b/src/share/classes/java/dyn/MethodHandle.java
index 4904e975306b2a69ce0817c57b5e497e7f535a3a..25d0f807488c5688c3c7cd46c0748fdc3e075d02 100644
--- a/src/share/classes/java/dyn/MethodHandle.java
+++ b/src/share/classes/java/dyn/MethodHandle.java
@@ -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}.
+ *
+ * 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.
*
* 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}.
*
- * 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).
*
* 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}.
*
+ * 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.
+ *
* 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.
*
- * 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.
*
- * 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.
*
- * 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 package summary.)
*
- * 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}.
*
* 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.<String>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[] => 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.<int>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
*
* 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}.
* * A note on generic typing: Method handles do not represent * their function types in terms of Java parameterized (generic) types, @@ -162,7 +209,7 @@ assert(i == 3); * Java types. *
+ * 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. + *
+ * 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 + * CONSTRUCTOR WILL BE REMOVED FOR PFD: + * 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: + *
+ *+ * "MethodHandle" + type().toString() + *
+ * 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.
-
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* 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
- * 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}.
*
* 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.
+ *
+ * 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.
+ *
+ * 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
- * 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.
+ *
- * 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:
*
* The result returned by the call is boxed if it is a primitive,
* or forced to null if the return type is void.
*
* This call is equivalent to the following code:
*
* If the original type and new type are equal, returns {@code this}.
*
- * 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:
- *
- */
- /**
- * PROVISIONAL API, WORK IN PROGRESS:
- * 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.
+ * 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}.
*
- * If the original type and new type are equal, returns {@code this}.
- *
- * This method is equivalent to {@link MethodHandles#convertArguments}.
+ * 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);
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle which adapts, as its target,
* 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}.
+ *
+ * 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}.
*
* 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);
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle which adapts, as its target,
* 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}.
+ *
+ * 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}.
*
- * When called, the adapter replaces its trailing {@code spreadArrayArgs}
- * arguments by a single new {@code Object} array, whose elements
+ * 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.
*
- * (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.
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Therefore, the type handler is invoked as if by this code:
+ *
+ * For example, here is a list-making variable-arity method handle:
+ *
- * 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.
- *
- * 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 incorrect 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.
- *
- * 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
- * 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.
- *
- * 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;
-}
diff --git a/src/share/classes/java/dyn/MethodHandles.java b/src/share/classes/java/dyn/MethodHandles.java
index b6e8333834094497ecc7c8105a8f5bb5c440cd05..d2de0c24a488f495abe99be6a83d62f4d674fd9c 100644
--- a/src/share/classes/java/dyn/MethodHandles.java
+++ b/src/share/classes/java/dyn/MethodHandles.java
@@ -29,6 +29,7 @@ import java.lang.reflect.*;
import sun.dyn.Access;
import sun.dyn.MemberName;
import sun.dyn.MethodHandleImpl;
+import sun.dyn.util.ValueConversions;
import sun.dyn.util.VerifyAccess;
import sun.dyn.util.Wrapper;
import java.util.List;
@@ -135,28 +136,58 @@ public class MethodHandles {
* In general, the conditions under which a method handle may be
* created for a method {@code M} are exactly as restrictive as the conditions
* under which the lookup class could have compiled a call to {@code M}.
- * This rule is applied even if the Java compiler might have created
+ *
+ * In some cases, this access is obtained by the Java compiler by creating
* an wrapper method to access a private method of another class
* in the same top-level declaration.
- * For example, a lookup object created for a nested class {@code C.D}
+ * For example, a nested class {@code C.D}
* can access private members within other related classes such as
- * {@code C}, {@code C.D.E}, or {@code C.B}.
+ * {@code C}, {@code C.D.E}, or {@code C.B},
+ * but the Java compiler may need to generate wrapper methods in
+ * those related classes. In such cases, a {@code Lookup} object on
+ * {@code C.E} would be unable to those private members.
+ * A workaround for this limitation is the {@link Lookup#in Lookup.in} method,
+ * which can transform a lookup on {@code C.E} into one on any of those other
+ * classes, without special elevation of privilege.
*/
public static final
class Lookup {
/** The class on behalf of whom the lookup is being performed. */
private final Class> lookupClass;
- /** The allowed sorts of members which may be looked up (public, etc.), with STATIC for package. */
+ /** The allowed sorts of members which may be looked up (PUBLIC, etc.). */
private final int allowedModes;
- private static final int
- PUBLIC = Modifier.PUBLIC,
- PACKAGE = Modifier.STATIC,
- PROTECTED = Modifier.PROTECTED,
- PRIVATE = Modifier.PRIVATE,
- ALL_MODES = (PUBLIC | PACKAGE | PROTECTED | PRIVATE),
- TRUSTED = -1;
+ /** A single-bit mask representing {@code public} access,
+ * which may contribute to the result of {@link #lookupModes lookupModes}.
+ * The value, {@code 0x01}, happens to be the same as the value of the
+ * {@code public} {@linkplain java.lang.reflect.Modifier#PUBLIC modifier bit}.
+ */
+ public static final int PUBLIC = Modifier.PUBLIC;
+
+ /** A single-bit mask representing {@code private} access,
+ * which may contribute to the result of {@link #lookupModes lookupModes}.
+ * The value, {@code 0x02}, happens to be the same as the value of the
+ * {@code private} {@linkplain java.lang.reflect.Modifier#PRIVATE modifier bit}.
+ */
+ public static final int PRIVATE = Modifier.PRIVATE;
+
+ /** A single-bit mask representing {@code protected} access,
+ * which may contribute to the result of {@link #lookupModes lookupModes}.
+ * The value, {@code 0x04}, happens to be the same as the value of the
+ * {@code protected} {@linkplain java.lang.reflect.Modifier#PROTECTED modifier bit}.
+ */
+ public static final int PROTECTED = Modifier.PROTECTED;
+
+ /** A single-bit mask representing {@code package} access (default access),
+ * which may contribute to the result of {@link #lookupModes lookupModes}.
+ * The value is {@code 0x08}, which does not correspond meaningfully to
+ * any particular {@linkplain java.lang.reflect.Modifier modifier bit}.
+ */
+ public static final int PACKAGE = Modifier.STATIC;
+
+ private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE);
+ private static final int TRUSTED = -1;
private static int fixmods(int mods) {
mods &= (ALL_MODES - PACKAGE);
@@ -181,13 +212,21 @@ public class MethodHandles {
}
/** Which types of members can this lookup object produce?
- * The result is a bit-mask of the {@link Modifier} bits
- * {@linkplain Modifier#PUBLIC PUBLIC (0x01)},
- * {@linkplain Modifier#PROTECTED PROTECTED (0x02)},
- * {@linkplain Modifier#PRIVATE PRIVATE (0x04)},
- * and {@linkplain Modifier#STATIC STATIC (0x08)}.
- * The modifier bit {@code STATIC} stands in for the package protection mode,
- * which does not have an explicit modifier bit.
+ * The result is a bit-mask of the bits
+ * {@linkplain #PUBLIC PUBLIC (0x01)},
+ * {@linkplain #PRIVATE PRIVATE (0x02)},
+ * {@linkplain #PROTECTED PROTECTED (0x04)},
+ * and {@linkplain #PACKAGE PACKAGE (0x08)}.
+ *
+ * A freshly-created lookup object
+ * on the {@linkplain java.dyn.MethodHandles#lookup() caller's class}
+ * has all possible bits set, since the caller class can access all its own members.
+ * A lookup object on a new lookup class
+ * {@linkplain java.dyn.MethodHandles.Lookup#in created from a previous lookup object}
+ * may have some mode bits set to zero.
+ * The purpose of this is to restrict access via the new lookup object,
+ * so that it can access only names which can be reached by the original
+ * lookup object, and also by the new lookup class.
*/
public int lookupModes() {
return allowedModes & ALL_MODES;
@@ -220,18 +259,21 @@ public class MethodHandles {
/**
* Create a lookup on the specified new lookup class.
* The resulting object will report the specified
- * class as its own {@link #lookupClass}.
+ * class as its own {@link #lookupClass lookupClass}.
*
* However, the resulting {@code Lookup} object is guaranteed
* to have no more access capabilities than the original.
- * In particular:
- * (BUG NOTE: The type {@code Object} may be prepended instead
- * of the receiver type, if the receiver type is not on the boot class path.
- * This is due to a temporary JVM limitation, in which MethodHandle
- * claims to be unable to access such classes. To work around this
- * bug, use {@code convertArguments} to normalize the type of the leading
- * argument to a type on the boot class path, such as {@code Object}.)
- *
* When called, the handle will treat the first argument as a receiver
* and dispatch on the receiver's type to determine which method
* implementation to enter.
@@ -358,7 +407,6 @@ public class MethodHandles {
* @param name the name of the method
* @param type the type of the method, with the receiver argument omitted
* @return the desired method handle
- * @exception SecurityException TBD
* @exception NoAccessException if the method does not exist or access checking fails
*/
public MethodHandle findVirtual(Class> refc, String name, MethodType type) throws NoAccessException {
@@ -382,7 +430,6 @@ public class MethodHandles {
* @param refc the class or interface from which the method is accessed
* @param type the type of the method, with the receiver argument omitted, and a void return type
* @return the desired method handle
- * @exception SecurityException TBD
* @exception NoAccessException if the method does not exist or access checking fails
*/
public MethodHandle findConstructor(Class> refc, MethodType type) throws NoAccessException {
@@ -409,13 +456,13 @@ public class MethodHandles {
* {@code invokespecial} instruction.)
*
* If the explicitly specified caller class is not identical with the
- * lookup class, a security check TBD is performed.
+ * lookup class, or if this lookup object does not have private access
+ * privileges, the access fails.
* @param refc the class or interface from which the method is accessed
* @param name the name of the method (which must not be "<init>")
* @param type the type of the method, with the receiver argument omitted
* @param specialCaller the proposed calling class to perform the {@code invokespecial}
* @return the desired method handle
- * @exception SecurityException TBD
* @exception NoAccessException if the method does not exist or access checking fails
*/
public MethodHandle findSpecial(Class> refc, String name, MethodType type,
@@ -428,7 +475,6 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle giving read access to a non-static field.
* The type of the method handle will have a return type of the field's
* value type.
@@ -445,7 +491,6 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle giving write access to a non-static field.
* The type of the method handle will have a void return type.
* The method handle will take two arguments, the instance containing
@@ -462,7 +507,6 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle giving read access to a static field.
* The type of the method handle will have a return type of the field's
* value type.
@@ -478,7 +522,6 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle giving write access to a static field.
* The type of the method handle will have a void return type.
* The method handle will take a single
@@ -515,7 +558,6 @@ public class MethodHandles {
* @param name the name of the method
* @param type the type of the method, with the receiver argument omitted
* @return the desired method handle
- * @exception SecurityException TBD
* @exception NoAccessException if the method does not exist or access checking fails
*/
public MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException {
@@ -530,7 +572,6 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Make a direct method handle to m, if the lookup class has permission.
* If m is non-static, the receiver argument is treated as an initial argument.
* If m is virtual, overriding is respected on every call.
@@ -554,7 +595,6 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle for a reflected method.
* It will bypass checks for overriding methods on the receiver,
* as if by a {@code invokespecial} instruction from within the {@code specialCaller}.
@@ -579,7 +619,6 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle for a reflected constructor.
* The type of the method handle will be that of the constructor,
* with the return type changed to the declaring class.
@@ -602,7 +641,6 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle giving read access to a reflected field.
* The type of the method handle will have a return type of the field's
* value type.
@@ -620,7 +658,6 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle giving write access to a reflected field.
* The type of the method handle will have a void return type.
* If the field is static, the method handle will take a single
@@ -681,7 +718,7 @@ public class MethodHandles {
int allowedModes = this.allowedModes;
if (allowedModes == TRUSTED) return;
int mods = m.getModifiers();
- if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers()))
+ if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers()) && allowedModes != 0)
return; // common case
int requestedModes = fixmods(mods); // adjust 0 => PACKAGE
if ((requestedModes & allowedModes) != 0
@@ -706,6 +743,8 @@ public class MethodHandles {
return "access to public member failed"; // (how?)
else if (allowedModes == PUBLIC)
return "member is not public";
+ else if (allowedModes == 0)
+ return "attempted member access through a non-public class";
if (Modifier.isPrivate(mods))
return "member is private";
if (Modifier.isProtected(mods))
@@ -713,9 +752,14 @@ public class MethodHandles {
return "member is private to package";
}
+ private static final boolean ALLOW_NESTMATE_ACCESS = false;
+
void checkSpecialCaller(Class> specialCaller) throws NoAccessException {
if (allowedModes == TRUSTED) return;
- if (!VerifyAccess.isSamePackageMember(specialCaller, lookupClass()))
+ if ((allowedModes & PRIVATE) == 0
+ || (specialCaller != lookupClass()
+ && !(ALLOW_NESTMATE_ACCESS &&
+ VerifyAccess.isSamePackageMember(specialCaller, lookupClass()))))
throw newNoAccessException("no private access for invokespecial",
new MemberName(specialCaller), lookupClass());
}
@@ -725,7 +769,9 @@ public class MethodHandles {
// on itself or a subclass. Enforce that restriction, from JVMS 5.4.4, etc.
if (!method.isProtected() || method.isStatic()
|| allowedModes == TRUSTED
- || VerifyAccess.isSamePackageMember(method.getDeclaringClass(), lookupClass()))
+ || method.getDeclaringClass() == lookupClass()
+ || (ALLOW_NESTMATE_ACCESS &&
+ VerifyAccess.isSamePackageMember(method.getDeclaringClass(), lookupClass())))
return mh;
else
return restrictReceiver(method, mh, lookupClass());
@@ -765,7 +811,6 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle giving read access to elements of an array.
* The type of the method handle will have a return type of the array's
* element type. Its first argument will be the array type,
@@ -780,7 +825,6 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle giving write access to elements of an array.
* The type of the method handle will have a void return type.
* Its last argument will be the array's element type.
@@ -796,25 +840,6 @@ public class MethodHandles {
/// method handle invocation (reflective style)
/**
- * @deprecated Alias for MethodHandle.invokeVarargs.
- */
- @Deprecated
- public static
- Object invokeVarargs(MethodHandle target, Object... arguments) throws Throwable {
- return target.invokeVarargs(arguments);
- }
-
- /**
- * @deprecated Alias for MethodHandle.invokeVarargs.
- */
- @Deprecated
- public static
- Object invoke(MethodHandle target, Object... arguments) throws Throwable {
- return target.invokeVarargs(arguments);
- }
-
- /**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle which will invoke any method handle of the
* given type on a standard set of {@code Object} type arguments.
* The resulting invoker will be a method handle with the following
@@ -823,18 +848,28 @@ public class MethodHandles {
*
+ * The invoker will behave like a call to {@link MethodHandle.invokeGeneric} with
+ * the indicated {@code type}.
+ * That is, if the target is exactly of the given {@code type}, it will behave
+ * like {@code invokeExact}; otherwise it behave as if {@link MethodHandle.asType}
+ * is used to convert the target to the required {@code type}.
+ *
+ * The type of the returned invoker will not be the given {@code type}, but rather
+ * will have all parameter and return types replaced by {@code Object}.
+ *
+ * Before invoking its target, the invoker will apply reference casts as
+ * necessary and unbox and widen primitive arguments, as if by {@link #convertArguments}.
* The return value of the invoker will be an {@code Object} reference,
* boxing a primitive value if the original type returns a primitive,
* and always null if the original type returns void.
*
* This method is equivalent to the following code (though it may be more efficient):
*
+ * The invoker will behave like a call to {@link MethodHandle.invokeGeneric} with
+ * the indicated {@code type}.
+ * That is, if the target is exactly of the given {@code type}, it will behave
+ * like {@code invokeExact}; otherwise it behave as if {@link MethodHandle.asType}
+ * is used to convert the target to the required {@code type}.
+ *
+ * The type of the returned invoker will not be the given {@code type}, but rather
+ * will have all parameter and return types replaced by {@code Object}, except for
+ * the last parameter type, which will be the array type {@code Object[]}.
+ *
+ * Before invoking its target, the invoker will spread the varargs array, apply
+ * reference casts as necessary, and unbox and widen primitive arguments.
* The return value of the invoker will be an {@code Object} reference,
* boxing a primitive value if the original type returns a primitive,
* and always null if the original type returns void.
*
* This method is equivalent to the following code (though it may be more efficient):
*
* This method is equivalent to the following code (though it may be more efficient):
* This method is equivalent to the following code:
- *
* If the original type and new type are equal, returns target.
@@ -1023,34 +1036,21 @@ public class MethodHandles {
* Given those types T0, T1, one of the following conversions is applied
* if possible:
*
+ * If the original type and new type are equal, returns target.
+ *
+ * The same conversions are allowed as for {@link #convertArguments convertArguments},
+ * and some additional conversions are also applied if those conversions fail.
+ * Given types T0, T1, one of the following conversions is applied
+ * in addition, if the conversions specified for {@code convertArguments}
+ * would be insufficient:
+ *
* The given array controls the reordering.
@@ -1092,22 +1175,42 @@ public class MethodHandles {
* outgoing argument will be taken from the {@code I}-th incoming
* argument, where {@code I} is {@code reorder[N]}.
*
+ * No argument or return value conversions are applied.
+ * The type of each incoming argument, as determined by {@code newType},
+ * must be identical to the type of the corresponding outgoing argument
+ * or arguments in the target method handle.
+ * The return type of {@code newType} must be identical to the return
+ * type of the original target.
+ *
* The reordering array need not specify an actual permutation.
* An incoming argument will be duplicated if its index appears
* more than once in the array, and an incoming argument will be dropped
* if its index does not appear in the array.
- *
- * Pairwise conversions are applied as needed to arguments and return
- * values, as with {@link #convertArguments}.
+ * As in the case of {@link #dropArguments(MethodHandle,int,List) dropArguments},
+ * incoming arguments which are not mentioned in the reordering array
+ * are may be any type, as determined only by {@code newType}.
+ *
- * The final parameter type of the new type must be an array type T[].
- * This is the type of what is called the spread argument.
- * All other arguments of the new type are called ordinary arguments.
- *
- * The ordinary arguments of the new type are pairwise converted
- * to the initial parameter types of the old type, according to the
- * rules in {@link #convertArguments}.
- * Any additional arguments in the old type
- * are converted from the array element type T,
- * again according to the rules in {@link #convertArguments}.
- * The return value is converted according likewise.
- *
- * The call verifies that the spread argument is in fact an array
- * of exactly the type length, i.e., the excess number of
- * arguments in the old type over the ordinary arguments in the new type.
- * If there are no excess arguments, the spread argument is also
- * allowed to be null.
- * @param target the method handle to invoke after the argument is prepended
+ * METHOD WILL BE REMOVED FOR PFD:
+ * Equivalent to the following code:
+ *
- * This method may be used as an inverse to {@link #spreadArguments}.
- * The final parameter type of the old type must be an array type T[],
- * which is the type of what is called the spread argument.
- * The trailing arguments of the new type which correspond to
- * the spread argument are all converted to type T and collected
- * into an array before the original method is called.
- * @param target the method handle to invoke after the argument is prepended
+ * METHOD WILL BE REMOVED FOR PFD:
+ * Equivalent to the following code:
+ *
+ * Before the method handle is returned, the passed-in value is converted to the requested type.
+ * If the requested type is primitive, widening primitive conversions are attempted,
+ * else reference conversions are attempted.
+ * The returned method handle is equivalent to {@code identity(type).bindTo(value)},
+ * unless the type is {@code void}, in which case it is {@code identity(type)}.
+ * @param type the return type of the desired method handle
+ * @param value the value to return
+ * @return a method handle of the given return type and no arguments, which always returns the given value
+ * @throws WrongMethodTypeException if the value cannot be converted to the required return type
+ */
+ public static
+ MethodHandle constant(Class> type, Object value) {
+ if (type.isPrimitive()) {
+ if (type == void.class) return identity(type);
+ Wrapper w = Wrapper.forPrimitiveType(type);
+ return identity(type).bindTo(w.convert(value, type));
+ } else {
+ return identity(type).bindTo(type.cast(value));
+ }
+ }
+
+ /**
+ * Produce a method handle of the requested type which returns the given
+ * constant value every time it is invoked.
+ *
+ * Before the method handle is returned, the passed-in value is converted to the requested return type,
+ * as if by {@link #explicitCastArguments #explicitCastArguments}.
+ * That is, if the return type is primitive, the value is unboxed,
+ * and the primitive value is widened and/or narrowed.
+ * Otherwise, reference conversions are attempted.
+ * @param type the type of the desired method handle
+ * @param value the value to return
+ * @return a method handle of the given return type and no arguments, which always returns the given value
+ * @throws WrongMethodTypeException if the value cannot be converted to the required return type
+ */
+ public static
+ MethodHandle constant(MethodType type, Object value) {
+ MethodHandle target = constant(type.returnType(), value);
+ int len = type.parameterCount();
+ if (len == 0)
+ return target.asType(type);
+ target = target.asType(type.dropParameterTypes(0, len));
+ return dropArguments(target, 0, type.parameterList().subList(0, len));
+ }
+
+ /**
+ * Produce a method handle which returns its sole argument when invoked.
+ * The identity function for {@code void} takes no arguments and returns no values.
+ * @param type the type of the sole parameter and return value of the desired method handle
+ * @return a unary method handle which accepts and returns the given type
+ */
+ public static
+ MethodHandle identity(Class> type) {
+ return ValueConversions.identity(type);
+ }
+
+ /**
+ * Produce a method handle of the requested type which returns its argument when invoked.
+ * If the return type differs from the first argument type, the argument will be
+ * converted as if by {@link #explicitCastArguments explicitCastArguments}.
+ * If there are additional arguments beyond the first, they are discarded.
+ * The identity function for {@code void} discards all its arguments.
+ * @param type the type of the desired method handle
+ * @return a method handle of the given type, which always returns its first argument
+ * @throws WrongMethodTypeException if the first argument cannot be converted to the required return type
+ */
+ public static
+ MethodHandle identity(MethodType type) {
+ MethodHandle target = identity(type.returnType());
+ int len = type.parameterCount();
+ if (len == 1)
+ return explicitCastArguments(target, type);
+ if (len == 0)
+ throw new IllegalArgumentException("not enough arguments");
+ target = explicitCastArguments(target, type.dropParameterTypes(1, len));
+ return dropArguments(target, 1, type.parameterList().subList(1, len));
+ }
+
+ /**
* Produce a method handle which calls the original method handle {@code target},
* after inserting the given argument(s) at the given position.
* The formal parameters to {@code target} which will be supplied by those
@@ -1229,8 +1402,9 @@ public class MethodHandles {
* @param target the method handle to invoke after the argument is inserted
* @param pos where to insert the argument (zero for the first)
* @param values the series of arguments to insert
- * @return a new method handle which inserts an additional argument,
+ * @return a method handle which inserts an additional argument,
* before calling the original method handle
+ * @see MethodHandle#bindTo
*/
public static
MethodHandle insertArguments(MethodHandle target, int pos, Object... values) {
@@ -1263,14 +1437,7 @@ public class MethodHandles {
return result;
}
- @Deprecated // "use MethodHandles.insertArguments instead"
- public static
- MethodHandle insertArgument(MethodHandle target, int pos, Object value) {
- return insertArguments(target, pos, value);
- }
-
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle which calls the original method handle,
* after dropping the given argument(s) at the given position.
* The type of the new method handle will insert the given argument
@@ -1283,25 +1450,25 @@ public class MethodHandles {
*
* Example:
*
* The pre-processing is performed by one or more method handles,
- * specified in the non-null elements of the {@code filters} array.
- * (If there are no such elements, the original target is returned.)
- * Each filter (that is, each non-null element of {@code filters})
- * is applied to the corresponding argument of the adapter.
+ * specified in the elements of the {@code filters} array.
+ * (If there are no elements in the array, the original target is returned.)
+ * Each filter is applied to the corresponding argument of the adapter.
*
* If a filter {@code F} applies to the {@code N}th argument of
* the method handle, then {@code F} must be a method handle which
@@ -1345,46 +1525,49 @@ public class MethodHandles {
* The return type of {@code F} must be identical to the corresponding
* parameter type of the target.
*
- * It is an error if there are non-null elements of {@code filters}
+ * It is an error if there are elements of {@code filters}
* which do not correspond to argument positions in the target.
- * The actual length of the target array may be any number, it need
- * not be the same as the parameter count of the target type.
- * (This provides an easy way to filter just the first argument or two
- * of a target method handle.)
- * Here is pseudocode for the resulting adapter:
- *
+ * If a filter {@code F} applies to the return value of
+ * the target method handle, then {@code F} must be a method handle which
+ * takes exactly one argument. The return type of {@code F}
+ * replaces the return type of the target
+ * in the resulting adapted method handle.
+ * The argument type of {@code F} must be identical to the
+ * return type of the target.
+ * Example:
+ *
- * (Note that {@link #dropArguments} can be used to remove any arguments
+ * (Note that {@link #dropArguments(MethodHandle,int,List) dropArguments} can be used to remove any arguments
* that either the {@code combiner} or {@code target} does not wish to receive.
* If some of the incoming arguments are destined only for the combiner,
- * consider using {@link #collectArguments} instead, since those
+ * consider using {@link MethodHandle#asCollector} instead, since those
* arguments will not need to be live on the stack on entry to the
* target.)
*
@@ -1434,7 +1658,7 @@ public class MethodHandles {
* @return method handle which incorporates the specified argument folding logic
* @throws IllegalArgumentException if the first argument type of
* {@code target} is not the same as {@code combiner}'s return type,
- * or if the next {@code foldArgs} argument types of {@code target}
+ * or if the following argument types of {@code target}
* are not identical with the argument types of {@code combiner}
*/
public static
@@ -1443,6 +1667,10 @@ public class MethodHandles {
MethodType combinerType = combiner.type();
int foldArgs = combinerType.parameterCount();
boolean ok = (targetType.parameterCount() >= 1 + foldArgs);
+ if (ok && !combinerType.parameterList().equals(targetType.parameterList().subList(1, foldArgs+1)))
+ ok = false;
+ if (ok && !combinerType.returnType().equals(targetType.parameterType(0)))
+ ok = false;
if (!ok)
throw misMatchedTypes("target and combiner types", targetType, combinerType);
MethodType newType = targetType.dropParameterTypes(0, 1);
@@ -1450,7 +1678,6 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Make a method handle which adapts a target method handle,
* by guarding it with a test, a boolean-valued method handle.
* If the guard fails, a fallback handle is called instead.
@@ -1470,6 +1697,9 @@ public class MethodHandles {
* return fallback(a..., b...);
* }
*
- * The handler must have leading parameter of {@code exType} or a supertype,
- * followed by arguments which correspond (how? TBD) to
- * all the parameters of the target.
- * The target and handler must return the same type.
+ * The target and handler must have the same corresponding
+ * argument and return types, except that handler may omit trailing arguments
+ * (similarly to the predicate in {@link #guardWithTest guardWithTest}).
+ * Also, the handler must have an extra leading parameter of {@code exType} or a supertype.
* Here is pseudocode for the resulting adapter:
*
+ * The target and handler must return the same type, even if the handler
+ * always throws. (This might happen, for instance, because the handler
+ * is simulating a {@code finally} clause).
+ * To create such a throwing handler, compose the handler creation logic
+ * with {@link #throwException throwException},
+ * in order to create a method handle of the correct return type.
* @param target method handle to call
* @param exType the type of exception which the handler will catch
* @param handler method handle to call if a matching exception is thrown
@@ -1563,16 +1781,23 @@ public class MethodHandles {
MethodHandle catchException(MethodHandle target,
Class extends Throwable> exType,
MethodHandle handler) {
- MethodType targetType = target.type();
- MethodType handlerType = handler.type();
- boolean ok = (targetType.parameterCount() ==
- handlerType.parameterCount() - 1);
-// for (int i = 0; ok && i < numExArgs; i++) {
-// if (targetType.parameterType(i) != handlerType.parameterType(1+i))
-// ok = false;
-// }
- if (!ok)
- throw newIllegalArgumentException("target and handler types do not match");
+ MethodType ttype = target.type();
+ MethodType htype = handler.type();
+ if (htype.parameterCount() < 1 ||
+ !htype.parameterType(0).isAssignableFrom(exType))
+ throw newIllegalArgumentException("handler does not accept exception type "+exType);
+ if (htype.returnType() != ttype.returnType())
+ throw misMatchedTypes("target and handler return types", ttype, htype);
+ List
* The resulting instance of the required SAM type will respond to
* invocation of the SAM type's single abstract method by calling
@@ -1605,9 +1831,9 @@ public class MethodHandles {
* The method handle may throw an undeclared exception,
* which means any checked exception (or other checked throwable)
* not declared by the SAM type's single abstract method.
- * If this happens, the throwable will be wrapped in an instance
- * of {@link UndeclaredThrowableException} and thrown in that
- * wrapped form.
+ * If this happens, the throwable will be wrapped in an instance of
+ * {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException}
+ * and thrown in that wrapped form.
*
* The wrapper instance is guaranteed to be of a non-public
* implementation class C in a package containing no classes
@@ -1618,19 +1844,36 @@ public class MethodHandles {
*
+ * (Note: When determining the unique abstract method of a SAM interface,
+ * the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode})
+ * are disregarded. For example, {@link java.util.Comparator} is a SAM interface,
+ * even though it re-declares the {@code Object.equals} method.)
+ *
* No stable mapping is promised between the SAM type and
* the implementation class C. Over time, several implementation
* classes might be used for the same SAM type.
*
* This method is not guaranteed to return a distinct
- * wrapper object for each separate call. If the JVM is able
- * to prove that a wrapper has already been created for a given
+ * wrapper object for each separate call. If the implementation is able
+ * to prove that a wrapper of the required SAM type
+ * has already been created for a given
* method handle, or for another method handle with the
- * same behavior, the JVM may return that wrapper in place of
+ * same behavior, the implementation may return that wrapper in place of
* a new wrapper.
+ *
+ * This method is designed to apply to common use cases
+ * where a single method handle must interoperate with
+ * a type (class or interface) that implements a function-like
+ * API. Additional variations, such as SAM classes with
+ * private constructors, or interfaces with multiple but related
+ * entry points, must be covered by hand-written or automatically
+ * generated adapter classes. In those cases, consider implementing
+ * {@link java.dyn.MethodHandles.AsInstanceObject AsInstanceObject}
+ * in the adapters, so that generic code can extract the underlying
+ * method handle without knowing where the SAM adapter came from.
* @param target the method handle to invoke from the wrapper
* @param samType the desired type of the wrapper, a SAM type
* @return a correctly-typed wrapper for the given {@code target}
@@ -1639,38 +1882,93 @@ public class MethodHandles {
*/
// ISSUE: Should we delegate equals/hashCode to the targets?
// Not useful unless there is a stable equals/hashCode behavior
- // for MethodHandle, and for MethodHandleProvider.asMethodHandle.
+ // for MethodHandle, but there isn't.
public static
-
* 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.
+ *
+ * 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.
*
* {@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.
*
- * 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 package summary.
+ *
+ * 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
- * 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);
- }
}
diff --git a/src/share/classes/java/dyn/MutableCallSite.java b/src/share/classes/java/dyn/MutableCallSite.java
new file mode 100644
index 0000000000000000000000000000000000000000..b33c41c1a5ad6bd059e2ccdb2ff8a4b7b303da55
--- /dev/null
+++ b/src/share/classes/java/dyn/MutableCallSite.java
@@ -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.
+ *
+ * Here is an example of a mutable call site which introduces a
+ * state variable into a method handle chain.
+ *
+ * The same call site may be used in several places at once.
+ *
+ * Non-synchronization of target values:
+ * 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.)
+ *
+ * The {@link #sync sync} operation provides a way to force threads
+ * to accept a new target value, even if there is no other synchronization.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.)
+ *
+ * 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.
+ *
+ * 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).
+ *
+ * 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.
+ *
+ * The following effects are apparent, for each individual call site {@code S}:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * (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.)
+ *
+ * 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();
+}
diff --git a/src/share/classes/java/dyn/Switcher.java b/src/share/classes/java/dyn/Switcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..b0838764b4417a68bda5dbde1d2418feceb600ce
--- /dev/null
+++ b/src/share/classes/java/dyn/Switcher.java
@@ -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;
+
+/**
+ *
+ * A {@code Switcher} is an object which can publish state transitions to other threads.
+ * A switcher is initially in the valid state, but may at any time be
+ * changed to the invalid state. Invalidation cannot be reversed.
+ *
+ * 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}.
+ *
+ * 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.
+ *
+ * Here is an example of a switcher in action:
+ *
+ * Implementation Note:
+ * A switcher behaves as if implemented on top of {@link MutableCallSite},
+ * approximately as follows:
+ *
+ * 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);
+ }
+}
diff --git a/src/share/classes/java/dyn/VolatileCallSite.java b/src/share/classes/java/dyn/VolatileCallSite.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c603b9191593991b7b0c9fd911d8f8a8d43056e
--- /dev/null
+++ b/src/share/classes/java/dyn/VolatileCallSite.java
@@ -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.
+ *
+ * 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.
+ *
+ * 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);
+ }
+}
diff --git a/src/share/classes/java/dyn/package-info.java b/src/share/classes/java/dyn/package-info.java
index 37555be14b4044dafaf6dc56ceb2c239bc3b41cd..41d97b8b15545060bfaf5123570d6904980a9129 100644
--- a/src/share/classes/java/dyn/package-info.java
+++ b/src/share/classes/java/dyn/package-info.java
@@ -24,7 +24,6 @@
*/
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* This package contains dynamic language support provided directly by
* the Java core class libraries and virtual machine.
*
@@ -42,13 +41,6 @@
* argument and return value conversions are applied.
*
* Each instance of an {@code invokedynamic} instruction is called a dynamic call site.
* 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.
*
- * 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.
- *
* 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 described below.
- *
- * (Historic Note: Some older JVMs may allow the index of a {@code CONSTANT_NameAndType}
+ *
+ *
+ * (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.)
* 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.
+ *
+ * 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.
*
- *
+ * (Note: The Proposed Final Draft of this specification is likely to support
+ * only the tag 18, not the tag 17.)
+ *
+ *
* 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.
*
* The method handle itself will have a type and behavior determined by the subtag as follows:
@@ -148,16 +157,45 @@
*
*
*
- * The special names {@code
- * 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.
*
- * 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.
+ *
+ * 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.
+ *
+ * The rules of section 5.4.3 of the
+ * JVM Specification
+ * 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.)
+ *
+ * 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.
*
*
- * 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:
*
+ * As long as each bootstrap method can be correctly invoked
+ * by
+ * As with any method handle constant, a {@code varargs} modifier bit
+ * on the bootstrap method is ignored.
+ *
+ * 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.)
*
* 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:
*
- * 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.
- *
- * 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).
- *
- * 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.
*
* 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.
- *
- * 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.)
- *
- * 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.
*
* 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.
+ *
+ *
+ * (Historic Note: Unlike some previous versions of this specification,
+ * these rules do not enable the JVM to duplicate dynamic call sites,
+ * or to issue “causeless” bootstrap method calls.
+ * Every dynamic call site transitions at most once from unlinked to linked,
+ * just before its first invocation.)
+ *
+ *
+ * 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 additional static arguments
+ * for the bootstrap method.
+ *
+ * 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).
+ *
+ *
+ * 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.
+ *
+ * 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:
+ *
+ * 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.
+ *
+ * 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.)
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *
+ * PROVISIONAL API, WORK IN PROGRESS:
+ * (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.)
+ *
+ *
- * 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.
- *
- * 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.
+ * Note: The Proposed Final Draft of JSR 292 may remove the constant tag 17,
+ * for the sake of simplicity.
*
* @author John Rose, JSR 292 EG
*/
diff --git a/src/share/classes/sun/dyn/AdapterMethodHandle.java b/src/share/classes/sun/dyn/AdapterMethodHandle.java
index fb9b7fa26c26b3e6a056c24df4b22f58e97b4edb..c23699b948cd2560a7c98029ce89bca63d573026 100644
--- a/src/share/classes/sun/dyn/AdapterMethodHandle.java
+++ b/src/share/classes/sun/dyn/AdapterMethodHandle.java
@@ -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.
*/
diff --git a/src/share/classes/sun/dyn/BoundMethodHandle.java b/src/share/classes/sun/dyn/BoundMethodHandle.java
index f2ae32efbc95b7f845bb90e2acc55314cf6ff118..cfe19663a276a1a47fcebea29fe027f2c028beff 100644
--- a/src/share/classes/sun/dyn/BoundMethodHandle.java
+++ b/src/share/classes/sun/dyn/BoundMethodHandle.java
@@ -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(); //
+ *
*
*
- * The following conversions are not applied:
- *
- *
+ *
* @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 ---
- * PROVISIONAL API, WORK IN PROGRESS:
+ /**
* 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.
*
- * 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);
*
- *
+ * 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.
*
+ *
+ * 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;
+ *
+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);
- /** Implementation of {@link MethodHandleProvider}, which returns {@code this.asType(type)}. */
- public final MethodHandle asMethodHandle(MethodType type) { return this.asType(type); }
+assertEquals("[]", makeAnyList.invokeGeneric().toString());
+assertEquals("[1]", makeAnyList.invokeGeneric(1).toString());
+assertEquals("[two, too]", makeAnyList.invokeGeneric("two", "too").toString());
+ *
+ */
+ public MethodHandle withTypeHandler(MethodHandle typeHandler) {
+ return MethodHandles.withTypeHandler(this, typeHandler);
+ }
}
diff --git a/src/share/classes/java/dyn/MethodHandleProvider.java b/src/share/classes/java/dyn/MethodHandleProvider.java
deleted file mode 100644
index 365b605469eaf534c16611cf5b3127df3c8c69be..0000000000000000000000000000000000000000
--- a/src/share/classes/java/dyn/MethodHandleProvider.java
+++ /dev/null
@@ -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.
- *
invokedynamic
- * 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.
- *
+ * In particular, access capabilities can be lost as follows:
- * The invoker will apply reference casts as necessary and unbox primitive arguments,
- * as if by {@link #convertArguments}.
+ *
*
*/
public Lookup in(Class> requestedLookupClass) {
@@ -245,10 +287,17 @@ public class MethodHandles {
&& !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) {
newModes &= ~(PACKAGE|PRIVATE);
}
+ // Allow nestmate lookups to be created without special privilege:
if ((newModes & PRIVATE) != 0
&& !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) {
newModes &= ~PRIVATE;
}
+ if (newModes == PUBLIC
+ && !VerifyAccess.isClassAccessible(requestedLookupClass, this.lookupClass)) {
+ // The requested class it not accessible from the lookup class.
+ // No permissions.
+ newModes = 0;
+ }
checkUnprivilegedlookupClass(requestedLookupClass);
return new Lookup(requestedLookupClass, newModes);
}
@@ -272,35 +321,43 @@ public class MethodHandles {
throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
}
- /** Display the name of the class.
- * If there are restrictions on the access permitted to this lookup,
- * display those also.
+ /**
+ * Display the name of the class from which lookups are to be made.
+ * (The name is the one reported by {@link java.lang.Class#getName() Class.getName}.)
+ * If there are restrictions on the access permitted to this lookup,
+ * this is indicated by adding a suffix to the class name, consisting
+ * of a slash and a keyword. The keyword is chosen as follows:
+ *
+ *
+ * If none of the above cases apply, it is the case that full
+ * access (public, package, private, and protected) is allowed.
+ * In this case, no suffix is added.
+ * This is true only of an object obtained originally from
+ * {@link java.dyn.MethodHandles#lookup() MethodHandles.lookup}.
+ * Objects created by {@link java.dyn.MethodHandles.Lookup#in() Lookup#in}
+ * always have restricted access, and will display a suffix.
*/
@Override
public String toString() {
- String modestr;
String cname = lookupClass.getName();
switch (allowedModes) {
case TRUSTED:
- return "/trusted";
+ return "/trusted"; // internal only
case PUBLIC:
- modestr = "/public";
- if (lookupClass == Object.class)
- return modestr;
- break;
+ return cname + "/public";
case PUBLIC|PACKAGE:
return cname + "/package";
- case 0: // should not happen
- return cname + "/empty";
+ case 0: // no privileges
+ return cname + "/noaccess";
case ALL_MODES:
return cname;
+ default:
+ return cname + "/private";
}
- StringBuilder buf = new StringBuilder(cname);
- if ((allowedModes & PUBLIC) != 0) buf.append("/public");
- if ((allowedModes & PACKAGE) != 0) buf.append("/package");
- if ((allowedModes & PROTECTED) != 0) buf.append("/protected");
- if ((allowedModes & PRIVATE) != 0) buf.append("/private");
- return buf.toString();
}
// call this from an entry point method in Lookup with extraFrames=0.
@@ -326,7 +383,6 @@ public class MethodHandles {
* @param name the name of the method
* @param type the type of the method
* @return the desired method handle
- * @exception SecurityException TBD
* @exception NoAccessException if the method does not exist or access checking fails
*/
public
@@ -342,13 +398,6 @@ public class MethodHandles {
* with the receiver type (usually {@code refc}) prepended.
* The method and all its argument types must be accessible to the lookup class.
*
* @param type the type of target methods which the invoker will apply to
* @return a method handle suitable for invoking any method handle of the given type
@@ -845,9 +880,8 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle which will invoke any method handle of the
- * given type on a standard set of {@code Object} type arguments
+ * given {@code type} on a standard set of {@code Object} type arguments
* and a single trailing {@code Object[]} array.
* The resulting invoker will be a method handle with the following
* arguments:
@@ -856,18 +890,31 @@ public class MethodHandles {
*
- * MethodHandle invoker = exactInvoker(type);
+ * MethodHandle invoker = lookup().findVirtual(MethodHandle.class, "invokeGeneric", type);
* MethodType genericType = type.generic();
* genericType = genericType.insertParameterType(0, MethodHandle.class);
- * return convertArguments(invoker, genericType);
+ * return invoker.asType(genericType);
*
* @param type the desired target type
* @param objectArgCount number of fixed (non-varargs) {@code Object} arguments
@@ -881,7 +928,6 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Produce a method handle which will take a invoke any method handle of the
* given type. The resulting invoker will have a type which is
* exactly equal to the desired type, except that it will accept
@@ -889,7 +935,7 @@ public class MethodHandles {
*
- * MethodHandle invoker = exactInvoker(type);
- * MethodType vaType = MethodType.makeGeneric(objectArgCount, true);
+ * MethodHandle invoker = lookup().findVirtual(MethodHandle.class, "invokeGeneric", type);
+ * MethodType vaType = MethodType.genericMethodType(objectArgCount, true);
* vaType = vaType.insertParameterType(0, MethodHandle.class);
- * return spreadArguments(invoker, vaType);
+ * int spreadArgCount = type.parameterCount - objectArgCount;
+ * invoker = invoker.asSpreader(Object.class, spreadArgCount);
+ * return invoker.asType(vaType);
*
* @param type the desired target type
* @return a method handle suitable for invoking any method handle of the given type
@@ -899,39 +945,6 @@ public class MethodHandles {
return invokers(type).exactInvoker();
}
- /**
- * PROVISIONAL API, WORK IN PROGRESS:
- * Produce a method handle equivalent to an invokedynamic instruction
- * which has been linked to the given call site.
- * Along with {@link Lookup#findVirtual}, {@link Lookup#findStatic},
- * and {@link Lookup#findSpecial}, this completes the emulation
- * of the JVM's {@code invoke} instructions.
- *
- * lookup().findVirtual(MethodHandle.class, "invoke", type);
+ * lookup().findVirtual(MethodHandle.class, "invokeExact", type);
*
- * @return a method handle which always invokes the call site's target
- */
- public static
- MethodHandle dynamicInvoker(CallSite site) throws NoAccessException {
- MethodHandle getCSTarget = GET_TARGET;
- if (getCSTarget == null) {
- try {
- GET_TARGET = getCSTarget = Lookup.IMPL_LOOKUP.
- findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
- } catch (NoAccessException ex) {
- throw new InternalError();
- }
- }
- MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, getCSTarget, site);
- MethodHandle invoker = exactInvoker(site.type());
- return foldArguments(invoker, getTarget);
- }
- private static MethodHandle GET_TARGET = null; // link this lazily, not eagerly
-
static Invokers invokers(MethodType type) {
return MethodTypeImpl.invokers(IMPL_TOKEN, type);
}
@@ -974,23 +987,23 @@ public class MethodHandles {
if (t0.isPrimitive())
return Wrapper.asPrimitiveType(t1).cast(value);
else
- return Wrapper.OBJECT.cast(value, t1);
+ return Wrapper.OBJECT.convert(value, t1);
}
boolean prim0 = t0.isPrimitive(), prim1 = t1.isPrimitive();
if (!prim0) {
// check contract with caller
- Wrapper.OBJECT.cast(value, t0);
+ Wrapper.OBJECT.convert(value, t0);
if (!prim1) {
- return Wrapper.OBJECT.cast(value, t1);
+ return Wrapper.OBJECT.convert(value, t1);
}
// convert reference to primitive by unboxing
Wrapper w1 = Wrapper.forPrimitiveType(t1);
- return w1.cast(value, t1);
+ return w1.convert(value, t1);
}
// check contract with caller:
Wrapper.asWrapperType(t0).cast(value);
Wrapper w1 = Wrapper.forPrimitiveType(t1);
- return w1.cast(value, t1);
+ return w1.convert(value, t1);
}
static
@@ -1011,7 +1024,7 @@ public class MethodHandles {
* Produce a method handle which adapts the type of the
* given 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
+ * The resulting method handle is guaranteed to report a type
* which is equal to the desired new type.
*
- * MethodHandle getTarget, invoker, result;
- * getTarget = lookup().bind(site, "getTarget", methodType(MethodHandle.class));
- * invoker = exactInvoker(site.type());
- * result = foldArguments(invoker, getTarget)
- *
- *
*
+ *
+ * @param target the method handle to invoke after arguments are retyped
+ * @param newType the expected type of the new method handle
+ * @return a method handle which delegates to {@code target} after performing
+ * any necessary argument conversions, and arranges for any
+ * necessary return value conversions
+ * @throws WrongMethodTypeException if the conversion cannot be made
+ * @see MethodHandle#asType
+ * @see MethodHandles#convertArguments
+ */
+ public static
+ MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) {
+ return convertArguments(target, newType); // FIXME!
+ }
+
+ /*
+ FIXME: Reconcile javadoc with 10/22/2010 EG notes on conversion:
+
+ Both converters arrange for their method handles to convert arguments
+ and return values. The conversion rules are the same for arguments
+ and return values, and depend only on source and target types, S and
+ T. The conversions allowed by castConvertArguments are a strict
+ superset of those performed by convertArguments.
+
+ In all cases, if S and T are references, a simple checkcast is done.
+ If neither S nor T is a primitive, no attempt is made to unbox and
+ box. A failed conversion throws ClassCastException.
+
+ If T is void, the value is dropped.
+
+ For compatibility with reflection, if S is void and T is a reference,
+ a null value is produced.
+
+ For compatibility with reflection, if S is a reference and T is a
+ primitive, S is first unboxed and then undergoes primitive conversion.
+ In the case of 'convertArguments', only assignment conversion is
+ performed (no narrowing primitive conversion).
+
+ If S is a primitive, S is boxed, and then the above rules are applied.
+ If S and T are both primitives, the boxing will be undetectable; only
+ the primitive conversions will be apparent to the user. The key point
+ is that if S is a primitive type, the implementation may box it and
+ treat is as Object, without loss of information, or it may use a "fast
+ path" which does not use boxing.
+
+ Notwithstanding the rules above, for compatibility with the verifier,
+ if T is an interface, it is treated as if it were Object. [KEEP THIS?]
+
+ Also, for compatibility with the verifier, a boolean may be undergo
+ widening or narrowing conversion to any other primitive type. [KEEP THIS?]
+ */
+
+ /**
* Produce a method handle which adapts the calling sequence of the
* given method handle to a new type, by reordering the arguments.
- * The resulting method handle is guaranteed to confess a type
+ * The resulting method handle is guaranteed to report a type
* which is equal to the desired new type.
*
* @param target the method handle to invoke after arguments are reordered
* @param newType the expected type of the new method handle
* @param reorder a string which controls the reordering
- * @return a method handle which delegates to {@code target} after performing
- * any necessary argument motion and conversions, and arranges for any
- * necessary return value conversions
+ * @return a method handle which delegates to {@code target} after it
+ * drops unused arguments and moves and/or duplicates the other arguments
*/
public static
- MethodHandle permuteArguments(MethodHandle target, MethodType newType, int[] reorder) {
+ MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
MethodType oldType = target.type();
checkReorder(reorder, newType, oldType);
return MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
@@ -1130,33 +1233,21 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
- * Produce a method handle which adapts the type of the
- * given method handle to a new type, by spreading the final argument.
- * The resulting method handle is guaranteed to confess a type
- * which is equal to the desired new type.
- *
+MethodType intfn1 = MethodType.methodType(int.class, int.class);
+MethodType intfn2 = MethodType.methodType(int.class, int.class, int.class);
+MethodHandle sub = ... {int x, int y => x-y} ...;
+assert(sub.type().equals(intfn2));
+MethodHandle sub1 = MethodHandles.permuteArguments(sub, intfn2, 0, 1);
+MethodHandle rsub = MethodHandles.permuteArguments(sub, intfn2, 1, 0);
+assert((int)rsub.invokeExact(1, 100) == 99);
+MethodHandle add = ... {int x, int y => x+y} ...;
+assert(add.type().equals(intfn2));
+MethodHandle twice = MethodHandles.permuteArguments(add, intfn1, 0, 0);
+assert(twice.type().equals(intfn1));
+assert((int)twice.invokeExact(21) == 42);
+ *
+ * @param target the method handle to invoke after argument spreading
* @param newType the expected type of the new method handle
- * @return a new method handle which spreads its final argument,
+ * @return a method handle which spreads its final argument,
* before calling the original method handle
+ * @deprecated Use {@link MethodHandle#asSpreader}
*/
public static
MethodHandle spreadArguments(MethodHandle target, MethodType newType) {
@@ -1176,21 +1267,22 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
- * Produce a method handle which adapts the type of the
- * given method handle to a new type, by collecting a series of
- * trailing arguments as elements to a single argument array.
- *
+ * int spreadPos = newType.parameterCount() - 1;
+ * Class> spreadType = newType.parameterType(spreadPos);
+ * int spreadCount = target.type().parameterCount() - spreadPos;
+ * MethodHandle adapter = target.asSpreader(spreadType, spreadCount);
+ * adapter = adapter.asType(newType);
+ * return adapter;
+ *
+ * @param target the method handle to invoke after argument collection
* @param newType the expected type of the new method handle
- * @return a new method handle which collects some trailing argument
+ * @return a method handle which collects some trailing argument
* into an array, before calling the original method handle
+ * @deprecated Use {@link MethodHandle#asCollector} instead.
*/
public static
MethodHandle collectArguments(MethodHandle target, MethodType newType) {
@@ -1209,7 +1301,88 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
+ * Produce a method handle of the requested return type which returns the given
+ * constant value every time it is invoked.
+ *
+ * int collectPos = target.type().parameterCount() - 1;
+ * Class> collectType = target.type().parameterType(collectPos);
+ * if (!collectType.isArray()) collectType = Object[].class;
+ * int collectCount = newType.parameterCount() - collectPos;
+ * MethodHandle adapter = target.asCollector(collectType, collectCount);
+ * adapter = adapter.asType(newType);
+ * return adapter;
+ *
- * @param target the method handle to invoke after the argument is dropped
- * @param valueTypes the type(s) of the argument to drop
- * @param pos which argument to drop (zero for the first)
- * @return a new method handle which drops an argument of the given type,
+ * @param target the method handle to invoke after the arguments are dropped
+ * @param valueTypes the type(s) of the argument(s) to drop
+ * @param pos position of first argument to drop (zero for the leftmost)
+ * @return a method handle which drops arguments of the given types,
* before calling the original method handle
*/
public static
@@ -1319,23 +1486,36 @@ public class MethodHandles {
return MethodHandleImpl.dropArguments(IMPL_TOKEN, target, newType, pos);
}
+ /**
+ * Produce a method handle which calls the original method handle,
+ * after dropping the given argument(s) at the given position.
+ * The type of the new method handle will insert the given argument
+ * type(s), at that position, into the original handle's type.
+ * This method is equivalent to the following code:
+ *
- * import static java.dyn.MethodHandles.*;
- * import static java.dyn.MethodType.*;
- * ...
- * MethodHandle cat = lookup().findVirtual(String.class,
- * "concat", methodType(String.class, String.class));
- * System.out.println((String) cat.invokeExact("x", "y")); // xy
- * MethodHandle d0 = dropArguments(cat, 0, String.class);
- * System.out.println((String) d0.invokeExact("x", "y", "z")); // yz
- * MethodHandle d1 = dropArguments(cat, 1, String.class);
- * System.out.println((String) d1.invokeExact("x", "y", "z")); // xz
- * MethodHandle d2 = dropArguments(cat, 2, String.class);
- * System.out.println((String) d2.invokeExact("x", "y", "z")); // xy
- * MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
- * System.out.println((String) d12.invokeExact("x", 12, true, "z")); // xz
+import static java.dyn.MethodHandles.*;
+import static java.dyn.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
+MethodHandle d0 = dropArguments(cat, 0, String.class);
+assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
+MethodHandle d1 = dropArguments(cat, 1, String.class);
+assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
+MethodHandle d2 = dropArguments(cat, 2, String.class);
+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"));
*
+ * {@link #dropArguments(MethodHandle,int,List) dropArguments}(target, pos, Arrays.asList(valueTypes))
+ *
+ * @param target the method handle to invoke after the arguments are dropped
+ * @param valueTypes the type(s) of the argument(s) to drop
+ * @param pos position of first argument to drop (zero for the leftmost)
+ * @return a method handle which drops arguments of the given types,
+ * before calling the original method handle
+ */
public static
MethodHandle dropArguments(MethodHandle target, int pos, Class>... valueTypes) {
return dropArguments(target, pos, Arrays.asList(valueTypes));
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
* Adapt a target method handle {@code target} by pre-processing
* one or more of its arguments, each with its own unary filter function,
* and then calling the target with each pre-processed argument
* replaced by the result of its corresponding filter function.
*
+ * Note that the test arguments ({@code a...} in the pseudocode) cannot
+ * be modified by execution of the test, and so are passed unchanged
+ * from the caller to the target or fallback as appropriate.
* @param test method handle used for test, must return boolean
* @param target method handle to call if test passes
* @param fallback method handle to call if test fails
@@ -1485,40 +1715,19 @@ public class MethodHandles {
MethodType gtype = test.type();
MethodType ttype = target.type();
MethodType ftype = fallback.type();
- if (ttype != ftype)
+ if (!ttype.equals(ftype))
throw misMatchedTypes("target and fallback types", ttype, ftype);
- MethodType gtype2 = ttype.changeReturnType(boolean.class);
- if (gtype2 != gtype) {
- if (gtype.returnType() != boolean.class)
- throw newIllegalArgumentException("guard type is not a predicate "+gtype);
- int gpc = gtype.parameterCount(), tpc = ttype.parameterCount();
- if (gpc < tpc) {
- test = dropArguments(test, gpc, ttype.parameterList().subList(gpc, tpc));
- gtype = test.type();
- }
- if (gtype2 != gtype)
+ if (gtype.returnType() != boolean.class)
+ throw newIllegalArgumentException("guard type is not a predicate "+gtype);
+ List
- * // there are N arguments in the A sequence
- * T target(A[N]...);
- * [i<N] V[i] filter[i](B[i]) = filters[i] ?: identity;
- * T adapter(B[N]... b) {
- * A[N] a...;
- * [i<N] a[i] = filter[i](b[i]);
- * return target(a...);
- * }
+ * Example:
+ *
* @param target the method handle to invoke after arguments are filtered
+ * @param pos the position of the first argument to filter
* @param filters method handles to call initially on filtered arguments
* @return method handle which incorporates the specified argument filtering logic
- * @throws IllegalArgumentException if a non-null element of {@code filters}
- * does not match a corresponding argument type of {@code target}
+ * @throws IllegalArgumentException if an element of {@code filters} is null or
+ * does not match a corresponding argument type of {@code target} as described above
*/
public static
- MethodHandle filterArguments(MethodHandle target, MethodHandle... filters) {
+ MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
MethodType targetType = target.type();
MethodHandle adapter = target;
MethodType adapterType = targetType;
- int pos = -1, maxPos = targetType.parameterCount();
+ int maxPos = targetType.parameterCount();
+ int curPos = pos;
for (MethodHandle filter : filters) {
- pos += 1;
- if (filter == null) continue;
- if (pos >= maxPos)
+ if (curPos >= maxPos)
throw newIllegalArgumentException("too many filters");
MethodType filterType = filter.type();
if (filterType.parameterCount() != 1
- || filterType.returnType() != targetType.parameterType(pos))
+ || filterType.returnType() != targetType.parameterType(curPos))
throw newIllegalArgumentException("target and filter types do not match");
- adapterType = adapterType.changeParameterType(pos, filterType.parameterType(0));
- adapter = MethodHandleImpl.filterArgument(IMPL_TOKEN, adapter, pos, filter);
+ adapterType = adapterType.changeParameterType(curPos, filterType.parameterType(0));
+ adapter = MethodHandleImpl.filterArgument(IMPL_TOKEN, adapter, curPos, filter);
+ curPos += 1;
}
MethodType midType = adapter.type();
if (midType != adapterType)
@@ -1393,7 +1576,48 @@ public class MethodHandles {
}
/**
- * PROVISIONAL API, WORK IN PROGRESS:
+ * Adapt a target method handle {@code target} by post-processing
+ * its return value with a unary filter function.
+ *
+import static java.dyn.MethodHandles.*;
+import static java.dyn.MethodType.*;
+...
+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
*
+ * @param target the method handle to invoke before filtering the return value
+ * @param filter method handle to call on the return value
+ * @return method handle which incorporates the specified return value filtering logic
+ * @throws IllegalArgumentException if {@code filter} is null or
+ * does not match the return type of {@code target} as described above
+ */
+ public static
+ MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
+ MethodType targetType = target.type();
+ MethodType filterType = filter.type();
+ if (filterType.parameterCount() != 1
+ || filterType.parameterType(0) != targetType.returnType())
+ throw newIllegalArgumentException("target and filter types do not match");
+ // FIXME: Too many nodes here.
+ MethodHandle returner = dropArguments(filter, 0, targetType.parameterList());
+ return foldArguments(returner, exactInvoker(target.type()).bindTo(target));
+ }
+
+ /**
* Adapt a target method handle {@code target} by pre-processing
* some of its arguments, and then calling the target with
* the result of the pre-processing, plus all original arguments.
@@ -1410,10 +1634,10 @@ public class MethodHandles {
* The resulting adapter is the same type as the target, except that the
* initial argument type of the target is dropped.
*
+import static java.dyn.MethodHandles.*;
+import static java.dyn.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+MethodHandle length = lookup().findVirtual(String.class,
+ "length", methodType(int.class));
+System.out.println((String) cat.invokeExact("x", "y")); // xy
+MethodHandle f0 = filterReturnValue(cat, length);
+System.out.println((int) f0.invokeExact("x", "y")); // 2
+ *
+ * Note that the saved arguments ({@code a...} in the pseudocode) cannot
+ * be modified by execution of the target, and so are passed unchanged
+ * from the caller to the handler, if the handler is invoked.
+ *
- * T target(A...);
+ * T target(A..., B...);
* T handler(ExType, A...);
- * T adapter(A... a) {
+ * T adapter(A... a, B... b) {
* try {
- * return target(a...);
+ * return target(a..., b...);
* } catch (ExType ex) {
* return handler(ex, a...);
* }
* }
*
+ *
+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)
+ *
+ *
+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());
+ *
+ *
+ * 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.
+ *
+ *
+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"));
+ *
+ * @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.
+ *
+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) {
+ ListCorresponding JVM bytecode format changes
* The following low-level information is presented here as a preview of
- * changes being made to the Java Virtual Machine specification for JSR 292.
+ * 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.
*
- * {@code invokedynamic} instruction format
+ * {@code invokedynamic} instruction format
* 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:
+ *
+ *
* constant pool entries for {@code invokedynamic} instructions
- * 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}.
+ * constant pool entries for {@code invokedynamic} instructions
+ * 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
+ * bootstrap method table, which is stored in the {@code BootstrapMethods}
+ * attribute as described below.
+ * 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.
+ * constant pool entries for {@code MethodType}s
+ * constant pool entries for {@linkplain java.dyn.MethodType method types}
* 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.
*
- * constant pool entries for {@code MethodHandle}s
+ * constant pool entries for {@linkplain java.dyn.MethodHandle method handles}
* 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 @@
* Bootstrap Methods
* 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.
*
*
* The method handle is then applied to the other values as if by
- * {@linkplain java.dyn.MethodHandle#invokeGeneric the invokeGeneric 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.
+ * invokeGeneric, 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}.
+ *
+ *
- * timing of linkage
+ *
+ * timing of linkage
* 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.
* the {@code BootstrapMethods} attribute
+ * 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.
+ * static arguments to the bootstrap method
+ * 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 static arguments to the
+ * {@code invokedynamic} instruction, because they are used once at link
+ * time to determine the instruction's behavior on subsequent sets of
+ * dynamic arguments.
+ *
+ *
+ *
+ *
+ *
+ * entry type argument type argument value
+ * CONSTANT_String java.lang.Stringthe indexed string literal
+ * CONSTANT_Class java.lang.Classthe indexed class, resolved
+ * CONSTANT_Integer java.lang.Integerthe indexed int value
+ * CONSTANT_Long java.lang.Longthe indexed long value
+ * CONSTANT_Float java.lang.Floatthe indexed float value
+ * CONSTANT_Double java.lang.Doublethe indexed double value
+ * CONSTANT_MethodHandle java.dyn.MethodHandlethe indexed method handle constant
+ * CONSTANT_MethodType java.dyn.MethodTypethe indexed method type constant
+ *
+ *
+ *
+ *
+ * N sample bootstrap method
+ * 0 CallSite bootstrap(Lookup caller, String name, MethodType type)
+ * 1 CallSite bootstrap(Lookup caller, String name, MethodType type, Object arg)
+ * 2 CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)Structure Summary
+ *
* // 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];
+}
+ *