changeset 7037:dd81042f4eb1

added unit tests for ResolvedJavaType replaced some CompilerToVM methods used by HotSpotResolvedJavaType with pure Java code
author Doug Simon <doug.simon@oracle.com>
date Tue, 27 Nov 2012 11:21:48 +0100
parents 8c4b757c2eb9
children adf5c101bc4b ca17d81cfa4b
files graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.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/TestResolvedJavaType.java graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotJavaType.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.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/HotSpotResolvedJavaType.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotTypePrimitive.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotTypeUnresolved.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/IntrinsifyArrayCopyPhase.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java src/share/vm/graal/graalCompilerToVM.cpp
diffstat 27 files changed, 783 insertions(+), 164 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java	Tue Nov 27 11:21:48 2012 +0100
@@ -84,7 +84,7 @@
                         double totalHintProbability = 0.0d;
                         for (ProfiledType ptype : ptypes) {
                             ResolvedJavaType hint = ptype.getType();
-                            if (type != null && hint.isSubtypeOf(type)) {
+                            if (type != null && hint.isAssignableTo(type)) {
                                 hintTypes[hintCount++] = hint;
                                 totalHintProbability += ptype.getProbability();
                             }
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestMetaAccessProvider.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestMetaAccessProvider.java	Tue Nov 27 11:21:48 2012 +0100
@@ -41,29 +41,121 @@
     }
 
     public static final MetaAccessProvider runtime = Graal.getRequiredCapability(MetaAccessProvider.class);
-    public static final List<Class<?>> classes = new ArrayList<>(Arrays.asList(
-        void.class,
-        boolean.class,
-        byte.class,
-        short.class,
-        char.class,
-        int.class,
-        float.class,
-        long.class,
-        double.class,
-        Object.class,
-        Serializable.class,
-        Cloneable.class,
-        Test.class,
-        TestMetaAccessProvider.class
-    ));
+    public static final Collection<Class<?>> classes = new HashSet<>();
+    public static final Map<Class<?>, Class<?>> arrayClasses = new HashMap<>();
+
+    public static synchronized Class<?> getArrayClass(Class componentType) {
+        Class< ? > arrayClass = arrayClasses.get(componentType);
+        if (arrayClass == null) {
+            arrayClass = Array.newInstance(componentType, 0).getClass();
+            arrayClasses.put(componentType, arrayClass);
+        }
+        return arrayClass;
+    }
+
+    public static int dimensions(Class c) {
+        if (c.getComponentType() != null) {
+            return 1 + dimensions(c.getComponentType());
+        }
+        return 0;
+    }
+
+    private static void addClass(Class c) {
+        if (classes.add(c)) {
+            if (c.getSuperclass() != null) {
+                addClass(c.getSuperclass());
+            }
+            for (Class sc : c.getInterfaces()) {
+                addClass(sc);
+            }
+            for (Class dc : c.getDeclaredClasses()) {
+                addClass(dc);
+            }
+            for (Method m : c.getDeclaredMethods()) {
+                addClass(m.getReturnType());
+                for (Class p : m.getParameterTypes()) {
+                    addClass(p);
+                }
+            }
+
+            if (c != void.class && dimensions(c) < 2) {
+                Class<?> arrayClass = Array.newInstance(c, 0).getClass();
+                arrayClasses.put(c, arrayClass);
+                addClass(arrayClass);
+            }
+        }
+    }
 
     static {
-        for (Class<?> c : new ArrayList<>(classes)) {
-            if (c != void.class) {
-                classes.add(Array.newInstance(c, 0).getClass());
+        Class[] initialClasses = {
+                        void.class,
+                        boolean.class,
+                        byte.class,
+                        short.class,
+                        char.class,
+                        int.class,
+                        float.class,
+                        long.class,
+                        double.class,
+                        Object.class,
+                        Class.class,
+                        ClassLoader.class,
+                        String.class,
+                        Serializable.class,
+                        Cloneable.class,
+                        Test.class,
+                        TestMetaAccessProvider.class,
+                        List.class,
+                        Collection.class,
+                        Map.class,
+                        Queue.class,
+                        HashMap.class,
+                        LinkedHashMap.class,
+                        IdentityHashMap.class,
+                        AbstractCollection.class,
+                        AbstractList.class,
+                        ArrayList.class
+        };
+        for (Class c : initialClasses) {
+            addClass(c);
+        }
+    }
+
+    static {
+        System.out.println(classes.size() + " classes");
+    }
+
+    public static final List<Constant> constants = new ArrayList<>();
+    static {
+        for (Field f : Constant.class.getDeclaredFields()) {
+            int mods = f.getModifiers();
+            if (f.getType() == Constant.class && Modifier.isPublic(mods) && Modifier.isStatic(mods) && Modifier.isFinal(mods)) {
+                try {
+                    Constant c = (Constant) f.get(null);
+                    if (c != null) {
+                        constants.add(c);
+                    }
+                } catch (Exception e) {
+                }
             }
         }
+        for (Class c : classes) {
+            if (c != void.class && !c.isArray()) {
+                constants.add(Constant.forObject(Array.newInstance(c, 42)));
+            }
+        }
+        constants.add(Constant.forObject(new ArrayList<>()));
+        constants.add(Constant.forObject(new IdentityHashMap<>()));
+        constants.add(Constant.forObject(new LinkedHashMap<>()));
+        constants.add(Constant.forObject(new TreeMap<>()));
+        constants.add(Constant.forObject(new ArrayDeque<>()));
+        constants.add(Constant.forObject(new LinkedList<>()));
+        constants.add(Constant.forObject("a string"));
+        constants.add(Constant.forObject(42));
+    }
+
+    static {
+        System.out.println(constants.size() + " constants");
     }
 
     @Test
@@ -86,7 +178,9 @@
             for (Method reflect : c.getDeclaredMethods()) {
                 ResolvedJavaMethod method = runtime.lookupJavaMethod(reflect);
                 assertNotNull(method);
-                assertEquals(reflect.getModifiers(), method.getModifiers());
+                int expected = reflect.getModifiers() & Modifier.methodModifiers();
+                int actual = method.getModifiers();
+                assertEquals(String.format("%s: 0x%x != 0x%x", reflect, expected, actual), expected, actual);
                 assertTrue(method.getDeclaringClass().isClass(reflect.getDeclaringClass()));
             }
         }
@@ -98,33 +192,14 @@
             for (Field reflect : c.getDeclaredFields()) {
                 ResolvedJavaField field = runtime.lookupJavaField(reflect);
                 assertNotNull(field);
-                assertEquals(reflect.getModifiers(), field.getModifiers());
+                int expected = reflect.getModifiers() & Modifier.fieldModifiers();
+                int actual = field.getModifiers();
+                assertEquals(String.format("%s: 0x%x != 0x%x", reflect, expected, actual), expected, actual);
                 assertTrue(field.getDeclaringClass().isClass(reflect.getDeclaringClass()));
             }
         }
     }
 
