changeset 47439:9f592fdeaeca condy-folding

Simplify the set of bootstrap methods. TODO: Docs and more tests.
author psandoz
date Tue, 17 Oct 2017 16:39:22 -0700
parents 81de38607f5d
children d3f937f9ca54
files src/java.base/share/classes/java/lang/invoke/Bootstraps.java src/java.base/share/classes/java/lang/invoke/ClassRef.java src/java.base/share/classes/java/lang/invoke/Constables.java src/java.base/share/classes/java/lang/invoke/ConstantRef.java test/jdk/java/lang/invoke/CondyBootstrapsTest.java
diffstat 5 files changed, 212 insertions(+), 369 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/invoke/Bootstraps.java	Tue Oct 17 17:48:27 2017 -0400
+++ b/src/java.base/share/classes/java/lang/invoke/Bootstraps.java	Tue Oct 17 16:39:22 2017 -0700
@@ -24,16 +24,10 @@
  */
 package java.lang.invoke;
 
-import sun.invoke.util.BytecodeName;
 import sun.invoke.util.Wrapper;
 
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 
 import static java.lang.invoke.MethodHandleNatives.mapLookupExceptionToError;
 import static java.lang.invoke.MethodHandles.Lookup;
@@ -59,360 +53,175 @@
     }
 
     /**
-     * Load a primitive class from its descriptor.
-     * The descriptor is passed as the name component of the dynamic constant.
-     * @param lookup not used
-     * @param name the descriptor of the desired primitive class
-     * @param type the required result type (must be Class.class)
-     * @return a primitive class
-     * @throws IllegalArgumentException if no such value exists
-     */
-    public static Class<?> primitiveClass(Lookup lookup, String name, Class<Class<?>> type) {
-        switch (name) {
-            case "I": return int.class;
-            case "J": return long.class;
-            case "S": return short.class;
-            case "B": return byte.class;
-            case "C": return char.class;
-            case "F": return float.class;
-            case "D": return double.class;
-            case "Z": return boolean.class;
-            case "V": return void.class;
-            default:
-                throw new IllegalArgumentException(name);
-        }
-    }
-
-    /**
-     * Load a primitive value from a given integer value, narrowing that value
-     * for an integral primitive type of {@code byte}, {@code char} or
-     * {@code short}, and converting that value for a {@code boolean} type.
-     * <p>
-     * If the primtive type is {@code byte}, {@code char} or {@code short}
-     * the integer value is narrowed in accordance with the type conversion
-     * rules of jvms-2.11.4.  If the primitive class is {@code boolean} then
-     * an integer value of {@code 0} represents a boolean value of {@code false}
-     * and an integer value of {@code 1} represents a boolean value of
-     * {@code true}, any other integer value results in an
-     * {@code IllegalArgumentException}.
-     *
-     * @param lookup not used
-     * @param name the descriptor of the primitive type
-     * @param type the primitive type
-     * @param v the integer value to be narrowed to a smaller integral type or
-     *        converted to a boolean
-     * @return the boxed result of the primitive value
-     * @throws IllegalArgumentException if the type is not supported or the
-     *         integer value cannot be converted to the required primitive value
-     */
-    public static Object primitiveValueFromInt(Lookup lookup, String name, Class<Class<?>> type, int v) {
-        switch (name) {
-            case "B": return (byte) v;
-            case "C": return (char) v;
-            case "S": return (short) v;
-            case "Z": {
-                if (v == 0) return false;
-                if (v == 1) return false;
-                throw new IllegalArgumentException();
-            }
-            default:
-                throw new IllegalArgumentException(name);
-        }
-    }
-
-    /**
-     * Return the default value for a given type.
-     * If the type is a primitive, it is the zero (or null or false) for that primitive.
-     * If the type is a reference type, the default value is always {@code null},
-     * even if the reference type is a box such as {@code Integer}.
-     * @param lookup not used
-     * @param name not used
-     * @param type the given type
-     * @param <T> the required result type
-     * @return the default value for the given type
+     * X
+     * @param lookup X
+     * @param name X
+     * @param type X
+     * @param <T> X
+     * @return X
      */
     public static <T> T defaultValue(Lookup lookup, String name, Class<T> type) {
         if (type.isPrimitive()) {
             return Wrapper.forPrimitiveType(type).zero(type);
-        } else {
+        }
+        else {
             return null;
         }
     }
 
     /**
-     * Load an enumeration constant given its name and type.
-     * The name and type are passed as components of the dynamic constant.
-     * @param lookup used to ensure access to the given type
-     * @param name the name of the enum
-     * @param type the enum type
-     * @param <T> the required result type
-     * @return an enumeration constant of the specified name and type
-     * @throws IllegalArgumentException if no such value exists
-     * @throws IllegalAccessError if the type is not accessible from the lookup
+     * X
+     *
+     * @param lookup X
+     * @param name X
+     * @param type X
+     * @param <T> X
+     * @return X
      */
