# HG changeset patch # User Gilles Duboscq # Date 1363293388 -3600 # Node ID 60f90b4b6a127910cd3117a72e08e9167b3574ca # Parent 5439cc2d73af4e05b63dc5d5b7b9a474cead6f8d Implement implicit null check on HIR during guard lowering diff -r 5439cc2d73af -r 60f90b4b6a12 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java Thu Mar 14 14:02:23 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java Thu Mar 14 21:36:28 2013 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes; +import java.util.*; + import com.oracle.graal.nodes.type.*; public abstract class FixedNode extends ValueNode { @@ -32,6 +34,10 @@ super(stamp); } + public FixedNode(Stamp stamp, List dependencies) { + super(stamp, dependencies); + } + public FixedNode(Stamp stamp, ValueNode... dependencies) { super(stamp, dependencies); } diff -r 5439cc2d73af -r 60f90b4b6a12 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java Thu Mar 14 14:02:23 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java Thu Mar 14 21:36:28 2013 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes; +import java.util.*; + import com.oracle.graal.nodes.type.*; /** @@ -43,6 +45,10 @@ super(stamp); } + public FixedWithNextNode(Stamp stamp, List dependencies) { + super(stamp, dependencies); + } + public FixedWithNextNode(Stamp stamp, ValueNode... dependencies) { super(stamp, dependencies); } diff -r 5439cc2d73af -r 60f90b4b6a12 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java Thu Mar 14 14:02:23 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java Thu Mar 14 21:36:28 2013 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes.extended; +import java.util.*; + import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; @@ -58,6 +60,12 @@ this.location = location; } + public AccessNode(ValueNode object, ValueNode location, Stamp stamp, List dependencies) { + super(stamp, dependencies); + this.object = object; + this.location = location; + } + public AccessNode(ValueNode object, ValueNode location, Stamp stamp, ValueNode... dependencies) { super(stamp, dependencies); this.object = object; diff -r 5439cc2d73af -r 60f90b4b6a12 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Thu Mar 14 14:02:23 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Thu Mar 14 21:36:28 2013 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes.extended; +import java.util.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; @@ -37,6 +39,10 @@ super(object, location, stamp); } + public ReadNode(ValueNode object, ValueNode location, Stamp stamp, List dependencies) { + super(object, location, stamp, dependencies); + } + private ReadNode(ValueNode object, int displacement, Object locationIdentity, Kind kind) { super(object, object.graph().add(new LocationNode(locationIdentity, kind, displacement)), StampFactory.forKind(kind)); } diff -r 5439cc2d73af -r 60f90b4b6a12 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Thu Mar 14 14:02:23 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Thu Mar 14 21:36:28 2013 +0100 @@ -23,30 +23,46 @@ package com.oracle.graal.phases.common; import java.util.*; +import java.util.Map.Entry; +import com.oracle.graal.api.code.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.schedule.*; public class GuardLoweringPhase extends Phase { + private TargetDescription target; + + public GuardLoweringPhase(TargetDescription target) { + this.target = target; + } + @Override protected void run(StructuredGraph graph) { SchedulePhase schedule = new SchedulePhase(); schedule.apply(graph); for (Block block : schedule.getCFG().getBlocks()) { - processBlock(block, schedule, graph); + processBlock(block, schedule, graph, target); } } - private static void processBlock(Block block, SchedulePhase schedule, StructuredGraph graph) { + private static void processBlock(Block block, SchedulePhase schedule, StructuredGraph graph, TargetDescription target) { List nodes = schedule.nodesFor(block); + if (GraalOptions.OptImplicitNullChecks && target.implicitNullCheckLimit > 0) { + useImplicitNullChecks(block.getBeginNode(), nodes, graph, target); + } FixedWithNextNode lastFixed = block.getBeginNode(); BeginNode lastFastPath = null; for (Node node : nodes) { + if (!node.isAlive()) { + continue; + } if (lastFastPath != null && node instanceof FixedNode) { lastFastPath.setNext((FixedNode) node); lastFastPath = null; @@ -81,4 +97,66 @@ } } } + + private static void useImplicitNullChecks(BeginNode begin, List nodes, StructuredGraph graph, TargetDescription target) { + ListIterator iterator = nodes.listIterator(); + IdentityHashMap nullGuarded = new IdentityHashMap<>(); + FixedWithNextNode lastFixed = begin; + FixedWithNextNode reconnect = null; + while (iterator.hasNext()) { + Node node = iterator.next(); + + if (reconnect != null && node instanceof FixedNode) { + reconnect.setNext((FixedNode) node); + reconnect = null; + } + if (node instanceof FixedWithNextNode) { + lastFixed = (FixedWithNextNode) node; + } + + if (node instanceof GuardNode) { + GuardNode guard = (GuardNode) node; + if (guard.negated() && guard.condition() instanceof IsNullNode) { + ValueNode obj = ((IsNullNode) guard.condition()).object(); + nullGuarded.put(obj, guard); + } + } else if (node instanceof Access) { + Access access = (Access) node; + GuardNode guard = nullGuarded.get(access.object()); + if (guard != null && isImplicitNullCheck(access.location(), target)) { + if (access instanceof FloatingReadNode) { + NodeInputList dependencies = ((FloatingReadNode) access).dependencies(); + dependencies.remove(guard); + ReadNode read = graph.add(new ReadNode(access.object(), access.location(), ((FloatingReadNode) access).stamp(), dependencies)); + node.replaceAndDelete(read); + access = read; + lastFixed.setNext(read); + lastFixed = read; + reconnect = read; + iterator.set(read); + } + assert access instanceof AccessNode; + access.setNullCheck(true); + guard.replaceAndDelete(access.node()); + nullGuarded.remove(access.object()); + } + } + if (node instanceof StateSplit && ((StateSplit) node).stateAfter() != null) { + nullGuarded.clear(); + } else { + Iterator> it = nullGuarded.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + GuardNode guard = entry.getValue(); + if (guard.usages().contains(node)) { + it.remove(); + } + } + } + } + } + + private static boolean isImplicitNullCheck(LocationNode location, TargetDescription target) { + return !(location instanceof IndexedLocationNode) && location.displacement() < target.implicitNullCheckLimit; + } }