diff -r ff9031a745d9 -r 4ada807383c8 jdk/src/share/classes/java/dyn/CallSite.java --- a/jdk/src/share/classes/java/dyn/CallSite.java Wed Jul 05 17:11:12 2017 +0200 +++ b/jdk/src/share/classes/java/dyn/CallSite.java Fri Apr 30 23:48:23 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,25 +25,32 @@ package java.dyn; -import sun.dyn.util.BytecodeName; import sun.dyn.Access; +import sun.dyn.MemberName; import sun.dyn.CallSiteImpl; -import sun.dyn.MethodHandleImpl; /** - * An {@code invokedynamic} call site, as reified by the - * containing class's bootstrap method. - * Every call site object corresponds to a distinct instance - * of the invokedynamic instruction, and vice versa. - * Every call site has one state variable, called the {@code target}. - * It is typed as a {@link MethodHandle}. This state is never null, and - * it is the responsibility of the bootstrap method to produce call sites - * which have been pre-linked to an initial target method. + * A {@code CallSite} reifies an {@code invokedynamic} instruction from bytecode, + * and controls its linkage. + * Every linked {@code CallSite} object corresponds to a distinct instance + * of the {@code invokedynamic} instruction, and vice versa. *

- * (Note: The bootstrap method may elect to produce call sites of a + * Every linked {@code CallSite} object has one state variable, + * a {@link MethodHandle} reference called the {@code target}. + * This reference is never null. Though it can change its value + * successive values must always have exactly the {@link MethodType method type} + * called for by the bytecodes of the associated {@code invokedynamic} instruction + *

+ * It is the responsibility of each class's + * {@link Linkage#registerBootstrapMethod(Class, MethodHandle) bootstrap method} + * to produce call sites which have been pre-linked to an initial target method. + * The required {@link MethodType type} for the target method is a parameter + * to each bootstrap method call. + *

+ * The bootstrap method may elect to produce call sites of a * language-specific subclass of {@code CallSite}. In such a case, * the subclass may claim responsibility for initializing its target to - * a non-null value, by overriding {@link #initialTarget}.) + * a non-null value, by overriding {@link #initialTarget}. *

* An {@code invokedynamic} instruction which has not yet been executed * is said to be unlinked. When an unlinked call site is executed, @@ -52,54 +59,139 @@ * value to the new call site's target variable, the method {@link #initialTarget} * is called to produce the new call site's first target method. *

+ * A freshly-created {@code CallSite} object is not yet in a linked state. + * An unlinked {@code CallSite} object reports null for its {@code callerClass}. + * When the JVM receives a {@code CallSite} object from a bootstrap method, + * it first ensures that its target is non-null and of the correct type. + * The JVM then links the {@code CallSite} object to the call site instruction, + * enabling the {@code callerClass} to return the class in which the instruction occurs. + *

+ * Next, the JVM links the instruction to the {@code CallSite}, at which point + * any further execution of the {@code invokedynamic} instruction implicitly + * invokes the current target of the {@code CallSite} object. + * After this two-way linkage, both the instruction and the {@code CallSite} + * object are said to be linked. + *

+ * This state of linkage continues until the method containing the + * dynamic call site is garbage collected, or the dynamic call site + * is invalidated by an explicit request. + *

+ * Linkage happens once in the lifetime of any given {@code CallSite} object. + * Because of call site invalidation, this linkage can be repeated for + * a single {@code invokedynamic} instruction, with multiple {@code CallSite} objects. + * When a {@code CallSite} is unlinked from an {@code invokedynamic} instruction, + * the instruction is reset so that it is no longer associated with + * the {@code CallSite} object, but the {@code CallSite} does not change + * state. + *

+ * Here is a sample use of call sites and bootstrap methods which links every + * dynamic call site to print its arguments: +


+private static void printArgs(Object... args) {
+  System.out.println(java.util.Arrays.deepToString(args));
+}
+private static final MethodHandle printArgs;
+static {
+  MethodHandles.Lookup lookup = MethodHandles.lookup();
+  Class thisClass = lookup.lookupClass();  // (who am I?)
+  printArgs = lookup.findStatic(thisClass,
+      "printArgs", MethodType.methodType(void.class, Object[].class));
+  Linkage.registerBootstrapMethod("bootstrapDynamic");
+}
+private static CallSite bootstrapDynamic(Class caller, String name, MethodType type) {
+  // ignore caller and name, but match the type:
+  return new CallSite(MethodHandles.collectArguments(printArgs, type));
+}
+
* @see Linkage#registerBootstrapMethod(java.lang.Class, java.dyn.MethodHandle) * @author John Rose, JSR 292 EG */ public class CallSite - // Note: This is an implementation inheritance hack, and will be removed - // with a JVM change which moves the required hidden state onto this class. - extends CallSiteImpl { private static final Access IMPL_TOKEN = Access.getToken(); - /* + // Fields used only by the JVM. Do not use or change. + private MemberName vmmethod; // supplied by the JVM (ref. to calling method) + private int vmindex; // supplied by the JVM (BCI within calling method) - // Fields used only by the JVM. Do not use or change. - private Object vmmethod; - int callerMID, callerBCI; // supplied by the JVM - + // The actual payload of this call site: private MethodHandle target; - final Object caller; // usually a class - final String name; - final MethodType type; - */ + // Remove this field for PFD and delete deprecated methods: + private MemberName calleeNameRemoveForPFD; + + /** + * Make a blank call site object. + * Before it is returned from a bootstrap method, this {@code CallSite} object + * must be provided with + * a target method via a call to {@link CallSite#setTarget(MethodHandle) setTarget}, + * or by a subclass override of {@link CallSite#initialTarget(Class,String,MethodType) initialTarget}. + */ + public CallSite() { + } /** - * Make a call site given the parameters from a call to the bootstrap method. - * The resulting call site is in an unlinked state, which means that before - * it is returned from a bootstrap method call it must be provided with - * a target method via a call to {@link CallSite#setTarget}. - * @param caller the class in which the relevant {@code invokedynamic} instruction occurs - * @param name the name specified by the {@code invokedynamic} instruction - * @param type the method handle type derived from descriptor of the {@code invokedynamic} instruction + * Make a blank call site object, possibly equipped with an initial target method handle. + * The initial target reference may be null, in which case the {@code CallSite} object + * must be provided with a target method via a call to {@link CallSite#setTarget}, + * or by a subclass override of {@link CallSite#initialTarget}. + * @param target the method handle which will be the initial target of the call site, or null if there is none yet */ - public CallSite(Object caller, String name, MethodType type) { - super(IMPL_TOKEN, caller, name, type); + public CallSite(MethodHandle target) { + this.target = target; } - private static void privateInitializeCallSite(CallSite site, int callerMID, int callerBCI) { - site.callerMID = callerMID; - site.callerBCI = callerBCI; - site.ensureTarget(); + /** @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()); } - private void ensureTarget() { - // Note use of super, which accesses the field directly, - // without deferring to possible subclass overrides. - if (super.getTarget() == null) { - super.setTarget(this.initialTarget()); - super.getTarget().type(); // provoke NPE if still null + + /** Report if the JVM has linked this {@code CallSite} object to a dynamic call site instruction. + * Once it is linked, it is never unlinked. + */ + private boolean isLinked() { + return vmmethod != null; + } + + /** Called from JVM (or low-level Java code) after the BSM returns the newly created CallSite. + * The parameters are JVM-specific. + */ + void initializeFromJVM(String name, + MethodType type, + MemberName callerMethod, + int callerBCI) { + if (this.isLinked()) { + throw new InvokeDynamicBootstrapError("call site has already been linked to an invokedynamic instruction"); } + MethodHandle target = this.target; + if (target == null) { + this.target = target = this.initialTarget(callerMethod.getDeclaringClass(), name, type); + } + if (!target.type().equals(type)) { + throw wrongTargetType(target, type); + } + this.vmindex = callerBCI; + this.vmmethod = callerMethod; + assert(this.isLinked()); } /** @@ -108,14 +200,18 @@ * the method {@code initialTarget} is called to produce an initial * non-null target. (Live call sites must never have null targets.) *