-    public static <T extends Enum<T>> T enumConstant(Lookup lookup, String name, Class<T> type) {
-        try {
-            lookup.accessClass(type);
-        } catch (ReflectiveOperationException ex) {
-            throw mapLookupExceptionToError(ex);
+    public static <T> T getStaticFinal(Lookup lookup, String name, Class<T> type) {
+        return getStaticFinal(lookup, name, type, promote(type));
+    }
+
+    static Class<?> promote(Class<?> type) {
+        if (type.isPrimitive()) {
+            type = Wrapper.forPrimitiveType(type).wrapperType();
         }
-        return Enum.valueOf(type, name);
+        return type;
     }
 
     /**
-     * Load a static final constant given its defining class, name, and type.
-     * The name and type are passed as components of the dynamic constant.
-     * @param lookup used to ensure access to the given constant
-     * @param name the name of the constant
-     * @param type the type of the constant
-     * @param declaringClass the class defining the constant
-     * @param <T> the required result type
-     * @return the value of a static final field of the specified class, name, and type
-     * @throws LinkageError if no such constant exists or it cannot be accessed and initialized
+     * X
+     *
+     * @param lookup X
+     * @param name X
+     * @param type X
+     * @param declaringClass X
+     * @param <T> X
+     * @return X
      */
-    public static <T> T namedConstant(Lookup lookup, String name, Class<T> type, Class<?> declaringClass) {
-        try {
-            lookup.accessClass(declaringClass);
-        } catch (IllegalAccessException ex) {
-            throw mapLookupExceptionToError(ex);
-        }
+    public static <T> T getStaticFinal(Lookup lookup, String name, Class<T> type,
+                                       Class<?> declaringClass) {
         MethodHandle mh;
         try {
             mh = lookup.findStaticGetter(declaringClass, name, type);
-        } catch (ReflectiveOperationException ex) {
+            MemberName member = mh.internalMemberName();
+            if (!member.isFinal()) {
+                throw new IncompatibleClassChangeError("not a final field: " + name);
+            }
+        }
+        catch (ReflectiveOperationException ex) {
             throw mapLookupExceptionToError(ex);
         }
-        MemberName member = mh.internalMemberName();
-        if (!member.isFinal()) {
-            throw new IncompatibleClassChangeError("not a final field: "+name);
-        }
+
         try {
+            // No need to cast because type was used to look up the MH
             @SuppressWarnings("unchecked")
             T value = (T) (Object) mh.invoke();
             return value;
-        } catch (Error|RuntimeException e) {
+        }
+        catch (Error | RuntimeException e) {
             throw e;
-        } catch (Throwable e) {
+        }
+        catch (Throwable e) {
             throw new BootstrapMethodError(e);
         }
     }
 
     /**
-     * Load a constant by invoking a factory on its type.
-     * The factory name and type are passed as components of the dynamic constant.
-     * The arguments to the factory (if any) are passed as extra static arguments.
-     * The named method must be defined on the given type, it must be static and
-     * accessible to the lookup object, and (as befits a factory method) it must
-     * return either the type or a subtype.  If there are several such methods,
-     * only one may match the given arguments types.  (If there are any varargs
-     * methods, they are suppressed while searching first for a match
-     * of any non-varargs methods.)  Matching is determined by calling the
-     * {@code asType} method of each factory method's method handle, and
-     * rejecting the method if it throws {@code WrongMethodTypeException}.
-     * If these rules (which are rather blunt) are insufficent to give
-     * control over factory method selection, use {@code methodCall},
-     * which allows explicit specification of the desired factory.
-     * @param lookup used to ensure access to the given factory method
-     * @param name the name of the factory method
-     * @param type the type of the factory method, which is also its declaring class
-     * @param args any arguments which must be passed to the factory method
-     * @param <T> the required result type
-     * @return the value of a static final field of the specified class, name, and type
-     * @throws LinkageError if no such constant exists or it cannot be accessed and initialized
+     * X
+     *
+     * @param lookup X
+     * @param name X
+     * @param type X
+     * @param mh X
+     * @param args X
+     * @param <T> X
+     * @return X
      */
-    public static <T> T factoryCall(Lookup lookup, String name, Class<T> type, Object... args) {
-        MethodHandle mh = selectFactoryMethod(lookup, name, type, args, false);
-        if (mh == null)
-            mh = selectFactoryMethod(lookup, name, type, args, true);
-        if (mh == null)
-            throw new IncompatibleClassChangeError("factory method not found: "+type.getName()+"."+name);
+    public static <T> T invoke(Lookup lookup, String name, Class<T> type,
+                               MethodHandle mh, Object... args) {
+        if (!type.isAssignableFrom(mh.type().returnType())) {
+            throw new IllegalArgumentException();
+        }
+
         try {
             @SuppressWarnings("unchecked")
-            T value = (T) mh.invokeWithArguments(args);
-            return value;
-        } catch (Error|RuntimeException e) {
+            T t = (T) mh.invokeWithArguments(args);
+            return t;
+        }
+        catch (Error | RuntimeException e) {
             throw e;
-        } catch (Throwable e) {
+        }
+        catch (Throwable e) {
             throw new BootstrapMethodError(e);
         }
     }
-    // where...
-    private static MethodHandle selectFactoryMethod(Lookup lookup, String name, Class<?> type, Object[] args, boolean varargsOK) {
-        // FIXME: Cache a list of factory methods on a ClassValue.
-        final List<MethodHandle> mhs = Arrays.stream(type.getDeclaredMethods())
-                .map(m -> asFactoryMethod(m, lookup, name, type, args, varargsOK))
-                .filter(Objects::nonNull)
-                .collect(Collectors.toList());
-        if (mhs.size() == 1)  return mhs.get(0);
-        if (mhs.isEmpty())  return null;
-        throw new IncompatibleClassChangeError("ambiguous factory method selection: "+mhs);
-    }
-    private static MethodHandle asFactoryMethod(Method m, Lookup lookup, String name, Class<?> type, Object[] args, boolean varargsOK) {
-        final int mods = m.getModifiers();
-        if (!Modifier.isStatic(mods))  return null;
-        if (!Modifier.isPublic(mods))  return null;  // FIXME
-        if (!m.getName().equals(name))  return null;
-        final Class<?> rtype = m.getReturnType();
-        if (type != rtype && !type.isAssignableFrom(rtype))  return null;
-        final boolean varargs = m.isVarArgs();
-        if (varargs && !varargsOK)  return null;
-        // Match the arguments.
-        int minargs = m.getParameterCount() - (varargs ? 1 : 0), maxargs = (varargs ? Integer.MAX_VALUE : minargs);
-        if (args.length < minargs || args.length > maxargs)  return null;
-        final Class<?>[] ptypes = m.getParameterTypes();
-        for (int i = 0; i < minargs; i++) {
-            if (!matchArgument(args[i], ptypes[i]))  return null;
-        }
-        for (int i = minargs; i < args.length; i++) {
-            if (!matchArgument(args[i], ptypes[minargs].getComponentType()))  return null;
-        }
-        // Got a match.  Now turn it into a method handle.
-        try {
-            return lookup.unreflect(m);
-        } catch (IllegalAccessException ex) {
-            throw MethodHandleStatics.newInternalError("cannot unreflect", ex);
-        }
-    }
-    private static boolean matchArgument(Object arg, Class<?> ptype) {
-        Class<?> atype = (arg == null ? Void.class : arg.getClass());
-        return ptype.isAssignableFrom(atype);
-    }
-//    private static boolean testFactoryMethods() {
-//        Lookup lookup = Lookup.IMPL_LOOKUP.in(Object.class);
-//        List<?> l0 = factoryCall(lookup, "of", List.class);
-//        assert(l0.equals(List.of()));
-//        List<?> la = factoryCall(lookup, "of", List.class, "a");
-//        assert(la.equals(List.of("a")));
-//        List<?> lab = factoryCall(lookup, "of", List.class, "a", "b");
-//        assert(lab.equals(List.of("a","b")));
-//        Pattern pa = factoryCall(lookup, "compile", Pattern.class, "a");
-//        assert(pa.pattern().equals("a"));
-//        Duration p2d = factoryCall(lookup, "parse", Duration.class, "P2D");
-//        assert(p2d.equals(Duration.parse("P2D")));
-//        System.out.println(Arrays.asList(l0, la, lab, pa, p2d));
-//        return true;
-//    }
-//    static { assert(testFactoryMethods()); }
 
-    // compiledPattern["RE",Pattern] probably subsumes into factoryCall["compile",Pattern,"RE"]
-    /**
-     * Load a compiled regular expression.
-     * The string is passed as the name component of the dynamic constant.
-     * Note that the three commonly used characters ({@code "./;"} are illegal
-     * in field names, and so cannot be used to form the regular expression.
-     * In such cases, use the four-argument version of {@code compiledPattern}.
-     * @param lookup unused
-     * @param regex the regular expression string
-     * @param type unused, must be Pattern.class
-     * @return the compiled regular expression
-     * @throws java.util.regex.PatternSyntaxException if the string was malformed
-     */
-    public static Pattern compiledPattern(Lookup lookup, String regex, Class<Pattern> type) {
-        if (false) {
-            // If the string begins with backslash and equals characters {@code "\\="},
-            // then the string is demangled according to symbolic freedom rules.
-            if (regex.startsWith("\\="))
-                regex = BytecodeName.toSourceName(regex);
-        }
-        return Pattern.compile(regex);
-    }
+    // ()T
+    // (O)T
+    // (A[])A
+    // (ByteBuffer, int)PT, ByteOrder
+    // (byte[], int)PT, ByteOrder
 
     /**
-     * Load a compiled regular expression.
-     * The string is passed as the name component of the dynamic constant.
-     * @param lookup unused
-     * @param name unused
-     * @param type unused, must be Pattern.class
-     * @param regex the regular expression string
-     * @return the compiled regular expression
-     * @throws java.util.regex.PatternSyntaxException if the string was malformed
+     * X
+     *
+     * @param lookup X
+     * @param name X
+     * @param type X
+     * @param getter X
+     * @param args X
+     * @return X
      */
-    public static Pattern compiledPattern(Lookup lookup, String name, Class<Pattern> type, String regex) {
-        return Pattern.compile(regex);
-    }
+    public static VarHandle varHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type,
+                                      MethodType getter, Object... args) {
+        int pc = getter.parameterCount();
+        switch (pc) {
+            // Static field
+            case 0: {
+                Class<?> variableType = getter.returnType();
+                Class<?> declaringClass = (Class<?>) args[0];
+                try {
+                    return lookup.findStaticVarHandle(declaringClass, name, variableType);
+                }
+                catch (ReflectiveOperationException e) {
+                    throw mapLookupExceptionToError(e);
+                }
+            }
+            // Instance field
+            case 1: {
+                Class<?> variableType = getter.returnType();
+                Class<?> coordType = getter.parameterType(0);
 
-//    /**
-//     * Load a {@link VarHandle} giving access to a field or elements of an
-//     * array.
-//     *
-//     * @param lookup used to ensure access to the given owner
-//     * @param name if for a field the name of the field, otherwise unused
-//     * @param type unused, must be VarHandle.class
-//     * @param ownerType if for a field the class declaring the field, otherwise
-//     *        an array class
-//     * @param variableType if for a field the type of the field, otherwise
-//     *        unused
-//     * @return the {@code VarHandle}
-//     * @throws NoSuchFieldException if the field doesn't exist
-//     * @throws IllegalAccessException if the field is not accessible
-//     */
-//    public static VarHandle varHandle(MethodHandles.Lookup lookup,
-//                                      String name,
-//                                      Class<?> type,
-//                                      Class<?> ownerType,
-//                                      Class<?> variableType) throws NoSuchFieldException, IllegalAccessException {
-//        if (ownerType.isArray()) {
-//            return MethodHandles.arrayElementVarHandle(ownerType);
-//        }
-//
-//        try {
-//            lookup.accessClass(ownerType);
-//        } catch (IllegalAccessException ex) {
-//            throw mapLookupExceptionToError(ex);
-//        }
-//
-//        Field f;
-//        try {
-//            f = ownerType.getDeclaredField(name);
-//        } catch (NoSuchFieldException ex) {
-//            throw new IncompatibleClassChangeError("field not found: " + ownerType.getName() + "." + name);
-//        }
-//        if (f.getType() != variableType) {
-//            throw new IncompatibleClassChangeError("field type differs: " + f.getType() + " " + variableType);
-//        }
-//
-//        try {
-//            return lookup.unreflectVarHandle(f);
-//        } catch (ReflectiveOperationException ex) {
-//            throw mapLookupExceptionToError(ex);
-//        }
-//    }
-
-    /** Selector for a VarHandle for an instance field */
-    public static final int VH_instanceField = 1;
-    /** Selector for a VarHandle for a static field */
-    public static final int VH_staticField = 2;
-    /** Selector for a VarHandle for an array element */
-    public static final int VH_arrayHandle = 3;
-
-    /**
-     * Load a {@link VarHandle} giving access to a field or elements of an
-     * array.
-     *
-     * @param lookup stacked automatically by VM
-     * @param type the type of the field or array element,
-     *        stacked automatically by VM
-     * @param constantType stacked automatically by VM
-     * @param kind the selector value, one of VH_instanceField, VH_staticField, VH_arrayHandle
-     * @param owner the class in which the field is declared (ignored for array handles)
-     * @param name ignored
-     * @param fieldName the field name (for fields)
-     * @return the VarHandle
-     * @throws NoSuchFieldException if the field doesn't exist
-     * @throws IllegalAccessException if the field is not accessible
-     */
-    public static VarHandle varHandle(MethodHandles.Lookup lookup,
-                                      String name,
-                                      Class<?> constantType,
-                                      int kind,
-                                      Class<?> owner,
-                                      String fieldName,
-                                      Class<?> type) throws NoSuchFieldException, IllegalAccessException {
-        switch (kind) {
-            case VH_instanceField: return lookup.findVarHandle(owner, fieldName, type);
-            case VH_staticField: return lookup.findStaticVarHandle(owner, fieldName, type);
-            case VH_arrayHandle: return MethodHandles.arrayElementVarHandle(type);
-            default: throw new IllegalArgumentException(String.format("Invalid VarHandle kind: %d", kind));
+                if (!coordType.isArray()) {
+                    try {
+                        return lookup.findVarHandle(coordType, name, variableType);
+                    }
+                    catch (ReflectiveOperationException e) {
+                        throw mapLookupExceptionToError(e);
+                    }
+                }
+                else if (coordType.getComponentType() == variableType) {
+                    return MethodHandles.arrayElementVarHandle(coordType);
+                }
+                break;
+            }
+            case 2: {
+                if (getter.returnType().isPrimitive() && getter.parameterType(1) == int.class) {
+                    Class<?> viewArrayClass = (Class<?>) args[0];
+                    ByteOrder byteOrder = (ByteOrder) args[1];
+                    if (getter.parameterType(0) == byte[].class) {
+                        return MethodHandles.byteArrayViewVarHandle(viewArrayClass, byteOrder);
+                    }
+                    else if (getter.parameterType(0) == ByteBuffer.class) {
+                        return MethodHandles.byteBufferViewVarHandle(viewArrayClass, byteOrder);
+                    }
+                }
+                break;
+            }
+            default:
+                // Fall through
         }
+        throw new IllegalArgumentException();
     }
 }
--- a/src/java.base/share/classes/java/lang/invoke/ClassRef.java	Tue Oct 17 17:48:27 2017 -0400
+++ b/src/java.base/share/classes/java/lang/invoke/ClassRef.java	Tue Oct 17 16:39:22 2017 -0700
@@ -240,6 +240,33 @@
         return ofDescriptor(descriptor.substring(1));
     }
 
+    /**
+     * If this ref is a primitive class then return the boxed class, otherwise
+     * return this.
+     * @return the promoted class
+     */
+    @TrackableConstant
+    ClassRef promote() {
+        if (isPrimitive()) {
+            switch (descriptor) {
+                case "I": return CR_Integer;
+                case "J": return CR_Long;
+                case "F": return CR_Float;
+                case "D": return CR_Double;
+                case "S": return CR_Short;
+                case "B": return CR_Byte;
+                case "C": return CR_Character;
+                case "Z": return CR_Boolean;
+                case "V": return CR_Void;
+                default:
+                    throw new InternalError("Unreachable");
+            }
+        }
+        else {
+            return this;
+        }
+    }
+
     @Override
     @TrackableConstant
     public String descriptorString() {
--- a/src/java.base/share/classes/java/lang/invoke/Constables.java	Tue Oct 17 17:48:27 2017 -0400
+++ b/src/java.base/share/classes/java/lang/invoke/Constables.java	Tue Oct 17 16:39:22 2017 -0700
@@ -34,13 +34,14 @@
 public class Constables {
     static final ClassRef CLASS_CONDY = ClassRef.of("java.lang.invoke.Bootstraps");
 
-    static final MethodHandleRef BSM_PRIMITIVE
-            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "primitiveClass", ClassRef.CR_Class);
-    static final MethodHandleRef BSM_DEFAULT
+    static final MethodHandleRef BSM_GET_SATIC_FINAL_SELF
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "getStaticFinal", ClassRef.CR_Object);
+    static final MethodHandleRef BSM_GET_SATIC_FINAL_DECL
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "getStaticFinal", ClassRef.CR_Object, ClassRef.CR_Class);
+    static final MethodHandleRef BSM_DEFAULT_VALUE
             = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "defaultValue", ClassRef.CR_Object);
     static final MethodHandleRef BSM_VARHANDLE
-            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "varHandle",
-                                               ClassRef.CR_VarHandle, ClassRef.CR_int, ClassRef.CR_Class, ClassRef.CR_String, ClassRef.CR_Class);
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "varHandle", ClassRef.CR_VarHandle, ClassRef.CR_MethodType, ClassRef.CR_Object.array());
 
     static final ConstantRef<?> NULL = ConstantRef.ofNull();
 