-    public static final List<Constant> constants = new ArrayList<>();
-    static {
-        for (Field f : Constant.class.getDeclaredFields()) {
-            int mods = f.getModifiers();
-            if (f.getType() == Constant.class && Modifier.isPublic(mods) && Modifier.isStatic(mods) && Modifier.isFinal(mods)) {
-                try {
-                    Constant c = (Constant) f.get(null);
-                    if (c != null) {
-                        constants.add(c);
-                    }
-                } catch (Exception e) {
-                }
-            }
-        }
-        for (Class c : classes) {
-            if (c != void.class) {
-                constants.add(Constant.forObject(Array.newInstance(c, 42)));
-            }
-        }
-    }
-
     @Test
     public void lookupJavaTypeConstantTest() {
         for (Constant c : constants) {
--- /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/TestResolvedJavaType.java	Tue Nov 27 11:21:48 2012 +0100
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 2011, 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 com.oracle.graal.api.meta.test.TestMetaAccessProvider.*;
+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 sun.reflect.ConstantPool;
+
+import com.oracle.graal.api.meta.*;
+
+public class TestResolvedJavaType {
+
+    public TestResolvedJavaType() {
+    }
+
+    @Test
+    public void isInterfaceTest() {
+        for (Class c : classes) {
+            ResolvedJavaType type = runtime.lookupJavaType(c);
+            boolean expected = c.isInterface();
+            boolean actual = type.isInterface();
+            assertEquals(expected, actual);
+        }
+    }
+
+
+    @Test
+    public void isInstanceClassTest() {
+        for (Class c : classes) {
+            ResolvedJavaType type = runtime.lookupJavaType(c);
+            boolean expected = !c.isArray() && !c.isPrimitive() && !c.isInterface();
+            boolean actual = type.isInstanceClass();
+            assertEquals(expected, actual);
+        }
+    }
+
+    @Test
+    public void isArrayClassTest() {
+        for (Class c : classes) {
+            ResolvedJavaType type = runtime.lookupJavaType(c);
+            boolean expected = c.isArray();
+            boolean actual = type.isArrayClass();
+            assertEquals(expected, actual);
+        }
+    }
+
+    @Test
+    public void getModifiersTest() {
+        for (Class c : classes) {
+            ResolvedJavaType type = runtime.lookupJavaType(c);
+            int expected = c.getModifiers();
+            int actual = type.getModifiers();
+            assertEquals(expected, actual);
+        }
+    }
+
+    @Test
+    public void isAssignableToTest() {
+        Class[] all = classes.toArray(new Class[classes.size()]);
+        for (int i = 0; i < all.length; i++) {
+            Class<?> c1 = all[i];
+            for (int j = i; j < all.length; j++) {
+                Class<?> c2 = all[j];
+                ResolvedJavaType t1 = runtime.lookupJavaType(c1);
+                ResolvedJavaType t2 = runtime.lookupJavaType(c2);
+                boolean expected = c1.isAssignableFrom(c2);
+                boolean actual = t2.isAssignableTo(t1);
+                assertEquals(expected, actual);
+                if (expected && t1 != t2) {
+                    assertFalse(t1.isAssignableTo(t2));
+                }
+            }
+        }
+    }
+
+    @Test
+    public void isInstanceTest() {
+        for (Constant c : constants) {
+            if (c.getKind().isObject() && !c.isNull()) {
+                Object o = c.asObject();
+                Class< ? extends Object> cls = o.getClass();
+                while (cls != null) {
+                    ResolvedJavaType type = runtime.lookupJavaType(cls);
+                    boolean expected = cls.isInstance(o);
+                    boolean actual = type.isInstance(c);
+                    assertEquals(expected, actual);
+                    cls = cls.getSuperclass();
+                }
+            }
+        }
+    }
+
+    private static Class asExactClass(Class c) {
+        if (c.isArray()) {
+            if (asExactClass(c.getComponentType()) != null) {
+                return c;
+            }
+        } else {
+            if (c.isPrimitive() || Modifier.isFinal(c.getModifiers())) {
+                return c;
+            }
+        }
+        return null;
+    }
+
+    @Test
+    public void asExactTypeTest() {
+        for (Class c : classes) {
+            ResolvedJavaType type = runtime.lookupJavaType(c);
+            ResolvedJavaType exactType = type.asExactType();
+            Class expected = asExactClass(c);
+            if (expected == null) {
+                assertTrue("exact(" + c.getName() + ") != null", exactType == null);
+            } else {
+                assertNotNull(exactType);
+                assertTrue(exactType.isClass(expected));
+            }
+        }
+    }
+
+    @Test
+    public void getSuperclassTest() {
+        for (Class c : classes) {
+            ResolvedJavaType type = runtime.lookupJavaType(c);
+            Class expected = c.getSuperclass();
+            ResolvedJavaType actual = type.getSuperclass();
+            if (expected == null) {
+                assertTrue(actual == null);
+            } else {
+                assertNotNull(actual);
+                assertTrue(actual.isClass(expected));
+            }
+        }
+    }
+
+    @Test
+    public void getInterfacesTest() {
+        for (Class c : classes) {
+            ResolvedJavaType type = runtime.lookupJavaType(c);
+            Class[] expected = c.getInterfaces();
+            ResolvedJavaType[] actual = type.getInterfaces();
+            assertEquals(expected.length, actual.length);
+            for (int i = 0; i < expected.length; i++) {
+                assertTrue(actual[i].isClass(expected[i]));
+            }
+        }
+    }
+
+    public static Class getSupertype(Class c) {
+        assert !c.isPrimitive();
+        if (c.isArray()) {
+            Class componentType = c.getComponentType();
+            if (componentType.isPrimitive() || componentType == Object.class) {
+                return Object.class;
+            }
+            return getArrayClass(getSupertype(componentType));
+        }
+        if (c.isInterface()) {
+            return Object.class;
+        }
+        return c.getSuperclass();
+    }
+
+    public static Class findLeastCommonAncestor(Class<?> c1Initial, Class<?> c2Initial) {
+        if (c1Initial.isPrimitive() || c2Initial.isPrimitive()) {
+            return null;
+        } else {
+            Class<?> c1 = c1Initial;
+            Class<?> c2 = c2Initial;
+            while (true) {
+              if (c1.isAssignableFrom(c2)) {
+                  return c1;
+              }
+              if (c2.isAssignableFrom(c1)) {
+                  return c2;
+              }
+              c1 = getSupertype(c1);
+              c2 = getSupertype(c2);
+            }
+        }
+    }
+
+    @Test
+    public void findLeastCommonAncestorTest() {
+        Class[] all = classes.toArray(new Class[classes.size()]);
+        for (int i = 0; i < all.length; i++) {
+            Class<?> c1 = all[i];
+            for (int j = i; j < all.length; j++) {
+                Class<?> c2 = all[j];
+                ResolvedJavaType t1 = runtime.lookupJavaType(c1);
+                ResolvedJavaType t2 = runtime.lookupJavaType(c2);
+                Class expected = findLeastCommonAncestor(c1, c2);
+                ResolvedJavaType actual = t1.findLeastCommonAncestor(t2);
+                if (expected == null) {
+                    assertTrue(actual == null);
+                } else {
+                    assertNotNull(actual);
+                    assertTrue(actual.isClass(expected));
+                }
+            }
+        }
+    }
+
+    private static class Base {}
+    abstract static class Abstract1 extends Base {}
+    interface Interface1 {}
+    static class Concrete1 extends Abstract1 {}
+    static class Concrete2 extends Abstract1 implements Interface1 {}
+    static class Concrete3 extends Concrete2 {}
+    abstract static class Abstract4 extends Concrete3 {}
+
+    static void checkConcreteSubtype(ResolvedJavaType type, Class expected) {
+        ResolvedJavaType subtype = type.findUniqueConcreteSubtype();
+        if (type.isInterface() && subtype == null) {
+            // A runtime may not record the subtype tree for interfaces in which case
+            // findUniqueConcreteSubtype() will return null for interfaces.
+            return;
+        }
+
+        if (expected == null) {
+            assertNull(subtype);
+        } else {
+            assertTrue(subtype.isClass(expected));
+        }
+        if (!type.isArrayClass()) {
+            ResolvedJavaType arrayType = type.getArrayClass();
+            if (subtype == type) {
+                assertEquals(arrayType.findUniqueConcreteSubtype(), arrayType);
+            } else {
+                assertNull(arrayType.findUniqueConcreteSubtype());
+            }
+        }
+    }
+
+    @Test
+    public void findUniqueConcreteSubtypeTest() {
+        ResolvedJavaType base = runtime.lookupJavaType(Base.class);
+        checkConcreteSubtype(base, Base.class);
+
+        ResolvedJavaType a1 = runtime.lookupJavaType(Abstract1.class);
+        ResolvedJavaType c1 = runtime.lookupJavaType(Concrete1.class);
+
+        checkConcreteSubtype(base, null);
+        checkConcreteSubtype(a1, Concrete1.class);
+        checkConcreteSubtype(c1, Concrete1.class);
+
+        ResolvedJavaType i1 = runtime.lookupJavaType(Interface1.class);
+        ResolvedJavaType c2 = runtime.lookupJavaType(Concrete2.class);
+
+        checkConcreteSubtype(base, null);
+        checkConcreteSubtype(a1, null);
+        checkConcreteSubtype(c1, Concrete1.class);
+        checkConcreteSubtype(i1, Concrete2.class);
+        checkConcreteSubtype(c2, Concrete2.class);
+
+        ResolvedJavaType c3 = runtime.lookupJavaType(Concrete3.class);
+        checkConcreteSubtype(c2, null);
+        checkConcreteSubtype(c3, Concrete3.class);
+
+        ResolvedJavaType a4 = runtime.lookupJavaType(Abstract4.class);
+        checkConcreteSubtype(c3, null);
+        checkConcreteSubtype(a4, null);
+    }
+
+    @Test
+    public void getComponentTypeTest() {
+        for (Class c : classes) {
+            ResolvedJavaType type = runtime.lookupJavaType(c);
+            Class expected = c.getComponentType();
+            ResolvedJavaType actual = type.getComponentType();
+            if (expected == null) {
+                assertNull(actual);
+            } else {
+                assertTrue(actual.isClass(expected));
+            }
+        }
+    }
+
+    @Test
+    public void getArrayClassTest() {
+        for (Class c : classes) {
+            if (c != void.class) {
+                ResolvedJavaType type = runtime.lookupJavaType(c);
+                Class expected = getArrayClass(c);
+                ResolvedJavaType actual = type.getArrayClass();
+                assertTrue(actual.isClass(expected));
+            }
+        }
+    }
+
+    static class Declarations {
+        final Method implementation;
+        final Set<Method> declarations;
+
+        public Declarations(Method impl) {
+            this.implementation = impl;
+            declarations = new HashSet<>();
+        }
+    }
+
+    /**
+     * See <a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.4.5">Method overriding</a>.
+     */
+    static boolean isOverriderOf(Method impl, Method m) {
+        if (!isPrivate(m.getModifiers()) && !isFinal(m.getModifiers())) {
+            if (m.getName().equals(impl.getName())) {
+                if (m.getReturnType() == impl.getReturnType()) {
+                    if (Arrays.equals(m.getParameterTypes(), impl.getParameterTypes())) {
+                        if (isPublic(m.getModifiers()) || isProtected(m.getModifiers())) {
+                            // m is public or protected
+                            return isPublic(impl.getModifiers()) || isProtected(impl.getModifiers());
+                        } else {
+                            // m is package-private
+                            return impl.getDeclaringClass().getPackage() == m.getDeclaringClass().getPackage();
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    static final Map<Class, VTable> vtables = new HashMap<>();
+
+    static class NameAndSig {
+        final String name;
+        final Class returnType;
+        final Class[] parameterTypes;
+        public NameAndSig(Method m) {
+            this.name = m.getName();
+            this.returnType = m.getReturnType();
+            this.parameterTypes = m.getParameterTypes();
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof NameAndSig) {
+                NameAndSig s = (NameAndSig) obj;
+                return s.returnType == returnType && name.equals(s.name) && Arrays.equals(s.parameterTypes, parameterTypes);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return name.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(name + "(");
+            String sep = "";
+            for (Class p : parameterTypes) {
+                sb.append(sep);
+                sep = ", ";
+                sb.append(p.getName());
+            }
+            return sb.append(')').append(returnType.getName()).toString();
+        }
+    }
+
+    static class VTable {
+        final Map<NameAndSig, Method> methods = new HashMap<>();
+    }
+
+    static synchronized VTable getVTable(Class c) {
+        VTable vtable = vtables.get(c);
+        if (vtable == null) {
+            vtable = new VTable();
+            if (c != Object.class) {
+                VTable superVtable = getVTable(c.getSuperclass());
+                vtable.methods.putAll(superVtable.methods);
+            }
+            for (Method m : c.getDeclaredMethods()) {
+                if (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers())) {
+                    Method overridden = vtable.methods.put(new NameAndSig(m), m);
+                    if (overridden != null) {
+                        //System.out.println(m + " overrides " + overridden);
+                    }
+                }
+            }
+            vtables.put(c, vtable);
+        }
+        return vtable;
+    }
+
+    static Set<Method> findDeclarations(Method impl, Class c) {
+        Set<Method> declarations = new HashSet<>();
+        NameAndSig implSig = new NameAndSig(impl);
+        if (c != null) {
+            for (Method m : c.getDeclaredMethods()) {
+                if (new NameAndSig(m).equals(implSig)) {
+                    declarations.add(m);
+                    break;
+                }
+            }
+            if (!c.isInterface()) {
+                declarations.addAll(findDeclarations(impl, c.getSuperclass()));
+            }
+            for (Class i : c.getInterfaces()) {
+                declarations.addAll(findDeclarations(impl, i));
+            }
+        }
+        return declarations;
+    }
+
+    private static void checkResolveMethod(ResolvedJavaType type, ResolvedJavaMethod decl, ResolvedJavaMethod expected) {
+        ResolvedJavaMethod impl = type.resolveMethod(decl);
+        assertEquals(expected, impl);
+    }
+
+    @Test
+    public void resolveMethodTest() {
+        for (Class c : classes) {
+            if (!c.isPrimitive() && !c.isInterface()) {
+                ResolvedJavaType type = runtime.lookupJavaType(c);
+                VTable vtable = getVTable(c);
+                for (Method impl : vtable.methods.values()) {
+                    Set<Method> decls = findDeclarations(impl, c);
+                    for (Method decl : decls) {
+                        ResolvedJavaMethod m = runtime.lookupJavaMethod(decl);
+                        ResolvedJavaMethod i = runtime.lookupJavaMethod(impl);
+                        checkResolveMethod(type, m, i);
+                    }
+                }
+            }
+        }
+    }
+
+    @Test
+    public void findUniqueConcreteMethodTest() {
+        // TODO
+    }
+
+    public static Set<Field> getInstanceFields(Class c, boolean includeSuperclasses) {
+        if (c.isArray() || c.isPrimitive() || c.isInterface()) {
+            return Collections.emptySet();
+        }
+        Set<Field> result = new HashSet<>();
+        for (Field f : c.getDeclaredFields()) {
+            if (!Modifier.isStatic(f.getModifiers())) {
+                result.add(f);
+            }
+        }
+        if (includeSuperclasses && c != Object.class) {
+            result.addAll(getInstanceFields(c.getSuperclass(), true));
+        }
+        return result;
+    }
+
+    public static boolean containsField(ResolvedJavaField[] fields, Field f) {
+        for (ResolvedJavaField rf : fields) {
+            if (rf.getName().equals(f.getName()) && rf.getType().resolve(rf.getDeclaringClass()).isClass(f.getType())) {
+                assert f.getModifiers() == rf.getModifiers() : f;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean containsField(Set<Field> fields, ResolvedJavaField rf) {
+        for (Field f : fields) {
+            if (f.getName().equals(rf.getName()) && rf.getType().resolve(rf.getDeclaringClass()).isClass(f.getType())) {
+                assert rf.getModifiers() == f.getModifiers() : rf;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isHiddenFromReflection(ResolvedJavaField f) {
+        if (f.getDeclaringClass().isClass(Throwable.class) && f.getName().equals("backtrace")) {
+            return true;
+        }
+        if (f.getDeclaringClass().isClass(ConstantPool.class) && f.getName().equals("constantPoolOop")) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void getInstanceFieldsTest() {
+        for (Class c : classes) {
+            ResolvedJavaType type = runtime.lookupJavaType(c);
+            for (boolean includeSuperclasses : new boolean[] {true, false}) {
+                Set<Field> expected = getInstanceFields(c, includeSuperclasses);
+                ResolvedJavaField[] actual = type.getInstanceFields(includeSuperclasses);
+                for (Field f : expected) {
+                    assertTrue(containsField(actual, f));
+                }
+                for (ResolvedJavaField rf : actual) {
+                    if (!isHiddenFromReflection(rf)) {
+                        assertEquals(containsField(expected, rf), !rf.isInternal());
+                    }
+                }
+
+                // Test stability of getInstanceFields
+                ResolvedJavaField[] actual2 = type.getInstanceFields(includeSuperclasses);
+                assertArrayEquals(actual, actual2);
+            }
+        }
+    }
+
+    @Test
+    public void getAnnotationTest() {
+        for (Class c : classes) {
+            ResolvedJavaType type = runtime.lookupJavaType(c);
+            for (Annotation a : c.getAnnotations()) {
+                assertEquals(a, type.getAnnotation(a.annotationType()));
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Tue Nov 27 11:21:48 2012 +0100
@@ -33,7 +33,8 @@
 
     /**
      * Returns the Java language modifiers for this field, as an integer. The {@link Modifier} class should be used to
-     * decode the modifiers. Only the flags specified in the JVM specification will be included in the returned mask.
+     * decode the modifiers. Only the {@linkplain Modifier#fieldModifiers() field flags} specified in the JVM
+     * specification will be included in the returned mask.
      */
     int getModifiers();
 
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Tue Nov 27 11:21:48 2012 +0100
@@ -35,7 +35,7 @@
     /**
      * Returns the bytecodes of this method, if the method has code. The returned byte array does not contain
      * breakpoints or non-Java bytecodes.
-     * 
+     *
      * @return the bytecodes of the method, or {@code null} if none is available
      */
     byte[] getCode();
@@ -43,21 +43,21 @@
     /**
      * Returns the size of the bytecodes of this method, if the method has code. This is equivalent to
      * {@link #getCode()}. {@code length} if the method has code.
-     * 
+     *
      * @return the size of the bytecodes in bytes, or 0 if no bytecodes is available
      */
     int getCodeSize();
 
     /**
      * Returns the size of the compiled machine code of this method.
-     * 
+     *
      * @return the size of the compiled machine code in bytes, or 0 if no compiled code exists.
      */
     int getCompiledCodeSize();
 
     /**
      * Returns an estimate how complex it is to compile this method.
-     * 
+     *
      * @return A value >= 0, where higher means more complex.
      */
     int getCompilationComplexity();
@@ -79,20 +79,21 @@
 
     /**
      * Returns the Java language modifiers for this method, as an integer. The {@link Modifier} class should be used to
-     * decode the modifiers. Only the flags specified in the JVM specification will be included in the returned mask.
+     * decode the modifiers. Only the {@linkplain Modifier#methodModifiers() method flags} specified in the JVM
+     * specification will be included in the returned mask.
      */
     int getModifiers();
 
     /**
      * Checks whether this method is a class initializer.
-     * 
+     *
      * @return {@code true} if the method is a class initializer
      */
     boolean isClassInitializer();
 
     /**
      * Checks whether this method is a constructor.
-     * 
+     *
      * @return {@code true} if the method is a constructor
      */
     boolean isConstructor();
@@ -100,7 +101,7 @@
     /**
      * Checks whether this method can be statically bound (usually, that means it is final or private or static, but not
      * abstract).
-     * 
+     *
      * @return {@code true} if this method can be statically bound
      */
     boolean canBeStaticallyBound();
@@ -132,7 +133,7 @@
 
     /**
      * Returns the annotation for the specified type of this method, if such an annotation is present.
-     * 
+     *
      * @param annotationClass the Class object corresponding to the annotation type
      * @return this element's annotation for the specified annotation type if present on this method, else {@code null}
      */
@@ -141,7 +142,7 @@
     /**
      * Returns an array of arrays that represent the annotations on the formal parameters, in declaration order, of this
      * method.
-     * 
+     *
      * @see Method#getParameterAnnotations()
      */
     Annotation[][] getParameterAnnotations();
@@ -149,7 +150,7 @@
     /**
      * Returns an array of {@link Type} objects that represent the formal parameter types, in declaration order, of this
      * method.
-     * 
+     *
      * @see Method#getGenericParameterTypes()
      */
     Type[] getGenericParameterTypes();
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Tue Nov 27 11:21:48 2012 +0100
@@ -127,8 +127,9 @@
      *
      * @param other the type to test
      * @return {@code true} if this type a subtype of the specified type
+     * @see Class#isAssignableFrom(Class)
      */
-    boolean isSubtypeOf(ResolvedJavaType other);
+    boolean isAssignableTo(ResolvedJavaType other);
 
     /**
      * Checks whether the specified object is an instance of this type.
@@ -170,7 +171,8 @@
     ResolvedJavaType findLeastCommonAncestor(ResolvedJavaType otherType);
 
     /**
-     * Attempts to get the unique concrete subclass of this type.
+     * Gets the unique concrete subclass of this type.
+     *
      * <p>
      * If the compiler uses the result of this method for its compilation, it must register an assumption because
      * dynamic class loading can invalidate the result of this method.
@@ -192,14 +194,14 @@
     ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method);
 
     /**
-     * Given a {@link ResolvedJavaMethod} a, returns a concrete {@link ResolvedJavaMethod} b that is the only possible
-     * unique target for a virtual call on a(). Returns {@code null} if either no such concrete method or more than one
-     * such method exists. Returns the method a if a is a concrete method that is not overridden.
+     * Given a {@link ResolvedJavaMethod} A, returns a concrete {@link ResolvedJavaMethod} B that is the only possible
+     * unique target for a virtual call on A(). Returns {@code null} if either no such concrete method or more than one
+     * such method exists. Returns the method A if A is a concrete method that is not overridden.
      * <p>
      * If the compiler uses the result of this method for its compilation, it must register an assumption because
      * dynamic class loading can invalidate the result of this method.
      *
-     * @param method the method a for which a unique concrete target is searched
+     * @param method the method A for which a unique concrete target is searched
      * @return the unique concrete target or {@code null} if no such target exists or assumptions are not supported by
      *         this runtime
      */
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue Nov 27 11:21:48 2012 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot;
 
+import static com.oracle.graal.graph.FieldIntrospection.*;
+
 import java.lang.reflect.*;
 
 import com.oracle.graal.api.code.*;
@@ -70,6 +72,16 @@
         return wordKind;
     }
 
+    /**
+     * Reads a word value from a given address.
+     */
+    public static long unsafeReadWord(long address) {
+        if (wordKind.isLong()) {
+            return unsafe.getLong(address);
+        }
+        return unsafe.getInt(address);
+    }
+
     protected final CompilerToVM compilerToVm;
     protected final VMToCompiler vmToCompiler;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Nov 27 11:21:48 2012 +0100
@@ -63,6 +63,16 @@
     public int prototypeMarkWordOffset;
 
     /**
+     * The offset of the _subklass field in a Klass.
+     */
+    public int subklassOffset;
+
+    /**
+     * The offset of the _next_sibling field in a Klass.
+     */
+    public int nextSiblingOffset;
+
+    /**
      * The offset of the array length word in an array object's header.
      */
     public int arrayLengthOffset;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Tue Nov 27 11:21:48 2012 +0100
@@ -142,18 +142,12 @@
 
     JavaMethod resolveMethod(HotSpotResolvedJavaType klass, String name, String signature);
 
-    boolean isSubtypeOf(HotSpotResolvedJavaType klass, JavaType other);
-
-    JavaType getLeastCommonAncestor(HotSpotResolvedJavaType thisType, HotSpotResolvedJavaType otherType);
-
     boolean isTypeInitialized(HotSpotResolvedJavaType klass);
 
     void initializeType(HotSpotResolvedJavaType klass);
 
     ResolvedJavaType getResolvedType(Class<?> javaClass);
 
-    JavaType getUniqueConcreteSubtype(HotSpotResolvedJavaType klass);
-
     HotSpotResolvedJavaField[] getInstanceFields(HotSpotResolvedJavaType klass);
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Tue Nov 27 11:21:48 2012 +0100
@@ -89,15 +89,6 @@
     public native JavaMethod resolveMethod(HotSpotResolvedJavaType klass, String name, String signature);
 
     @Override
-    public native boolean isSubtypeOf(HotSpotResolvedJavaType klass, JavaType other);
-
-    @Override
-    public native JavaType getLeastCommonAncestor(HotSpotResolvedJavaType thisType, HotSpotResolvedJavaType otherType);
-
-    @Override
-    public native JavaType getUniqueConcreteSubtype(HotSpotResolvedJavaType klass);
-
-    @Override
     public native boolean isTypeInitialized(HotSpotResolvedJavaType klass);
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotJavaType.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotJavaType.java	Tue Nov 27 11:21:48 2012 +0100
@@ -41,9 +41,4 @@
     public final String getName() {
         return name;
     }
-
-    /**
-     * Gets the address of the C++ Klass object for this type.
-     */
-    public abstract Constant klass();
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Tue Nov 27 11:21:48 2012 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.meta;
 
 import static com.oracle.graal.graph.FieldIntrospection.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.util.*;
 
@@ -141,9 +142,9 @@
         return unsafe.getInt(null, metaspaceMethodData + fullOffsetInBytes);
     }
 
-    private long readLong(int position, int offsetInBytes) {
+    private long readWord(int position, int offsetInBytes) {
         long fullOffsetInBytes = computeFullOffset(position, offsetInBytes);
-        return unsafe.getLong(null, metaspaceMethodData + fullOffsetInBytes);
+        return unsafeReadWord(metaspaceMethodData + fullOffsetInBytes);
     }
 
     private static int truncateLongToInt(long value) {
@@ -340,10 +341,9 @@
             int entries = 0;
 
             for (int i = 0; i < typeProfileWidth; i++) {
-                long receiverKlass = data.readLong(position, getReceiverOffset(i));
+                long receiverKlass = data.readWord(position, getReceiverOffset(i));
                 if (receiverKlass != 0) {
                     types[entries] = HotSpotResolvedJavaType.fromMetaspaceKlass(receiverKlass);
-
                     long count = data.readUnsignedInt(position, getCountOffset(i));
                     totalCount += count;
                     counts[entries] = count;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Tue Nov 27 11:21:48 2012 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.meta;
 
 import static com.oracle.graal.graph.FieldIntrospection.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.lang.annotation.*;
 import java.lang.reflect.*;
@@ -199,7 +200,7 @@
         ProfilingInfo info;
 
         if (GraalOptions.UseProfilingInformation && methodData == null) {
-            long metaspaceMethodData = unsafe.getLong(null, metaspaceMethod + HotSpotGraalRuntime.getInstance().getConfig().methodDataOffset);
+            long metaspaceMethodData = unsafeReadWord(metaspaceMethod + HotSpotGraalRuntime.getInstance().getConfig().methodDataOffset);
             if (metaspaceMethodData != 0) {
                 methodData = new HotSpotMethodData(metaspaceMethodData);
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java	Tue Nov 27 11:21:48 2012 +0100
@@ -23,6 +23,8 @@
 package com.oracle.graal.hotspot.meta;
 
 import static com.oracle.graal.graph.FieldIntrospection.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static java.lang.reflect.Modifier.*;
 
 import java.lang.annotation.*;
 import java.lang.reflect.*;
@@ -162,16 +164,27 @@
         if (isArrayClass()) {
             return getComponentType().findUniqueConcreteSubtype() == getComponentType() ? this : null;
         } else {
-            ResolvedJavaType subtype = (ResolvedJavaType) HotSpotGraalRuntime.getInstance().getCompilerToVM().getUniqueConcreteSubtype(this);
-            assert subtype == null || !subtype.isInterface();
-            return subtype;
+            HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig();
+            HotSpotResolvedJavaType type = this;
+            while (isAbstract(type.getModifiers())) {
+                long subklass = unsafeReadWord(type.metaspaceKlass + config.subklassOffset);
+                if (subklass == 0 || unsafeReadWord(subklass + config.nextSiblingOffset) != 0) {
+                    return null;
+                }
+                type = (HotSpotResolvedJavaType) fromMetaspaceKlass(subklass);
+            }
+            if (unsafeReadWord(type.metaspaceKlass + config.subklassOffset) != 0) {
+                return null;
+            }
+            assert !type.isInterface();
+            return type;
         }
     }
 
     @Override
-    public ResolvedJavaType getSuperclass() {
+    public HotSpotResolvedJavaType getSuperclass() {
         Class javaSuperclass = javaMirror.getSuperclass();
-        return javaSuperclass == null ? null : fromClass(javaSuperclass);
+        return javaSuperclass == null ? null : (HotSpotResolvedJavaType) fromClass(javaSuperclass);
     }
 
     @Override
@@ -187,12 +200,37 @@
         return interfaces;
     }
 
+    public HotSpotResolvedJavaType getSupertype() {
+        if (isArrayClass()) {
+            ResolvedJavaType componentType = getComponentType();
+            if (javaMirror == Object[].class || componentType instanceof HotSpotTypePrimitive) {
+                return (HotSpotResolvedJavaType) fromClass(Object.class);
+            }
+            return (HotSpotResolvedJavaType) ((HotSpotResolvedJavaType) componentType).getSupertype().getArrayClass();
+        }
+        if (isInterface()) {
+            return (HotSpotResolvedJavaType) fromClass(Object.class);
+        }
+        return getSuperclass();
+    }
+
     @Override
     public ResolvedJavaType findLeastCommonAncestor(ResolvedJavaType otherType) {
         if (otherType instanceof HotSpotTypePrimitive) {
             return null;
         } else {
-            return (ResolvedJavaType) HotSpotGraalRuntime.getInstance().getCompilerToVM().getLeastCommonAncestor(this, (HotSpotResolvedJavaType) otherType);
+            HotSpotResolvedJavaType t1 = this;
+            HotSpotResolvedJavaType t2 = (HotSpotResolvedJavaType) otherType;
+            while (true) {
+              if (t2.isAssignableTo(t1)) {
+                  return t1;
+              }
+              if (t1.isAssignableTo(t2)) {
+                  return t2;
+              }
+              t1 = t1.getSupertype();
+              t2 = t2.getSupertype();
+            }
         }
     }
 
@@ -271,11 +309,11 @@
     }
 
     @Override
-    public boolean isSubtypeOf(ResolvedJavaType other) {
+    public boolean isAssignableTo(ResolvedJavaType other) {
         if (other instanceof HotSpotResolvedJavaType) {
-            return HotSpotGraalRuntime.getInstance().getCompilerToVM().isSubtypeOf(this, other);
+            HotSpotResolvedJavaType otherType = (HotSpotResolvedJavaType) other;
+            return otherType.javaMirror.isAssignableFrom(javaMirror);
         }
-        // No resolved type is a subtype of an unresolved type.
         return false;
     }
 
@@ -409,7 +447,9 @@
         return this;
     }
 
-    @Override
+    /**
+     * Gets the address of the C++ Klass object for this type.
+     */
     public Constant klass() {
         return new Constant(HotSpotGraalRuntime.getInstance().getTarget().wordKind, metaspaceKlass, this);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotTypePrimitive.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotTypePrimitive.java	Tue Nov 27 11:21:48 2012 +0100
@@ -122,7 +122,10 @@
     }
 
     @Override
-    public boolean isSubtypeOf(ResolvedJavaType other) {
+    public boolean isAssignableTo(ResolvedJavaType other) {
+        if (other instanceof HotSpotTypePrimitive) {
+            return other == this;
+        }
         return false;
     }
 
@@ -177,11 +180,6 @@
     }
 
     @Override
-    public Constant klass() {
-        throw GraalInternalError.shouldNotReachHere("HotSpotTypePrimitive.klass()");
-    }
-
-    @Override
     public void initialize() {
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotTypeUnresolved.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotTypeUnresolved.java	Tue Nov 27 11:21:48 2012 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.hotspot.meta;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 
 /**
@@ -88,9 +87,4 @@
     public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
         return (ResolvedJavaType) HotSpotGraalRuntime.getInstance().lookupType(getName(), (HotSpotResolvedJavaType) accessingClass, true);
     }
-
-    @Override
-    public Constant klass() {
-        throw GraalInternalError.shouldNotReachHere("HotSpotTypeUnresolved.klass()");
-    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Tue Nov 27 11:21:48 2012 +0100
@@ -297,7 +297,7 @@
         static ConstantNode[] createHints(TypeCheckHints hints, MetaAccessProvider runtime, Graph graph) {
             ConstantNode[] hintHubs = new ConstantNode[hints.types.length];
             for (int i = 0; i < hintHubs.length; i++) {
-                hintHubs[i] = ConstantNode.forConstant(((HotSpotJavaType) hints.types[i]).klass(), runtime, graph);
+                hintHubs[i] = ConstantNode.forConstant(((HotSpotResolvedJavaType) hints.types[i]).klass(), runtime, graph);
             }
             return hintHubs;
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/IntrinsifyArrayCopyPhase.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/IntrinsifyArrayCopyPhase.java	Tue Nov 27 11:21:48 2012 +0100
@@ -106,7 +106,7 @@
                             snippetMethod = objectArrayCopy;
                         }
                     } else if (componentKind == Kind.Object
-                                    && srcType.getComponentType().isSubtypeOf(destType.getComponentType())) {
+                                    && srcType.getComponentType().isAssignableTo(destType.getComponentType())) {
                         snippetMethod = objectArrayCopy;
                     }
                 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Nov 27 11:21:48 2012 +0100
@@ -1407,7 +1407,7 @@
         if (initialized && graphBuilderConfig.getSkippedExceptionTypes() != null) {
             ResolvedJavaType resolvedCatchType = (ResolvedJavaType) catchType;
             for (ResolvedJavaType skippedType : graphBuilderConfig.getSkippedExceptionTypes()) {
-                initialized &= !resolvedCatchType.isSubtypeOf(skippedType);
+                initialized &= !resolvedCatchType.isAssignableTo(skippedType);
                 if (!initialized) {
                     break;
                 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Tue Nov 27 11:21:48 2012 +0100
@@ -68,7 +68,7 @@
             if (my.nonNull() && !other.nonNull()) {
                 return this;
             }
-            if (my.type() != other.type() && my.type().isSubtypeOf(other.type())) {
+            if (my.type() != other.type() && my.type().isAssignableTo(other.type())) {
                 return this;
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Tue Nov 27 11:21:48 2012 +0100
@@ -72,7 +72,7 @@
 
         if (type != null) {
             ResolvedJavaType objectType = object().objectStamp().type();
-            if (objectType != null && objectType.isSubtypeOf(type)) {
+            if (objectType != null && objectType.isAssignableTo(type)) {
                 // we don't have to check for null types here because they will also pass the checkcast.
                 return object();
             }
@@ -102,7 +102,7 @@
     @Override
     public void virtualize(VirtualizerTool tool) {
         VirtualObjectNode virtual = tool.getVirtualState(object());
-        if (virtual != null && virtual.type().isSubtypeOf(type())) {
+        if (virtual != null && virtual.type().isAssignableTo(type())) {
             tool.replaceWithVirtual(virtual);
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Tue Nov 27 11:21:48 2012 +0100
@@ -70,7 +70,7 @@
         ResolvedJavaType stampType = stamp.type();
 
         if (stamp.isExactType()) {
-            boolean subType = stampType.isSubtypeOf(type());
+            boolean subType = stampType.isAssignableTo(type());
 
             if (subType) {
                 if (stamp.nonNull()) {
@@ -87,7 +87,7 @@
                 return ConstantNode.forBoolean(false, graph());
             }
         } else if (stampType != null) {
-            boolean subType = stampType.isSubtypeOf(type());
+            boolean subType = stampType.isAssignableTo(type());
 
             if (subType) {
                 if (stamp.nonNull()) {
@@ -135,7 +135,7 @@
     public void virtualize(VirtualizerTool tool) {
         VirtualObjectNode virtual = tool.getVirtualState(object());
         if (virtual != null) {
-            tool.replaceWithValue(ConstantNode.forBoolean(virtual.type().isSubtypeOf(type()), graph()));
+            tool.replaceWithValue(ConstantNode.forBoolean(virtual.type().isAssignableTo(type()), graph()));
         }
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Tue Nov 27 11:21:48 2012 +0100
@@ -98,7 +98,7 @@
             if (stamp.type() != null) {
                 int validKeys = 0;
                 for (int i = 0; i < keyCount(); i++) {
-                    if (keys[i].isSubtypeOf(stamp.type())) {
+                    if (keys[i].isAssignableTo(stamp.type())) {
                         validKeys++;
                     }
                 }
@@ -113,7 +113,7 @@
                     double totalProbability = 0;
                     int current = 0;
                     for (int i = 0; i < keyCount() + 1; i++) {
-                        if (i == keyCount() || keys[i].isSubtypeOf(stamp.type())) {
+                        if (i == keyCount() || keys[i].isAssignableTo(stamp.type())) {
                             int index = newSuccessors.indexOf(keySuccessor(i));
                             if (index == -1) {
                                 index = newSuccessors.size();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java	Tue Nov 27 11:21:48 2012 +0100
@@ -78,7 +78,7 @@
             return false;
         } else if (other.nonNull || nonNull) {
             // One of the two values cannot be null.
-            return !other.type.isInterface() && !type.isInterface() && !other.type.isSubtypeOf(type) && !type.isSubtypeOf(other.type);
+            return !other.type.isInterface() && !type.isInterface() && !other.type.isAssignableTo(type) && !type.isAssignableTo(other.type);
         }
         return false;
     }
@@ -139,7 +139,7 @@
             joinType = type;
         } else {
             // both types are != null
-            if (other.type.isSubtypeOf(type)) {
+            if (other.type.isAssignableTo(type)) {
                 joinType = other.type;
             } else {
                 joinType = type;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Tue Nov 27 11:21:48 2012 +0100
@@ -240,9 +240,9 @@
             return a;
         } else if (a == b) {
             return a;
-        } else if (a.isSubtypeOf(b)) {
+        } else if (a.isAssignableTo(b)) {
             return a;
-        } else if (b.isSubtypeOf(a)) {
+        } else if (b.isAssignableTo(a)) {
             return b;
         } else {
             return a;
@@ -326,7 +326,7 @@
             } else if (node instanceof CheckCastNode) {
                 CheckCastNode checkCast = (CheckCastNode) node;
                 ResolvedJavaType type = state.getNodeType(checkCast.object());
-                if (type != null && type.isSubtypeOf(checkCast.type())) {
+                if (type != null && type.isAssignableTo(checkCast.type())) {
                     PiNode piNode;
                     boolean nonNull = state.knownNotNull.contains(checkCast.object());
                     piNode = graph.unique(new PiNode(checkCast.object(), lastBegin, nonNull ? StampFactory.declaredNonNull(type) : StampFactory.declared(type)));
@@ -351,7 +351,7 @@
                             replaceWith = ConstantNode.forBoolean(false, graph);
                         } else if (state.knownNotNull.contains(object)) {
                             ResolvedJavaType type = state.getNodeType(object);
-                            if (type != null && type.isSubtypeOf(instanceOf.type())) {
+                            if (type != null && type.isAssignableTo(instanceOf.type())) {
                                 replaceWith = ConstantNode.forBoolean(true, graph);
                             }
                         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Tue Nov 27 11:18:34 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Tue Nov 27 11:21:48 2012 +0100
@@ -610,7 +610,7 @@
         ObjectStamp receiverStamp = callTarget.receiver().objectStamp();
         ResolvedJavaType receiverType = receiverStamp.type();
         if (receiverStamp.isExactType()) {
-            assert receiverType.isSubtypeOf(targetMethod.getDeclaringClass()) : receiverType + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod;
+            assert receiverType.isAssignableTo(targetMethod.getDeclaringClass()) : receiverType + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod;
             ResolvedJavaMethod resolved = receiverType.resolveMethod(targetMethod);
             if (checkTargetConditions(invoke, resolved, optimisticOpts)) {
                 double weight = callback == null ? 0 : callback.inliningWeight(parent, resolved, invoke);
@@ -623,7 +623,7 @@
         if (receiverStamp.type() != null) {
             // the invoke target might be more specific than the holder (happens after inlining: locals lose their declared type...)
             // TODO (lstadler) fix this
-            if (receiverType != null && receiverType.isSubtypeOf(holder)) {
+            if (receiverType != null && receiverType.isAssignableTo(holder)) {
                 holder = receiverType;
             }
         }
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Tue Nov 27 11:18:34 2012 +0100
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Tue Nov 27 11:21:48 2012 +0100
@@ -504,31 +504,6 @@
   return JNIHandles::make_local(THREAD, VMToCompiler::createResolvedJavaMethod(holder, method(), THREAD));
 C2V_END
 
-C2V_VMENTRY(jboolean, isSubtypeOf, (JNIEnv *, jobject, jobject klass, jobject jother))
-  oop other = JNIHandles::resolve(jother);
-  assert(other->is_a(HotSpotResolvedJavaType::klass()), "resolved HotSpot type expected");
-  assert(JNIHandles::resolve(klass) != NULL, "");
-  Klass* thisKlass = java_lang_Class::as_Klass(HotSpotResolvedJavaType::javaMirror(klass));
-  Klass* otherKlass = java_lang_Class::as_Klass(HotSpotResolvedJavaType::javaMirror(other));
-  if (thisKlass->oop_is_instance()) {
-    return InstanceKlass::cast(thisKlass)->is_subtype_of(otherKlass);
-  } else if (thisKlass->oop_is_array()) {
-    return ArrayKlass::cast(thisKlass)->is_subtype_of(otherKlass);
-  } else {
-    fatal("unexpected class type");
-    return false;
-  }
-C2V_END
-
-C2V_VMENTRY(jobject, getLeastCommonAncestor, (JNIEnv *, jobject, jobject this_type, jobject other_type))
-
-  Klass* this_klass  = java_lang_Class::as_Klass(HotSpotResolvedJavaType::javaMirror(this_type));
-  Klass* other_klass = java_lang_Class::as_Klass(HotSpotResolvedJavaType::javaMirror(other_type));
-  Klass* lca         = this_klass->LCA(other_klass);
-
-  return JNIHandles::make_local(GraalCompiler::get_JavaType(lca, THREAD)());
-C2V_END
-
 C2V_VMENTRY(jlong, getPrototypeMarkWord, (JNIEnv *, jobject, jobject klass))
   KlassHandle klass_handle(java_lang_Class::as_Klass(HotSpotResolvedJavaType::javaMirror(klass)));
   if (klass_handle->oop_is_array()) {
@@ -538,15 +513,6 @@
   }
 C2V_END
 
-C2V_VMENTRY(jobject, getUniqueConcreteSubtype, (JNIEnv *, jobject, jobject klass))
-  KlassHandle klass_handle(java_lang_Class::as_Klass(HotSpotResolvedJavaType::javaMirror(klass)));
-  Klass *up_cast = klass_handle->up_cast_abstract();
-  if (!up_cast->is_interface() && up_cast->subklass() == NULL) {
-    return JNIHandles::make_local(GraalCompiler::get_JavaType(up_cast, THREAD)());
-  }
-  return NULL;
-C2V_END
-
 C2V_VMENTRY(jboolean, isTypeInitialized,(JNIEnv *, jobject, jobject hotspot_klass))
   Klass* klass = java_lang_Class::as_Klass(HotSpotResolvedJavaType::javaMirror(hotspot_klass));
   assert(klass != NULL, "method must not be called for primitive types");
@@ -646,6 +612,8 @@
   set_int(env, config, "superCheckOffsetOffset", in_bytes(Klass::super_check_offset_offset()));
   set_int(env, config, "secondarySuperCacheOffset", in_bytes(Klass::secondary_super_cache_offset()));
   set_int(env, config, "secondarySupersOffset", in_bytes(Klass::secondary_supers_offset()));
+  set_int(env, config, "subklassOffset", in_bytes(Klass::subklass_offset()));
+  set_int(env, config, "nextSiblingOffset", in_bytes(Klass::next_sibling_offset()));
   set_int(env, config, "arrayLengthOffset", arrayOopDesc::length_offset_in_bytes());
   set_int(env, config, "klassStateOffset", in_bytes(InstanceKlass::init_state_offset()));
   set_int(env, config, "klassStateFullyInitialized", (int)InstanceKlass::fully_initialized);
@@ -962,9 +930,6 @@
   {CC"lookupReferencedTypeInPool",    CC"("HS_RESOLVED_TYPE"IB)V",                                      FN_PTR(lookupReferencedTypeInPool)},
   {CC"lookupFieldInPool",             CC"("HS_RESOLVED_TYPE"IB)"FIELD,                                  FN_PTR(lookupFieldInPool)},
   {CC"resolveMethod",                 CC"("HS_RESOLVED_TYPE STRING STRING")"METHOD,                     FN_PTR(resolveMethod)},
-  {CC"isSubtypeOf",                   CC"("HS_RESOLVED_TYPE TYPE")Z",                                   FN_PTR(isSubtypeOf)},
-  {CC"getLeastCommonAncestor",        CC"("HS_RESOLVED_TYPE HS_RESOLVED_TYPE")"TYPE,                    FN_PTR(getLeastCommonAncestor)},
-  {CC"getUniqueConcreteSubtype",      CC"("HS_RESOLVED_TYPE")"TYPE,                                     FN_PTR(getUniqueConcreteSubtype)},
   {CC"getPrototypeMarkWord",          CC"("HS_RESOLVED_TYPE")J",                                        FN_PTR(getPrototypeMarkWord)},
   {CC"getInstanceFields",             CC"("HS_RESOLVED_TYPE")["HS_RESOLVED_FIELD,                       FN_PTR(getInstanceFields)},
   {CC"isTypeInitialized",             CC"("HS_RESOLVED_TYPE")Z",                                        FN_PTR(isTypeInitialized)},