changeset 13136:3adfe375b01b

Merge
author Christian Wimmer <christian.wimmer@oracle.com>
date Fri, 22 Nov 2013 13:41:17 -0800
parents c7ce697ddb9a (diff) 124860fac470 (current diff)
children 438ed35bed29
files graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java
diffstat 42 files changed, 320 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Address.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Address.java	Fri Nov 22 13:41:17 2013 -0800
@@ -70,6 +70,8 @@
         this.index = index;
         this.scale = scale;
         this.displacement = displacement;
+
+        assert scale != null;
     }
 
     /**
@@ -104,7 +106,7 @@
                 case 8:
                     return Times8;
                 default:
-                    throw new IllegalArgumentException(String.valueOf(scale));
+                    return null;
             }
         }
     }
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri Nov 22 13:41:17 2013 -0800
@@ -164,6 +164,17 @@
             if (isConstant(index)) {
                 finalDisp += asConstant(index).asLong() * scale;
                 indexRegister = Value.ILLEGAL;
+
+            } else if (scaleEnum == null) {
+                /* Scale value that architecture cannot handle, so scale manually. */
+                Value longIndex = index.getKind().getStackKind() == Kind.Int ? emitConvert(Kind.Int, Kind.Long, index) : index;
+                if (CodeUtil.isPowerOf2(scale)) {
+                    indexRegister = emitShl(longIndex, Constant.forLong(CodeUtil.log2(scale)));
+                } else {
+                    indexRegister = emitMul(longIndex, Constant.forLong(scale));
+                }
+                scaleEnum = Scale.Times1;
+
             } else {
                 indexRegister = asAllocatable(index);
             }
@@ -812,7 +823,10 @@
         Kind from = inputVal.getKind();
         AllocatableValue input = asAllocatable(inputVal);
 
-        // These cases require a move between CPU and FPU registers:
+        /*
+         * Conversions between integer to floating point types require moves between CPU and FPU
+         * registers.
+         */
         switch (to) {
             case Int:
                 switch (from) {
@@ -826,6 +840,19 @@
                     case Float:
                     case Double:
                         return emitConvert2Op(to, MOV_D2L, input);
+                    case Int:
+                        /*
+                         * Unsigned int-to-long conversion: In theory, instructions that move or
+                         * generate 32-bit register values also set the upper 32 bits of the
+                         * register to zero. However, we cannot rely that the value was really
+                         * generated by an instruction, it could come from an untrusted source such
+                         * as native code. Therefore, make sure the high bits are really cleared.
+                         */
+                        Variable temp = newVariable(Kind.Int);
+                        Variable result = newVariable(Kind.Long);
+                        append(new BinaryRegConst(AMD64Arithmetic.IAND, temp, input, Constant.forInt(0xFFFFFFFF)));
+                        emitMove(result, temp);
+                        return result;
                 }
                 break;
             case Float:
@@ -843,12 +870,7 @@
                 }
                 break;
         }
-
-        // Otherwise, just emit an ordinary move instruction.
-        // Instructions that move or generate 32-bit register values also set the upper 32
-        // bits of the register to zero.
-        // Consequently, there is no need for a special zero-extension move.
-        return emitConvertMove(to, input);
+        throw GraalInternalError.shouldNotReachHere();
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Fri Nov 22 13:41:17 2013 -0800
@@ -212,6 +212,10 @@
         return providers;
     }
 
