changeset 9230:7e3c7d55d538

Merge.
author Christian Humer <christian.humer@gmail.com>
date Mon, 22 Apr 2013 16:40:54 +0200
parents 76a6e7907b67 (current diff) 898045a71791 (diff)
children ee3a9188c65e
files
diffstat 27 files changed, 479 insertions(+), 188 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Register.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Register.java	Mon Apr 22 16:40:54 2013 +0200
@@ -196,6 +196,16 @@
     }
 
     /**
+     * Gets a hash code for this register.
+     * 
+     * @return the value of {@link #number}
+     */
+    @Override
+    public int hashCode() {
+        return number;
+    }
+
+    /**
      * Categorizes a set of registers by {@link RegisterFlag}.
      * 
      * @param registers a list of registers to be categorized
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java	Mon Apr 22 16:40:54 2013 +0200
@@ -25,7 +25,6 @@
 /**
  * Enumeration of reasons for why a deoptimization is happening.
  */
-// @formatter:off
 public enum DeoptimizationReason {
     None,
     NullCheckException,
--- a/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java	Mon Apr 22 16:40:54 2013 +0200
@@ -59,7 +59,7 @@
      * Determines if this method should be substituted in all cases, even if inlining thinks it is
      * not important.
      * 
-     * Not that this is still depending on whether inlining sees the correct call target, so it's
+     * Note that this is still depending on whether inlining sees the correct call target, so it's
      * only a hard guarantee for static and special invocations.
      */
     boolean forced() default false;
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Apr 22 16:40:54 2013 +0200
@@ -156,23 +156,15 @@
         append(createMove(dst, src));
     }
 
-    private AMD64AddressValue prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) {
+    private AMD64AddressValue prepareAddress(Kind kind, Value base, long displacement, Value index, int scale) {
         AllocatableValue baseRegister;
-        int finalDisp = displacement;
+        long finalDisp = displacement;
         if (isConstant(base)) {
             if (asConstant(base).isNull()) {
                 baseRegister = AllocatableValue.UNUSED;
-            } else if (asConstant(base).getKind() != Kind.Object) {
-                long newDisplacement = displacement + asConstant(base).asLong();
-                if (NumUtil.isInt(newDisplacement)) {
-                    assert !runtime.needsDataPatch(asConstant(base));
-                    finalDisp = (int) newDisplacement;
-                    baseRegister = AllocatableValue.UNUSED;
-                } else {
-                    Variable newBase = newVariable(Kind.Long);
-                    emitMove(newBase, base);
-                    baseRegister = newBase;
-                }
+            } else if (asConstant(base).getKind() != Kind.Object && !runtime.needsDataPatch(asConstant(base))) {
+                finalDisp += asConstant(base).asLong();
+                baseRegister = AllocatableValue.UNUSED;
             } else {
                 baseRegister = load(base);
             }
@@ -187,19 +179,8 @@
         if (index != Value.ILLEGAL && scale != 0) {
             scaleEnum = Scale.fromInt(scale);
             if (isConstant(index)) {
-                long newDisplacement = finalDisp + asConstant(index).asLong() * scale;
-                // only use the constant index if the resulting displacement fits into a 32 bit
-                // offset
-                if (NumUtil.isInt(newDisplacement)) {
-                    finalDisp = (int) newDisplacement;
-                    indexRegister = AllocatableValue.UNUSED;
-                } else {
-                    // create a temporary variable for the index, the pointer load cannot handle a
-                    // constant index
-                    Variable newIndex = newVariable(Kind.Long);
-                    emitMove(newIndex, index);
-                    indexRegister = newIndex;
-                }
+                finalDisp += asConstant(index).asLong() * scale;
+                indexRegister = AllocatableValue.UNUSED;
             } else {
                 indexRegister = asAllocatable(index);
             }
@@ -208,11 +189,27 @@
             scaleEnum = Scale.Times1;
         }
 
-        return new AMD64AddressValue(kind, baseRegister, indexRegister, scaleEnum, finalDisp);
+        int displacementInt;
+        if (NumUtil.isInt(finalDisp)) {
+            displacementInt = (int) finalDisp;
+        } else {
+            displacementInt = 0;
+            AllocatableValue displacementRegister = load(Constant.forLong(finalDisp));
+            if (baseRegister == AllocatableValue.UNUSED) {
+                baseRegister = displacementRegister;
+            } else if (indexRegister == AllocatableValue.UNUSED) {
+                indexRegister = displacementRegister;
+                scaleEnum = Scale.Times1;
+            } else {
+                baseRegister = emitAdd(baseRegister, displacementRegister);
+            }
+        }
+
+        return new AMD64AddressValue(kind, baseRegister, indexRegister, scaleEnum, displacementInt);
     }
 
     @Override
-    public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, DeoptimizingNode deopting) {
+    public Variable emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode deopting) {
         AMD64AddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale);
         Variable result = newVariable(loadAddress.getKind());
         append(new LoadOp(result, loadAddress, deopting != null ? state(deopting) : null));
@@ -220,7 +217,7 @@
     }
 
     @Override
-    public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, DeoptimizingNode deopting) {
+    public void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value inputVal, DeoptimizingNode deopting) {
         AMD64AddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale);
         LIRFrameState state = deopting != null ? state(deopting) : null;
 
@@ -237,7 +234,7 @@
     }
 
     @Override
-    public Variable emitLea(Value base, int displacement, Value index, int scale) {
+    public Variable emitLea(Value base, long displacement, Value index, int scale) {
         Variable result = newVariable(target().wordKind);
         AMD64AddressValue address = prepareAddress(result.getKind(), base, displacement, index, scale);
         append(new LeaOp(result, address));
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Mon Apr 22 16:40:54 2013 +0200
@@ -137,7 +137,7 @@
         }
     }
 
