# HG changeset patch # User Gilles Duboscq # Date 1339686649 -7200 # Node ID cf630991cb1d547ff824bed9fd951e1bc35ae860 # Parent a03ca01cfe62452565cea074689e2d42fea0153f# Parent a9b615da0cba85a20307d2d9302ed494cc1bc533 Merge diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Thu Jun 14 17:10:49 2012 +0200 @@ -261,7 +261,7 @@ * Only instructions in methods whose fully qualified name contains this option will be HIR lowered. */ public static String HIRLowerCheckcast = ""; - public static String HIRLowerNewInstance = null; + public static String HIRLowerNewInstance = "NewInstanceTest"; /** * The profiling info cache directory. diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Thu Jun 14 17:10:49 2012 +0200 @@ -32,7 +32,6 @@ import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.virtual.*; public class DebugInfoBuilder { @@ -52,20 +51,13 @@ VirtualObject[] virtualObjectsArray = null; if (virtualObjects.size() != 0) { // collect all VirtualObjectField instances: - IdentityHashMap objectStates = new IdentityHashMap<>(); + IdentityHashMap objectStates = new IdentityHashMap<>(); FrameState current = topState; do { - for (Node n : current.virtualObjectMappings()) { - Node p = n; - while (p instanceof PhiNode) { - PhiNode phi = (PhiNode) p; - assert phi.type() == PhiType.Virtual; - p = phi.valueAt(0); - } - VirtualObjectFieldNode field = (VirtualObjectFieldNode) p; + for (VirtualObjectState state : current.virtualObjectMappings()) { // null states occur for objects with 0 fields - if (field != null && !objectStates.containsKey(field.object())) { - objectStates.put(field.object(), field); + if (!objectStates.containsKey(state.object())) { + objectStates.put(state.object(), state); } } current = current.outerFrameState(); @@ -87,20 +79,11 @@ entry.getValue().setValues(values); if (values.length > 0) { changed = true; - ValueNode currentField = objectStates.get(vobj); + VirtualObjectState currentField = objectStates.get(vobj); assert currentField != null; - do { - if (currentField instanceof VirtualObjectFieldNode) { - int index = ((VirtualObjectFieldNode) currentField).index(); - if (values[index] == null) { - values[index] = toCiValue(((VirtualObjectFieldNode) currentField).input()); - } - currentField = ((VirtualObjectFieldNode) currentField).lastState(); - } else { - assert currentField instanceof PhiNode : currentField; - currentField = ((PhiNode) currentField).valueAt(0); - } - } while (currentField != null); + for (int i = 0; i < vobj.fieldsCount(); i++) { + values[i] = toCiValue(currentField.fields().get(i)); + } } } } diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Thu Jun 14 17:10:49 2012 +0200 @@ -381,7 +381,7 @@ lastState = fs; } - List nodes = lir.nodesFor(block); + List nodes = lir.nodesFor(block); for (int i = 0; i < nodes.size(); i++) { Node instr = nodes.get(i); diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragment.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragment.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragment.java Thu Jun 14 17:10:49 2012 +0200 @@ -30,7 +30,6 @@ import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.PhiNode.PhiType; -import com.oracle.graal.nodes.util.*; public abstract class LoopFragment { @@ -245,14 +244,8 @@ PhiNode phi = graph.add(vpn.type() == PhiType.Value ? new PhiNode(vpn.kind(), merge) : new PhiNode(vpn.type(), merge)); phi.addInput(vpn); phi.addInput(newVpn); - if (vpn.type() == PhiType.Value) { - replaceWith = phi; - } else { - assert vpn.type() == PhiType.Virtual; - ValueNode vof = GraphUtil.unProxify(vpn); - ValueNode newVof = GraphUtil.unProxify(newVpn); - replaceWith = GraphUtil.mergeVirtualChain(graph, vof, newVof, phi, earlyExit, newEarlyExit, merge); - } + assert vpn.type() == PhiType.Value; + replaceWith = phi; } else { replaceWith = vpn.value(); } diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java Thu Jun 14 17:10:49 2012 +0200 @@ -246,9 +246,6 @@ if (duplicateState != null) { duplicateState.replaceFirstInput(phi, firstPhi); // fix the merge's state after } - if (phi.type() == PhiType.Virtual) { - initializer = GraphUtil.mergeVirtualChain(graph, firstPhi, newExitMerge); - } mergedInitializers.put(phi, initializer); } } diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java Thu Jun 14 17:10:49 2012 +0200 @@ -110,7 +110,7 @@ assert boxNode.objectStamp().isExactType(); virtualizeUsages(boxNode, boxNode.source(), boxNode.objectStamp().type()); - if (boxNode.usages().filter(isNotA(FrameState.class).nor(VirtualObjectFieldNode.class)).isNotEmpty()) { + if (boxNode.usages().filter(isNotA(VirtualState.class)).isNotEmpty()) { // Elimination failed, because boxing object escapes. return; } @@ -125,7 +125,7 @@ private static void virtualizeUsages(ValueNode boxNode, ValueNode replacement, ResolvedJavaType exactType) { ValueNode virtualValueNode = null; VirtualObjectNode virtualObjectNode = null; - for (Node n : boxNode.usages().filter(NodePredicates.isA(FrameState.class).or(VirtualObjectFieldNode.class)).snapshot()) { + for (Node n : boxNode.usages().filter(NodePredicates.isA(VirtualState.class)).snapshot()) { if (virtualValueNode == null) { virtualObjectNode = n.graph().unique(new BoxedVirtualObjectNode(exactType, replacement)); } diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Thu Jun 14 17:10:49 2012 +0200 @@ -24,7 +24,6 @@ import java.util.*; -import com.oracle.max.criutils.*; import com.oracle.graal.api.code.*; import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.graph.*; @@ -38,38 +37,34 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.virtual.*; +import com.oracle.max.criutils.*; public class EscapeAnalysisPhase extends Phase { + /** + * Encapsulates the state of the virtual object, which is updated while traversing the control flow graph. + */ public static class BlockExitState implements MergeableState { public final ValueNode[] fieldState; public final VirtualObjectNode virtualObject; - public ValueNode virtualObjectField; public final Graph graph; public BlockExitState(EscapeField[] fields, VirtualObjectNode virtualObject) { this.fieldState = new ValueNode[fields.length]; this.virtualObject = virtualObject; - this.virtualObjectField = null; this.graph = virtualObject.graph(); for (int i = 0; i < fields.length; i++) { fieldState[i] = ConstantNode.defaultForKind(fields[i].type().kind(), virtualObject.graph()); - virtualObjectField = graph.add(new VirtualObjectFieldNode(virtualObject, virtualObjectField, fieldState[i], i)); } } public BlockExitState(BlockExitState state) { this.fieldState = state.fieldState.clone(); this.virtualObject = state.virtualObject; - this.virtualObjectField = state.virtualObjectField; this.graph = state.graph; } - public void updateField(int fieldIndex) { - virtualObjectField = graph.add(new VirtualObjectFieldNode(virtualObject, virtualObjectField, fieldState[fieldIndex], fieldIndex)); - } - @Override public BlockExitState clone() { return new BlockExitState(this); @@ -77,14 +72,8 @@ @Override public boolean merge(MergeNode merge, List withStates) { - PhiNode vobjPhi = null; PhiNode[] valuePhis = new PhiNode[fieldState.length]; for (BlockExitState other : withStates) { - if (virtualObjectField != other.virtualObjectField && vobjPhi == null) { - vobjPhi = graph.add(new PhiNode(PhiType.Virtual, merge)); - vobjPhi.addInput(virtualObjectField); - virtualObjectField = vobjPhi; - } for (int i2 = 0; i2 < fieldState.length; i2++) { if (fieldState[i2] != other.fieldState[i2] && valuePhis[i2] == null) { valuePhis[i2] = graph.add(new PhiNode(fieldState[i2].kind(), merge)); @@ -94,51 +83,27 @@ } } for (BlockExitState other : withStates) { - if (vobjPhi != null) { - vobjPhi.addInput(other.virtualObjectField); - } for (int i2 = 0; i2 < fieldState.length; i2++) { if (valuePhis[i2] != null) { valuePhis[i2].addInput(other.fieldState[i2]); } } } - assert vobjPhi == null || vobjPhi.valueCount() == withStates.size() + 1; - for (int i2 = 0; i2 < fieldState.length; i2++) { - if (valuePhis[i2] != null) { - virtualObjectField = graph.add(new VirtualObjectFieldNode(virtualObject, virtualObjectField, valuePhis[i2], i2)); - assert valuePhis[i2].valueCount() == withStates.size() + 1; - } - } return true; } @Override public void loopBegin(LoopBeginNode loopBegin) { - assert virtualObjectField != null : "unexpected null virtualObjectField"; - PhiNode vobjPhi = null; - vobjPhi = graph.add(new PhiNode(PhiType.Virtual, loopBegin)); - vobjPhi.addInput(virtualObjectField); - virtualObjectField = vobjPhi; for (int i2 = 0; i2 < fieldState.length; i2++) { PhiNode valuePhi = graph.add(new PhiNode(fieldState[i2].kind(), loopBegin)); valuePhi.addInput(fieldState[i2]); fieldState[i2] = valuePhi; - updateField(i2); } } @Override public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { - while (!loopBegin.isPhiAtMerge(virtualObjectField)) { - if (virtualObjectField instanceof PhiNode) { - virtualObjectField = ((PhiNode) virtualObjectField).valueAt(0); - } else { - virtualObjectField = ((VirtualObjectFieldNode) virtualObjectField).lastState(); - } - } for (BlockExitState loopEndState : loopEndStates) { - ((PhiNode) virtualObjectField).addInput(loopEndState.virtualObjectField); for (int i2 = 0; i2 < fieldState.length; i2++) { ((PhiNode) fieldState[i2]).addInput(loopEndState.fieldState[i2]); } @@ -175,6 +140,12 @@ } } + private void process() { + for (Node usage : node.usages().snapshot()) { + op.beforeUpdate(node, usage); + } + } + public void removeAllocation() { escapeFields = op.fields(node); for (int i = 0; i < escapeFields.length; i++) { @@ -202,42 +173,21 @@ final PostOrderNodeIterator iterator = new PostOrderNodeIterator(next, startState) { @Override protected void node(FixedNode curNode) { - int changedField = op.updateState(virtual, curNode, fields, state.fieldState); - if (changedField != -1) { - state.updateField(changedField); - } + op.updateState(virtual, curNode, fields, state.fieldState); if (curNode instanceof LoopExitNode) { - state.virtualObjectField = graph.unique(new ValueProxyNode(state.virtualObjectField, (LoopExitNode) curNode, PhiType.Virtual)); for (int i = 0; i < state.fieldState.length; i++) { state.fieldState[i] = graph.unique(new ValueProxyNode(state.fieldState[i], (LoopExitNode) curNode, PhiType.Value)); } } if (!curNode.isDeleted() && curNode instanceof StateSplit && ((StateSplit) curNode).stateAfter() != null) { - if (state.virtualObjectField != null) { - ValueNode v = state.virtualObjectField; - if (curNode instanceof LoopBeginNode) { - while (!((LoopBeginNode) curNode).isPhiAtMerge(v)) { - if (v instanceof PhiNode) { - v = ((PhiNode) v).valueAt(0); - } else { - v = ((VirtualObjectFieldNode) v).lastState(); - } - } - } - ((StateSplit) curNode).stateAfter().addVirtualObjectMapping(v); - } + VirtualObjectState v = graph.add(new VirtualObjectState(virtual, state.fieldState)); + ((StateSplit) curNode).stateAfter().addVirtualObjectMapping(v); } } }; iterator.apply(); } } - - private void process() { - for (Node usage : node.usages().snapshot()) { - op.beforeUpdate(node, usage); - } - } } private final TargetDescription target; @@ -278,7 +228,7 @@ private static Node escape(EscapeRecord record, Node usage) { final Node node = record.node; - if (usage instanceof FrameState) { + if (usage instanceof VirtualState) { assert usage.inputs().contains(node); return null; } else { @@ -318,8 +268,6 @@ // in order to not escape, the access needs to have a valid constant index and either a store into node or be self-referencing return EscapeOp.isValidConstantIndex(x) && x.value() != node ? null : x.array(); } - } else if (usage instanceof VirtualObjectFieldNode) { - return null; } else if (usage instanceof RegisterFinalizerNode) { assert ((RegisterFinalizerNode) usage).object() == node; return null; @@ -467,7 +415,7 @@ for (Node usage : node.usages().snapshot()) { boolean escapes = op.escape(node, usage); if (escapes) { - if (usage instanceof FrameState) { + if (usage instanceof VirtualState) { // nothing to do... } else if (usage instanceof MethodCallTargetNode) { if (usage.usages().size() == 0) { diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java Thu Jun 14 17:10:49 2012 +0200 @@ -49,7 +49,7 @@ protected void run(StructuredGraph graph) { for (ReturnNode ret : graph.getNodes(ReturnNode.class)) { PlaceholderNode p = graph.add(new PlaceholderNode()); - p.setStateAfter(graph.add(new FrameState(null, FrameState.AFTER_BCI, 0, 0, false, false))); + p.setStateAfter(graph.add(new FrameState(FrameState.AFTER_BCI))); graph.addBeforeFixed(ret, p); } } diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java Thu Jun 14 17:10:49 2012 +0200 @@ -41,7 +41,7 @@ /** * Map from blocks to the nodes in each block. */ - private BlockMap> blockToNodesMap; + private BlockMap> blockToNodesMap; public SchedulePhase() { super("Schedule"); @@ -57,17 +57,20 @@ sortNodesWithinBlocks(graph); } + /** + * Sets {@link ScheduledNode#scheduledNext} on all scheduled nodes in all blocks using the scheduling built by @link {@link #run(StructuredGraph)}. + * This method should thus only be called when run has been successfully executed. + */ public void scheduleGraph() { + assert blockToNodesMap != null : "cannot set scheduledNext before run has been executed"; for (Block block : cfg.getBlocks()) { - List nodeList = blockToNodesMap.get(block); + List nodeList = blockToNodesMap.get(block); ScheduledNode last = null; - for (Node node : nodeList) { - if (!(node instanceof FrameState)) { - if (last != null) { - last.setScheduledNext((ScheduledNode) node); - } - last = (ScheduledNode) node; + for (ScheduledNode node : nodeList) { + if (last != null) { + last.setScheduledNext(node); } + last = node; } } } @@ -79,79 +82,86 @@ /** * Gets the map from each block to the nodes in the block. */ - public BlockMap> getBlockToNodesMap() { + public BlockMap> getBlockToNodesMap() { return blockToNodesMap; } /** * Gets the nodes in a given block. */ - public List nodesFor(Block block) { + public List nodesFor(Block block) { return blockToNodesMap.get(block); } private void assignBlockToNodes(StructuredGraph graph) { for (Block block : cfg.getBlocks()) { - List nodes = new ArrayList<>(); + List nodes = new ArrayList<>(); assert blockToNodesMap.get(block) == null; blockToNodesMap.put(block, nodes); - for (Node node : block.getNodes()) { + for (FixedNode node : block.getNodes()) { nodes.add(node); } } for (Node n : graph.getNodes()) { - assignBlockToNode(n); + if (n instanceof ScheduledNode) { + assignBlockToNode((ScheduledNode) n); + } } } - private void assignBlockToNode(Node n) { - if (n == null) { - return; - } + /** + * Assigns a block to the given node. This method expects that PhiNodes and FixedNodes are already assigned to a + * block, since they should already have been placed by {@link ControlFlowGraph#identifyBlocks()}. + * This method will also try to + */ + private void assignBlockToNode(ScheduledNode node) { + assert !node.isDeleted(); - assert !n.isDeleted(); - - Block prevBlock = cfg.getNodeToBlock().get(n); + Block prevBlock = cfg.getNodeToBlock().get(node); if (prevBlock != null) { return; } - assert !(n instanceof PhiNode) : n; - assert !(n instanceof MergeNode); + // PhiNodes and FixedNodes should already have been placed in blocks by ControlFlowGraph.identifyBlocks + assert !(node instanceof PhiNode) : node; + assert !(node instanceof FixedNode) : node; // if in CFG, schedule at the latest position possible in the outermost loop possible - Block latestBlock = latestBlock(n); + Block latestBlock = latestBlock(node); Block block; if (latestBlock == null) { - block = earliestBlock(n); - } else if (GraalOptions.ScheduleOutOfLoops && !(n instanceof VirtualObjectFieldNode) && !(n instanceof VirtualObjectNode)) { - Block earliestBlock = earliestBlock(n); - block = scheduleOutOfLoops(n, latestBlock, earliestBlock); - assert earliestBlock.dominates(block) : "Graph can not be scheduled : inconsistent for " + n; + block = earliestBlock(node); + } else if (GraalOptions.ScheduleOutOfLoops && !(node instanceof VirtualObjectNode)) { + Block earliestBlock = earliestBlock(node); + block = scheduleOutOfLoops(node, latestBlock, earliestBlock); + assert earliestBlock.dominates(block) : "Graph can not be scheduled : inconsistent for " + node + " (" + earliestBlock + " needs to dominate " + block + ")"; } else { block = latestBlock; } - cfg.getNodeToBlock().set(n, block); - blockToNodesMap.get(block).add(n); + cfg.getNodeToBlock().set(node, block); + blockToNodesMap.get(block).add(node); } - private Block latestBlock(Node n) { - Block block = null; - for (Node succ : n.successors()) { - if (succ == null) { - continue; - } - assignBlockToNode(succ); - block = getCommonDominator(block, cfg.getNodeToBlock().get(succ)); + /** + * Calculates the last block that the given node could be scheduled in, i.e., the common dominator of all usages. + * To do so all usages are also assigned to blocks. + */ + private Block latestBlock(ScheduledNode node) { + CommonDominatorBlockClosure cdbc = new CommonDominatorBlockClosure(null); + for (Node succ : node.successors().nonNull()) { + assert cfg.getNodeToBlock().get(succ) != null; + cdbc.apply(cfg.getNodeToBlock().get(succ)); } - ensureScheduledUsages(n); - CommonDominatorBlockClosure cdbc = new CommonDominatorBlockClosure(block); - for (Node usage : n.usages()) { - blocksForUsage(n, usage, cdbc); + ensureScheduledUsages(node); + for (Node usage : node.usages()) { + blocksForUsage(node, usage, cdbc); } return cdbc.block; } - private class CommonDominatorBlockClosure implements BlockClosure { + /** + * A closure that will calculate the common dominator of all blocks passed to its {@link #apply(Block)} method. + */ + private static class CommonDominatorBlockClosure implements BlockClosure { public Block block; public CommonDominatorBlockClosure(Block block) { this.block = block; @@ -162,42 +172,45 @@ } } - private Block earliestBlock(Node n) { - Block earliest = cfg.getNodeToBlock().get(n); + /** + * Determines the earliest block in which the given node can be scheduled. + */ + private Block earliestBlock(Node node) { + Block earliest = cfg.getNodeToBlock().get(node); if (earliest != null) { return earliest; } - earliest = earliestCache.get(n); + earliest = earliestCache.get(node); if (earliest != null) { return earliest; } - BitSet bits = new BitSet(cfg.getBlocks().length); - ArrayList before = new ArrayList<>(); - if (n.predecessor() != null) { - before.add(n.predecessor()); - } - for (Node input : n.inputs()) { - before.add(input); - } - for (Node pred : before) { - if (pred == null) { - continue; - } - Block b = earliestBlock(pred); - if (!bits.get(b.getId())) { - earliest = b; + /* + * All inputs must be in a dominating block, otherwise the graph cannot be scheduled. This implies that the + * inputs' blocks have a total ordering via their dominance relation. So in order to find the earliest block + * placement for this node we need to find the input block that is dominated by all other input blocks. + * + * While iterating over the inputs a set of dominator blocks of the current earliest placement is maintained. + * When the block of an input is not within this set, it becomes the current earliest placement and the list of + * dominator blocks is updated. + */ + BitSet dominators = new BitSet(cfg.getBlocks().length); + + assert node.predecessor() == null; + for (Node input : node.inputs().nonNull()) { + assert input instanceof ValueNode; + Block inputEarliest = earliestBlock(input); + if (!dominators.get(inputEarliest.getId())) { + earliest = inputEarliest; do { - bits.set(b.getId()); - b = b.getDominator(); - } while(b != null && !bits.get(b.getId())); + dominators.set(inputEarliest.getId()); + inputEarliest = inputEarliest.getDominator(); + } while(inputEarliest != null && !dominators.get(inputEarliest.getId())); } } if (earliest == null) { - Block start = cfg.getNodeToBlock().get(((StructuredGraph) n.graph()).start()); - assert start != null; - return start; + earliest = cfg.getStartBlock(); } - earliestCache.set(n, earliest); + earliestCache.set(node, earliest); return earliest; } @@ -216,8 +229,20 @@ return result; } - private void blocksForUsage(Node node, Node usage, BlockClosure closure) { + /** + * Passes all blocks that a specific usage of a node is in to a given closure. + * This is more complex than just taking the usage's block because of of PhiNodes and FrameStates. + * + * @param node the node that needs to be scheduled + * @param usage the usage whose blocks need to be considered + * @param closure the closure that will be called for each block + */ + private void blocksForUsage(ScheduledNode node, Node usage, BlockClosure closure) { + assert !(node instanceof PhiNode); + if (usage instanceof PhiNode) { + // An input to a PhiNode is used at the end of the predecessor block that corresponds to the PhiNode input. + // One PhiNode can use an input multiple times, the closure will be called for each usage. PhiNode phi = (PhiNode) usage; MergeNode merge = phi.merge(); Block mergeBlock = cfg.getNodeToBlock().get(merge); @@ -235,22 +260,38 @@ closure.apply(mergeBlock.getPredecessors().get(i)); } } - } else if (usage instanceof FrameState && ((FrameState) usage).block() != null) { - MergeNode merge = ((FrameState) usage).block(); - Block block = null; - for (Node pred : merge.cfgPredecessors()) { - block = getCommonDominator(block, cfg.getNodeToBlock().get(pred)); + } else if (usage instanceof VirtualState) { + // The following logic does not work if node is a PhiNode, but this method is never called for PhiNodes. + for (Node unscheduledUsage : usage.usages()) { + if (unscheduledUsage instanceof VirtualState) { + // If a FrameState is an outer FrameState this method behaves as if the inner FrameState was the actual usage, by recursing. + blocksForUsage(node, unscheduledUsage, closure); + } else if (unscheduledUsage instanceof MergeNode) { + // Only FrameStates can be connected to MergeNodes. + assert usage instanceof FrameState; + // If a FrameState belongs to a MergeNode then it's inputs will be placed at the common dominator of all EndNodes. + for (Node pred : unscheduledUsage.cfgPredecessors()) { + closure.apply(cfg.getNodeToBlock().get(pred)); + } + } else { + // For the time being, only FrameStates can be connected to StateSplits. + assert usage instanceof FrameState; + assert unscheduledUsage instanceof StateSplit; + // Otherwise: Put the input into the same block as the usage. + assignBlockToNode((ScheduledNode) unscheduledUsage); + closure.apply(cfg.getNodeToBlock().get(unscheduledUsage)); + } } - closure.apply(block); } else { - assignBlockToNode(usage); + // All other types of usages: Put the input into the same block as the usage. + assignBlockToNode((ScheduledNode) usage); closure.apply(cfg.getNodeToBlock().get(usage)); } } private void ensureScheduledUsages(Node node) { - for (Node usage : node.usages().snapshot()) { - assignBlockToNode(usage); + for (Node usage : node.usages().filter(ScheduledNode.class)) { + assignBlockToNode((ScheduledNode) usage); } // now true usages are ready } @@ -266,21 +307,25 @@ } private void sortNodesWithinBlocks(StructuredGraph graph) { - NodeBitMap map = graph.createNodeBitMap(); + NodeBitMap visited = graph.createNodeBitMap(); for (Block b : cfg.getBlocks()) { - sortNodesWithinBlocks(b, map); + sortNodesWithinBlock(b, visited); } } - private void sortNodesWithinBlocks(Block b, NodeBitMap map) { - List instructions = blockToNodesMap.get(b); - List sortedInstructions = new ArrayList<>(instructions.size() + 2); + /** + * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over all inputs. + * This means that a node is added to the list after all its inputs have been processed. + */ + private void sortNodesWithinBlock(Block b, NodeBitMap visited) { + List instructions = blockToNodesMap.get(b); + List sortedInstructions = new ArrayList<>(instructions.size() + 2); - assert !map.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b; - assert !map.isMarked(b.getEndNode()) && cfg.blockFor(b.getEndNode()) == b; + assert !visited.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b; + assert !visited.isMarked(b.getEndNode()) && cfg.blockFor(b.getEndNode()) == b; - for (Node i : instructions) { - addToSorting(b, i, sortedInstructions, map); + for (ScheduledNode i : instructions) { + addToSorting(b, i, sortedInstructions, visited); } // Make sure that last node gets really last (i.e. when a frame state successor hangs off it). @@ -310,32 +355,45 @@ blockToNodesMap.put(b, sortedInstructions); } - private void addToSorting(Block b, Node i, List sortedInstructions, NodeBitMap map) { - if (i == null || map.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) { + private void addUnscheduledToSorting(Block b, VirtualState state, List sortedInstructions, NodeBitMap visited) { + if (state != null) { + // UnscheduledNodes should never be marked as visited. + assert !visited.isMarked(state); + + for (Node input : state.inputs()) { + if (input instanceof VirtualState) { + addUnscheduledToSorting(b, (VirtualState) input, sortedInstructions, visited); + } else { + addToSorting(b, (ScheduledNode) input, sortedInstructions, visited); + } + } + } + } + + private void addToSorting(Block b, ScheduledNode i, List sortedInstructions, NodeBitMap visited) { + if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) { return; } FrameState state = null; - WriteNode writeNode = null; + WriteNode write = null; for (Node input : i.inputs()) { - if (input instanceof WriteNode && !map.isMarked(input) && cfg.getNodeToBlock().get(input) == b) { - writeNode = (WriteNode) input; + if (input instanceof WriteNode && !visited.isMarked(input) && cfg.getNodeToBlock().get(input) == b) { + assert write == null; + write = (WriteNode) input; } else if (input instanceof FrameState) { + assert state == null; state = (FrameState) input; } else { - addToSorting(b, input, sortedInstructions, map); + addToSorting(b, (ScheduledNode) input, sortedInstructions, visited); } } - if (i.predecessor() != null) { - addToSorting(b, i.predecessor(), sortedInstructions, map); - } - - map.mark(i); - - addToSorting(b, state, sortedInstructions, map); - assert writeNode == null || !map.isMarked(writeNode); - addToSorting(b, writeNode, sortedInstructions, map); + addToSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited); + visited.mark(i); + addUnscheduledToSorting(b, state, sortedInstructions, visited); + assert write == null || !visited.isMarked(write); + addToSorting(b, write, sortedInstructions, visited); // Now predecessors and inputs are scheduled => we can add this node. sortedInstructions.add(i); diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java Thu Jun 14 17:10:49 2012 +0200 @@ -55,6 +55,7 @@ this.nodes = new Node[elements.length]; for (int i = 0; i < elements.length; i++) { this.nodes[i] = elements[i]; + assert this.nodes[i] == null || !this.nodes[i].isDeleted(); } } } @@ -70,6 +71,7 @@ this.nodes = new Node[elements.size()]; for (int i = 0; i < elements.size(); i++) { this.nodes[i] = elements.get(i); + assert this.nodes[i] == null || !this.nodes[i].isDeleted(); } } } diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Thu Jun 14 17:10:49 2012 +0200 @@ -112,8 +112,9 @@ @Override public void run() { VMToCompilerImpl.this.intrinsifyArrayCopy = new IntrinsifyArrayCopyPhase(runtime); - GraalIntrinsics.installIntrinsics(runtime, runtime.getCompiler().getTarget()); - runtime.installSnippets(); + SnippetInstaller installer = new SnippetInstaller(runtime, runtime.getCompiler().getTarget()); + GraalIntrinsics.installIntrinsics(installer); + runtime.installSnippets(installer); } }); diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Thu Jun 14 17:10:49 2012 +0200 @@ -68,12 +68,12 @@ System.setProperty(Backend.BACKEND_CLASS_PROPERTY, HotSpotAMD64Backend.class.getName()); } - public void installSnippets() { - Snippets.install(this, compiler.getTarget(), new SystemSnippets()); - Snippets.install(this, compiler.getTarget(), new UnsafeSnippets()); - Snippets.install(this, compiler.getTarget(), new ArrayCopySnippets()); - Snippets.install(this, compiler.getTarget(), new CheckCastSnippets()); - Snippets.install(this, compiler.getTarget(), new NewInstanceSnippets()); + public void installSnippets(SnippetInstaller installer) { + installer.install(SystemSnippets.class); + installer.install(UnsafeSnippets.class); + installer.install(ArrayCopySnippets.class); + installer.install(CheckCastSnippets.class); + installer.install(NewInstanceSnippets.class); checkcastSnippets = new CheckCastSnippets.Templates(this); newInstanceSnippets = new NewInstanceSnippets.Templates(this); } diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewInstanceSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewInstanceSnippets.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewInstanceSnippets.java Thu Jun 14 17:10:49 2012 +0200 @@ -55,16 +55,18 @@ */ public class NewInstanceSnippets implements SnippetsInterface { + private static final boolean LOG_ALLOCATION = Boolean.getBoolean("graal.traceAllocation"); + /** * Type test used when the type being tested against is a final type. */ @Snippet - public static Object newInstance(@Parameter("hub") Object hub, @ConstantParameter("size") int size, @ConstantParameter("checkInit") boolean checkInit) { + public static Object newInstance(@Parameter("hub") Object hub, @ConstantParameter("size") int size, @ConstantParameter("checkInit") boolean checkInit, @ConstantParameter("logType") String logType) { if (checkInit) { int klassState = load(hub, 0, klassStateOffset(), Kind.Int); if (klassState != klassStateFullyInitialized()) { Object instance = NewInstanceStubCall.call(hub); - return formatInstance(hub, size, instance); + return formatInstance(hub, size, instance, logType); } } @@ -80,7 +82,7 @@ instance = NewInstanceStubCall.call(hub); } - return formatInstance(hub, size, instance); + return formatInstance(hub, size, instance, logType); } private static Word asWord(Object object) { @@ -94,7 +96,7 @@ /** * Formats the header of a created instance and zeroes out its body. */ - private static Object formatInstance(Object hub, int size, Object instance) { + private static Object formatInstance(Object hub, int size, Object instance, String logType) { Word headerPrototype = cast(load(hub, 0, instanceHeaderPrototypeOffset(), wordKind()), Word.class); store(instance, 0, 0, headerPrototype); store(instance, 0, hubOffset(), hub); @@ -102,6 +104,12 @@ for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { store(instance, 0, offset, 0); } + if (logType != null) { + Log.print("allocated instance of "); + Log.print(logType); + Log.print(" at "); + Log.printlnAddress(instance); + } return instance; } @@ -155,7 +163,7 @@ this.runtime = runtime; this.cache = new Cache(runtime); try { - newInstance = runtime.getResolvedJavaMethod(NewInstanceSnippets.class.getDeclaredMethod("newInstance", Object.class, int.class, boolean.class)); + newInstance = runtime.getResolvedJavaMethod(NewInstanceSnippets.class.getDeclaredMethod("newInstance", Object.class, int.class, boolean.class, String.class)); } catch (NoSuchMethodException e) { throw new GraalInternalError(e); } @@ -170,7 +178,7 @@ HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) newInstanceNode.instanceClass(); HotSpotKlassOop hub = type.klassOop(); int instanceSize = type.instanceSize(); - Key key = new Key(newInstance).add("size", instanceSize).add("checkInit", !type.isInitialized()); + Key key = new Key(newInstance).add("size", instanceSize).add("checkInit", !type.isInitialized()).add("logType", LOG_ALLOCATION ? type.name() : null); Arguments arguments = arguments("hub", hub); SnippetTemplate template = cache.get(key); Debug.log("Lowering newInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, arguments); diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Thu Jun 14 17:10:49 2012 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; /** * This class implements the overall container for the LIR graph @@ -42,7 +43,7 @@ * The nodes for the blocks. * TODO: This should go away, we want all nodes connected with a next-pointer. */ - private final BlockMap> blockToNodesMap; + private final BlockMap> blockToNodesMap; /** * The linear-scan ordered list of blocks. @@ -87,7 +88,7 @@ * @param numLoops number of loops * @param compilation the compilation */ - public LIR(ControlFlowGraph cfg, BlockMap> blockToNodesMap, List linearScanOrder, List codeEmittingOrder) { + public LIR(ControlFlowGraph cfg, BlockMap> blockToNodesMap, List linearScanOrder, List codeEmittingOrder) { this.cfg = cfg; this.blockToNodesMap = blockToNodesMap; this.codeEmittingOrder = codeEmittingOrder; @@ -99,7 +100,7 @@ /** * Gets the nodes in a given block. */ - public List nodesFor(Block block) { + public List nodesFor(Block block) { return blockToNodesMap.get(block); } diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java Thu Jun 14 17:10:49 2012 +0200 @@ -24,7 +24,6 @@ import java.util.*; -import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; @@ -33,7 +32,7 @@ protected int id; protected BeginNode beginNode; - protected Node endNode; + protected FixedNode endNode; protected Loop loop; protected double probability; @@ -62,7 +61,7 @@ return beginNode; } - public Node getEndNode() { + public FixedNode getEndNode() { return endNode; } @@ -122,8 +121,8 @@ return postdominator; } - private class NodeIterator implements Iterator { - private Node cur; + private class NodeIterator implements Iterator { + private FixedNode cur; public NodeIterator() { cur = getBeginNode(); @@ -135,8 +134,8 @@ } @Override - public Node next() { - Node result = cur; + public FixedNode next() { + FixedNode result = cur; if (cur == getEndNode()) { cur = null; } else { @@ -152,10 +151,10 @@ } } - public Iterable getNodes() { - return new Iterable() { + public Iterable getNodes() { + return new Iterable() { @Override - public Iterator iterator() { + public Iterator iterator() { return new NodeIterator(); } }; diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java Thu Jun 14 17:10:49 2012 +0200 @@ -118,9 +118,9 @@ block.beginNode = (BeginNode) node; Node cur = node; + Node last; do { assert !cur.isDeleted(); - block.endNode = cur; assert nodeToBlock.get(cur) == null; nodeToBlock.set(cur, block); @@ -137,15 +137,11 @@ } } - Node next = null; - for (Node sux : cur.successors()) { - if (sux != null && !(sux instanceof BeginNode)) { - assert next == null; - next = sux; - } - } - cur = next; - } while (cur != null); + last = cur; + cur = cur.successors().first(); + } while (cur != null && !(cur instanceof BeginNode)); + + block.endNode = (FixedNode) last; } } diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java Thu Jun 14 17:10:49 2012 +0200 @@ -28,6 +28,7 @@ import com.oracle.graal.nodes.type.*; public abstract class CallTargetNode extends ValueNode implements LIRLowerable { + @Input protected final NodeInputList arguments; public CallTargetNode(ValueNode[] arguments) { @@ -45,6 +46,6 @@ @Override public void generate(LIRGeneratorTool gen) { - //nop + // nop } } diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Thu Jun 14 17:10:49 2012 +0200 @@ -35,7 +35,7 @@ * The {@code FrameState} class encapsulates the frame state (i.e. local variables and * operand stack) at a particular point in the abstract interpretation. */ -public final class FrameState extends Node implements Node.IterableNodeType, LIRLowerable { +public final class FrameState extends VirtualState implements Node.IterableNodeType, LIRLowerable { protected final int localsSize; @@ -74,11 +74,10 @@ @Input private final NodeInputList values; - @Input private final NodeInputList virtualObjectMappings; + @Input private final NodeInputList virtualObjectMappings; /** - * The bytecode index to which this frame state applies. This will be {@code -1} - * iff this state is mutable. + * The bytecode index to which this frame state applies. */ public final int bci; @@ -93,19 +92,28 @@ * @param stackSize size of the stack * @param rethrowException if true the VM should re-throw the exception on top of the stack when deopt'ing using this framestate */ - public FrameState(ResolvedJavaMethod method, int bci, int localsSize, int stackSize, boolean rethrowException, boolean duringCall) { + public FrameState(ResolvedJavaMethod method, int bci, List values, int stackSize, boolean rethrowException, boolean duringCall, List virtualObjectMappings) { assert stackSize >= 0; + assert (bci >= 0 && method != null) || (bci < 0 && method == null && values.isEmpty()); this.method = method; this.bci = bci; - this.localsSize = localsSize; + this.localsSize = values.size() - stackSize; this.stackSize = stackSize; - this.values = new NodeInputList<>(this, localsSize + stackSize); - this.virtualObjectMappings = new NodeInputList<>(this); + this.values = new NodeInputList<>(this, values); + this.virtualObjectMappings = new NodeInputList<>(this, virtualObjectMappings); this.rethrowException = rethrowException; this.duringCall = duringCall; assert !rethrowException || stackSize == 1 : "must have exception on top of the stack"; } + /** + * Simple constructor used to create marker FrameStates. + * @param bci marker bci, needs to be < 0 + */ + public FrameState(int bci) { + this(null, bci, Collections.emptyList(), 0, false, false, Collections.emptyList()); + } + public FrameState(ResolvedJavaMethod method, int bci, ValueNode[] locals, ValueNode[] stack, int stackSize, boolean rethrowException, boolean duringCall) { this.method = method; this.bci = bci; @@ -140,10 +148,6 @@ this.outerFrameState = x; } - private void setValueAt(int i, ValueNode x) { - values.set(i, x); - } - public boolean rethrowException() { return rethrowException; } @@ -160,8 +164,7 @@ return method; } - public void addVirtualObjectMapping(Node virtualObject) { - assert virtualObject instanceof VirtualObjectFieldNode || virtualObject instanceof PhiNode || virtualObject instanceof ValueProxyNode : virtualObject; + public void addVirtualObjectMapping(VirtualObjectState virtualObject) { virtualObjectMappings.add(virtualObject); } @@ -173,7 +176,7 @@ return virtualObjectMappings.get(i); } - public Iterable virtualObjectMappings() { + public Iterable virtualObjectMappings() { return virtualObjectMappings; } @@ -192,9 +195,7 @@ } public FrameState duplicate(int newBci, boolean duplicateOuter) { - FrameState other = graph().add(new FrameState(method, newBci, localsSize, stackSize, rethrowException, duringCall)); - other.values.setAll(values); - other.virtualObjectMappings.setAll(virtualObjectMappings); + FrameState other = graph().add(new FrameState(method, newBci, values, stackSize, rethrowException, duringCall, virtualObjectMappings)); FrameState newOuterFrameState = outerFrameState(); if (duplicateOuter && newOuterFrameState != null) { newOuterFrameState = newOuterFrameState.duplicate(newOuterFrameState.bci, duplicateOuter); @@ -209,30 +210,18 @@ * or double is followed by a null slot. */ public FrameState duplicateModified(int newBci, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) { - int popSlots = 0; + ArrayList copy = new ArrayList<>(values); if (popKind != Kind.Void) { if (stackAt(stackSize() - 1) == null) { - popSlots = 2; - } else { - popSlots = 1; + copy.remove(copy.size() - 1); } - assert stackAt(stackSize() - popSlots).kind().stackKind() == popKind.stackKind() || (stackAt(stackSize() - popSlots) instanceof BoxedVirtualObjectNode && popKind.isObject()); + ValueNode lastSlot = copy.get(copy.size() - 1); + assert lastSlot.kind().stackKind() == popKind.stackKind() || (lastSlot instanceof BoxedVirtualObjectNode && popKind.isObject()); + copy.remove(copy.size() - 1); } + Collections.addAll(copy, pushedValues); - int pushSlots = pushedValues.length; - FrameState other = graph().add(new FrameState(method, newBci, localsSize, stackSize - popSlots + pushSlots, newRethrowException, false)); - for (int i = 0; i < localsSize; i++) { - other.setValueAt(i, localAt(i)); - } - for (int i = 0; i < stackSize - popSlots; i++) { - other.setValueAt(localsSize + i, stackAt(i)); - } - int slot = localsSize + stackSize - popSlots; - for (int i = 0; i < pushSlots; i++) { - assert pushedValues[i] == null || !pushedValues[i].kind().isVoid(); - other.setValueAt(slot++, pushedValues[i]); - } - other.virtualObjectMappings.setAll(virtualObjectMappings); + FrameState other = graph().add(new FrameState(method, newBci, copy, copy.size() - localsSize, newRethrowException, false, virtualObjectMappings)); other.setOuterFrameState(outerFrameState()); return other; } diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Thu Jun 14 17:10:49 2012 +0200 @@ -36,8 +36,7 @@ public static enum PhiType { Value(null), // normal value phis - Memory(StampFactory.dependency()), // memory phis - Virtual(StampFactory.virtual()); // phis used for VirtualObjectField merges + Memory(StampFactory.dependency()); public final Stamp stamp; diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java Thu Jun 14 17:10:49 2012 +0200 @@ -26,7 +26,7 @@ import com.oracle.graal.graph.*; -public class ScheduledNode extends Node { +public abstract class ScheduledNode extends Node { @Successor private ScheduledNode scheduledNext; // the immediate successor of the current node diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java Thu Jun 14 17:10:49 2012 +0200 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes; + +import com.oracle.graal.graph.*; + +/** + * Base class for nodes that contain "virtual" state, like FrameState and VirtualObjectState. + * Subclasses of this class will be treated in a special way by the scheduler. + */ +public abstract class VirtualState extends Node { + +} diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Thu Jun 14 17:10:49 2012 +0200 @@ -34,11 +34,10 @@ /** * The ValueAnchor instruction keeps non-CFG (floating) nodes above a certain point in the graph. */ - public final class ValueAnchorNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType { public ValueAnchorNode(ValueNode... values) { - super(StampFactory.dependency(), values); + super(StampFactory.forVoid(), values); } @Override @@ -53,6 +52,12 @@ } @Override + public boolean verify() { + assertTrue(usages().isEmpty(), "upwards dependencies should target BeginNodes only"); + return super.verify(); + } + + @Override public ValueNode canonical(CanonicalizerTool tool) { if (this.predecessor() instanceof ValueAnchorNode) { // transfer values and remove diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java Thu Jun 14 17:10:49 2012 +0200 @@ -29,8 +29,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.virtual.*; - public abstract class EscapeOp { @@ -43,7 +41,7 @@ } else if (usage instanceof IsTypeNode) { assert ((IsTypeNode) usage).objectClass() == node; return false; - } else if (usage instanceof FrameState) { + } else if (usage instanceof VirtualState) { assert usage.inputs().contains(node); return true; } else if (usage instanceof AccessMonitorNode) { @@ -73,8 +71,6 @@ // in order to not escape the access needs to have a valid constant index and either a store into node or self-referencing return !isValidConstantIndex(x) || x.value() == node && x.array() != node; } - } else if (usage instanceof VirtualObjectFieldNode) { - return false; } else if (usage instanceof RegisterFinalizerNode) { assert ((RegisterFinalizerNode) usage).object() == node; return false; @@ -112,8 +108,8 @@ ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(false, node.graph())); } else if (usage instanceof IsTypeNode) { IsTypeNode x = (IsTypeNode) usage; - assert x.type() == ((ValueNode) node).objectStamp().type(); - ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(true, node.graph())); + boolean result = ((ValueNode) node).objectStamp().type() == x.type(); + ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(result, node.graph())); } else if (usage instanceof AccessMonitorNode) { ((AccessMonitorNode) usage).eliminate(); } diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Thu Jun 14 17:10:49 2012 +0200 @@ -31,14 +31,12 @@ import com.oracle.graal.graph.iterators.*; import com.oracle.graal.graph.iterators.NodePredicates.PositiveTypePredicate; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.virtual.*; public class GraphUtil { - private static final PositiveTypePredicate FLOATING = isA(FloatingNode.class).or(CallTargetNode.class).or(FrameState.class).or(VirtualObjectFieldNode.class).or(VirtualObjectNode.class); + private static final PositiveTypePredicate FLOATING = isA(FloatingNode.class).or(VirtualState.class).or(CallTargetNode.class); public static void killCFG(FixedNode node) { assert node.isAlive(); @@ -61,30 +59,32 @@ private static void killEnd(EndNode end) { MergeNode merge = end.merge(); - merge.removeEnd(end); - StructuredGraph graph = (StructuredGraph) end.graph(); - if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) { //dead loop - for (PhiNode phi : merge.phis().snapshot()) { - propagateKill(phi); - } - LoopBeginNode begin = (LoopBeginNode) merge; - // disconnect and delete loop ends & loop exits - for (LoopEndNode loopend : begin.loopEnds().snapshot()) { - loopend.predecessor().replaceFirstSuccessor(loopend, null); - loopend.safeDelete(); + if (merge != null) { + merge.removeEnd(end); + StructuredGraph graph = (StructuredGraph) end.graph(); + if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) { //dead loop + for (PhiNode phi : merge.phis().snapshot()) { + propagateKill(phi); + } + LoopBeginNode begin = (LoopBeginNode) merge; + // disconnect and delete loop ends & loop exits + for (LoopEndNode loopend : begin.loopEnds().snapshot()) { + loopend.predecessor().replaceFirstSuccessor(loopend, null); + loopend.safeDelete(); + } + for (LoopExitNode loopexit : begin.loopExits().snapshot()) { + for (ValueProxyNode vpn : loopexit.proxies().snapshot()) { + graph.replaceFloating(vpn, vpn.value()); + } + graph.replaceFixedWithFixed(loopexit, graph.add(new BeginNode())); + } + killCFG(begin.next()); + begin.safeDelete(); + } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { // not a loop anymore + graph.reduceDegenerateLoopBegin((LoopBeginNode) merge); + } else if (merge.phiPredecessorCount() == 1) { // not a merge anymore + graph.reduceTrivialMerge(merge); } - for (LoopExitNode loopexit : begin.loopExits().snapshot()) { - for (ValueProxyNode vpn : loopexit.proxies().snapshot()) { - graph.replaceFloating(vpn, vpn.value()); - } - graph.replaceFixedWithFixed(loopexit, graph.add(new BeginNode())); - } - killCFG(begin.next()); - begin.safeDelete(); - } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { // not a loop anymore - graph.reduceDegenerateLoopBegin((LoopBeginNode) merge); - } else if (merge.phiPredecessorCount() == 1) { // not a merge anymore - graph.reduceTrivialMerge(merge); } } @@ -219,144 +219,4 @@ } return v; } - - private static ValueProxyNode findProxy(ValueNode value, BeginNode proxyPoint) { - for (ValueProxyNode vpn : proxyPoint.proxies()) { - ValueNode v = vpn; - while (v instanceof ValueProxyNode) { - v = ((ValueProxyNode) v).value(); - if (v == value) { - return vpn; - } - } - } - return null; - } - - public static ValueNode mergeVirtualChain( - StructuredGraph graph, - ValueNode vof, - ValueNode newVof, - PhiNode vPhi, - BeginNode earlyExit, - BeginNode newEarlyExit, - MergeNode merge) { - VirtualObjectNode vObject = virtualObject(vof); - assert virtualObject(newVof) == vObject; - ValueNode[] virtualState = virtualState(vof); - ValueNode[] newVirtualState = virtualState(newVof); - ValueNode chain = vPhi; - for (int i = 0; i < virtualState.length; i++) { - ValueNode value = virtualState[i]; - ValueNode newValue = newVirtualState[i]; - assert value.kind() == newValue.kind(); - if (value != newValue) { - PhiNode valuePhi = graph.add(new PhiNode(value.kind(), merge)); - ValueProxyNode inputProxy = findProxy(value, earlyExit); - if (inputProxy != null) { - ValueProxyNode newInputProxy = findProxy(newValue, newEarlyExit); - assert newInputProxy != null : "no proxy for " + newValue + " at " + newEarlyExit; - valuePhi.addInput(inputProxy); - valuePhi.addInput(newInputProxy); - } else { - valuePhi.addInput(graph.unique(new ValueProxyNode(value, earlyExit, PhiType.Value))); - valuePhi.addInput(newValue); - } - chain = graph.add(new VirtualObjectFieldNode(vObject, chain, valuePhi, i)); - } - } - return chain; - } - - public static ValueNode mergeVirtualChain( - StructuredGraph graph, - PhiNode vPhi, - MergeNode merge) { - NodeInputList virtuals = vPhi.values(); - VirtualObjectNode vObject = virtualObject(unProxify(virtuals.first())); - List virtualStates = new ArrayList<>(virtuals.size()); - for (ValueNode virtual : virtuals) { - virtualStates.add(virtualState(unProxify(virtual))); - } - ValueNode chain = vPhi; - int stateLength = virtualStates.get(0).length; - for (int i = 0; i < stateLength; i++) { - ValueNode v = null; - boolean reconcile = false; - for (ValueNode[] state : virtualStates) { - if (v == null) { - v = state[i]; - } else if (v != state[i]) { - reconcile = true; - break; - } - assert v.kind() == state[i].kind(); - } - if (reconcile) { - PhiNode valuePhi = graph.add(new PhiNode(v.kind(), merge)); - for (ValueNode[] state : virtualStates) { - valuePhi.addInput(state[i]); - } - chain = graph.add(new VirtualObjectFieldNode(vObject, chain, valuePhi, i)); - } - } - return chain; - } - - /** - * Returns the VirtualObjectNode associated with the virtual chain of the provided virtual node. - * @param vof a virtual ValueNode (a VirtualObjectFieldNode or a Virtual Phi) - * @return the VirtualObjectNode associated with the virtual chain of the provided virtual node. - */ - public static VirtualObjectNode virtualObject(ValueNode vof) { - assert vof instanceof VirtualObjectFieldNode || (vof instanceof PhiNode && ((PhiNode) vof).type() == PhiType.Virtual) : vof; - ValueNode currentField = vof; - do { - if (currentField instanceof VirtualObjectFieldNode) { - return ((VirtualObjectFieldNode) currentField).object(); - } else { - assert currentField instanceof PhiNode && ((PhiNode) currentField).type() == PhiType.Virtual : currentField; - currentField = ((PhiNode) currentField).valueAt(0); - } - } while (currentField != null); - throw new GraalInternalError("Invalid virtual chain : cound not find virtual object from %s", vof); - } - - /** - * Builds the state of the virtual object at the provided point into a virtual chain. - * @param vof a virtual ValueNode (a VirtualObjectFieldNode or a Virtual Phi) - * @return the state of the virtual object at the provided point into a virtual chain. - */ - public static ValueNode[] virtualState(ValueNode vof) { - return virtualState(vof, virtualObject(vof)); - } - - /** - * Builds the state of the virtual object at the provided point into a virtual chain. - * @param vof a virtual ValueNode (a VirtualObjectFieldNode or a Virtual Phi) - * @param vObj the virtual object - * @return the state of the virtual object at the provided point into a virtual chain. - */ - public static ValueNode[] virtualState(ValueNode vof, VirtualObjectNode vObj) { - int fieldsCount = vObj.fieldsCount(); - int dicovered = 0; - ValueNode[] state = new ValueNode[fieldsCount]; - ValueNode currentField = vof; - do { - if (currentField instanceof VirtualObjectFieldNode) { - int index = ((VirtualObjectFieldNode) currentField).index(); - if (state[index] == null) { - dicovered++; - state[index] = ((VirtualObjectFieldNode) currentField).input(); - } - currentField = ((VirtualObjectFieldNode) currentField).lastState(); - } else if (currentField instanceof ValueProxyNode) { - currentField = ((ValueProxyNode) currentField).value(); - } else { - assert currentField instanceof PhiNode && ((PhiNode) currentField).type() == PhiType.Virtual : currentField; - currentField = ((PhiNode) currentField).valueAt(0); - } - } while (currentField != null && dicovered < fieldsCount); - return state; - } } diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectFieldNode.java Thu Jun 14 17:10:17 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* - * 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.graal.nodes.virtual; - -import java.util.*; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class VirtualObjectFieldNode extends ValueNode implements LIRLowerable { - - @Input private VirtualObjectNode object; - @Input private ValueNode lastState; - @Input private ValueNode input; - - private int index; - - public VirtualObjectNode object() { - return object; - } - - public ValueNode lastState() { - return lastState; - } - - public ValueNode input() { - return input; - } - - public VirtualObjectFieldNode(VirtualObjectNode object, ValueNode lastState, ValueNode input, int index) { - super(StampFactory.virtual()); - this.index = index; - this.object = object; - this.lastState = lastState; - this.input = input; - } - - public int index() { - return index; - } - - @Override - public void generate(LIRGeneratorTool gen) { - // nothing to do... - } - - @Override - public boolean verify() { - assertTrue(object != null, "No object"); - assertTrue(input != null, "No input"); - return super.verify(); - } - - @Override - public Map getDebugProperties() { - Map properties = super.getDebugProperties(); - properties.put("index", index); - return properties; - } - - @Override - public String toString(Verbosity verbosity) { - if (verbosity == Verbosity.Name && object() != null && object().fields() != null) { - return super.toString(Verbosity.Name) + " " + object().fields()[index].name(); - } else { - return super.toString(verbosity); - } - } -} diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Thu Jun 14 17:10:49 2012 +0200 @@ -23,12 +23,11 @@ package com.oracle.graal.nodes.virtual; import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; - -public class VirtualObjectNode extends ValueNode implements LIRLowerable { +public class VirtualObjectNode extends FloatingNode implements LIRLowerable { private ResolvedJavaType type; private EscapeField[] fields; diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java Thu Jun 14 17:10:49 2012 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, 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.virtual; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; + +/** + * This class encapsulated the virtual state of an escape analyzed object. + */ +public final class VirtualObjectState extends VirtualState implements Node.IterableNodeType, LIRLowerable { + + @Input private VirtualObjectNode object; + @Input private NodeInputList fields; + + public VirtualObjectNode object() { + return object; + } + + public NodeInputList fields() { + return fields; + } + + public VirtualObjectState(VirtualObjectNode object, ValueNode[] fields) { + this.object = object; + assert object.fields().length == fields.length; + this.fields = new NodeInputList<>(this, fields); + } + + @Override + public void generate(LIRGeneratorTool generator) { + // Nothing to do, virtual object states are processed as part of the handling of StateSplit nodes. + } +} diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/GraalIntrinsics.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/GraalIntrinsics.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/GraalIntrinsics.java Thu Jun 14 17:10:49 2012 +0200 @@ -22,20 +22,18 @@ */ package com.oracle.graal.snippets; -import com.oracle.graal.api.code.*; import com.oracle.graal.compiler.*; -import com.oracle.graal.cri.*; /** * Definition of the snippets that are VM-independent and can be intrinsified by Graal in any VM. */ public class GraalIntrinsics { - public static void installIntrinsics(ExtendedRiRuntime runtime, TargetDescription target) { + public static void installIntrinsics(SnippetInstaller installer) { if (GraalOptions.Intrinsify) { - Snippets.install(runtime, target, new MathSnippetsX86()); - Snippets.install(runtime, target, new DoubleSnippets()); - Snippets.install(runtime, target, new FloatSnippets()); - Snippets.install(runtime, target, new NodeClassSnippets()); + installer.install(MathSnippetsX86.class); + installer.install(DoubleSnippets.class); + installer.install(FloatSnippets.class); + installer.install(NodeClassSnippets.class); } } } diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Thu Jun 14 17:10:49 2012 +0200 @@ -0,0 +1,195 @@ +/* + * 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.graal.snippets; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.phases.*; +import com.oracle.graal.compiler.util.*; +import com.oracle.graal.cri.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.snippets.Snippet.InliningPolicy; + +/** + * Utility for snippet {@linkplain #install(Class) installation}. + */ +public class SnippetInstaller { + + private final ExtendedRiRuntime runtime; + private final TargetDescription target; + private final BoxingMethodPool pool; + + /** + * A graph cache used by this installer to avoid using the compiler + * storage for each method processed during snippet installation. + * Without this, all processed methods are to be determined as + * {@linkplain IntrinsificationPhase#canIntrinsify intrinsifiable}. + */ + private final Map graphCache; + + public SnippetInstaller(ExtendedRiRuntime runtime, TargetDescription target) { + this.runtime = runtime; + this.target = target; + this.pool = new BoxingMethodPool(runtime); + this.graphCache = new HashMap<>(); + } + + /** + * Finds all the snippet methods in a given class, builds a graph for them and + * installs the graph with the key value of {@code Graph.class} in the + * {@linkplain ResolvedJavaMethod#compilerStorage() compiler storage} of each method. + *

