changeset 3160:8044bdfaab06

Lowering of array accesses.
author Thomas Wuerthinger <thomas@wuerthinger.net>
date Wed, 06 Jul 2011 16:15:15 +0200
parents 7f2bf8fe6804
children ce7e5b3798f7 462c89186179
files graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CheckCast.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/GuardNode.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoadIndexed.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/StoreIndexed.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/TypeCheck.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoweringPhase.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/MemoryPhase.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRAssembler.java graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotRuntime.java graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/nodes/ArrayWriteBarrier.java graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/nodes/FieldWriteBarrier.java graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/nodes/WriteBarrier.java
diffstat 17 files changed, 301 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java	Wed Jul 06 13:28:51 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java	Wed Jul 06 16:15:15 2011 +0200
@@ -153,6 +153,7 @@
     public static boolean CommentedAssembly                  = ____;
     public static boolean PrintLIRWithAssembly               = ____;
 
+    public static boolean OptReadElimination                 = ____;
     public static boolean OptGVN                             = ____;
     public static boolean OptCanonicalizer                   = true;
     public static boolean OptLoops                           = ____;
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Wed Jul 06 13:28:51 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Wed Jul 06 16:15:15 2011 +0200
@@ -484,6 +484,8 @@
             emitCompare((Compare) node, trueSuccessor, falseSuccessor);
         } else if (node instanceof InstanceOf) {
             emitInstanceOf((TypeCheck) node, trueSuccessor, falseSuccessor, info);
+        } else if (node instanceof Constant) {
+            emitConstantBranch(((Constant) node).asConstant().asBoolean(), trueSuccessor, falseSuccessor, info);
         } else {
             throw Util.unimplemented(node.toString());
         }
@@ -498,6 +500,21 @@
         instr.setFalseSuccessor(falseSuccessor);
     }
 
+
+    public void emitConstantBranch(boolean value, LIRBlock trueSuccessorBlock, LIRBlock falseSuccessorBlock, LIRDebugInfo info) {
+        if (value) {
+            emitConstantBranch(trueSuccessorBlock, info);
+        } else {
+            emitConstantBranch(falseSuccessorBlock, info);
+        }
+    }
+
+    private void emitConstantBranch(LIRBlock block, LIRDebugInfo info) {
+        if (block != null) {
+            lir.jump(block);
+        }
+    }
+
     public void emitCompare(Compare compare, LIRBlock trueSuccessorBlock, LIRBlock falseSuccessorBlock) {
         CiKind kind = compare.x().kind;
 
@@ -761,13 +778,17 @@
             FrameState state = lastState;
             assert state != null : "deoptimize instruction always needs a state";
 
-            if (deoptimizationStubs == null) {
-                deoptimizationStubs = new ArrayList<DeoptimizationStub>();
+            if (comp instanceof Constant && comp.asConstant().asBoolean()) {
+                // Nothing to emit.
+            } else {
+                if (deoptimizationStubs == null) {
+                    deoptimizationStubs = new ArrayList<DeoptimizationStub>();
+                }
+
+                DeoptimizationStub stub = new DeoptimizationStub(DeoptAction.InvalidateReprofile, state);
+                deoptimizationStubs.add(stub);
+                emitBooleanBranch(comp, null, new LIRBlock(stub.label, stub.info), stub.info);
             }
-            DeoptimizationStub stub = new DeoptimizationStub(DeoptAction.InvalidateReprofile, state);
-            deoptimizationStubs.add(stub);
-
-            emitBooleanBranch(comp, null, new LIRBlock(stub.label, stub.info), stub.info);
         }
     }
 
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java	Wed Jul 06 13:28:51 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java	Wed Jul 06 16:15:15 2011 +0200
@@ -111,13 +111,15 @@
             new GlobalValueNumberingPhase().apply(graph);
         }
 
