changeset 18359:a3a2359ac88e

Support constant folding of pointer reads.
author Roland Schatz <roland.schatz@oracle.com>
date Tue, 11 Nov 2014 18:34:21 +0100
parents 2dc0d4dcb709
children 6a5dc0bbebe7
files graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantReflectionProvider.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractPointerStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstantImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowOopStamp.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowPointerStamp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java
diffstat 13 files changed, 167 insertions(+), 120 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantReflectionProvider.java	Tue Nov 11 15:03:10 2014 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantReflectionProvider.java	Tue Nov 11 18:34:21 2014 +0100
@@ -71,9 +71,19 @@
      * @param base the base address from which the value is read
      * @param displacement the displacement within the object in bytes
      * @param bits the number of bits to read from memory
-     * @return the read value encapsulated in a {@link JavaConstant} object of {@link Kind} kind
+     * @return the read value encapsulated in a {@link Constant} object of {@link Kind} kind
      */
-    JavaConstant readRawConstant(Kind kind, JavaConstant base, long displacement, int bits);
+    JavaConstant readRawConstant(Kind kind, Constant base, long displacement, int bits);
+
+    /**
+     * Reads a pointer value using a base address and a displacement.
+     *
+     * @param type the {@link PointerType} of the returned {@link Constant} object
+     * @param base the base address from which the value is read
+     * @param displacement the displacement within the object in bytes
+     * @return the read value encapsulated in a {@link Constant} object
+     */
+    Constant readPointerConstant(PointerType type, Constant base, long displacement);
 
     /**
      * Converts the given {@link Kind#isPrimitive() primitive} constant to a boxed
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractPointerStamp.java	Tue Nov 11 15:03:10 2014 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractPointerStamp.java	Tue Nov 11 18:34:21 2014 +0100
@@ -61,6 +61,11 @@
     }
 
     @Override
+    public Constant readConstant(ConstantReflectionProvider provider, Constant base, long displacement) {
+        return provider.readPointerConstant(type, base, displacement);
+    }
+
+    @Override
     public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
         throw GraalInternalError.shouldNotReachHere(type + " pointer has no Java type");
     }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java	Tue Nov 11 15:03:10 2014 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java	Tue Nov 11 18:34:21 2014 +0100
@@ -89,6 +89,11 @@
         return false;
     }
 
+    @Override
+    public Constant readConstant(ConstantReflectionProvider provider, Constant base, long displacement) {
+        throw GraalInternalError.shouldNotReachHere("can't read values of illegal stamp");
+    }
+
     private static IllegalStamp instance = new IllegalStamp();
 
     static IllegalStamp getInstance() {
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java	Tue Nov 11 15:03:10 2014 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java	Tue Nov 11 18:34:21 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.compiler.common.type;
 
+import com.oracle.graal.api.meta.*;
+
 /**
  * Type describing primitive values.
  */
@@ -50,6 +52,11 @@
     }
 
     @Override
+    public Constant readConstant(ConstantReflectionProvider provider, Constant base, long displacement) {
+        return provider.readRawConstant(getStackKind(), base, displacement, getBits());
+    }
+
+    @Override
     public int hashCode() {
         final int prime = 31;
         int result = super.hashCode();
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Tue Nov 11 15:03:10 2014 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Tue Nov 11 18:34:21 2014 +0100
@@ -116,10 +116,12 @@
         return null;
     }
 
+    public abstract Constant readConstant(ConstantReflectionProvider provider, Constant base, long displacement);
+
     /**
      * Tries to improve this stamp with the stamp given as parameter. If successful, returns the new
      * improved stamp. Otherwise, returns null.
-     * 
+     *
      * @param other the stamp that should be used to improve this stamp
      * @return the newly improved stamp of null if an improvement was not possible
      */
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java	Tue Nov 11 15:03:10 2014 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java	Tue Nov 11 18:34:21 2014 +0100
@@ -103,6 +103,11 @@
     }
 
     @Override