+ * If {@code snippetsHolder} is annotated with {@link ClassSubstitution}, then all + * methods in the class are snippets. Otherwise, the snippets are those methods + * annotated with {@link Snippet}. + */ + public void install(Class snippetsHolder) { + if (snippetsHolder.isAnnotationPresent(ClassSubstitution.class)) { + installSubstitutions(snippetsHolder, snippetsHolder.getAnnotation(ClassSubstitution.class).value()); + } else { + installSnippets(snippetsHolder); + } + } + + private void installSnippets(Class< ? extends SnippetsInterface> clazz) { + for (Method method : clazz.getDeclaredMethods()) { + if (method.getAnnotation(Snippet.class) != null) { + int modifiers = method.getModifiers(); + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + throw new RuntimeException("Snippet must not be abstract or native"); + } + ResolvedJavaMethod snippet = runtime.getResolvedJavaMethod(method); + assert snippet.compilerStorage().get(Graph.class) == null; + StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); + //System.out.println("snippet: " + graph); + snippet.compilerStorage().put(Graph.class, graph); + } + } + } + + private void installSubstitutions(Class< ? extends SnippetsInterface> clazz, Class originalClazz) { + for (Method method : clazz.getDeclaredMethods()) { + try { + Method originalMethod = originalClazz.getDeclaredMethod(method.getName(), method.getParameterTypes()); + if (!originalMethod.getReturnType().isAssignableFrom(method.getReturnType())) { + throw new RuntimeException("Snippet has incompatible return type"); + } + int modifiers = method.getModifiers(); + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + throw new RuntimeException("Snippet must not be abstract or native"); + } + ResolvedJavaMethod snippet = runtime.getResolvedJavaMethod(method); + StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); + //System.out.println("snippet: " + graph); + runtime.getResolvedJavaMethod(originalMethod).compilerStorage().put(Graph.class, graph); + } catch (NoSuchMethodException e) { + throw new GraalInternalError("Could not resolve method in " + originalClazz + " to substitute with " + method, e); + } + } + } + + private static InliningPolicy inliningPolicy(ResolvedJavaMethod method) { + Class policyClass = InliningPolicy.class; + Snippet snippet = method.getAnnotation(Snippet.class); + if (snippet != null) { + policyClass = snippet.inlining(); + } + if (policyClass == InliningPolicy.class) { + return InliningPolicy.Default; + } + try { + return policyClass.getConstructor().newInstance(); + } catch (Exception e) { + throw new GraalInternalError(e); + } + } + + private StructuredGraph makeGraph(final ResolvedJavaMethod method, final InliningPolicy policy) { + StructuredGraph graph = graphCache.get(method); + if (graph == null) { + graph = buildGraph(method, policy); + //System.out.println("built " + graph); + graphCache.put(method, graph); + } + return graph; + } + + private StructuredGraph buildGraph(final ResolvedJavaMethod method, final InliningPolicy policy) { + final StructuredGraph graph = new StructuredGraph(method); + return Debug.scope("BuildSnippetGraph", new Object[] {method, graph}, new Callable() { + @Override + public StructuredGraph call() throws Exception { + GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(); + GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); + graphBuilder.apply(graph); + + Debug.dump(graph, "%s: %s", method.name(), GraphBuilderPhase.class.getSimpleName()); + + new SnippetIntrinsificationPhase(runtime, pool).apply(graph); + + for (Invoke invoke : graph.getInvokes()) { + MethodCallTargetNode callTarget = invoke.callTarget(); + ResolvedJavaMethod callee = callTarget.targetMethod(); + if (policy.shouldInline(callee, method)) { + StructuredGraph targetGraph = makeGraph(callee, policy); + InliningUtil.inline(invoke, targetGraph, true); + Debug.dump(graph, "after inlining %s", callee); + if (GraalOptions.OptCanonicalizer) { + new WordTypeRewriterPhase(target).apply(graph); + new CanonicalizerPhase(target, runtime, null).apply(graph); + } + } + } + + new SnippetIntrinsificationPhase(runtime, pool).apply(graph); + + new WordTypeRewriterPhase(target).apply(graph); + + new DeadCodeEliminationPhase().apply(graph); + if (GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(target, runtime, null).apply(graph); + } + + for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { + end.disableSafepoint(); + } + + new InsertStateAfterPlaceholderPhase().apply(graph); + + Debug.dump(graph, "%s: Final", method.name()); + + return graph; + } + }); + } +} diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java Thu Jun 14 17:10:17 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,164 +0,0 @@ -/* - * 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.graal.snippets; - -import java.lang.reflect.*; -import java.util.concurrent.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.compiler.util.*; -import com.oracle.graal.cri.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.java.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.snippets.Snippet.InliningPolicy; - -/** - * Utilities for snippet installation and management. - */ -public class Snippets { - - public static void install(ExtendedRiRuntime runtime, TargetDescription target, SnippetsInterface obj) { - Class clazz = obj.getClass(); - BoxingMethodPool pool = new BoxingMethodPool(runtime); - if (clazz.isAnnotationPresent(ClassSubstitution.class)) { - installSubstitution(runtime, target, clazz, pool, clazz.getAnnotation(ClassSubstitution.class).value()); - } else { - installSnippets(runtime, target, clazz, pool); - } - } - - private static void installSnippets(ExtendedRiRuntime runtime, TargetDescription target, Class< ? extends SnippetsInterface> clazz, BoxingMethodPool pool) { - for (Method method : clazz.getDeclaredMethods()) { - if (method.getAnnotation(Snippet.class) != null) { - Method snippet = method; - int modifiers = snippet.getModifiers(); - if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { - throw new RuntimeException("Snippet must not be abstract or native"); - } - ResolvedJavaMethod snippetRiMethod = runtime.getResolvedJavaMethod(snippet); - if (snippetRiMethod.compilerStorage().get(Graph.class) == null) { - buildSnippetGraph(snippetRiMethod, runtime, target, pool, inliningPolicy(snippetRiMethod)); - } - } - } - } - - private static InliningPolicy inliningPolicy(ResolvedJavaMethod method) { - Class policyClass = InliningPolicy.class; - Snippet snippet = method.getAnnotation(Snippet.class); - if (snippet != null) { - policyClass = snippet.inlining(); - } - if (policyClass == InliningPolicy.class) { - return InliningPolicy.Default; - } - try { - return policyClass.getConstructor().newInstance(); - } catch (Exception e) { - throw new GraalInternalError(e); - } - } - - private static void installSubstitution(ExtendedRiRuntime runtime, TargetDescription target, Class< ? extends SnippetsInterface> clazz, - BoxingMethodPool pool, Class original) throws GraalInternalError { - for (Method snippet : clazz.getDeclaredMethods()) { - try { - Method method = original.getDeclaredMethod(snippet.getName(), snippet.getParameterTypes()); - if (!method.getReturnType().isAssignableFrom(snippet.getReturnType())) { - throw new RuntimeException("Snippet has incompatible return type"); - } - int modifiers = snippet.getModifiers(); - if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { - throw new RuntimeException("Snippet must not be abstract or native"); - } - ResolvedJavaMethod snippetRiMethod = runtime.getResolvedJavaMethod(snippet); - StructuredGraph graph = buildSnippetGraph(snippetRiMethod, runtime, target, pool, inliningPolicy(snippetRiMethod)); - runtime.getResolvedJavaMethod(method).compilerStorage().put(Graph.class, graph); - } catch (NoSuchMethodException e) { - throw new RuntimeException("Could not resolve method to substitute with: " + snippet.getName(), e); - } - } - } - - private static StructuredGraph buildSnippetGraph(final ResolvedJavaMethod snippetRiMethod, final ExtendedRiRuntime runtime, final TargetDescription target, final BoxingMethodPool pool, final InliningPolicy policy) { - final StructuredGraph graph = new StructuredGraph(snippetRiMethod); - return Debug.scope("BuildSnippetGraph", new Object[] {snippetRiMethod, graph}, new Callable() { - @Override - public StructuredGraph call() throws Exception { - GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(); - GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); - graphBuilder.apply(graph); - - Debug.dump(graph, "%s: %s", snippetRiMethod.name(), GraphBuilderPhase.class.getSimpleName()); - - new SnippetIntrinsificationPhase(runtime, pool).apply(graph); - - for (Invoke invoke : graph.getInvokes()) { - MethodCallTargetNode callTarget = invoke.callTarget(); - ResolvedJavaMethod method = callTarget.targetMethod(); - if (policy.shouldInline(method, snippetRiMethod)) { - StructuredGraph targetGraph = (StructuredGraph) method.compilerStorage().get(Graph.class); - if (targetGraph == null) { - targetGraph = buildSnippetGraph(method, runtime, target, pool, policy); - } - InliningUtil.inline(invoke, targetGraph, true); - Debug.dump(graph, "after inlining %s", method); - if (GraalOptions.OptCanonicalizer) { - new WordTypeRewriterPhase(target).apply(graph); - new CanonicalizerPhase(target, runtime, null).apply(graph); - } - } - } - - new SnippetIntrinsificationPhase(runtime, pool).apply(graph); - - new WordTypeRewriterPhase(target).apply(graph); - - new DeadCodeEliminationPhase().apply(graph); - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, null).apply(graph); - } - - for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { - end.disableSafepoint(); - } - - new InsertStateAfterPlaceholderPhase().apply(graph); - - Debug.dump(graph, "%s: Final", snippetRiMethod.name()); - - snippetRiMethod.compilerStorage().put(Graph.class, graph); - - return graph; - } - }); - - } -} diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphScheduleTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphScheduleTest.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphScheduleTest.java Thu Jun 14 17:10:49 2012 +0200 @@ -40,7 +40,7 @@ Block aBlock = nodeToBlock.get(a); if (bBlock == aBlock) { - List instructions = ibp.nodesFor(bBlock); + List instructions = ibp.nodesFor(bBlock); Assert.assertTrue(instructions.indexOf(b) > instructions.indexOf(a)); } else { Block block = bBlock; diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java Thu Jun 14 17:10:49 2012 +0200 @@ -160,17 +160,14 @@ } private void test(final String snippet, final String referenceSnippet) { - Debug.scope("ScalarTypeSystemTest", new DebugDumpScope(snippet), new Runnable() { - public void run() { - StructuredGraph graph = parse(snippet); - Debug.dump(graph, "Graph"); -// TypeSystemTest.outputGraph(graph); - new CanonicalizerPhase(null, runtime(), null).apply(graph); - new CheckCastEliminationPhase().apply(graph); - new CanonicalizerPhase(null, runtime(), null).apply(graph); - StructuredGraph referenceGraph = parse(referenceSnippet); - assertEquals(referenceGraph, graph); - } - }); + // No debug scope to reduce console noise for @Test(expected = ...) tests + StructuredGraph graph = parse(snippet); + Debug.dump(graph, "Graph"); +// TypeSystemTest.outputGraph(graph); + new CanonicalizerPhase(null, runtime(), null).apply(graph); + new CheckCastEliminationPhase().apply(graph); + new CanonicalizerPhase(null, runtime(), null).apply(graph); + StructuredGraph referenceGraph = parse(referenceSnippet); + assertEquals(referenceGraph, graph); } } diff -r a03ca01cfe62 -r cf630991cb1d graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/StraighteningTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/StraighteningTest.java Thu Jun 14 17:10:17 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/StraighteningTest.java Thu Jun 14 17:10:49 2012 +0200 @@ -85,14 +85,11 @@ } private void test(final String snippet) { - Debug.scope("StraighteningTest", new DebugDumpScope(snippet), new Runnable() { - public void run() { - StructuredGraph graph = parse(snippet); - Debug.dump(graph, "Graph"); - new CanonicalizerPhase(null, runtime(), null).apply(graph); - StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); - assertEquals(referenceGraph, graph); - } - }); + // No debug scope to reduce console noise for @Test(expected = ...) tests + StructuredGraph graph = parse(snippet); + Debug.dump(graph, "Graph"); + new CanonicalizerPhase(null, runtime(), null).apply(graph); + StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); + assertEquals(referenceGraph, graph); } } diff -r a03ca01cfe62 -r cf630991cb1d mx/commands.py --- a/mx/commands.py Thu Jun 14 17:10:17 2012 +0200 +++ b/mx/commands.py Thu Jun 14 17:10:49 2012 +0200 @@ -338,6 +338,11 @@ for line in lines: f.write(line) + # Install a copy of the disassembler library + try: + hsdis([], copyToDir=_vmLibDirInJdk(jdk)) + except SystemExit: + pass else: if not exists(jdk): mx.abort('The ' + build + ' VM has not been created - run \'mx clean; mx build ' + build + '\'') @@ -553,11 +558,12 @@ vm = _vm build = vmbuild if vmbuild is not None else _vmbuild if _vmSourcesAvailable else 'product' + jdk = _jdk(build) mx.expand_project_in_args(args) if _make_eclipse_launch: mx.make_eclipse_launch(args, 'graal-' + build, name=None, deps=mx.project('com.oracle.graal.hotspot').all_deps([], True)) if len([a for a in args if 'PrintAssembly' in a]) != 0: - hsdis([]) + hsdis([], copyToDir=_vmLibDirInJdk(jdk)) if mx.java().debug_port is not None: args = ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(mx.java().debug_port)] + args if _jacoco == 'on' or _jacoco == 'append': @@ -573,7 +579,7 @@ 'excludes' : ':'.join(excludes) } args = ['-javaagent:' + jacocoagent.get_path(True) + '=' + ','.join([k + '=' + v for k, v in agentOptions.items()])] + args - exe = join(_jdk(build), 'bin', mx.exe_suffix('java')) + exe = join(jdk, 'bin', mx.exe_suffix('java')) return mx.run([exe, '-' + vm] + args, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd, timeout=timeout) def _find_classes_with_annotations(classes, p, pkgRoot, annotations, includeInnerClasses=False): @@ -967,19 +973,20 @@ vm = _vm; sanitycheck.getSPECjvm2008(benchArgs, skipValid, wt, it).bench(vm, opts=vmArgs) -def hsdis(args): - """install the hsdis library +def hsdis(args, copyToDir=None): + """downloads the hsdis library This is needed to support HotSpot's assembly dumping features. - By default it installs the Intel syntax version, use the 'att' argument to install AT&T syntax.""" + By default it downloads the Intel syntax version, use the 'att' argument to install AT&T syntax.""" flavor = 'intel' if 'att' in args: flavor = 'att' - build = _vmbuild if _vmSourcesAvailable else 'product' lib = mx.lib_suffix('hsdis-amd64') - path = join(_vmLibDirInJdk(_jdk(build)), lib) + path = join(_graal_home, 'lib', lib) if not exists(path): mx.download(path, ['http://lafo.ssw.uni-linz.ac.at/hsdis/' + flavor + "/" + lib]) + if copyToDir is not None and exists(copyToDir): + shutil.copy(path, copyToDir) def hcfdis(args): """disassembles HexCodeFiles embedded in text files diff -r a03ca01cfe62 -r cf630991cb1d src/cpu/x86/vm/c1_Runtime1_x86.cpp --- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Jun 14 17:10:17 2012 +0200 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Jun 14 17:10:49 2012 +0200 @@ -1885,6 +1885,30 @@ break; } + case graal_log_primitive_id: { + __ enter(); + oop_maps = new OopMapSet(); + OopMap* oop_map = save_live_registers(sasm, 0); + int call_offset = __ call_RT(noreg, noreg, (address)graal_log_primitive, j_rarg0, j_rarg1, j_rarg2); + oop_maps->add_gc_map(call_offset, oop_map); + restore_live_registers(sasm); + __ leave(); + __ ret(0); + break; + } + + case graal_log_object_id: { + __ enter(); + oop_maps = new OopMapSet(); + OopMap* oop_map = save_live_registers(sasm, 0); + int call_offset = __ call_RT(noreg, noreg, (address)graal_log_object, j_rarg0, j_rarg1, j_rarg2); + oop_maps->add_gc_map(call_offset, oop_map); + restore_live_registers(sasm); + __ leave(); + __ ret(0); + break; + } + case graal_generic_callback_id: { __ enter(); oop_maps = new OopMapSet(); diff -r a03ca01cfe62 -r cf630991cb1d src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Thu Jun 14 17:10:17 2012 +0200 +++ b/src/share/vm/c1/c1_Runtime1.cpp Thu Jun 14 17:10:49 2012 +0200 @@ -212,8 +212,6 @@ case graal_arithmetic_frem_id: case graal_arithmetic_drem_id: case graal_set_deopt_info_id: - case graal_log_primitive_id: - case graal_log_object_id: #endif break; @@ -751,22 +749,29 @@ int length = java_lang_String::length(obj); if (length != 0) { + int printLength = MIN2(length, 1024); if (value == NULL) { // This can happen if, e.g., printing a String // object before its initializer has been called tty->print("null"); - } else if (length < 256 - 1) { + } else if (printLength < 256 - 1) { // Use an intermediate buffer to try and prevent interlacing of multi-threaded output char buf[256]; - for (int index = 0; index < length; index++) { + for (int index = 0; index < printLength; index++) { buf[index] = value->char_at(index + offset); } - buf[length] = 0; + buf[printLength] = 0; tty->print("%s", buf); + if (printLength < length) { + tty->print("... (%d more)", length - printLength); + } } else { - for (int index = 0; index < length; index++) { + for (int index = 0; index < printLength; index++) { tty->print("%c", value->char_at(index + offset)); } + if (printLength < length) { + tty->print("... (%d more)", length - printLength); + } } } }