changeset 48624:25adfa59cdfa condy-folding

Rename @TrackableConstant to @Foldable; add Constable support to many classes; more tests and bugfixes; more docs
author briangoetz
date Thu, 04 Jan 2018 16:03:09 -0500
parents 812478fb30e5
children 5c5bc69f593b
files src/java.base/share/classes/java/lang/annotation/Foldable.java src/java.base/share/classes/java/lang/annotation/TrackableConstant.java src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java src/java.base/share/classes/java/lang/invoke/MethodHandle.java src/java.base/share/classes/java/lang/sym/BootstrapSpecifier.java src/java.base/share/classes/java/lang/sym/ClassRef.java src/java.base/share/classes/java/lang/sym/Constable.java src/java.base/share/classes/java/lang/sym/DynamicConstantRef.java src/java.base/share/classes/java/lang/sym/EnumRef.java src/java.base/share/classes/java/lang/sym/MethodHandleRef.java src/java.base/share/classes/java/lang/sym/MethodTypeRef.java src/java.base/share/classes/java/lang/sym/NamedClassRef.java src/java.base/share/classes/java/lang/sym/PrimitiveClassRef.java src/java.base/share/classes/java/lang/sym/SymbolicRef.java src/java.base/share/classes/java/lang/sym/SymbolicRefs.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java test/jdk/java/lang/invoke/ConstablesTest.java test/jdk/java/lang/sym/ClassRefTest.java test/jdk/java/lang/sym/DynamicConstantRefTest.java test/jdk/java/lang/sym/MethodHandleRefTest.java test/jdk/java/lang/sym/MethodTypeRefTest.java test/jdk/java/lang/sym/SymbolicRefTest.java
diffstat 22 files changed, 1340 insertions(+), 667 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/annotation/Foldable.java	Thu Jan 04 16:03:09 2018 -0500
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017, 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.lang.annotation;
+
+import java.lang.sym.Constable;
+import java.lang.sym.SymbolicRef;
+import java.lang.invoke.Intrinsics;
+
+/**
+ * Identifies a method that is a candidate for compile-time constant folding.
+ * Such a method must be a <em>pure function</em> of its inputs, all inputs
+ * (including the receiver, if applied to an instance method) must be value-based
+ * types, and the output must be a value-based type that is representable
+ * in the constant pool ({@link Constable} or {@link SymbolicRef}).
+ *
+ * <p>For accesses of fields annotated as {@linkplain Foldable}, and invocations
+ * of methods annotated as {@linkplain Foldable} whose arguments (and, for instance
+ * methods, the receiver) are all constant expressions, the compiler may evaluate
+ * the expression reflectively at compile time and replace it with a constant
+ * load of the result, or track the result as a constant expression for possible
+ * intrinsification via methods in {@link Intrinsics}.
+ *
+ * @see Constable
+ * @see SymbolicRef
+ * @see Intrinsics
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target({ ElementType.METHOD, ElementType.FIELD })
+public @interface Foldable { }
--- a/src/java.base/share/classes/java/lang/annotation/TrackableConstant.java	Tue Jan 02 18:05:15 2018 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2017, 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.lang.annotation;
-
-import java.lang.sym.SymbolicRef;
-import java.lang.invoke.Intrinsics;
-
-/**
- * Identifies a {@link SymbolicRef}-yielding factory method or combinator.
- * For invocations of methods
- * annotated as {@linkplain TrackableConstant} whose arguments (and, for instance
- * methods, the receiver) are all constant expressions, the compiler will track
- * the result as a constant expression, for possible intrinsification.
- *
- * @see SymbolicRef
- * @see Intrinsics
- */
-@Retention(RetentionPolicy.CLASS)
-@Target({ ElementType.METHOD, ElementType.FIELD })
-public @interface TrackableConstant {}
--- a/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java	Tue Jan 02 18:05:15 2018 -0500
+++ b/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java	Thu Jan 04 16:03:09 2018 -0500
@@ -242,10 +242,6 @@
         requireNonNull(handle);
         requireNonNull(args);
 
-        if (type != handle.type().returnType()) {
-            handle = handle.asType(handle.type().changeReturnType(type));
-        }
-
         return handle.invokeWithArguments(args);
     }
 
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Tue Jan 02 18:05:15 2018 -0500
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Thu Jan 04 16:03:09 2018 -0500
@@ -1534,11 +1534,11 @@
             case REF_getField:
                 return Optional.of(MethodHandleRef.ofField(MethodHandleRef.Kind.GETTER, owner, name, type.returnType()));
             case REF_putField:
-                return Optional.of(MethodHandleRef.ofField(MethodHandleRef.Kind.SETTER, owner, name, type.returnType()));
+                return Optional.of(MethodHandleRef.ofField(MethodHandleRef.Kind.SETTER, owner, name, type.parameterType(0)));
             case REF_getStatic:
                 return Optional.of(MethodHandleRef.ofField(MethodHandleRef.Kind.STATIC_GETTER, owner, name, type.returnType()));
             case REF_putStatic:
-                return Optional.of(MethodHandleRef.ofField(MethodHandleRef.Kind.STATIC_SETTER, owner, name, type.returnType()));
+                return Optional.of(MethodHandleRef.ofField(MethodHandleRef.Kind.STATIC_SETTER, owner, name, type.parameterType(0)));
             case REF_invokeVirtual:
                 return Optional.of(MethodHandleRef.of(MethodHandleRef.Kind.VIRTUAL, owner, name, type));
             case REF_invokeStatic:
--- a/src/java.base/share/classes/java/lang/sym/BootstrapSpecifier.java	Tue Jan 02 18:05:15 2018 -0500
+++ b/src/java.base/share/classes/java/lang/sym/BootstrapSpecifier.java	Thu Jan 04 16:03:09 2018 -0500
@@ -24,7 +24,7 @@
  */
 package java.lang.sym;
 
-import java.lang.annotation.TrackableConstant;
+import java.lang.annotation.Foldable;
 import java.util.Arrays;
 import java.util.Objects;
 
@@ -46,7 +46,7 @@
      * @param bootstrapArgs the bootstrap arguments for the {@code invokedynamic}
      * @return the descriptor
      */
-    @TrackableConstant
+    @Foldable
     public static BootstrapSpecifier of(MethodHandleRef bootstrapMethod, SymbolicRef<?>... bootstrapArgs) {
         return new BootstrapSpecifier(bootstrapMethod, bootstrapArgs);
     }
@@ -55,7 +55,7 @@
      * Returns the bootstrap method for the {@code invokedynamic}
      * @return the bootstrap method for the {@code invokedynamic}
      */
-    @TrackableConstant
+    @Foldable
     public MethodHandleRef method() { return bootstrapMethod; }
 
     /**
--- a/src/java.base/share/classes/java/lang/sym/ClassRef.java	Tue Jan 02 18:05:15 2018 -0500
+++ b/src/java.base/share/classes/java/lang/sym/ClassRef.java	Thu Jan 04 16:03:09 2018 -0500
@@ -24,7 +24,9 @@
  */
 package java.lang.sym;
 
-import java.lang.annotation.TrackableConstant;
+import java.lang.annotation.Foldable;
+import java.lang.invoke.MethodHandles;
+import java.util.Optional;
 
 /**
  * A descriptor for a {@linkplain Class} constant.
@@ -39,7 +41,7 @@
      * @throws IllegalArgumentException if the name string does not
      * describe a valid class name
      */
-    @TrackableConstant
+    @Foldable
     static ClassRef of(String name) {
         return ClassRef.ofDescriptor("L" + name.replace('.', '/') + ";");
     }
@@ -52,7 +54,7 @@
      * @return a {@linkplain ClassRef} describing the desired class
      * @throws IllegalArgumentException if the package name or class name are not in the correct format
      */
-    @TrackableConstant
+    @Foldable
     static ClassRef of(String packageName, String className) {
         return ofDescriptor("L" + packageName.replace('.', '/') + (packageName.length() > 0 ? "/" : "") + className + ";");
     }
@@ -66,7 +68,7 @@
      * @throws IllegalArgumentException if the descriptor string does not
      * describe a valid class descriptor
      */
