changeset 18381:53bd20792127

Merge.
author Doug Simon <doug.simon@oracle.com>
date Sat, 15 Nov 2014 16:39:23 +0100
parents 601dfbdcc5bf (current diff) ed0fce2e999a (diff)
children 322d928a373e
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectGetClassNode.java
diffstat 16 files changed, 535 insertions(+), 127 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ClassSubstitutionsTests.java	Sat Nov 15 16:39:23 2014 +0100
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2014, 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.hotspot.test;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+
+public class ClassSubstitutionsTests extends GraalCompilerTest {
+
+    public Number instanceField;
+
+    public Object[] arrayField;
+
+    public String[] stringArrayField;
+
+    protected StructuredGraph test(final String snippet) {
+        try (Scope s = Debug.scope("ClassSubstitutionsTest", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) {
+            StructuredGraph graph = parseEager(snippet);
+            compile(graph.method(), graph);
+            assertNotInGraph(graph, Invoke.class);
+            Debug.dump(graph, snippet);
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected static StructuredGraph assertNotInGraph(StructuredGraph graph, Class<?> clazz) {
+        for (Node node : graph.getNodes()) {
+            if (clazz.isInstance(node)) {
+                fail(node.toString());
+            }
+        }
+        return graph;
+    }
+
+    public boolean constantIsArray() {
+        return "".getClass().isArray();
+    }
+
+    public boolean constantIsInterface() {
+        return "".getClass().isInterface();
+    }
+
+    public boolean constantIsPrimitive() {
+        return "".getClass().isPrimitive();
+    }
+
+    @Test
+    public void testIsArray() {
+        testConstantReturn("constantIsArray", 0);
+    }
+
+    @Test
+    public void testIsInterface() {
+        testConstantReturn("constantIsInterface", 0);
+    }
+
+    @Test
+    public void testIsPrimitive() {
+        testConstantReturn("constantIsPrimitive", 0);
+    }
+
+    public boolean fieldIsNotArray() {
+        if (instanceField != null) {
+            // The base type of instanceField is not Object or an Interface, so it's provably an
+            // instance type, so isArray will always return false.
+            return instanceField.getClass().isArray();
+        }
+        return false;
+    }
+
+    @Test
+    public void testFieldIsNotArray() {
+        testConstantReturn("fieldIsNotArray", 0);
+    }
+
+    public boolean foldComponentType() {
+        return stringArrayField.getClass().getComponentType() == String.class;
+    }
+
+    @Test
+    public void testFoldComponenetType() {
+        testConstantReturn("foldComponentType", 1);
+    }
+
+    @Ignore("Can't constant fold LoadHubNode == 0 yet")
+    @Test
+    public void testFieldIsArray() {
+        testConstantReturn("fieldIsArray", 1);
+    }
+
+    public boolean fieldIsArray() {
+        if (arrayField != null) {
+            // The base type of arrayField is an array of some sort so isArray will always return
+            // true.
+            return arrayField.getClass().isArray();
+        }
+        return true;
+    }
+
+    private void testConstantReturn(String name, Object value) {
+        StructuredGraph result = test(name);
+        ReturnNode ret = result.getNodes(ReturnNode.class).first();
+        assertDeepEquals(1, result.getNodes(ReturnNode.class).count());
+
+        assertDeepEquals(true, ret.result().isConstant());
+        assertDeepEquals(value, ret.result().asJavaConstant().asBoxedPrimitive());
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowPointerStamp.java	Sat Nov 15 14:46:39 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowPointerStamp.java	Sat Nov 15 16:39:23 2014 +0100
@@ -84,6 +84,7 @@
 
     @Override
     public Stamp constant(Constant c, MetaAccessProvider meta) {
+        assert (c instanceof HotSpotMetaspaceConstantImpl) && ((HotSpotMetaspaceConstantImpl) c).isCompressed();
         return this;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java	Sat Nov 15 14:46:39 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java	Sat Nov 15 16:39:23 2014 +0100
@@ -93,7 +93,7 @@
         UnsafeArrayCopyNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, baseKind);
     }
 
-    private static int checkArrayType(Pointer hub) {
+    private static int checkArrayType(TypePointer hub) {
         int layoutHelper = readLayoutHelper(hub);
         if (probability(SLOW_PATH_PROBABILITY, layoutHelper >= 0)) {
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
@@ -183,9 +183,9 @@
     public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) {
         Object nonNullSrc = guardingNonNull(src);
         Object nonNullDest = guardingNonNull(dest);
-        Pointer srcHub = loadHub(nonNullSrc);
-        Pointer destHub = loadHub(nonNullDest);
-        if (probability(FAST_PATH_PROBABILITY, srcHub.equal(destHub)) && probability(FAST_PATH_PROBABILITY, nonNullSrc != nonNullDest)) {
+        TypePointer srcHub = loadHub(nonNullSrc);
+        TypePointer destHub = loadHub(nonNullDest);
+        if (probability(FAST_PATH_PROBABILITY, Word.equal(srcHub, destHub)) && probability(FAST_PATH_PROBABILITY, nonNullSrc != nonNullDest)) {
             int layoutHelper = checkArrayType(srcHub);
             final boolean isObjectArray = ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) == 0);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassGetHubNode.java	Sat Nov 15 16:39:23 2014 +0100
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2014, 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.hotspot.replacements;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.HeapAccess.BarrierType;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Read Class::_klass to get the hub for a {@link java.lang.Class}. This node mostly exists to
+ * replace _klass._java_mirror._klass with _klass. The constant folding could be handled by
+ * {@link ReadNode#canonicalizeRead(ValueNode, LocationNode, ValueNode, CanonicalizerTool)}.
+ */
+@NodeInfo
+public class ClassGetHubNode extends FloatingGuardedNode implements Lowerable, Canonicalizable {
+    @Input protected ValueNode clazz;
+
+    public static ClassGetHubNode create(ValueNode clazz) {
+        return new ClassGetHubNode(clazz);
+    }
+
+    public static ClassGetHubNode create(ValueNode clazz, ValueNode guard) {
+        return new ClassGetHubNode(clazz, guard);
+    }
+
+    protected ClassGetHubNode(ValueNode clazz) {
+        super(StampFactory.forPointer(PointerType.Type), null);
+        this.clazz = clazz;
+    }
+
+    protected ClassGetHubNode(ValueNode clazz, ValueNode guard) {
+        super(StampFactory.forPointer(PointerType.Type), (GuardingNode) guard);
+        this.clazz = clazz;
+    }
+
+    public ValueNode getHub() {
+        return clazz;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (usages().isEmpty()) {
+            return null;
+        } else {
+            if (clazz.isConstant()) {
+                MetaAccessProvider metaAccess = tool.getMetaAccess();
+                if (metaAccess != null) {
+                    HotSpotResolvedJavaType exactType = (HotSpotResolvedJavaType) tool.getConstantReflection().asJavaType(clazz.asJavaConstant());
+                    if (exactType instanceof HotSpotResolvedObjectType) {
+                        HotSpotResolvedObjectType objectType = (HotSpotResolvedObjectType) exactType;
+                        ConstantNode cn = ConstantNode.forConstant(stamp(), objectType.getObjectHub(), metaAccess);
+                        return cn;
+                    } else if (exactType instanceof HotSpotResolvedPrimitiveType) {
+                        /*
+                         * The constant value is null but we don't have a JavaConstant subclass to
+                         * talk about a NULL pointer yet.
+                         */
+                    }
+                }
+            }
+            if (clazz instanceof HubGetClassNode) {
+                // replace _klass._java_mirror._klass -> _klass
+                return ((HubGetClassNode) clazz).getHub();
+            }
+            return this;
+        }
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
+            return;
+        }
+
+        HotSpotVMConfig config = runtime().getConfig();
+        LocationNode location = ConstantLocationNode.create(CLASS_KLASS_LOCATION, getWordKind(), config.klassOffset, graph());
+        assert !clazz.isConstant();
+        FloatingReadNode read = graph().unique(FloatingReadNode.create(clazz, location, null, stamp(), getGuard(), BarrierType.NONE));
+        graph().replaceFloating(this, read);
+    }
+
+    @NodeIntrinsic
+    public static native TypePointer readClass(Class<?> clazz);
+
+    @NodeIntrinsic
+    public static native TypePointer readClass(Class<?> clazz, GuardingNode guard);
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java	Sat Nov 15 14:46:39 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java	Sat Nov 15 16:39:23 2014 +0100
@@ -40,21 +40,23 @@
 public class ClassSubstitutions {
 
     @MacroSubstitution(macro = ClassGetModifiersNode.class, isStatic = false)
-    @MethodSubstitution(isStatic = false)
+    @MethodSubstitution(isStatic = false, forced = true)
     public static int getModifiers(final Class<?> thisObj) {
-        Word klass = loadWordFromObject(thisObj, klassOffset(), CLASS_KLASS_LOCATION);
-        if (klass.equal(0)) {
+        TypePointer klass = ClassGetHubNode.readClass(thisObj);
+        TypePointer zero = Word.unsigned(0).toTypePointer();
+        if (Word.equal(klass, zero)) {
             // Class for primitive type
             return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC;
         } else {
-            return klass.readInt(klassModifierFlagsOffset(), KLASS_MODIFIER_FLAGS_LOCATION);
+            return Word.fromTypePointer(klass).readInt(klassModifierFlagsOffset(), KLASS_MODIFIER_FLAGS_LOCATION);
         }
     }
 
+    // This MacroSubstitution should be removed once non-null klass pointers can be optimized
     @MacroSubstitution(macro = ClassIsInterfaceNode.class, isStatic = false)
-    @MethodSubstitution(isStatic = false)
+    @MethodSubstitution(isStatic = false, forced = true)
     public static boolean isInterface(final Class<?> thisObj) {
-        Word klass = loadWordFromObject(thisObj, klassOffset(), CLASS_KLASS_LOCATION);
+        Pointer klass = Word.fromTypePointer(ClassGetHubNode.readClass(thisObj));
         if (klass.equal(0)) {
             return false;
         } else {
@@ -63,21 +65,24 @@
         }
     }
 
+    // This MacroSubstitution should be removed once non-null klass pointers can be optimized
     @MacroSubstitution(macro = ClassIsArrayNode.class, isStatic = false)
-    @MethodSubstitution(isStatic = false)
+    @MethodSubstitution(isStatic = false, forced = true)
     public static boolean isArray(final Class<?> thisObj) {
-        Word klass = loadWordFromObject(thisObj, klassOffset(), CLASS_KLASS_LOCATION);
+        TypePointer klassPtr = ClassGetHubNode.readClass(thisObj);
+        Pointer klass = Word.fromTypePointer(klassPtr);
         if (klass.equal(0)) {
             return false;
         } else {
-            return klassIsArray(klass);
+            return klassIsArray(klassPtr);
         }
     }
 
+    // This MacroSubstitution should be removed once non-null klass pointers can be optimized
     @MacroSubstitution(macro = ClassIsPrimitiveNode.class, isStatic = false)
-    @MethodSubstitution(isStatic = false)
+    @MethodSubstitution(isStatic = false, forced = true)
     public static boolean isPrimitive(final Class<?> thisObj) {
-        Word klass = loadWordFromObject(thisObj, klassOffset(), CLASS_KLASS_LOCATION);
+        Pointer klass = Word.fromTypePointer(ClassGetHubNode.readClass(thisObj));
         return klass.equal(0);
     }
 
@@ -87,11 +92,12 @@
     @MacroSubstitution(macro = ClassGetSuperclassNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false)
     public static Class<?> getSuperclass(final Class<?> thisObj) {
-        Word klass = loadWordFromObject(thisObj, klassOffset(), CLASS_KLASS_LOCATION);
+        TypePointer klassPtr = ClassGetHubNode.readClass(thisObj);
+        Pointer klass = Word.fromTypePointer(klassPtr);
         if (klass.notEqual(0)) {
             int accessFlags = klass.readInt(klassAccessFlagsOffset(), KLASS_ACCESS_FLAGS_LOCATION);
             if ((accessFlags & Modifier.INTERFACE) == 0) {
-                if (klassIsArray(klass)) {
+                if (klassIsArray(klassPtr)) {
                     return Object.class;
                 } else {
                     Word superKlass = klass.readWord(klassSuperKlassOffset(), KLASS_SUPER_KLASS_LOCATION);
@@ -109,9 +115,10 @@
     @MacroSubstitution(macro = ClassGetComponentTypeNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false)
     public static Class<?> getComponentType(final Class<?> thisObj) {
-        Word klass = loadWordFromObject(thisObj, klassOffset(), CLASS_KLASS_LOCATION);
+        TypePointer klassPtr = ClassGetHubNode.readClass(thisObj);
+        Pointer klass = Word.fromTypePointer(klassPtr);
         if (klass.notEqual(0)) {
-            if (klassIsArray(klass)) {
+            if (klassIsArray(klassPtr)) {
                 return piCastExactNonNull(klass.readObject(arrayKlassComponentMirrorOffset(), ARRAY_KLASS_COMPONENT_MIRROR), Class.class);
             }
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotNodeSubstitutions.java	Sat Nov 15 14:46:39 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotNodeSubstitutions.java	Sat Nov 15 16:39:23 2014 +0100
@@ -41,7 +41,7 @@
         // HotSpot creates the NodeClass for each Node subclass while initializing it
         // so we are guaranteed to read a non-null value here. As long as NodeClass
         // is final, the stamp of the PiNode below will automatically be exact.
-        Pointer klass = loadHub(node);
-        return piCastNonNull(klass.readObject(Word.signed(instanceKlassNodeClassOffset()), KLASS_NODE_CLASS), NodeClass.class);
+        TypePointer klass = loadHub(node);
+        return piCastNonNull(Word.fromTypePointer(klass).readObject(Word.signed(instanceKlassNodeClassOffset()), KLASS_NODE_CLASS), NodeClass.class);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Sat Nov 15 14:46:39 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Sat Nov 15 16:39:23 2014 +0100
@@ -34,6 +34,7 @@
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.nodes.*;
@@ -297,10 +298,18 @@
         return config().klassLayoutHelperOffset;
     }
 
-    public static int readLayoutHelper(Pointer hub) {
-        return hub.readInt(klassLayoutHelperOffset(), KLASS_LAYOUT_HELPER_LOCATION);
+    public static int readLayoutHelper(TypePointer hub) {
+        // return hub.readInt(klassLayoutHelperOffset(), KLASS_LAYOUT_HELPER_LOCATION);
+        GuardingNode anchorNode = SnippetAnchorNode.anchor();
+        return loadKlassLayoutHelperIntrinsic(hub, anchorNode);
     }
 
+    @NodeIntrinsic(value = KlassLayoutHelperNode.class)
+    public static native int loadKlassLayoutHelperIntrinsic(TypePointer object, GuardingNode anchor);
+
+    @NodeIntrinsic(value = KlassLayoutHelperNode.class)
+    public static native int loadKlassLayoutHelperIntrinsic(TypePointer object);
+
     /**
      * Checks if class {@code klass} is an array.
      *
@@ -309,7 +318,7 @@
      * @param klass the class to be checked
      * @return true if klass is an array, false otherwise
      */
-    public static boolean klassIsArray(Word klass) {
+    public static boolean klassIsArray(TypePointer klass) {
         /*
          * The less-than check only works if both values are ints. We use local variables to make
          * sure these are still ints and haven't changed.
@@ -540,8 +549,8 @@
     /**
      * Loads the hub of an object (without null checking it first).
      */
-    public static Pointer loadHub(Object object) {
-        return Word.fromTypePointer(loadHubIntrinsic(object));
+    public static TypePointer loadHub(Object object) {
+        return loadHubIntrinsic(object);
     }
 
     public static Object verifyOop(Object object) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HubGetClassNode.java	Sat Nov 15 16:39:23 2014 +0100
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2014, 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.hotspot.replacements;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.HeapAccess.BarrierType;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Read Klass::_java_mirror and incorporate non-null type information into stamp. This is also used
+ * by {@link ClassGetHubNode} to eliminate chains of klass._java_mirror._klass.
+ */
+@NodeInfo
+public class HubGetClassNode extends FloatingGuardedNode implements Lowerable, Canonicalizable {
+    @Input protected ValueNode hub;
+
+    public static HubGetClassNode create(ValueNode hub) {
+        return new HubGetClassNode(hub);
+    }
+
+    protected HubGetClassNode(ValueNode hub) {
+        super(StampFactory.declaredNonNull(runtime().fromClass(Class.class)), null);
+        this.hub = hub;
+    }
+
+    public ValueNode getHub() {
+        return hub;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (usages().isEmpty()) {
+            return null;
+        } else {
+            MetaAccessProvider metaAccess = tool.getMetaAccess();
+            if (metaAccess != null) {
+                if (hub.isConstant()) {
+                    ResolvedJavaType exactType = tool.getConstantReflection().asJavaType(hub.asJavaConstant());
+                    return ConstantNode.forConstant(exactType.getJavaClass(), metaAccess);
+                }
+            }
+            return this;
+        }
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
+            return;
+        }
+
+        HotSpotVMConfig config = runtime().getConfig();
+        LocationNode location = ConstantLocationNode.create(CLASS_MIRROR_LOCATION, Kind.Object, config.classMirrorOffset, graph());
+        assert !hub.isConstant();
+        FloatingReadNode read = graph().unique(FloatingReadNode.create(hub, location, null, stamp(), getGuard(), BarrierType.NONE));
+        graph().replaceFloating(this, read);
+    }
+
+    @NodeIntrinsic
+    public static native Class<?> readClass(TypePointer hub);
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Sat Nov 15 14:46:39 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Sat Nov 15 16:39:23 2014 +0100
@@ -186,7 +186,7 @@
             return falseValue;
         }
         GuardingNode anchorNode = SnippetAnchorNode.anchor();
-        Word hub = loadWordFromObject(mirror, klassOffset(), CLASS_KLASS_LOCATION);
+        Pointer hub = Word.fromTypePointer(ClassGetHubNode.readClass(mirror, anchorNode));
         Pointer objectHub = Word.fromTypePointer(loadHubIntrinsic(object, anchorNode));
         if (hub.equal(0) || !checkUnknownSubType(hub, objectHub)) {
             return falseValue;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/KlassLayoutHelperNode.java	Sat Nov 15 16:39:23 2014 +0100
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2014, 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.hotspot.replacements;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.HeapAccess.BarrierType;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * Read Klass::_layout_helper and incorporate any useful stamp information based on any type
+ * information in {@code klass}.
+ */
+@NodeInfo
+public class KlassLayoutHelperNode extends FloatingGuardedNode implements Canonicalizable, Lowerable {
+
+    @Input protected ValueNode klass;
+
+    public static KlassLayoutHelperNode create(ValueNode klass) {
+        return new KlassLayoutHelperNode(klass);
+    }
+
+    public static KlassLayoutHelperNode create(ValueNode klass, ValueNode guard) {
+        return new KlassLayoutHelperNode(klass, guard);
+    }
+
+    protected KlassLayoutHelperNode(ValueNode klass) {
+        super(StampFactory.forKind(Kind.Int));
+        this.klass = klass;
+    }
+
+    protected KlassLayoutHelperNode(ValueNode klass, ValueNode guard) {
+        super(StampFactory.forKind(Kind.Int), (GuardingNode) guard);
+        this.klass = klass;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        if (klass instanceof LoadHubNode) {
+            LoadHubNode hub = (LoadHubNode) klass;
+            Stamp hubStamp = hub.getValue().stamp();
+            if (hubStamp instanceof ObjectStamp) {
+                ObjectStamp objectStamp = (ObjectStamp) hubStamp;
+                ResolvedJavaType type = objectStamp.type();
+                if (type != null && !type.isJavaLangObject()) {
+                    if (!type.isArray() && !type.isInterface()) {
+                        /*
+                         * Definitely some form of instance type.
+                         */
+                        return updateStamp(StampFactory.forInteger(Kind.Int, runtime().getConfig().klassLayoutHelperNeutralValue, Integer.MAX_VALUE));
+                    }
+                    if (type.isArray()) {
+                        return updateStamp(StampFactory.forInteger(Kind.Int, Integer.MIN_VALUE, runtime().getConfig().klassLayoutHelperNeutralValue - 1));
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (usages().isEmpty()) {
+            return null;
+        } else {
+            if (klass.isConstant()) {
+                long base = klass.asJavaConstant().asLong();
+                if (base != 0L) {
+                    Constant constant = stamp().readConstant(tool.getConstantReflection(), klass.asJavaConstant(), runtime().getConfig().klassLayoutHelperOffset);
+                    return ConstantNode.forConstant(stamp(), constant, tool.getMetaAccess());
+                }
+            }
+            if (klass instanceof LoadHubNode) {
+                LoadHubNode hub = (LoadHubNode) klass;
+                Stamp hubStamp = hub.getValue().stamp();
+                if (hubStamp instanceof ObjectStamp) {
+                    ObjectStamp ostamp = (ObjectStamp) hubStamp;
+                    HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) ostamp.type();
+                    if (type != null && type.isArray() && !type.getComponentType().isPrimitive()) {
+                        // The layout for all object arrays is the same.
+                        Constant constant = stamp().readConstant(tool.getConstantReflection(), type.klass(), runtime().getConfig().klassLayoutHelperOffset);
+                        return ConstantNode.forConstant(stamp(), constant, tool.getMetaAccess());
+                    }
+                }
+            }
+            return this;
+        }
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
+            return;
+        }
+        LocationNode location = ConstantLocationNode.create(KLASS_LAYOUT_HELPER_LOCATION, Kind.Int, runtime().getConfig().klassLayoutHelperOffset, graph());
+        assert !klass.isConstant();
+        graph().replaceFloating(this, graph().unique(FloatingReadNode.create(klass, location, null, stamp(), getGuard(), BarrierType.NONE)));
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Sat Nov 15 14:46:39 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Sat Nov 15 16:39:23 2014 +0100
@@ -151,10 +151,11 @@
 
     @Snippet
     public static Object allocateInstanceDynamic(Class<?> type, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter String typeContext) {
-        Word hub = loadWordFromObject(type, klassOffset(), CLASS_KLASS_LOCATION);
+        TypePointer hubPtr = ClassGetHubNode.readClass(type);
+        Pointer hub = Word.fromTypePointer(hubPtr);
         if (probability(FAST_PATH_PROBABILITY, !hub.equal(Word.zero()))) {
             if (probability(FAST_PATH_PROBABILITY, isInstanceKlassFullyInitialized(hub))) {
-                int layoutHelper = readLayoutHelper(hub);
+                int layoutHelper = readLayoutHelper(hubPtr);
                 /*
                  * src/share/vm/oops/klass.hpp: For instances, layout helper is a positive number,
                  * the instance size. This size is already passed through align_object_size and
@@ -223,7 +224,7 @@
             return dynamicNewArrayStub(DYNAMIC_NEW_ARRAY, elementType, length);
         }
 
-        int layoutHelper = readLayoutHelper(hub);
+        int layoutHelper = readLayoutHelper(hub.toTypePointer());
         //@formatter:off
         // from src/share/vm/oops/klass.hpp:
         //
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectGetClassNode.java	Sat Nov 15 14:46:39 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, 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.hotspot.replacements;
-
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * This macro node will replace itself with the correct Java {@link Class} as soon as the object's
- * type is known (exact).
- */
-@NodeInfo
-public class ObjectGetClassNode extends MacroNode implements Virtualizable, Canonicalizable {
-
-    public static ObjectGetClassNode create(Invoke invoke) {
-        return new ObjectGetClassNode(invoke);
-    }
-
-    protected ObjectGetClassNode(Invoke invoke) {
-        super(invoke);
-    }
-
-    private ValueNode getObject() {
-        return arguments.get(0);
-    }
-
-    @Override
-    public void virtualize(VirtualizerTool tool) {
-        if (ImmutableCode.getValue()) {
-            return;
-        }
-        State state = tool.getObjectState(getObject());
-        if (state != null) {
-            JavaConstant clazz = state.getVirtualObject().type().getJavaClass();
-            tool.replaceWithValue(ConstantNode.forConstant(clazz, tool.getMetaAccessProvider(), graph()));
-        }
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (ImmutableCode.getValue()) {
-            return this;
-        }
-        if (usages().isEmpty()) {
-            return null;
-        } else {
-            ResolvedJavaType type = StampTool.typeOrNull(getObject());
-            if (StampTool.isExactType(getObject())) {
-                JavaConstant clazz = type.getJavaClass();
-                return ConstantNode.forConstant(clazz, tool.getMetaAccess());
-            }
-            if (type != null && tool.assumptions().useOptimisticAssumptions()) {
-                ResolvedJavaType exactType = type.findUniqueConcreteSubtype();
-                if (exactType != null) {
-                    tool.assumptions().recordConcreteSubtype(type, exactType);
-                    JavaConstant clazz = exactType.getJavaClass();
-                    return ConstantNode.forConstant(clazz, tool.getMetaAccess());
-                }
-            }
-            return this;
-        }
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java	Sat Nov 15 14:46:39 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java	Sat Nov 15 16:39:23 2014 +0100
@@ -23,9 +23,9 @@
 package com.oracle.graal.hotspot.replacements;
 
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.nodes.PiNode.*;
 
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
@@ -36,11 +36,10 @@
 @ClassSubstitution(java.lang.Object.class)
 public class ObjectSubstitutions {
 
-    @MacroSubstitution(macro = ObjectGetClassNode.class, isStatic = false, forced = true)
     @MethodSubstitution(isStatic = false, forced = true)
     public static Class<?> getClass(final Object thisObj) {
-        Pointer hub = loadHub(thisObj);
-        return piCastExactNonNull(hub.readObject(Word.signed(classMirrorOffset()), CLASS_MIRROR_LOCATION), Class.class);
+        TypePointer hub = loadHub(GuardingPiNode.guardingNonNull(thisObj));
+        return HubGetClassNode.readClass(hub);
     }
 
     @MethodSubstitution(isStatic = false)
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Sat Nov 15 14:46:39 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Sat Nov 15 16:39:23 2014 +0100
@@ -84,7 +84,7 @@
      */
     @Snippet
     private static Object newArray(TypePointer hub, int length, @ConstantParameter TypePointer intArrayHub, @ConstantParameter Register threadRegister) {
-        int layoutHelper = Word.fromTypePointer(hub).readInt(klassLayoutHelperOffset(), KLASS_LAYOUT_HELPER_LOCATION);
+        int layoutHelper = loadKlassLayoutHelperIntrinsic(hub);
         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
         int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask();
         int elementKind = (layoutHelper >> layoutHelperElementTypeShift()) & layoutHelperElementTypeMask();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Sat Nov 15 14:46:39 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Sat Nov 15 16:39:23 2014 +0100
@@ -102,7 +102,7 @@
          * raw number
          */
         Pointer hubPtr = Word.fromTypePointer(hub);
-        int sizeInBytes = hubPtr.readInt(klassLayoutHelperOffset(), KLASS_LAYOUT_HELPER_LOCATION);
+        int sizeInBytes = loadKlassLayoutHelperIntrinsic(hub);
         Word thread = registerAsWord(threadRegister);
         if (!forceSlowPath() && inlineContiguousAllocationSupported()) {
             if (isInstanceKlassFullyInitialized(hubPtr)) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Sat Nov 15 14:46:39 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Sat Nov 15 16:39:23 2014 +0100
@@ -62,6 +62,9 @@
 
     @Override
     public void lower(LoweringTool tool) {
+        if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
+            return;
+        }
         tool.getLowerer().lower(this, tool);
     }