-    private PTXAddressValue prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) {
+    private PTXAddressValue prepareAddress(Kind kind, Value base, long displacement, Value index, int scale) {
         AllocatableValue baseRegister;
         long finalDisp = displacement;
         if (isConstant(base)) {
@@ -181,7 +181,7 @@
     }
 
     @Override
-    public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, DeoptimizingNode deopting) {
+    public Variable emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode deopting) {
         PTXAddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale);
         Variable result = newVariable(loadAddress.getKind());
         append(new LoadOp(result, loadAddress, deopting != null ? state(deopting) : null));
@@ -189,14 +189,14 @@
     }
 
     @Override
-    public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, DeoptimizingNode deopting) {
+    public void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value inputVal, DeoptimizingNode deopting) {
         PTXAddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale);
         Variable input = load(inputVal);
         append(new StoreOp(storeAddress, input, deopting != null ? state(deopting) : null));
     }
 
     @Override
-    public Variable emitLea(Value base, int displacement, Value index, int scale) {
+    public Variable emitLea(Value base, long displacement, Value index, int scale) {
         throw new InternalError("NYI");
     }
 
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Mon Apr 22 16:40:54 2013 +0200
@@ -214,19 +214,19 @@
     }
 
     @Override
-    public Value emitLoad(Kind kind, Value base, int displacement, Value index, int scale, DeoptimizingNode canTrap) {
+    public Value emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode canTrap) {
         // SPARC: Auto-generated method stub
         return null;
     }
 
     @Override
-    public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value input, DeoptimizingNode canTrap) {
+    public void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value input, DeoptimizingNode canTrap) {
         // SPARC: Auto-generated method stub
 
     }
 
     @Override
-    public Value emitLea(Value base, int displacement, Value index, int scale) {
+    public Value emitLea(Value base, long displacement, Value index, int scale) {
         // SPARC: Auto-generated method stub
         return null;
     }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Mon Apr 22 16:40:54 2013 +0200
@@ -76,9 +76,26 @@
         return callable;
     }
 
-    public static void sandbox(String name, Runnable runnable) {
+    public static void sandbox(String name, DebugConfig config, Runnable runnable) {
         if (ENABLED) {
-            DebugScope.getInstance().scope(name, runnable, null, true, new Object[0]);
+            DebugScope.getInstance().scope(name, runnable, null, true, config, new Object[0]);
+        } else {
+            runnable.run();
+        }
+    }
+
+    /**
+     * Creates a new debug scope that is unrelated to the current scope and runs a given task in the
+     * new scope.
+     * 
+     * @param name new scope name
+     * @param context the context objects of the new scope
+     * @param config the debug configuration to use for the new scope
+     * @param runnable the task to run in the new scope
+     */
+    public static void sandbox(String name, Object[] context, DebugConfig config, Runnable runnable) {
+        if (ENABLED) {
+            DebugScope.getInstance().scope(name, runnable, null, true, config, context);
         } else {
             runnable.run();
         }
@@ -98,7 +115,7 @@
 
     public static void scope(String name, Object[] context, Runnable runnable) {
         if (ENABLED) {
-            DebugScope.getInstance().scope(name, runnable, null, false, context);
+            DebugScope.getInstance().scope(name, runnable, null, false, null, context);
         } else {
             runnable.run();
         }
@@ -118,7 +135,7 @@
 
     public static <T> T scope(String name, Object[] context, Callable<T> callable) {
         if (ENABLED) {
-            return DebugScope.getInstance().scope(name, null, callable, false, context);
+            return DebugScope.getInstance().scope(name, null, callable, false, null, context);
         } else {
             return DebugScope.call(callable);
         }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Mon Apr 22 16:40:54 2013 +0200
@@ -138,13 +138,26 @@
         }
     }
 
-    public <T> T scope(String newName, Runnable runnable, Callable<T> callable, boolean sandbox, Object[] newContext) {
+    /**
+     * Runs a task in a new debug scope which is either a child of the current scope or a disjoint
+     * top level scope.
+     * 
+     * @param newName the name of the new scope
+     * @param runnable the task to run (must be null iff {@code callable} is not null)
+     * @param callable the task to run (must be null iff {@code runnable} is not null)
+     * @param sandbox specifies if the scope is a child of the current scope or a top level scope
+     * @param sandboxConfig the config to use of a new top level scope (ignored if
+     *            {@code sandbox == false})
+     * @param newContext context objects of the new scope
+     * @return the value returned by the task
+     */
+    public <T> T scope(String newName, Runnable runnable, Callable<T> callable, boolean sandbox, DebugConfig sandboxConfig, Object[] newContext) {
         DebugScope oldContext = getInstance();
         DebugConfig oldConfig = getConfig();
         DebugScope newChild = null;
         if (sandbox) {
             newChild = new DebugScope(newName, newName, null, newContext);
-            setConfig(null);
+            setConfig(sandboxConfig);
         } else {
             newChild = oldContext.createChild(newName, newContext);
         }
@@ -215,7 +228,7 @@
                         return new RuntimeException("Exception while intercepting exception", t);
                     }
                 }
-            }, false, new Object[]{e});
+            }, false, null, new Object[]{e});
         }
         return null;
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Mon Apr 22 16:40:54 2013 +0200
@@ -28,6 +28,7 @@
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.lang.reflect.*;
+import java.util.*;
 
 import sun.misc.*;
 