-    @TrackableConstant
+    @Foldable
     static ClassRef ofDescriptor(String descriptor) {
         if (descriptor == null)
             throw new NullPointerException("descriptor");
@@ -82,7 +84,7 @@
      *
      * @return a {@linkplain ClassRef} describing an array type
      */
-    @TrackableConstant
+    @Foldable
     default ClassRef array() {
         return ClassRef.ofDescriptor("[" + descriptorString());
     }
@@ -91,14 +93,14 @@
      * Create a {@linkplain ClassRef} describing an inner class of the
      * non-array reference type described by this {@linkplain ClassRef}
      */
-    @TrackableConstant
+    @Foldable
     ClassRef inner(String innerName);
 
     /**
      * Create a {@linkplain ClassRef} describing an inner class of the
      * non-array reference type described by this {@linkplain ClassRef}
      */
-    @TrackableConstant
+    @Foldable
     ClassRef inner(String firstInnerName, String... moreInnerNames);
 
     /**
@@ -128,7 +130,7 @@
      * @throws IllegalStateException if this reference does not describe an array type
      * {@linkplain ClassRef}
      */
-    @TrackableConstant
+    @Foldable
     default ClassRef componentType() {
         if (!isArray())
             throw new IllegalStateException();
@@ -140,4 +142,10 @@
      * @return the canonical name of the type described by this descriptor
      */
     String canonicalName();
+
+    @Override
+    default Optional<? extends SymbolicRef<Class<?>>> toSymbolicRef(MethodHandles.Lookup lookup) {
+        return Optional.of(DynamicConstantRef.<Class<?>>of(SymbolicRefs.BSM_INVOKE)
+                                   .withArgs(SymbolicRefs.MHR_CLASSREF_FACTORY, descriptorString()));
+    }
 }
--- a/src/java.base/share/classes/java/lang/sym/Constable.java	Tue Jan 02 18:05:15 2018 -0500
+++ b/src/java.base/share/classes/java/lang/sym/Constable.java	Thu Jan 04 16:03:09 2018 -0500
@@ -24,16 +24,40 @@
  */
 package java.lang.sym;
 
+import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
 import java.util.Optional;
 
 /**
- * Constable
+ * A type for which at least some instances have a representation in the constant
+ * pool, and which can be described by a {@link SymbolicRef}.
+ * This includes the types that act as their own symbolic references
+ * ({@link String}, {@link Integer}, {@link Long}, {@link Float}, {@link Double}),
+ * types for which explicit constant pool forms exist ({@link Class},
+ * {@link MethodType}, {@link MethodHandle}), types corresponding to core language
+ * features ({@link Enum}), and types which can be represented as dynamic
+ * constants via {@link DynamicConstantRef}.
  */
 public interface Constable<T> {
+    /**
+     * Return a symbolic reference for this instance, if one can be constructed;
+     * this method behaves as a call to {@link #toSymbolicRef(MethodHandles.Lookup)}
+     * made with a parameter of {@code MethodHandles.publicLookup()}
+     *
+     * @return An {@link Optional} describing the resulting symbolic reference,
+     * or an empty {@link Optional} if one cannot be constructed
+     */
     default Optional<? extends SymbolicRef<T>> toSymbolicRef() {
         return toSymbolicRef(MethodHandles.publicLookup());
     }
 
+    /**
+     * Return a symbolic reference for this instance, if one can be constructed.
+     * @param lookup A {@link MethodHandles.Lookup} to be used to perform
+     *               access control determinations
+     * @return An {@link Optional} describing the resulting symbolic reference,
+     * or an empty {@link Optional} if one cannot be constructed
+     */
     Optional<? extends SymbolicRef<T>> toSymbolicRef(MethodHandles.Lookup lookup);
 }
--- a/src/java.base/share/classes/java/lang/sym/DynamicConstantRef.java	Tue Jan 02 18:05:15 2018 -0500
+++ b/src/java.base/share/classes/java/lang/sym/DynamicConstantRef.java	Thu Jan 04 16:03:09 2018 -0500
@@ -24,11 +24,14 @@
  */
 package java.lang.sym;
 
-import java.lang.annotation.TrackableConstant;
+import java.lang.annotation.Foldable;
 import java.lang.invoke.ConstantBootstraps;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+import java.util.Arrays;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
 import java.util.function.Function;
 import java.util.stream.Stream;
 
@@ -72,7 +75,7 @@
      * @param bootstrapArgs the bootstrap arguments
      * @return the descriptor for the dynamic constant
      */
-    @TrackableConstant
+    @Foldable
     public DynamicConstantRef<T> withArgs(SymbolicRef<?>... bootstrapArgs) {
         return new DynamicConstantRef<>(bootstrapMethod, name, type, bootstrapArgs);
     }
@@ -88,7 +91,7 @@
      * @param bootstrapArgs the bootstrap arguments
      * @return the descriptor for the symbolic reference
      */
-    @TrackableConstant
+    @Foldable
     public static<T> SymbolicRef<T> ofCanonical(MethodHandleRef bootstrapMethod, String name, ClassRef type, SymbolicRef<?>[] bootstrapArgs) {
         DynamicConstantRef<T> dcr = new DynamicConstantRef<>(bootstrapMethod, name, type, bootstrapArgs);
         return dcr.canonicalize();
@@ -114,7 +117,7 @@
      * @param bootstrapArgs the bootstrap arguments
      * @return the descriptor for the dynamic constant
      */
-    @TrackableConstant
+    @Foldable
     public static<T> DynamicConstantRef<T> of(MethodHandleRef bootstrapMethod, String name, ClassRef type, SymbolicRef<?>[] bootstrapArgs) {
         return new DynamicConstantRef<>(bootstrapMethod, name, type, bootstrapArgs);
     }
@@ -127,7 +130,7 @@
      * @param type the type of the dynamic constant
      * @return the descriptor for the dynamic constant
      */
-    @TrackableConstant
+    @Foldable
     public static<T> DynamicConstantRef<T> of(MethodHandleRef bootstrapMethod, String name, ClassRef type) {
         return new DynamicConstantRef<>(bootstrapMethod, name, type);
     }
@@ -140,7 +143,7 @@
      * @param type the type of the dynamic constant
      * @return the descriptor for the dynamic constant
      */
-    @TrackableConstant
+    @Foldable
     public static<T> DynamicConstantRef<T> of(MethodHandleRef bootstrapMethod, ClassRef type) {
         return of(bootstrapMethod, "_", type);
     }
@@ -153,7 +156,7 @@
      * @param name the name for the dynamic constant
      * @return the descriptor for the dynamic constant
      */
-    @TrackableConstant
+    @Foldable
     public static<T> DynamicConstantRef<T> of(MethodHandleRef bootstrapMethod, String name) {
         return of(bootstrapMethod, name, bootstrapMethod.type().returnType());
     }
@@ -165,7 +168,7 @@
      * @param bootstrapMethod the bootstrap method
      * @return the descriptor for the dynamic constant
      */
-    @TrackableConstant
+    @Foldable
     public static<T> DynamicConstantRef<T> of(MethodHandleRef bootstrapMethod) {
         return of(bootstrapMethod, "_");
     }
@@ -174,7 +177,7 @@
      * returns the name
      * @return the name
      */
-    @TrackableConstant
+    @Foldable
     public String name() {
         return name;
     }
@@ -183,7 +186,7 @@
      * returns the type
      * @return the type
      */
-    @TrackableConstant
+    @Foldable
     public ClassRef type() {
         return type;
     }
@@ -192,7 +195,7 @@
      * Returns the bootstrap method in the bootstrap specifier
      * @return the bootstrap method in the bootstrap specifier
      */
-    @TrackableConstant
+    @Foldable
     public MethodHandleRef bootstrapMethod() { return bootstrapMethod; }
 
     /**
@@ -238,4 +241,40 @@
             throw new RuntimeException(t);
         }
     }
+
+    @Override
+    public Optional<? extends SymbolicRef<T>> toSymbolicRef(MethodHandles.Lookup lookup) {
+        SymbolicRef<?>[] args = new SymbolicRef<?>[bootstrapArgs.length + 4];
+        args[0] = SymbolicRefs.MHR_DYNAMICCONSTANTREF_FACTORY;
+        args[1] = bootstrapMethod;
+        args[2] = name;
+        args[3] = type;
+        System.arraycopy(bootstrapArgs, 0, args, 4, bootstrapArgs.length);
+        return Optional.of(DynamicConstantRef.<T>of(SymbolicRefs.BSM_INVOKE).withArgs(args));
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        DynamicConstantRef<?> ref = (DynamicConstantRef<?>) o;
+        return Objects.equals(bootstrapMethod, ref.bootstrapMethod) &&
+               Arrays.equals(bootstrapArgs, ref.bootstrapArgs) &&
+               Objects.equals(name, ref.name) &&
+               Objects.equals(type, ref.type);
+    }
+
+    @Override
+    public int hashCode() {
+
+        int result = Objects.hash(bootstrapMethod, name, type);
+        result = 31 * result + Arrays.hashCode(bootstrapArgs);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("DynamicConstantRef[bsm=%s, name=%s, type=%s, args=%s]",
+                             bootstrapMethod, name, type, Arrays.toString(bootstrapArgs));
+    }
 }
--- a/src/java.base/share/classes/java/lang/sym/EnumRef.java	Tue Jan 02 18:05:15 2018 -0500
+++ b/src/java.base/share/classes/java/lang/sym/EnumRef.java	Thu Jan 04 16:03:09 2018 -0500
@@ -24,9 +24,11 @@
  */
 package java.lang.sym;
 
-import java.lang.annotation.TrackableConstant;
+import java.lang.annotation.Foldable;
+import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.util.Objects;
+import java.util.Optional;
 
 /**
  * EnumRef
@@ -43,17 +45,17 @@
         this.constantName = constantName;
     }
 
-    @TrackableConstant
+    @Foldable
     public static<E extends Enum<E>> EnumRef<E> of(ClassRef enumClass, String constantName) {
         return new EnumRef<>(enumClass, constantName);
     }
 
-    @TrackableConstant
+    @Foldable
     public ClassRef enumClass() {
         return enumClass;
     }
 
-    @TrackableConstant
+    @Foldable
     public String constantName() {
         return constantName;
     }
@@ -65,6 +67,15 @@
     }
 
     @Override
+    public Optional<? extends SymbolicRef<E>> toSymbolicRef(MethodHandles.Lookup lookup) {
+        Optional<? extends SymbolicRef<Class<?>>> classRefRef = enumClass.toSymbolicRef(lookup);
+        if (!classRefRef.isPresent())
+            return Optional.empty();
+        return Optional.of(DynamicConstantRef.<E>of(SymbolicRefs.BSM_INVOKE)
+                                   .withArgs(SymbolicRefs.MHR_ENUMREF_FACTORY, classRefRef.get(), constantName));
+    }
+
+    @Override
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
--- a/src/java.base/share/classes/java/lang/sym/MethodHandleRef.java	Tue Jan 02 18:05:15 2018 -0500
+++ b/src/java.base/share/classes/java/lang/sym/MethodHandleRef.java	Thu Jan 04 16:03:09 2018 -0500
@@ -24,11 +24,13 @@
  */
 package java.lang.sym;
 
-import java.lang.annotation.TrackableConstant;
+import java.lang.annotation.Foldable;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandleInfo;
 import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
 import java.util.Objects;
+import java.util.Optional;
 
 import static java.lang.invoke.MethodHandleInfo.REF_getField;
 import static java.lang.invoke.MethodHandleInfo.REF_getStatic;
@@ -39,7 +41,10 @@
 import static java.lang.invoke.MethodHandleInfo.REF_newInvokeSpecial;
 import static java.lang.invoke.MethodHandleInfo.REF_putField;
 import static java.lang.invoke.MethodHandleInfo.REF_putStatic;
+import static java.lang.sym.MethodHandleRef.Kind.CONSTRUCTOR;
 import static java.lang.sym.MethodHandleRef.Kind.STATIC;
+import static java.lang.sym.SymbolicRefs.CR_void;
+import static java.util.Objects.requireNonNull;
 
 /**
  * A descriptor for a {@linkplain MethodHandle} constant.
@@ -56,15 +61,15 @@
      * Kinds of method handle refs
      */
     public enum Kind {
-        @TrackableConstant STATIC(REF_invokeStatic),
-        @TrackableConstant VIRTUAL(REF_invokeVirtual),
-        @TrackableConstant INTERFACE_VIRTUAL(REF_invokeInterface),
-        @TrackableConstant SPECIAL(REF_invokeSpecial),
-        @TrackableConstant CONSTRUCTOR(REF_newInvokeSpecial),
-        @TrackableConstant GETTER(REF_getField),
-        @TrackableConstant SETTER(REF_putField),
-        @TrackableConstant STATIC_GETTER(REF_getStatic),
-        @TrackableConstant STATIC_SETTER(REF_putStatic);
+        @Foldable STATIC(REF_invokeStatic),
+        @Foldable VIRTUAL(REF_invokeVirtual),
+        @Foldable INTERFACE_VIRTUAL(REF_invokeInterface),
+        @Foldable SPECIAL(REF_invokeSpecial),
+        @Foldable CONSTRUCTOR(REF_newInvokeSpecial),
+        @Foldable GETTER(REF_getField),
+        @Foldable SETTER(REF_putField),
+        @Foldable STATIC_GETTER(REF_getStatic),
+        @Foldable STATIC_SETTER(REF_putStatic);
 
         public final int refKind;
 
@@ -79,34 +84,27 @@
     private final MethodTypeRef type;
 
     private MethodHandleRef(Kind kind, ClassRef owner, String name, MethodTypeRef type) {
-        this.kind = kind;
-        this.owner = owner;
-        this.name = name;
-        this.type = type;
+        this.kind = requireNonNull(kind);
+        this.owner = requireNonNull(owner);
+        this.name = requireNonNull(name);
+        this.type = requireNonNull(type);
     }
 
     /**
      * Return a {@code MethodHandleRef} corresponding to an
      * invocation of a static method
-     * @param kind One of: STATIC, VIRTUAL, INTERFACE_VIRTUAL, SPECIAL, CONSTRUCTOR
+     * @param kind The kind of method handle to be described
      * @param clazz the class containing the method
      * @param name the name of the method (ignored if kind=CONSTRUCTOR)
      * @param type the method type of the method
      * @return the {@code MethodHandleRef}
+     * @throws NullPointerException if any of the non-ignored arguments are null
      */
-    @TrackableConstant
+    @Foldable
     public static MethodHandleRef of(Kind kind, ClassRef clazz, String name, MethodTypeRef type) {
-        switch (kind) {
-            case STATIC:
-            case VIRTUAL:
-            case INTERFACE_VIRTUAL:
-            case SPECIAL:
-                return new MethodHandleRef(kind, clazz, name, type);
-            case CONSTRUCTOR:
-                return new MethodHandleRef(kind, clazz, "<init>", type);
-            default:
-                throw new IllegalArgumentException(kind.toString());
-        }
+        if (kind == CONSTRUCTOR)
+            name = "<init>";
+        return new MethodHandleRef(kind, clazz, name, type);
     }
 
     /**
@@ -117,8 +115,9 @@
      * @param name the name of the method (ignored if kind=CONSTRUCTOR)
      * @param descriptorString descriptor string of the method
      * @return the {@code MethodHandleRef}
+     * @throws NullPointerException if any of the non-ignored arguments are null
      */
-    @TrackableConstant
+    @Foldable
     public static MethodHandleRef of(Kind kind, ClassRef clazz, String name, String descriptorString) {
         return of(kind, clazz, name, MethodTypeRef.ofDescriptor(descriptorString));
     }
@@ -132,8 +131,9 @@
      * @param returnType the return type of the method
      * @param paramTypes the parameter types of the method
      * @return the {@code MethodHandleRef}
+     * @throws NullPointerException if any of the non-ignored arguments are null
      */
-    @TrackableConstant
+    @Foldable
     public static MethodHandleRef of(Kind kind, ClassRef clazz, String name, ClassRef returnType, ClassRef... paramTypes) {
         return of(kind, clazz, name, MethodTypeRef.of(returnType, paramTypes));
     }
@@ -146,8 +146,9 @@
      * @param returnType the return type of the method
      * @param paramTypes the parameter types of the method
      * @return the {@code MethodHandleRef}
+     * @throws NullPointerException if any of the arguments are null
      */
-    @TrackableConstant
+    @Foldable
     public static MethodHandleRef ofIndyBootstrap(ClassRef clazz, String name, ClassRef returnType, ClassRef... paramTypes) {
         return of(STATIC, clazz, name, MethodTypeRef.of(returnType, paramTypes).insertParameterTypes(0, INDY_BOOTSTRAP_ARGS));
     }
@@ -160,8 +161,9 @@
      * @param returnType the return type of the method
      * @param paramTypes the parameter types of the method
      * @return the {@code MethodHandleRef}
+     * @throws NullPointerException if any of the arguments are null
      */
-    @TrackableConstant
+    @Foldable
     public static MethodHandleRef ofCondyBootstrap(ClassRef clazz, String name, ClassRef returnType, ClassRef... paramTypes) {
         return of(STATIC, clazz, name, MethodTypeRef.of(returnType, paramTypes).insertParameterTypes(0, CONDY_BOOTSTRAP_ARGS));
     }
@@ -173,18 +175,20 @@
      * @param name the name of the field
      * @param type the type of the field
      * @return the {@code MethodHandleRef}
+     * @throws NullPointerException if any of the arguments are null
      */
-    @TrackableConstant
+    @Foldable
     public static MethodHandleRef ofField(Kind kind, ClassRef clazz, String name, ClassRef type) {
+        MethodTypeRef mtr;
         switch (kind) {
-            case GETTER: return new MethodHandleRef(Kind.GETTER, clazz, name, MethodTypeRef.of(type, clazz));
-            case SETTER:
-                return new MethodHandleRef(Kind.SETTER, clazz, name, MethodTypeRef.of(SymbolicRefs.CR_void, clazz, type));
-            case STATIC_GETTER: return new MethodHandleRef(Kind.STATIC_GETTER, clazz, name, MethodTypeRef.of(type));
-            case STATIC_SETTER:
-                return new MethodHandleRef(Kind.STATIC_SETTER, clazz, name, MethodTypeRef.of(SymbolicRefs.CR_void, type));
-            default: throw new IllegalArgumentException(kind.toString());
+            case GETTER: mtr = MethodTypeRef.of(type, clazz); break;
+            case SETTER: mtr = MethodTypeRef.of(CR_void, clazz, type); break;
+            case STATIC_GETTER: mtr = MethodTypeRef.of(type); break;
+            case STATIC_SETTER: mtr = MethodTypeRef.of(CR_void, type); break;
+            default:
+                throw new IllegalArgumentException(kind.toString());
         }
+        return new MethodHandleRef(kind, clazz, name, mtr);
     }
 
     /**
@@ -194,36 +198,53 @@
      * @throws ReflectiveOperationException exception
      */
     public MethodHandle resolveRef(MethodHandles.Lookup lookup) throws ReflectiveOperationException {
+        Class<?> resolvedOwner = owner.resolveRef(lookup);
+        MethodType resolvedType = this.type.resolveRef(lookup);
         switch (kind) {
-            case STATIC: return lookup.findStatic(owner.resolveRef(lookup), name, type.resolveRef(lookup));
+            case STATIC:
+                return lookup.findStatic(resolvedOwner, name, resolvedType);
             case INTERFACE_VIRTUAL:
             case VIRTUAL:
-                return lookup.findVirtual(owner.resolveRef(lookup), name, type.resolveRef(lookup));
-            case SPECIAL: return lookup.findSpecial(owner.resolveRef(lookup), name, type.resolveRef(lookup), lookup.lookupClass());
-            case CONSTRUCTOR: return lookup.findConstructor(owner.resolveRef(lookup), type.resolveRef(lookup));
-            case GETTER: return lookup.findGetter(owner.resolveRef(lookup), name, type.resolveRef(lookup).returnType());
-            case STATIC_GETTER: return lookup.findStaticGetter(owner.resolveRef(lookup), name, type.resolveRef(lookup).returnType());
-            case SETTER: return lookup.findSetter(owner.resolveRef(lookup), name, type.resolveRef(lookup).parameterType(1));
-            case STATIC_SETTER: return lookup.findStaticSetter(owner.resolveRef(lookup), name, type.resolveRef(lookup).parameterType(0));
-            default: throw new IllegalStateException(kind.name());
+                return lookup.findVirtual(resolvedOwner, name, resolvedType);
+            case SPECIAL:
+                return lookup.findSpecial(resolvedOwner, name, resolvedType, lookup.lookupClass());
+            case CONSTRUCTOR:
+                return lookup.findConstructor(resolvedOwner, resolvedType);
+            case GETTER:
+                return lookup.findGetter(resolvedOwner, name, resolvedType.returnType());
+            case STATIC_GETTER:
+                return lookup.findStaticGetter(resolvedOwner, name, resolvedType.returnType());
+            case SETTER:
+                return lookup.findSetter(resolvedOwner, name, resolvedType.parameterType(1));
+            case STATIC_SETTER:
+                return lookup.findStaticSetter(resolvedOwner, name, resolvedType.parameterType(0));
+            default:
+                throw new IllegalStateException(kind.name());
         }
     }
 
     /**
      * Return the {@code refKind} of the method handle described by this descriptor,
      * as defined by {@link MethodHandleInfo}
-     * @return the reference kind
+     * @return the {@link MethodHandle} reference kind
      */
-    @TrackableConstant
+    @Foldable
     public int refKind() { return kind.refKind; }
 
     /**
+     * Return the {@code kind} of the method handle described by this descriptor
+     * @return the {@link Kind}
+     */
+    @Foldable
+    public Kind kind() { return kind; }
+
+    /**
      * Return the class in which the method described by this descriptor is
      * declared
      *
      * @return the class in which the method is declared
      */
-    @TrackableConstant
+    @Foldable
     public ClassRef owner() {
         return owner;
     }
@@ -232,7 +253,7 @@
      * Return the name of the method described by this descriptor
      * @return the name of the method
      */
-    @TrackableConstant
+    @Foldable
     public String name() {
         return name;
     }
@@ -241,12 +262,23 @@
      * Return the method type of the method described by this descriptor
      * @return the method type
      */
-    @TrackableConstant
+    @Foldable
     public MethodTypeRef type() {
         return type;
     }
 
     @Override
+    public Optional<? extends SymbolicRef<MethodHandle>> toSymbolicRef(MethodHandles.Lookup lookup) {
+        Optional<EnumRef<Kind>> kindRef = kind.toSymbolicRef(lookup);
+        Optional<? extends SymbolicRef<Class<?>>> classRefRef = owner.toSymbolicRef(lookup);
+        Optional<? extends SymbolicRef<MethodType>> typeRefRef = type.toSymbolicRef(lookup);
+        if (!kindRef.isPresent() || !classRefRef.isPresent() || !typeRefRef.isPresent())
+            return Optional.empty();
+        return Optional.of(DynamicConstantRef.<MethodHandle>of(SymbolicRefs.BSM_INVOKE)
+                                   .withArgs(SymbolicRefs.MHR_METHODHANDLEREF_FACTORY, kindRef.get(), classRefRef.get(), name, typeRefRef.get()));
+    }
+
+    @Override
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
--- a/src/java.base/share/classes/java/lang/sym/MethodTypeRef.java	Tue Jan 02 18:05:15 2018 -0500
+++ b/src/java.base/share/classes/java/lang/sym/MethodTypeRef.java	Thu Jan 04 16:03:09 2018 -0500
@@ -24,12 +24,13 @@
  */
 package java.lang.sym;
 
-import java.lang.annotation.TrackableConstant;
+import java.lang.annotation.Foldable;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Optional;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -60,7 +61,7 @@
      * @throws IllegalArgumentException if the descriptor string does not
      * describe a valid method descriptor
      */
-    @TrackableConstant
+    @Foldable
     public static MethodTypeRef ofDescriptor(String descriptor) {
         Matcher matcher = pattern.matcher(descriptor);
         if (!matcher.matches())
@@ -90,7 +91,7 @@
      * @param paramDescriptors {@linkplain ClassRef}s describing the argument types type
      * @return a {@linkplain MethodTypeRef} describing the desired method type
      */
-    @TrackableConstant
+    @Foldable
     public static MethodTypeRef of(ClassRef returnDescriptor, ClassRef... paramDescriptors) {
         return new MethodTypeRef(returnDescriptor, paramDescriptors);
     }
@@ -99,7 +100,7 @@
      * Get the return type of the method type described by this {@linkplain MethodTypeRef}
      * @return the return type
      */
-    @TrackableConstant
+    @Foldable
     public ClassRef returnType() {
         return returnType;
     }
@@ -109,7 +110,7 @@
      * this {@linkplain MethodTypeRef}
      * @return the number of parameters
      */
-    @TrackableConstant
+    @Foldable
     public int parameterCount() {
         return argTypes.length;
     }
@@ -123,7 +124,7 @@
      * @throws IndexOutOfBoundsException if the index is outside the half-open
      * range {[0, parameterCount)}
      */
-    @TrackableConstant
+    @Foldable
     public ClassRef parameterType(int index) {
         return argTypes[index];
     }
@@ -133,7 +134,7 @@
      *
      * @return the parameter types
      */
-    @TrackableConstant
+    @Foldable
     public List<ClassRef> parameterList() {
         return Arrays.asList(argTypes);
     }
@@ -143,7 +144,7 @@
      *
      * @return the parameter types
      */
-    @TrackableConstant
+    @Foldable
     public ClassRef[] parameterArray() {
         return argTypes.clone();
     }
@@ -154,7 +155,7 @@
      * @param returnType the new return type
      * @return the new method type descriptor
      */
-    @TrackableConstant
+    @Foldable
     public MethodTypeRef changeReturnType(ClassRef returnType) {
         return of(returnType, argTypes);
     }
@@ -169,7 +170,7 @@
      * @throws IndexOutOfBoundsException if the index is outside the half-open
      * range {[0, parameterCount)}
      */
-    @TrackableConstant
+    @Foldable
     public MethodTypeRef changeParameterType(int index, ClassRef paramType) {
         ClassRef[] newArgs = argTypes.clone();
         newArgs[index] = paramType;
@@ -186,7 +187,7 @@
      * range {[0, parameterCount)}, or {@code end} is outside the closed range
      * {@code [0, parameterCount]}
      */
-    @TrackableConstant
+    @Foldable
     public MethodTypeRef dropParameterTypes(int start, int end) {
         if (start < 0 || start >= argTypes.length || end < 0 || end > argTypes.length)
             throw new IndexOutOfBoundsException();
@@ -207,7 +208,7 @@
      * @throws IndexOutOfBoundsException if {@code pos} is outside the closed-open
      * range {[0, parameterCount]}
      */
-    @TrackableConstant
+    @Foldable
     public MethodTypeRef insertParameterTypes(int pos, ClassRef... paramTypes) {
         if (pos < 0 || pos > argTypes.length)
             throw new IndexOutOfBoundsException(pos);
@@ -229,6 +230,12 @@
     }
 
     @Override
+    public Optional<? extends SymbolicRef<MethodType>> toSymbolicRef(MethodHandles.Lookup lookup) {
+        return Optional.of(DynamicConstantRef.<MethodType>of(SymbolicRefs.BSM_INVOKE)
+                                   .withArgs(SymbolicRefs.MHR_METHODTYPEREF_FACTORY, descriptorString()));
+    }
+
+    @Override
     public String descriptorString() {
         return String.format("(%s)%s",
                              Stream.of(argTypes)
--- a/src/java.base/share/classes/java/lang/sym/NamedClassRef.java	Tue Jan 02 18:05:15 2018 -0500
+++ b/src/java.base/share/classes/java/lang/sym/NamedClassRef.java	Thu Jan 04 16:03:09 2018 -0500
@@ -24,16 +24,13 @@
  */
 package java.lang.sym;
 
-import java.lang.annotation.TrackableConstant;
-import java.lang.invoke.ConstantBootstraps;
+import java.lang.annotation.Foldable;
 import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Array;
 import java.util.Objects;
 import java.util.regex.Pattern;
 import java.util.stream.Stream;
 
-import sun.invoke.util.Wrapper;
-
 import static java.util.stream.Collectors.joining;
 
 /**
@@ -57,7 +54,7 @@
      * Create a {@linkplain ClassRef} describing an inner class of the
      * non-array reference type described by this {@linkplain ClassRef}
      */
-    @TrackableConstant
+    @Foldable
     public ClassRef inner(String innerName) {
         if (!descriptor.startsWith("L"))
             throw new IllegalStateException("Outer class is not a non-array reference type");
@@ -68,7 +65,7 @@
      * Create a {@linkplain ClassRef} describing an inner class of the
      * non-array reference type described by this {@linkplain ClassRef}
      */
-    @TrackableConstant
+    @Foldable
     public ClassRef inner(String firstInnerName, String... moreInnerNames) {
         if (!descriptor.startsWith("L"))
             throw new IllegalStateException("Outer class is not a non-array reference type");
@@ -79,7 +76,7 @@
     }
 
     @Override
-    @TrackableConstant
+    @Foldable
     public String descriptorString() {
         return descriptor;
     }
--- a/src/java.base/share/classes/java/lang/sym/PrimitiveClassRef.java	Tue Jan 02 18:05:15 2018 -0500
+++ b/src/java.base/share/classes/java/lang/sym/PrimitiveClassRef.java	Thu Jan 04 16:03:09 2018 -0500
@@ -24,8 +24,7 @@
  */
 package java.lang.sym;
 
-import java.lang.annotation.TrackableConstant;
-import java.lang.invoke.DynamicConstant;
+import java.lang.annotation.Foldable;
 import java.lang.invoke.MethodHandles;
 import java.util.Objects;
 
@@ -58,7 +57,7 @@
     }
 
     @Override
-    @TrackableConstant
+    @Foldable
     public String descriptorString() {
         return descriptor;
     }
--- a/src/java.base/share/classes/java/lang/sym/SymbolicRef.java	Tue Jan 02 18:05:15 2018 -0500
+++ b/src/java.base/share/classes/java/lang/sym/SymbolicRef.java	Thu Jan 04 16:03:09 2018 -0500
@@ -24,7 +24,7 @@
  */
 package java.lang.sym;
 
-import java.lang.annotation.TrackableConstant;
+import java.lang.annotation.Foldable;
 import java.lang.invoke.Intrinsics;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -33,40 +33,75 @@
 import java.util.Optional;
 
 /**
- * Purely-nominal descriptor for a constant value expressible in a classfile
- * constant pool.
+ * A purely-nominal descriptor for a constant value expressible in a classfile
+ * constant pool, or other classfile structures.
  *
  * <p> Native constant types that don't require linkage ({@link String}, {@link
  * Integer}, {@link Long}, {@link Float}, and {@link Double}) implement
- * {@linkplain SymbolicRef} directly. Native linkable constant types ({@link
- * Class}, {@link MethodType}, and {@link MethodHandle}) are represented as
- * {@linkplain SymbolicRef} via the symbolic reference classes {@link ClassRef},
+ * {@linkplain SymbolicRef.OfSelf}, indicating that they serve as their own
+ * symbolic reference. Native linkable constant types ({@link
+ * Class}, {@link MethodType}, and {@link MethodHandle}) have counterpart
+ * {@linkplain SymbolicRef} types, such as {@link ClassRef},
  * {@link MethodTypeRef}, and {@link MethodHandleRef}.  Dynamic constants are
  * represented by the symbolic reference type {@link DynamicConstantRef}.
  *
- * <p>APIs that deal in generation or parsing of bytecode should use
+ * <p>APIs that deal in generation or parsing of bytecode are encouraged to use
  * {@linkplain SymbolicRef} to describe the operand of an {@code LDC} instruction,
- * including dynamic constants, and the static argument lists of
- * {@code invokedynamic} instructions.  The {@linkplain SymbolicRef} types are also
- * used by the {@link Intrinsics} API to express {@code LDC} and
- * {@code invokedynamic} instructions.
+ * including dynamic constants, the static argument lists of
+ * {@code invokedynamic} instructions, and other bytecodes or classfile structures
+ * that make use of the constant pool (such as describing the supertypes of a class,
+ * or the types of a field.
+ *
+ * <p>The {@linkplain SymbolicRef} types are also used by the {@link Intrinsics}
+ * API to express {@code LDC} and {@code invokedynamic} instructions.
  *
  * <p> Like names in the constant pool, names in a {@linkplain SymbolicRef} are
  * independent of a class loader.  When a {@linkplain SymbolicRef} is
  * intrinsified, it is interpreted relative to the class loader that loaded the
  * class in which the intrinsic appears (just like names that appear in that
- * classes constant pool.)
+ * classes constant pool.)  Symbolic references can be reflectively resolved
+ * via {@link SymbolicRef#resolveRef(MethodHandles.Lookup)}.
+ *
+ * <p>Constants describing various useful symbolic references (such as {@link ClassRef}
+ * for platform classes) can be found in {@link SymbolicRefs}.
+ *
+ * <p>Non-platform classes should not implement {@linkplain SymbolicRef} directly.
+ * Instead, they should extend {@link DynamicConstantRef}.
+ *
+ * @apiNote In the future, if the Java language permits, {@linkplain SymbolicRef}
+ * may become a {@code sealed} interface, which would prohibit subclassing except by
+ * explicitly permitted types.
  *
  * @param <T> The type of the object which this {@linkplain SymbolicRef}
  *            describes
  * @see Intrinsics
- * @see TrackableConstant
+ * @see SymbolicRefs
  */
 public interface SymbolicRef<T> {
 
+    /**
+     * Resolve this symbolic reference reflectively.
+     * @param lookup The {@link MethodHandles.Lookup} to be used in resolution
+     * @return The resolved object
+     * @throws ReflectiveOperationException if this symbolic reference refers
+     * (directly or indirectly) to a class, method, or field that cannot be
+     * resolved
+     */
     T resolveRef(MethodHandles.Lookup lookup) throws ReflectiveOperationException;
 
     /**
+     *  Returns a symbolic reference that resolves to this symbolic reference.
+     *
+     *  @apiNote
+     *  For self-describing constants such as {@link String}, this returns
+     *  itself; for most other types, will return a {@link DynamicConstantRef}.
+     *
+     * @param lookup {@link MethodHandles.Lookup}
+     * @return the symbolic reference
+     */
+    Optional<? extends SymbolicRef<T>> toSymbolicRef(MethodHandles.Lookup lookup);
+
+    /**
      * Construct a VarHandle for an instance field
      * @param owner the class containing the field
      * @param name the field name
@@ -109,14 +144,12 @@
          *
          * @return the descriptor string
          */
-        @TrackableConstant
+        @Foldable
         String descriptorString();
     }
 
     /**
-     * SelfRef
-     *
-     * @author Brian Goetz
+     * An object that serves as its own symbolic reference.
      */
     interface OfSelf<T extends SymbolicRef<T>> extends SymbolicRef<T>, Constable<T> {
         @Override
--- a/src/java.base/share/classes/java/lang/sym/SymbolicRefs.java	Tue Jan 02 18:05:15 2018 -0500
+++ b/src/java.base/share/classes/java/lang/sym/SymbolicRefs.java	Thu Jan 04 16:03:09 2018 -0500
@@ -24,173 +24,231 @@
  */
 package java.lang.sym;
 
-import java.lang.annotation.TrackableConstant;
+import java.lang.annotation.Foldable;
 
 /**
- * SymbolicRefs
- *
- * @author Brian Goetz
+ * Predefined constants for common symbolic references, including class references
+ * for primitive types and common platform types, and method handle references
+ * for standard bootstrap methods.
  */
 public final class SymbolicRefs {
     // Warning -- don't change the order of these declarations!
 
     /**  ClassRef representing the class java.lang.Object */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Object = ClassRef.of("java.lang.Object");
 
     /**  ClassRef representing the class java.lang.String */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_String = ClassRef.of("java.lang.String");
 
     /**  ClassRef representing the class java.lang.Class */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Class = ClassRef.of("java.lang.Class");
 
     /**  ClassRef representing the class java.lang.Number */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Number = ClassRef.of("java.lang.Number");
 
     /**  ClassRef representing the class java.lang.Integer */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Integer = ClassRef.of("java.lang.Integer");
 
     /**  ClassRef representing the class java.lang.Long */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Long = ClassRef.of("java.lang.Long");
 
     /**  ClassRef representing the class java.lang.Float */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Float = ClassRef.of("java.lang.Float");
 
     /**  ClassRef representing the class java.lang.Double */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Double = ClassRef.of("java.lang.Double");
 
     /**  ClassRef representing the class java.lang.Short */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Short = ClassRef.of("java.lang.Short");
 
     /**  ClassRef representing the class java.lang.Byte */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Byte = ClassRef.of("java.lang.Byte");
 
     /**  ClassRef representing the class java.lang.Character */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Character = ClassRef.of("java.lang.Character");
 
     /**  ClassRef representing the class java.lang.Boolean */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Boolean = ClassRef.of("java.lang.Boolean");
 
     /**  ClassRef representing the class java.lang.Void */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Void = ClassRef.of("java.lang.Void");
 
     /**  ClassRef representing the class java.lang.Throwable */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Throwable = ClassRef.of("java.lang.Throwable");
 
     /**  ClassRef representing the class java.lang.Exception */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Exception = ClassRef.of("java.lang.Exception");
 
     /**  ClassRef representing the class java.lang.Enum */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Enum = ClassRef.of("java.lang.Enum");
 
     /**  ClassRef representing the class java.lang.invoke.VarHandle */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_VarHandle = ClassRef.of("java.lang.invoke.VarHandle");
 
     /**  ClassRef representing the class java.lang.invoke.MethodHandles */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_MethodHandles = ClassRef.of("java.lang.invoke.MethodHandles");
 
     /**  ClassRef representing the class java.lang.invoke.MethodHandles.Lookup */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Lookup = CR_MethodHandles.inner("Lookup");
 
     /**  ClassRef representing the class java.lang.invoke.MethodHandle */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_MethodHandle = ClassRef.of("java.lang.invoke.MethodHandle");
 
     /**  ClassRef representing the class java.lang.invoke.MethodType */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_MethodType = ClassRef.of("java.lang.invoke.MethodType");
 
     /**  ClassRef representing the class java.lang.invoke.CallSite */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_CallSite = ClassRef.of("java.lang.invoke.CallSite");
 
     /**  ClassRef representing the interface java.util.Collection */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Collection = ClassRef.of("java.util.Collection");
 
     /**  ClassRef representing the interface java.util.List */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_List = ClassRef.of("java.util.List");
 
     /**  ClassRef representing the interface java.util.Set */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Set = ClassRef.of("java.util.Set");
 
     /**  ClassRef representing the interface java.util.Map */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_Map = ClassRef.of("java.util.Map");
 
+    @Foldable
+    static final ClassRef CR_SymbolicRef = ClassRef.of("java.lang.sym.SymbolicRef");
+
+    @Foldable
+    static final ClassRef CR_ClassRef = ClassRef.of("java.lang.sym.ClassRef");
+
+    @Foldable
+    static final ClassRef CR_EnumRef = ClassRef.of("java.lang.sym.EnumRef");
+
+    @Foldable
+    static final ClassRef CR_MethodTypeRef = ClassRef.of("java.lang.sym.MethodTypeRef");
+
+    @Foldable
+    static final ClassRef CR_MethodHandleRef = ClassRef.of("java.lang.sym.MethodHandleRef");
+
+    @Foldable
+    static final ClassRef CR_MethodHandleRef_Kind = CR_MethodHandleRef.inner("Kind");
+
+    @Foldable
+    static final ClassRef CR_DynamicConstantRef = ClassRef.of("java.lang.sym.DynamicConstantRef");
+
+    @Foldable
     static final ClassRef CR_ConstantBootstraps = ClassRef.of("java.lang.invoke.ConstantBootstraps");
 
+    @Foldable
     static final MethodHandleRef BSM_PRIMITIVE_CLASS
             = MethodHandleRef.ofCondyBootstrap(CR_ConstantBootstraps, "primitiveClass", CR_Class);
+
+    @Foldable
     static final MethodHandleRef BSM_ENUM_CONSTANT
             = MethodHandleRef.ofCondyBootstrap(CR_ConstantBootstraps, "enumConstant", CR_Enum);
+
+    @Foldable
     static final MethodHandleRef BSM_NULL_CONSTANT
             = MethodHandleRef.ofCondyBootstrap(CR_ConstantBootstraps, "nullConstant", SymbolicRefs.CR_Object);
 
+    @Foldable
     static final MethodHandleRef BSM_VARHANDLE_FIELD
             = MethodHandleRef.ofCondyBootstrap(CR_ConstantBootstraps, "fieldVarHandle", CR_VarHandle, CR_Class, CR_Class);
+
+    @Foldable
     static final MethodHandleRef BSM_VARHANDLE_STATIC_FIELD
             = MethodHandleRef.ofCondyBootstrap(CR_ConstantBootstraps, "staticFieldVarHandle", CR_VarHandle, CR_Class, CR_Class);
+
+    @Foldable
     static final MethodHandleRef BSM_VARHANDLE_ARRAY
             = MethodHandleRef.ofCondyBootstrap(CR_ConstantBootstraps, "arrayVarHandle", CR_VarHandle, CR_Class);
 
+    @Foldable
+    static final MethodHandleRef BSM_INVOKE
+            = MethodHandleRef.ofCondyBootstrap(CR_ConstantBootstraps, "invoke", CR_Object, CR_MethodHandle, CR_Object.array());
+
     /**  ClassRef representing the primitive type int */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_int = ClassRef.ofDescriptor("I");
 
     /**  ClassRef representing the primitive type long */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_long = ClassRef.ofDescriptor("J");
 
     /**  ClassRef representing the primitive type float */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_float = ClassRef.ofDescriptor("F");
 
     /**  ClassRef representing the primitive type double */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_double = ClassRef.ofDescriptor("D");
 
     /**  ClassRef representing the primitive type short */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_short = ClassRef.ofDescriptor("S");
 
     /**  ClassRef representing the primitive type byte */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_byte = ClassRef.ofDescriptor("B");
 
     /**  ClassRef representing the primitive type char */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_char = ClassRef.ofDescriptor("C");
 
     /**  ClassRef representing the primitive type boolean */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_boolean = ClassRef.ofDescriptor("Z");
 
     /**  ClassRef representing the void type */
-    @TrackableConstant
+    @Foldable
     public static final ClassRef CR_void = ClassRef.ofDescriptor("V");
 
     /** Symbolic reference representing null */
-    @TrackableConstant
+    @Foldable
     public static final SymbolicRef<?> NULL = DynamicConstantRef.of(SymbolicRefs.BSM_NULL_CONSTANT, SymbolicRefs.CR_Object);
+
+    @Foldable
+    static final MethodHandleRef MHR_CLASSREF_FACTORY
+            = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, CR_ClassRef, "ofDescriptor", CR_ClassRef, CR_String);
+
+    @Foldable
+    static final MethodHandleRef MHR_ENUMREF_FACTORY
+            = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, CR_EnumRef, "of", CR_EnumRef, CR_ClassRef, CR_String);
+
+    @Foldable
+    static final MethodHandleRef MHR_METHODTYPEREF_FACTORY
+            = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, CR_MethodTypeRef, "ofDescriptor", CR_MethodTypeRef, CR_String);
+
+    @Foldable
+    static final MethodHandleRef MHR_METHODHANDLEREF_FACTORY
+            = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, CR_MethodHandleRef, "of",
+                                 CR_MethodHandleRef, CR_MethodHandleRef_Kind, CR_ClassRef, CR_String, CR_MethodTypeRef);
+
+    @Foldable
+    static final MethodHandleRef MHR_DYNAMICCONSTANTREF_FACTORY
+            = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, CR_DynamicConstantRef, "of",
+                                 CR_DynamicConstantRef, CR_MethodHandleRef, CR_String, CR_ClassRef, CR_SymbolicRef.array());
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Tue Jan 02 18:05:15 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Thu Jan 04 16:03:09 2018 -0500
@@ -501,7 +501,7 @@
         dynamicConstantRefType = enterClass("java.lang.sym.DynamicConstantRef");
         intrinsicsType = enterClass("java.lang.invoke.Intrinsics");
         methodTypeType = enterClass("java.lang.invoke.MethodType");
-        trackableConstantType = enterClass("java.lang.annotation.TrackableConstant");
+        trackableConstantType = enterClass("java.lang.annotation.Foldable");
         errorType = enterClass("java.lang.Error");
         illegalArgumentExceptionType = enterClass("java.lang.IllegalArgumentException");
         interruptedExceptionType = enterClass("java.lang.InterruptedException");
--- a/test/jdk/java/lang/invoke/ConstablesTest.java	Tue Jan 02 18:05:15 2018 -0500
+++ b/test/jdk/java/lang/invoke/ConstablesTest.java	Thu Jan 04 16:03:09 2018 -0500
@@ -64,359 +64,6 @@
 
     public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
 
-    enum Primitives {
-        INT("I", "int", int.class, int[].class, SymbolicRefs.CR_int),
-        LONG("J", "long", long.class, long[].class, SymbolicRefs.CR_long),
-        SHORT("S", "short", short.class, short[].class, SymbolicRefs.CR_short),
-        BYTE("B", "byte", byte.class, byte[].class, SymbolicRefs.CR_byte),
-        CHAR("C", "char", char.class, char[].class, SymbolicRefs.CR_char),
-        FLOAT("F", "float", float.class, float[].class, SymbolicRefs.CR_float),
-        DOUBLE("D", "double", double.class, double[].class, SymbolicRefs.CR_double),
-        BOOLEAN("Z", "boolean", boolean.class, boolean[].class, SymbolicRefs.CR_boolean),
-        VOID("V", "void", void.class, null, SymbolicRefs.CR_void);
-
-        public final String descriptor;
-        public final String name;
-        public final Class<?> clazz;
-        public final Class<?> arrayClass;
-        public final ClassRef classRef;
-
-        Primitives(String descriptor, String name, Class<?> clazz, Class<?> arrayClass, ClassRef ref) {
-            this.descriptor = descriptor;
-            this.name = name;
-            this.clazz = clazz;
-            this.arrayClass = arrayClass;
-            classRef = ref;
-        }
-    }
-
-    static List<String> someRefs = List.of("Ljava/lang/String;", "Ljava/util/List;");
-    static String[] basicDescs = Stream.concat(Stream.of(Primitives.values()).filter(p -> p != Primitives.VOID).map(p -> p.descriptor),
-                                               someRefs.stream())
-                                       .toArray(String[]::new);
-    static String[] paramDescs = Stream.of(basicDescs).flatMap(d -> Stream.of(d, "[" + d))
-                                       .toArray(String[]::new);
-    static String[] returnDescs = Stream.concat(Stream.of(paramDescs), Stream.of("V")).toArray(String[]::new);
-
-
-    public void testPrimitiveClassRef() throws ReflectiveOperationException {
-        for (Primitives p : Primitives.values()) {
-            ClassRef c1 = ClassRef.ofDescriptor(p.descriptor);
-            ClassRef c2 = p.classRef;
-            ClassRef c3 = p.clazz.toSymbolicRef().get();
-            List<ClassRef> refs = List.of(c1, c2, c3);
-            for (ClassRef c : refs) {
-                assertTrue(c.isPrimitive());
-                assertEquals(p.descriptor, c.descriptorString());
-                assertEquals(p.name, c.canonicalName());
-                assertEquals(c.resolveRef(LOOKUP), p.clazz);
-                for (ClassRef cc : refs)
-                    assertEquals(c, cc);
-                if (p != Primitives.VOID)
-                    assertEquals(c.array().resolveRef(LOOKUP), p.arrayClass);
-            }
-
-            for (Primitives other : Primitives.values()) {
-                ClassRef otherDescr = ClassRef.ofDescriptor(other.descriptor);
-                if (p != other)
-                    assertNotEquals(c1, otherDescr);
-                else
-                    assertEquals(c1, otherDescr);
-            }
-        }
-    }
-
-    public void testSimpleClassRef() throws ReflectiveOperationException {
-        String desc = "Ljava/lang/String;";
-        Class<?> clazz = String.class;
-        ClassRef ref1 = ClassRef.ofDescriptor(desc);
-        ClassRef ref2 = ClassRef.of("java.lang", "String");
-        ClassRef ref3 = ClassRef.of("java.lang.String");
-        ClassRef ref4 = clazz.toSymbolicRef(LOOKUP).get();
-
-        List<ClassRef> refs = Arrays.asList(ref1, ref2, ref3, ref4);
-
-        refs.forEach(s -> assertFalse(s.isPrimitive()));
-        refs.forEach(s -> assertEquals(desc, s.descriptorString()));
-        refs.forEach(s -> assertEquals("java.lang.String", s.canonicalName()));
-        for (ClassRef r : refs)
-            assertEquals(r.resolveRef(LOOKUP), String.class);
-
-        assertEquals(ref1, ref2);
-        assertEquals(ref2, ref3);
-        assertEquals(ref3, ref4);
-        assertEquals(ref4, ref1);
-
-        ClassRef thisClassRef = ClassRef.ofDescriptor("LConstablesTest;");
-        assertEquals(thisClassRef, ClassRef.of("", "ConstablesTest"));
-        assertEquals(thisClassRef, ClassRef.of("ConstablesTest"));
-        assertEquals(thisClassRef.canonicalName(), "ConstablesTest");
-
-    }
-
-    public void testArrayClassRef() throws ReflectiveOperationException {
-        for (String d : basicDescs) {
-            ClassRef a0 = ClassRef.ofDescriptor(d);
-            ClassRef a1 = a0.array();
-            ClassRef a2 = a1.array();
-
-            assertFalse(a0.isArray());
-            assertTrue(a1.isArray());
-            assertTrue(a2.isArray());
-            assertFalse(a1.isPrimitive());
-            assertFalse(a2.isPrimitive());
-            assertEquals(a0.descriptorString(), d);
-            assertEquals(a1.descriptorString(), "[" + a0.descriptorString());
-            assertEquals(a2.descriptorString(), "[[" + a0.descriptorString());
-
-            try {
-                assertEquals(a0, a0.componentType());
-                fail("Didn't throw ISE");
-            }
-            catch (IllegalStateException expected) {
-                // succeed
-            }
-            assertEquals(a0, a1.componentType());
-            assertEquals(a1, a2.componentType());
-
-            assertNotEquals(a0, a1);
-            assertNotEquals(a1, a2);
-
-            assertEquals(a1, ClassRef.ofDescriptor("[" + d));
-            assertEquals(a2, ClassRef.ofDescriptor("[[" + d));
-            assertEquals(classToDescriptor(a0.resolveRef(LOOKUP)), a0.descriptorString());
-            assertEquals(classToDescriptor(a1.resolveRef(LOOKUP)), a1.descriptorString());
-            assertEquals(classToDescriptor(a2.resolveRef(LOOKUP)), a2.descriptorString());
-        }
-    }
-
-    public void testBadClassRefs() {
-        List<String> badDescriptors = List.of("II", "I;", "Q", "L",
-                                              "java.lang.String", "[]", "Ljava/lang/String",
-                                              "Ljava.lang.String;", "java/lang/String");
-
-        for (String d : badDescriptors) {
-            try {
-                ClassRef constant = ClassRef.ofDescriptor(d);
-                fail(d);
-            }
-            catch (IllegalArgumentException e) {
-                // good
-            }
-        }
-    }
-
-    private void assertMethodType(String returnDesc,
-                                  String... paramDescs) throws ReflectiveOperationException {
-        String descriptor = Stream.of(paramDescs).collect(joining("", "(", ")")) + returnDesc;
-        ClassRef ret = ClassRef.ofDescriptor(returnDesc);
-        ClassRef[] params = Stream.of(paramDescs).map(ClassRef::ofDescriptor).toArray(ClassRef[]::new);
-
-        MethodTypeRef mtRef = MethodTypeRef.of(ret, params);
-        MethodType mt = mtRef.resolveRef(LOOKUP);
-
-        assertEquals(mtRef, MethodTypeRef.ofDescriptor(descriptor));
-        assertEquals(mt.toMethodDescriptorString(), descriptor);
-
-        assertEquals(descriptor, mtRef.descriptorString());
-        assertEquals(returnDesc, mtRef.returnType().descriptorString());
-        assertEquals(paramDescs.length, mtRef.parameterCount());
-        for (int i=0; i<paramDescs.length; i++) {
-            assertEquals(params[i], mtRef.parameterType(i));
-            assertEquals(paramDescs[i], mtRef.parameterType(i).descriptorString());
-        }
-
-        // changeReturnType
-        for (String r : returnDescs) {
-            ClassRef rc = ClassRef.ofDescriptor(r);
-            MethodTypeRef newRef = mtRef.changeReturnType(rc);
-            MethodType newMT = mt.changeReturnType(rc.resolveRef(LOOKUP));
-            assertEquals(newRef, MethodTypeRef.of(rc, params));
-            assertEquals(newMT.toMethodDescriptorString(), newRef.descriptorString());
-            assertEquals(newMT.toSymbolicRef(LOOKUP).get(), newRef);
-        }
-
-        // changeParamType
-        for (int i=0; i<paramDescs.length; i++) {
-            for (String p : paramDescs) {
-                ClassRef pc = ClassRef.ofDescriptor(p);
-                ClassRef[] ps = params.clone();
-                ps[i] = pc;
-                MethodTypeRef newRef = mtRef.changeParameterType(i, pc);
-                assertEquals(newRef, MethodTypeRef.of(ret, ps));
-                MethodType newMT = mt.changeParameterType(i, pc.resolveRef(LOOKUP));
-                assertEquals(newMT.toMethodDescriptorString(), newRef.descriptorString());
-                assertEquals(newMT.toSymbolicRef(LOOKUP).get(), newRef);
-            }
-        }
-
-        // dropParamType
-        for (int i=0; i<paramDescs.length; i++) {
-            int k = i;
-            ClassRef[] ps = IntStream.range(0, paramDescs.length)
-                                     .filter(j -> j != k)
-                                     .mapToObj(j -> params[j])
-                                     .toArray(ClassRef[]::new);
-            MethodTypeRef newRef = mtRef.dropParameterTypes(i, i + 1);
-            assertEquals(newRef, MethodTypeRef.of(ret, ps));
-            MethodType newMT = mt.dropParameterTypes(i, i + 1);
-            assertEquals(newMT.toMethodDescriptorString(), newRef.descriptorString());
-            assertEquals(newMT.toSymbolicRef(LOOKUP).get(), newRef);
-        }
-
-        // addParam
-        for (int i=0; i <= paramDescs.length; i++) {
-            for (String p : paramDescs) {
-                int k = i;
-                ClassRef pc = ClassRef.ofDescriptor(p);
-                ClassRef[] ps = IntStream.range(0, paramDescs.length + 1)
-                                         .mapToObj(j -> (j < k) ? params[j] : (j == k) ? pc : params[j-1])
-                                         .toArray(ClassRef[]::new);
-                MethodTypeRef newRef = mtRef.insertParameterTypes(i, pc);
-                MethodType newMT = mt.insertParameterTypes(i, pc.resolveRef(LOOKUP));
-                assertEquals(newRef, MethodTypeRef.of(ret, ps));
-                assertEquals(newMT.toMethodDescriptorString(), newRef.descriptorString());
-                assertEquals(newMT.toSymbolicRef(LOOKUP).get(), newRef);
-            }
-        }
-    }
-
-    public void testMethodTypeRef() throws ReflectiveOperationException {
-        for (String r : returnDescs) {
-            assertMethodType(r);
-            for (String p1 : paramDescs) {
-                assertMethodType(r, p1);
-                for (String p2 : paramDescs) {
-                    assertMethodType(r, p1, p2);
-                }
-            }
-        }
-    }
-
-    public void testMethodHandleRef() throws Throwable {
-        ClassRef thisClass = ClassRef.of("ConstablesTest");
-        ClassRef testClass = thisClass.inner("TestClass");
-        ClassRef testInterface = thisClass.inner("TestInterface");
-        ClassRef testSuperclass = thisClass.inner("TestSuperclass");
-
-        MethodHandleRef ctorRef = MethodHandleRef.of(MethodHandleRef.Kind.CONSTRUCTOR, testClass, "<ignored!>", MethodTypeRef.ofDescriptor("()V"));
-        MethodHandleRef staticMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testClass, "sm", "(I)I");
-        MethodHandleRef staticIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testInterface, "sm", "(I)I");
-        MethodHandleRef instanceMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.VIRTUAL, testClass, "m", MethodTypeRef.ofDescriptor("(I)I"));
-        MethodHandleRef instanceIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.INTERFACE_VIRTUAL, testInterface, "m", MethodTypeRef.ofDescriptor("(I)I"));
-        MethodHandleRef superMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testSuperclass, "m", "(I)I");
-        MethodHandleRef superIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testInterface, "m", "(I)I");
-        MethodHandleRef privateMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testClass, "pm", MethodTypeRef.ofDescriptor("(I)I"));
-        MethodHandleRef privateIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testInterface, "pm", MethodTypeRef.ofDescriptor("(I)I"));
-        MethodHandleRef privateStaticMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testClass, "psm", MethodTypeRef.ofDescriptor("(I)I"));
-        MethodHandleRef privateStaticIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testInterface, "psm", MethodTypeRef.ofDescriptor("(I)I"));
-
-        TestClass instance = (TestClass) ctorRef.resolveRef(LOOKUP).invokeExact();
-        instance = (TestClass) ctorRef.resolveRef(TestClass.LOOKUP).invokeExact();
-        TestInterface instanceI = instance;
-        
-        assertEquals(5, (int) staticMethodRef.resolveRef(LOOKUP).invokeExact(5));
-        assertEquals(5, (int) staticMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(5));
-        assertEquals(0, (int) staticIMethodRef.resolveRef(LOOKUP).invokeExact(5));
-        assertEquals(0, (int) staticIMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(5));
-        
-        assertEquals(5, (int) instanceMethodRef.resolveRef(LOOKUP).invokeExact(instance, 5));
-        assertEquals(5, (int) instanceMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(instance, 5));
-        assertEquals(5, (int) instanceIMethodRef.resolveRef(LOOKUP).invokeExact(instanceI, 5));
-        assertEquals(5, (int) instanceIMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(instanceI, 5));
-
-        try { superMethodRef.resolveRef(LOOKUP); fail(); }
-        catch (IllegalAccessException e) { /* expected */ }
-        assertEquals(-1, (int) superMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(instance, 5));
-        try { superIMethodRef.resolveRef(LOOKUP); fail(); }
-        catch (IllegalAccessException e) { /* expected */ }
-        assertEquals(0, (int) superIMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(instance, 5));
-        
-        try { privateMethodRef.resolveRef(LOOKUP); fail(); }
-        catch (IllegalAccessException e) { /* expected */ }
-        assertEquals(5, (int) privateMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(instance, 5));
-        try { privateIMethodRef.resolveRef(LOOKUP); fail(); }
-        catch (IllegalAccessException e) { /* expected */ }
-        try { privateIMethodRef.resolveRef(TestClass.LOOKUP); fail(); }
-        catch (IllegalAccessException e) { /* expected */ }
-        assertEquals(0, (int) privateIMethodRef.resolveRef(TestInterface.LOOKUP).invokeExact(instanceI, 5));
-        
-        try { privateStaticMethodRef.resolveRef(LOOKUP); fail(); }
-        catch (IllegalAccessException e) { /* expected */ }
-        assertEquals(5, (int) privateStaticMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(5));
-        try { privateStaticIMethodRef.resolveRef(LOOKUP); fail(); }
-        catch (IllegalAccessException e) { /* expected */ }
-        try { privateStaticIMethodRef.resolveRef(TestClass.LOOKUP); fail(); }
-        catch (IllegalAccessException e) { /* expected */ }
-        assertEquals(0, (int) privateStaticIMethodRef.resolveRef(TestInterface.LOOKUP).invokeExact(5));
-
-        MethodHandleRef staticSetterRef = MethodHandleRef.ofField(STATIC_SETTER, testClass, "sf", SymbolicRefs.CR_int);
-        MethodHandleRef staticGetterRef = MethodHandleRef.ofField(STATIC_GETTER, testClass, "sf", SymbolicRefs.CR_int);
-        MethodHandleRef staticGetterIRef = MethodHandleRef.ofField(STATIC_GETTER, testInterface, "sf", SymbolicRefs.CR_int);
-        MethodHandleRef setterRef = MethodHandleRef.ofField(SETTER, testClass, "f", SymbolicRefs.CR_int);
-        MethodHandleRef getterRef = MethodHandleRef.ofField(GETTER, testClass, "f", SymbolicRefs.CR_int);
-
-        staticSetterRef.resolveRef(LOOKUP).invokeExact(6); assertEquals(TestClass.sf, 6);
-        assertEquals(6, (int) staticGetterRef.resolveRef(LOOKUP).invokeExact());
-        assertEquals(6, (int) staticGetterRef.resolveRef(TestClass.LOOKUP).invokeExact());
-        staticSetterRef.resolveRef(TestClass.LOOKUP).invokeExact(7); assertEquals(TestClass.sf, 7);
-        assertEquals(7, (int) staticGetterRef.resolveRef(LOOKUP).invokeExact());
-        assertEquals(7, (int) staticGetterRef.resolveRef(TestClass.LOOKUP).invokeExact());
-
-        assertEquals(3, (int) staticGetterIRef.resolveRef(LOOKUP).invokeExact());
-        assertEquals(3, (int) staticGetterIRef.resolveRef(TestClass.LOOKUP).invokeExact());
-
-        setterRef.resolveRef(LOOKUP).invokeExact(instance, 6); assertEquals(instance.f, 6);
-        assertEquals(6, (int) getterRef.resolveRef(LOOKUP).invokeExact(instance));
-        assertEquals(6, (int) getterRef.resolveRef(TestClass.LOOKUP).invokeExact(instance));
-        setterRef.resolveRef(TestClass.LOOKUP).invokeExact(instance, 7); assertEquals(instance.f, 7);
-        assertEquals(7, (int) getterRef.resolveRef(LOOKUP).invokeExact(instance));
-        assertEquals(7, (int) getterRef.resolveRef(TestClass.LOOKUP).invokeExact(instance));
-    }
-
-    public void testVarHandles() throws ReflectiveOperationException {
-        ClassRef testClass = ClassRef.of("ConstablesTest").inner("TestClass");
-        TestClass instance = new TestClass();
-        int[] ints = new int[3];
-
-        // static varHandle
-        DynamicConstantRef<VarHandle> vhc = (DynamicConstantRef<VarHandle>) SymbolicRef.staticFieldVarHandle(testClass, "sf", SymbolicRefs.CR_int);
-        MethodTypeRef methodTypeRef = vhc.bootstrapMethod().type();
-        System.out.println(vhc.name() + " " + methodTypeRef.returnType() + " " + methodTypeRef.parameterList());
-        VarHandle varHandle = vhc.resolveRef(LOOKUP);
-        assertEquals(varHandle.varType(), int.class);
-        varHandle.set(8);
-        assertEquals(8, (int) varHandle.get());
-        assertEquals(TestClass.sf, 8);
-
-        // static varHandle
-        vhc = (DynamicConstantRef<VarHandle>) SymbolicRef.fieldVarHandle(testClass, "f", SymbolicRefs.CR_int);
-        varHandle = vhc.resolveRef(LOOKUP);
-        assertEquals(varHandle.varType(), int.class);
-        varHandle.set(instance, 9);
-        assertEquals(9, (int) varHandle.get(instance));
-        assertEquals(instance.f, 9);
-
-        vhc = (DynamicConstantRef<VarHandle>) SymbolicRef.arrayVarHandle(SymbolicRefs.CR_int.array());
-        varHandle = vhc.resolveRef(LOOKUP);
-        varHandle.set(ints, 0, 1);
-        varHandle.set(ints, 1, 2);
-        varHandle.set(ints, 2, 3);
-
-        assertEquals(1, varHandle.get(ints, 0));
-        assertEquals(2, varHandle.get(ints, 1));
-        assertEquals(3, varHandle.get(ints, 2));
-        assertEquals(1, ints[0]);
-        assertEquals(2, ints[1]);
-        assertEquals(3, ints[2]);
-
-    }
-
-    public void testMiscConstablesFactories() throws ReflectiveOperationException {
-        DynamicConstantRef<?> ofNull = (DynamicConstantRef<?>) SymbolicRefs.NULL;
-
-        assertNull(ofNull.resolveRef(LOOKUP));
-    }
 
     public void testLdcClassRef() {
         assertEquals(String.class, Intrinsics.ldc(ClassRef.ofDescriptor("Ljava/lang/String;")));
@@ -456,31 +103,6 @@
                      Intrinsics.ldc(MethodTypeRef.ofDescriptor("([I)[Ljava/lang/String;")));
     }
 