+    public Constant readConstant(ConstantReflectionProvider provider, Constant base, long displacement) {
+        throw GraalInternalError.shouldNotReachHere("can't read values of void stamp");
+    }
+
+    @Override
     public Stamp constant(Constant c, MetaAccessProvider meta) {
         throw GraalInternalError.shouldNotReachHere("void stamp has no value");
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Tue Nov 11 15:03:10 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Tue Nov 11 18:34:21 2014 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.hotspot.meta;
 
 import static com.oracle.graal.compiler.common.UnsafeAccess.*;
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 
 import java.lang.reflect.*;
 
@@ -61,94 +60,22 @@
         return Array.getLength(arrayObject);
     }
 
-    @Override
-    public JavaConstant readUnsafeConstant(Kind kind, JavaConstant baseConstant, long initialDisplacement) {
+    private static long readRawValue(Constant baseConstant, long initialDisplacement, int bits) {
         Object base;
         long displacement;
-        if (baseConstant.getKind() == Kind.Object) {
-            base = baseConstant.isNull() ? null : ((HotSpotObjectConstantImpl) baseConstant).object();
-            displacement = initialDisplacement;
-            if (base == null) {
-                return null;
-            }
-        } else if (baseConstant.getKind().isNumericInteger()) {
-            long baseLong = baseConstant.asLong();
-            if (baseLong == 0L) {
-                return null;
+        if (baseConstant instanceof JavaConstant) {
+            JavaConstant javaConstant = (JavaConstant) baseConstant;
+            if (javaConstant instanceof HotSpotObjectConstantImpl) {
+                base = ((HotSpotObjectConstantImpl) javaConstant).object();
+                displacement = initialDisplacement;
+            } else if (javaConstant.getKind().isNumericInteger()) {
+                long baseLong = javaConstant.asLong();
+                assert baseLong != 0;
+                displacement = initialDisplacement + baseLong;
+                base = null;
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
             }
-            displacement = initialDisplacement + baseLong;
-            base = null;
-        } else {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-
-        switch (kind) {
-            case Boolean:
-                return JavaConstant.forBoolean(base == null ? unsafe.getByte(displacement) != 0 : unsafe.getBoolean(base, displacement));
-            case Byte:
-                return JavaConstant.forByte(base == null ? unsafe.getByte(displacement) : unsafe.getByte(base, displacement));
-            case Char:
-                return JavaConstant.forChar(base == null ? unsafe.getChar(displacement) : unsafe.getChar(base, displacement));
-            case Short:
-                return JavaConstant.forShort(base == null ? unsafe.getShort(displacement) : unsafe.getShort(base, displacement));
-            case Int:
-                return JavaConstant.forInt(base == null ? unsafe.getInt(displacement) : unsafe.getInt(base, displacement));
-            case Long:
-                if (displacement == config().hubOffset && runtime.getConfig().useCompressedClassPointers) {
-                    if (base == null) {
-                        throw new GraalInternalError("Base of object must not be null");
-                    } else {
-                        return JavaConstant.forLong(runtime.getCompilerToVM().readUnsafeKlassPointer(base));
-                    }
-                } else {
-                    return JavaConstant.forLong(base == null ? unsafe.getLong(displacement) : unsafe.getLong(base, displacement));
-                }
-            case Float:
-                return JavaConstant.forFloat(base == null ? unsafe.getFloat(displacement) : unsafe.getFloat(base, displacement));
-            case Double:
-                return JavaConstant.forDouble(base == null ? unsafe.getDouble(displacement) : unsafe.getDouble(base, displacement));
-            case Object: {
-                Object o = null;
-                if (baseConstant.getKind() == Kind.Object) {
-                    o = unsafe.getObject(base, displacement);
-                } else if (baseConstant instanceof HotSpotMetaspaceConstant) {
-                    Object metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(baseConstant);
-                    if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl && initialDisplacement == runtime.getConfig().classMirrorOffset) {
-                        o = ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror();
-                    } else if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl && initialDisplacement == runtime.getConfig().arrayKlassComponentMirrorOffset) {
-                        o = ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror().getComponentType();
-                    } else if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl && initialDisplacement == runtime.getConfig().instanceKlassNodeClassOffset) {
-                        o = NodeClass.get(((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror());
-                    } else {
-                        throw GraalInternalError.shouldNotReachHere();
-                    }
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
-                return HotSpotObjectConstantImpl.forObject(o);
-            }
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    @Override
-    public JavaConstant readRawConstant(Kind kind, JavaConstant baseConstant, long initialDisplacement, int bits) {
-        Object base;
-        long displacement;
-        if (baseConstant.getKind() == Kind.Object) {
-            base = baseConstant.isNull() ? null : ((HotSpotObjectConstantImpl) baseConstant).object();
-            displacement = initialDisplacement;
-            if (base == null) {
-                return null;
-            }
-        } else if (baseConstant.getKind().isNumericInteger()) {
-            long baseLong = baseConstant.asLong();
-            if (baseLong == 0L) {
-                return null;
-            }
-            displacement = initialDisplacement + baseLong;
-            base = null;
         } else {
             throw GraalInternalError.shouldNotReachHere();
         }
@@ -170,22 +97,54 @@
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
+        return rawValue;
+    }
 
-        if (base != null && displacement == config().hubOffset) {
-            if (config().useCompressedClassPointers) {
-                assert bits == 32 && kind == Kind.Int;
-                long klassPointer = config().getKlassEncoding().uncompress((int) rawValue);
-                assert klassPointer == runtime.getCompilerToVM().readUnsafeKlassPointer(base);
-                return HotSpotMetaspaceConstantImpl.forMetaspaceObject(kind, rawValue, HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(klassPointer), true);
-            } else {
-                assert bits == 64 && kind == Kind.Long;
-                return HotSpotMetaspaceConstantImpl.forMetaspaceObject(kind, rawValue, HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(rawValue), false);
+    private Object readRawObject(Constant baseConstant, long displacement, boolean compressed) {
+        if (baseConstant instanceof HotSpotObjectConstantImpl) {
+            assert compressed == runtime.getConfig().useCompressedOops;
+            return unsafe.getObject(((HotSpotObjectConstantImpl) baseConstant).object(), displacement);
+        } else if (baseConstant instanceof HotSpotMetaspaceConstant) {
+            Object metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(baseConstant);
+            if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) {
+                assert !compressed : "unexpected compressed read from Klass*";
+                if (displacement == runtime.getConfig().classMirrorOffset) {
+                    return ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror();
+                } else if (displacement == runtime.getConfig().arrayKlassComponentMirrorOffset) {
+                    return ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror().getComponentType();
+                } else if (displacement == runtime.getConfig().instanceKlassNodeClassOffset) {
+                    return NodeClass.get(((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror());
+                }
             }
-        } else if (displacement == config().klassOffset && base instanceof Class) {
-            long value = unsafe.getLong(base, displacement);
-            return HotSpotMetaspaceConstantImpl.forMetaspaceObject(kind, value, runtime.getHostProviders().getMetaAccess().lookupJavaType((Class<?>) base), false);
+            throw GraalInternalError.shouldNotReachHere("read from unknown Klass* offset " + displacement);
+        } else {
+            throw GraalInternalError.shouldNotReachHere("unexpected base pointer: " + (baseConstant == null ? "null" : baseConstant.toString()));
+        }
+    }
+
+    @Override
+    public JavaConstant readUnsafeConstant(Kind kind, JavaConstant baseConstant, long displacement) {
+        if (kind == Kind.Object) {
+            Object o = readRawObject(baseConstant, displacement, runtime.getConfig().useCompressedOops);
+            return HotSpotObjectConstantImpl.forObject(o);
         } else {
+            return readRawConstant(kind, baseConstant, displacement, kind.getByteCount() * 8);
+        }
+    }
+
+    @Override
+    public JavaConstant readRawConstant(Kind kind, Constant baseConstant, long initialDisplacement, int bits) {
+        try {
+            long rawValue = readRawValue(baseConstant, initialDisplacement, bits);
             switch (kind) {
+                case Boolean:
+                    return JavaConstant.forBoolean(rawValue != 0);
+                case Byte:
+                    return JavaConstant.forByte((byte) rawValue);
+                case Char:
+                    return JavaConstant.forChar((char) rawValue);
+                case Short:
+                    return JavaConstant.forShort((short) rawValue);
                 case Int:
                     return JavaConstant.forInt((int) rawValue);
                 case Long:
@@ -195,8 +154,51 @@
                 case Double:
                     return JavaConstant.forDouble(Double.longBitsToDouble(rawValue));
                 default:
-                    throw GraalInternalError.shouldNotReachHere();
+                    throw GraalInternalError.shouldNotReachHere("unsupported kind: " + kind);
             }
+        } catch (NullPointerException e) {
+            return null;
+        }
+    }
+
+    public Constant readPointerConstant(PointerType type, Constant base, long displacement) {
+        switch (type) {
+            case Object:
+                if (base instanceof PrimitiveConstant && !(base instanceof HotSpotMetaspaceConstant)) {
+                    // FIXME: we lost a metaspace annotation somewhere
+                    return null;
+                }
+                return HotSpotObjectConstantImpl.forObject(readRawObject(base, displacement, false));
+            case Type:
+                long klass = readRawValue(base, displacement, runtime.getTarget().wordSize * 8);
+                HotSpotResolvedObjectType metaKlass = HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(klass);
+                return HotSpotMetaspaceConstantImpl.forMetaspaceObject(runtime.getTarget().wordKind, klass, metaKlass, false);
+            case Method:
+                long method = readRawValue(base, displacement, runtime.getTarget().wordSize * 8);
+                HotSpotResolvedJavaMethod metaMethod = HotSpotResolvedJavaMethodImpl.fromMetaspace(method);
+                return HotSpotMetaspaceConstantImpl.forMetaspaceObject(runtime.getTarget().wordKind, method, metaMethod, false);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    public Constant readNarrowPointerConstant(PointerType type, Constant base, long displacement) {
+        switch (type) {
+            case Object:
+                if (base instanceof PrimitiveConstant && !(base instanceof HotSpotMetaspaceConstant)) {
+                    // FIXME: we lost a metaspace annotation somewhere
+                    return null;
+                }
+                return HotSpotObjectConstantImpl.forObject(readRawObject(base, displacement, true), true);
+            case Type:
+                int compressed = (int) readRawValue(base, displacement, 32);
+                long klass = runtime.getConfig().getKlassEncoding().uncompress(compressed);
+                HotSpotResolvedObjectType metaKlass = HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(klass);
+                return HotSpotMetaspaceConstantImpl.forMetaspaceObject(Kind.Int, compressed, metaKlass, true);
+            case Method:
+                // there are no compressed method pointers
+            default:
+                throw GraalInternalError.shouldNotReachHere();
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstantImpl.java	Tue Nov 11 15:03:10 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstantImpl.java	Tue Nov 11 18:34:21 2014 +0100
@@ -36,7 +36,7 @@
         return new HotSpotMetaspaceConstantImpl(kind, primitive, metaspaceObject, compressed);
     }
 
-    static Object getMetaspaceObject(JavaConstant constant) {
+    static Object getMetaspaceObject(Constant constant) {
         return ((HotSpotMetaspaceConstantImpl) constant).metaspaceObject;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Tue Nov 11 15:03:10 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Tue Nov 11 18:34:21 2014 +0100
@@ -40,10 +40,14 @@
     private static final long serialVersionUID = 3592151693708093496L;
 
     public static JavaConstant forObject(Object object) {
+        return forObject(object, false);
+    }
+
+    public static JavaConstant forObject(Object object, boolean compressed) {
         if (object == null) {
-            return JavaConstant.NULL_OBJECT;
+            return compressed ? HotSpotCompressedNullConstant.COMPRESSED_NULL : JavaConstant.NULL_OBJECT;
         } else {
-            return new HotSpotObjectConstantImpl(object, false);
+            return new HotSpotObjectConstantImpl(object, compressed);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Tue Nov 11 15:03:10 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Tue Nov 11 18:34:21 2014 +0100
@@ -81,6 +81,9 @@
         } else if (c instanceof HotSpotMetaspaceConstant) {
             assert ((HotSpotMetaspaceConstant) c).stamp().getStackKind() == Kind.Long;
             return ((HotSpotMetaspaceConstant) c).compress(encoding);
+        } else if (c instanceof PrimitiveConstant) {
+            assert ((PrimitiveConstant) c).getKind() == Kind.Long;
+            return JavaConstant.forInt(encoding.compress(((PrimitiveConstant) c).asLong()));
         } else {
             throw GraalInternalError.shouldNotReachHere("invalid constant input for compress op: " + c);
         }
@@ -94,6 +97,9 @@
         } else if (c instanceof HotSpotMetaspaceConstant) {
             assert ((HotSpotMetaspaceConstant) c).stamp().getStackKind() == Kind.Int;
             return ((HotSpotMetaspaceConstant) c).uncompress(encoding);
+        } else if (c instanceof PrimitiveConstant) {
+            assert ((PrimitiveConstant) c).getKind() == Kind.Int;
+            return JavaConstant.forLong(encoding.uncompress(((PrimitiveConstant) c).asInt()));
         } else {
             throw GraalInternalError.shouldNotReachHere("invalid constant input for uncompress op: " + c);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowOopStamp.java	Tue Nov 11 15:03:10 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowOopStamp.java	Tue Nov 11 18:34:21 2014 +0100
@@ -80,6 +80,11 @@
     }
 
     @Override
+    public Constant readConstant(ConstantReflectionProvider provider, Constant base, long displacement) {
+        return ((HotSpotConstantReflectionProvider) provider).readNarrowPointerConstant(PointerType.Object, base, displacement);
+    }
+
+    @Override
     public int hashCode() {
         final int prime = 31;
         int result = super.hashCode();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowPointerStamp.java	Tue Nov 11 15:03:10 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowPointerStamp.java	Tue Nov 11 18:34:21 2014 +0100
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.spi.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.*;
+import com.oracle.graal.hotspot.meta.*;
 
 public class NarrowPointerStamp extends AbstractPointerStamp {
 
@@ -87,6 +88,11 @@
     }
 
     @Override
+    public Constant readConstant(ConstantReflectionProvider provider, Constant base, long displacement) {
+        return ((HotSpotConstantReflectionProvider) provider).readNarrowPointerConstant(getType(), base, displacement);
+    }
+
+    @Override
     public boolean isLegal() {
         return true;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Tue Nov 11 15:03:10 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Tue Nov 11 18:34:21 2014 +0100
@@ -119,22 +119,12 @@
     public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool) {
         MetaAccessProvider metaAccess = tool.getMetaAccess();
         if (tool.canonicalizeReads()) {
-            if (metaAccess != null && object != null && object.isConstant()) {
+            if (metaAccess != null && object != null && object.isConstant() && !object.isNullConstant()) {
                 if ((location.getLocationIdentity().isImmutable()) && location instanceof ConstantLocationNode) {
                     long displacement = ((ConstantLocationNode) location).getDisplacement();
-                    JavaConstant base = object.asJavaConstant();
-                    if (base != null) {
-                        JavaConstant constant;
-                        if (read.stamp() instanceof PrimitiveStamp) {
-                            PrimitiveStamp stamp = (PrimitiveStamp) read.stamp();
-                            constant = tool.getConstantReflection().readRawConstant(stamp.getStackKind(), base, displacement, stamp.getBits());
-                        } else {
-                            assert read.stamp() instanceof ObjectStamp;
-                            constant = tool.getConstantReflection().readUnsafeConstant(Kind.Object, base, displacement);
-                        }
-                        if (constant != null) {
-                            return ConstantNode.forConstant(read.stamp(), constant, metaAccess);
-                        }
+                    Constant constant = read.stamp().readConstant(tool.getConstantReflection(), object.asConstant(), displacement);
+                    if (constant != null) {
+                        return ConstantNode.forConstant(read.stamp(), constant, metaAccess);
                     }
                 }
             }