changeset 3395:75040738aec9

7001424: implement JSR 292 EG adjustments, November 2010 Reviewed-by: twisti
author jrose
date Thu, 16 Dec 2010 15:59:27 -0800
parents 0db159ce2517
children 04c9b38d6bf3
files src/share/classes/java/dyn/CallSite.java src/share/classes/java/dyn/ClassValue.java src/share/classes/java/dyn/ConstantCallSite.java src/share/classes/java/dyn/InvokeDynamicBootstrapError.java src/share/classes/java/dyn/MethodHandle.java src/share/classes/java/dyn/MethodHandles.java src/share/classes/java/dyn/MethodType.java src/share/classes/java/dyn/MutableCallSite.java src/share/classes/java/dyn/Switcher.java src/share/classes/java/dyn/VolatileCallSite.java src/share/classes/java/dyn/package-info.java test/java/dyn/ClassValueTest.java test/java/dyn/InvokeDynamicPrintArgs.java test/java/dyn/JavaDocExamplesTest.java test/java/dyn/MethodHandlesTest.java
diffstat 15 files changed, 775 insertions(+), 348 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/dyn/CallSite.java	Thu Dec 16 00:32:15 2010 -0800
+++ b/src/share/classes/java/dyn/CallSite.java	Thu Dec 16 15:59:27 2010 -0800
@@ -35,14 +35,25 @@
  * which is called its {@code 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>
- * If a mutable target is not required, the {@code invokedynamic} instruction
- * should be linked to a {@linkplain ConstantCallSite constant call site}.
- * If a volatile target is required, because updates to the target must be
- * reliably witnessed by other threads, the {@code invokedynamic} instruction
- * should be linked to a {@linkplain VolatileCallSite volatile call site}.
+ * {@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.
+ * 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
@@ -72,6 +83,7 @@
 </pre></blockquote>
  * @author John Rose, JSR 292 EG
  */
+abstract
 public class CallSite {
     private static final Access IMPL_TOKEN = Access.getToken();
 
@@ -87,7 +99,6 @@
     private MemberName calleeNameRemoveForPFD;
 
     /**
-     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
      * 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.
@@ -95,16 +106,20 @@
      * 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(MethodType type) {
+    /*package-private*/
+    CallSite(MethodType type) {
         target = MethodHandles.invokers(type).uninitializedCallSite();
     }
 
     /**
      * 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 CallSite(MethodHandle target) {
+    /*package-private*/
+    CallSite(MethodHandle target) {
         target.type();  // null check
         this.target = target;
     }
@@ -199,6 +214,8 @@
      * @throws NullPointerException if the proposed new target is null
      * @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) {
         checkTargetChange(this.target, newTarget);
@@ -216,14 +233,6 @@
         return new WrongMethodTypeException(String.valueOf(target)+" 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 super.toString() + type();
-    }
-
     /**
      * Produce a method handle equivalent to an invokedynamic instruction
      * which has been linked to this call site.
@@ -240,7 +249,7 @@
      */
     public final MethodHandle dynamicInvoker() {
         if (this instanceof ConstantCallSite) {
-            return target;  // will not change dynamically
+            return getTarget0();  // will not change dynamically
         }
         MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, GET_TARGET, this);
         MethodHandle invoker = MethodHandles.exactInvoker(this.type());
--- a/src/share/classes/java/dyn/ClassValue.java	Thu Dec 16 00:32:15 2010 -0800
+++ b/src/share/classes/java/dyn/ClassValue.java	Thu Dec 16 15:59:27 2010 -0800
@@ -28,44 +28,78 @@
 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 @@
     /**
      * 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 @@
             // 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);
--- a/src/share/classes/java/dyn/ConstantCallSite.java	Thu Dec 16 00:32:15 2010 -0800
+++ b/src/share/classes/java/dyn/ConstantCallSite.java	Thu Dec 16 15:59:27 2010 -0800
@@ -32,14 +32,16 @@
  * @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");
     }
 }
--- a/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java	Thu Dec 16 00:32:15 2010 -0800
+++ b/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java	Thu Dec 16 15:59:27 2010 -0800
@@ -67,4 +67,16 @@
     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);
+    }
 }
--- a/src/share/classes/java/dyn/MethodHandle.java	Thu Dec 16 00:32:15 2010 -0800
+++ b/src/share/classes/java/dyn/MethodHandle.java	Thu Dec 16 15:59:27 2010 -0800
@@ -128,8 +128,11 @@
  * <p>
  * Bytecode in the JVM can directly obtain a method handle
  * for any accessible method from a {@code ldc} instruction
- * which refers to a {@code CONSTANT_Methodref} or
- * {@code CONSTANT_InterfaceMethodref} constant pool entry.
+ * which refers to a {@code CONSTANT_MethodHandle} constant pool entry.
+ * (Each such entry refers directly to a {@code CONSTANT_Methodref},
+ * {@code CONSTANT_InterfaceMethodref}, or {@code CONSTANT_Fieldref}
+ * constant pool entry.
+ * For more details, see the <a href="package-summary.html#mhcon">package summary</a>.)
  * <p>
  * Java code can also use a reflective API called
  * {@link java.dyn.MethodHandles.Lookup MethodHandles.Lookup}
@@ -185,12 +188,20 @@
 // (Ljava/util/List;)I
 i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
 assert(i == 3);
+mt = MethodType.methodType(void.class, String.class);
+mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt);
+mh.invokeExact(System.out, "Hello, world.");
+// (Ljava/io/PrintStream;Ljava/lang/String;)V
  * </pre></blockquote>
  * Each of the above calls generates a single invokevirtual instruction
  * with the name {@code invoke} and the type descriptors indicated in the comments.
  * The argument types are taken directly from the actual arguments,
- * while the return type is taken from the type parameter.
- * (This type parameter may be a primitive, and it defaults to {@code Object}.)
+ * while the return type is taken from the cast immediately applied to the call.
+ * This cast may be to a primitive.
+ * If it is missing, the type defaults to {@code Object} if the call
+ * occurs in a context which uses the return value.
+ * If the call occurs as a statement, a cast is impossible,
+ * and there is no return type; the call is {@code void}.
  * <p>
  * <em>A note on generic typing:</em>  Method handles do not represent
  * their function types in terms of Java parameterized (generic) types,
@@ -216,6 +227,19 @@
  * fields, methods, and constructors can be represented directly
  * in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
  * Loading such a constant causes the component classes of its type to be loaded as necessary.
+ * <p>
+ * Method handles cannot be subclassed by the user.
+ * Implementations may (or may not) create internal subclasses of {@code MethodHandle}
+ * which may be visible via the {@code java.lang.Object#getClass Object.getClass}
+ * operation.  The programmer should not draw conclusions about a method handle
+ * from its specific class, as the method handle class hierarchy (if any)
+ * may change from time to time or across implementations from different vendors.
+ * <p>
+ * With respect to the Java Memory Model, any method handle will behave
+ * as if all of its fields are final variables.  This means that any method
+ * handle made visible to the application will always be fully formed.
+ * This is true even if the method handle is published through a shared
+ * variables in a data race.
  *
  * @see MethodType
  * @see MethodHandles
@@ -282,8 +306,20 @@
         });
     }
 
-    /** Produce a printed representation that displays information about this call site
-     *  that may be useful to the human reader.
+    /**
+     * Returns a string representation of the method handle,
+     * starting with the string {@code "MethodHandle"} and
+     * ending with the string representation of the method handle's type.
+     * In other words, this method returns a string equal to the value of:
+     * <blockquote><pre>
+     * "MethodHandle" + type().toString()
+     * </pre></blockquote>
+     * <p>
+     * Note:  Future releases of this API may add further information
+     * to the string representation.
+     * Therefore, the present syntax should not be parsed by applications.
+     *
+     * @return a string representation of the method handle
      */
     @Override
     public String toString() {
@@ -512,7 +548,7 @@
         if (nargs < arrayLength)  throw newIllegalArgumentException("bad spread array length");
         int keepPosArgs = nargs - arrayLength;
         MethodType newType = oldType.dropParameterTypes(keepPosArgs, nargs);
-        newType = newType.insertParameterTypes(keepPosArgs, arrayElement);
+        newType = newType.insertParameterTypes(keepPosArgs, arrayType);
         return MethodHandles.spreadArguments(this, newType);
     }
 
@@ -610,6 +646,14 @@
      * else if the type of the target does not exactly match
      * the requested type, a {@link WrongMethodTypeException} is thrown.
      * <p>
+     * A method handle's type handler is not guaranteed to be called every
+     * time its {@code asType} or {@code invokeGeneric} method is called.
+     * If the implementation is faced is able to prove that an equivalent
+     * type handler call has already occurred (on the same two arguments),
+     * it may substitute the result of that previous invocation, without
+     * making a new invocation.  Thus, type handlers should not (in general)
+     * perform significant side effects.
+     * <p>
      * Therefore, the type handler is invoked as if by this code:
      * <blockquote><pre>
      * MethodHandle target = this;      // original method handle
@@ -637,9 +681,9 @@
      methodType(MethodHandle.class, MethodHandle.class, MethodType.class));
 MethodHandle makeAnyList = makeEmptyList.withTypeHandler(collectingTypeHandler);
 
-System.out.println(makeAnyList.invokeGeneric()); // prints []
-System.out.println(makeAnyList.invokeGeneric(1)); // prints [1]
-System.out.println(makeAnyList.invokeGeneric("two", "too")); // prints [two, too]
+assertEquals("[]", makeAnyList.invokeGeneric().toString());
+assertEquals("[1]", makeAnyList.invokeGeneric(1).toString());
+assertEquals("[two, too]", makeAnyList.invokeGeneric("two", "too").toString());
      * <pre><blockquote>
      */
     public MethodHandle withTypeHandler(MethodHandle typeHandler) {
--- a/src/share/classes/java/dyn/MethodHandles.java	Thu Dec 16 00:32:15 2010 -0800
+++ b/src/share/classes/java/dyn/MethodHandles.java	Thu Dec 16 15:59:27 2010 -0800
@@ -155,16 +155,39 @@
         /** The class on behalf of whom the lookup is being performed. */
         private final Class<?> lookupClass;
 
-        /** The allowed sorts of members which may be looked up (public, etc.), with STATIC for package. */
+        /** The allowed sorts of members which may be looked up (PUBLIC, etc.). */
         private final int allowedModes;
 
-        private static final int
-            PUBLIC    = Modifier.PUBLIC,
-            PACKAGE   = Modifier.STATIC,
-            PROTECTED = Modifier.PROTECTED,
-            PRIVATE   = Modifier.PRIVATE,
-            ALL_MODES = (PUBLIC | PACKAGE | PROTECTED | PRIVATE),
-            TRUSTED   = -1;
+        /** A single-bit mask representing {@code public} access,
+         *  which may contribute to the result of {@link #lookupModes lookupModes}.
+         *  The value, {@code 0x01}, happens to be the same as the value of the
+         *  {@code public} {@linkplain java.lang.reflect.Modifier#PUBLIC modifier bit}.
+         */
+        public static final int PUBLIC = Modifier.PUBLIC;
+
+        /** A single-bit mask representing {@code private} access,
+         *  which may contribute to the result of {@link #lookupModes lookupModes}.
+         *  The value, {@code 0x02}, happens to be the same as the value of the
+         *  {@code private} {@linkplain java.lang.reflect.Modifier#PRIVATE modifier bit}.
+         */
+        public static final int PRIVATE = Modifier.PRIVATE;
+
+        /** A single-bit mask representing {@code protected} access,
+         *  which may contribute to the result of {@link #lookupModes lookupModes}.
+         *  The value, {@code 0x04}, happens to be the same as the value of the
+         *  {@code protected} {@linkplain java.lang.reflect.Modifier#PROTECTED modifier bit}.
+         */
+        public static final int PROTECTED = Modifier.PROTECTED;
+
+        /** A single-bit mask representing {@code package} access (default access),
+         *  which may contribute to the result of {@link #lookupModes lookupModes}.
+         *  The value is {@code 0x08}, which does not correspond meaningfully to
+         *  any particular {@linkplain java.lang.reflect.Modifier modifier bit}.
+         */
+        public static final int PACKAGE = Modifier.STATIC;
+
+        private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE);
+        private static final int TRUSTED   = -1;
 
         private static int fixmods(int mods) {
             mods &= (ALL_MODES - PACKAGE);
@@ -189,13 +212,11 @@
         }
 
         /** Which types of members can this lookup object produce?
-         *  The result is a bit-mask of the {@link java.lang.reflect.Modifier Modifier} bits
-         *  {@linkplain java.lang.reflect.Modifier#PUBLIC PUBLIC (0x01)},
-         *  {@linkplain java.lang.reflect.Modifier#PROTECTED PROTECTED (0x02)},
-         *  {@linkplain java.lang.reflect.Modifier#PRIVATE PRIVATE (0x04)},
-         *  and {@linkplain java.lang.reflect.Modifier#STATIC STATIC (0x08)}.
-         *  The modifier bit {@code STATIC} stands in for the package protection mode,
-         *  which does not have an explicit modifier bit.
+         *  The result is a bit-mask of the bits
+         *  {@linkplain #PUBLIC PUBLIC (0x01)},
+         *  {@linkplain #PRIVATE PRIVATE (0x02)},
+         *  {@linkplain #PROTECTED PROTECTED (0x04)},
+         *  and {@linkplain #PACKAGE PACKAGE (0x08)}.
          *  <p>
          *  A freshly-created lookup object
          *  on the {@linkplain java.dyn.MethodHandles#lookup() caller's class}
@@ -238,7 +259,7 @@
         /**
          * Create a lookup on the specified new lookup class.
          * The resulting object will report the specified
-         * class as its own {@link #lookupClass}.
+         * class as its own {@link #lookupClass lookupClass}.
          * <p>
          * However, the resulting {@code Lookup} object is guaranteed
          * to have no more access capabilities than the original.
@@ -300,35 +321,43 @@
                 throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
         }
 
-        /** Display the name of the class.
-         *  If there are restrictions on the access permitted to this lookup,
-         *  display those also.
+        /**
+         * Display the name of the class from which lookups are to be made.
+         * (The name is the one reported by {@link java.lang.Class#getName() Class.getName}.)
+         * If there are restrictions on the access permitted to this lookup,
+         * this is indicated by adding a suffix to the class name, consisting
+         * of a slash and a keyword.  The keyword is chosen as follows:
+         * <ul>
+         * <li>If no access is allowed, the suffix is "/noaccess".
+         * <li>If only public access is allowed, the suffix is "/public".
+         * <li>If only public and package access are allowed, the suffix is "/package".
+         * <li>If only public, package, and private access are allowed, the suffix is "/private".
+         * </ul>
+         * If none of the above cases apply, it is the case that full
+         * access (public, package, private, and protected) is allowed.
+         * In this case, no suffix is added.
+         * This is true only of an object obtained originally from
+         * {@link java.dyn.MethodHandles#lookup() MethodHandles.lookup}.
+         * Objects created by {@link java.dyn.MethodHandles.Lookup#in() Lookup#in}
+         * always have restricted access, and will display a suffix.
          */
         @Override
         public String toString() {
-            String modestr;
             String cname = lookupClass.getName();
             switch (allowedModes) {
             case TRUSTED:
-                return "/trusted";
+                return "/trusted";  // internal only
             case PUBLIC:
-                modestr = "/public";
-                if (lookupClass == Object.class)
-                    return modestr;
-                break;
+                return cname + "/public";
             case PUBLIC|PACKAGE:
                 return cname + "/package";
             case 0:  // no privileges
                 return cname + "/noaccess";
             case ALL_MODES:
                 return cname;
+            default:
+                return cname + "/private";
             }
-            StringBuilder buf = new StringBuilder(cname);
-            if ((allowedModes & PUBLIC) != 0)     buf.append("/public");
-            if ((allowedModes & PACKAGE) != 0)    buf.append("/package");
-            if ((allowedModes & PROTECTED) != 0)  buf.append("/protected");
-            if ((allowedModes & PRIVATE) != 0)    buf.append("/private");
-            return buf.toString();
         }
 
         // call this from an entry point method in Lookup with extraFrames=0.
@@ -369,13 +398,6 @@
          * with the receiver type (usually {@code refc}) prepended.
          * The method and all its argument types must be accessible to the lookup class.
          * <p>
-         * (<em>BUG NOTE:</em> The type {@code Object} may be prepended instead
-         * of the receiver type, if the receiver type is not on the boot class path.
-         * This is due to a temporary JVM limitation, in which MethodHandle
-         * claims to be unable to access such classes.  To work around this
-         * bug, use {@code convertArguments} to normalize the type of the leading
-         * argument to a type on the boot class path, such as {@code Object}.)
-         * <p>
          * When called, the handle will treat the first argument as a receiver
          * and dispatch on the receiver's type to determine which method
          * implementation to enter.
@@ -923,18 +945,6 @@
         return invokers(type).exactInvoker();
     }
 
-    /**
-     * <em>METHOD WILL BE REMOVED FOR PFD:</em>
-     * Produce a method handle equivalent to an invokedynamic instruction
-     * which has been linked to the given call site.
-     * @return a method handle which always invokes the call site's target
-     * @deprecated Use {@link CallSite#dynamicInvoker} instead.
-     */
-    public static
-    MethodHandle dynamicInvoker(CallSite site) throws NoAccessException {
-        return site.dynamicInvoker();
-    }
-
     static Invokers invokers(MethodType type) {
         return MethodTypeImpl.invokers(IMPL_TOKEN, type);
     }
@@ -1071,7 +1081,6 @@
     }
 
     /**
-     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
      * Produce a method handle which adapts the type of the
      * given method handle to a new type by pairwise argument conversion.
      * The original type and new type must have the same number of arguments.
@@ -1292,7 +1301,6 @@
     }
 
     /**
-     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
      * Produce a method handle of the requested return type which returns the given
      * constant value every time it is invoked.
      * <p>
@@ -1318,7 +1326,6 @@
     }
 
     /**
-     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
      * Produce a method handle of the requested type which returns the given
      * constant value every time it is invoked.
      * <p>
@@ -1343,7 +1350,6 @@
     }
 
      /**
-      * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
       * Produce a method handle which returns its sole argument when invoked.
       * <p>The identity function for {@code void} takes no arguments and returns no values.
       * @param type the type of the sole parameter and return value of the desired method handle
@@ -1355,13 +1361,11 @@
     }
 
      /**
-      * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
       * Produce a method handle of the requested type which returns its argument when invoked.
       * If the return type differs from the first argument type, the argument will be
       * converted as if by {@link #explicitCastArguments explicitCastArguments}.
-      * All other arguments are discarded.
+      * If there are additional arguments beyond the first, they are discarded.
       * <p>The identity function for {@code void} discards all its arguments.
-      * <p>
       * @param type the type of the desired method handle
       * @return a method handle of the given type, which always returns its first argument
       * @throws WrongMethodTypeException if the first argument cannot be converted to the required return type
@@ -1446,20 +1450,20 @@
      * <p>
      * <b>Example:</b>
      * <p><blockquote><pre>
-     *   import static java.dyn.MethodHandles.*;
-     *   import static java.dyn.MethodType.*;
-     *   ...
-     *   MethodHandle cat = lookup().findVirtual(String.class,
-     *     "concat", methodType(String.class, String.class));
-     *   System.out.println((String) cat.invokeExact("x", "y")); // xy
-     *   MethodHandle d0 = dropArguments(cat, 0, String.class);
-     *   System.out.println((String) d0.invokeExact("x", "y", "z")); // yz
-     *   MethodHandle d1 = dropArguments(cat, 1, String.class);
-     *   System.out.println((String) d1.invokeExact("x", "y", "z")); // xz
-     *   MethodHandle d2 = dropArguments(cat, 2, String.class);
-     *   System.out.println((String) d2.invokeExact("x", "y", "z")); // xy
-     *   MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
-     *   System.out.println((String) d12.invokeExact("x", 12, true, "z")); // xz
+import static java.dyn.MethodHandles.*;
+import static java.dyn.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+  "concat", methodType(String.class, String.class));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
+MethodHandle d0 = dropArguments(cat, 0, String.class);
+assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
+MethodHandle d1 = dropArguments(cat, 1, String.class);
+assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
+MethodHandle d2 = dropArguments(cat, 2, String.class);
+assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
+MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
+assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
      * </pre></blockquote>
      * @param target the method handle to invoke after the arguments are dropped
      * @param valueTypes the type(s) of the argument(s) to drop
@@ -1532,13 +1536,13 @@
   "concat", methodType(String.class, String.class));
 MethodHandle upcase = lookup().findVirtual(String.class,
   "toUpperCase", methodType(String.class));
-System.out.println((String) cat.invokeExact("x", "y")); // xy
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
 MethodHandle f0 = filterArguments(cat, 0, upcase);
-System.out.println((String) f0.invokeExact("x", "y")); // Xy
+assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy
 MethodHandle f1 = filterArguments(cat, 1, upcase);
-System.out.println((String) f1.invokeExact("x", "y")); // xY
+assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
 MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
-System.out.println((String) f2.invokeExact("x", "y")); // XY
+assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
      * </pre></blockquote>
      * @param target the method handle to invoke after arguments are filtered
      * @param pos the position of the first argument to filter
@@ -1571,7 +1575,7 @@
         return adapter;
     }
 
-    /** <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+    /**
      * Adapt a target method handle {@code target} by post-processing
      * its return value with a unary filter function.
      * <p>
@@ -1693,6 +1697,9 @@
      *     return fallback(a..., b...);
      * }
      * </pre></blockquote>
+     * Note that the test arguments ({@code a...} in the pseudocode) cannot
+     * be modified by execution of the test, and so are passed unchanged
+     * from the caller to the target or fallback as appropriate.
      * @param test method handle used for test, must return boolean
      * @param target method handle to call if test passes
      * @param fallback method handle to call if test fails
@@ -1708,40 +1715,19 @@
         MethodType gtype = test.type();
         MethodType ttype = target.type();
         MethodType ftype = fallback.type();
-        if (ttype != ftype)
+        if (!ttype.equals(ftype))
             throw misMatchedTypes("target and fallback types", ttype, ftype);
-        MethodType gtype2 = ttype.changeReturnType(boolean.class);
-        if (gtype2 != gtype) {
-            if (gtype.returnType() != boolean.class)
-                throw newIllegalArgumentException("guard type is not a predicate "+gtype);
-            int gpc = gtype.parameterCount(), tpc = ttype.parameterCount();
-            if (gpc < tpc) {
-                test = dropArguments(test, gpc, ttype.parameterList().subList(gpc, tpc));
-                gtype = test.type();
-            }
-            if (gtype2 != gtype)
+        if (gtype.returnType() != boolean.class)
+            throw newIllegalArgumentException("guard type is not a predicate "+gtype);
+        List<Class<?>> targs = ttype.parameterList();
+        List<Class<?>> gargs = gtype.parameterList();
+        if (!targs.equals(gargs)) {
+            int gpc = gargs.size(), tpc = targs.size();
+            if (gpc >= tpc || !targs.subList(0, gpc).equals(gargs))
                 throw misMatchedTypes("target and test types", ttype, gtype);
+            test = dropArguments(test, gpc, targs.subList(gpc, tpc));
+            gtype = test.type();
         }
-        /* {
-            MethodHandle invoke = findVirtual(MethodHandle.class, "invoke", target.type());
-            static MethodHandle choose(boolean z, MethodHandle t, MethodHandle f) {
-                return z ? t : f;
-            }
-            static MethodHandle compose(MethodHandle f, MethodHandle g) {
-                Class<?> initargs = g.type().parameterArray();
-                f = dropArguments(f, 1, initargs);  // ignore 2nd copy of args
-                return combineArguments(f, g);
-            }
-            // choose = \z.(z ? target : fallback)
-            MethodHandle choose = findVirtual(MethodHandles.class, "choose",
-                    MethodType.methodType(boolean.class, MethodHandle.class, MethodHandle.class));
-            choose = appendArgument(choose, target);
-            choose = appendArgument(choose, fallback);
-            MethodHandle dispatch = compose(choose, test);
-            // dispatch = \(a...).(test(a...) ? target : fallback)
-            return combineArguments(invoke, dispatch, 0);
-            // return \(a...).((test(a...) ? target : fallback).invokeExact(a...))
-        } */
         return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback);
     }
 