-    public void testLifting() {
-        ClassRef CR_ConstantBootstraps = ClassRef.of("java.lang.invoke.ConstantBootstraps");
-        MethodHandleRef BSM_NULL_CONSTANT
-                = MethodHandleRef.ofCondyBootstrap(CR_ConstantBootstraps, "nullConstant", SymbolicRefs.CR_Object);
-        MethodHandleRef BSM_PRIMITIVE_CLASS
-                = MethodHandleRef.ofCondyBootstrap(CR_ConstantBootstraps, "primitiveClass", SymbolicRefs.CR_Class);
-        MethodHandleRef BSM_ENUM_CONSTANT
-                = MethodHandleRef.ofCondyBootstrap(CR_ConstantBootstraps, "enumConstant", SymbolicRefs.CR_Enum);
-
-        assertNotEquals(SymbolicRefs.NULL, DynamicConstantRef.of(BSM_NULL_CONSTANT, "_", SymbolicRefs.CR_Object, new SymbolicRef[0]));
-        assertEquals(SymbolicRefs.NULL, DynamicConstantRef.ofCanonical(BSM_NULL_CONSTANT, "_", SymbolicRefs.CR_Object, new SymbolicRef[0]));
-        assertEquals(SymbolicRefs.NULL, DynamicConstantRef.ofCanonical(BSM_NULL_CONSTANT, "_", SymbolicRefs.CR_String, new SymbolicRef[0]));
-        assertEquals(SymbolicRefs.NULL, DynamicConstantRef.ofCanonical(BSM_NULL_CONSTANT, "wahoo", SymbolicRefs.CR_Object, new SymbolicRef[0]));
-
-        assertNotEquals(SymbolicRefs.CR_int, DynamicConstantRef.of(BSM_PRIMITIVE_CLASS, "I", SymbolicRefs.CR_Class, new SymbolicRef[0]));
-        assertEquals(SymbolicRefs.CR_int, DynamicConstantRef.<Class<?>>ofCanonical(BSM_PRIMITIVE_CLASS, "I", SymbolicRefs.CR_Class, new SymbolicRef[0]));
-
-        ClassRef enumClass = ClassRef.of("ConstablesTest").inner("MyEnum");
-        assertNotEquals(EnumRef.of(enumClass, "A"),
-                        DynamicConstantRef.of(BSM_ENUM_CONSTANT, "A", enumClass, new SymbolicRef[0]));
-        assertEquals(EnumRef.of(enumClass, "A"),
-                     DynamicConstantRef.ofCanonical(BSM_ENUM_CONSTANT, "A", enumClass, new SymbolicRef[0]));
-    }
-
-    private enum MyEnum { A, B, C }
 
     public void testLdcMethodHandle() throws Throwable {
         ldcMethodHandleTestsFromOuter();
@@ -557,86 +179,5 @@
         return i;
     }
 