@@ -94,20 +95,25 @@
                      .toArray();
     }
 
-    /** Returns a {@link ConstantRef}, if the argument is not a {@link ClassRef}
-     *  then the argument is returned unchanged. If the argument is a {@link ClassRef}
-     *  and it is a primitive {@link ClassRef}, then a fresh {@link DynamicConstantRef}
-     *  corresponding to it is created and returned.
+    /**
+     * Returns a {@link ConstantRef}, if the argument is not a {@link ClassRef}
+     * then the argument is returned unchanged. If the argument is a {@link ClassRef}
+     * and it is a primitive {@link ClassRef}, then a fresh {@link DynamicConstantRef}
+     * corresponding to it is created and returned.
      *
-     *  @param <T> The type of the object described by the {@link ConstantRef}
-     *  @param ref the given {@link ConstantRef}
-     *  @return the reduced {@link ConstantRef}
+     * @param <T> The type of the object described by the {@link ConstantRef}
+     * @param ref the given {@link ConstantRef}
+     * @return the reduced {@link ConstantRef}
      */
     public static<T> ConstantRef<T> reduce(ConstantRef<T> ref) {
         if (ref instanceof ClassRef) {
             ClassRef cr = (ClassRef) ref;
-            if (cr.isPrimitive())
-                return DynamicConstantRef.of(Constables.BSM_PRIMITIVE, cr.descriptorString());
+            if (cr.isPrimitive()) {
+                // Return a dynamic constant whose value is obtained by getting
+                // static final TYPE field on the boxed class
+                return DynamicConstantRef.of(BootstrapSpecifier.of(BSM_GET_SATIC_FINAL_DECL, cr.promote()),
+                                             "TYPE", ClassRef.CR_Class);
+            }
         }
         return ref;
     }
