changeset 47442:c31a6355bd81 condy-folding

Refine bootstraps, more tests.
author psandoz
date Wed, 18 Oct 2017 16:08:37 -0500
parents a98cd9df2724
children 14b4ecde7b20
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 test/jdk/java/lang/invoke/ConstablesTest.java
diffstat 6 files changed, 186 insertions(+), 141 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/invoke/Bootstraps.java	Wed Oct 18 16:19:46 2017 -0400
+++ b/src/java.base/share/classes/java/lang/invoke/Bootstraps.java	Wed Oct 18 16:08:37 2017 -0500
@@ -26,8 +26,6 @@
 
 import sun.invoke.util.Wrapper;
 
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 import java.util.AbstractMap;
 import java.util.List;
 import java.util.Map;
@@ -81,9 +79,13 @@
      * @param name the descriptor (JVMS 4.3) of the desired primitive type
      * @param type the required result type (must be {@code Class.class})
      * @return the {@link Class} mirror
-     * @throws IllegalArgumentException if no such value exists
+     * @throws IllegalArgumentException if the name is not a descriptor for a
+     *         primitive type
      */
-    public static Class<?> primitiveClass(Lookup lookup, String name, Class<Class<?>> type) {
+    @SuppressWarnings("rawtypes")
+    public static Class<?> primitiveClass(Lookup lookup, String name, Class<Class> type) {
+        if (name == null || name.length() == 0 || name.length() > 1)
+            throw new IllegalArgumentException("not primitive: " + name);
         return Wrapper.forPrimitiveType(name.charAt(0)).primitiveType();
     }
 
@@ -176,15 +178,17 @@
      * @param <T> the type of the value to be returned (or the corresponding box
      *           type, if the type is a primitive type)
      * @return the result of invoking the method handle
-     * @throws IllegalArgumentException if {@code type} is not assignable from
-     * the return type of {@code handle}
+     * @throws WrongMethodTypeException if the type is incompatible with the
+     *         handle's return type
+     * @throws Throwable TODO
      */
     public static <T> T invoke(Lookup lookup, String name, Class<T> type,
                                MethodHandle handle, Object... args) {
-        if (!type.isAssignableFrom(handle.type().returnType())) {
-            throw new IllegalArgumentException();
+        if (type != handle.type().returnType()) {
+            // Convert if the method handle return type and the constanr type
+            // differ
+            handle.asType(handle.type().changeReturnType(type));
         }
-
         try {
             @SuppressWarnings("unchecked")
             T t = (T) handle.invokeWithArguments(args);
@@ -198,81 +202,67 @@
         }
     }
 
-    // ()T
-    // (O)T
-    // (A[])A
-    // (ByteBuffer, int)PT, ByteOrder
-    // (byte[], int)PT, ByteOrder
-
     /**
-     * Find a {@link VarHandle} for an instance field, static field, or an
-     * array type.
+     * Finds a {@link VarHandle} for an instance field.
      *
      * @param lookup the lookup context describing the class performing the
      *               operation (normally stacked by the JVM)
-     * @param name the name of the field for a field {@link VarHandle}; ignored
-     *             for an array {@link VarHandle}
+     * @param name the name of the field
      * @param type unused; must be {@code Class<VarHandle>}
-     * @param getter The type of the desired field or array, encoded as a
-     *               {@code MethodType} for a getter.  In all cases, the return
-     *               type is the type of the varaible to be accessed.  For a
-     *               static field, the getter has no arguments; for an instance
-     *               field, it has one argument which is the type of the
-     *               declaring class; for an array, it has two arguments, the
-     *               the array type and an {@code int} index
-     * @param args X
-     * @return X
+     * @param decl the type declaring the field
+     * @param fieldType the field type
+     * @return the {@code VarHandle}
+     * @throws LinkageError if the {@code VarHandle} cannot be found
+     * @throws NullPointerException if any unused argument is {@code null}
      */
-    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);
+    public static VarHandle varHandleInstanceField(MethodHandles.Lookup lookup, String name, Class<VarHandle> type,
+                                                   Class<?> decl, Class<?> fieldType) {
+        try {
+            return lookup.findVarHandle(decl, name, fieldType);
+        }
+        catch (ReflectiveOperationException e) {
+            throw mapLookupExceptionToError(e);
+        }
+    }
 
-                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
+    /**
+     * Finds a {@link VarHandle} for a static field.
+     *
+     * @param lookup the lookup context describing the class performing the
+     *               operation (normally stacked by the JVM)
+     * @param name the name of the field
+     * @param type unused; must be {@code Class<VarHandle>}
+     * @param decl the type declaring the field
+     * @param fieldType the field type
+     * @return the handle
+     * @throws LinkageError if the {@code VarHandle} cannot be found
+     * @throws NullPointerException if any unused argument is {@code null}
+     */
+    public static VarHandle varHandleStaticField(MethodHandles.Lookup lookup, String name, Class<VarHandle> type,
+                                                 Class<?> decl, Class<?> fieldType) {
+        try {
+            return lookup.findStaticVarHandle(decl, name, fieldType);
         }
-        throw new IllegalArgumentException();
+        catch (ReflectiveOperationException e) {
+            throw mapLookupExceptionToError(e);
+        }
+    }
+
+    /**
+     * Finds a {@link VarHandle} for an array type.
+     *
+     * @param lookup unused; the lookup context describing the class performing
+     *               the operation (normally stacked by the JVM)
+     * @param name unused
+     * @param type unused; must be {@code Class<VarHandle>}
+     * @param arrayClass the array type
+     * @return the handle
+     * @throws IllegalArgumentException if arrayClass is not an array type
+     * @throws NullPointerException if any unused argument is {@code null}
+     */
+    public static VarHandle varHandleArray(MethodHandles.Lookup lookup, String name, Class<VarHandle> type,
+                                           Class<?> arrayClass) {
+        return MethodHandles.arrayElementVarHandle(arrayClass);
     }
 
     /**
--- a/src/java.base/share/classes/java/lang/invoke/ClassRef.java	Wed Oct 18 16:19:46 2017 -0400
+++ b/src/java.base/share/classes/java/lang/invoke/ClassRef.java	Wed Oct 18 16:08:37 2017 -0500
@@ -24,13 +24,13 @@
  */
 package java.lang.invoke;
 
+import sun.invoke.util.Wrapper;
+
 import java.lang.annotation.TrackableConstant;
 import java.lang.reflect.Array;
 import java.util.regex.Pattern;
 import java.util.stream.Stream;
 
-import sun.invoke.util.Wrapper;
-
 import static java.util.stream.Collectors.joining;
 
 /**
@@ -193,8 +193,7 @@
                : ClassRef.ofDescriptor(descriptor.substring(0, descriptor.length() - 1) + "$" + firstInnerName
                                        + Stream.of(moreInnerNames).collect(joining("$", "$", "")) + ";");
     }
-
-
+        
     /**
      * Returns whether this {@linkplain ClassRef}
      * describes an array type
@@ -229,33 +228,6 @@
         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	Wed Oct 18 16:19:46 2017 -0400
+++ b/src/java.base/share/classes/java/lang/invoke/Constables.java	Wed Oct 18 16:08:37 2017 -0500
@@ -34,14 +34,16 @@
 public class Constables {
     static final ClassRef CLASS_CONDY = ClassRef.of("java.lang.invoke.Bootstraps");
 
-    static final MethodHandleRef BSM_GET_STATIC_FINAL_SELF
-            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "getStaticFinal", ClassRef.CR_Object);
-    static final MethodHandleRef BSM_GET_STATIC_FINAL_DECL
-            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "getStaticFinal", ClassRef.CR_Object, ClassRef.CR_Class);
+    static final MethodHandleRef BSM_PRIMITIVE_CLASS
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "primitiveClass", 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());
+    static final MethodHandleRef BSM_VARHANDLE_INSTANCE_FIELD
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "varHandleInstanceField", ClassRef.CR_VarHandle, ClassRef.CR_Class, ClassRef.CR_Class);
+    static final MethodHandleRef BSM_VARHANDLE_STATIC_FIELD
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "varHandleStaticField", ClassRef.CR_VarHandle, ClassRef.CR_Class, ClassRef.CR_Class);
+    static final MethodHandleRef BSM_VARHANDLE_ARRAY
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "varHandleArray", ClassRef.CR_VarHandle, ClassRef.CR_Class);
 
     static final ConstantRef<?> NULL = ConstantRef.ofNull();
 
@@ -109,10 +111,7 @@
         if (ref instanceof ClassRef) {
             ClassRef cr = (ClassRef) ref;
             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_STATIC_FINAL_DECL, cr.promote()),
-                                             "TYPE", ClassRef.CR_Class);
+                return DynamicConstantRef.of(BootstrapSpecifier.of(BSM_PRIMITIVE_CLASS), cr.descriptorString());
             }
         }
         return ref;
--- a/src/java.base/share/classes/java/lang/invoke/ConstantRef.java	Wed Oct 18 16:19:46 2017 -0400
+++ b/src/java.base/share/classes/java/lang/invoke/ConstantRef.java	Wed Oct 18 16:08:37 2017 -0500
@@ -79,7 +79,7 @@
      */
     static ConstantRef<VarHandle> fieldVarHandle(ClassRef owner, String name, ClassRef type) {
         return DynamicConstantRef.of(
-                BootstrapSpecifier.of(Constables.BSM_VARHANDLE, MethodTypeRef.of(type, owner)),
+                BootstrapSpecifier.of(Constables.BSM_VARHANDLE_INSTANCE_FIELD, owner, type),
                 name);
     }
 
@@ -92,7 +92,7 @@
      */
     static ConstantRef<VarHandle> staticFieldVarHandle(ClassRef owner, String name, ClassRef type) {
         return DynamicConstantRef.of(
-                BootstrapSpecifier.of(Constables.BSM_VARHANDLE, MethodTypeRef.of(type), owner),
+                BootstrapSpecifier.of(Constables.BSM_VARHANDLE_STATIC_FIELD, owner, type),
                 name);
     }
 
@@ -103,7 +103,7 @@
      */
     static ConstantRef<VarHandle> arrayVarHandle(ClassRef arrayClass) {
         return DynamicConstantRef.of(
-                BootstrapSpecifier.of(Constables.BSM_VARHANDLE, MethodTypeRef.of(arrayClass.componentType(), arrayClass)));
+                BootstrapSpecifier.of(Constables.BSM_VARHANDLE_ARRAY, arrayClass));
     }
 
     /**
--- a/test/jdk/java/lang/invoke/CondyBootstrapsTest.java	Wed Oct 18 16:19:46 2017 -0400
+++ b/test/jdk/java/lang/invoke/CondyBootstrapsTest.java	Wed Oct 18 16:08:37 2017 -0500
@@ -24,12 +24,15 @@
  */
 
 import java.lang.invoke.BootstrapSpecifier;