+    protected TargetDescription getTarget() {
+        return getProviders().getCodeCache().getTarget();
+    }
+
     protected CodeCacheProvider getCodeCache() {
         return getProviders().getCodeCache();
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Fri Nov 22 13:41:17 2013 -0800
@@ -37,7 +37,7 @@
 
 public class HighTier extends PhaseSuite<HighTierContext> {
 
-    static class Options {
+    public static class Options {
 
         // @formatter:off
         @Option(help = "")
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Fri Nov 22 13:41:17 2013 -0800
@@ -89,7 +89,9 @@
 
         appendPhase(new FrameStateAssignmentPhase());
 
-        appendPhase(new DeoptimizationGroupingPhase());
+        if (OptDeoptimizationGrouping.getValue()) {
+            appendPhase(new DeoptimizationGroupingPhase());
+        }
 
         if (OptCanonicalizer.getValue()) {
             appendPhase(canonicalizer);
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Nov 22 13:41:17 2013 -0800
@@ -158,13 +158,17 @@
      */
     private final boolean isSimplifiable;
 
-    private NodeClass(Class<?> clazz) {
+    public NodeClass(Class<?> clazz) {
+        this(clazz, new DefaultCalcOffset(), null, 0);
+    }
+
+    public NodeClass(Class<?> clazz, CalcOffset calcOffset, int[] presetIterableIds, int presetIterableId) {
         super(clazz);
         assert NODE_CLASS.isAssignableFrom(clazz);
         this.isCanonicalizable = Canonicalizable.class.isAssignableFrom(clazz);
         this.isSimplifiable = Simplifiable.class.isAssignableFrom(clazz);
 
-        FieldScanner scanner = new FieldScanner(new DefaultCalcOffset());
+        FieldScanner scanner = new FieldScanner(calcOffset);
         scanner.scan(clazz);
 
         directInputCount = scanner.inputOffsets.size();
@@ -200,7 +204,10 @@
         }
         this.nameTemplate = newNameTemplate == null ? newShortName : newNameTemplate;
         this.shortName = newShortName;
-        if (IterableNodeType.class.isAssignableFrom(clazz)) {
+        if (presetIterableIds != null) {
+            this.iterableIds = presetIterableIds;
+            this.iterableId = presetIterableId;
+        } else if (IterableNodeType.class.isAssignableFrom(clazz)) {
             ITERABLE_NODE_TYPES.increment();
             this.iterableId = nextIterableId++;
             List<NodeClass> existingClasses = new LinkedList<>();
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Fri Nov 22 13:41:17 2013 -0800
@@ -84,7 +84,7 @@
     }
 
     protected Replacements createReplacements(HotSpotGraalRuntime runtime, Assumptions assumptions, Providers p) {
-        return new HotSpotReplacementsImpl(p, runtime.getConfig(), assumptions);
+        return new HotSpotReplacementsImpl(p, runtime.getConfig(), assumptions, p.getCodeCache().getTarget());
     }
 
     protected AMD64HotSpotForeignCallsProvider createForeignCalls(HotSpotGraalRuntime runtime, HotSpotMetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache,
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Fri Nov 22 13:41:17 2013 -0800
@@ -48,7 +48,7 @@
         // to be valid for the entire run of the VM.
         Assumptions assumptions = new Assumptions(false);
         Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null);
-        Replacements replacements = new HSAILHotSpotReplacementsImpl(p, assumptions, host.getReplacements());
+        Replacements replacements = new HSAILHotSpotReplacementsImpl(p, assumptions, codeCache.getTarget(), host.getReplacements());
         HotSpotDisassemblerProvider disassembler = host.getDisassembler();
         HotSpotSuitesProvider suites = host.getSuites();
         HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers);
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java	Fri Nov 22 13:41:17 2013 -0800
@@ -38,8 +38,8 @@
 
     private final Replacements host;
 
-    public HSAILHotSpotReplacementsImpl(Providers providers, Assumptions assumptions, Replacements host) {
-        super(providers, assumptions);
+    public HSAILHotSpotReplacementsImpl(Providers providers, Assumptions assumptions, TargetDescription target, Replacements host) {
+        super(providers, assumptions, target);
         this.host = host;
     }
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Fri Nov 22 13:41:17 2013 -0800
@@ -61,7 +61,7 @@
         // to be valid for the entire run of the VM.
         Assumptions assumptions = new Assumptions(false);
         Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null);
-        HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, runtime.getConfig(), assumptions);
+        HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, runtime.getConfig(), assumptions, target);
         HotSpotDisassemblerProvider disassembler = new HotSpotDisassemblerProvider(runtime);
         HotSpotSuitesProvider suites = new HotSpotSuitesProvider(runtime);
         HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Fri Nov 22 13:41:17 2013 -0800
@@ -40,8 +40,8 @@
 
     private final HotSpotVMConfig config;
 
-    public HotSpotReplacementsImpl(Providers providers, HotSpotVMConfig config, Assumptions assumptions) {
-        super(providers, assumptions);
+    public HotSpotReplacementsImpl(Providers providers, HotSpotVMConfig config, Assumptions assumptions, TargetDescription target) {
+        super(providers, assumptions, target);
         this.config = config;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Fri Nov 22 13:41:17 2013 -0800
@@ -520,6 +520,8 @@
             boxingSnippets.lower((BoxNode) n, tool);
         } else if (n instanceof UnboxNode) {
             boxingSnippets.lower((UnboxNode) n, tool);
+        } else if (n instanceof DeoptimizeNode || n instanceof UnwindNode) {
+            /* No lowering, we generate LIR directly for these nodes. */
         } else {
             assert false : "Node implementing Lowerable not handled: " + n;
             throw GraalInternalError.shouldNotReachHere();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Fri Nov 22 13:41:17 2013 -0800
@@ -317,7 +317,7 @@
 
     private void inline(InvokeNode invoke) {
         ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
-        ReplacementsImpl repl = new ReplacementsImpl(providers, new Assumptions(false));
+        ReplacementsImpl repl = new ReplacementsImpl(providers, new Assumptions(false), providers.getCodeCache().getTarget());
         StructuredGraph calleeGraph = repl.makeGraph(method, null, null, false);
         InliningUtil.inline(invoke, calleeGraph, false);
     }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Nov 22 13:41:17 2013 -0800
@@ -159,6 +159,10 @@
         return currentGraph;
     }
 
+    protected ResolvedJavaMethod getMethod() {
+        return method;
+    }
+
     public GraphBuilderPhase(MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
         this.graphBuilderConfig = graphBuilderConfig;
         this.optimisticOpts = optimisticOpts;
@@ -864,12 +868,16 @@
     void genNewInstance(int cpi) {
         JavaType type = lookupType(cpi, NEW);
         if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) {
-            frameState.apush(append(new NewInstanceNode((ResolvedJavaType) type, true)));
+            frameState.apush(append(createNewInstance((ResolvedJavaType) type, true)));
         } else {
             handleUnresolvedNewInstance(type);
         }
     }
 
+    protected NewInstanceNode createNewInstance(ResolvedJavaType type, boolean fillContents) {
+        return new NewInstanceNode(type, fillContents);
+    }
+
     /**
      * Gets the kind of array elements for the array type code that appears in a
      * {@link Bytecodes#NEWARRAY} bytecode.
@@ -905,20 +913,24 @@
     private void genNewPrimitiveArray(int typeCode) {
         Class<?> clazz = arrayTypeCodeToClass(typeCode);
         ResolvedJavaType elementType = metaAccess.lookupJavaType(clazz);
-        frameState.apush(append(new NewArrayNode(elementType, frameState.ipop(), true)));
+        frameState.apush(append(createNewArray(elementType, frameState.ipop(), true)));
     }
 
     private void genNewObjectArray(int cpi) {
         JavaType type = lookupType(cpi, ANEWARRAY);
         ValueNode length = frameState.ipop();
         if (type instanceof ResolvedJavaType) {
-            frameState.apush(append(new NewArrayNode((ResolvedJavaType) type, length, true)));
+            frameState.apush(append(createNewArray((ResolvedJavaType) type, length, true)));
         } else {
             handleUnresolvedNewObjectArray(type, length);
         }
 
     }
 
+    protected NewArrayNode createNewArray(ResolvedJavaType elementType, ValueNode length, boolean fillContents) {
+        return new NewArrayNode(elementType, length, fillContents);
+    }
+
     private void genNewMultiArray(int cpi) {
         JavaType type = lookupType(cpi, MULTIANEWARRAY);
         int rank = stream().readUByte(bci() + 3);
@@ -1187,16 +1199,21 @@
                 args[0] = TypeProfileProxyNode.create(args[0], profile);
             }
         }
-        MethodCallTargetNode callTarget = currentGraph.add(new MethodCallTargetNode(invokeKind, targetMethod, args, returnType));
+        MethodCallTargetNode callTarget = currentGraph.add(createMethodCallTarget(invokeKind, targetMethod, args, returnType));
         createInvokeNode(callTarget, resultType);
     }
 
+    protected MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, JavaType returnType) {
+        return new MethodCallTargetNode(invokeKind, targetMethod, args, returnType);
+    }
+
     protected Invoke createInvokeNode(CallTargetNode callTarget, Kind resultType) {
         // be conservative if information was not recorded (could result in endless recompiles
         // otherwise)
         if (graphBuilderConfig.omitAllExceptionEdges() || (optimisticOpts.useExceptionProbability() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE)) {
-            frameState.pushReturn(resultType, append(new InvokeNode(callTarget, bci())));
-            return new InvokeNode(callTarget, bci());
+            InvokeNode invoke = new InvokeNode(callTarget, bci());
+            frameState.pushReturn(resultType, append(invoke));
+            return invoke;
         } else {
             DispatchBeginNode exceptionEdge = handleException(null, bci());
             InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci()));
@@ -1636,15 +1653,15 @@
         ValueNode x = returnKind == Kind.Void ? null : frameState.pop(returnKind);
         assert frameState.stackSize() == 0;
 
+        if (graphBuilderConfig.eagerInfopointMode()) {
+            append(new InfopointNode(InfopointReason.METHOD_END, frameState.create(bci())));
+        }
+
         synchronizedEpilogue(FrameState.AFTER_BCI, x);
         if (frameState.lockDepth() != 0) {
             throw new BailoutException("unbalanced monitors");
         }
 
-        if (graphBuilderConfig.eagerInfopointMode()) {
-            append(new InfopointNode(InfopointReason.METHOD_END, frameState.create(FrameState.AFTER_BCI)));
-        }
-
         append(new ReturnNode(x));
     }
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Fri Nov 22 13:41:17 2013 -0800
@@ -51,6 +51,8 @@
         this.index = index;
         this.scale = scale;
         this.displacement = displacement;
+
+        assert scale != null;
     }
 
     private static Register toRegister(AllocatableValue value) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Fri Nov 22 13:41:17 2013 -0800
@@ -61,11 +61,15 @@
     private final long[] componentOffsets;
     private final EnumSet<OperandFlag>[] componentFlags;
 
+    public CompositeValueClass(Class<? extends CompositeValue> clazz) {
+        this(clazz, new DefaultCalcOffset());
+    }
+
     @SuppressWarnings("unchecked")
-    public CompositeValueClass(Class<? extends CompositeValue> clazz) {
+    public CompositeValueClass(Class<? extends CompositeValue> clazz, CalcOffset calcOffset) {
         super(clazz);
 
-        ValueFieldScanner scanner = new ValueFieldScanner(new DefaultCalcOffset());
+        ValueFieldScanner scanner = new ValueFieldScanner(calcOffset);
         scanner.scan(clazz);
 
         OperandModeAnnotation mode = scanner.valueAnnotations.get(CompositeValue.Component.class);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Fri Nov 22 13:41:17 2013 -0800
@@ -73,12 +73,16 @@
     private String opcodeConstant;
     private long opcodeOffset;
 
+    public LIRInstructionClass(Class<? extends LIRInstruction> clazz) {
+        this(clazz, new DefaultCalcOffset());
+    }
+
     @SuppressWarnings("unchecked")
-    public LIRInstructionClass(Class<? extends LIRInstruction> clazz) {
+    public LIRInstructionClass(Class<? extends LIRInstruction> clazz, CalcOffset calcOffset) {
         super(clazz);
         assert INSTRUCTION_CLASS.isAssignableFrom(clazz);
 
-        InstructionFieldScanner scanner = new InstructionFieldScanner(new DefaultCalcOffset());
+        InstructionFieldScanner scanner = new InstructionFieldScanner(calcOffset);
         scanner.scan(clazz);
 
         OperandModeAnnotation mode = scanner.valueAnnotations.get(LIRInstruction.Use.class);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Fri Nov 22 13:41:17 2013 -0800
@@ -27,7 +27,7 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "Deopt", nameTemplate = "Deopt {p#reason/s}")
-public class DeoptimizeNode extends AbstractDeoptimizeNode implements LIRLowerable {
+public class DeoptimizeNode extends AbstractDeoptimizeNode implements Lowerable, LIRLowerable {
 
     private final DeoptimizationAction action;
     private final DeoptimizationReason reason;
@@ -54,6 +54,11 @@
     }
 
     @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.emitDeoptimize(gen.getMetaAccess().encodeDeoptActionAndReason(action, reason, speculationId), this);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Fri Nov 22 13:41:17 2013 -0800
@@ -57,6 +57,8 @@
         this.negated = negated;
         this.condition = condition;
         this.reason = deoptReason;
+
+        assert action != null && reason != null;
     }
 
     public DeoptimizationReason getReason() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Fri Nov 22 13:41:17 2013 -0800
@@ -108,10 +108,12 @@
             if (c.getValue() == negated) {
                 // The guard always fails
                 return graph().add(new DeoptimizeNode(action, reason));
-            }
-
-            if (c.getValue() != negated && stamp().equals(object().stamp())) {
+            } else if (stamp().equals(object().stamp())) {
+                // The guard always succeeds, and does not provide new type information
                 return object;
+            } else {
+                // The guard always succeeds, and provides new type information
+                return graph().unique(new PiNode(object, stamp()));
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java	Fri Nov 22 13:41:17 2013 -0800
@@ -29,7 +29,7 @@
 /**
  * Unwinds the current frame to an exception handler in the caller frame.
  */
-public final class UnwindNode extends ControlSinkNode implements LIRLowerable {
+public final class UnwindNode extends ControlSinkNode implements Lowerable, LIRLowerable {
 
     @Input private ValueNode exception;
 
@@ -44,6 +44,11 @@
     }
 
     @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.emitUnwind(gen.operand(exception()));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Fri Nov 22 13:41:17 2013 -0800
@@ -61,7 +61,7 @@
 
     @Override
     public void lower(LoweringTool tool) {
-        if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+        if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS || graph().getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
             tool.getLowerer().lower(this, tool);
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Fri Nov 22 13:41:17 2013 -0800
@@ -43,6 +43,15 @@
         super(object, location, stamp, guard, barrierType, compressible);
     }
 
+    private ReadNode(ValueNode object, ValueNode location, ValueNode guard, BarrierType barrierType, boolean compressible) {
+        /*
+         * Used by node intrinsics. Really, you can trust me on that! Since the initial value for
+         * location is a parameter, i.e., a LocalNode, the constructor cannot use the declared type
+         * LocationNode.
+         */
+        super(object, location, StampFactory.forNodeIntrinsic(), (GuardingNode) guard, barrierType, compressible);
+    }
+
     @Override
     public void generate(LIRGeneratorTool gen) {
         Value address = location().generateAddress(gen, gen.operand(object()));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Fri Nov 22 13:41:17 2013 -0800
@@ -45,6 +45,16 @@
         return stateAfter;
     }
 
+    @Override
+    public FrameState getState() {
+        if (stateAfter != null) {
+            assert super.getState() == null;
+            return stateAfter;
+        } else {
+            return super.getState();
+        }
+    }
+
     public void setStateAfter(FrameState x) {
         assert x == null || x.isAlive() : "frame state must be in a graph";
         updateUsages(stateAfter, x);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Fri Nov 22 13:41:17 2013 -0800
@@ -34,8 +34,6 @@
  */
 public class NewArrayNode extends AbstractNewArrayNode implements VirtualizableAllocation {
 
-    private final ResolvedJavaType elementType;
-
     /**
      * Constructs a new NewArrayNode.
      * 
@@ -46,7 +44,6 @@
      */
     public NewArrayNode(ResolvedJavaType elementType, ValueNode length, boolean fillContents) {
         super(StampFactory.exactNonNull(elementType.getArrayClass()), length, fillContents);
-        this.elementType = elementType;
     }
 
     /**
@@ -55,7 +52,7 @@
      * @return the element type of the array
      */
     public ResolvedJavaType elementType() {
-        return elementType;
+        return ObjectStamp.typeOrNull(this).getComponentType();
     }
 
     @Override
@@ -64,14 +61,19 @@
             final int constantLength = length().asConstant().asInt();
             if (constantLength >= 0 && constantLength < tool.getMaximumEntryCount()) {
                 ValueNode[] state = new ValueNode[constantLength];
-                ConstantNode defaultForKind = constantLength == 0 ? null : ConstantNode.defaultForKind(elementType().getKind(), graph());
+                ConstantNode defaultForKind = constantLength == 0 ? null : defaultElementValue();
                 for (int i = 0; i < constantLength; i++) {
                     state[i] = defaultForKind;
                 }
-                VirtualObjectNode virtualObject = new VirtualArrayNode(elementType, constantLength);
+                VirtualObjectNode virtualObject = new VirtualArrayNode(elementType(), constantLength);
                 tool.createVirtualObject(virtualObject, state, null);
                 tool.replaceWithVirtual(virtualObject);
             }
         }
     }
+
+    /* Factored out in a separate method so that subclasses can override it. */
+    protected ConstantNode defaultElementValue() {
+        return ConstantNode.defaultForKind(elementType().getKind(), graph());
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Fri Nov 22 13:41:17 2013 -0800
@@ -36,7 +36,7 @@
  * The {@code NewInstanceNode} represents the allocation of an instance class object.
  */
 @NodeInfo(nameTemplate = "New {p#instanceClass/s}")
-public final class NewInstanceNode extends DeoptimizingFixedWithNextNode implements Canonicalizable, Lowerable, VirtualizableAllocation {
+public class NewInstanceNode extends DeoptimizingFixedWithNextNode implements Canonicalizable, Lowerable, VirtualizableAllocation {
 
     private final ResolvedJavaType instanceClass;
     private final boolean fillContents;
@@ -96,13 +96,18 @@
             ResolvedJavaField[] fields = virtualObject.getFields();
             ValueNode[] state = new ValueNode[fields.length];
             for (int i = 0; i < state.length; i++) {
-                state[i] = ConstantNode.defaultForKind(fields[i].getType().getKind(), graph());
+                state[i] = defaultFieldValue(fields[i]);
             }
             tool.createVirtualObject(virtualObject, state, null);
             tool.replaceWithVirtual(virtualObject);
         }
     }
 
+    /* Factored out in a separate method so that subclasses can override it. */
+    protected ConstantNode defaultFieldValue(ResolvedJavaField field) {
+        return ConstantNode.defaultForKind(field.getType().getKind(), graph());
+    }
+
     @Override
     public boolean canDeoptimize() {
         return true;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Fri Nov 22 13:41:17 2013 -0800
@@ -1511,12 +1511,7 @@
             InliningUtil.replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete);
         }
 
-        FixedWithNextNode macroNode;
-        try {
-            macroNode = macroNodeClass.getConstructor(Invoke.class).newInstance(invoke);
-        } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
-            throw new GraalInternalError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass);
-        }
+        FixedWithNextNode macroNode = createMacroNodeInstance(macroNodeClass, invoke);
 
         CallTargetNode callTarget = invoke.callTarget();
         if (invoke instanceof InvokeNode) {
@@ -1529,4 +1524,12 @@
         GraphUtil.killWithUnusedFloatingInputs(callTarget);
         return macroNode;
     }
+
+    private static FixedWithNextNode createMacroNodeInstance(Class<? extends FixedWithNextNode> macroNodeClass, Invoke invoke) throws GraalInternalError {
+        try {
+            return macroNodeClass.getConstructor(Invoke.class).newInstance(invoke);
+        } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
+            throw new GraalInternalError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass);
+        }
+    }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Fri Nov 22 13:41:17 2013 -0800
@@ -178,7 +178,7 @@
         Mark expectedMark = graph.getMark();
         lower(graph, context, 1);
         Mark mark = graph.getMark();
-        assert mark.equals(expectedMark) : graph + ": a second round in the current lowering phase introduced these new nodes: " + graph.getNewNodes(mark).snapshot();
+        assert mark.equals(expectedMark) : graph + ": a second round in the current lowering phase introduced these new nodes: " + graph.getNewNodes(expectedMark).snapshot();
         return true;
     }
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Fri Nov 22 13:41:17 2013 -0800
@@ -258,7 +258,9 @@
     @Option(help = "")
     public static final OptionValue<Boolean> OptCanonicalizer = new OptionValue<>(true);
     @Option(help = "")
-     public static final OptionValue<Boolean> OptScheduleOutOfLoops = new OptionValue<>(true);
+    public static final OptionValue<Boolean> OptDeoptimizationGrouping = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptScheduleOutOfLoops = new OptionValue<>(true);
     @Option(help = "")
     public static final OptionValue<Boolean> OptEliminateGuards = new OptionValue<>(true);
     @Option(help = "")
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Fri Nov 22 13:41:17 2013 -0800
@@ -46,7 +46,7 @@
     private final ReplacementsImpl installer;
 
     public ObjectAccessTest() {
-        installer = new ReplacementsImpl(getProviders(), new Assumptions(false));
+        installer = new ReplacementsImpl(getProviders(), new Assumptions(false), getTarget());
     }
 
     private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
@@ -60,7 +60,7 @@
     @Test
     public void testRead1() {
         for (Kind kind : KINDS) {
-            assertRead(parse("read" + kind.name() + "1"), kind, false, ID);
+            assertRead(parse("read" + kind.name() + "1"), kind, true, ID);
         }
     }
 
@@ -74,14 +74,14 @@
     @Test
     public void testRead3() {
         for (Kind kind : KINDS) {
-            assertRead(parse("read" + kind.name() + "3"), kind, false, LocationIdentity.ANY_LOCATION);
+            assertRead(parse("read" + kind.name() + "3"), kind, true, LocationIdentity.ANY_LOCATION);
         }
     }
 
     @Test
     public void testWrite1() {
         for (Kind kind : KINDS) {
-            assertWrite(parse("write" + kind.name() + "1"), kind, false, ID);
+            assertWrite(parse("write" + kind.name() + "1"), kind, true, ID);
         }
     }
 
@@ -95,7 +95,7 @@
     @Test
     public void testWrite3() {
         for (Kind kind : KINDS) {
-            assertWrite(parse("write" + kind.name() + "3"), kind, false, LocationIdentity.ANY_LOCATION);
+            assertWrite(parse("write" + kind.name() + "3"), kind, true, LocationIdentity.ANY_LOCATION);
         }
     }
 
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Fri Nov 22 13:41:17 2013 -0800
@@ -52,7 +52,7 @@
 
     public PointerTest() {
         target = getCodeCache().getTarget();
-        installer = new ReplacementsImpl(getProviders(), new Assumptions(false));
+        installer = new ReplacementsImpl(getProviders(), new Assumptions(false), getTarget());
     }
 
     private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
@@ -66,7 +66,7 @@
     @Test
     public void testRead1() {
         for (Kind kind : KINDS) {
-            assertRead(parse("read" + kind.name() + "1"), kind, false, ID);
+            assertRead(parse("read" + kind.name() + "1"), kind, true, ID);
         }
     }
 
@@ -80,14 +80,14 @@
     @Test
     public void testRead3() {
         for (Kind kind : KINDS) {
-            assertRead(parse("read" + kind.name() + "3"), kind, false, LocationIdentity.ANY_LOCATION);
+            assertRead(parse("read" + kind.name() + "3"), kind, true, LocationIdentity.ANY_LOCATION);
         }
     }
 
     @Test
     public void testWrite1() {
         for (Kind kind : KINDS) {
-            assertWrite(parse("write" + kind.name() + "1"), kind, false, ID);
+            assertWrite(parse("write" + kind.name() + "1"), kind, true, ID);
         }
     }
 
@@ -101,7 +101,7 @@
     @Test
     public void testWrite3() {
         for (Kind kind : KINDS) {
-            assertWrite(parse("write" + kind.name() + "3"), kind, false, LocationIdentity.ANY_LOCATION);
+            assertWrite(parse("write" + kind.name() + "3"), kind, true, LocationIdentity.ANY_LOCATION);
         }
     }
 
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Fri Nov 22 13:41:17 2013 -0800
@@ -41,7 +41,7 @@
     private final ReplacementsImpl installer;
 
     public WordTest() {
-        installer = new ReplacementsImpl(getProviders(), new Assumptions(false));
+        installer = new ReplacementsImpl(getProviders(), new Assumptions(false), getTarget());
     }
 
     private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Fri Nov 22 13:41:17 2013 -0800
@@ -69,9 +69,9 @@
     private final Set<ResolvedJavaMethod> forcedSubstitutions;
     private final Map<Class<? extends SnippetTemplateCache>, SnippetTemplateCache> snippetTemplateCache;
 
-    public ReplacementsImpl(Providers providers, Assumptions assumptions) {
+    public ReplacementsImpl(Providers providers, Assumptions assumptions, TargetDescription target) {
         this.providers = providers.copyWith(this);
-        this.target = providers.getCodeCache().getTarget();
+        this.target = target;
         this.assumptions = assumptions;
         this.graphs = new ConcurrentHashMap<>();
         this.registeredMethodSubstitutions = new HashMap<>();
@@ -212,7 +212,15 @@
         return originalJavaMethod;
     }
 
-    private SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) {
+    private static SnippetInliningPolicy createPolicyClassInstance(Class<? extends SnippetInliningPolicy> policyClass) {
+        try {
+            return policyClass.getConstructor().newInstance();
+        } catch (Exception e) {
+            throw new GraalInternalError(e);
+        }
+    }
+
+    protected SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) {
         Class<? extends SnippetInliningPolicy> policyClass = SnippetInliningPolicy.class;
         Snippet snippet = method.getAnnotation(Snippet.class);
         if (snippet != null) {
@@ -221,11 +229,7 @@
         if (policyClass == SnippetInliningPolicy.class) {
             return new DefaultSnippetInliningPolicy(providers.getMetaAccess());
         }
-        try {
-            return policyClass.getConstructor().newInstance();
-        } catch (Exception e) {
-            throw new GraalInternalError(e);
-        }
+        return createPolicyClassInstance(policyClass);
     }
 
     /**
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Fri Nov 22 13:41:17 2013 -0800
@@ -926,8 +926,8 @@
 
     private class DuplicateMapper extends MemoryMapNode {
 
-        Map<Node, Node> duplicates;
-        StartNode replaceeStart;
+        private final Map<Node, Node> duplicates;
+        @Input private StartNode replaceeStart;
 
         public DuplicateMapper(Map<Node, Node> duplicates, StartNode replaceeStart) {
             this.duplicates = duplicates;
@@ -1005,7 +1005,7 @@
 
             // Replace all usages of the replacee with the value returned by the snippet
             ValueNode returnValue = null;
-            if (returnNode != null) {
+            if (returnNode != null && !(replacee instanceof ControlSinkNode)) {
                 if (returnNode.result() instanceof LocalNode) {
                     returnValue = (ValueNode) replacements.get(returnNode.result());
                 } else if (returnNode.result() != null) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Fri Nov 22 13:41:17 2013 -0800
@@ -43,7 +43,7 @@
     private final Replacements graalReplacements;
 
     private TruffleReplacements(Providers providers) {
-        super(providers, providers.getReplacements().getAssumptions());
+        super(providers, providers.getReplacements().getAssumptions(), providers.getCodeCache().getTarget());
         this.graalReplacements = providers.getReplacements();
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/ComparableWord.java	Fri Nov 22 13:41:17 2013 -0800
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.word;
+
+public interface ComparableWord extends WordBase {
+
+    /**
+     * Compares this word with the specified value.
+     * 
+     * @param val value to which this word is to be compared.
+     * @return {@code this == val}
+     */
+    boolean equal(ComparableWord val);
+
+    /**
+     * Compares this word with the specified value.
+     * 
+     * @param val value to which this word is to be compared.
+     * @return {@code this != val}
+     */
+    boolean notEqual(ComparableWord val);
+}
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java	Fri Nov 22 13:41:17 2013 -0800
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
 
-public interface Pointer extends Unsigned {
+public interface Pointer extends Unsigned, PointerBase {
 
     /**
      * Unsafe conversion of this Pointer to a Java language object. No correctness checks or type
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/PointerBase.java	Fri Nov 22 13:41:17 2013 -0800
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.word;
+
+/**
+ * Marker interface for all {@link WordBase word types} that have the semantic of a pointer (but not
+ * necessarily all the memory access methods defined in {@link Pointer}).
+ */
+public interface PointerBase extends ComparableWord {
+}
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Signed.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Signed.java	Fri Nov 22 13:41:17 2013 -0800
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.word;
 
-public interface Signed extends WordBase {
+public interface Signed extends ComparableWord {
 
     /**
      * Returns a Signed whose value is {@code (this + val)}.
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Unsigned.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Unsigned.java	Fri Nov 22 13:41:17 2013 -0800
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.word;
 
-public interface Unsigned extends WordBase {
+public interface Unsigned extends ComparableWord {
 
     /**
      * Returns a Unsigned whose value is {@code (this + val)}.
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Fri Nov 22 13:41:17 2013 -0800
@@ -427,6 +427,12 @@
 
     @Override
     @Operation(opcode = Opcode.COMPARISON, condition = Condition.EQ)
+    public boolean equal(ComparableWord val) {
+        return equal((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.EQ)
     public boolean equal(Signed val) {
         return equal((Word) val);
     }
@@ -450,6 +456,12 @@
 
     @Override
     @Operation(opcode = Opcode.COMPARISON, condition = Condition.NE)
+    public boolean notEqual(ComparableWord val) {
+        return notEqual((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.NE)
     public boolean notEqual(Signed val) {
         return notEqual((Word) val);
     }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Fri Nov 22 21:09:36 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Fri Nov 22 13:41:17 2013 -0800
@@ -86,6 +86,21 @@
      * prepared to see the word type during canonicalization.
      */
     protected void inferStamps(StructuredGraph graph) {
+        /*
+         * We want to make the stamps more precise. For cyclic phi functions, this means we have to
+         * ignore the initial stamp because the imprecise stamp would always propagate around the
+         * cycle. We therefore set the stamp to an illegal stamp, which is automatically ignored
+         * when the phi function performs the "meet" operator on its input stamps.
+         */
+        for (Node n : graph.getNodes()) {
+            if (n instanceof PhiNode || n instanceof ProxyNode) {
+                ValueNode node = (ValueNode) n;
+                if (node.kind() == Kind.Object) {
+                    node.setStamp(StampFactory.illegal(node.kind()));
+                }
+            }
+        }
+
         boolean stampChanged;
         do {
             stampChanged = false;
@@ -104,6 +119,22 @@
                 }
             }
         } while (stampChanged);
+
+        /*
+         * Check that all the illegal stamps we introduced above are correctly replaced with real
+         * stamps again.
+         */
+        assert checkNoIllegalStamp(graph);
+    }
+
+    private static boolean checkNoIllegalStamp(StructuredGraph graph) {
+        for (Node n : graph.getNodes()) {
+            if (n instanceof ValueNode) {
+                ValueNode node = (ValueNode) n;
+                assert !(node.stamp() instanceof IllegalStamp);
+            }
+        }
+        return true;
     }
 
     /**
@@ -243,7 +274,7 @@
                 } else {
                     location = makeLocation(graph, arguments.get(1), readKind, arguments.get(2));
                 }
-                replace(invoke, readOp(graph, arguments.get(0), invoke, location, BarrierType.NONE, false));
+                replace(invoke, readOp(graph, arguments.get(0), invoke, location, readKind, BarrierType.NONE, false));
                 break;
             }
             case READ_HEAP: {
@@ -251,7 +282,7 @@
                 Kind readKind = asKind(callTargetNode.returnType());
                 LocationNode location = makeLocation(graph, arguments.get(1), readKind, ANY_LOCATION);
                 BarrierType barrierType = (BarrierType) arguments.get(2).asConstant().asObject();
-                replace(invoke, readOp(graph, arguments.get(0), invoke, location, barrierType, arguments.get(3).asConstant().asInt() == 0 ? false : true));
+                replace(invoke, readOp(graph, arguments.get(0), invoke, location, readKind, barrierType, arguments.get(3).asConstant().asInt() == 0 ? false : true));
                 break;
             }
             case WRITE:
@@ -390,15 +421,16 @@
         if (locationIdentity.isConstant()) {
             return makeLocation(graph, offset, readKind, (LocationIdentity) locationIdentity.asConstant().asObject());
         }
-        return SnippetLocationNode.create(locationIdentity, ConstantNode.forObject(readKind, metaAccess, graph), ConstantNode.forLong(0, graph), offset, ConstantNode.forInt(1, graph), graph);
+        return SnippetLocationNode.create(locationIdentity, ConstantNode.forObject(readKind, metaAccess, graph), ConstantNode.forLong(0, graph), fromSigned(graph, offset),
+                        ConstantNode.forInt(1, graph), graph);
     }
 
     protected LocationNode makeLocation(StructuredGraph graph, ValueNode offset, Kind readKind, LocationIdentity locationIdentity) {
-        return IndexedLocationNode.create(locationIdentity, readKind, 0, offset, graph, 1);
+        return IndexedLocationNode.create(locationIdentity, readKind, 0, fromSigned(graph, offset), graph, 1);
     }
 
-    protected ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, BarrierType barrierType, boolean compressible) {
-        ReadNode read = graph.add(new ReadNode(base, location, invoke.asNode().stamp(), barrierType, compressible));
+    protected ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, Kind readKind, BarrierType barrierType, boolean compressible) {
+        ReadNode read = graph.add(new ReadNode(base, location, StampFactory.forKind(readKind), barrierType, compressible));
         graph.addBeforeFixed(invoke.asNode(), read);
         /*
          * The read must not float outside its block otherwise it may float above an explicit zero