提交 4d781e31 编写于 作者: I igor

Merge

......@@ -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
......@@ -26,40 +26,45 @@
package java.dyn;
import sun.dyn.*;
import sun.dyn.empty.Empty;
import sun.misc.Unsafe;
import java.util.Collection;
/**
* A {@code CallSite} is a holder for a variable {@link MethodHandle},
* which is called its {@code target}.
* Every call to a {@code CallSite} is delegated to the site's current target.
* An {@code invokedynamic} instruction linked to a {@code CallSite} delegates
* all calls to the site's current target.
* A {@code CallSite} may be associated with several {@code invokedynamic}
* instructions, or it may be "free floating", associated with none.
* In any case, it may be invoked through an associated method handle
* called its {@linkplain #dynamicInvoker dynamic invoker}.
* <p>
* A call site is initially created in an <em>unlinked</em> state,
* which is distinguished by a null target variable.
* Before the call site may be invoked (and before certain other
* operations are attempted), the call site must be linked to
* a non-null target.
* {@code CallSite} is an abstract class which does not allow
* direct subclassing by users. It has three immediate,
* concrete subclasses that may be either instantiated or subclassed.
* <ul>
* <li>If a mutable target is not required, an {@code invokedynamic} instruction
* may be permanently bound by means of a {@linkplain ConstantCallSite constant call site}.
* <li>If a mutable target is required which has volatile variable semantics,
* because updates to the target must be immediately and reliably witnessed by other threads,
* a {@linkplain VolatileCallSite volatile call site} may be used.
* <li>Otherwise, if a mutable target is required,
* a {@linkplain MutableCallSite mutable call site} may be used.
* </ul>
* <p>
* A call site may be <em>relinked</em> by changing its target.
* The new target must be non-null and must have the same
* {@linkplain MethodHandle#type() type}
* A non-constant call site may be <em>relinked</em> by changing its target.
* The new target must have the same {@linkplain MethodHandle#type() type}
* as the previous target.
* Thus, though a call site can be relinked to a series of
* successive targets, it cannot change its type.
* <p>
* Linkage happens once in the lifetime of any given {@code CallSite} object.
* Because of call site invalidation, this linkage can be repeated for
* a single {@code invokedynamic} instruction, with multiple {@code CallSite} objects.
* When a {@code CallSite} is unlinked from an {@code invokedynamic} instruction,
* the instruction is reset so that it is no longer associated with
* the {@code CallSite} object, but the {@code CallSite} does not change
* state.
* <p>
* Here is a sample use of call sites and bootstrap methods which links every
* dynamic call site to print its arguments:
<blockquote><pre><!-- see indy-demo/src/PrintArgsDemo.java -->
&#064;BootstrapMethod(value=PrintArgsDemo.class, name="bootstrapDynamic")
static void test() throws Throwable {
InvokeDynamic.baz("baz arg", 2, 3.14);
// THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION
InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
}
private static void printArgs(Object... args) {
System.out.println(java.util.Arrays.deepToString(args));
......@@ -71,16 +76,15 @@ static {
printArgs = lookup.findStatic(thisClass,
"printArgs", MethodType.methodType(void.class, Object[].class));
}
private static CallSite bootstrapDynamic(Class caller, String name, MethodType type) {
private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) {
// ignore caller and name, but match the type:
return new CallSite(MethodHandles.collectArguments(printArgs, type));
return new ConstantCallSite(MethodHandles.collectArguments(printArgs, type));
}
</pre></blockquote>
* @author John Rose, JSR 292 EG
*/
public class CallSite
implements MethodHandleProvider
{
abstract
public class CallSite {
private static final Access IMPL_TOKEN = Access.getToken();
// Fields used only by the JVM. Do not use or change.
......@@ -88,61 +92,47 @@ public class CallSite
private int vmindex; // supplied by the JVM (BCI within calling method)
// The actual payload of this call site:
private MethodHandle target;
/*package-private*/
MethodHandle target;
// Remove this field for PFD and delete deprecated methods:
private MemberName calleeNameRemoveForPFD;
/**
* Make a blank call site object.
* Before it is returned from a bootstrap method, this {@code CallSite} object
* must be provided with
* a target method via a call to {@link CallSite#setTarget(MethodHandle) setTarget},
* or by a subclass override of {@link CallSite#initialTarget(Class,String,MethodType) initialTarget}.
* Make a blank call site object with the given method type.
* An initial target method is supplied which will throw
* an {@link IllegalStateException} if called.
* <p>
* Before this {@code CallSite} object is returned from a bootstrap method,
* it is usually provided with a more useful target method,
* via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
* @throws NullPointerException if the proposed type is null
*/
public CallSite() {
/*package-private*/
CallSite(MethodType type) {
target = MethodHandles.invokers(type).uninitializedCallSite();
}
/**
* Make a blank call site object, possibly equipped with an initial target method handle.
* The initial target reference may be null, in which case the {@code CallSite} object
* must be provided with a target method via a call to {@link CallSite#setTarget},
* or by a subclass override of {@link CallSite#initialTarget}.
* @param target the method handle which will be the initial target of the call site, or null if there is none yet
* @param target the method handle which will be the initial target of the call site
* @throws NullPointerException if the proposed target is null
*/
public CallSite(MethodHandle target) {
/*package-private*/
CallSite(MethodHandle target) {
target.type(); // null check
this.target = target;
}
/** @deprecated transitional form defined in EDR but removed in PFD */
public CallSite(Class<?> caller, String name, MethodType type) {
this.calleeNameRemoveForPFD = new MemberName(caller, name, type);
}
/** @deprecated transitional form defined in EDR but removed in PFD */
public Class<?> callerClass() {
MemberName callee = this.calleeNameRemoveForPFD;
return callee == null ? null : callee.getDeclaringClass();
}
/** @deprecated transitional form defined in EDR but removed in PFD */
public String name() {
MemberName callee = this.calleeNameRemoveForPFD;
return callee == null ? null : callee.getName();
}
/** @deprecated transitional form defined in EDR but removed in PFD */
public MethodType type() {
MemberName callee = this.calleeNameRemoveForPFD;
return callee == null ? (target == null ? null : target.type()) : callee.getMethodType();
}
/** @deprecated transitional form defined in EDR but removed in PFD */
protected MethodHandle initialTarget() {
return initialTarget(callerClass(), name(), type());
}
/** Report if the JVM has linked this {@code CallSite} object to a dynamic call site instruction.
* Once it is linked, it is never unlinked.
/**
* Report the type of this call site's target.
* Although targets may change, the call site's type can never change.
* The {@code setTarget} method enforces this invariant by refusing any new target that does
* not have the previous target's type.
* @return the type of the current target, which is also the type of any future target
*/
private boolean isLinked() {
return vmmethod != null;
public MethodType type() {
return target.type();
}
/** Called from JVM (or low-level Java code) after the BSM returns the newly created CallSite.
......@@ -152,68 +142,66 @@ public class CallSite
MethodType type,
MemberName callerMethod,
int callerBCI) {
if (this.isLinked()) {
if (this.vmmethod != null) {
// FIXME
throw new InvokeDynamicBootstrapError("call site has already been linked to an invokedynamic instruction");
}
MethodHandle target = this.target;
if (target == null) {
this.target = target = this.initialTarget(callerMethod.getDeclaringClass(), name, type);
}
if (!target.type().equals(type)) {
if (!this.type().equals(type)) {
throw wrongTargetType(target, type);
}
this.vmindex = callerBCI;
this.vmmethod = callerMethod;
assert(this.isLinked());
}
/**
* Just after a call site is created by a bootstrap method handle,
* if the target has not been initialized by the factory method itself,
* the method {@code initialTarget} is called to produce an initial
* non-null target. (Live call sites must never have null targets.)
* <p>
* The arguments are the same as those passed to the bootstrap method.
* Thus, a bootstrap method is free to ignore the arguments and simply
* create a "blank" {@code CallSite} object of an appropriate subclass.
* Report the current linkage state of the call site, a value which may change over time.
* <p>
* If the bootstrap method itself does not initialize the call site,
* this method must be overridden, because it just raises an
* {@code InvokeDynamicBootstrapError}, which in turn causes the
* linkage of the {@code invokedynamic} instruction to terminate
* abnormally.
* @deprecated transitional form defined in EDR but removed in PFD
*/
protected MethodHandle initialTarget(Class<?> callerClass, String name, MethodType type) {
throw new InvokeDynamicBootstrapError("target must be initialized before call site is linked: "+name+type);
}
/**
* Report the current linkage state of the call site. (This is mutable.)
* The value may not be null after the {@code CallSite} object is returned
* from the bootstrap method of the {@code invokedynamic} instruction.
* When an {@code invokedynamic} instruction is executed, the target method
* of its associated {@code call site} object is invoked directly,
* as if via {@link MethodHandle}{@code .invoke}.
* If a {@code CallSite} object is returned
* from the bootstrap method of the {@code invokedynamic} instruction,
* the {@code CallSite} is permanently bound to that instruction.
* When the {@code invokedynamic} instruction is executed, the target method
* of its associated call site object is invoked directly.
* It is as if the instruction calls {@code getTarget} and then
* calls {@link MethodHandle#invokeExact invokeExact} on the result.
* <p>
* The interactions of {@code getTarget} with memory are the same
* Unless specified differently by a subclass,
* the interactions of {@code getTarget} with memory are the same
* as of a read from an ordinary variable, such as an array element or a
* non-volatile, non-final field.
* <p>
* In particular, the current thread may choose to reuse the result
* of a previous read of the target from memory, and may fail to see
* a recent update to the target by another thread.
* @return the current linkage state of the call site
* <p>
* In a {@linkplain ConstantCallSite constant call site}, the {@code getTarget} method behaves
* like a read from a {@code final} field of the {@code CallSite}.
* <p>
* In a {@linkplain VolatileCallSite volatile call site}, the {@code getTarget} method behaves
* like a read from a {@code volatile} field of the {@code CallSite}.
* <p>
* This method may not be overridden by application code.
* @return the current linkage state of the call site, its target method handle
* @see ConstantCallSite
* @see VolatileCallSite
* @see #setTarget
*/
public MethodHandle getTarget() {
public final MethodHandle getTarget() {
return getTarget0();
}
/**
* Privileged implementations can override this to force final or volatile semantics on getTarget.
*/
/*package-private*/
MethodHandle getTarget0() {
return target;
}
/**
* Set the target method of this call site.
* <p>
* The interactions of {@code setTarget} with memory are the same
* Unless a subclass of CallSite documents otherwise,
* the interactions of {@code setTarget} with memory are the same
* as of a write to an ordinary variable, such as an array element or a
* non-volatile, non-final field.
* <p>
......@@ -224,43 +212,32 @@ public class CallSite
* at any given call site.
* @param newTarget the new target
* @throws NullPointerException if the proposed new target is null
* @throws WrongMethodTypeException if the call site is linked and the proposed new target
* @throws WrongMethodTypeException if the proposed new target
* has a method type that differs from the previous target
* @throws UnsupportedOperationException if the call site is
* in fact a {@link ConstantCallSite}
*/
public void setTarget(MethodHandle newTarget) {
MethodType newType = newTarget.type(); // null check!
MethodHandle oldTarget = this.target;
if (oldTarget == null) {
// CallSite is not yet linked.
assert(!isLinked());
this.target = newTarget; // might be null!
return;
}
checkTargetChange(this.target, newTarget);
setTargetNormal(newTarget);
}
void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) {
MethodType oldType = oldTarget.type();
if (!newTarget.type().equals(oldType))
MethodType newType = newTarget.type(); // null check!
if (!newType.equals(oldType))
throw wrongTargetType(newTarget, oldType);
if (oldTarget != newTarget)
CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
}
private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
return new WrongMethodTypeException(String.valueOf(target)+target.type()+" should be of type "+type);
}
/** Produce a printed representation that displays information about this call site
* that may be useful to the human reader.
*/
@Override
public String toString() {
return "CallSite"+(target == null ? "" : target.type());
return new WrongMethodTypeException(String.valueOf(target)+" should be of type "+type);
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle equivalent to an invokedynamic instruction
* which has been linked to this call site.
* <p>If this call site is a {@link ConstantCallSite}, this method
* simply returns the call site's target, since that will not change.
* <p>If this call site is a {@linkplain ConstantCallSite constant call site},
* this method simply returns the call site's target, since that will never change.
* <p>Otherwise, this method is equivalent to the following code:
* <p><blockquote><pre>
* MethodHandle getTarget, invoker, result;
......@@ -271,8 +248,9 @@ public class CallSite
* @return a method handle which always invokes this call site's current target
*/
public final MethodHandle dynamicInvoker() {
if (this instanceof ConstantCallSite)
return getTarget(); // will not change dynamically
if (this instanceof ConstantCallSite) {
return getTarget0(); // will not change dynamically
}
MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, GET_TARGET, this);
MethodHandle invoker = MethodHandles.exactInvoker(this.type());
return MethodHandles.foldArguments(invoker, getTarget);
......@@ -287,9 +265,34 @@ public class CallSite
}
}
/** Implementation of {@link MethodHandleProvider} which returns {@code this.dynamicInvoker()}. */
public final MethodHandle asMethodHandle() { return dynamicInvoker(); }
/** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
/*package-private*/
static Empty uninitializedCallSite() {
throw new IllegalStateException("uninitialized call site");
}
// 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);
}
}
......@@ -28,44 +28,78 @@ package java.dyn;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.lang.reflect.UndeclaredThrowableException;
/**
* Lazily associate a computed value with (potentially) every class.
* @author John Rose, JSR 292 EG
*/
public abstract class ClassValue<T> {
public class ClassValue<T> {
/**
* Compute the given class's derived value for this {@code ClassValue}.
* <p>
* This method will be invoked within the first thread that accesses
* the value with the {@link #get}.
* the value with the {@link #get get} method.
* <p>
* Normally, this method is invoked at most once per class,
* but it may be invoked again in case of subsequent invocations
* of {@link #remove} followed by {@link #get}.
* but it may be invoked again if there has been a call to
* {@link #remove remove}.
* <p>
* If there is no override from a subclass, this method returns
* the result of applying the {@code ClassValue}'s {@code computeValue}
* method handle, which was supplied at construction time.
*
* @return the computed value for this thread-local
* @return the newly computed value associated with this {@code ClassValue}, for the given class or interface
* @throws UndeclaredThrowableException if the {@code computeValue} method handle invocation throws something other than a {@code RuntimeException} or {@code Error}
* @throws UnsupportedOperationException if the {@code computeValue} method handle is null (subclasses must override)
*/
protected abstract T computeValue(Class<?> type);
protected T computeValue(Class<?> type) {
if (computeValue == null)
return null;
try {
return (T) (Object) computeValue.invokeGeneric(type);
} catch (Throwable ex) {
if (ex instanceof Error) throw (Error) ex;
if (ex instanceof RuntimeException) throw (RuntimeException) ex;
throw new UndeclaredThrowableException(ex);
}
}
private final MethodHandle computeValue;
/**
* Creates a new class value.
* Subclasses which use this constructor must override
* the {@link #computeValue computeValue} method,
* since the default {@code computeValue} method requires a method handle,
* which this constructor does not provide.
*/
protected ClassValue() {
this.computeValue = null;
}
/**
* Creates a new class value, whose {@link #computeValue computeValue} method
* will return the result of {@code computeValue.invokeGeneric(type)}.
* @throws NullPointerException if the method handle parameter is null
*/
public ClassValue(MethodHandle computeValue) {
computeValue.getClass(); // trigger NPE if null
this.computeValue = computeValue;
}
/**
* Returns the value for the given class.
* If no value has yet been computed, it is obtained by
* by an invocation of the {@link #computeValue} method.
* by an invocation of the {@link #computeValue computeValue} method.
* <p>
* The actual installation of the value on the class
* is performed while the class's synchronization lock
* is held. At that point, if racing threads have
* is performed atomically.
* At that point, if racing threads have
* computed values, one is chosen, and returned to
* all the racing threads.
*
* @return the current thread's value of this thread-local
* @return the current value associated with this {@code ClassValue}, for the given class or interface
*/
public T get(Class<?> type) {
ClassValueMap map = getMap(type);
......@@ -81,9 +115,16 @@ public abstract class ClassValue<T> {
/**
* Removes the associated value for the given class.
* If this value is subsequently {@linkplain #get read} for the same class,
* its value will be reinitialized by invoking its {@link #computeValue} method.
* its value will be reinitialized by invoking its {@link #computeValue computeValue} method.
* This may result in an additional invocation of the
* {@code computeValue} method for the given class.
* {@code computeValue computeValue} method for the given class.
* <p>
* If racing threads perform a combination of {@code get} and {@code remove} calls,
* the calls are serialized.
* A value produced by a call to {@code computeValue} will be discarded, if
* the corresponding {@code get} call was followed by a {@code remove} call
* before the {@code computeValue} could complete.
* In such a case, the {@code get} call will re-invoke {@code computeValue}.
*/
public void remove(Class<?> type) {
ClassValueMap map = getMap(type);
......@@ -118,6 +159,7 @@ public abstract class ClassValue<T> {
// Warm up the table with a null entry.
map.preInitializeEntry(this);
}
STORE_BARRIER.lazySet(0);
// All stores pending from table expansion are completed.
synchronized (map) {
value = (T) map.initializeEntry(this, value);
......
......@@ -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");
}
}
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -26,55 +26,8 @@
package java.dyn;
/**
* {@code InvokeDynamic} is a class with neither methods nor instances,
* which serves only as a syntactic marker in Java source code for
* an {@code invokedynamic} instruction.
* (See <a href="package-summary.html#jvm_mods">the package information</a> for specifics on this instruction.)
* <p>
* The {@code invokedynamic} instruction is incomplete without a target method.
* The target method is a property of the reified {@linkplain CallSite call site object}
* which is linked to each active {@code invokedynamic} instruction.
* The call site object is initially produced by a
* {@linkplain BootstrapMethod bootstrap method}
* associated with the class whose bytecodes include the dynamic call site.
* <p>
* The type {@code InvokeDynamic} has no particular meaning as a
* class or interface supertype, or an object type; it can never be instantiated.
* Logically, it denotes a source of all dynamically typed methods.
* It may be viewed as a pure syntactic marker of static calls.
* It may be imported for ease of use.
* <p>
* Here are some examples:
<blockquote><pre><!-- see indy-demo/src/JavaDocExamples.java -->
&#064;BootstrapMethod(value=Here.class, name="bootstrapDynamic")
static void example() throws Throwable {
Object x; String s; int i;
x = InvokeDynamic.greet("world"); // greet(Ljava/lang/String;)Ljava/lang/Object;
s = (String) InvokeDynamic.hail(x); // hail(Ljava/lang/Object;)Ljava/lang/String;
InvokeDynamic.cogito(); // cogito()V
i = (int) InvokeDynamic.#"op:+"(2, 3); // "op:+"(II)I
}
static MethodHandle bootstrapDynamic(Class caller, String name, MethodType type) { ... }
</pre></blockquote>
* Each of the above calls generates a single invokedynamic instruction
* with the name-and-type descriptors indicated in the comments.
* <p>
* The argument types are taken directly from the actual arguments,
* while the return type corresponds to the target of the assignment.
* (Currently, the return type must be given as a false type parameter.
* This type parameter is an irregular use of the generic type syntax,
* and is likely to change in favor of a convention based on target typing.)
* <p>
* The final example uses a special syntax for uttering non-Java names.
* Any name legal to the JVM may be given between the double quotes.
* <p>
* None of these calls is complete without a bootstrap method,
* which must be declared for the enclosing class or method.
* @author John Rose, JSR 292 EG
* This is a place-holder class. Some HotSpot implementations need to see it.
*/
@MethodHandle.PolymorphicSignature
public final class InvokeDynamic {
final class InvokeDynamic {
private InvokeDynamic() { throw new InternalError(); } // do not instantiate
// no statically defined static methods
}
......@@ -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);
}
}
......@@ -29,15 +29,16 @@ import java.dyn.MethodHandles.Lookup;
import java.util.WeakHashMap;
import sun.dyn.Access;
import sun.dyn.MethodHandleImpl;
import sun.dyn.util.VerifyAccess;
import sun.reflect.Reflection;
import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege;
import static sun.dyn.MemberName.newIllegalArgumentException;
/**
* This class consists exclusively of static methods that control
* the linkage of {@code invokedynamic} instructions, and specifically
* their reification as {@link CallSite} objects.
* <em>CLASS WILL BE REMOVED FOR PFD:</em>
* Static routines for controlling invokedynamic behavior.
* Replaced by non-static APIs.
* @author John Rose, JSR 292 EG
* @deprecated This class will be removed in the Public Final Draft.
*/
public class Linkage {
private static final Access IMPL_TOKEN = Access.getToken();
......@@ -45,68 +46,24 @@ public class Linkage {
private Linkage() {} // do not instantiate
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Register a <em>bootstrap method</em> to use when linking dynamic call sites within
* a given caller class.
* <p>
* A bootstrap method must be a method handle with a return type of {@link CallSite}
* and the following arguments:
* <ul>
* <li>the class containing the {@code invokedynamic} instruction, for which the bootstrap method was registered
* <li>the name of the method being invoked (a {@link String})
* <li>the type of the method being invoked (a {@link MethodType})
* </ul>
* The bootstrap method acts as a factory method which accepts the given arguments
* and returns a {@code CallSite} object (possibly of a subclass of {@code CallSite}).
* <p>
* The registration must take place exactly once, either before the class has begun
* being initialized, or from within the class's static initializer.
* Registration will fail with an exception if any of the following conditions hold:
* <ul>
* <li>The immediate caller of this method is in a different package than the given caller class,
* and there is a security manager, and its {@code checkPermission} call throws
* when passed {@link LinkagePermission}("registerBootstrapMethod",callerClass).
* <li>The given caller class already has a bootstrap method registered.
* <li>The given caller class is already fully initialized.
* <li>The given caller class is in the process of initialization, in another thread.
* </ul>
* Because of these rules, a class may install its own bootstrap method in
* a static initializer.
* @param callerClass a class that may have {@code invokedynamic} sites
* @param bootstrapMethod the method to use to bootstrap all such sites
* @exception IllegalArgumentException if the class argument is null or
* a primitive class, or if the bootstrap method is the wrong type
* @exception IllegalStateException if the class already has a bootstrap
* method, or if the its static initializer has already run
* or is already running in another thread
* @exception SecurityException if there is a security manager installed,
* and a {@link LinkagePermission} check fails for "registerBootstrapMethod"
* @deprecated Use @{@link BootstrapMethod} annotations instead
* @deprecated Use @{@link BootstrapMethod} annotations instead.
*/
public static
void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) {
Class callc = Reflection.getCallerClass(2);
checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod");
checkBSM(bootstrapMethod);
if (callc != null && !VerifyAccess.isSamePackage(callerClass, callc))
throw new IllegalArgumentException("cannot set bootstrap method on "+callerClass);
MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
}
static private void checkBSM(MethodHandle mh) {
if (mh == null) throw newIllegalArgumentException("null bootstrap method");
if (mh.type() == BOOTSTRAP_METHOD_TYPE) return;
throw new WrongMethodTypeException(mh.toString());
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Simplified version of {@code registerBootstrapMethod} for self-registration,
* to be called from a static initializer.
* Finds a static method of the required type in the
* given runtime class, and installs it on the caller class.
* @throws NoSuchMethodException if there is no such method
* @throws IllegalStateException if the caller class's static initializer
* has already run, or is already running in another thread
* @deprecated Use @{@link BootstrapMethod} annotations instead
* @deprecated Use @{@link BootstrapMethod} annotations instead.
*/
public static
void registerBootstrapMethod(Class<?> runtime, String name) {
......@@ -115,15 +72,9 @@ public class Linkage {
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Simplified version of {@code registerBootstrapMethod} for self-registration,
* to be called from a static initializer.
* Finds a static method of the required type in the
* caller class itself, and installs it on the caller class.
* @throws IllegalArgumentException if there is no such method
* @throws IllegalStateException if the caller class's static initializer
* has already run, or is already running in another thread
* @deprecated Use @{@link BootstrapMethod} annotations instead
* @deprecated Use @{@link BootstrapMethod} annotations instead.
*/
public static
void registerBootstrapMethod(String name) {
......@@ -140,82 +91,33 @@ public class Linkage {
} catch (NoAccessException ex) {
throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex);
}
checkBSM(bootstrapMethod);
MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Report the bootstrap method registered for a given caller class.
* Returns null if the class has never yet registered a bootstrap method.
* Only callers privileged to set the bootstrap method may inquire
* about it, because a bootstrap method is potentially a back-door entry
* point into its class.
* @exception IllegalArgumentException if the argument is null or
* a primitive class
* @exception SecurityException if there is a security manager installed,
* and the immediate caller of this method is not in the same
* package as the caller class
* and a {@link LinkagePermission} check fails for "getBootstrapMethod"
* @deprecated
*/
public static
MethodHandle getBootstrapMethod(Class callerClass) {
Class callc = Reflection.getCallerClass(2);
checkBootstrapPrivilege(callc, callerClass, "getBootstrapMethod");
return MethodHandleImpl.getBootstrap(IMPL_TOKEN, callerClass);
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* The type of any bootstrap method is a three-argument method
* {@code (Class, String, MethodType)} returning a {@code CallSite}.
*/
public static final MethodType BOOTSTRAP_METHOD_TYPE
private static final MethodType BOOTSTRAP_METHOD_TYPE
= MethodType.methodType(CallSite.class,
Class.class, String.class, MethodType.class);
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Invalidate all <code>invokedynamic</code> call sites everywhere.
* <p>
* When this method returns, every <code>invokedynamic</code> instruction
* will invoke its bootstrap method on next call.
* <p>
* It is unspecified whether call sites already known to the Java
* code will continue to be associated with <code>invokedynamic</code>
* instructions. If any call site is still so associated, its
* {@link CallSite#getTarget()} method is guaranteed to return null
* the invalidation operation completes.
* <p>
* Invalidation operations are likely to be slow. Use them sparingly.
* @deprecated Use {@linkplain CallSite#setTarget call site target setting}
* and {@link VolatileCallSite#invalidateAll call site invalidation} instead.
*/
public static
Object invalidateAll() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(new LinkagePermission("invalidateAll"));
}
throw new UnsupportedOperationException("NYI");
throw new UnsupportedOperationException();
}
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Invalidate all {@code invokedynamic} call sites in the bytecodes
* of any methods of the given class.
* <p>
* When this method returns, every matching <code>invokedynamic</code>
* instruction will invoke its bootstrap method on next call.
* <p>
* For additional semantics of call site invalidation,
* see {@link #invalidateAll()}.
* @deprecated Use {@linkplain CallSite#setTarget call site target setting}
* and {@link VolatileCallSite#invalidateAll call site invalidation} instead.
*/
public static
Object invalidateCallerClass(Class<?> callerClass) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(new LinkagePermission("invalidateAll", callerClass));
}
throw new UnsupportedOperationException("NYI");
throw new UnsupportedOperationException();
}
}
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.dyn;
import java.security.*;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* This class is for managing runtime permission checking for
* operations performed by methods in the {@link Linkage} class.
* Like a {@link RuntimePermission}, on which it is modeled,
* a {@code LinkagePermission} contains a target name but
* no actions list; you either have the named permission
* or you don't.
* <p>
* The following table lists all the possible {@code LinkagePermission} target names,
* and for each provides a description of what the permission allows
* and a discussion of the risks of granting code the permission.
* <p>
*
* <table border=1 cellpadding=5 summary="permission target name,
* what the target allows,and associated risks">
* <tr>
* <th>Permission Target Name</th>
* <th>What the Permission Allows</th>
* <th>Risks of Allowing this Permission</th>
* </tr>
*
* <tr>
* <td>invalidateAll</td>
* <td>Force the relinking of invokedynamic call sites everywhere.</td>
* <td>This could allow an attacker to slow down the system,
* or perhaps expose timing bugs in a dynamic language implementations,
* by forcing redundant relinking operations.</td>
* </tr>
*
*
* <tr>
* <td>invalidateCallerClass.{class name}</td>
* <td>Force the relinking of invokedynamic call sites in the given class.</td>
* <td>See {@code invalidateAll}.</td>
* </tr>
* </table>
* <p>ISSUE: Is this still needed?
*
* @see java.lang.RuntimePermission
* @see java.lang.SecurityManager
*
* @author John Rose, JSR 292 EG
*/
public final class LinkagePermission extends BasicPermission {
private static final long serialVersionUID = 292L;
/**
* Create a new LinkagePermission with the given name.
* The name is the symbolic name of the LinkagePermission, such as
* "invalidateCallerClass.*", etc. An asterisk
* may appear at the end of the name, following a ".", or by itself, to
* signify a wildcard match.
*
* @param name the name of the LinkagePermission
*/
public LinkagePermission(String name) {
super(name);
}
/**
* Create a new LinkagePermission with the given name on the given class.
* Equivalent to {@code LinkagePermission(name+"."+clazz.getName())}.
*
* @param name the name of the LinkagePermission
* @param clazz the class affected by the permission
*/
public LinkagePermission(String name, Class<?> clazz) {
super(name + "." + clazz.getName());
}
}
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.dyn;
/**
* An interface for an object to provide a target {@linkplain MethodHandle method handle} to a {@code invokedynamic} instruction.
* There are many function-like objects in various Java APIs.
* This interface provides a standard way for such function-like objects to be bound
* to a dynamic call site, by providing a view of their behavior in the form of a low-level method handle.
* <p>
* The type {@link MethodHandle} is a concrete class whose implementation
* hierarchy (if any) may be tightly coupled to the underlying JVM implementation.
* It cannot also serve as a base type for user-defined functional APIs.
* For this reason, {@code MethodHandle} cannot be subclassed to add new
* behavior to method handles. But this interface can be used to provide
* a link between a user-defined function and the {@code invokedynamic}
* instruction and the method handle API.
*/
public interface MethodHandleProvider {
/** Produce a method handle which will serve as a behavioral proxy for the current object.
* The type and invocation behavior of the proxy method handle are user-defined,
* and should have some relation to the intended meaning of the original object itself.
* <p>
* The current object may have a changeable behavior.
* For example, {@link CallSite} has a {@code setTarget} method which changes its invocation.
* In such a case, it is <em>incorrect</em> for {@code asMethodHandle} to return
* a method handle whose behavior may diverge from that of the current object.
* Rather, the returned method handle must stably and permanently access
* the behavior of the current object, even if that behavior is changeable.
* <p>
* The reference identity of the proxy method handle is not guaranteed to
* have any particular relation to the reference identity of the object.
* In particular, several objects with the same intended meaning could
* share a common method handle, or the same object could return different
* method handles at different times. In the latter case, the different
* method handles should have the same type and invocation behavior,
* and be usable from any thread at any time.
* In particular, if a MethodHandleProvider is bound to an <code>invokedynamic</code>
* call site, the proxy method handle extracted at the time of binding
* will be used for an unlimited time, until the call site is rebound.
* <p>
* The type {@link MethodHandle} itself implements {@code MethodHandleProvider}, and
* for this method simply returns {@code this}.
*/
public MethodHandle asMethodHandle();
/** Produce a method handle of a given type which will serve as a behavioral proxy for the current object.
* As for the no-argument version {@link #asMethodHandle()}, the invocation behavior of the
* proxy method handle is user-defined. But the type must be the given type,
* or else a {@link WrongMethodTypeException} must be thrown.
* <p>
* If the current object somehow represents a variadic or overloaded behavior,
* the method handle returned for a given type might represent only a subset of
* the current object's repertoire of behaviors, which correspond to that type.
*/
public MethodHandle asMethodHandle(MethodType type) throws WrongMethodTypeException;
}
......@@ -56,21 +56,33 @@ import static sun.dyn.MemberName.newIllegalArgumentException;
* <p>
* This type can be created only by factory methods.
* All factory methods may cache values, though caching is not guaranteed.
* Some factory methods are static, while others are virtual methods which
* modify precursor method types, e.g., by changing a selected parameter.
* <p>
* Factory methods which operate on groups of parameter types
* are systematically presented in two versions, so that both Java arrays and
* Java lists can be used to work with groups of parameter types.
* The query methods {@code parameterArray} and {@code parameterList}
* also provide a choice between arrays and lists.
* <p>
* {@code MethodType} objects are sometimes derived from bytecode instructions
* such as {@code invokedynamic}, specifically from the type descriptor strings associated
* with the instructions in a class file's constant pool.
* When this occurs, any classes named in the descriptor strings must be loaded.
* (But they need not be initialized.)
* This loading may occur at any time before the {@code MethodType} object is first derived.
* <p>
* Like classes and strings, method types can be represented directly
* in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
* Loading such a constant causes its component classes to be loaded as necessary.
* Like classes and strings, method types can also be represented directly
* in a class file's constant pool as constants. The may be loaded by an {@code ldc}
* instruction which refers to a suitable {@code CONSTANT_MethodType} constant pool entry.
* The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
* For more details, see the <a href="package-summary.html#mtcon">package summary</a>.
* <p>
* When the JVM materializes a {@code MethodType} from a descriptor string,
* all classes named in the descriptor must be accessible, and will be loaded.
* (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
* This loading may occur at any time before the {@code MethodType} object is first derived.
* @author John Rose, JSR 292 EG
*/
public final
class MethodType implements java.lang.reflect.Type {
class MethodType {
private final Class<?> rtype;
private final Class<?>[] ptypes;
private MethodTypeForm form; // erased form, plus cached data about primitives
......@@ -119,7 +131,7 @@ class MethodType implements java.lang.reflect.Type {
for (Class<?> ptype : ptypes) {
ptype.equals(ptype); // null check
if (ptype == void.class)
throw newIllegalArgumentException("void parameter: "+this);
throw newIllegalArgumentException("parameter type cannot be void");
}
}
......@@ -139,10 +151,6 @@ class MethodType implements java.lang.reflect.Type {
MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
return makeImpl(rtype, ptypes, false);
}
@Deprecated public static
MethodType make(Class<?> rtype, Class<?>[] ptypes) {
return methodType(rtype, ptypes);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. */
public static
......@@ -150,10 +158,6 @@ class MethodType implements java.lang.reflect.Type {
boolean notrust = false; // random List impl. could return evil ptypes array
return makeImpl(rtype, ptypes.toArray(NO_PTYPES), notrust);
}
@Deprecated public static
MethodType make(Class<?> rtype, List<? extends Class<?>> ptypes) {
return methodType(rtype, ptypes);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* The leading parameter type is prepended to the remaining array.
......@@ -165,10 +169,6 @@ class MethodType implements java.lang.reflect.Type {
System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
return makeImpl(rtype, ptypes1, true);
}
@Deprecated public static
MethodType make(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
return methodType(rtype, ptype0, ptypes);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* The resulting method has no parameter types.
......@@ -177,10 +177,6 @@ class MethodType implements java.lang.reflect.Type {
MethodType methodType(Class<?> rtype) {
return makeImpl(rtype, NO_PTYPES, true);
}
@Deprecated public static
MethodType make(Class<?> rtype) {
return methodType(rtype);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* The resulting method has the single given parameter type.
......@@ -189,10 +185,6 @@ class MethodType implements java.lang.reflect.Type {
MethodType methodType(Class<?> rtype, Class<?> ptype0) {
return makeImpl(rtype, new Class<?>[]{ ptype0 }, true);
}
@Deprecated public static
MethodType make(Class<?> rtype, Class<?> ptype0) {
return methodType(rtype, ptype0);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* The resulting method has the same parameter types as {@code ptypes},
......@@ -202,10 +194,6 @@ class MethodType implements java.lang.reflect.Type {
MethodType methodType(Class<?> rtype, MethodType ptypes) {
return makeImpl(rtype, ptypes.ptypes, true);
}
@Deprecated public static
MethodType make(Class<?> rtype, MethodType ptypes) {
return methodType(rtype, ptypes);
}
/**
* Sole factory method to find or create an interned method type.
......@@ -275,10 +263,6 @@ class MethodType implements java.lang.reflect.Type {
}
return mt;
}
@Deprecated public static
MethodType makeGeneric(int objectArgCount, boolean varargs) {
return genericMethodType(objectArgCount, varargs);
}
/**
* All parameters and the return type will be Object.
......@@ -290,10 +274,6 @@ class MethodType implements java.lang.reflect.Type {
MethodType genericMethodType(int objectArgCount) {
return genericMethodType(objectArgCount, false);
}
@Deprecated public static
MethodType makeGeneric(int objectArgCount) {
return genericMethodType(objectArgCount);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param num the index (zero-based) of the parameter type to change
......@@ -307,18 +287,6 @@ class MethodType implements java.lang.reflect.Type {
return makeImpl(rtype, nptypes, true);
}
/** Convenience method for {@link #insertParameterTypes}.
* @deprecated Use {@link #insertParameterTypes} instead.
*/
@Deprecated
public MethodType insertParameterType(int num, Class<?> nptype) {
int len = ptypes.length;
Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+1);
System.arraycopy(nptypes, num, nptypes, num+1, len-num);
nptypes[num] = nptype;
return makeImpl(rtype, nptypes, true);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param num the position (zero-based) of the inserted parameter type(s)
* @param ptypesToInsert zero or more a new parameter types to insert into the parameter list
......@@ -336,6 +304,22 @@ class MethodType implements java.lang.reflect.Type {
return makeImpl(rtype, nptypes, true);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param ptypesToInsert zero or more a new parameter types to insert after the end of the parameter list
* @return the same type, except with the selected parameter(s) appended
*/
public MethodType appendParameterTypes(Class<?>... ptypesToInsert) {
return insertParameterTypes(parameterCount(), ptypesToInsert);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param ptypesToInsert zero or more a new parameter types to insert after the end of the parameter list
* @return the same type, except with the selected parameter(s) appended
*/
public MethodType appendParameterTypes(List<Class<?>> ptypesToInsert) {
return insertParameterTypes(parameterCount(), ptypesToInsert);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param num the position (zero-based) of the inserted parameter type(s)
* @param ptypesToInsert zero or more a new parameter types to insert into the parameter list
......@@ -377,14 +361,6 @@ class MethodType implements java.lang.reflect.Type {
return makeImpl(rtype, nptypes, true);
}
/** Convenience method for {@link #dropParameterTypes}.
* @deprecated Use {@link #dropParameterTypes} instead.
*/
@Deprecated
public MethodType dropParameterType(int num) {
return dropParameterTypes(num, num+1);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param nrtype a return parameter type to replace the old one with
* @return the same type, except with the return type change
......@@ -552,7 +528,9 @@ class MethodType implements java.lang.reflect.Type {
* parenthesis enclosed, comma separated list of type names,
* followed immediately by the return type.
* <p>
* If a type name is array, it the base type followed
* Each type is represented by its
* {@link java.lang.Class#getSimpleName simple name}.
* If a type name name is array, it the base type followed
* by [], rather than the Class.getName of the array type.
*/
@Override
......@@ -561,35 +539,13 @@ class MethodType implements java.lang.reflect.Type {
sb.append("(");
for (int i = 0; i < ptypes.length; i++) {
if (i > 0) sb.append(",");
putName(sb, ptypes[i]);
sb.append(ptypes[i].getSimpleName());
}
sb.append(")");
putName(sb, rtype);
sb.append(rtype.getSimpleName());
return sb.toString();
}
static void putName(StringBuilder sb, Class<?> cls) {
int brackets = 0;
while (cls.isArray()) {
cls = cls.getComponentType();
brackets++;
}
String n = cls.getName();
/*
if (n.startsWith("java.lang.")) {
String nb = n.substring("java.lang.".length());
if (nb.indexOf('.') < 0) n = nb;
} else if (n.indexOf('.') < 0) {
n = "."+n; // anonymous package
}
*/
sb.append(n);
while (brackets > 0) {
sb.append("[]");
brackets--;
}
}
/// Queries which have to do with the bytecode architecture
/** The number of JVM stack slots required to invoke a method
......@@ -690,14 +646,4 @@ class MethodType implements java.lang.reflect.Type {
public String toMethodDescriptorString() {
return BytecodeDescriptor.unparse(this);
}
/** Temporary alias for toMethodDescriptorString; delete after M3. */
public String toBytecodeString() {
return toMethodDescriptorString();
}
/** Temporary alias for fromMethodDescriptorString; delete after M3. */
public static MethodType fromBytecodeString(String descriptor, ClassLoader loader)
throws IllegalArgumentException, TypeNotPresentException {
return fromMethodDescriptorString(descriptor, loader);
}
}
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.dyn;
import sun.dyn.*;
import sun.dyn.empty.Empty;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A {@code MutableCallSite} is a {@link CallSite} whose target variable
* behaves like an ordinary field.
* An {@code invokedynamic} instruction linked to a {@code MutableCallSite} delegates
* all calls to the site's current target.
* The {@linkplain CallSite#dynamicInvoker dynamic invoker} of a mutable call site
* also delegates each call to the site's current target.
* <p>
* Here is an example of a mutable call site which introduces a
* state variable into a method handle chain.
* <blockquote><pre>
MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
MethodHandle MH_name = name.dynamicInvoker();
MethodType MT_str2 = MethodType.methodType(String.class, String.class);
MethodHandle MH_upcase = MethodHandles.lookup()
.findVirtual(String.class, "toUpperCase", MT_str2);
MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
name.setTarget(MethodHandles.constant(String.class, "Rocky"));
assertEquals("ROCKY", (String) worker1.invokeExact());
name.setTarget(MethodHandles.constant(String.class, "Fred"));
assertEquals("FRED", (String) worker1.invokeExact());
// (mutation can be continued indefinitely)
* </pre></blockquote>
* <p>
* The same call site may be used in several places at once.
* <blockquote><pre>
MethodHandle MH_dear = MethodHandles.lookup()
.findVirtual(String.class, "concat", MT_str2).bindTo(", dear?");
MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
assertEquals("Fred, dear?", (String) worker2.invokeExact());
name.setTarget(MethodHandles.constant(String.class, "Wilma"));
assertEquals("WILMA", (String) worker1.invokeExact());
assertEquals("Wilma, dear?", (String) worker2.invokeExact());
* </pre></blockquote>
* <p>
* <em>Non-synchronization of target values:</em>
* A write to a mutable call site's target does not force other threads
* to become aware of the updated value. Threads which do not perform
* suitable synchronization actions relative to the updated call site
* may cache the old target value and delay their use of the new target
* value indefinitely.
* (This is a normal consequence of the Java Memory Model as applied
* to object fields.)
* <p>
* The {@link #sync sync} operation provides a way to force threads
* to accept a new target value, even if there is no other synchronization.
* <p>
* For target values which will be frequently updated, consider using
* a {@linkplain VolatileCallSite volatile call site} instead.
* @author John Rose, JSR 292 EG
*/
public class MutableCallSite extends CallSite {
/**
* Make a blank call site object with the given method type.
* An initial target method is supplied which will throw
* an {@link IllegalStateException} if called.
* <p>
* Before this {@code CallSite} object is returned from a bootstrap method,
* it is usually provided with a more useful target method,
* via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
* @throws NullPointerException if the proposed type is null
*/
public MutableCallSite(MethodType type) {
super(type);
}
/**
* Make a blank call site object, possibly equipped with an initial target method handle.
* @param target the method handle which will be the initial target of the call site
* @throws NullPointerException if the proposed target is null
*/
public MutableCallSite(MethodHandle target) {
super(target);
}
/**
* Perform a synchronization operation on each call site in the given array,
* forcing all other threads to throw away any cached values previously
* loaded from the target of any of the call sites.
* <p>
* This operation does not reverse any calls that have already started
* on an old target value.
* (Java supports {@linkplain java.lang.Object#wait() forward time travel} only.)
* <p>
* The overall effect is to force all future readers of each call site's target
* to accept the most recently stored value.
* ("Most recently" is reckoned relative to the {@code sync} itself.)
* Conversely, the {@code sync} call may block until all readers have
* (somehow) decached all previous versions of each call site's target.
* <p>
* To avoid race conditions, calls to {@code setTarget} and {@code sync}
* should generally be performed under some sort of mutual exclusion.
* Note that reader threads may observe an updated target as early
* as the {@code setTarget} call that install the value
* (and before the {@code sync} that confirms the value).
* On the other hand, reader threads may observe previous versions of
* the target until the {@code sync} call returns
* (and after the {@code setTarget} that attempts to convey the updated version).
* <p>
* In terms of the Java Memory Model, this operation performs a synchronization
* action which is comparable in effect to the writing of a volatile variable
* by the current thread, and an eventual volatile read by every other thread
* that may access one of the affected call sites.
* <p>
* The following effects are apparent, for each individual call site {@code S}:
* <ul>
* <li>A new volatile variable {@code V} is created, and written by the current thread.
* As defined by the JMM, this write is a global synchronization event.
* <li>As is normal with thread-local ordering of write events,
* every action already performed by the current thread is
* taken to happen before the volatile write to {@code V}.
* (In some implementations, this means that the current thread
* performs a global release operation.)
* <li>Specifically, the write to the current target of {@code S} is
* taken to happen before the volatile write to {@code V}.
* <li>The volatile write to {@code V} is placed
* (in an implementation specific manner)
* in the global synchronization order.
* <li>Consider an arbitrary thread {@code T} (other than the current thread).
* If {@code T} executes a synchronization action {@code A}
* after the volatile write to {@code V} (in the global synchronization order),
* it is therefore required to see either the current target
* of {@code S}, or a later write to that target,
* if it executes a read on the target of {@code S}.
* (This constraint is called "synchronization-order consistency".)
* <li>The JMM specifically allows optimizing compilers to elide
* reads or writes of variables that are known to be useless.
* Such elided reads and writes have no effect on the happens-before
* relation. Regardless of this fact, the volatile {@code V}
* will not be elided, even though its written value is
* indeterminate and its read value is not used.
* </ul>
* Because of the last point, the implementation behaves as if a
* volatile read of {@code V} were performed by {@code T}
* immediately after its action {@code A}. In the local ordering
* of actions in {@code T}, this read happens before any future
* read of the target of {@code S}. It is as if the
* implementation arbitrarily picked a read of {@code S}'s target
* by {@code T}, and forced a read of {@code V} to precede it,
* thereby ensuring communication of the new target value.
* <p>
* As long as the constraints of the Java Memory Model are obeyed,
* implementations may delay the completion of a {@code sync}
* operation while other threads ({@code T} above) continue to
* use previous values of {@code S}'s target.
* However, implementations are (as always) encouraged to avoid
* livelock, and to eventually require all threads to take account
* of the updated target.
* <p>
* This operation is likely to be expensive and should be used sparingly.
* If possible, it should be buffered for batch processing on sets of call sites.
* <p style="font-size:smaller;">
* (This is a static method on a set of call sites, not a
* virtual method on a single call site, for performance reasons.
* Some implementations may incur a large fixed overhead cost
* for processing one or more synchronization operations,
* but a small incremental cost for each additional call site.
* In any case, this operation is likely to be costly, since
* other threads may have to be somehow interrupted
* in order to make them notice the updated target value.
* However, it may be observed that a single call to synchronize
* several sites has the same formal effect as many calls,
* each on just one of the sites.)
* <p>
* Simple implementations of {@code MutableCallSite} may use
* a volatile variable for the target of a mutable call site.
* In such an implementation, the {@code sync} method can be a no-op,
* and yet it will conform to the JMM behavior documented above.
*/
public static void sync(MutableCallSite[] sites) {
STORE_BARRIER.lazySet(0);
// FIXME: NYI
}
private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
}
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.dyn;
/**
* <p>
* A {@code Switcher} is an object which can publish state transitions to other threads.
* A switcher is initially in the <em>valid</em> state, but may at any time be
* changed to the <em>invalid</em> state. Invalidation cannot be reversed.
* <p>
* A single switcher may be used to create any number of guarded method handle pairs.
* Each guarded pair is wrapped in a new method handle {@code M},
* which is permanently associated with the switcher that created it.
* Each pair consists of a target {@code T} and a fallback {@code F}.
* While the switcher is valid, invocations to {@code M} are delegated to {@code T}.
* After it is invalidated, invocations are delegated to {@code F}.
* <p>
* Invalidation is global and immediate, as if the switcher contained a
* volatile boolean variable consulted on every call to {@code M}.
* The invalidation is also permanent, which means the switcher
* can change state only once.
* <p>
* Here is an example of a switcher in action:
* <blockquote><pre>
MethodType MT_str2 = MethodType.methodType(String.class, String.class);
MethodHandle MH_strcat = MethodHandles.lookup()
.findVirtual(String.class, "concat", MT_str2);
Switcher switcher = new Switcher();
// the following steps may be repeated to re-use the same switcher:
MethodHandle worker1 = strcat;
MethodHandle worker2 = MethodHandles.permuteArguments(strcat, MT_str2, 1, 0);
MethodHandle worker = switcher.guardWithTest(worker1, worker2);
assertEquals("method", (String) worker.invokeExact("met", "hod"));
switcher.invalidate();
assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
* </pre></blockquote>
* <p>
* <em>Implementation Note:</em>
* A switcher behaves as if implemented on top of {@link MutableCallSite},
* approximately as follows:
* <blockquote><pre>
public class Switcher {
private static final MethodHandle
K_true = MethodHandles.constant(boolean.class, true),
K_false = MethodHandles.constant(boolean.class, false);
private final MutableCallSite mcs;
private final MethodHandle mcsInvoker;
public Switcher() {
this.mcs = new MutableCallSite(K_true);
this.mcsInvoker = mcs.dynamicInvoker();
}
public MethodHandle guardWithTest(
MethodHandle target, MethodHandle fallback) {
// Note: mcsInvoker is of type boolean().
// Target and fallback may take any arguments, but must have the same type.
return MethodHandles.guardWithTest(this.mcsInvoker, target, fallback);
}
public static void invalidateAll(Switcher[] switchers) {
List<MutableCallSite> mcss = new ArrayList<>();
for (Switcher s : switchers) mcss.add(s.mcs);
for (MutableCallSite mcs : mcss) mcs.setTarget(K_false);
MutableCallSite.sync(mcss.toArray(new MutableCallSite[0]));
}
}
* </pre></blockquote>
* @author Remi Forax, JSR 292 EG
*/
public class Switcher {
private static final MethodHandle
K_true = MethodHandles.constant(boolean.class, true),
K_false = MethodHandles.constant(boolean.class, false);
private final MutableCallSite mcs;
private final MethodHandle mcsInvoker;
/** Create a switcher. */
public Switcher() {
this.mcs = new MutableCallSite(K_true);
this.mcsInvoker = mcs.dynamicInvoker();
}
/**
* Return a method handle which always delegates either to the target or the fallback.
* The method handle will delegate to the target exactly as long as the switcher is valid.
* After that, it will permanently delegate to the fallback.
* <p>
* The target and fallback must be of exactly the same method type,
* and the resulting combined method handle will also be of this type.
* @see MethodHandles#guardWithTest
*/
public MethodHandle guardWithTest(MethodHandle target, MethodHandle fallback) {
if (mcs.getTarget() == K_false)
return fallback; // already invalid
return MethodHandles.guardWithTest(mcsInvoker, target, fallback);
}
/** Set all of the given switchers into the invalid state. */
public static void invalidateAll(Switcher[] switchers) {
MutableCallSite[] sites = new MutableCallSite[switchers.length];
int fillp = 0;
for (Switcher switcher : switchers) {
sites[fillp++] = switcher.mcs;
switcher.mcs.setTarget(K_false);
}
MutableCallSite.sync(sites);
}
}
......@@ -25,58 +25,55 @@
package java.dyn;
import java.lang.annotation.*;
import java.util.List;
/**
* Annotation on InvokeDynamic method calls which requests the JVM to use a specific
* <a href="package-summary.html#bsm">bootstrap method</a>
* to link the call. This annotation is not retained as such in the class file,
* but is transformed into a constant-pool entry for the invokedynamic instruction which
* specifies the desired bootstrap method.
* A {@code VolatileCallSite} is a {@link CallSite} whose target acts like a volatile variable.
* An {@code invokedynamic} instruction linked to a {@code VolatileCallSite} sees updates
* to its call site target immediately, even if the update occurs in another thread.
* There may be a performance penalty for such tight coupling between threads.
* <p>
* If only the <code>value</code> is given, it must name a subclass of {@link CallSite}
* with a constructor which accepts a class, string, and method type.
* If the <code>value</code> and <code>name</code> are both given, there must be
* a static method in the given class of the given name which accepts a class, string,
* and method type, and returns a reference coercible to {@link CallSite}.
* <p>
* This annotation can be placed either on the return type of a single {@link InvokeDynamic}
* call (see examples) or else it can be placed on an enclosing class or method, where it
* determines a default bootstrap method for any {@link InvokeDynamic} calls which are not
* specifically annotated with a bootstrap method.
* Every {@link InvokeDynamic} call must be given a bootstrap method.
* <p>
* Examples:
<blockquote><pre>
&#064;BootstrapMethod(value=MyLanguageRuntime.class, name="bootstrapDynamic")
String x = (String) InvokeDynamic.greet();
//BSM => MyLanguageRuntime.bootstrapDynamic(Here.class, "greet", methodType(String.class))
&#064;BootstrapMethod(MyCallSite.class)
void example() throws Throwable {
InvokeDynamic.greet();
//BSM => new MyCallSite(Here.class, "greet", methodType(void.class))
}
</pre></blockquote>
* Unlike {@code MutableCallSite}, there is no
* {@linkplain MutableCallSite#sync sync operation} on volatile
* call sites, since every write to a volatile variable is implicitly
* synchronized with reader threads.
* <p>
* In other respects, a {@code VolatileCallSite} is interchangeable
* with {@code MutableCallSite}.
* @see MutableCallSite
* @author John Rose, JSR 292 EG
*/
@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();
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);
}
/** 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.
/** Create a call site with a volatile target.
* The target is set to the given value.
* @throws NullPointerException if the proposed target is null
*/
String name() default ""; // empty string denotes a constructor with 'new'
public VolatileCallSite(MethodHandle target) {
super(target);
}
/** Internal override to nominally final getTarget. */
@Override
MethodHandle getTarget0() {
return getTargetVolatile();
}
/** The argument types of the bootstrap method, as passed out by the JVM.
* There is usually no reason to override the default.
/**
* 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.
*/
Class<?>[] arguments() default {Class.class, String.class, MethodType.class};
@Override public void setTarget(MethodHandle newTarget) {
checkTargetChange(getTargetVolatile(), newTarget);
setTargetVolatile(newTarget);
}
}
......@@ -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.
*/
......
......@@ -103,21 +103,20 @@ public class BoundMethodHandle extends MethodHandle {
super(Access.TOKEN, type);
this.argument = argument;
this.vmargslot = vmargslot;
assert(this.getClass() == AdapterMethodHandle.class);
assert(this instanceof AdapterMethodHandle);
}
/** Initialize the current object as a Java method handle, binding it
/** Initialize the current object as a self-bound method handle, binding it
* as the first argument of the method handle {@code entryPoint}.
* The invocation type of the resulting method handle will be the
* same as {@code entryPoint}, except that the first argument
* type will be dropped.
*/
protected BoundMethodHandle(MethodHandle entryPoint) {
super(Access.TOKEN, entryPoint.type().dropParameterTypes(0, 1));
protected BoundMethodHandle(Access token, MethodHandle entryPoint) {
super(token, entryPoint.type().dropParameterTypes(0, 1));
this.argument = this; // kludge; get rid of
this.vmargslot = this.type().parameterSlotDepth(0);
initTarget(entryPoint, 0);
assert(this instanceof JavaMethodHandle);
}
/** Make sure the given {@code argument} can be used as {@code argnum}-th
......@@ -173,6 +172,11 @@ public class BoundMethodHandle extends MethodHandle {
@Override
public String toString() {
return MethodHandleImpl.addTypeString(baseName(), this);
}
/** Component of toString() before the type string. */
protected String baseName() {
MethodHandle mh = this;
while (mh instanceof BoundMethodHandle) {
Object info = MethodHandleNatives.getTargetInfo(mh);
......@@ -185,12 +189,16 @@ public class BoundMethodHandle extends MethodHandle {
if (name != null)
return name;
else
return super.toString(); // <unknown>, probably
return noParens(super.toString()); // "invoke", probably
}
assert(mh != this);
if (mh instanceof JavaMethodHandle)
break; // access JMH.toString(), not BMH.toString()
}
return mh.toString();
return noParens(mh.toString());
}
private static String noParens(String str) {
int paren = str.indexOf('(');
if (paren >= 0) str = str.substring(0, paren);
return str;
}
}
......@@ -41,31 +41,45 @@ public class CallSiteImpl {
Object info,
// Caller information:
MemberName callerMethod, int callerBCI) {
Class<?> caller = callerMethod.getDeclaringClass();
Class<?> callerClass = callerMethod.getDeclaringClass();
Object caller;
if (bootstrapMethod.type().parameterType(0) == Class.class)
caller = callerClass; // remove for PFD
else
caller = MethodHandleImpl.IMPL_LOOKUP.in(callerClass);
if (bootstrapMethod == null) {
// If there is no bootstrap method, throw IncompatibleClassChangeError.
// This is a valid generic error type for resolution (JLS 12.3.3).
throw new IncompatibleClassChangeError
("Class "+caller.getName()+" has not declared a bootstrap method for invokedynamic");
("Class "+callerClass.getName()+" has not declared a bootstrap method for invokedynamic");
}
CallSite site;
try {
Object binding;
if (false) // switch when invokeGeneric works
binding = bootstrapMethod.invokeGeneric(caller, name, type);
else
binding = bootstrapMethod.invokeVarargs(new Object[]{ caller, name, type });
if (info == null) {
if (false) // switch when invokeGeneric works
binding = bootstrapMethod.invokeGeneric(caller, name, type);
else
binding = bootstrapMethod.invokeVarargs(new Object[]{ caller, name, type });
} else {
info = maybeReBox(info);
if (false) // switch when invokeGeneric works
binding = bootstrapMethod.invokeGeneric(caller, name, type, info);
else
binding = bootstrapMethod.invokeVarargs(new Object[]{ caller, name, type, info });
}
//System.out.println("BSM for "+name+type+" => "+binding);
if (binding instanceof CallSite) {
site = (CallSite) binding;
} else if (binding instanceof MethodHandleProvider) {
MethodHandle target = ((MethodHandleProvider) binding).asMethodHandle();
} else if (binding instanceof MethodHandle) {
// Transitional!
MethodHandle target = (MethodHandle) binding;
site = new ConstantCallSite(target);
} else {
throw new ClassCastException("bootstrap method failed to produce a MethodHandle or CallSite");
}
PRIVATE_INITIALIZE_CALL_SITE.<void>invokeExact(site, name, type,
callerMethod, callerBCI);
PRIVATE_INITIALIZE_CALL_SITE.invokeExact(site, name, type,
callerMethod, callerBCI);
assert(site.getTarget() != null);
assert(site.getTarget().type().equals(type));
} catch (Throwable ex) {
......@@ -79,6 +93,24 @@ public class CallSiteImpl {
return site;
}
private static Object maybeReBox(Object x) {
if (x instanceof Integer) {
int xi = (int) x;
if (xi == (byte) xi)
x = xi; // must rebox; see JLS 5.1.7
return x;
} else if (x instanceof Object[]) {
Object[] xa = (Object[]) x;
for (int i = 0; i < xa.length; i++) {
if (xa[i] instanceof Integer)
xa[i] = maybeReBox(xa[i]);
}
return xa;
} else {
return x;
}
}
// This method is private in CallSite because it touches private fields in CallSite.
// These private fields (vmmethod, vmindex) are specific to the JVM.
private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE;
......
......@@ -115,7 +115,7 @@ class FilterGeneric {
static MethodHandle make(Kind kind, int pos, MethodHandle filter, MethodHandle target) {
FilterGeneric fgen = of(kind, pos, filter.type(), target.type());
return fgen.makeInstance(kind, pos, filter, target).asMethodHandle();
return fgen.makeInstance(kind, pos, filter, target);
}
/** Return the adapter information for this target and filter type. */
......@@ -225,13 +225,13 @@ class FilterGeneric {
* The invoker is kept separate from the target because it can be
* generated once per type erasure family, and reused across adapters.
*/
static abstract class Adapter extends JavaMethodHandle {
static abstract class Adapter extends BoundMethodHandle {
protected final MethodHandle filter; // transforms one or more arguments
protected final MethodHandle target; // ultimate target
@Override
public String toString() {
return target.toString();
return MethodHandleImpl.addTypeString(target, this);
}
protected boolean isPrototype() { return target == null; }
......@@ -246,7 +246,7 @@ class FilterGeneric {
protected Adapter(MethodHandle entryPoint,
MethodHandle filter, MethodHandle target) {
super(entryPoint);
super(Access.TOKEN, entryPoint);
this.filter = filter;
this.target = target;
}
......@@ -303,7 +303,7 @@ class FilterGeneric {
protected Object invoke_C0(Object a0) { return target.invokeExact(filter.invokeExact(a0)); }
protected Object invoke_C1(Object a0) { return target.invokeExact(a0, filter.invokeExact()); }
protected Object invoke_Y0(Object a0) { Object[] av = { a0 };
filter.<void>invokeExact(av); return target.invokeExact(av[0]); }
filter.invokeExact(av); return target.invokeExact(av[0]); }
}
static class F2X extends Adapter {
protected F2X(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
......@@ -320,7 +320,7 @@ class FilterGeneric {
protected Object invoke_C1(Object a0, Object a1) { return target.invokeExact(a0, filter.invokeExact(a1)); }
protected Object invoke_C2(Object a0, Object a1) { return target.invokeExact(a0, a1, filter.invokeExact()); }
protected Object invoke_Y0(Object a0, Object a1) { Object[] av = { a0, a1 };
filter.<void>invokeExact(av); return target.invokeExact(av[0], av[1]); }
filter.invokeExact(av); return target.invokeExact(av[0], av[1]); }
}
// */
......@@ -337,7 +337,7 @@ class FilterGeneric {
return target.invokeExact(filter.invokeExact()); }
static final Object[] NO_ARGS = { };
protected Object invoke_Y0() throws Throwable {
filter.<void>invokeExact(NO_ARGS); // make the flyby
filter.invokeExact(NO_ARGS); // make the flyby
return target.invokeExact(); }
}
......@@ -375,7 +375,7 @@ class genclasses {
" return target.invokeExact(@av@, filter.invokeExact()); }",
" protected Object invoke_Y0(@Tvav@) throws Throwable {",
" Object[] av = { @av@ };",
" filter.<void>invokeExact(av); // make the flyby",
" filter.invokeExact(av); // make the flyby",
" return target.invokeExact(@av[i]@); }",
" }",
} };
......@@ -518,7 +518,7 @@ class genclasses {
return target.invokeExact(a0, filter.invokeExact()); }
protected Object invoke_Y0(Object a0) throws Throwable {
Object[] av = { a0 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0]); }
}
static class F2 extends Adapter {
......@@ -548,7 +548,7 @@ class genclasses {
return target.invokeExact(a0, a1, filter.invokeExact()); }
protected Object invoke_Y0(Object a0, Object a1) throws Throwable {
Object[] av = { a0, a1 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1]); }
}
static class F3 extends Adapter {
......@@ -585,7 +585,7 @@ class genclasses {
return target.invokeExact(a0, a1, a2, filter.invokeExact()); }
protected Object invoke_Y0(Object a0, Object a1, Object a2) throws Throwable {
Object[] av = { a0, a1, a2 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2]); }
}
static class F4 extends Adapter {
......@@ -629,7 +629,7 @@ class genclasses {
return target.invokeExact(a0, a1, a2, a3, filter.invokeExact()); }
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3) throws Throwable {
Object[] av = { a0, a1, a2, a3 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3]); }
}
static class F5 extends Adapter {
......@@ -698,7 +698,7 @@ class genclasses {
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
Object a4) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4]); }
}
static class F6 extends Adapter {
......@@ -777,7 +777,7 @@ class genclasses {
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
Object a4, Object a5) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5]); }
}
static class F7 extends Adapter {
......@@ -866,7 +866,7 @@ class genclasses {
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
Object a4, Object a5, Object a6) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6]); }
}
static class F8 extends Adapter {
......@@ -965,7 +965,7 @@ class genclasses {
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
Object a4, Object a5, Object a6, Object a7) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7]); }
}
static class F9 extends Adapter {
......@@ -1104,7 +1104,7 @@ class genclasses {
Object a4, Object a5, Object a6, Object a7,
Object a8) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8]); }
}
static class F10 extends Adapter {
......@@ -1256,7 +1256,7 @@ class genclasses {
Object a4, Object a5, Object a6, Object a7,
Object a8, Object a9) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9]); }
}
static class F11 extends Adapter {
......@@ -1442,7 +1442,7 @@ class genclasses {
Object a4, Object a5, Object a6, Object a7,
Object a8, Object a9, Object a10) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10]); }
}
static class F12 extends Adapter {
......@@ -1644,7 +1644,7 @@ class genclasses {
Object a4, Object a5, Object a6, Object a7,
Object a8, Object a9, Object a10, Object a11) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11]); }
}
static class F13 extends Adapter {
......@@ -1904,7 +1904,7 @@ class genclasses {
Object a8, Object a9, Object a10, Object a11,
Object a12) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12]); }
}
static class F14 extends Adapter {
......@@ -2183,7 +2183,7 @@ class genclasses {
Object a8, Object a9, Object a10, Object a11,
Object a12, Object a13) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13]); }
}
static class F15 extends Adapter {
......@@ -2481,7 +2481,7 @@ class genclasses {
Object a8, Object a9, Object a10, Object a11,
Object a12, Object a13, Object a14) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14]); }
}
static class F16 extends Adapter {
......@@ -2798,7 +2798,7 @@ class genclasses {
Object a8, Object a9, Object a10, Object a11,
Object a12, Object a13, Object a14, Object a15) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15]); }
}
static class F17 extends Adapter {
......@@ -3188,7 +3188,7 @@ class genclasses {
Object a12, Object a13, Object a14, Object a15,
Object a16) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16]); }
}
static class F18 extends Adapter {
......@@ -3600,7 +3600,7 @@ class genclasses {
Object a12, Object a13, Object a14, Object a15,
Object a16, Object a17) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16], av[17]); }
}
static class F19 extends Adapter {
......@@ -4034,7 +4034,7 @@ class genclasses {
Object a12, Object a13, Object a14, Object a15,
Object a16, Object a17, Object a18) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16], av[17], av[18]); }
}
static class F20 extends Adapter {
......@@ -4490,7 +4490,7 @@ class genclasses {
Object a12, Object a13, Object a14, Object a15,
Object a16, Object a17, Object a18, Object a19) throws Throwable {
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19 };
filter.<void>invokeExact(av); // make the flyby
filter.invokeExact(av); // make the flyby
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16], av[17], av[18], av[19]); }
}
}
......@@ -36,7 +36,7 @@ import static sun.dyn.MemberName.uncaughtException;
* final method type is the responsibility of a JVM-level adapter.
* @author jrose
*/
public class FilterOneArgument extends JavaMethodHandle {
public class FilterOneArgument extends BoundMethodHandle {
protected final MethodHandle filter; // Object -> Object
protected final MethodHandle target; // Object -> Object
......@@ -62,7 +62,7 @@ public class FilterOneArgument extends JavaMethodHandle {
}
protected FilterOneArgument(MethodHandle filter, MethodHandle target) {
super(INVOKE);
super(Access.TOKEN, INVOKE);
this.filter = filter;
this.target = target;
}
......
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.dyn;
import java.dyn.*;
import java.lang.reflect.*;
import sun.dyn.util.*;
/**
* Adapters which manage MethodHanndle.invokeGeneric calls.
* The JVM calls one of these when the exact type match fails.
* @author jrose
*/
class InvokeGeneric {
// erased type for the call, which originates from an invokeGeneric site
private final MethodType erasedCallerType;
// an invoker of type (MT, MH; A...) -> R
private final MethodHandle initialInvoker;
/** Compute and cache information for this adapter, so that it can
* call out to targets of the erasure-family of the given erased type.
*/
private InvokeGeneric(MethodType erasedCallerType) throws NoAccessException {
this.erasedCallerType = erasedCallerType;
this.initialInvoker = makeInitialInvoker();
assert initialInvoker.type().equals(erasedCallerType
.insertParameterTypes(0, MethodType.class, MethodHandle.class))
: initialInvoker.type();
}
private static MethodHandles.Lookup lookup() {
return MethodHandleImpl.IMPL_LOOKUP;
}
/** Return the adapter information for this type's erasure. */
static MethodHandle genericInvokerOf(MethodType type) {
MethodTypeImpl form = MethodTypeImpl.of(type);
MethodHandle genericInvoker = form.genericInvoker;
if (genericInvoker == null) {
try {
InvokeGeneric gen = new InvokeGeneric(form.erasedType());
form.genericInvoker = genericInvoker = gen.initialInvoker;
} catch (NoAccessException ex) {
throw new RuntimeException(ex);
}
}
return genericInvoker;
}
private MethodHandle makeInitialInvoker() throws NoAccessException {
// postDispatch = #(MH'; MT, MH; A...){MH'(MT, MH; A)}
MethodHandle postDispatch = makePostDispatchInvoker();
MethodHandle invoker;
if (returnConversionPossible()) {
invoker = MethodHandles.foldArguments(postDispatch,
dispatcher("dispatchWithConversion"));
} else {
invoker = MethodHandles.foldArguments(postDispatch, dispatcher("dispatch"));
}
return invoker;
}
private static final Class<?>[] EXTRA_ARGS = { MethodType.class, MethodHandle.class };
private MethodHandle makePostDispatchInvoker() {
// Take (MH'; MT, MH; A...) and run MH'(MT, MH; A...).
MethodType invokerType = erasedCallerType.insertParameterTypes(0, EXTRA_ARGS);
return MethodHandles.exactInvoker(invokerType);
}
private MethodHandle dropDispatchArguments(MethodHandle targetInvoker) {
assert(targetInvoker.type().parameterType(0) == MethodHandle.class);
return MethodHandles.dropArguments(targetInvoker, 1, EXTRA_ARGS);
}
private MethodHandle dispatcher(String dispatchName) throws NoAccessException {
return lookup().bind(this, dispatchName,
MethodType.methodType(MethodHandle.class,
MethodType.class, MethodHandle.class));
}
static final boolean USE_AS_TYPE_PATH = true;
/** Return a method handle to invoke on the callerType, target, and remaining arguments.
* The method handle must finish the call.
* This is the first look at the caller type and target.
*/
private MethodHandle dispatch(MethodType callerType, MethodHandle target) {
MethodType targetType = target.type();
if (USE_AS_TYPE_PATH || target instanceof AdapterMethodHandle.WithTypeHandler) {
MethodHandle newTarget = target.asType(callerType);
targetType = callerType;
Invokers invokers = MethodTypeImpl.invokers(Access.TOKEN, targetType);
MethodHandle invoker = invokers.erasedInvokerWithDrops;
if (invoker == null) {
invokers.erasedInvokerWithDrops = invoker =
dropDispatchArguments(invokers.erasedInvoker());
}
return invoker.bindTo(newTarget);
}
throw new RuntimeException("NYI");
}
private MethodHandle dispatchWithConversion(MethodType callerType, MethodHandle target) {
MethodHandle finisher = dispatch(callerType, target);
if (returnConversionNeeded(callerType, target))
finisher = addReturnConversion(finisher, callerType.returnType()); //FIXME: slow
return finisher;
}
private boolean returnConversionPossible() {
Class<?> needType = erasedCallerType.returnType();
return !needType.isPrimitive();
}
private boolean returnConversionNeeded(MethodType callerType, MethodHandle target) {
Class<?> needType = callerType.returnType();
if (needType == erasedCallerType.returnType())
return false; // no conversions possible, since must be primitive or Object
Class<?> haveType = target.type().returnType();
if (VerifyType.isNullConversion(haveType, needType))
return false;
return true;
}
private MethodHandle addReturnConversion(MethodHandle target, Class<?> type) {
if (true) throw new RuntimeException("NYI");
// FIXME: This is slow because it creates a closure node on every call that requires a return cast.
MethodType targetType = target.type();
MethodHandle caster = ValueConversions.identity(type);
caster = caster.asType(MethodType.methodType(type, targetType.returnType()));
// Drop irrelevant arguments, because we only care about the return value:
caster = MethodHandles.dropArguments(caster, 1, targetType.parameterList());
MethodHandle result = MethodHandles.foldArguments(caster, target);
return result.asType(target.type());
}
public String toString() {
return "InvokeGeneric"+erasedCallerType;
}
}
......@@ -316,6 +316,20 @@ class MethodHandleNatives {
return MethodTypeImpl.makeImpl(Access.TOKEN, rtype, ptypes, true);
}
/**
* The JVM wants to use a MethodType with invokeGeneric. Give the runtime fair warning.
*/
static void notifyGenericMethodType(MethodType type) {
try {
// Trigger adapter creation.
InvokeGeneric.genericInvokerOf(type);
} catch (Exception ex) {
Error err = new InternalError("Exception while resolving invokeGeneric");
err.initCause(ex);
throw err;
}
}
/**
* The JVM is resolving a CONSTANT_MethodHandle CP entry. And it wants our help.
* It will make an up-call to this method. (Do not change the name or signature.)
......
......@@ -48,6 +48,7 @@ public class MethodTypeImpl {
final long primCounts; // packed prim & double counts
final int vmslots; // total number of parameter slots
final MethodType erasedType; // the canonical erasure
/*lazy*/ MethodType primsAsBoxes; // replace prims by wrappers
/*lazy*/ MethodType primArgsAsBoxes; // wrap args only; make raw return
/*lazy*/ MethodType primsAsInts; // replace prims by int/long
......@@ -59,6 +60,7 @@ public class MethodTypeImpl {
/*lazy*/ FromGeneric fromGeneric; // convert cs. w/o prims to with
/*lazy*/ SpreadGeneric[] spreadGeneric; // expand one argument to many
/*lazy*/ FilterGeneric filterGeneric; // convert argument(s) on the fly
/*lazy*/ MethodHandle genericInvoker; // hook for invokeGeneric
public MethodType erasedType() {
return erasedType;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册