+        new LoweringPhase(compilation.runtime).apply(graph);
         if (GraalOptions.Lower) {
-            new LoweringPhase(compilation.runtime).apply(graph);
             new MemoryPhase().apply(graph);
             if (GraalOptions.OptGVN) {
                 new GlobalValueNumberingPhase().apply(graph);
             }
-            new ReadEliminationPhase().apply(graph);
+            if (GraalOptions.OptReadElimination) {
+                new ReadEliminationPhase().apply(graph);
+            }
         }
 
         IdentifyBlocksPhase schedule = new IdentifyBlocksPhase(true);
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CheckCast.java	Wed Jul 06 13:28:51 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CheckCast.java	Wed Jul 06 16:15:15 2011 +0200
@@ -42,7 +42,7 @@
      * @param object the instruction producing the object
      * @param graph
      */
-    public CheckCast(Constant targetClassInstruction, Value object, Graph graph) {
+    public CheckCast(Value targetClassInstruction, Value object, Graph graph) {
         super(targetClassInstruction, object, CiKind.Object, INPUT_COUNT, SUCCESSOR_COUNT, graph);
     }
 
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/GuardNode.java	Wed Jul 06 13:28:51 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/GuardNode.java	Wed Jul 06 16:15:15 2011 +0200
@@ -55,8 +55,9 @@
         inputs().set(super.inputCount() + INPUT_NODE, n);
     }
 