@@ -42,10 +43,13 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.phases.*;
 
 /**
@@ -154,6 +158,30 @@
         if (deoptimizationRescueSlot != null) {
             tasm.compilationResult.setCustomStackAreaOffset(frameMap.offsetForStackSlot(deoptimizationRescueSlot));
         }
+
+        Stub stub = runtime().asStub(lirGen.method());
+        if (stub != null) {
+            final Set<Register> definedRegisters = new HashSet<>();
+            ValueProcedure defProc = new ValueProcedure() {
+
+                @Override
+                public Value doValue(Value value) {
+                    if (ValueUtil.isRegister(value)) {
+                        final Register reg = ValueUtil.asRegister(value);
+                        definedRegisters.add(reg);
+                    }
+                    return value;
+                }
+            };
+            for (Block block : lir.codeEmittingOrder()) {
+                for (LIRInstruction op : lir.lir(block)) {
+                    op.forEachTemp(defProc);
+                    op.forEachOutput(defProc);
+                }
+            }
+            stub.initDefinedRegisters(definedRegisters);
+        }
+
         return tasm;
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Mon Apr 22 16:40:54 2013 +0200
@@ -105,8 +105,7 @@
                 /* arg0: object */ javaCallingConvention(Kind.Object,
                 /* arg1:   lock */                       word));
 
-        addRuntimeCall(NEW_ARRAY, 0L,
-                /*        temps */ null,
+        addStubCall(NEW_ARRAY,
                 /*          ret */ rax.asValue(Kind.Object),
                 /* arg0:    hub */ rdx.asValue(word),
                 /* arg1: length */ rbx.asValue(Kind.Int));
@@ -117,8 +116,7 @@
                 /* arg0:    hub */ rdx.asValue(word),
                 /* arg1: length */ rbx.asValue(Kind.Int));
 
-        addRuntimeCall(NEW_INSTANCE, 0L,
-                /*        temps */ null,
+        addStubCall(NEW_INSTANCE,
                 /*          ret */ rax.asValue(Kind.Object),
                 /* arg0:    hub */ rdx.asValue(word));
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java	Mon Apr 22 16:40:54 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.target.*;
@@ -51,7 +53,7 @@
     /**
      * Where the stub gets its arguments and where it places its result.
      */
-    public final CallingConvention cc;
+    private CallingConvention cc;
 
     private final CompilerToVM vm;
 
@@ -87,12 +89,28 @@
     public void finalizeAddress(Backend backend) {
         if (address == 0) {
             assert stub != null : "linkage without an address must be a stub";
-            address = stub.getAddress(backend);
+            InstalledCode code = stub.getCode(backend);
+
+            Value[] argumentLocations = new Value[cc.getArgumentCount()];
+            for (int i = 0; i < argumentLocations.length; i++) {
+                argumentLocations[i] = cc.getArgument(i);
+            }
+
+            Set<Register> definedRegisters = stub.getDefinedRegisters();
+            Value[] temporaryLocations = new Value[definedRegisters.size()];
+            int i = 0;
+            for (Register reg : definedRegisters) {
+                temporaryLocations[i++] = reg.asValue();
+            }
+            // Update calling convention with temporaries
+            cc = new CallingConvention(temporaryLocations, cc.getStackSize(), cc.getReturn(), argumentLocations);
+            address = code.getStart();
         }
     }
 
     @Override
     public boolean preservesRegisters() {
-        return stub == null;
+        assert address != 0;
+        return true;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon Apr 22 16:40:54 2013 +0200
@@ -271,6 +271,17 @@
     }
 
     /**
+     * Registers the details for linking a call to a compiled {@link Stub}.
+     * 
+     * @param descriptor name and signature of the call
+     * @param ret where the call returns its result
+     * @param args where arguments are passed to the call
+     */
+    protected RuntimeCallTarget addStubCall(Descriptor descriptor, Value ret, Value... args) {
+        return addRuntimeCall(descriptor, 0L, null, ret, args);
+    }
+
+    /**
      * Registers the details for linking a runtime call.
      * 
      * @param descriptor name and signature of the call
@@ -496,7 +507,7 @@
         if (n instanceof ArrayLengthNode) {
             ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n;
             ValueNode array = arrayLengthNode.array();
-            ReadNode arrayLengthRead = graph.add(new ReadNode(array, LocationNode.create(LocationNode.FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt()));
+            ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(LocationNode.FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt()));
             arrayLengthRead.dependencies().add(tool.createNullCheckGuard(array));
             graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
         } else if (n instanceof Invoke) {
@@ -522,8 +533,9 @@
                             // as HotSpot does not guarantee they are final values.
                             assert vtableEntryOffset > 0;
                             LoadHubNode hub = graph.add(new LoadHubNode(receiver, wordKind));
-                            ReadNode metaspaceMethod = graph.add(new ReadNode(hub, LocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind())));
-                            ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, LocationNode.create(LocationNode.ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph),
+                            ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph),
+                                            StampFactory.forKind(wordKind())));
+                            ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph),
                                             StampFactory.forKind(wordKind())));
 
                             loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
@@ -547,7 +559,7 @@
             HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
             ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : loadField.object();
             assert loadField.kind() != Kind.Illegal;
-            ReadNode memoryRead = graph.add(new ReadNode(object, LocationNode.create(field, field.getKind(), field.offset(), graph), loadField.stamp()));
+            ReadNode memoryRead = graph.add(new ReadNode(object, ConstantLocationNode.create(field, field.getKind(), field.offset(), graph), loadField.stamp()));
             memoryRead.dependencies().add(tool.createNullCheckGuard(object));
 
             graph.replaceFixedWithFixed(loadField, memoryRead);
@@ -562,7 +574,7 @@
             StoreFieldNode storeField = (StoreFieldNode) n;
             HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
             ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : storeField.object();
-            LocationNode location = LocationNode.create(field, field.getKind(), field.offset(), graph);
+            LocationNode location = ConstantLocationNode.create(field, field.getKind(), field.offset(), graph);
             WriteBarrierType barrierType = getFieldStoreBarrierType(storeField);
             WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), location, barrierType));
             memoryWrite.dependencies().add(tool.createNullCheckGuard(object));
@@ -610,7 +622,7 @@
                     }
                 } else {
                     LoadHubNode arrayClass = graph.add(new LoadHubNode(array, wordKind));
-                    LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph);
+                    LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph);
                     FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind())));
                     CheckCastDynamicNode checkcast = graph.add(new CheckCastDynamicNode(arrayElementKlass, value));
                     graph.addBeforeFixed(storeIndexed, checkcast);
@@ -645,7 +657,7 @@
         } else if (n instanceof LoadHubNode) {
             LoadHubNode loadHub = (LoadHubNode) n;
             assert loadHub.kind() == wordKind;
-            LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph);
+            LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph);
             ValueNode object = loadHub.object();
             assert !object.isConstant() || object.asConstant().isNull();
             ValueNode guard = tool.createNullCheckGuard(object);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Mon Apr 22 16:40:54 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
+import java.util.*;
 import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
@@ -29,6 +30,7 @@
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.java.*;
@@ -64,11 +66,26 @@
     /**
      * The code installed for the stub.
      */
-    protected InstalledCode stubCode;
+    protected InstalledCode code;
 
     /**
-     * Creates a new stub container. The new stub still needs to be
-     * {@linkplain #getAddress(Backend) installed}.
+     * The registers defined by this stub.
+     */
+    private Set<Register> definedRegisters;
+
+    public void initDefinedRegisters(Set<Register> registers) {
+        assert registers != null;
+        assert definedRegisters == null : "cannot redefine";
+        definedRegisters = registers;
+    }
+
+    public Set<Register> getDefinedRegisters() {
+        assert definedRegisters != null : "not yet initialized";
+        return definedRegisters;
+    }
+
+    /**
+     * Creates a new stub container..
      * 
      * @param linkage linkage details for a call to the stub
      */
@@ -100,37 +117,43 @@
     }
 
     /**
-     * Ensures the code for this stub is installed.
-     * 
-     * @return the entry point address for calls to this stub
+     * Gets the code for this stub, compiling it first if necessary.
      */