-    private static interface TestInterface {
-        public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
-        
-        public static final int sf = 3;
-        
-        static int sm(int  x) { return 0; }
-        default int m(int x) { return 0; }
-        private int pm(int x) { return 0; }
-        private static int psm(int x) { return 0; }
-    }
-    
-    private static class TestSuperclass {
-        public int m(int x) { return -1; }
-    }
 
-    private static class TestClass extends TestSuperclass implements TestInterface {
-        public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
-    
-        static int sf;
-        int f;
-
-        public TestClass()  {}
-
-        public static int sm(int x) { return x; }
-        public int m(int x) { return x; }
-        private static int psm(int x) { return x; }
-        private int pm(int x) { return x; }
-        
-        private static void ldcMethodHandleTestsFromClass() throws Throwable {
-            ClassRef thisClass = ClassRef.of("ConstablesTest");
-            ClassRef testClass = thisClass.inner("TestClass");
-            ClassRef testInterface = thisClass.inner("TestInterface");
-            ClassRef testSuperclass = thisClass.inner("TestSuperclass");
-
-            MethodHandleRef ctorRef = MethodHandleRef.of(MethodHandleRef.Kind.CONSTRUCTOR, testClass, "<ignored!>", MethodTypeRef.ofDescriptor("()V"));
-            MethodHandleRef staticMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testClass, "sm", "(I)I");
-            MethodHandleRef staticIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testInterface, "sm", "(I)I");
-            MethodHandleRef instanceMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.VIRTUAL, testClass, "m", MethodTypeRef.ofDescriptor("(I)I"));
-            MethodHandleRef instanceIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.INTERFACE_VIRTUAL, testInterface, "m", MethodTypeRef.ofDescriptor("(I)I"));
-            MethodHandleRef superMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testSuperclass, "m", "(I)I");
-            MethodHandleRef superIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testInterface, "m", "(I)I");
-            MethodHandleRef privateMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testClass, "pm", MethodTypeRef.ofDescriptor("(I)I"));
-            MethodHandleRef privateIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testInterface, "pm", MethodTypeRef.ofDescriptor("(I)I"));
-            MethodHandleRef privateStaticMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testClass, "psm", MethodTypeRef.ofDescriptor("(I)I"));
-            MethodHandleRef privateStaticIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testInterface, "psm", MethodTypeRef.ofDescriptor("(I)I"));
-
-            TestClass instance = (TestClass) Intrinsics.ldc(ctorRef).invokeExact();
-            TestInterface instanceI = instance;
-        
-            assertEquals(5, (int) Intrinsics.ldc(staticMethodRef).invokeExact(5));
-            assertEquals(0, (int) Intrinsics.ldc(staticIMethodRef).invokeExact(5));
-        
-            assertEquals(5, (int) Intrinsics.ldc(instanceMethodRef).invokeExact(instance, 5));
-            assertEquals(5, (int) Intrinsics.ldc(instanceIMethodRef).invokeExact(instanceI, 5));
-
-            assertEquals(-1, (int) Intrinsics.ldc(superMethodRef).invokeExact(instance, 5));
-            assertEquals(0, (int) Intrinsics.ldc(superIMethodRef).invokeExact(instance, 5));
-        
-            assertEquals(5, (int) Intrinsics.ldc(privateMethodRef).invokeExact(instance, 5));
-            try { Intrinsics.ldc(privateIMethodRef); fail(); }
-            catch (IllegalAccessError e) { /* expected */ }
-        
-            assertEquals(5, (int) Intrinsics.ldc(privateStaticMethodRef).invokeExact(5));
-            try { Intrinsics.ldc(privateStaticIMethodRef); fail(); }
-            catch (IllegalAccessError e) { /* expected */ }
-
-            MethodHandleRef staticSetterRef = MethodHandleRef.ofField(STATIC_SETTER, testClass, "sf", SymbolicRefs.CR_int);
-            MethodHandleRef staticGetterRef = MethodHandleRef.ofField(STATIC_GETTER, testClass, "sf", SymbolicRefs.CR_int);
-            MethodHandleRef staticGetterIRef = MethodHandleRef.ofField(STATIC_GETTER, testInterface, "sf", SymbolicRefs.CR_int);
-            MethodHandleRef setterRef = MethodHandleRef.ofField(SETTER, testClass, "f", SymbolicRefs.CR_int);
-            MethodHandleRef getterRef = MethodHandleRef.ofField(GETTER, testClass, "f", SymbolicRefs.CR_int);
-
-            Intrinsics.ldc(staticSetterRef).invokeExact(10); assertEquals(TestClass.sf, 10);
-            assertEquals(10, (int) Intrinsics.ldc(staticGetterRef).invokeExact());
-
-            //assertEquals(3, (int) Intrinsics.ldc(staticGetterIRef).invokeExact());
-
-            Intrinsics.ldc(setterRef).invokeExact(instance, 11); assertEquals(instance.f, 11);
-            assertEquals(11, (int) Intrinsics.ldc(getterRef).invokeExact(instance));
-        }
-
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/sym/ClassRefTest.java	Thu Jan 04 16:03:09 2018 -0500
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+import java.lang.reflect.Array;
+import java.lang.sym.ClassRef;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+/**
+ * @test
+ * @run testng ClassRefTest
+ * @summary unit tests for java.lang.sym.ClassRef
+ */
+@Test
+public class ClassRefTest extends SymbolicRefTest {
+
+    private void testClassRef(ClassRef r) throws ReflectiveOperationException {
+        testSymbolicRef(r);
+
+        // Test descriptor accessor, factory, equals
+        assertEquals(r, ClassRef.ofDescriptor(r.descriptorString()));
+
+        if (!r.descriptorString().equals("V")) {
+            assertEquals(r, r.array().componentType());
+            // Commutativity: array -> resolve -> componentType -> toSymbolic
+            assertEquals(r, r.array().resolveRef(LOOKUP).getComponentType().toSymbolicRef(LOOKUP).get());
+            // Commutativity: resolve -> array -> toSymbolic -> component type
+            assertEquals(r, Array.newInstance(r.resolveRef(LOOKUP), 0).getClass().toSymbolicRef(LOOKUP).get().componentType());
+        }
+
+        if (r.isArray()) {
+            assertEquals(r, r.componentType().array());
+            assertEquals(r, r.resolveRef(LOOKUP).getComponentType().toSymbolicRef(LOOKUP).get().array());
+            assertEquals(r, Array.newInstance(r.componentType().resolveRef(LOOKUP), 0).getClass().toSymbolicRef(LOOKUP).get());
+        }
+    }
+
+    private void testClassRef(ClassRef r, Class<?> c) throws ReflectiveOperationException {
+        testClassRef(r);
+
+        assertEquals(r.resolveRef(LOOKUP), c);
+        assertEquals(c.toSymbolicRef(LOOKUP).get(), r);
+        assertEquals(ClassRef.ofDescriptor(c.toDescriptorString()), r);
+    }
+
+    public void testPrimitiveClassRef() throws ReflectiveOperationException {
+        for (Primitives p : Primitives.values()) {
+            List<ClassRef> refs = List.of(ClassRef.ofDescriptor(p.descriptor),
+                                          p.classRef,
+                                          (ClassRef) p.clazz.toSymbolicRef().get());
+            for (ClassRef c : refs) {
+                testClassRef(c, p.clazz);
+                assertTrue(c.isPrimitive());
+                assertEquals(p.descriptor, c.descriptorString());
+                assertEquals(p.name, c.canonicalName());
+                refs.forEach(cc -> assertEquals(c, cc));
+                if (p != Primitives.VOID) {
+                    testClassRef(c.array(), p.arrayClass);
+                    assertEquals(c, ((ClassRef) p.arrayClass.toSymbolicRef().get()).componentType());
+                    assertEquals(c, p.classRef.array().componentType());
+                }
+            }
+
+            for (Primitives other : Primitives.values()) {
+                ClassRef otherDescr = ClassRef.ofDescriptor(other.descriptor);
+                if (p != other)
+                    refs.forEach(c -> assertNotEquals(c, otherDescr));
+                else
+                    refs.forEach(c -> assertEquals(c, otherDescr));
+            }
+        }
+    }
+
+    public void testSimpleClassRef() throws ReflectiveOperationException {
+
+        List<ClassRef> stringClassRefs = Arrays.asList(ClassRef.ofDescriptor("Ljava/lang/String;"),
+                                                       ClassRef.of("java.lang", "String"),
+                                                       ClassRef.of("java.lang.String"),
+                                                       ClassRef.of("java.lang.String").array().componentType(),
+                                                       String.class.toSymbolicRef(LOOKUP).get());
+        for (ClassRef r : stringClassRefs) {
+            testClassRef(r, String.class);
+            assertFalse(r.isPrimitive());
+            assertEquals("Ljava/lang/String;", r.descriptorString());
+            assertEquals("java.lang.String", r.canonicalName());
+            assertEquals(r.array().resolveRef(LOOKUP), String[].class);
+            stringClassRefs.forEach(rr -> assertEquals(r, rr));
+        }
+
+        testClassRef(ClassRef.of("java.lang.String").array(), String[].class);
+        testClassRef(ClassRef.of("java.util.Map").inner("Entry"), Map.Entry.class);
+
+        ClassRef thisClassRef = ClassRef.ofDescriptor("LClassRefTest;");
+        assertEquals(thisClassRef, ClassRef.of("", "ClassRefTest"));
+        assertEquals(thisClassRef, ClassRef.of("ClassRefTest"));
+        assertEquals(thisClassRef.canonicalName(), "ClassRefTest");
+        testClassRef(thisClassRef, ClassRefTest.class);
+    }
+
+    public void testArrayClassRef() throws ReflectiveOperationException {
+        for (String d : basicDescs) {
+            ClassRef a0 = ClassRef.ofDescriptor(d);
+            ClassRef a1 = a0.array();
+            ClassRef a2 = a1.array();
+
+            testClassRef(a0);
+            testClassRef(a1);
+            testClassRef(a2);
+            assertFalse(a0.isArray());
+            assertTrue(a1.isArray());
+            assertTrue(a2.isArray());
+            assertFalse(a1.isPrimitive());
+            assertFalse(a2.isPrimitive());
+            assertEquals(a0.descriptorString(), d);
+            assertEquals(a1.descriptorString(), "[" + a0.descriptorString());
+            assertEquals(a2.descriptorString(), "[[" + a0.descriptorString());
+
+            try {
+                assertEquals(a0, a0.componentType());
+                fail("Didn't throw ISE");
+            }
+            catch (IllegalStateException expected) {
+                // succeed
+            }
+            assertEquals(a0, a1.componentType());
+            assertEquals(a1, a2.componentType());
+
+            assertNotEquals(a0, a1);
+            assertNotEquals(a1, a2);
+
+            assertEquals(a1, ClassRef.ofDescriptor("[" + d));
+            assertEquals(a2, ClassRef.ofDescriptor("[[" + d));
+            assertEquals(classToDescriptor(a0.resolveRef(LOOKUP)), a0.descriptorString());
+            assertEquals(classToDescriptor(a1.resolveRef(LOOKUP)), a1.descriptorString());
+            assertEquals(classToDescriptor(a2.resolveRef(LOOKUP)), a2.descriptorString());
+        }
+    }
+
+    public void testBadClassRefs() {
+        List<String> badDescriptors = List.of("II", "I;", "Q", "L",
+                                              "java.lang.String", "[]", "Ljava/lang/String",
+                                              "Ljava.lang.String;", "java/lang/String");
+
+        for (String d : badDescriptors) {
+            try {
+                ClassRef constant = ClassRef.ofDescriptor(d);
+                fail(d);
+            }
+            catch (IllegalArgumentException e) {
+                // good
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/sym/DynamicConstantRefTest.java	Thu Jan 04 16:03:09 2018 -0500
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.lang.sym.ClassRef;
+import java.lang.sym.DynamicConstantRef;
+import java.lang.sym.EnumRef;
+import java.lang.sym.MethodHandleRef;
+import java.lang.sym.MethodTypeRef;
+import java.lang.sym.SymbolicRef;
+import java.lang.sym.SymbolicRefs;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+import static java.lang.sym.SymbolicRefs.CR_MethodHandle;
+import static java.lang.sym.SymbolicRefs.CR_Object;
+import static java.lang.sym.SymbolicRefs.CR_String;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * @test
+ * @run testng DynamicConstantRefTest
+ * @summary unit tests for java.lang.sym.DynamicConstantRefTest
+ */
+@Test
+public class DynamicConstantRefTest extends SymbolicRefTest {
+    static ClassRef CR_ConstantBootstraps = ClassRef.of("java.lang.invoke.ConstantBootstraps");
+
+    private static<T> void testDCR(DynamicConstantRef<T> r, T c) throws ReflectiveOperationException {
+        assertEquals(r, DynamicConstantRef.of(r.bootstrapMethod(), r.name(), r.type(), r.bootstrapArgs()));
+        assertEquals(r.resolveRef(LOOKUP), c);
+    }
+
+    private static<E extends Enum<E>> void testEnumRef(EnumRef<E> r, E e) throws ReflectiveOperationException {
+        testSymbolicRef(r);
+
+        assertEquals(r, EnumRef.of(r.enumClass(), r.constantName()));
+        assertEquals(r.resolveRef(LOOKUP), e);
+    }
+
+    public void testNullConstant() throws ReflectiveOperationException {
+        DynamicConstantRef<?> r = (DynamicConstantRef<?>) SymbolicRefs.NULL;
+        assertEquals(r, DynamicConstantRef.of(r.bootstrapMethod(), r.name(), r.type(), r.bootstrapArgs()));
+        assertNull(r.resolveRef(LOOKUP));
+    }
+
+    static String concatBSM(MethodHandles.Lookup lookup, String name, Class<?> type, String a, String b) {
+        return a + b;
+    }
+
+    public void testDynamicConstant() throws ReflectiveOperationException {
+        MethodHandleRef bsmRef = MethodHandleRef.ofCondyBootstrap(ClassRef.of("DynamicConstantRefTest"), "concatBSM",
+                                                                  CR_String, CR_String, CR_String);
+        DynamicConstantRef<String> r = DynamicConstantRef.<String>of(bsmRef).withArgs("foo", "bar");
+        testDCR(r, "foobar");
+    }
+
+    public void testNested() throws Throwable {
+        MethodHandleRef invoker = MethodHandleRef.ofCondyBootstrap(CR_ConstantBootstraps, "invoke", CR_Object, CR_MethodHandle, CR_Object.array());
+        MethodHandleRef format = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, CR_String, "format", CR_String, CR_String, CR_Object.array());
+
+        String s = (String) invoker.resolveRef(LOOKUP)
+                                   .invoke(LOOKUP, "", String.class,
+                                           format.resolveRef(LOOKUP), "%s%s", "moo", "cow");
+        assertEquals(s, "moocow");
+
+        DynamicConstantRef<String> ref = DynamicConstantRef.<String>of(invoker).withArgs(format, "%s%s", "moo", "cow");
+        testDCR(ref, "moocow");
+
+        DynamicConstantRef<String> ref2 = DynamicConstantRef.<String>of(invoker).withArgs(format, "%s%s", ref, "cow");
+        testDCR(ref2, "moocowcow");
+    }
+
+    enum MyEnum { A, B, C }
+
+    public void testEnumRef() throws ReflectiveOperationException {
+        ClassRef enumClass = ClassRef.of("DynamicConstantRefTest").inner("MyEnum");
+
+        testEnumRef(EnumRef.of(enumClass, "A"), MyEnum.A);
+        testEnumRef(EnumRef.of(enumClass, "B"), MyEnum.B);
+        testEnumRef(EnumRef.of(enumClass, "C"), MyEnum.C);
+    }
+
+    public void testLifting() {
+        MethodHandleRef BSM_NULL_CONSTANT
+                = MethodHandleRef.ofCondyBootstrap(CR_ConstantBootstraps, "nullConstant", CR_Object);
+        MethodHandleRef BSM_PRIMITIVE_CLASS
+                = MethodHandleRef.ofCondyBootstrap(CR_ConstantBootstraps, "primitiveClass", SymbolicRefs.CR_Class);
+        MethodHandleRef BSM_ENUM_CONSTANT
+                = MethodHandleRef.ofCondyBootstrap(CR_ConstantBootstraps, "enumConstant", SymbolicRefs.CR_Enum);
+
+        assertEquals(SymbolicRefs.NULL, DynamicConstantRef.of(BSM_NULL_CONSTANT, "_", CR_Object, new SymbolicRef[0]));
+        assertTrue(SymbolicRefs.NULL != DynamicConstantRef.of(BSM_NULL_CONSTANT, "_", CR_Object, new SymbolicRef[0]));
+        assertTrue(SymbolicRefs.NULL == DynamicConstantRef.ofCanonical(BSM_NULL_CONSTANT, "_", CR_Object, new SymbolicRef[0]));
+        assertTrue(SymbolicRefs.NULL == DynamicConstantRef.ofCanonical(BSM_NULL_CONSTANT, "_", CR_String, new SymbolicRef[0]));
+        assertTrue(SymbolicRefs.NULL == DynamicConstantRef.ofCanonical(BSM_NULL_CONSTANT, "wahoo", CR_Object, new SymbolicRef[0]));
+
+        assertNotEquals(SymbolicRefs.CR_int, DynamicConstantRef.of(BSM_PRIMITIVE_CLASS, "I", SymbolicRefs.CR_Class, new SymbolicRef[0]));
+        assertEquals(SymbolicRefs.CR_int, DynamicConstantRef.<Class<?>>ofCanonical(BSM_PRIMITIVE_CLASS, "I", SymbolicRefs.CR_Class, new SymbolicRef[0]));
+
+        ClassRef enumClass = ClassRef.of("DynamicConstantRefTest").inner("MyEnum");
+        assertNotEquals(EnumRef.of(enumClass, "A"),
+                        DynamicConstantRef.of(BSM_ENUM_CONSTANT, "A", enumClass, new SymbolicRef[0]));
+        assertEquals(EnumRef.of(enumClass, "A"),
+                     DynamicConstantRef.ofCanonical(BSM_ENUM_CONSTANT, "A", enumClass, new SymbolicRef[0]));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/sym/MethodHandleRefTest.java	Thu Jan 04 16:03:09 2018 -0500
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandleInfo;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.VarHandle;
+import java.lang.sym.ClassRef;
+import java.lang.sym.DynamicConstantRef;
+import java.lang.sym.MethodHandleRef;
+import java.lang.sym.MethodTypeRef;
+import java.lang.sym.SymbolicRef;
+import java.lang.sym.SymbolicRefs;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+import static java.lang.sym.MethodHandleRef.Kind.GETTER;
+import static java.lang.sym.MethodHandleRef.Kind.SETTER;
+import static java.lang.sym.MethodHandleRef.Kind.STATIC_GETTER;
+import static java.lang.sym.MethodHandleRef.Kind.STATIC_SETTER;
+import static java.lang.sym.SymbolicRefs.CR_List;
+import static java.lang.sym.SymbolicRefs.CR_Object;
+import static java.lang.sym.SymbolicRefs.CR_String;
+import static java.lang.sym.SymbolicRefs.CR_void;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+/**
+ * @test
+ * @run testng MethodHandleRefTest
+ * @summary unit tests for java.lang.sym.MethodHandleRefTest
+ */
+@Test
+public class MethodHandleRefTest extends SymbolicRefTest {
+    private static ClassRef thisClass = ClassRef.of("MethodHandleRefTest");
+    private static ClassRef testClass = thisClass.inner("TestClass");
+    private static ClassRef testInterface = thisClass.inner("TestInterface");
+    private static ClassRef testSuperclass = thisClass.inner("TestSuperclass");
+
+
+    private static void assertMHEquals(MethodHandle a, MethodHandle b) {
+        MethodHandleInfo ia = LOOKUP.revealDirect(a);
+        MethodHandleInfo ib = LOOKUP.revealDirect(b);
+        assertEquals(ia.getDeclaringClass(), ib.getDeclaringClass());
+        assertEquals(ia.getName(), ib.getName());
+        assertEquals(ia.getMethodType(), ib.getMethodType());
+        assertEquals(ia.getReferenceKind(), ib.getReferenceKind());
+    }
+
+    private void testMethodHandleRef(MethodHandleRef r) throws ReflectiveOperationException {
+        testSymbolicRef(r);
+
+        assertEquals(r, MethodHandleRef.of(r.kind(), r.owner(), r.name(), r.type()));
+    }
+
+    private void testMethodHandleRef(MethodHandleRef r, MethodHandle mh) throws ReflectiveOperationException {
+        testMethodHandleRef(r);
+
+        assertMHEquals(r.resolveRef(LOOKUP), mh);
+        assertEquals(mh.toSymbolicRef(LOOKUP).get(), r);
+
+        // compare extractable properties: refKind, owner, name, type
+        MethodHandleInfo mhi = LOOKUP.revealDirect(mh);
+        assertEquals(mhi.getDeclaringClass().toDescriptorString(), r.owner().descriptorString());
+        assertEquals(mhi.getName(), r.name());
+        assertEquals(mhi.getReferenceKind(), r.kind().refKind);
+        assertEquals(mhi.getMethodType().toMethodDescriptorString(), r.type().descriptorString());
+    }
+
+    private void testVarHandleRef(DynamicConstantRef<VarHandle> r, VarHandle vh) throws ReflectiveOperationException {
+//        testSymbolicRef(r);
+//        assertEquals(r.resolveRef(LOOKUP), vh);
+
+        // @@@ VarHandle not yet Constable
+//        assertEquals(vh.toSymbolicRef(LOOKUP).get(), r);
+        // @@@ Test other assertable properties
+    }
+
+    public void testSimpleMHs() throws ReflectiveOperationException {
+        testMethodHandleRef(MethodHandleRef.of(MethodHandleRef.Kind.VIRTUAL, CR_String, "isEmpty", "()Z"),
+                            LOOKUP.findVirtual(String.class, "isEmpty", MethodType.fromMethodDescriptorString("()Z", null)));
+        testMethodHandleRef(MethodHandleRef.of(MethodHandleRef.Kind.STATIC, CR_String, "format", CR_String, CR_String, CR_Object.array()),
+                            LOOKUP.findStatic(String.class, "format", MethodType.methodType(String.class, String.class, Object[].class)));
+        testMethodHandleRef(MethodHandleRef.of(MethodHandleRef.Kind.INTERFACE_VIRTUAL, CR_List, "isEmpty", "()Z"),
+                            LOOKUP.findVirtual(List.class, "isEmpty", MethodType.fromMethodDescriptorString("()Z", null)));
+        testMethodHandleRef(MethodHandleRef.of(MethodHandleRef.Kind.CONSTRUCTOR, ClassRef.of("java.util.ArrayList"), "<init>", CR_void),
+                            LOOKUP.findConstructor(ArrayList.class, MethodType.methodType(void.class)));
+    }
+
+    public void testMethodHandleRef() throws Throwable {
+        MethodHandleRef ctorRef = MethodHandleRef.of(MethodHandleRef.Kind.CONSTRUCTOR, testClass, "<ignored!>", CR_void);
+        MethodHandleRef staticMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testClass, "sm", "(I)I");
+        MethodHandleRef staticIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testInterface, "sm", "(I)I");
+        MethodHandleRef instanceMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.VIRTUAL, testClass, "m", "(I)I");
+        MethodHandleRef instanceIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.INTERFACE_VIRTUAL, testInterface, "m", "(I)I");
+        MethodHandleRef superMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testSuperclass, "m", "(I)I");
+        MethodHandleRef superIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testInterface, "m", "(I)I");
+        MethodHandleRef privateMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testClass, "pm", "(I)I");
+        MethodHandleRef privateIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testInterface, "pm", "(I)I");
+        MethodHandleRef privateStaticMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testClass, "psm", "(I)I");
+        MethodHandleRef privateStaticIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testInterface, "psm", "(I)I");
+
+        for (MethodHandleRef r : List.of(ctorRef, staticMethodRef, staticIMethodRef, instanceMethodRef, instanceIMethodRef))
+            testMethodHandleRef(r);
+
+        TestClass instance = (TestClass) ctorRef.resolveRef(LOOKUP).invokeExact();
+        TestClass instance2 = (TestClass) ctorRef.resolveRef(TestClass.LOOKUP).invokeExact();
+        TestInterface instanceI = instance;
+
+        assertTrue(instance != instance2);
+
+        assertEquals(5, (int) staticMethodRef.resolveRef(LOOKUP).invokeExact(5));
+        assertEquals(5, (int) staticMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(5));
+        assertEquals(0, (int) staticIMethodRef.resolveRef(LOOKUP).invokeExact(5));
+        assertEquals(0, (int) staticIMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(5));
+
+        assertEquals(5, (int) instanceMethodRef.resolveRef(LOOKUP).invokeExact(instance, 5));
+        assertEquals(5, (int) instanceMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(instance, 5));
+        assertEquals(5, (int) instanceIMethodRef.resolveRef(LOOKUP).invokeExact(instanceI, 5));
+        assertEquals(5, (int) instanceIMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(instanceI, 5));
+
+        try { superMethodRef.resolveRef(LOOKUP); fail(); }
+        catch (IllegalAccessException e) { /* expected */ }
+        assertEquals(-1, (int) superMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(instance, 5));
+
+        try { superIMethodRef.resolveRef(LOOKUP); fail(); }
+        catch (IllegalAccessException e) { /* expected */ }
+        assertEquals(0, (int) superIMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(instance, 5));
+
+        try { privateMethodRef.resolveRef(LOOKUP); fail(); }
+        catch (IllegalAccessException e) { /* expected */ }
+        assertEquals(5, (int) privateMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(instance, 5));
+
+        try { privateIMethodRef.resolveRef(LOOKUP); fail(); }
+        catch (IllegalAccessException e) { /* expected */ }
+        try { privateIMethodRef.resolveRef(TestClass.LOOKUP); fail(); }
+        catch (IllegalAccessException e) { /* expected */ }
+        assertEquals(0, (int) privateIMethodRef.resolveRef(TestInterface.LOOKUP).invokeExact(instanceI, 5));
+
+        try { privateStaticMethodRef.resolveRef(LOOKUP); fail(); }
+        catch (IllegalAccessException e) { /* expected */ }
+        assertEquals(5, (int) privateStaticMethodRef.resolveRef(TestClass.LOOKUP).invokeExact(5));
+
+        try { privateStaticIMethodRef.resolveRef(LOOKUP); fail(); }
+        catch (IllegalAccessException e) { /* expected */ }
+        try { privateStaticIMethodRef.resolveRef(TestClass.LOOKUP); fail(); }
+        catch (IllegalAccessException e) { /* expected */ }
+        assertEquals(0, (int) privateStaticIMethodRef.resolveRef(TestInterface.LOOKUP).invokeExact(5));
+
+        MethodHandleRef staticSetterRef = MethodHandleRef.ofField(STATIC_SETTER, testClass, "sf", SymbolicRefs.CR_int);
+        MethodHandleRef staticGetterRef = MethodHandleRef.ofField(STATIC_GETTER, testClass, "sf", SymbolicRefs.CR_int);
+        MethodHandleRef staticGetterIRef = MethodHandleRef.ofField(STATIC_GETTER, testInterface, "sf", SymbolicRefs.CR_int);
+        MethodHandleRef setterRef = MethodHandleRef.ofField(SETTER, testClass, "f", SymbolicRefs.CR_int);
+        MethodHandleRef getterRef = MethodHandleRef.ofField(GETTER, testClass, "f", SymbolicRefs.CR_int);
+
+        for (MethodHandleRef r : List.of(staticSetterRef, staticGetterRef, staticGetterIRef, setterRef, getterRef))
+            testMethodHandleRef(r);
+
+        staticSetterRef.resolveRef(LOOKUP).invokeExact(6); assertEquals(TestClass.sf, 6);
+        assertEquals(6, (int) staticGetterRef.resolveRef(LOOKUP).invokeExact());
+        assertEquals(6, (int) staticGetterRef.resolveRef(TestClass.LOOKUP).invokeExact());
+        staticSetterRef.resolveRef(TestClass.LOOKUP).invokeExact(7); assertEquals(TestClass.sf, 7);
+        assertEquals(7, (int) staticGetterRef.resolveRef(LOOKUP).invokeExact());
+        assertEquals(7, (int) staticGetterRef.resolveRef(TestClass.LOOKUP).invokeExact());
+
+        assertEquals(3, (int) staticGetterIRef.resolveRef(LOOKUP).invokeExact());
+        assertEquals(3, (int) staticGetterIRef.resolveRef(TestClass.LOOKUP).invokeExact());
+
+        setterRef.resolveRef(LOOKUP).invokeExact(instance, 6); assertEquals(instance.f, 6);
+        assertEquals(6, (int) getterRef.resolveRef(LOOKUP).invokeExact(instance));
+        assertEquals(6, (int) getterRef.resolveRef(TestClass.LOOKUP).invokeExact(instance));
+        setterRef.resolveRef(TestClass.LOOKUP).invokeExact(instance, 7); assertEquals(instance.f, 7);
+        assertEquals(7, (int) getterRef.resolveRef(LOOKUP).invokeExact(instance));
+        assertEquals(7, (int) getterRef.resolveRef(TestClass.LOOKUP).invokeExact(instance));
+    }
+
+    // This test method belongs elsewhere; move when we revamp VarHandleRef API
+    public void testVarHandles() throws ReflectiveOperationException {
+        TestClass instance = new TestClass();
+        int[] ints = new int[3];
+
+        // static varHandle
+        DynamicConstantRef<VarHandle> vhc = (DynamicConstantRef<VarHandle>) SymbolicRef.staticFieldVarHandle(testClass, "sf", SymbolicRefs.CR_int);
+        MethodTypeRef methodTypeRef = vhc.bootstrapMethod().type();
+        System.out.println(vhc.name() + " " + methodTypeRef.returnType() + " " + methodTypeRef.parameterList());
+        VarHandle varHandle = vhc.resolveRef(LOOKUP);
+        testVarHandleRef(vhc, varHandle);
+        assertEquals(varHandle.varType(), int.class);
+        varHandle.set(8);
+        assertEquals(8, (int) varHandle.get());
+        assertEquals(TestClass.sf, 8);
+
+        // static varHandle
+        vhc = (DynamicConstantRef<VarHandle>) SymbolicRef.fieldVarHandle(testClass, "f", SymbolicRefs.CR_int);
+        varHandle = vhc.resolveRef(LOOKUP);
+        testVarHandleRef(vhc, varHandle);
+        assertEquals(varHandle.varType(), int.class);
+        varHandle.set(instance, 9);
+        assertEquals(9, (int) varHandle.get(instance));
+        assertEquals(instance.f, 9);
+
+        vhc = (DynamicConstantRef<VarHandle>) SymbolicRef.arrayVarHandle(SymbolicRefs.CR_int.array());
+        varHandle = vhc.resolveRef(LOOKUP);
+        testVarHandleRef(vhc, varHandle);
+        varHandle.set(ints, 0, 1);
+        varHandle.set(ints, 1, 2);
+        varHandle.set(ints, 2, 3);
+
+        assertEquals(1, varHandle.get(ints, 0));
+        assertEquals(2, varHandle.get(ints, 1));
+        assertEquals(3, varHandle.get(ints, 2));
+        assertEquals(1, ints[0]);
+        assertEquals(2, ints[1]);
+        assertEquals(3, ints[2]);
+    }
+
+    private static interface TestInterface {
+        public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
+
+        public static final int sf = 3;
+
+        static int sm(int  x) { return 0; }
+        default int m(int x) { return 0; }
+        private int pm(int x) { return 0; }
+        private static int psm(int x) { return 0; }
+    }
+
+    private static class TestSuperclass {
+        public int m(int x) { return -1; }
+    }
+
+    private static class TestClass extends TestSuperclass implements TestInterface {
+        public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
+
+        static int sf;
+        int f;
+
+        public TestClass()  {}
+
+        public static int sm(int x) { return x; }
+        public int m(int x) { return x; }
+        private static int psm(int x) { return x; }
+        private int pm(int x) { return x; }
+
+        // @@@ Intrinsification test -- move to Intrinsics test
+
+//        private static void ldcMethodHandleTestsFromClass() throws Throwable {
+//            ClassRef thisClass = ClassRef.of("ConstablesTest");
+//            ClassRef testClass = thisClass.inner("TestClass");
+//            ClassRef testInterface = thisClass.inner("TestInterface");
+//            ClassRef testSuperclass = thisClass.inner("TestSuperclass");
+//
+//            MethodHandleRef ctorRef = MethodHandleRef.of(MethodHandleRef.Kind.CONSTRUCTOR, testClass, "<ignored!>", MethodTypeRef.ofDescriptor("()V"));
+//            MethodHandleRef staticMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testClass, "sm", "(I)I");
+//            MethodHandleRef staticIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testInterface, "sm", "(I)I");
+//            MethodHandleRef instanceMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.VIRTUAL, testClass, "m", MethodTypeRef.ofDescriptor("(I)I"));
+//            MethodHandleRef instanceIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.INTERFACE_VIRTUAL, testInterface, "m", MethodTypeRef.ofDescriptor("(I)I"));
+//            MethodHandleRef superMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testSuperclass, "m", "(I)I");
+//            MethodHandleRef superIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testInterface, "m", "(I)I");
+//            MethodHandleRef privateMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testClass, "pm", MethodTypeRef.ofDescriptor("(I)I"));
+//            MethodHandleRef privateIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.SPECIAL, testInterface, "pm", MethodTypeRef.ofDescriptor("(I)I"));
+//            MethodHandleRef privateStaticMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testClass, "psm", MethodTypeRef.ofDescriptor("(I)I"));
+//            MethodHandleRef privateStaticIMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testInterface, "psm", MethodTypeRef.ofDescriptor("(I)I"));
+//
+//            TestClass instance = (TestClass) Intrinsics.ldc(ctorRef).invokeExact();
+//            TestInterface instanceI = instance;
+//
+//            assertEquals(5, (int) Intrinsics.ldc(staticMethodRef).invokeExact(5));
+//            assertEquals(0, (int) Intrinsics.ldc(staticIMethodRef).invokeExact(5));
+//
+//            assertEquals(5, (int) Intrinsics.ldc(instanceMethodRef).invokeExact(instance, 5));
+//            assertEquals(5, (int) Intrinsics.ldc(instanceIMethodRef).invokeExact(instanceI, 5));
+//
+//            assertEquals(-1, (int) Intrinsics.ldc(superMethodRef).invokeExact(instance, 5));
+//            assertEquals(0, (int) Intrinsics.ldc(superIMethodRef).invokeExact(instance, 5));
+//
+//            assertEquals(5, (int) Intrinsics.ldc(privateMethodRef).invokeExact(instance, 5));
+//            try { Intrinsics.ldc(privateIMethodRef); fail(); }
+//            catch (IllegalAccessError e) { /* expected */ }
+//
+//            assertEquals(5, (int) Intrinsics.ldc(privateStaticMethodRef).invokeExact(5));
+//            try { Intrinsics.ldc(privateStaticIMethodRef); fail(); }
+//            catch (IllegalAccessError e) { /* expected */ }
+//
+//            MethodHandleRef staticSetterRef = MethodHandleRef.ofField(STATIC_SETTER, testClass, "sf", SymbolicRefs.CR_int);
+//            MethodHandleRef staticGetterRef = MethodHandleRef.ofField(STATIC_GETTER, testClass, "sf", SymbolicRefs.CR_int);
+//            MethodHandleRef staticGetterIRef = MethodHandleRef.ofField(STATIC_GETTER, testInterface, "sf", SymbolicRefs.CR_int);
+//            MethodHandleRef setterRef = MethodHandleRef.ofField(SETTER, testClass, "f", SymbolicRefs.CR_int);
+//            MethodHandleRef getterRef = MethodHandleRef.ofField(GETTER, testClass, "f", SymbolicRefs.CR_int);
+//
+//            Intrinsics.ldc(staticSetterRef).invokeExact(10); assertEquals(TestClass.sf, 10);
+//            assertEquals(10, (int) Intrinsics.ldc(staticGetterRef).invokeExact());
+//
+//            //assertEquals(3, (int) Intrinsics.ldc(staticGetterIRef).invokeExact());
+//
+//            Intrinsics.ldc(setterRef).invokeExact(instance, 11); assertEquals(instance.f, 11);
+//            assertEquals(11, (int) Intrinsics.ldc(getterRef).invokeExact(instance));
+//        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/sym/MethodTypeRefTest.java	Thu Jan 04 16:03:09 2018 -0500
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+import java.lang.invoke.MethodType;
+import java.lang.sym.ClassRef;
+import java.lang.sym.MethodTypeRef;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import org.testng.annotations.Test;
+
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+/**
+ * @test
+ * @run testng MethodTypeRefTest
+ * @summary unit tests for java.lang.sym.MethodTypeRef
+ */
+@Test
+public class MethodTypeRefTest extends SymbolicRefTest {
+
+    private void testMethodTypeRef(MethodTypeRef r) throws ReflectiveOperationException {
+        testSymbolicRef(r);
+
+        // Tests accessors (rType, pType, pCount, pList, pArray, descriptorString),
+        // factories (ofDescriptor, of), equals
+        assertEquals(r, MethodTypeRef.ofDescriptor(r.descriptorString()));
+        assertEquals(r, MethodTypeRef.of(r.returnType(), r.parameterArray()));
+        assertEquals(r, MethodTypeRef.of(r.returnType(), r.parameterList().toArray(new ClassRef[0])));
+        assertEquals(r, MethodTypeRef.of(r.returnType(), r.parameterList().stream().toArray(ClassRef[]::new)));
+        assertEquals(r, MethodTypeRef.of(r.returnType(), IntStream.range(0, r.parameterCount())
+                                                                  .mapToObj(r::parameterType)
+                                                                  .toArray(ClassRef[]::new)));
+    }
+
+    private void testMethodTypeRef(MethodTypeRef r, MethodType mt) throws ReflectiveOperationException {
+        testMethodTypeRef(r);
+
+        assertEquals(r.resolveRef(LOOKUP), mt);
+        assertEquals(mt.toSymbolicRef(LOOKUP).get(), r);
+
+        assertEquals(r.descriptorString(), mt.toMethodDescriptorString());
+        assertEquals(r.parameterCount(), mt.parameterCount());
+        assertEquals(r.parameterList(), mt.parameterList().stream().map(SymbolicRefTest::classToRef).collect(toList()));
+        assertEquals(r.parameterArray(), Stream.of(mt.parameterArray()).map(SymbolicRefTest::classToRef).toArray(ClassRef[]::new));
+        for (int i=0; i<r.parameterCount(); i++)
+            assertEquals(r.parameterType(i), classToRef(mt.parameterType(i)));
+        assertEquals(r.returnType(), classToRef(mt.returnType()));
+    }
+
+    private void assertMethodType(ClassRef returnType,
+                                  ClassRef... paramTypes) throws ReflectiveOperationException {
+        String descriptor = Stream.of(paramTypes).map(ClassRef::descriptorString).collect(joining("", "(", ")"))
+                            + returnType.descriptorString();
+        MethodTypeRef mtRef = MethodTypeRef.of(returnType, paramTypes);
+
+        // MTRef accessors
+        assertEquals(descriptor, mtRef.descriptorString());
+        assertEquals(returnType, mtRef.returnType());
+        assertEquals(paramTypes, mtRef.parameterArray());
+        assertEquals(Arrays.asList(paramTypes), mtRef.parameterList());
+        assertEquals(paramTypes.length, mtRef.parameterCount());
+        for (int i=0; i<paramTypes.length; i++)
+            assertEquals(paramTypes[i], mtRef.parameterType(i));
+
+        // Consistency between MT and MTRef
+        MethodType mt = MethodType.fromMethodDescriptorString(descriptor, null);
+        testMethodTypeRef(mtRef, mt);
+
+        // changeReturnType
+        for (String r : returnDescs) {
+            ClassRef rc = ClassRef.ofDescriptor(r);
+            MethodTypeRef newRef = mtRef.changeReturnType(rc);
+            assertEquals(newRef, MethodTypeRef.of(rc, paramTypes));
+            testMethodTypeRef(newRef, mt.changeReturnType(rc.resolveRef(LOOKUP)));
+        }
+
+        // changeParamType
+        for (int i=0; i<paramTypes.length; i++) {
+            for (String p : paramDescs) {
+                ClassRef pc = ClassRef.ofDescriptor(p);
+                ClassRef[] ps = paramTypes.clone();
+                ps[i] = pc;
+                MethodTypeRef newRef = mtRef.changeParameterType(i, pc);
+                assertEquals(newRef, MethodTypeRef.of(returnType, ps));
+                testMethodTypeRef(newRef, mt.changeParameterType(i, pc.resolveRef(LOOKUP)));
+            }
+        }
+
+        // dropParamType
+        for (int i=0; i<paramTypes.length; i++) {
+            int k = i;
+            ClassRef[] ps = IntStream.range(0, paramTypes.length)
+                                     .filter(j -> j != k)
+                                     .mapToObj(j -> paramTypes[j])
+                                     .toArray(ClassRef[]::new);
+            MethodTypeRef newRef = mtRef.dropParameterTypes(i, i + 1);
+            assertEquals(newRef, MethodTypeRef.of(returnType, ps));
+            testMethodTypeRef(newRef, mt.dropParameterTypes(i, i+1));
+        }
+
+        // addParam
+        for (int i=0; i <= paramTypes.length; i++) {
+            for (ClassRef p : paramTypes) {
+                int k = i;
+                ClassRef[] ps = IntStream.range(0, paramTypes.length + 1)
+                                         .mapToObj(j -> (j < k) ? paramTypes[j] : (j == k) ? p : paramTypes[j-1])
+                                         .toArray(ClassRef[]::new);
+                MethodTypeRef newRef = mtRef.insertParameterTypes(i, p);
+                assertEquals(newRef, MethodTypeRef.of(returnType, ps));
+                testMethodTypeRef(newRef, mt.insertParameterTypes(i, p.resolveRef(LOOKUP)));
+            }
+        }
+    }
+
+    public void testMethodTypeRef() throws ReflectiveOperationException {
+        for (String r : returnDescs) {
+            assertMethodType(ClassRef.ofDescriptor(r));
+            for (String p1 : paramDescs) {
+                assertMethodType(ClassRef.ofDescriptor(r), ClassRef.ofDescriptor(p1));
+                for (String p2 : paramDescs) {
+                    assertMethodType(ClassRef.ofDescriptor(r), ClassRef.ofDescriptor(p1), ClassRef.ofDescriptor(p2));
+                }
+            }
+        }
+    }
+
+    public void testBadMethodTypeRefs() {
+        List<String> badDescriptors = List.of("()II", "()I;", "(I;)", "(I)", "()L",
+                                              "(java.lang.String)V", "()[]", "(Ljava/lang/String)V",
+                                              "(Ljava.lang.String;)V", "(java/lang/String)V");
+
+        for (String d : badDescriptors) {
+            try {
+                MethodTypeRef r = MethodTypeRef.ofDescriptor(d);
+                fail(d);
+            }
+            catch (IllegalArgumentException e) {
+                // good
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/sym/SymbolicRefTest.java	Thu Jan 04 16:03:09 2018 -0500
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+import java.lang.Class;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandleInfo;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.sym.ClassRef;
+import java.lang.sym.Constable;
+import java.lang.sym.SymbolicRef;
+import java.lang.sym.SymbolicRefs;
+import java.util.List;
+import java.util.stream.Stream;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * Base class for XxxRef tests
+ */
+public abstract class SymbolicRefTest {
+
+    public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
+
+    static List<String> someRefs = List.of("Ljava/lang/String;", "Ljava/util/List;");
+    static String[] basicDescs = Stream.concat(Stream.of(Primitives.values())
+                                                     .filter(p -> p != Primitives.VOID)
+                                                     .map(p -> p.descriptor),
+                                               someRefs.stream())
+                                       .toArray(String[]::new);
+    static String[] paramDescs = Stream.of(basicDescs)
+                                       .flatMap(d -> Stream.of(d, "[" + d))
+                                       .toArray(String[]::new);
+    static String[] returnDescs = Stream.concat(Stream.of(paramDescs), Stream.of("V")).toArray(String[]::new);
+
+    enum Primitives {
+        INT("I", "int", int.class, int[].class, SymbolicRefs.CR_int),
+        LONG("J", "long", long.class, long[].class, SymbolicRefs.CR_long),
+        SHORT("S", "short", short.class, short[].class, SymbolicRefs.CR_short),
+        BYTE("B", "byte", byte.class, byte[].class, SymbolicRefs.CR_byte),
+        CHAR("C", "char", char.class, char[].class, SymbolicRefs.CR_char),
+        FLOAT("F", "float", float.class, float[].class, SymbolicRefs.CR_float),
+        DOUBLE("D", "double", double.class, double[].class, SymbolicRefs.CR_double),
+        BOOLEAN("Z", "boolean", boolean.class, boolean[].class, SymbolicRefs.CR_boolean),
+        VOID("V", "void", void.class, null, SymbolicRefs.CR_void);
+
+        public final String descriptor;
+        public final String name;
+        public final Class<?> clazz;
+        public final Class<?> arrayClass;
+        public final ClassRef classRef;
+
+        Primitives(String descriptor, String name, Class<?> clazz, Class<?> arrayClass, ClassRef ref) {
+            this.descriptor = descriptor;
+            this.name = name;
+            this.clazz = clazz;
+            this.arrayClass = arrayClass;
+            classRef = ref;
+        }
+    }
+
+    static String classToDescriptor(Class<?> clazz) {
+        return MethodType.methodType(clazz).toMethodDescriptorString().substring(2);
+    }
+
+    static ClassRef classToRef(Class<?> c) {
+        return ClassRef.ofDescriptor(c.toDescriptorString());
+    }
+
+    static<T> void testSymbolicRef(SymbolicRef<T> ref) throws ReflectiveOperationException {
+        // Round trip sym -> resolve -> toSymbolicRef
+        SymbolicRef<T> s = ((Constable<T>) ref.resolveRef(LOOKUP)).toSymbolicRef(LOOKUP).get();
+        assertEquals(ref, s);
+
+        // Round trip sym -> quoted sym -> resolve
+        SymbolicRef<? extends SymbolicRef<T>> ssr = (SymbolicRef<? extends SymbolicRef<T>>) ref.toSymbolicRef(LOOKUP).get();
+        SymbolicRef<T> sr = ssr.resolveRef(LOOKUP);
+        assertEquals(sr, ref);
+    }
+}