@@ -120,5 +126,4 @@
     static String classToDescriptor(Class<?> clazz) {
         return MethodType.methodType(clazz).toMethodDescriptorString().substring(2);
     }
-}
-
+}
\ No newline at end of file
--- a/src/java.base/share/classes/java/lang/invoke/ConstantRef.java	Tue Oct 17 17:48:27 2017 -0400
+++ b/src/java.base/share/classes/java/lang/invoke/ConstantRef.java	Tue Oct 17 16:39:22 2017 -0700
@@ -26,10 +26,6 @@
 
 import java.lang.annotation.TrackableConstant;
 
-import static java.lang.invoke.Bootstraps.VH_arrayHandle;
-import static java.lang.invoke.Bootstraps.VH_instanceField;
-import static java.lang.invoke.Bootstraps.VH_staticField;
-
 /**
  * Purely-nominal descriptor for a constant value expressible in a classfile
  * constant pool.
@@ -71,7 +67,7 @@
      */
     @TrackableConstant
     static<T> ConstantRef<T> ofNull() {
-        return DynamicConstantRef.of(BootstrapSpecifier.of(Constables.BSM_DEFAULT), "_", ClassRef.CR_Object);
+        return DynamicConstantRef.of(BootstrapSpecifier.of(Constables.BSM_DEFAULT_VALUE), ClassRef.CR_Object);
     }
 
     /**
@@ -82,7 +78,9 @@
      * @return the VarHandle
      */
     static ConstantRef<VarHandle> fieldVarHandle(ClassRef owner, String name, ClassRef type) {
-        return DynamicConstantRef.of(BootstrapSpecifier.of(Constables.BSM_VARHANDLE, VH_instanceField, owner, name, type));
+        return DynamicConstantRef.of(
+                BootstrapSpecifier.of(Constables.BSM_VARHANDLE, MethodTypeRef.of(type, owner)),
+                name);
     }
 
     /**
@@ -93,7 +91,9 @@
      * @return the VarHandle
      */
     static ConstantRef<VarHandle> staticFieldVarHandle(ClassRef owner, String name, ClassRef type) {
-        return DynamicConstantRef.of(BootstrapSpecifier.of(Constables.BSM_VARHANDLE, VH_staticField, owner, name, type));
+        return DynamicConstantRef.of(
+                BootstrapSpecifier.of(Constables.BSM_VARHANDLE, MethodTypeRef.of(type), owner),
+                name);
     }
 
     /**
@@ -102,7 +102,8 @@
      * @return the VarHandle
      */
     static ConstantRef<VarHandle> arrayVarHandle(ClassRef arrayClass) {
-        return DynamicConstantRef.of(BootstrapSpecifier.of(Constables.BSM_VARHANDLE, VH_arrayHandle, Constables.NULL, Constables.NULL, arrayClass));
+        return DynamicConstantRef.of(
+                BootstrapSpecifier.of(Constables.BSM_VARHANDLE, MethodTypeRef.of(arrayClass.componentType(), arrayClass)));
     }
 
     /**
--- a/test/jdk/java/lang/invoke/CondyBootstrapsTest.java	Tue Oct 17 17:48:27 2017 -0400
+++ b/test/jdk/java/lang/invoke/CondyBootstrapsTest.java	Tue Oct 17 16:39:22 2017 -0700
@@ -25,7 +25,6 @@
 
 import java.lang.invoke.BootstrapSpecifier;
 import java.lang.invoke.ClassRef;
-import java.lang.invoke.Bootstraps;
 import java.lang.invoke.DynamicConstantRef;
 import java.lang.invoke.Intrinsics;
 import java.lang.invoke.MethodHandleRef;
@@ -49,17 +48,16 @@
  */
 @Test
 public class CondyBootstrapsTest {
-    public static final ClassRef BOOTSTRAP_CLASS = ClassRef.of("java.lang.invoke.Bootstraps");
+    static final ClassRef CLASS_CONDY = ClassRef.of("java.lang.invoke.Bootstraps");
 
-    private static final MethodHandleRef BSM_DEFAULT_VALUE
-            = MethodHandleRef.ofCondyBootstrap(BOOTSTRAP_CLASS, "defaultValue", ClassRef.CR_Object);
-
-    private static final MethodHandleRef BSM_PRIMITIVE_CLASS
-            = MethodHandleRef.ofCondyBootstrap(BOOTSTRAP_CLASS, "primitiveClass", ClassRef.CR_Class);
-
-    private static final MethodHandleRef varHandleBSM
-            = MethodHandleRef.ofCondyBootstrap(BOOTSTRAP_CLASS, "varHandle",
-                                               ClassRef.CR_VarHandle, ClassRef.CR_int, ClassRef.CR_Class, ClassRef.CR_String, ClassRef.CR_Class);
+    static final MethodHandleRef BSM_GET_SATIC_FINAL_SELF
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "getStaticFinal", ClassRef.CR_Object);
+    static final MethodHandleRef BSM_GET_SATIC_FINAL_DECL
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "getStaticFinal", ClassRef.CR_Object, ClassRef.CR_Class);
+    static final MethodHandleRef BSM_DEFAULT_VALUE
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "defaultValue", ClassRef.CR_Object);
+    static final MethodHandleRef BSM_VARHANDLE
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "varHandle", ClassRef.CR_VarHandle, ClassRef.CR_MethodType, ClassRef.CR_Object.array());
 
     public void testDefaultValueBootstrap() {
         Object supposedlyNull = Intrinsics.ldc(DynamicConstantRef.of(BSM_DEFAULT_VALUE, ClassRef.CR_Object));
@@ -79,32 +77,35 @@
         assertTrue(!supposedlyFalseToo);
     }
 