+ * The arguments are the same as those passed to the bootstrap method. + * Thus, a bootstrap method is free to ignore the arguments and simply + * create a "blank" {@code CallSite} object of an appropriate subclass. + *

* If the bootstrap method itself does not initialize the call site, * this method must be overridden, because it just raises an * {@code InvokeDynamicBootstrapError}, which in turn causes the * linkage of the {@code invokedynamic} instruction to terminate * abnormally. */ - protected MethodHandle initialTarget() { - throw new InvokeDynamicBootstrapError("target must be initialized before call site is linked: "+this); + protected MethodHandle initialTarget(Class callerClass, String name, MethodType type) { + throw new InvokeDynamicBootstrapError("target must be initialized before call site is linked: "+name+type); } /** @@ -137,11 +233,11 @@ * @see #setTarget */ public MethodHandle getTarget() { - return super.getTarget(); + return target; } /** - * Link or relink the call site, by setting its target method. + * Set the target method of this call site. *

* The interactions of {@code setTarget} with memory are the same * as of a write to an ordinary variable, such as an array element or a @@ -152,96 +248,46 @@ * Stronger guarantees can be created by putting appropriate operations * into the bootstrap method and/or the target methods used * at any given call site. - * @param target the new target, or null if it is to be unlinked + * @param newTarget the new target * @throws NullPointerException if the proposed new target is null - * @throws WrongMethodTypeException if the proposed new target - * has a method type that differs from the call site's {@link #type()} + * @throws WrongMethodTypeException if the call site is linked and the proposed new target + * has a method type that differs from the previous target */ - public void setTarget(MethodHandle target) { - checkTarget(target); - super.setTarget(target); - } - - protected void checkTarget(MethodHandle target) { - target.type(); // provoke NPE - if (!canSetTarget(target)) - throw new WrongMethodTypeException(String.valueOf(target)+target.type()+" should be of type "+type()); - } - - protected boolean canSetTarget(MethodHandle target) { - return (target != null && target.type() == type()); - } - - /** - * Report the class containing the call site. - * This is an immutable property of the call site, set from the first argument to the constructor. - * @return class containing the call site - */ - public Class callerClass() { - return (Class) caller; + public void setTarget(MethodHandle newTarget) { + MethodType newType = newTarget.type(); // null check! + MethodHandle oldTarget = this.target; + if (oldTarget == null) { + // CallSite is not yet linked. + assert(!isLinked()); + this.target = newTarget; // might be null! + return; + } + MethodType oldType = oldTarget.type(); + if (!newTarget.type().equals(oldType)) + throw wrongTargetType(newTarget, oldType); + if (oldTarget != newTarget) + CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget); } - /** - * Report the method name specified in the {@code invokedynamic} instruction. - * This is an immutable property of the call site, set from the second argument to the constructor. - *

- * Note that the name is a JVM bytecode name, and as such can be any - * non-empty string, as long as it does not contain certain "dangerous" - * characters such as slash {@code '/'} and dot {@code '.'}. - * See the Java Virtual Machine specification for more details. - *

- * Application such as a language runtimes may need to encode - * arbitrary program element names and other configuration information - * into the name. A standard convention for doing this is - * specified here. - * @return method name specified by the call site - */ - public String name() { - return name; + private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) { + return new WrongMethodTypeException(String.valueOf(target)+target.type()+" should be of type "+type); } - /** - * Report the method name specified in the {@code invokedynamic} instruction, - * as a series of components, individually demangled according to - * the standard convention - * specified here. - *

- * Non-empty runs of characters between dangerous characters are demangled. - * Each component is either a completely arbitrary demangled string, - * or else a character constant for a punctuation character, typically ':'. - * (In principle, the character can be any dangerous character that the - * JVM lets through in a method name, such as '$' or ']'. - * Runtime implementors are encouraged to use colon ':' for building - * structured names.) - *

- * In the common case where the name contains no dangerous characters, - * the result is an array whose only element array is the demangled - * name at the call site. Such a demangled name can be any sequence - * of any number of any unicode characters. - * @return method name components specified by the call site + /** Produce a printed representation that displays information about this call site + * that may be useful to the human reader. */ - public Object[] nameComponents() { - return BytecodeName.parseBytecodeName(name); - } - - /** - * Report the resolved result and parameter types of this call site, - * which are derived from its bytecode-level invocation descriptor. - * The types are packaged into a {@link MethodType}. - * Any linked target of this call site must be exactly this method type. - * This is an immutable property of the call site, set from the third argument to the constructor. - * @return method type specified by the call site - */ - public MethodType type() { - return type; - } - @Override public String toString() { - return "CallSite#"+hashCode()+"["+name+type+" => "+getTarget()+"]"; + StringBuilder buf = new StringBuilder("CallSite#"); + buf.append(hashCode()); + if (!isLinked()) + buf.append("[unlinked]"); + else + buf.append("[") + .append("from ").append(vmmethod.getDeclaringClass().getName()) + .append(" : ").append(getTarget().type()) + .append(" => ").append(getTarget()) + .append("]"); + return buf.toString(); } - - // Package-local constant: - static final MethodHandle GET_TARGET = MethodHandleImpl.getLookup(IMPL_TOKEN). - findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class)); }