+import java.lang.invoke.Bootstraps;
 import java.lang.invoke.ClassRef;
 import java.lang.invoke.DynamicConstantRef;
 import java.lang.invoke.Intrinsics;
 import java.lang.invoke.MethodHandleRef;
+import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodTypeRef;
 import java.lang.invoke.VarHandle;
+import java.util.List;
 
 import org.testng.annotations.Test;
 
@@ -37,7 +40,6 @@
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
 
 /**
  * @test
@@ -50,33 +52,81 @@
 public class CondyBootstrapsTest {
     static final ClassRef CLASS_CONDY = ClassRef.of("java.lang.invoke.Bootstraps");
 
+    static final MethodHandleRef BSM_PRIMITIVE_CLASS
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "primitiveClass", ClassRef.CR_Class);
+    static final MethodHandleRef BSM_DEFAULT_VALUE
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "defaultValue", ClassRef.CR_Object);
     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());
+    static final MethodHandleRef BSM_INVOKE
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "invoke", ClassRef.CR_Object, ClassRef.CR_MethodHandle, ClassRef.CR_Object.array());
+    static final MethodHandleRef BSM_VARHANDLE_INSTANCE_FIELD
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "varHandleInstanceField", ClassRef.CR_VarHandle, ClassRef.CR_Class, ClassRef.CR_Class);
+    static final MethodHandleRef BSM_VARHANDLE_STATIC_FIELD
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "varHandleStaticField", ClassRef.CR_VarHandle, ClassRef.CR_Class, ClassRef.CR_Class);
+    static final MethodHandleRef BSM_VARHANDLE_ARRAY
+            = MethodHandleRef.ofCondyBootstrap(CLASS_CONDY, "varHandleArray", ClassRef.CR_VarHandle, ClassRef.CR_Class);
 
     public void testDefaultValueBootstrap() {
         Object supposedlyNull = Intrinsics.ldc(DynamicConstantRef.of(BSM_DEFAULT_VALUE, ClassRef.CR_Object));
         assertNull(supposedlyNull);
 
         DynamicConstantRef<Integer> defaultInt = DynamicConstantRef.of(BSM_DEFAULT_VALUE, ClassRef.CR_int);
-        DynamicConstantRef<Boolean> defaultBoolean = DynamicConstantRef.of(BSM_DEFAULT_VALUE, ClassRef.CR_boolean);
-
-        int supposedlyZero = Intrinsics.ldc(defaultInt);
-        int supposedlyZeroToo = (int) ldc(defaultInt);
-        boolean supposedlyFalse = Intrinsics.ldc(defaultBoolean);
-        boolean supposedlyFalseToo = (boolean) ldc(defaultBoolean);
-
+        int supposedlyZero = ldc(defaultInt);
+        int supposedlyZeroToo = ldc(defaultInt);
         assertEquals(supposedlyZero, 0);
         assertEquals(supposedlyZeroToo, 0);
+
+        DynamicConstantRef<Boolean> defaultBoolean = DynamicConstantRef.of(BSM_DEFAULT_VALUE, ClassRef.CR_boolean);
+        boolean supposedlyFalse = ldc(defaultBoolean);
+        boolean supposedlyFalseToo = ldc(defaultBoolean);
         assertTrue(!supposedlyFalse);
         assertTrue(!supposedlyFalseToo);
     }
 
+    public void testPrimitiveClass() {
+        assertEquals(ldc(DynamicConstantRef.of(BootstrapSpecifier.of(BSM_PRIMITIVE_CLASS), ClassRef.CR_int.descriptorString())),
+                     int.class);
+        assertEquals(ldc(DynamicConstantRef.of(BootstrapSpecifier.of(BSM_PRIMITIVE_CLASS), ClassRef.CR_long.descriptorString())),
+                     long.class);
+        assertEquals(ldc(DynamicConstantRef.of(BootstrapSpecifier.of(BSM_PRIMITIVE_CLASS), ClassRef.CR_short.descriptorString())),
+                     short.class);
+        assertEquals(ldc(DynamicConstantRef.of(BootstrapSpecifier.of(BSM_PRIMITIVE_CLASS), ClassRef.CR_byte.descriptorString())),
+                     byte.class);
+        assertEquals(ldc(DynamicConstantRef.of(BootstrapSpecifier.of(BSM_PRIMITIVE_CLASS), ClassRef.CR_char.descriptorString())),
+                     char.class);
+        assertEquals(ldc(DynamicConstantRef.of(BootstrapSpecifier.of(BSM_PRIMITIVE_CLASS), ClassRef.CR_float.descriptorString())),
+                     float.class);
+        assertEquals(ldc(DynamicConstantRef.of(BootstrapSpecifier.of(BSM_PRIMITIVE_CLASS), ClassRef.CR_double.descriptorString())),
+                     double.class);
+        assertEquals(ldc(DynamicConstantRef.of(BootstrapSpecifier.of(BSM_PRIMITIVE_CLASS), ClassRef.CR_boolean.descriptorString())),
+                     boolean.class);
+        assertEquals(ldc(DynamicConstantRef.of(BootstrapSpecifier.of(BSM_PRIMITIVE_CLASS), ClassRef.CR_void.descriptorString())),
+                     void.class);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testPrimitiveClassNullName() {
+        Bootstraps.primitiveClass(MethodHandles.lookup(), null, Class.class);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testPrimitiveClassEmptyName() {
+        Bootstraps.primitiveClass(MethodHandles.lookup(), "", Class.class);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testPrimitiveClassWrongNameChar() {
+        Bootstraps.primitiveClass(MethodHandles.lookup(), "L", Class.class);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testPrimitiveClassWrongNameString() {
+        Bootstraps.primitiveClass(MethodHandles.lookup(), "Ljava/lang/Object;", Class.class);
+    }
+
     public void testStaticFinalDecl() {
         DynamicConstantRef<Class<Integer>> intClass =
                 DynamicConstantRef.of(BootstrapSpecifier.of(BSM_GET_SATIC_FINAL_DECL, ClassRef.CR_Integer),
@@ -92,21 +142,56 @@
         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(BSM_VARHANDLE, MethodTypeRef.of(stringClass, helperClass)), "f"));
-        VarHandle sfh = Intrinsics.ldc(DynamicConstantRef.of(BootstrapSpecifier.of(BSM_VARHANDLE, MethodTypeRef.of(stringClass), helperClass), "sf"));
+    public void testInvoke() {
+        DynamicConstantRef<List<Integer>> list = DynamicConstantRef.of(
+                BootstrapSpecifier.of(BSM_INVOKE,
+                                      MethodHandleRef.of(MethodHandleRef.Kind.STATIC, ClassRef.CR_List, "of", ClassRef.CR_List, ClassRef.CR_Object.array()),
+                                      1, 2, 3, 4),
+                ClassRef.CR_List);
 
-        assertEquals(null, sfh.get());
-        sfh.set("42");
-        assertEquals(sfh.get(), "42");
+        List<Integer> l = ldc(list);
+        assertEquals(l, List.of(1, 2, 3, 4));
+    }
+
+    public void testInvokeAsType() {
+        DynamicConstantRef<Integer> valueOf = DynamicConstantRef.of(
+                BootstrapSpecifier.of(BSM_INVOKE,
+                                      MethodHandleRef.of(MethodHandleRef.Kind.STATIC, ClassRef.CR_Integer, "valueOf", ClassRef.CR_Integer, ClassRef.CR_String),
+                                      "42"),
+                ClassRef.CR_int);
+
+        int v = ldc(valueOf);
+        assertEquals(v, 42);
+    }
+
+    public void testVarHandleInstanceField() {
+        VarHandle fh = Intrinsics.ldc(DynamicConstantRef.of(
+                BootstrapSpecifier.of(BSM_VARHANDLE_INSTANCE_FIELD, ClassRef.of("CondyTestHelper"), ClassRef.CR_String), "f"));
 
         CondyTestHelper instance = new CondyTestHelper();
         assertEquals(null, fh.get(instance));
         fh.set(instance, "42");
         assertEquals(fh.get(instance), "42");
     }
+
+    public void testVarHandleStaticField() {
+        VarHandle sfh = Intrinsics.ldc(DynamicConstantRef.of(
+                BootstrapSpecifier.of(BSM_VARHANDLE_STATIC_FIELD, ClassRef.of("CondyTestHelper"), ClassRef.CR_String), "sf"));
+
+        assertEquals(null, sfh.get());
+        sfh.set("42");
+        assertEquals(sfh.get(), "42");
+    }
+
+    public void testVarHandleArray() {
+        VarHandle ah = Intrinsics.ldc(DynamicConstantRef.of(
+                BootstrapSpecifier.of(BSM_VARHANDLE_ARRAY, ClassRef.CR_String.array())));
+
+        String[] sa = { "A" };
+        assertEquals("A", ah.get(sa, 0));
+        ah.set(sa, 0, "B");
+        assertEquals(ah.get(sa, 0), "B");
+    }
 }
 
 class CondyTestHelper {
--- a/test/jdk/java/lang/invoke/ConstablesTest.java	Wed Oct 18 16:19:46 2017 -0400
+++ b/test/jdk/java/lang/invoke/ConstablesTest.java	Wed Oct 18 16:08:37 2017 -0500
@@ -285,7 +285,6 @@
         ClassRef thisClass = ClassRef.of("ConstablesTest");
         ClassRef testClass = thisClass.inner("TestClass");
         ClassRef testInterface = thisClass.inner("TestInterface");
-
         // ctor
         MethodHandleRef ctorRef = MethodHandleRef.of(MethodHandleRef.Kind.CONSTRUCTOR, testClass, "<ignored!>", MethodTypeRef.ofDescriptor("()V"));
         MethodHandleRef staticMethodRef = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, testClass, "sm", "(I)I");