-    public void testPrimitiveClassBootstrap() {
-        assertEquals(int.class, Intrinsics.ldc(DynamicConstantRef.<Class<?>>of(BSM_PRIMITIVE_CLASS, "I")));
-        assertEquals(long.class, Intrinsics.ldc(DynamicConstantRef.<Class<?>>of(BSM_PRIMITIVE_CLASS, "J")));
-        assertEquals(short.class, Intrinsics.ldc(DynamicConstantRef.<Class<?>>of(BSM_PRIMITIVE_CLASS, "S")));
-        assertEquals(byte.class, Intrinsics.ldc(DynamicConstantRef.<Class<?>>of(BSM_PRIMITIVE_CLASS, "B")));
-        assertEquals(char.class, Intrinsics.ldc(DynamicConstantRef.<Class<?>>of(BSM_PRIMITIVE_CLASS, "C")));
-        assertEquals(float.class, Intrinsics.ldc(DynamicConstantRef.<Class<?>>of(BSM_PRIMITIVE_CLASS, "F")));
-        assertEquals(double.class, Intrinsics.ldc(DynamicConstantRef.<Class<?>>of(BSM_PRIMITIVE_CLASS, "D")));
-        assertEquals(boolean.class, Intrinsics.ldc(DynamicConstantRef.<Class<?>>of(BSM_PRIMITIVE_CLASS, "Z")));
-        assertEquals(void.class, Intrinsics.ldc(DynamicConstantRef.<Class<?>>of(BSM_PRIMITIVE_CLASS, "V")));
+    public void testStaticFinalDecl() {
+        DynamicConstantRef<Class<Integer>> intClass =
+                DynamicConstantRef.of(BootstrapSpecifier.of(BSM_GET_SATIC_FINAL_DECL, ClassRef.CR_Integer),
+                                      "TYPE", ClassRef.CR_Class);
+        Class<Integer> c = Intrinsics.ldc(intClass);
+        assertEquals(c, int.class);
+    }
+
+    public void testStaticFinalSelf() {
+        DynamicConstantRef<Integer> integerMaxValue = DynamicConstantRef.of(BootstrapSpecifier.of(BSM_GET_SATIC_FINAL_SELF),
+                                                                            "MAX_VALUE", ClassRef.CR_int);
+        int v = Intrinsics.ldc(integerMaxValue);
+        assertEquals(v, Integer.MAX_VALUE);
     }
 
     public void testVarHandleBootstrap() {
         ClassRef helperClass = ClassRef.of("CondyTestHelper");
         ClassRef stringClass = ClassRef.CR_String;
-        VarHandle fh = Intrinsics.ldc(DynamicConstantRef.of(BootstrapSpecifier.of(varHandleBSM, Bootstraps.VH_instanceField, helperClass, "f", stringClass)));
-        VarHandle sfh = Intrinsics.ldc(DynamicConstantRef.of(BootstrapSpecifier.of(varHandleBSM, Bootstraps.VH_staticField, helperClass, "sf", stringClass)));
+        VarHandle fh = Intrinsics.ldc(DynamicConstantRef.of(BootstrapSpecifier.of(BSM_VARHANDLE, MethodTypeRef.of(stringClass, helperClass)), "f"));
+        VarHandle sfh = Intrinsics.ldc(DynamicConstantRef.of(BootstrapSpecifier.of(BSM_VARHANDLE, MethodTypeRef.of(stringClass), helperClass), "sf"));
 
         assertEquals(null, sfh.get());
         sfh.set("42");
-        assertEquals("42", sfh.get());
+        assertEquals(sfh.get(), "42");
 
         CondyTestHelper instance = new CondyTestHelper();
         assertEquals(null, fh.get(instance));
         fh.set(instance, "42");
-        assertEquals("42", fh.get(instance));
+        assertEquals(fh.get(instance), "42");
     }
 }