-    public GuardNode(Graph graph) {
+    public GuardNode(BooleanNode node, Graph graph) {
         super(CiKind.Illegal, INPUT_COUNT, SUCCESSOR_COUNT, graph);
+        setNode(node);
     }
 
     @Override
@@ -71,7 +72,7 @@
 
     @Override
     public Node copy(Graph into) {
-        return new GuardNode(into);
+        return new GuardNode(null, into);
     }
 
     @SuppressWarnings("unchecked")
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoadIndexed.java	Wed Jul 06 13:28:51 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoadIndexed.java	Wed Jul 06 16:15:15 2011 +0200
@@ -23,6 +23,8 @@
 package com.oracle.max.graal.compiler.ir;
 
 import com.oracle.max.graal.compiler.debug.*;
+import com.oracle.max.graal.compiler.phases.*;
+import com.oracle.max.graal.compiler.phases.LoweringPhase.LoweringOp;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.ci.*;
 import com.sun.cri.ri.*;
@@ -85,6 +87,16 @@
         return false;
     }
 
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends Op> T lookup(Class<T> clazz) {
+        if (clazz == LoweringOp.class) {
+            return (T) LoweringPhase.DELEGATE_TO_RUNTIME;
+        }
+        return super.lookup(clazz);
+    }
+
     @Override
     public Node copy(Graph into) {
         LoadIndexed x = new LoadIndexed(null, null, null, elementKind(), into);
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/StoreIndexed.java	Wed Jul 06 13:28:51 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/StoreIndexed.java	Wed Jul 06 16:15:15 2011 +0200
@@ -23,6 +23,8 @@
 package com.oracle.max.graal.compiler.ir;
 
 import com.oracle.max.graal.compiler.debug.*;
+import com.oracle.max.graal.compiler.phases.*;
+import com.oracle.max.graal.compiler.phases.LoweringPhase.*;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.ci.*;
 
@@ -82,6 +84,15 @@
         out.print(array()).print('[').print(index()).print("] := ").print(value()).print(" (").print(kind.typeChar).print(')');
     }
 
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends Op> T lookup(Class<T> clazz) {
+        if (clazz == LoweringOp.class) {
+            return (T) LoweringPhase.DELEGATE_TO_RUNTIME;
+        }
+        return super.lookup(clazz);
+    }
+
     @Override
     public Node copy(Graph into) {
         StoreIndexed x = new StoreIndexed(null, null, null, elementKind(), null, into);
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/TypeCheck.java	Wed Jul 06 13:28:51 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/TypeCheck.java	Wed Jul 06 16:15:15 2011 +0200
@@ -61,11 +61,11 @@
     /**
      * The instruction that loads the target class object that is used by this checkcast.
      */
-     public Constant targetClassInstruction() {
-        return (Constant) inputs().get(super.inputCount() + INPUT_TARGET_CLASS_INSTRUCTION);
+     public Value targetClassInstruction() {
+        return (Value) inputs().get(super.inputCount() + INPUT_TARGET_CLASS_INSTRUCTION);
     }
 
-    private void setTargetClassInstruction(Constant n) {
+    private void setTargetClassInstruction(Value n) {
         inputs().set(super.inputCount() + INPUT_TARGET_CLASS_INSTRUCTION, n);
     }
 
@@ -75,7 +75,7 @@
      * @return the target class
      */
     public RiType targetClass() {
-        return (RiType) targetClassInstruction().asConstant().asObject();
+        return targetClassInstruction() instanceof Constant ? (RiType) targetClassInstruction().asConstant().asObject() : null;
     }
 
     /**
@@ -87,7 +87,7 @@
      * @param successorCount
      * @param graph
      */
-    public TypeCheck(Constant targetClassInstruction, Value object, CiKind kind, int inputCount, int successorCount, Graph graph) {
+    public TypeCheck(Value targetClassInstruction, Value object, CiKind kind, int inputCount, int successorCount, Graph graph) {
         super(kind, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph);
         setObject(object);
         setTargetClassInstruction(targetClassInstruction);
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoweringPhase.java	Wed Jul 06 13:28:51 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoweringPhase.java	Wed Jul 06 16:15:15 2011 +0200
@@ -57,11 +57,13 @@
     }
 
     private void process(final Block b) {
+
+        final Node anchor = b.javaBlock().createAnchor();
         final CiLoweringTool loweringTool = new CiLoweringTool() {
 
             @Override
             public Node getGuardAnchor() {
-                return b.createAnchor();
+                return anchor;
             }
 
             @Override
@@ -72,19 +74,13 @@
             @Override
             public Node createGuard(Node condition) {
                 Anchor anchor = (Anchor) getGuardAnchor();
-                for (GuardNode guard : anchor.happensAfterGuards()) {
-                    if (guard.node().valueEqual(condition)) {
-                        condition.delete();
-                        return guard;
-                    }
-                }
-                GuardNode newGuard = new GuardNode(anchor.graph());
+                GuardNode newGuard = new GuardNode((BooleanNode) condition, anchor.graph());
                 newGuard.setAnchor(anchor);
-                newGuard.setNode((BooleanNode) condition);
                 return newGuard;
             }
         };
 
+
         // Lower the instructions of this block.
         for (final Node n : b.getInstructions()) {
             if (n instanceof FixedNode) {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/MemoryPhase.java	Wed Jul 06 13:28:51 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/MemoryPhase.java	Wed Jul 06 16:15:15 2011 +0200
@@ -315,6 +315,8 @@
             LoopBegin begin = end.loopBegin();
             Block beginBlock = nodeMap.get(begin);
             MemoryMap memoryMap = memoryMaps[beginBlock.blockID()];
+            assert memoryMap != null : beginBlock.name();
+            assert memoryMap.getLoopEntryMap() != null;
             memoryMap.getLoopEntryMap().resetMergeOperationCount();
             memoryMap.getLoopEntryMap().mergeWith(map, beginBlock);
             Node loopCheckPoint = memoryMap.getLoopCheckPoint();
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java	Wed Jul 06 13:28:51 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java	Wed Jul 06 16:15:15 2011 +0200
@@ -246,4 +246,8 @@
             }
         }
     }
+
+    public String name() {
+        return "B" + blockID;
+    }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRAssembler.java	Wed Jul 06 13:28:51 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRAssembler.java	Wed Jul 06 16:15:15 2011 +0200
@@ -1300,11 +1300,11 @@
                     default      : throw Util.shouldNotReachHere();
                 }
             } else {
-                throw Util.shouldNotReachHere();
+                throw Util.shouldNotReachHere("opr1=" + opr1.toString() + " opr2=" + opr2);
             }
 
         } else {
-            throw Util.shouldNotReachHere(opr1.toString() + " opr2 = " + opr2);
+            throw Util.shouldNotReachHere("opr1=" + opr1.toString() + " opr2=" + opr2);
         }
         // Checkstyle: on
     }
--- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotRuntime.java	Wed Jul 06 13:28:51 2011 +0200
+++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotRuntime.java	Wed Jul 06 16:15:15 2011 +0200
@@ -26,6 +26,7 @@
 import java.lang.reflect.*;
 import java.util.*;
 
+import com.oracle.max.graal.compiler.*;
 import com.oracle.max.graal.compiler.graph.*;
 import com.oracle.max.graal.compiler.ir.*;
 import com.oracle.max.graal.compiler.value.*;
@@ -36,6 +37,7 @@
 import com.sun.cri.ci.CiTargetMethod.DataPatch;
 import com.sun.cri.ci.CiTargetMethod.Safepoint;
 import com.sun.cri.ri.*;
+import com.sun.cri.ri.RiType.Representation;
 import com.sun.max.asm.dis.*;
 import com.sun.max.lang.*;
 
@@ -246,6 +248,10 @@
 
     @Override
     public void lower(Node n, CiLoweringTool tool) {
+        if (!GraalOptions.Lower) {
+            return;
+        }
+
         if (n instanceof LoadField) {
             LoadField field = (LoadField) n;
             if (field.isVolatile()) {
@@ -277,9 +283,70 @@
                 memoryWrite.setNext(field.next());
             }
             field.replaceAndDelete(memoryWrite);
+        } else if (n instanceof LoadIndexed) {
+            LoadIndexed loadIndexed = (LoadIndexed) n;
+            Graph graph = loadIndexed.graph();
+            GuardNode boundsCheck = createBoundsCheck(loadIndexed, tool);
+
+            CiKind elementKind = loadIndexed.elementKind();
+            LocationNode arrayLocation = createArrayLocation(graph, elementKind);
+            arrayLocation.setIndex(loadIndexed.index());
+            ReadNode memoryRead = new ReadNode(elementKind.stackKind(), loadIndexed.array(), arrayLocation, graph);
+            memoryRead.setGuard(boundsCheck);
+            memoryRead.setNext(loadIndexed.next());
+            loadIndexed.replaceAndDelete(memoryRead);
+        } else if (n instanceof StoreIndexed) {
+            StoreIndexed storeIndexed = (StoreIndexed) n;
+            Graph graph = storeIndexed.graph();
+            Anchor anchor = new Anchor(graph);
+            GuardNode boundsCheck = createBoundsCheck(storeIndexed, tool);
+            anchor.inputs().add(boundsCheck);
+
+
+            CiKind elementKind = storeIndexed.elementKind();
+            LocationNode arrayLocation = createArrayLocation(graph, elementKind);
+            arrayLocation.setIndex(storeIndexed.index());
+            Value value = storeIndexed.value();
+            if (elementKind == CiKind.Object) {
+                // Store check!
+                if (storeIndexed.array().exactType() != null) {
+                    RiType elementType = storeIndexed.array().exactType().componentType();
+                    if (elementType.superType() != null) {
+                        Constant type = new Constant(elementType.getEncoding(Representation.ObjectHub), graph);
+                        value = new CheckCast(type, value, graph);
+                    } else {
+                        assert elementType.name().equals("Ljava/lang/Object;") : elementType.name();
+                    }
+                } else {
+                    ReadNode arrayKlass = new ReadNode(CiKind.Object, storeIndexed.array(), LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph), graph);
+                    ReadNode arrayElementKlass = new ReadNode(CiKind.Object, arrayKlass, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.arrayClassElementOffset, graph), graph);
+                    value = new CheckCast(arrayElementKlass, value, graph);
+                }
+            }
+            WriteNode memoryWrite = new WriteNode(elementKind.stackKind(), storeIndexed.array(), value, arrayLocation, graph);
+            memoryWrite.setGuard(boundsCheck);
+            memoryWrite.setStateAfter(storeIndexed.stateAfter());
+            anchor.setNext(memoryWrite);
+            if (elementKind == CiKind.Object && !value.isNullConstant()) {
+                ArrayWriteBarrier writeBarrier = new ArrayWriteBarrier(storeIndexed.array(), arrayLocation, graph);
+                memoryWrite.setNext(writeBarrier);
+                writeBarrier.setNext(storeIndexed.next());
+            } else {
+                memoryWrite.setNext(storeIndexed.next());
+            }
+            storeIndexed.replaceAtPredecessors(anchor);
+            storeIndexed.delete();
         }
     }
 
