8212934: [JVMCI] do not propagate resolution error in HotSpotResolvedJavaFieldImpl.getType
authordnsimon
Thu, 01 Nov 2018 11:23:12 +0100
changeset 52367 0eedd8701f91
parent 52366 8f543813b402
child 52368 ecef74be8e25
8212934: [JVMCI] do not propagate resolution error in HotSpotResolvedJavaFieldImpl.getType Reviewed-by: kvn
src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java
test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java	Tue Oct 23 14:23:46 2018 -0400
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java	Thu Nov 01 11:23:12 2018 +0100
@@ -125,7 +125,7 @@
         if (currentType instanceof UnresolvedJavaType) {
             // Don't allow unresolved types to hang around forever
             UnresolvedJavaType unresolvedType = (UnresolvedJavaType) currentType;
-            ResolvedJavaType resolved = unresolvedType.resolve(holder);
+            ResolvedJavaType resolved = holder.lookupType(unresolvedType, false);
             if (resolved != null) {
                 type = resolved;
             }
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java	Tue Oct 23 14:23:46 2018 -0400
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java	Thu Nov 01 11:23:12 2018 +0100
@@ -33,10 +33,15 @@
 
 package jdk.vm.ci.runtime.test;
 
-import jdk.vm.ci.meta.ResolvedJavaField;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import org.junit.Test;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
@@ -45,10 +50,13 @@
 import java.util.Map;
 import java.util.Set;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.runtime.test.TestResolvedJavaField.TestClassLoader;
 
 /**
  * Tests for {@link ResolvedJavaField}.
@@ -134,4 +142,89 @@
             }
         }
     }
+    static class TestClassLoader extends ClassLoader {
+
+        @Override
+        protected Class<?> findClass(final String name) {
+            if (!name.equals(TypeWithUnresolvedFieldType.class.getName())) {
+                try {
+                    return super.findClass(name);
+                } catch (ClassNotFoundException e) {
+                    throw new AssertionError("unexpected: " + e);
+                }
+            }
+            // copy classfile to byte array
+            byte[] classData = null;
+            try {
+                String simpleName = TypeWithUnresolvedFieldType.class.getSimpleName();
+                InputStream is = TypeWithUnresolvedFieldType.class.getResourceAsStream(simpleName + ".class");
+                assert is != null;
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+                byte[] buf = new byte[1024];
+                int size;
+                while ((size = is.read(buf, 0, buf.length)) != -1) {
+                    baos.write(buf, 0, size);
+                }
+                baos.flush();
+                classData = baos.toByteArray();
+            } catch (IOException e) {
+                Assert.fail("can't access class: " + name);
+            }
+
+            // replace all occurrences of "PrintStream" in classfile
+            int index = -1;
+
+            while ((index = indexOf(classData, index + 1, "PrintStream")) != -1) {
+                replace(classData, index, "XXXXXXXXXXX");
+            }
+
+            Class<?> c = defineClass(null, classData, 0, classData.length);
+            return c;
+        }
+
+        private static int indexOf(byte[] b, int index, String find) {
+            for (int i = index; i < b.length; i++) {
+                boolean match = true;
+                for (int j = i; j < i + find.length(); j++) {
+                    if (b[j] != (byte) find.charAt(j - i)) {
+                        match = false;
+                        break;
+                    }
+                }
+                if (match) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        private static void replace(byte[] b, int index, String replace) {
+            for (int i = index; i < index + replace.length(); i++) {
+                b[i] = (byte) replace.charAt(i - index);
+            }
+        }
+    }
+
+    /**
+     * Tests that calling {@link ResolvedJavaField#getType()} does not cause a linkage error if the
+     * type of the field is not resolvable.
+     */
+    @Test
+    public void testGetType() {
+        Class<?> c = new TestClassLoader().findClass(TypeWithUnresolvedFieldType.class.getName());
+        ResolvedJavaType type = metaAccess.lookupJavaType(c);
+        for (ResolvedJavaField field : type.getInstanceFields(false)) {
+            assertTrue(field.getName().equals("fieldWithUnresolvableType"));
+            field.getType();
+            field.toString();
+        }
+    }
 }
+
+class TypeWithUnresolvedFieldType {
+    /**
+     * {@link TestClassLoader} will rewrite the type of this field to "Ljava/io/XXXXXXXXXXX;".
+     */
+    PrintStream fieldWithUnresolvableType;
+}