@@ -1756,22 +1742,32 @@
      * If an exception matching the specified type is thrown, the fallback
      * handle is called instead on the exception, plus the original arguments.
      * <p>
-     * The handler must have leading parameter of {@code exType} or a supertype,
-     * followed by arguments which correspond <em>(how? TBD)</em> to
-     * all the parameters of the target.
-     * The target and handler must return the same type.
+     * The target and handler must have the same corresponding
+     * argument and return types, except that handler may omit trailing arguments
+     * (similarly to the predicate in {@link #guardWithTest guardWithTest}).
+     * Also, the handler must have an extra leading parameter of {@code exType} or a supertype.
      * <p> Here is pseudocode for the resulting adapter:
      * <blockquote><pre>
-     * T target(A...);
+     * T target(A..., B...);
      * T handler(ExType, A...);
-     * T adapter(A... a) {
+     * T adapter(A... a, B... b) {
      *   try {
-     *     return target(a...);
+     *     return target(a..., b...);
      *   } catch (ExType ex) {
      *     return handler(ex, a...);
      *   }
      * }
      * </pre></blockquote>
+     * Note that the saved arguments ({@code a...} in the pseudocode) cannot
+     * be modified by execution of the target, and so are passed unchanged
+     * from the caller to the handler, if the handler is invoked.
+     * <p>
+     * The target and handler must return the same type, even if the handler
+     * always throws.  (This might happen, for instance, because the handler
+     * is simulating a {@code finally} clause).
+     * To create such a throwing handler, compose the handler creation logic
+     * with {@link #throwException throwException},
+     * in order to create a method handle of the correct return type.
      * @param target method handle to call
      * @param exType the type of exception which the handler will catch
      * @param handler method handle to call if a matching exception is thrown
@@ -1785,16 +1781,23 @@
     MethodHandle catchException(MethodHandle target,
                                 Class<? extends Throwable> exType,
                                 MethodHandle handler) {
-        MethodType targetType = target.type();
-        MethodType handlerType = handler.type();
-        boolean ok = (targetType.parameterCount() ==
-                      handlerType.parameterCount() - 1);
-//        for (int i = 0; ok && i < numExArgs; i++) {
-//            if (targetType.parameterType(i) != handlerType.parameterType(1+i))
-//                ok = false;
-//        }
-        if (!ok)
-            throw newIllegalArgumentException("target and handler types do not match");
+        MethodType ttype = target.type();
+        MethodType htype = handler.type();
+        if (htype.parameterCount() < 1 ||
+            !htype.parameterType(0).isAssignableFrom(exType))
+            throw newIllegalArgumentException("handler does not accept exception type "+exType);
+        if (htype.returnType() != ttype.returnType())
+            throw misMatchedTypes("target and handler return types", ttype, htype);
+        List<Class<?>> targs = ttype.parameterList();
+        List<Class<?>> hargs = htype.parameterList();
+        hargs = hargs.subList(1, hargs.size());  // omit leading parameter from handler
+        if (!targs.equals(hargs)) {
+            int hpc = hargs.size(), tpc = targs.size();
+            if (hpc >= tpc || !targs.subList(0, hpc).equals(hargs))
+                throw misMatchedTypes("target and handler types", ttype, htype);
+            handler = dropArguments(handler, hpc, hargs.subList(hpc, tpc));
+            htype = handler.type();
+        }
         return MethodHandleImpl.makeGuardWithCatch(IMPL_TOKEN, target, exType, handler);
     }
 
@@ -1813,10 +1816,10 @@
 
     /**
      * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
-     * Produce a wrapper instance of the given "SAM" type which redirects its calls to the given method handle.
-     * A SAM type is a type which declares a single abstract method.
-     * Additionally, it must have either no constructor (as an interface)
-     * or have a public or protected constructor of zero arguments (as a class).
+     * Produce a wrapper instance of the given "SAM" interface which redirects
+     * its calls to the given method handle.
+     * A SAM interface is an interface which declares a single abstract method.
+     * The type must be public.  (No additional access checks are performed.)
      * <p>
      * The resulting instance of the required SAM type will respond to
      * invocation of the SAM type's single abstract method by calling
@@ -1828,9 +1831,9 @@
      * The method handle may throw an <em>undeclared exception</em>,
      * which means any checked exception (or other checked throwable)
      * not declared by the SAM type's single abstract method.
-     * If this happens, the throwable will be wrapped in an instance
-     * of {@link UndeclaredThrowableException} and thrown in that
-     * wrapped form.
+     * If this happens, the throwable will be wrapped in an instance of
+     * {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException}
+     * and thrown in that wrapped form.
      * <p>
      * The wrapper instance is guaranteed to be of a non-public
      * implementation class C in a package containing no classes
@@ -1841,18 +1844,36 @@
      * <li>the SAM type itself and any methods in the SAM type
      * <li>the supertypes of the SAM type (if any) and their methods
      * <li>{@link Object} and its methods
+     * <li>{@link java.dyn.AsInstanceObject AsInstanceObject} and its methods</li>
      * </ul>
      * <p>
+     * (Note: When determining the unique abstract method of a SAM interface,
+     * the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode})
+     * are disregarded.  For example, {@link java.util.Comparator} is a SAM interface,
+     * even though it re-declares the {@code Object.equals} method.)
+     * <p>
      * No stable mapping is promised between the SAM type and
      * the implementation class C.  Over time, several implementation
      * classes might be used for the same SAM type.
      * <p>
      * This method is not guaranteed to return a distinct
-     * wrapper object for each separate call.  If the JVM is able
-     * to prove that a wrapper has already been created for a given
+     * wrapper object for each separate call.  If the implementation is able
+     * to prove that a wrapper of the required SAM type
+     * has already been created for a given
      * method handle, or for another method handle with the
-     * same behavior, the JVM may return that wrapper in place of
+     * same behavior, the implementation may return that wrapper in place of
      * a new wrapper.
+     * <p>
+     * This method is designed to apply to common use cases
+     * where a single method handle must interoperate with
+     * a type (class or interface) that implements a function-like
+     * API.  Additional variations, such as SAM classes with
+     * private constructors, or interfaces with multiple but related
+     * entry points, must be covered by hand-written or automatically
+     * generated adapter classes.  In those cases, consider implementing
+     * {@link java.dyn.MethodHandles.AsInstanceObject AsInstanceObject}
+     * in the adapters, so that generic code can extract the underlying
+     * method handle without knowing where the SAM adapter came from.
      * @param target the method handle to invoke from the wrapper
      * @param samType the desired type of the wrapper, a SAM type
      * @return a correctly-typed wrapper for the given {@code target}
@@ -1870,7 +1891,7 @@
             throw new IllegalArgumentException("not a SAM type: "+samType.getName());
         MethodType samMT = MethodType.methodType(sam.getReturnType(), sam.getParameterTypes());
         if (!samMT.equals(target.type()))
-            throw new IllegalArgumentException("wrong method type");
+            throw new IllegalArgumentException("wrong method type: "+target+" should match "+sam);
         return samType.cast(Proxy.newProxyInstance(
                 samType.getClassLoader(),
                 new Class[]{ samType, AsInstanceObject.class },
@@ -1883,8 +1904,11 @@
                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                         if (method.getDeclaringClass() == AsInstanceObject.class)
                             return getArg(method.getName());
-                        assert method.equals(sam) : method;
-                        return target.invokeVarargs(args);
+                        if (method.equals(sam))
+                            return target.invokeVarargs(args);
+                        if (isObjectMethod(method))
+                            return callObjectMethod(this, method, args);
+                        throw new InternalError();
                     }
                 }));
     }
@@ -1908,12 +1932,43 @@
     }
 
     private static
+    boolean isObjectMethod(Method m) {
+        switch (m.getName()) {
+        case "toString":
+            return (m.getReturnType() == String.class
+                    && m.getParameterTypes().length == 0);
+        case "hashCode":
+            return (m.getReturnType() == int.class
+                    && m.getParameterTypes().length == 0);
+        case "equals":
+            return (m.getReturnType() == boolean.class
+                    && m.getParameterTypes().length == 1
+                    && m.getParameterTypes()[0] == Object.class);
+        }
+        return false;
+    }
+
+    private static
+    Object callObjectMethod(Object self, Method m, Object[] args) {
+        assert(isObjectMethod(m)) : m;
+        switch (m.getName()) {
+        case "toString":
+            return self.getClass().getName() + "@" + Integer.toHexString(self.hashCode());
+        case "hashCode":
+            return System.identityHashCode(self);
+        case "equals":
+            return (self == args[0]);
+        }
+        return null;
+    }
+
+    private static
     Method getSamMethod(Class<?> samType) {
         Method sam = null;
         for (Method m : samType.getMethods()) {
             int mod = m.getModifiers();
             if (Modifier.isAbstract(mod)) {
-                if (sam != null)
+                if (sam != null && !isObjectMethod(sam))
                     return null;  // too many abstract methods
                 sam = m;
             }
--- a/src/share/classes/java/dyn/MethodType.java	Thu Dec 16 00:32:15 2010 -0800
+++ b/src/share/classes/java/dyn/MethodType.java	Thu Dec 16 15:59:27 2010 -0800
@@ -56,21 +56,33 @@
  * <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
@@ -301,6 +313,14 @@
     }
 
     /** 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
      * @return the same type, except with the selected parameter(s) inserted
@@ -508,7 +528,9 @@
      * 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
@@ -517,35 +539,13 @@
         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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/dyn/MutableCallSite.java	Thu Dec 16 15:59:27 2010 -0800
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.dyn;
+
+import sun.dyn.*;
+import sun.dyn.empty.Empty;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A {@code MutableCallSite} is a {@link CallSite} whose target variable
+ * behaves like an ordinary field.
+ * An {@code invokedynamic} instruction linked to a {@code MutableCallSite} delegates
+ * all calls to the site's current target.
+ * The {@linkplain CallSite#dynamicInvoker dynamic invoker} of a mutable call site
+ * also delegates each call to the site's current target.
+ * <p>
+ * Here is an example of a mutable call site which introduces a
+ * state variable into a method handle chain.
+ * <blockquote><pre>
+MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
+MethodHandle MH_name = name.dynamicInvoker();
+MethodType MT_str2 = MethodType.methodType(String.class, String.class);
+MethodHandle MH_upcase = MethodHandles.lookup()
+    .findVirtual(String.class, "toUpperCase", MT_str2);
+MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
+name.setTarget(MethodHandles.constant(String.class, "Rocky"));
+assertEquals("ROCKY", (String) worker1.invokeExact());
+name.setTarget(MethodHandles.constant(String.class, "Fred"));
+assertEquals("FRED", (String) worker1.invokeExact());
+// (mutation can be continued indefinitely)
+ * </pre></blockquote>
+ * <p>
+ * The same call site may be used in several places at once.
+ * <blockquote><pre>
+MethodHandle MH_dear = MethodHandles.lookup()
+    .findVirtual(String.class, "concat", MT_str2).bindTo(", dear?");
+MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
+assertEquals("Fred, dear?", (String) worker2.invokeExact());
+name.setTarget(MethodHandles.constant(String.class, "Wilma"));
+assertEquals("WILMA", (String) worker1.invokeExact());
+assertEquals("Wilma, dear?", (String) worker2.invokeExact());
+ * </pre></blockquote>
+ * <p>
+ * <em>Non-synchronization of target values:</em>
+ * A write to a mutable call site's target does not force other threads
+ * to become aware of the updated value.  Threads which do not perform
+ * suitable synchronization actions relative to the updated call site
+ * may cache the old target value and delay their use of the new target
+ * value indefinitely.
+ * (This is a normal consequence of the Java Memory Model as applied
+ * to object fields.)
+ * <p>
+ * The {@link #sync sync} operation provides a way to force threads
+ * to accept a new target value, even if there is no other synchronization.
+ * <p>
+ * For target values which will be frequently updated, consider using
+ * a {@linkplain VolatileCallSite volatile call site} instead.
+ * @author John Rose, JSR 292 EG
+ */
+public class MutableCallSite extends CallSite {
+    /**
+     * Make a blank call site object with the given method type.
+     * An initial target method is supplied which will throw
+     * an {@link IllegalStateException} if called.
+     * <p>
+     * Before this {@code CallSite} object is returned from a bootstrap method,
+     * it is usually provided with a more useful target method,
+     * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
+     * @throws NullPointerException if the proposed type is null
+     */
+    public MutableCallSite(MethodType type) {
+        super(type);
+    }
+
+    /**
+     * Make a blank call site object, possibly equipped with an initial target method handle.
+     * @param target the method handle which will be the initial target of the call site
+     * @throws NullPointerException if the proposed target is null
+     */
+    public MutableCallSite(MethodHandle target) {
+        super(target);
+    }
+
+    /**
+     * Perform a synchronization operation on each call site in the given array,
+     * forcing all other threads to throw away any cached values previously
+     * loaded from the target of any of the call sites.
+     * <p>
+     * This operation does not reverse any calls that have already started
+     * on an old target value.
+     * (Java supports {@linkplain java.lang.Object#wait() forward time travel} only.)
+     * <p>
+     * The overall effect is to force all future readers of each call site's target
+     * to accept the most recently stored value.
+     * ("Most recently" is reckoned relative to the {@code sync} itself.)
+     * Conversely, the {@code sync} call may block until all readers have
+     * (somehow) decached all previous versions of each call site's target.
+     * <p>
+     * To avoid race conditions, calls to {@code setTarget} and {@code sync}
+     * should generally be performed under some sort of mutual exclusion.
+     * Note that reader threads may observe an updated target as early
+     * as the {@code setTarget} call that install the value
+     * (and before the {@code sync} that confirms the value).
+     * On the other hand, reader threads may observe previous versions of
+     * the target until the {@code sync} call returns
+     * (and after the {@code setTarget} that attempts to convey the updated version).
+     * <p>
+     * In terms of the Java Memory Model, this operation performs a synchronization
+     * action which is comparable in effect to the writing of a volatile variable
+     * by the current thread, and an eventual volatile read by every other thread
+     * that may access one of the affected call sites.
+     * <p>
+     * The following effects are apparent, for each individual call site {@code S}:
+     * <ul>
+     * <li>A new volatile variable {@code V} is created, and written by the current thread.
+     *     As defined by the JMM, this write is a global synchronization event.
+     * <li>As is normal with thread-local ordering of write events,
+     *     every action already performed by the current thread is
+     *     taken to happen before the volatile write to {@code V}.
+     *     (In some implementations, this means that the current thread
+     *     performs a global release operation.)
+     * <li>Specifically, the write to the current target of {@code S} is
+     *     taken to happen before the volatile write to {@code V}.
+     * <li>The volatile write to {@code V} is placed
+     *     (in an implementation specific manner)
+     *     in the global synchronization order.
+     * <li>Consider an arbitrary thread {@code T} (other than the current thread).
+     *     If {@code T} executes a synchronization action {@code A}
+     *     after the volatile write to {@code V} (in the global synchronization order),
+     *     it is therefore required to see either the current target
+     *     of {@code S}, or a later write to that target,
+     *     if it executes a read on the target of {@code S}.
+     *     (This constraint is called "synchronization-order consistency".)
+     * <li>The JMM specifically allows optimizing compilers to elide
+     *     reads or writes of variables that are known to be useless.
+     *     Such elided reads and writes have no effect on the happens-before
+     *     relation.  Regardless of this fact, the volatile {@code V}
+     *     will not be elided, even though its written value is
+     *     indeterminate and its read value is not used.
+     * </ul>
+     * Because of the last point, the implementation behaves as if a
+     * volatile read of {@code V} were performed by {@code T}
+     * immediately after its action {@code A}.  In the local ordering
+     * of actions in {@code T}, this read happens before any future
+     * read of the target of {@code S}.  It is as if the
+     * implementation arbitrarily picked a read of {@code S}'s target
+     * by {@code T}, and forced a read of {@code V} to precede it,
+     * thereby ensuring communication of the new target value.
+     * <p>
+     * As long as the constraints of the Java Memory Model are obeyed,
+     * implementations may delay the completion of a {@code sync}
+     * operation while other threads ({@code T} above) continue to
+     * use previous values of {@code S}'s target.
+     * However, implementations are (as always) encouraged to avoid
+     * livelock, and to eventually require all threads to take account
+     * of the updated target.
+     * <p>
+     * This operation is likely to be expensive and should be used sparingly.
+     * If possible, it should be buffered for batch processing on sets of call sites.
+     * <p style="font-size:smaller;">
+     * (This is a static method on a set of call sites, not a
+     * virtual method on a single call site, for performance reasons.
+     * Some implementations may incur a large fixed overhead cost
+     * for processing one or more synchronization operations,
+     * but a small incremental cost for each additional call site.
+     * In any case, this operation is likely to be costly, since
+     * other threads may have to be somehow interrupted
+     * in order to make them notice the updated target value.
+     * However, it may be observed that a single call to synchronize
+     * several sites has the same formal effect as many calls,
+     * each on just one of the sites.)
+     * <p>
+     * Simple implementations of {@code MutableCallSite} may use
+     * a volatile variable for the target of a mutable call site.
+     * In such an implementation, the {@code sync} method can be a no-op,
+     * and yet it will conform to the JMM behavior documented above.
+     */
+    public static void sync(MutableCallSite[] sites) {
+        STORE_BARRIER.lazySet(0);
+        // FIXME: NYI
+    }
+    private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/dyn/Switcher.java	Thu Dec 16 15:59:27 2010 -0800
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.dyn;
+
+/**
+ * <p>
+ * A {@code Switcher} is an object which can publish state transitions to other threads.
+ * A switcher is initially in the <em>valid</em> state, but may at any time be
+ * changed to the <em>invalid</em> state.  Invalidation cannot be reversed.
+ * <p>
+ * A single switcher may be used to create any number of guarded method handle pairs.
+ * Each guarded pair is wrapped in a new method handle {@code M},
+ * which is permanently associated with the switcher that created it.
+ * Each pair consists of a target {@code T} and a fallback {@code F}.
+ * While the switcher is valid, invocations to {@code M} are delegated to {@code T}.
+ * After it is invalidated, invocations are delegated to {@code F}.
+ * <p>
+ * Invalidation is global and immediate, as if the switcher contained a
+ * volatile boolean variable consulted on every call to {@code M}.
+ * The invalidation is also permanent, which means the switcher
+ * can change state only once.
+ * <p>
+ * Here is an example of a switcher in action:
+ * <blockquote><pre>
+MethodType MT_str2 = MethodType.methodType(String.class, String.class);
+MethodHandle MH_strcat = MethodHandles.lookup()
+    .findVirtual(String.class, "concat", MT_str2);
+Switcher switcher = new Switcher();
+// the following steps may be repeated to re-use the same switcher:
+MethodHandle worker1 = strcat;
+MethodHandle worker2 = MethodHandles.permuteArguments(strcat, MT_str2, 1, 0);
+MethodHandle worker = switcher.guardWithTest(worker1, worker2);
+assertEquals("method", (String) worker.invokeExact("met", "hod"));
+switcher.invalidate();
+assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
+ * </pre></blockquote>
+ * <p>
+ * <em>Implementation Note:</em>
+ * A switcher behaves as if implemented on top of {@link MutableCallSite},
+ * approximately as follows:
+ * <blockquote><pre>
+public class Switcher {
+  private static final MethodHandle
+    K_true  = MethodHandles.constant(boolean.class, true),
+    K_false = MethodHandles.constant(boolean.class, false);
+  private final MutableCallSite mcs;
+  private final MethodHandle mcsInvoker;
+  public Switcher() {
+    this.mcs = new MutableCallSite(K_true);
+    this.mcsInvoker = mcs.dynamicInvoker();
+  }
+  public MethodHandle guardWithTest(
+                MethodHandle target, MethodHandle fallback) {
+    // Note:  mcsInvoker is of type boolean().
+    // Target and fallback may take any arguments, but must have the same type.
+    return MethodHandles.guardWithTest(this.mcsInvoker, target, fallback);
+  }
+  public static void invalidateAll(Switcher[] switchers) {
+    List<MutableCallSite> mcss = new ArrayList<>();
+    for (Switcher s : switchers)  mcss.add(s.mcs);
+    for (MutableCallSite mcs : mcss)  mcs.setTarget(K_false);
+    MutableCallSite.sync(mcss.toArray(new MutableCallSite[0]));
+  }
+}
+ * </pre></blockquote>
+ * @author Remi Forax, JSR 292 EG
+ */
+public class Switcher {
+    private static final MethodHandle
+        K_true  = MethodHandles.constant(boolean.class, true),
+        K_false = MethodHandles.constant(boolean.class, false);
+
+    private final MutableCallSite mcs;
+    private final MethodHandle mcsInvoker;
+
+    /** Create a switcher. */
+    public Switcher() {
+        this.mcs = new MutableCallSite(K_true);
+        this.mcsInvoker = mcs.dynamicInvoker();
+    }
+
+    /**
+     * Return a method handle which always delegates either to the target or the fallback.
+     * The method handle will delegate to the target exactly as long as the switcher is valid.
+     * After that, it will permanently delegate to the fallback.
+     * <p>
+     * The target and fallback must be of exactly the same method type,
+     * and the resulting combined method handle will also be of this type.
+     * @see MethodHandles#guardWithTest
+     */
+    public MethodHandle guardWithTest(MethodHandle target, MethodHandle fallback) {
+        if (mcs.getTarget() == K_false)
+            return fallback;  // already invalid
+        return MethodHandles.guardWithTest(mcsInvoker, target, fallback);
+    }
+
+    /** Set all of the given switchers into the invalid state. */
+    public static void invalidateAll(Switcher[] switchers) {
+        MutableCallSite[] sites = new MutableCallSite[switchers.length];
+        int fillp = 0;
+        for (Switcher switcher : switchers) {
+            sites[fillp++] = switcher.mcs;
+            switcher.mcs.setTarget(K_false);
+        }
+        MutableCallSite.sync(sites);
+    }
+}
--- a/src/share/classes/java/dyn/VolatileCallSite.java	Thu Dec 16 00:32:15 2010 -0800
+++ b/src/share/classes/java/dyn/VolatileCallSite.java	Thu Dec 16 15:59:27 2010 -0800
@@ -28,63 +28,37 @@
 import java.util.List;
 
 /**
- * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
  * 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.
- * <p>
- * Also, a volatile call site has the ability to be <em>invalidated</em>,
- * or reset to a well-defined fallback state.
+ * There may be a performance penalty for such tight coupling between threads.
  * <p>
- * A volatile call site can be used as a switch to control the behavior
- * of another method handle.  For example:
- * <blockquote><pre>
-MethodHandle strcat = MethodHandles.lookup()
-  .findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
-MethodHandle trueCon  = MethodHandles.constant(boolean.class, true);
-MethodHandle falseCon = MethodHandles.constant(boolean.class, false);
-VolatileCallSite switcher = new VolatileCallSite(trueCon, falseCon);
-// following steps may be repeated to re-use the same switcher:
-MethodHandle worker1 = strcat;
-MethodHandle worker2 = MethodHandles.permuteArguments(strcat, strcat.type(), 1, 0);
-MethodHandle worker = MethodHandles.guardWithTest(switcher.dynamicInvoker(), worker1, worker2);
-System.out.println((String) worker.invokeExact("met", "hod"));  // method
-switcher.invalidate();
-System.out.println((String) worker.invokeExact("met", "hod"));  // hodmet
- * </pre></blockquote>
- * In this case, the fallback path (worker2) does not cause a state change.
- * In a real application, the fallback path could cause call sites to relink
- * themselves in response to a global data structure change.
- * Thus, volatile call sites can be used to build dependency mechanisms.
+ * Unlike {@code MutableCallSite}, there is no
+ * {@linkplain MutableCallSite#sync sync operation} on volatile
+ * call sites, since every write to a volatile variable is implicitly
+ * synchronized with reader threads.
+ * <p>
+ * In other respects, a {@code VolatileCallSite} is interchangeable
+ * with {@code MutableCallSite}.
+ * @see MutableCallSite
  * @author John Rose, JSR 292 EG
  */
 public class VolatileCallSite extends CallSite {
-    volatile MethodHandle fallback;
-
     /** Create a call site with a volatile target.
-     *  The initial target and fallback are both set to a method handle
+     *  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);
-        fallback = target;
     }
 
     /** Create a call site with a volatile target.
-     *  The fallback and target are both set to the same initial value.
+     *  The target is set to the given value.
+     * @throws NullPointerException if the proposed target is null
      */
     public VolatileCallSite(MethodHandle target) {
         super(target);
-        fallback = target;
-    }
-
-    /** Create a call site with a volatile target.
-     *  The fallback and target are set to the given initial values.
-     */
-    public VolatileCallSite(MethodHandle target, MethodHandle fallback) {
-        this(target);
-        checkTargetChange(target, fallback);  // make sure they have the same type
-        this.fallback = fallback;
     }
 
     /** Internal override to nominally final getTarget. */
@@ -95,50 +69,11 @@
 
     /**
      * Set the target method of this call site, as a volatile variable.
-     * Has the same effect as {@link CallSite#setTarget}, with the additional
+     * Has the same effect as {@link CallSite#setTarget CallSite.setTarget}, with the additional
      * effects associated with volatiles, in the Java Memory Model.
      */
     @Override public void setTarget(MethodHandle newTarget) {
         checkTargetChange(getTargetVolatile(), newTarget);
         setTargetVolatile(newTarget);
     }
-
-    /**
-     * Return the fallback target for this call site.
-     * It is initialized to the target the call site had when it was constructed,
-     * but it may be changed by {@link setFallbackTarget}.
-     * <p>
-     * Like the regular target of a volatile call site,
-     * the fallback target also has the behavior of a volatile variable.
-     */
-    public MethodHandle getFallbackTarget() {
-        return fallback;
-    }
-
-    /**
-     * Update the fallback target for this call site.
-     * @see #getFallbackTarget
-     */
-    public void setFallbackTarget(MethodHandle newFallbackTarget) {
-        checkTargetChange(fallback, newFallbackTarget);
-        fallback = newFallbackTarget;
-    }
-
-    /**
-     * Reset this call site to a known state by changing the target to the fallback target value.
-     * Equivalent to {@code setTarget(getFallbackTarget())}.
-     */
-    public void invalidate() {
-        setTargetVolatile(getFallbackTarget());
-    }
-
-    /**
-     * Reset all call sites in a list by changing the target of each to its fallback value.
-     */
-    public static void invalidateAll(List<VolatileCallSite> sites) {
-        for (VolatileCallSite site : sites) {
-            site.invalidate();
-        }
-    }
-
 }
--- a/src/share/classes/java/dyn/package-info.java	Thu Dec 16 00:32:15 2010 -0800
+++ b/src/share/classes/java/dyn/package-info.java	Thu Dec 16 15:59:27 2010 -0800
@@ -51,7 +51,7 @@
  * changes being made to the Java Virtual Machine specification for JSR 292.
  * This information will be incorporated in a future version of the JVM specification.</em>
  *
- * <h3>{@code invokedynamic} instruction format</h3>
+ * <h3><a name="indyinsn"></a>{@code invokedynamic} instruction format</h3>
  * In bytecode, an {@code invokedynamic} instruction is formatted as five bytes.
  * The first byte is the opcode 186 (hexadecimal {@code BA}).
  * The next two bytes are a constant pool index (in the same format as for the other {@code invoke} instructions).
@@ -82,7 +82,7 @@
  * instead of a {@code CONSTANT_InvokeDynamic}.  In earlier, obsolete versions of this API, the
  * bootstrap method was specified dynamically, in a per-class basis, during class initialization.)
  *
- * <h3>constant pool entries for {@code invokedynamic} instructions</h3>
+ * <h3><a name="indycon"></a>constant pool entries for {@code invokedynamic} instructions</h3>
  * If a constant pool entry has the tag {@code CONSTANT_InvokeDynamic} (decimal 18),
  * it must contain exactly four more bytes after the tag.
  * These bytes are interpreted as two 16-bit indexes, in the usual {@code u2} format.
@@ -109,7 +109,7 @@
  * <em>(Note: The Proposed Final Draft of this specification is likely to support
  * only the tag 18, not the tag 17.)</em>
  *
- * <h3>constant pool entries for {@linkplain java.dyn.MethodType method types}</h3>
+ * <h3><a name="mtcon"></a>constant pool entries for {@linkplain java.dyn.MethodType method types}</h3>
  * If a constant pool entry has the tag {@code CONSTANT_MethodType} (decimal 16),
  * it must contain exactly two more bytes, which must be an index to a {@code CONSTANT_Utf8}
  * entry which represents a method type signature.
@@ -121,13 +121,8 @@
  * but not initialized.
  * Access checking and error reporting is performed exactly as it is for
  * references by {@code ldc} instructions to {@code CONSTANT_Class} constants.
- * <p>
- * Every use of this constant pool entry must lead to the same outcome.
- * If the resolution of the names in the method type constant causes an exception to occur,
- * this exception must be recorded by the JVM, and re-thrown on every subsequent attempt
- * to use this particular constant.
  *
- * <h3>constant pool entries for {@linkplain java.dyn.MethodHandle method handles}</h3>
+ * <h3><a name="mhcon"></a>constant pool entries for {@linkplain java.dyn.MethodHandle method handles}</h3>
  * If a constant pool entry has the tag {@code CONSTANT_MethodHandle} (decimal 15),
  * it must contain exactly three more bytes.  The first byte after the tag is a subtag
  * value which must be in the range 1 through 9, and the last two must be an index to a
@@ -162,7 +157,8 @@
  * </table>
  * </code>
  * <p>
- * The special names {@code <init>} and {@code <clinit>} are not allowed except for subtag 8 as shown.
+ * The special name {@code <clinit>} is not allowed.
+ * The special name {@code <init>} is not allowed except for subtag 8 as shown.
  * <p>
  * The JVM verifier and linker apply the same access checks and restrictions for these references as for the hypothetical
  * bytecode instructions specified in the last column of the table.  In particular, method handles to
@@ -183,10 +179,23 @@
  * Method handle constants for subtags {@code REF_getStatic}, {@code REF_putStatic}, and {@code REF_invokeStatic}
  * may force class initialization on their first invocation, just like the corresponding bytecodes.
  * <p>
- * Every use of this constant pool entry must lead to the same outcome.
- * If the resolution of the names in the method handle constant causes an exception to occur,
- * this exception must be recorded by the JVM, and re-thrown on every subsequent attempt
- * to use this particular constant.
+ * The rules of section 5.4.3 of the
+ * <a href="http://java.sun.com/docs/books/jvms/second_edition/html/ConstantPool.doc.html#73492">JVM Specification</a>
+ * apply to the resolution of {@code CONSTANT_MethodType}, {@code CONSTANT_MethodHandle},
+ * and {@code CONSTANT_InvokeDynamic} constants,
+ * by the execution of {@code invokedynamic} and {@code ldc} instructions.
+ * (Roughly speaking, this means that every use of a constant pool entry
+ * must lead to the same outcome.
+ * If the resoultion succeeds, the same object reference is produced
+ * by every subsequent execution of the same instruction.
+ * If the resolution of the constant causes an error to occur,
+ * the same error will be re-thrown on every subsequent attempt
+ * to use this particular constant.)
+ * <p>
+ * Constants created by the resolution of these constant pool types are not necessarily
+ * interned.  Except for {@link CONSTANT_Class} and {@link CONSTANT_String} entries,
+ * two distinct constant pool entries might not resolve to the same reference
+ * even if they contain the same symbolic reference.
  *
  * <h2><a name="bsm"></a>Bootstrap Methods</h2>
  * Before the JVM can execute a dynamic call site (an {@code invokedynamic} instruction),
@@ -263,7 +272,7 @@
  *     the expected {@code MethodType} </li>
  * </ul>
  *
- * <h3>timing of linkage</h3>
+ * <h3><a name="linktime"></a>timing of linkage</h3>
  * A dynamic call site is linked just before its first execution.
  * The bootstrap method call implementing the linkage occurs within
  * a thread that is attempting a first execution.
@@ -398,6 +407,7 @@
  * Such a practice is likely to produce large class files and constant pools.
  *
  * <p style="font-size:smaller;">
+ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
  * (Usage Note: There is no mechanism for specifying five or more positional arguments to the bootstrap method.
  * If there are two or more arguments, the Java code of the bootstrap method is required to extract them from
  * a varargs-style object array.
@@ -414,7 +424,7 @@
  * {@link java.dyn.MethodHandle#asSpreader asSpreader}
  * and {@link java.dyn.MethodHandle#asSpreader asCollector} methods.)
  *
- * <h2>Structure Summary</h2>
+ * <h2><a name="structs"></a>Structure Summary</h2>
  * <blockquote><pre>// summary of constant and attribute structures
 struct CONSTANT_MethodHandle_info {
   u1 tag = 15;
--- a/test/java/dyn/ClassValueTest.java	Thu Dec 16 00:32:15 2010 -0800
+++ b/test/java/dyn/ClassValueTest.java	Thu Dec 16 15:59:27 2010 -0800
@@ -53,12 +53,13 @@
         return "CV1:" + type.getName();
     }
     static int countForCV1;
-    static final ClassValue<String> CV1 = new ClassValue<String>() {
+    static final ClassValue<String> CV1 = new CV1();
+    private static class CV1 extends ClassValue<String> {
         protected String computeValue(Class<?> type) {
             countForCV1++;
             return nameForCV1(type);
         }
-    };
+    }
 
     static final Class[] CLASSES = {
         String.class,
--- a/test/java/dyn/InvokeDynamicPrintArgs.java	Thu Dec 16 00:32:15 2010 -0800
+++ b/test/java/dyn/InvokeDynamicPrintArgs.java	Thu Dec 16 15:59:27 2010 -0800
@@ -99,7 +99,7 @@
     private static CallSite bsm(Lookup caller, String name, MethodType type) throws ReflectiveOperationException {
         // ignore caller and name, but match the type:
         Object bsmInfo = Arrays.asList(caller, name, type);
-        return new CallSite(MH_printArgs().bindTo(bsmInfo).asCollector(Object[].class, type.parameterCount()).asType(type));
+        return new ConstantCallSite(MH_printArgs().bindTo(bsmInfo).asCollector(Object[].class, type.parameterCount()).asType(type));
     }
     private static MethodType MT_bsm() {
         shouldNotCallThis();
@@ -117,7 +117,7 @@
             bsmInfo.addAll(Arrays.asList((Object[])arg));
         else
             bsmInfo.add(arg);
-        return new CallSite(MH_printArgs().bindTo(bsmInfo).asCollector(Object[].class, type.parameterCount()).asType(type));
+        return new ConstantCallSite(MH_printArgs().bindTo(bsmInfo).asCollector(Object[].class, type.parameterCount()).asType(type));
     }
     private static MethodType MT_bsm2() {
         shouldNotCallThis();
--- a/test/java/dyn/JavaDocExamplesTest.java	Thu Dec 16 00:32:15 2010 -0800
+++ b/test/java/dyn/JavaDocExamplesTest.java	Thu Dec 16 15:59:27 2010 -0800
@@ -107,16 +107,15 @@
 {} /// JAVADOC
 MethodHandle cat = lookup().findVirtual(String.class,
   "concat", methodType(String.class, String.class));
-cat = cat.asType(methodType(Object.class, String.class, String.class)); /*(String)*/
-assertEquals("xy", /*(String)*/ cat.invokeExact("x", "y"));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
 MethodHandle d0 = dropArguments(cat, 0, String.class);
-assertEquals("yz", /*(String)*/ d0.invokeExact("x", "y", "z"));
+assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
 MethodHandle d1 = dropArguments(cat, 1, String.class);
-assertEquals("xz", /*(String)*/ d1.invokeExact("x", "y", "z"));
+assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
 MethodHandle d2 = dropArguments(cat, 2, String.class);
-assertEquals("xy", /*(String)*/ d2.invokeExact("x", "y", "z"));
+assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
 MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
-assertEquals("xz", /*(String)*/ d12.invokeExact("x", 12, true, "z"));
+assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
             }}
     }
 
@@ -125,16 +124,15 @@
 {} /// JAVADOC
 MethodHandle cat = lookup().findVirtual(String.class,
   "concat", methodType(String.class, String.class));
-cat = cat.asType(methodType(Object.class, String.class, String.class)); /*(String)*/
 MethodHandle upcase = lookup().findVirtual(String.class,
   "toUpperCase", methodType(String.class));
-assertEquals("xy", /*(String)*/ cat.invokeExact("x", "y")); // xy
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
 MethodHandle f0 = filterArguments(cat, 0, upcase);
-assertEquals("Xy", /*(String)*/ f0.invokeExact("x", "y")); // Xy
+assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy
 MethodHandle f1 = filterArguments(cat, 1, upcase);
-assertEquals("xY", /*(String)*/ f1.invokeExact("x", "y")); // xY
+assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
 MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
-assertEquals("XY", /*(String)*/ f2.invokeExact("x", "y")); // XY
+assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
             }}
     }
 
@@ -144,24 +142,6 @@
         Assert.assertEquals(exp, act);
     }
 
-    @Test public void testVolatileCallSite() throws Throwable {
-        {{
-{} /// JAVADOC
-MethodHandle strcat = MethodHandles.lookup()
-  .findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
-MethodHandle trueCon  = MethodHandles.constant(boolean.class, true);
-MethodHandle falseCon = MethodHandles.constant(boolean.class, false);
-VolatileCallSite switcher = new VolatileCallSite(trueCon, falseCon);
-// following steps may be repeated to re-use the same switcher:
-MethodHandle worker1 = strcat;
-MethodHandle worker2 = MethodHandles.permuteArguments(strcat, strcat.type(), 1, 0);
-MethodHandle worker = MethodHandles.guardWithTest(switcher.dynamicInvoker(), worker1, worker2);
-System.out.println((String) worker.invokeExact("met", "hod"));  // method
-switcher.invalidate();
-System.out.println((String) worker.invokeExact("met", "hod"));  // hodmet
-            }}
-    }
-
 static MethodHandle asList;
     @Test public void testWithTypeHandler() throws Throwable {
         {{
@@ -182,9 +162,9 @@
      methodType(MethodHandle.class, MethodHandle.class, MethodType.class));
 MethodHandle makeAnyList = makeEmptyList.withTypeHandler(collectingTypeHandler);
 
-System.out.println(makeAnyList.invokeGeneric());
-System.out.println(makeAnyList.invokeGeneric(1));
-System.out.println(makeAnyList.invokeGeneric("two", "too"));
+assertEquals("[]", makeAnyList.invokeGeneric().toString());
+assertEquals("[1]", makeAnyList.invokeGeneric(1).toString());
+assertEquals("[two, too]", makeAnyList.invokeGeneric("two", "too").toString());
             }}
     }
 
--- a/test/java/dyn/MethodHandlesTest.java	Thu Dec 16 00:32:15 2010 -0800
+++ b/test/java/dyn/MethodHandlesTest.java	Thu Dec 16 15:59:27 2010 -0800
@@ -1688,8 +1688,8 @@
 
         // dynamic invoker
         countTest();
-        CallSite site = new CallSite(type);
-        inv = MethodHandles.dynamicInvoker(site);
+        CallSite site = new MutableCallSite(type);
+        inv = site.dynamicInvoker();
 
         // see if we get the result of the original target:
         try {
@@ -1820,11 +1820,12 @@
         MethodHandle throwOrReturn
                 = PRIVATE.findStatic(MethodHandlesTest.class, "throwOrReturn",
                     MethodType.methodType(Object.class, Object.class, Throwable.class));
-        MethodHandle thrower = throwOrReturn;
+        MethodHandle thrower = throwOrReturn.asType(MethodType.genericMethodType(2));
         while (thrower.type().parameterCount() < nargs)
             thrower = MethodHandles.dropArguments(thrower, thrower.type().parameterCount(), Object.class);
+        MethodHandle catcher = ValueConversions.varargsList(1+nargs).asType(MethodType.genericMethodType(1+nargs));
         MethodHandle target = MethodHandles.catchException(thrower,
-                thrown.getClass(), ValueConversions.varargsList(1+nargs));
+                thrown.getClass(), catcher);
         assertEquals(thrower.type(), target.type());
         //System.out.println("catching with "+target+" : "+throwOrReturn);
         Object[] args = randomArgs(nargs, Object.class);