-    public synchronized long getAddress(Backend backend) {
-        if (stubCode == null) {
-            Arguments args = makeArguments(stubInfo);
-            SnippetTemplate template = template(args);
-            StructuredGraph graph = template.copySpecializedGraph();
-
-            PhasePlan phasePlan = new PhasePlan();
-            GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL);
-            phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
-            final CompilationResult compResult = GraalCompiler.compileMethod(runtime(), replacements, backend, runtime().getTarget(), getMethod(), graph, null, phasePlan, OptimisticOptimizations.ALL,
-                            new SpeculationLog());
-
-            stubCode = Debug.scope("CodeInstall", new Object[]{runtime(), getMethod()}, new Callable<InstalledCode>() {
+    public synchronized InstalledCode getCode(final Backend backend) {
+        if (code == null) {
+            Debug.sandbox("CompilingStub", new Object[]{runtime(), getMethod()}, DebugScope.getConfig(), new Runnable() {
 
                 @Override
-                public InstalledCode call() {
-                    InstalledCode installedCode = runtime().addMethod(getMethod(), compResult);
-                    assert installedCode != null : "error installing stub " + getMethod();
-                    if (Debug.isDumpEnabled()) {
-                        Debug.dump(new Object[]{compResult, installedCode}, "After code installation");
-                    }
-                    return installedCode;
+                public void run() {
+
+                    Arguments args = makeArguments(stubInfo);
+                    SnippetTemplate template = template(args);
+                    StructuredGraph graph = template.copySpecializedGraph();
+
+                    PhasePlan phasePlan = new PhasePlan();
+                    GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL);
+                    phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
+                    final CompilationResult compResult = GraalCompiler.compileMethod(runtime(), replacements, backend, runtime().getTarget(), getMethod(), graph, null, phasePlan,
+                                    OptimisticOptimizations.ALL, new SpeculationLog());
+
+                    assert definedRegisters != null;
+                    code = Debug.scope("CodeInstall", new Callable<InstalledCode>() {
+
+                        @Override
+                        public InstalledCode call() {
+                            InstalledCode installedCode = runtime().addMethod(getMethod(), compResult);
+                            assert installedCode != null : "error installing stub " + getMethod();
+                            if (Debug.isDumpEnabled()) {
+                                Debug.dump(new Object[]{compResult, installedCode}, "After code installation");
+                            }
+                            return installedCode;
+                        }
+                    });
+
                 }
             });
-
-            assert stubCode != null : "error installing stub " + getMethod();
+            assert code != null : "error installing stub " + getMethod();
         }
-        return stubCode.getStart();
+        return code;
     }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Apr 22 16:40:54 2013 +0200
@@ -285,7 +285,7 @@
         ValueNode value;
         if (kind == Kind.Object) {
             value = frameState.xpop();
-            // astore and astore_<n> may be used to store a returnAddress (jsr) see JVMS par. 6.5.astore
+            // astore and astore_<n> may be used to store a returnAddress (jsr)
             assert value.kind() == Kind.Object || value.kind() == Kind.Int;
         } else {
             value = frameState.pop(kind);
@@ -1169,7 +1169,7 @@
         createInvokeNode(callTarget, resultType);
     }
 
-    protected Invoke createInvokeNode(MethodCallTargetNode callTarget, Kind resultType) {
+    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)) {
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_idea.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_idea.java	Mon Apr 22 16:40:54 2013 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.jtt.*;
 import org.junit.*;
 
-//@formatter:off
 public class HP_idea extends JTTTest {
 
     public boolean test() {
@@ -60,7 +59,7 @@
 
     /*
      * buildTestData
-     *
+     * 
      * Builds the data used for the test -- each time the test is run.
      */
 
@@ -115,10 +114,11 @@
 
     /*
      * calcEncryptKey
-     *
-     * Builds the 52 16-bit encryption subkeys Z[] from the user key and stores in 32-bit int array. The routing
-     * corrects an error in the source code in the Schnier book. Basically, the sense of the 7- and 9-bit shifts are
-     * reversed. It still works reversed, but would encrypted code would not decrypt with someone else's IDEA code.
+     * 
+     * Builds the 52 16-bit encryption subkeys Z[] from the user key and stores in 32-bit int array.
+     * The routing corrects an error in the source code in the Schnier book. Basically, the sense of
+     * the 7- and 9-bit shifts are reversed. It still works reversed, but would encrypted code would
+     * not decrypt with someone else's IDEA code.
      */
 
     private void calcEncryptKey() {
@@ -168,9 +168,9 @@
 
     /*
      * calcDecryptKey
-     *
-     * Builds the 52 16-bit encryption subkeys DK[] from the encryption- subkeys Z[]. DK[] is a 32-bit int array holding
-     * 16-bit values as unsigned.
+     * 
+     * Builds the 52 16-bit encryption subkeys DK[] from the encryption- subkeys Z[]. DK[] is a
+     * 32-bit int array holding 16-bit values as unsigned.
      */
 
     private void calcDecryptKey() {
@@ -215,12 +215,14 @@
 
     /*
      * cipher_idea
-     *
-     * IDEA encryption/decryption algorithm. It processes plaintext in 64-bit blocks, one at a time, breaking the block
-     * into four 16-bit unsigned subblocks. It goes through eight rounds of processing using 6 new subkeys each time,
-     * plus four for last step. The source text is in array text1, the destination text goes into array text2 The
-     * routine represents 16-bit subblocks and subkeys as type int so that they can be treated more easily as unsigned.
-     * Multiplication modulo 0x10001 interprets a zero sub-block as 0x10000; it must to fit in 16 bits.
+     * 
+     * IDEA encryption/decryption algorithm. It processes plaintext in 64-bit blocks, one at a time,
+     * breaking the block into four 16-bit unsigned subblocks. It goes through eight rounds of
+     * processing using 6 new subkeys each time, plus four for last step. The source text is in
+     * array text1, the destination text goes into array text2 The routine represents 16-bit
+     * subblocks and subkeys as type int so that they can be treated more easily as unsigned.
+     * Multiplication modulo 0x10001 interprets a zero sub-block as 0x10000; it must to fit in 16
+     * bits.
      */
 
     @SuppressWarnings("static-method")
@@ -356,35 +358,40 @@
 
     /*
      * mul
-     *
-     * Performs multiplication, modulo (2**16)+1. This code is structured on the assumption that untaken branches are
-     * cheaper than taken branches, and that the compiler doesn't schedule branches. Java: Must work with 32-bit int and
-     * one 64-bit long to keep 16-bit values and their products "unsigned." The routine assumes that both a and b could
-     * fit in 16 bits even though they come in as 32-bit ints. Lots of "& 0xFFFF" masks here to keep things 16-bit.
-     * Also, because the routine stores mod (2**16)+1 results in a 2**16 space, the result is truncated to zero whenever
-     * the result would zero, be 2**16. And if one of the multiplicands is 0, the result is not zero, but (2**16) + 1
-     * minus the other multiplicand (sort of an additive inverse mod 0x10001).
-     *
-     * NOTE: The java conversion of this routine works correctly, but is half the speed of using Java's modulus division
-     * function (%) on the multiplication with a 16-bit masking of the result--running in the Symantec Caje IDE. So it's
-     * not called for now; the test uses Java % instead.
+     * 
+     * Performs multiplication, modulo (2**16)+1. This code is structured on the assumption that
+     * untaken branches are cheaper than taken branches, and that the compiler doesn't schedule
+     * branches. Java: Must work with 32-bit int and one 64-bit long to keep 16-bit values and their
+     * products "unsigned." The routine assumes that both a and b could fit in 16 bits even though
+     * they come in as 32-bit ints. Lots of "& 0xFFFF" masks here to keep things 16-bit. Also,
+     * because the routine stores mod (2**16)+1 results in a 2**16 space, the result is truncated to
+     * zero whenever the result would zero, be 2**16. And if one of the multiplicands is 0, the
+     * result is not zero, but (2**16) + 1 minus the other multiplicand (sort of an additive inverse
+     * mod 0x10001).
+     * 
+     * NOTE: The java conversion of this routine works correctly, but is half the speed of using
+     * Java's modulus division function (%) on the multiplication with a 16-bit masking of the
+     * result--running in the Symantec Caje IDE. So it's not called for now; the test uses Java %
+     * instead.
      */
 
     /*
-     * private int mul(int a, int b) throws ArithmeticException { long p; // Large enough to catch 16-bit multiply //
-     * without hitting sign bit. if (a != 0) { if (b != 0) { p = (long) a * b; b = (int) p & 0xFFFF; // Lower 16 bits. a
-     * = (int) p >>> 16; // Upper 16 bits.
-     *
-     * return (b - a + (b < a ? 1 : 0) & 0xFFFF); } else return ((1 - a) & 0xFFFF); // If b = 0, then same as // 0x10001
-     * - a. } else // If a = 0, then return return((1 - b) & 0xFFFF); // same as 0x10001 - b. }
+     * private int mul(int a, int b) throws ArithmeticException { long p; // Large enough to catch
+     * 16-bit multiply // without hitting sign bit. if (a != 0) { if (b != 0) { p = (long) a * b; b
+     * = (int) p & 0xFFFF; // Lower 16 bits. a = (int) p >>> 16; // Upper 16 bits.
+     * 
+     * return (b - a + (b < a ? 1 : 0) & 0xFFFF); } else return ((1 - a) & 0xFFFF); // If b = 0,
+     * then same as // 0x10001 - a. } else // If a = 0, then return return((1 - b) & 0xFFFF); //
+     * same as 0x10001 - b. }
      */
 
     /*
      * inv
-     *
-     * Compute multiplicative inverse of x, modulo (2**16)+1 using extended Euclid's GCD (greatest common divisor)
-     * algorithm. It is unrolled twice to avoid swapping the meaning of the registers. And some subtracts are changed to
-     * adds. Java: Though it uses signed 32-bit ints, the interpretation of the bits within is strictly unsigned 16-bit.
+     * 
+     * Compute multiplicative inverse of x, modulo (2**16)+1 using extended Euclid's GCD (greatest
+     * common divisor) algorithm. It is unrolled twice to avoid swapping the meaning of the
+     * registers. And some subtracts are changed to adds. Java: Though it uses signed 32-bit ints,
+     * the interpretation of the bits within is strictly unsigned 16-bit.
      */
 
     @SuppressWarnings("static-method")
@@ -432,7 +439,7 @@
 
     /*
      * freeTestData
-     *
+     * 
      * Nulls arrays and forces garbage collection to free up memory.
      */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Mon Apr 22 16:40:54 2013 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 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.nodes.extended;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * Location node that is the sum of two other location nodes. Can represent locations in the form of
+ * [(base + x) + y] where base is a node and x and y are location nodes.
+ */
+@NodeInfo(nameTemplate = "AddLoc {p#locationIdentity/s}")
+public final class AddLocationNode extends LocationNode implements Canonicalizable {
+
+    @Input private ValueNode x;
+    @Input private ValueNode y;
+
+    public LocationNode getX() {
+        return (LocationNode) x;
+    }
+
+    public LocationNode getY() {
+        return (LocationNode) y;
+    }
+
+    public static AddLocationNode create(LocationNode x, LocationNode y, Graph graph) {
+        assert x.getValueKind().equals(y.getValueKind()) && x.locationIdentity() == y.locationIdentity();
+        return graph.unique(new AddLocationNode(x, y));
+    }
+
+    private AddLocationNode(LocationNode x, LocationNode y) {
+        super(x.locationIdentity(), x.getValueKind());
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    protected LocationNode addDisplacement(long displacement) {
+        LocationNode added = getX().addDisplacement(displacement);
+        return graph().unique(new AddLocationNode(added, getY()));
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (x instanceof ConstantLocationNode) {
+            return getY().addDisplacement(((ConstantLocationNode) x).displacement());
+        }
+        if (y instanceof ConstantLocationNode) {
+            return getX().addDisplacement(((ConstantLocationNode) y).displacement());
+        }
+
+        if (x instanceof IndexedLocationNode && y instanceof IndexedLocationNode) {
+            IndexedLocationNode xIdx = (IndexedLocationNode) x;
+            IndexedLocationNode yIdx = (IndexedLocationNode) y;
+            if (xIdx.indexScaling() == yIdx.indexScaling()) {
+                long displacement = xIdx.displacement() + yIdx.displacement();
+                ValueNode index = IntegerArithmeticNode.add(xIdx.index(), yIdx.index());
+                return IndexedLocationNode.create(locationIdentity(), getValueKind(), displacement, index, graph(), xIdx.indexScaling());
+            }
+        }
+
+        return this;
+    }
+
+    @Override
+    public Value generateLea(LIRGeneratorTool gen, Value base) {
+        Value xAddr = getX().generateLea(gen, base);
+        return getY().generateLea(gen, xAddr);
+    }
+
+    @Override
+    public Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting) {
+        Value xAddr = getX().generateLea(gen, base);
+        return getY().generateLoad(gen, xAddr, deopting);
+    }
+
+    @Override
+    public void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting) {
+        Value xAddr = getX().generateLea(gen, base);
+        getY().generateStore(gen, xAddr, value, deopting);
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java	Mon Apr 22 16:40:54 2013 +0200
@@ -49,7 +49,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        Value addr = getLocation().generateLea(gen, getObject());
+        Value addr = getLocation().generateLea(gen, gen.operand(getObject()));
         gen.setResult(this, addr);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Mon Apr 22 16:40:54 2013 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2011, 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.nodes.extended;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * Location node that has a constant displacement. Can represent addresses of the form [base + disp]
+ * where base is a node and disp is a constant.
+ */
+@NodeInfo(nameTemplate = "Loc {p#locationIdentity/s}")
+public class ConstantLocationNode extends LocationNode {
+
+    private final long displacement;
+
+    public long displacement() {
+        return displacement;
+    }
+
+    public static ConstantLocationNode create(Object identity, Kind kind, long displacement, Graph graph) {
+        return graph.unique(new ConstantLocationNode(identity, kind, displacement));
+    }
+
+    protected ConstantLocationNode(Object identity, Kind kind, long displacement) {
+        super(identity, kind);
+        this.displacement = displacement;
+    }
+
+    @Override
+    protected ConstantLocationNode addDisplacement(long x) {
+        return create(locationIdentity(), getValueKind(), displacement + x, graph());
+    }
+
+    @Override
+    public Value generateLea(LIRGeneratorTool gen, Value base) {
+        return gen.emitLea(base, displacement(), Value.ILLEGAL, 0);
+    }
+
+    @Override
+    public Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting) {
+        return gen.emitLoad(getValueKind(), base, displacement(), Value.ILLEGAL, 0, deopting);
+    }
+
+    @Override
+    public void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting) {
+        gen.emitStore(getValueKind(), base, displacement(), Value.ILLEGAL, 0, value, deopting);
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Mon Apr 22 16:40:54 2013 +0200
@@ -53,7 +53,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, location().generateLoad(gen, object(), this));
+        gen.setResult(this, location().generateLoad(gen, gen.operand(object()), this));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Mon Apr 22 16:40:54 2013 +0200
@@ -28,13 +28,15 @@
 import com.oracle.graal.nodes.spi.*;
 
 /**
- * Extension of a {@linkplain LocationNode location} to include a scaled index. Can represent
- * locations in the form of [base + index * scale + disp] where base and index are nodes and scale
- * and disp are integer constants.
+ * Location node that has a displacement and a scaled index. Can represent locations in the form of
+ * [base + index * scale + disp] where base and index are nodes and scale and disp are integer
+ * constants.
  */
+@NodeInfo(nameTemplate = "IdxLoc {p#locationIdentity/s}")
 public final class IndexedLocationNode extends LocationNode implements Canonicalizable {
 
     @Input private ValueNode index;
+    private final long displacement;
     private final int indexScaling;
 
     /**
@@ -44,8 +46,8 @@
         return index;
     }
 
-    public static Object getArrayLocation(Kind elementKind) {
-        return elementKind;
+    public long displacement() {
+        return displacement;
     }
 
     /**
@@ -55,43 +57,46 @@
         return indexScaling;
     }
 
-    public static IndexedLocationNode create(Object identity, Kind kind, int displacement, ValueNode index, Graph graph, int indexScaling) {
+    public static IndexedLocationNode create(Object identity, Kind kind, long displacement, ValueNode index, Graph graph, int indexScaling) {
         return graph.unique(new IndexedLocationNode(identity, kind, index, displacement, indexScaling));
     }
 
-    private IndexedLocationNode(Object identity, Kind kind, ValueNode index, int displacement, int indexScaling) {
-        super(identity, kind, displacement);
+    private IndexedLocationNode(Object identity, Kind kind, ValueNode index, long displacement, int indexScaling) {
+        super(identity, kind);
         this.index = index;
+        this.displacement = displacement;
         this.indexScaling = indexScaling;
     }
 
     @Override
+    protected LocationNode addDisplacement(long x) {
+        return create(locationIdentity(), getValueKind(), displacement + x, index, graph(), indexScaling);
+    }
+
+    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         Constant constantIndex = index.asConstant();
         if (constantIndex != null) {
             long constantIndexLong = constantIndex.asLong();
             constantIndexLong *= indexScaling;
-            constantIndexLong += displacement();
-            int constantIndexInt = (int) constantIndexLong;
-            if (constantIndexLong == constantIndexInt) {
-                return LocationNode.create(locationIdentity(), getValueKind(), constantIndexInt, graph());
-            }
+            constantIndexLong += displacement;
+            return ConstantLocationNode.create(locationIdentity(), getValueKind(), constantIndexLong, graph());
         }
         return this;
     }
 
     @Override
-    public Value generateLea(LIRGeneratorTool gen, ValueNode base) {
-        return gen.emitLea(gen.operand(base), displacement(), gen.operand(index()), indexScaling());
+    public Value generateLea(LIRGeneratorTool gen, Value base) {
+        return gen.emitLea(base, displacement, gen.operand(index()), indexScaling());
     }
 
     @Override
-    public Value generateLoad(LIRGeneratorTool gen, ValueNode base, DeoptimizingNode deopting) {
-        return gen.emitLoad(getValueKind(), gen.operand(base), displacement(), gen.operand(index()), indexScaling(), deopting);
+    public Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting) {
+        return gen.emitLoad(getValueKind(), base, displacement, gen.operand(index()), indexScaling(), deopting);
     }
 
     @Override
-    public void generateStore(LIRGeneratorTool gen, ValueNode base, ValueNode value, DeoptimizingNode deopting) {
-        gen.emitStore(getValueKind(), gen.operand(base), displacement(), gen.operand(index()), indexScaling(), gen.operand(value), deopting);
+    public void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting) {
+        gen.emitStore(getValueKind(), base, displacement, gen.operand(index()), indexScaling(), value, deopting);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Mon Apr 22 16:40:54 2013 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -31,20 +30,18 @@
 import com.oracle.graal.nodes.type.*;
 
 /**
- * A location for a memory access in terms of the kind of value accessed and how to access it. The
- * base version can represent addresses of the form [base + disp] where base is a node and disp is a
- * constant.
+ * A location for a memory access in terms of the kind of value accessed and how to access it.
+ * All locations have the form [base + location], where base is a node and location is defined
+ * by subclasses of the {@link LocationNode}.
  */
-@NodeInfo(nameTemplate = "Loc {p#locationIdentity/s}")
-public class LocationNode extends FloatingNode implements LIRLowerable, ValueNumberable {
+public abstract class LocationNode extends FloatingNode implements LIRLowerable, ValueNumberable {
 
-    private int displacement;
     private Kind valueKind;
     private Object locationIdentity;
 
     /**
      * Creates a new unique location identity for read and write operations.
-     * 
+     *
      * @param name the name of the new location identity, for debugging purposes
      * @return the new location identity
      */
@@ -74,18 +71,9 @@
         return elementKind;
     }
 
-    public int displacement() {
-        return displacement;
-    }
-
-    public static LocationNode create(Object identity, Kind kind, int displacement, Graph graph) {
-        return graph.unique(new LocationNode(identity, kind, displacement));
-    }
-
-    protected LocationNode(Object identity, Kind kind, int displacement) {
+    protected LocationNode(Object identity, Kind kind) {
         super(StampFactory.extension());
         assert kind != Kind.Illegal && kind != Kind.Void;
-        this.displacement = displacement;
         this.valueKind = kind;
         this.locationIdentity = identity;
     }
@@ -98,20 +86,16 @@
         return locationIdentity;
     }
 
+    protected abstract LocationNode addDisplacement(long displacement);
+
     @Override
     public void generate(LIRGeneratorTool generator) {
         // nothing to do...
     }
 
-    public Value generateLea(LIRGeneratorTool gen, ValueNode base) {
-        return gen.emitLea(gen.operand(base), displacement(), Value.ILLEGAL, 0);
-    }
+    public abstract Value generateLea(LIRGeneratorTool gen, Value base);
 
-    public Value generateLoad(LIRGeneratorTool gen, ValueNode base, DeoptimizingNode deopting) {
-        return gen.emitLoad(getValueKind(), gen.operand(base), displacement(), Value.ILLEGAL, 0, deopting);
-    }
+    public abstract Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting);
 
-    public void generateStore(LIRGeneratorTool gen, ValueNode base, ValueNode value, DeoptimizingNode deopting) {
-        gen.emitStore(getValueKind(), gen.operand(base), displacement(), Value.ILLEGAL, 0, gen.operand(value), deopting);
-    }
+    public abstract void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon Apr 22 16:40:54 2013 +0200
@@ -44,7 +44,7 @@
     }
 
     private ReadNode(ValueNode object, int displacement, Object locationIdentity, Kind kind) {
-        super(object, object.graph().add(new LocationNode(locationIdentity, kind, displacement)), StampFactory.forKind(kind));
+        super(object, ConstantLocationNode.create(locationIdentity, kind, displacement, object.graph()), StampFactory.forKind(kind));
     }
 
     private ReadNode(ValueNode object, ValueNode location, ValueNode dependency) {
@@ -57,7 +57,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, location().generateLoad(gen, object(), this));
+        gen.setResult(this, location().generateLoad(gen, gen.operand(object()), this));
     }
 
     @Override
@@ -73,8 +73,8 @@
     public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool) {
         MetaAccessProvider runtime = tool.runtime();
         if (runtime != null && object != null && object.isConstant()) {
-            if (location.locationIdentity() == LocationNode.FINAL_LOCATION && location.getClass() == LocationNode.class) {
-                long displacement = location.displacement();
+            if (location.locationIdentity() == LocationNode.FINAL_LOCATION && location instanceof ConstantLocationNode) {
+                long displacement = ((ConstantLocationNode) location).displacement();
                 Kind kind = location.getValueKind();
                 if (object.kind() == Kind.Object) {
                     Object base = object.asConstant().asObject();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Mon Apr 22 16:40:54 2013 +0200
@@ -84,7 +84,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        location().generateStore(gen, object(), value(), this);
+        location().generateStore(gen, gen.operand(object()), gen.operand(value()), this);
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Mon Apr 22 16:40:54 2013 +0200
@@ -57,11 +57,11 @@
 
     public abstract void emitMove(Value dst, Value src);
 
-    public abstract Value emitLoad(Kind kind, Value base, int displacement, Value index, int scale, DeoptimizingNode deopting);
+    public abstract Value emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode deopting);
 
-    public abstract void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value input, DeoptimizingNode deopting);
+    public abstract void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value input, DeoptimizingNode deopting);
 
-    public abstract Value emitLea(Value base, int displacement, Value index, int scale);
+    public abstract Value emitLea(Value base, long displacement, Value index, int scale);
 
     public abstract Value emitLea(StackSlot slot);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MacroSubstitution.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MacroSubstitution.java	Mon Apr 22 16:40:54 2013 +0200
@@ -78,7 +78,7 @@
      * Determines if this method should be substituted in all cases, even if inlining thinks it is
      * not important.
      * 
-     * Not that this is still depending on whether inlining sees the correct call target, so it's
+     * Note that this is still depending on whether inlining sees the correct call target, so it's
      * only a hard guarantee for static and special invocations.
      */
     boolean forced() default false;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Mon Apr 22 16:40:54 2013 +0200
@@ -218,6 +218,10 @@
     }
 
     private boolean isImplicitNullCheck(LocationNode location) {
-        return !(location instanceof IndexedLocationNode) && location.displacement() < target.implicitNullCheckLimit;
+        if (location instanceof ConstantLocationNode) {
+            return ((ConstantLocationNode) location).displacement() < target.implicitNullCheckLimit;
+        } else {
+            return false;
+        }
     }
 }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Mon Apr 22 16:39:47 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Mon Apr 22 16:40:54 2013 +0200
@@ -161,7 +161,7 @@
                 previousInlineContext = inlineContext;
 
                 final SchedulePhase predefinedSchedule = getPredefinedSchedule();
-                Debug.sandbox("PrintingGraph", new Runnable() {
+                Debug.sandbox("PrintingGraph", null, new Runnable() {
 
                     @Override
                     public void run() {