+    private LocationNode createArrayLocation(Graph graph, CiKind elementKind) {
+        return LocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, config.getArrayOffset(elementKind), graph);
+    }
+
+    private GuardNode createBoundsCheck(AccessIndexed n, CiLoweringTool tool) {
+        return (GuardNode) tool.createGuard(new Compare(n.index(), Condition.BT, n.length(), n.graph()));
+    }
+
     @Override
     public Graph intrinsicGraph(RiMethod method, List<? extends Node> parameters) {
         if (!intrinsicGraphs.containsKey(method)) {
--- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java	Wed Jul 06 13:28:51 2011 +0200
+++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java	Wed Jul 06 16:15:15 2011 +0200
@@ -1179,7 +1179,6 @@
 
     @Override
     public XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiType type) {
-        assert type.isResolved();
         return new XirSnippet(checkCastTemplates.get(site), receiver, hub);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/nodes/ArrayWriteBarrier.java	Wed Jul 06 16:15:15 2011 +0200
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.max.graal.runtime.nodes;
+
+import com.oracle.max.graal.compiler.debug.*;
+import com.oracle.max.graal.compiler.gen.*;
+import com.oracle.max.graal.compiler.ir.*;
+import com.oracle.max.graal.graph.*;
+import com.sun.cri.ci.*;
+
+
+public final class ArrayWriteBarrier extends WriteBarrier {
+    private static final int INPUT_COUNT = 2;
+    private static final int INPUT_OBJECT = 0;
+    private static final int INPUT_LOCATION = 1;
+
+    private static final int SUCCESSOR_COUNT = 0;
+
+    @Override
+    protected int inputCount() {
+        return super.inputCount() + INPUT_COUNT;
+    }
+
+    /**
+     * The instruction that produces the object tested against null.
+     */
+     public Value object() {
+        return (Value) inputs().get(super.inputCount() + INPUT_OBJECT);
+    }
+
+    public void setObject(Value n) {
+        inputs().set(super.inputCount() + INPUT_OBJECT, n);
+    }
+
+    /**
+     * The instruction that produces the object tested against null.
+     */
+     public LocationNode location() {
+        return (LocationNode) inputs().get(super.inputCount() + INPUT_LOCATION);
+    }
+
+    public void setLocation(LocationNode n) {
+        inputs().set(super.inputCount() + INPUT_LOCATION, n);
+    }
+
+    public ArrayWriteBarrier(Value object, LocationNode index, Graph graph) {
+        super(INPUT_COUNT, SUCCESSOR_COUNT, graph);
+        this.setObject(object);
+        this.setLocation(index);
+    }
+
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends Op> T lookup(Class<T> clazz) {
+        if (clazz == LIRGenerator.LIRGeneratorOp.class) {
+            return (T) new LIRGenerator.LIRGeneratorOp() {
+                @Override
+                public void generate(Node n, LIRGenerator generator) {
+                    assert n == ArrayWriteBarrier.this;
+                    CiVariable temp = generator.newVariable(CiKind.Word);
+                    generator.lir().lea(location().createAddress(generator, object()), temp);
+                    ArrayWriteBarrier.this.generateBarrier(temp, generator);
+                }
+            };
+        }
+        return super.lookup(clazz);
+    }
+
+    @Override
+    public void print(LogStream out) {
+        out.print("field write barrier ").print(object());
+    }
+
+    @Override
+    public Node copy(Graph into) {
+        return new ArrayWriteBarrier(null, null, into);
+    }
+}
--- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/nodes/FieldWriteBarrier.java	Wed Jul 06 13:28:51 2011 +0200
+++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/nodes/FieldWriteBarrier.java	Wed Jul 06 16:15:15 2011 +0200
@@ -25,13 +25,11 @@
 import com.oracle.max.graal.compiler.debug.*;
 import com.oracle.max.graal.compiler.gen.*;
 import com.oracle.max.graal.compiler.ir.*;
-import com.oracle.max.graal.compiler.lir.*;
 import com.oracle.max.graal.graph.*;
-import com.oracle.max.graal.runtime.*;
 import com.sun.cri.ci.*;
 
 
-public final class FieldWriteBarrier extends FixedNodeWithNext {
+public final class FieldWriteBarrier extends WriteBarrier {
     private static final int INPUT_COUNT = 1;
     private static final int INPUT_OBJECT = 0;
 
@@ -54,7 +52,7 @@
     }
 
     public FieldWriteBarrier(Value object, Graph graph) {
-        super(CiKind.Illegal, INPUT_COUNT, SUCCESSOR_COUNT, graph);
+        super(INPUT_COUNT, SUCCESSOR_COUNT, graph);
         this.setObject(object);
     }
 
@@ -68,18 +66,8 @@
                 public void generate(Node n, LIRGenerator generator) {
                     assert n == FieldWriteBarrier.this;
                     CiVariable temp = generator.newVariable(CiKind.Word);
-                    HotSpotVMConfig config = CompilerImpl.getInstance().getConfig();
                     generator.lir().move(generator.makeOperand(object()), temp);
-                    generator.lir().unsignedShiftRight(temp, CiConstant.forInt(config.cardtableShift), temp, CiValue.IllegalValue);
-
-                    long startAddress = config.cardtableStartAddress;
-                    int displacement = 0;
-                    if (((int) startAddress) == startAddress) {
-                        displacement = (int) startAddress;
-                    } else {
-                        generator.lir().add(temp, CiConstant.forLong(config.cardtableStartAddress), temp);
-                    }
-                    generator.lir().move(CiConstant.FALSE, new CiAddress(CiKind.Boolean, temp, displacement), (LIRDebugInfo) null);
+                    FieldWriteBarrier.this.generateBarrier(temp, generator);
                 }
             };
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/nodes/WriteBarrier.java	Wed Jul 06 16:15:15 2011 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.max.graal.runtime.nodes;
+
+import com.oracle.max.graal.compiler.gen.*;
+import com.oracle.max.graal.compiler.ir.*;
+import com.oracle.max.graal.compiler.lir.*;
+import com.oracle.max.graal.graph.*;
+import com.oracle.max.graal.runtime.*;
+import com.sun.cri.ci.*;
+
+
+public abstract class WriteBarrier extends FixedNodeWithNext {
+    private static final int INPUT_COUNT = 0;
+    private static final int SUCCESSOR_COUNT = 0;
+
+    public WriteBarrier(int inputCount, int successorCount, Graph graph) {
+        super(CiKind.Illegal, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph);
+    }
+
+
+    protected void generateBarrier(CiValue temp, LIRGenerator generator) {
+        HotSpotVMConfig config = CompilerImpl.getInstance().getConfig();
+        generator.lir().unsignedShiftRight(temp, CiConstant.forInt(config.cardtableShift), temp, CiValue.IllegalValue);
+
+        long startAddress = config.cardtableStartAddress;
+        int displacement = 0;
+        if (((int) startAddress) == startAddress) {
+            displacement = (int) startAddress;
+        } else {
+            generator.lir().add(temp, CiConstant.forLong(config.cardtableStartAddress), temp);
+        }
+        generator.lir().move(CiConstant.FALSE, new CiAddress(CiKind.Boolean, temp, displacement), (LIRDebugInfo) null);
+    }
+}