changeset 13818:d2f520f46180

added more unit tests for meta.api, discovering and fixing an issue with HotSpotResolvedJavaField.getModifiers() in the process
author Doug Simon <doug.simon@oracle.com>
date Thu, 30 Jan 2014 00:48:41 +0100
parents d7ed39d0a6d9
children 49db2c1e3bee
files graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/FieldUniverse.java graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestJavaField.java graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestMetaAccessProvider.java graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java src/share/vm/graal/vmStructs_graal.hpp src/share/vm/runtime/vmStructs.cpp
diffstat 12 files changed, 325 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/FieldUniverse.java	Thu Jan 30 00:48:41 2014 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013, 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.
+ *
+ * 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 com.oracle.graal.api.meta.test;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Context for field related api.meta tests.
+ */
+public class FieldUniverse extends TypeUniverse {
+
+    public final Map<Field, ResolvedJavaField> fields = new HashMap<>();
+
+    public FieldUniverse() {
+        for (Class c : classes) {
+            for (Field f : c.getDeclaredFields()) {
+                ResolvedJavaField field = metaAccess.lookupJavaField(f);
+                fields.put(f, field);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestJavaField.java	Thu Jan 30 00:48:41 2014 +0100
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ *
+ * 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 com.oracle.graal.api.meta.test;
+
+import static org.junit.Assert.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Tests for {@link JavaField}.
+ */
+public class TestJavaField extends FieldUniverse {
+
+    @Test
+    public void getNameTest() {
+        for (Map.Entry<Field, ResolvedJavaField> e : fields.entrySet()) {
+            String expected = e.getKey().getName();
+            String actual = e.getValue().getName();
+            assertEquals(expected, actual);
+        }
+    }
+
+    @Test
+    public void getTypeTest() {
+        for (Map.Entry<Field, ResolvedJavaField> e : fields.entrySet()) {
+            // Must resolve types first as a resolved types != unresolved types
+            ResolvedJavaField rf = e.getValue();
+            JavaType expected = metaAccess.lookupJavaType(e.getKey().getType()).resolve(rf.getDeclaringClass());
+            JavaType actual = rf.getType().resolve(rf.getDeclaringClass());
+            assertEquals(expected, actual);
+        }
+    }
+
+    @Test
+    public void getKindTest() {
+        for (Map.Entry<Field, ResolvedJavaField> e : fields.entrySet()) {
+            Kind expected = metaAccess.lookupJavaType(e.getKey().getType()).getKind();
+            Kind actual = e.getValue().getKind();
+            assertEquals(expected, actual);
+        }
+    }
+
+    @Test
+    public void getDeclaringClassTest() {
+        for (Map.Entry<Field, ResolvedJavaField> e : fields.entrySet()) {
+            Class expected = e.getKey().getDeclaringClass();
+            ResolvedJavaType actual = e.getValue().getDeclaringClass();
+            assertTrue(actual.equals(metaAccess.lookupJavaType(expected)));
+        }
+    }
+}
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestMetaAccessProvider.java	Wed Jan 29 15:02:19 2014 -0800
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestMetaAccessProvider.java	Thu Jan 30 00:48:41 2014 +0100
@@ -69,7 +69,7 @@
             for (Field reflect : c.getDeclaredFields()) {
                 ResolvedJavaField field = metaAccess.lookupJavaField(reflect);
                 assertNotNull(field);
-                int expected = reflect.getModifiers() & Modifier.fieldModifiers();
+                int expected = reflect.getModifiers();
                 int actual = field.getModifiers();
                 assertEquals(String.format("%s: 0x%x != 0x%x", reflect, expected, actual), expected, actual);
                 assertTrue(field.getDeclaringClass().equals(metaAccess.lookupJavaType(reflect.getDeclaringClass())));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java	Thu Jan 30 00:48:41 2014 +0100
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ *
+ * 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 com.oracle.graal.api.meta.test;
+
+import static java.lang.reflect.Modifier.*;
+import static org.junit.Assert.*;
+
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Tests for {@link ResolvedJavaField}.
+ */
+public class TestResolvedJavaField extends FieldUniverse {
+
+    public TestResolvedJavaField() {
+    }
+
+    @Test
+    public void getModifiersTest() {
+        for (Map.Entry<Field, ResolvedJavaField> e : fields.entrySet()) {
+            int expected = e.getKey().getModifiers();
+            int actual = e.getValue().getModifiers();
+            assertEquals(expected, actual);
+        }
+    }
+
+    @Test
+    public void isSyntheticTest() {
+        for (Map.Entry<Field, ResolvedJavaField> e : fields.entrySet()) {
+            boolean expected = e.getKey().isSynthetic();
+            boolean actual = e.getValue().isSynthetic();
+            assertEquals(expected, actual);
+        }
+    }
+
+    @Test
+    public void getAnnotationTest() {
+        for (Map.Entry<Field, ResolvedJavaField> e : fields.entrySet()) {
+            for (Annotation expected : e.getKey().getAnnotations()) {
+                if (expected != null) {
+                    Annotation actual = e.getValue().getAnnotation(expected.annotationType());
+                    assertEquals(expected, actual);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void readConstantValueTest() throws NoSuchFieldException {
+        for (Map.Entry<Field, ResolvedJavaField> e : fields.entrySet()) {
+            Field field = e.getKey();
+            if (isStatic(field.getModifiers())) {
+                try {
+                    Object expected = field.get(null);
+                    Object actual = e.getValue().readConstantValue(null).asBoxedValue();
+                    assertEquals(expected, actual);
+                } catch (IllegalArgumentException | IllegalAccessException e1) {
+                }
+            } else {
+                try {
+                    Object receiver = field.getDeclaringClass().newInstance();
+                    Object expected = field.get(receiver);
+                    Object actual = e.getValue().readConstantValue(Constant.forObject(receiver)).asBoxedValue();
+                    assertEquals(expected, actual);
+                } catch (InstantiationException | IllegalArgumentException | IllegalAccessException e1) {
+                }
+            }
+        }
+
+        ResolvedJavaField field = metaAccess.lookupJavaField(getClass().getDeclaredField("stringField"));
+        for (Object receiver : new Object[]{this, null, new String()}) {
+            Constant value = field.readConstantValue(Constant.forObject(receiver));
+            assertNull(value);
+        }
+
+        ResolvedJavaField constField = metaAccess.lookupJavaField(getClass().getDeclaredField("constantStringField"));
+        for (Object receiver : new Object[]{this, null, new String()}) {
+            Constant value = constField.readConstantValue(Constant.forObject(receiver));
+            if (value != null) {
+                Object expected = "constantField";
+                assertTrue(value.asObject() == expected);
+            }
+        }
+    }
+
+    @Test
+    public void readValueTest() throws IllegalArgumentException, IllegalAccessException {
+        for (Map.Entry<Field, ResolvedJavaField> e : fields.entrySet()) {
+            Field field = e.getKey();
+            field.setAccessible(true);
+            if (isStatic(field.getModifiers())) {
+                try {
+                    Object expected = field.get(null);
+                    Object actual = e.getValue().readValue(null).asBoxedValue();
+                    assertEquals(expected, actual);
+                } catch (IllegalArgumentException | IllegalAccessException e1) {
+                }
+            }
+        }
+
+        String testString = "a test string";
+        testString.hashCode(); // create hash
+        for (Field f : String.class.getDeclaredFields()) {
+            f.setAccessible(true);
+            ResolvedJavaField rf = metaAccess.lookupJavaField(f);
+            Object receiver = isStatic(f.getModifiers()) ? null : testString;
+            Object expected = f.get(receiver);
+            Object actual = rf.readValue(receiver == null ? null : Constant.forObject(receiver)).asBoxedValue();
+            assertEquals(expected, actual);
+        }
+    }
+
+    String stringField = "field";
+    final String constantStringField = "constantField";
+
+    private Method findTestMethod(Method apiMethod) {
+        String testName = apiMethod.getName() + "Test";
+        for (Method m : getClass().getDeclaredMethods()) {
+            if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) {
+                return m;
+            }
+        }
+        return null;
+    }
+
+    // @formatter:off
+    private static final String[] untestedApiMethods = {
+        "getDeclaringClass",
+        "isInternal"
+    };
+    // @formatter:on
+
+    /**
+     * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written
+     * for them or are added to {@link #untestedApiMethods}.
+     */
+    @Test
+    public void testCoverage() {
+        Set<String> known = new HashSet<>(Arrays.asList(untestedApiMethods));
+        for (Method m : ResolvedJavaField.class.getDeclaredMethods()) {
+            if (findTestMethod(m) == null) {
+                assertTrue("test missing for " + m, known.contains(m.getName()));
+            } else {
+                assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName()));
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java	Wed Jan 29 15:02:19 2014 -0800
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java	Thu Jan 30 00:48:41 2014 +0100
@@ -40,6 +40,7 @@
 /**
  * Tests for {@link ResolvedJavaType}.
  */
+@SuppressWarnings("unused")
 public class TestResolvedJavaType extends TypeUniverse {
 
     public TestResolvedJavaType() {
@@ -503,7 +504,6 @@
     public ResolvedJavaField lookupField(ResolvedJavaField[] fields, Field key) {
         for (ResolvedJavaField rf : fields) {
             if (fieldsEqual(key, rf)) {
-                assert (fieldModifiers() & key.getModifiers()) == rf.getModifiers() : key + ": " + toHexString(key.getModifiers()) + " != " + toHexString(rf.getModifiers());
                 return rf;
             }
         }
@@ -513,7 +513,6 @@
     public Field lookupField(Set<Field> fields, ResolvedJavaField key) {
         for (Field f : fields) {
             if (fieldsEqual(f, key)) {
-                assert key.getModifiers() == (fieldModifiers() & f.getModifiers()) : key + ": " + toHexString(key.getModifiers()) + " != " + toHexString(f.getModifiers());
                 return f;
             }
         }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Wed Jan 29 15:02:19 2014 -0800
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Thu Jan 30 00:48:41 2014 +0100
@@ -64,7 +64,7 @@
     /**
      * Gets the current value of this field for a given object, if available. There is no guarantee
      * that the same value will be returned by this method for a field unless the field is
-     * considered to be {@link #readConstantValue(Constant)} by the runtime.
+     * considered to be {@linkplain #readConstantValue(Constant) constant} by the runtime.
      * 
      * @param receiver object from which this field's value is to be read. This value is ignored if
      *            this field is static.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Wed Jan 29 15:02:19 2014 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Thu Jan 30 00:48:41 2014 +0100
@@ -29,6 +29,7 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.bridge.*;
+import com.oracle.graal.hotspot.meta.*;
 
 /**
  * Used to access native configuration details.
@@ -999,6 +1000,14 @@
 
     @HotSpotVMConstant(name = "JVM_ACC_HAS_FINALIZER") @Stable public int klassHasFinalizerFlag;
 
+    // Modifier.SYNTHETIC is not public so we get it via vmStructs.
+    @HotSpotVMConstant(name = "JVM_ACC_SYNTHETIC") @Stable public int syntheticFlag;
+
+    /**
+     * @see HotSpotResolvedObjectType#createField
+     */
+    @HotSpotVMConstant(name = "JVM_RECOGNIZED_FIELD_MODIFIERS") @Stable public int recognizedFieldModifiers;
+
     /**
      * Bit pattern that represents a non-oop. Neither the high bits nor the low bits of this value
      * are allowed to look like (respectively) the high or low bits of a real oop.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Wed Jan 29 15:02:19 2014 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Thu Jan 30 00:48:41 2014 +0100
@@ -73,7 +73,7 @@
 
     @Override
     public int getModifiers() {
-        return modifiers & Modifier.fieldModifiers();
+        return modifiers;
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Wed Jan 29 15:02:19 2014 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Thu Jan 30 00:48:41 2014 +0100
@@ -432,23 +432,10 @@
         return javaMethod == null ? null : javaMethod.getAnnotation(annotationClass);
     }
 
-    private static final int SYNTHETIC;
-    static {
-        try {
-            // Unfortunately, Modifier.SYNTHETIC is not public so we have
-            // to jump though hoops to get it.
-            Field field = Modifier.class.getDeclaredField("SYNTHETIC");
-            field.setAccessible(true);
-            SYNTHETIC = field.getInt(null);
-        } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
-            throw GraalInternalError.shouldNotReachHere(e.toString());
-        }
-    }
-
     @Override
     public boolean isSynthetic() {
         int modifiers = getAllModifiers();
-        return (SYNTHETIC & modifiers) != 0;
+        return (runtime().getConfig().syntheticFlag & modifiers) != 0;
     }
 
     public boolean isDefault() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Wed Jan 29 15:02:19 2014 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Thu Jan 30 00:48:41 2014 +0100
@@ -422,10 +422,12 @@
         ResolvedJavaField result = null;
 
         /*
-         * Filter out flags used internally by HotSpot, to get a canonical id value. When a field is
-         * created from a java.lang.reflect.Field, these flags would not be available anyway.
+         * Filter flags to be only those return by Field.getModifiers() to get a canonical id value.
+         * Strangely, Field.getModifiers() uses JVM_RECOGNIZED_FIELD_MODIFIERS in jvm.h instead of
+         * Modifier.fieldModifiers() to mask out HotSpot internal flags.
          */
-        int flags = rawFlags & fieldModifiers();
+        int reflectionFieldModifiers = runtime().getConfig().recognizedFieldModifiers;
+        int flags = rawFlags & reflectionFieldModifiers;
 
         long id = offset + ((long) flags << 32);
 
--- a/src/share/vm/graal/vmStructs_graal.hpp	Wed Jan 29 15:02:19 2014 -0800
+++ b/src/share/vm/graal/vmStructs_graal.hpp	Thu Jan 30 00:48:41 2014 +0100
@@ -34,11 +34,14 @@
 
 #define VM_TYPES_GRAAL(declare_type, declare_toplevel_type)                   \
 
-#define VM_INT_CONSTANTS_GRAAL(declare_constant)                              \
-  declare_constant(Deoptimization::Reason_aliasing)                           \
-  declare_constant(GraalEnv::ok)                                              \
-  declare_constant(GraalEnv::dependencies_failed)                             \
-  declare_constant(GraalEnv::cache_full)                                      \
-  declare_constant(GraalEnv::code_too_large)                                  \
+#define VM_INT_CONSTANTS_GRAAL(declare_constant, declare_preprocessor_constant)                   \
+  declare_constant(Deoptimization::Reason_aliasing)                                               \
+  declare_constant(GraalEnv::ok)                                                                  \
+  declare_constant(GraalEnv::dependencies_failed)                                                 \
+  declare_constant(GraalEnv::cache_full)                                                          \
+  declare_constant(GraalEnv::code_too_large)                                                      \
+                                                                                                  \
+  declare_preprocessor_constant("JVM_ACC_SYNTHETIC", JVM_ACC_SYNTHETIC)                           \
+  declare_preprocessor_constant("JVM_RECOGNIZED_FIELD_MODIFIERS", JVM_RECOGNIZED_FIELD_MODIFIERS) \
 
 #endif // SHARE_VM_GRAAL_VMSTRUCTS_GRAAL_HPP
--- a/src/share/vm/runtime/vmStructs.cpp	Wed Jan 29 15:02:19 2014 -0800
+++ b/src/share/vm/runtime/vmStructs.cpp	Thu Jan 30 00:48:41 2014 +0100
@@ -3060,7 +3060,8 @@
                    GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY)
 
 #ifdef GRAAL
-  VM_INT_CONSTANTS_GRAAL(GENERATE_VM_INT_CONSTANT_ENTRY)
+  VM_INT_CONSTANTS_GRAAL(GENERATE_VM_INT_CONSTANT_ENTRY,
+                         GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY)
 #endif
 
 #if INCLUDE_ALL_GCS