# HG changeset patch # User Christian Wimmer # Date 1330970154 28800 # Node ID b115611115857eeedbffbec1f880628904a4a915 # Parent df0deec2af088763a8e03d634d7163d04edd862e Remove FrameStateAccess: Make FrameState immutable and move all modification logic into FrameStateBuilder diff -r df0deec2af08 -r b11561111585 graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/XirSite.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/XirSite.java Mon Mar 05 14:38:43 2012 +0100 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/XirSite.java Mon Mar 05 09:55:54 2012 -0800 @@ -22,8 +22,6 @@ */ package com.oracle.max.cri.xir; -import com.oracle.max.cri.ci.*; - /** * Encapsulates the notion of a site where XIR can be supplied. It is supplied to the {@link RiXirGenerator} by the * compiler for each place where XIR can be generated. This interface allows a number of queries, including the @@ -32,13 +30,6 @@ public interface XirSite { /** - * Gets the {@link CiCodePos code position} associated with this site. This is useful for inserting - * instrumentation at the XIR level. - * @return the code position if it is available; {@code null} otherwise - */ - CiCodePos getCodePos(); - - /** * Checks whether the specified argument is guaranteed to be non-null at this site. * @param argument the argument * @return {@code true} if the argument is non null at this site diff -r df0deec2af08 -r b11561111585 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Mon Mar 05 14:38:43 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Mon Mar 05 09:55:54 2012 -0800 @@ -186,6 +186,7 @@ public static boolean OptReorderLoops = true; public static boolean OptEliminateGuards = true; public static boolean OptImplicitNullChecks = true; + public static boolean OptLivenessAnalysis = false; /** * Flag to turn on SSA-based register allocation, which is currently under development. diff -r df0deec2af08 -r b11561111585 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/DebugInfoBuilder.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/DebugInfoBuilder.java Mon Mar 05 14:38:43 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/DebugInfoBuilder.java Mon Mar 05 09:55:54 2012 -0800 @@ -106,13 +106,16 @@ } private CiFrame computeFrameForState(FrameState state, LockScope locks) { + int numLocals = state.localsSize(); + int numStack = state.stackSize(); int numLocks = (locks != null && locks.callerState == state.outerFrameState()) ? locks.stateDepth + 1 : 0; - CiValue[] values = new CiValue[state.valuesSize() + numLocks]; - int valueIndex = 0; - - for (int i = 0; i < state.valuesSize(); i++) { - values[valueIndex++] = toCiValue(state.valueAt(i)); + CiValue[] values = new CiValue[numLocals + numStack + numLocks]; + for (int i = 0; i < numLocals; i++) { + values[i] = toCiValue(state.localAt(i)); + } + for (int i = 0; i < numStack; i++) { + values[numLocals + i] = toCiValue(state.stackAt(i)); } LockScope nextLock = locks; @@ -122,7 +125,7 @@ CiValue owner = toCiValue(nextLock.monitor.object()); CiValue lockData = nextLock.lockData; boolean eliminated = nextLock.monitor.eliminated(); - values[state.valuesSize() + nextLock.stateDepth] = new CiMonitorValue(owner, lockData, eliminated); + values[numLocals + numStack + nextLock.stateDepth] = new CiMonitorValue(owner, lockData, eliminated); nextLock = nextLock.outer; } diff -r df0deec2af08 -r b11561111585 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Mon Mar 05 14:38:43 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Mon Mar 05 09:55:54 2012 -0800 @@ -347,7 +347,7 @@ } else { TTY.println("STATE CHANGE (singlePred)"); if (GraalOptions.TraceLIRGeneratorLevel >= 3) { - TTY.println(fs.toDetailedString()); + TTY.println(fs.toString(Node.Verbosity.Debugger)); } } } @@ -400,7 +400,7 @@ if (GraalOptions.TraceLIRGeneratorLevel >= 2) { TTY.println("STATE CHANGE"); if (GraalOptions.TraceLIRGeneratorLevel >= 3) { - TTY.println(stateAfter.toDetailedString()); + TTY.println(stateAfter.toString(Node.Verbosity.Debugger)); } } } @@ -428,8 +428,7 @@ private boolean checkStateReady(FrameState state) { FrameState fs = state; while (fs != null) { - for (int i = 0; i < fs.valuesSize(); i++) { - ValueNode v = fs.valueAt(i); + for (ValueNode v : fs.values()) { if (v != null && !(v instanceof VirtualObjectNode)) { assert operand(v) != null : "Value " + v + " in " + fs + " is not ready!"; } @@ -1054,7 +1053,15 @@ FrameState stateAfter = x.stateAfter(); if (stateAfter != null) { // TODO change back to stateBeforeReturn() when RuntimeCallNode uses a CallTargetNode - FrameState stateBeforeReturn = stateAfter.duplicateModified(stateAfter.bci, stateAfter.rethrowException(), x.kind()); + // (cwi) I made the code that modifies the operand stack conditional. My scenario: runtime calls to, e.g., + // CreateNullPointerException have no equivalent in the bytecodes, so there is in invoke bytecode. + // Therefore, the result of the runtime call was never pushed to the stack, and we cannot pop it here. + FrameState stateBeforeReturn = stateAfter; + if ((stateAfter.stackSize() > 0 && stateAfter.stackAt(stateAfter.stackSize() - 1) == x) || + (stateAfter.stackSize() > 1 && stateAfter.stackAt(stateAfter.stackSize() - 2) == x)) { + + stateBeforeReturn = stateAfter.duplicateModified(stateAfter.bci, stateAfter.rethrowException(), x.kind()); + } // TODO is it correct here that the pointerSlots are not passed to the oop map generation? info = stateFor(stateBeforeReturn); @@ -1451,19 +1458,6 @@ ValueNode current; ValueNode receiver; - XirSupport() { - } - - public CiCodePos getCodePos() { - if (current instanceof StateSplit) { - FrameState stateAfter = ((StateSplit) current).stateAfter(); - if (stateAfter != null) { - return stateAfter.toCodePos(); - } - } - return null; - } - public boolean isNonNull(XirArgument argument) { return false; } diff -r df0deec2af08 -r b11561111585 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java Mon Mar 05 14:38:43 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java Mon Mar 05 09:55:54 2012 -0800 @@ -22,10 +22,24 @@ */ package com.oracle.max.graal.compiler.phases; +import com.oracle.max.graal.graph.*; import com.oracle.max.graal.nodes.*; +import com.oracle.max.graal.nodes.spi.*; +import com.oracle.max.graal.nodes.type.*; public class InsertStateAfterPlaceholderPhase extends Phase { + private static class PlaceholderNode extends AbstractStateSplit implements Node.IterableNodeType, LIRLowerable { + public PlaceholderNode() { + super(StampFactory.illegal()); + } + + @Override + public void generate(LIRGeneratorTool gen) { + // nothing to do + } + } + @Override protected void run(StructuredGraph graph) { for (ReturnNode ret : graph.getNodes(ReturnNode.class)) { diff -r df0deec2af08 -r b11561111585 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/Phase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/Phase.java Mon Mar 05 14:38:43 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/Phase.java Mon Mar 05 09:55:54 2012 -0800 @@ -55,6 +55,7 @@ if (dumpGraph) { Debug.dump(graph, "After phase %s", name); } + assert graph.verify(); } }); } diff -r df0deec2af08 -r b11561111585 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRuntime.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRuntime.java Mon Mar 05 14:38:43 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRuntime.java Mon Mar 05 09:55:54 2012 -0800 @@ -437,7 +437,7 @@ private CiTargetMethod createCallbackStub(RiResolvedMethod method, CiGenericCallback callback) { StructuredGraph graph = new StructuredGraph(); - FrameStateBuilder frameState = new FrameStateBuilder(method, method.maxLocals(), method.maxStackSize(), graph, false); + FrameStateBuilder frameState = new FrameStateBuilder(method, graph, false); ValueNode local0 = frameState.loadLocal(0); FrameState initialFrameState = frameState.create(0); diff -r df0deec2af08 -r b11561111585 graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java --- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java Mon Mar 05 14:38:43 2012 +0100 +++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java Mon Mar 05 09:55:54 2012 -0800 @@ -29,6 +29,8 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.debug.*; +import com.oracle.max.graal.graph.*; import com.oracle.max.graal.nodes.*; /** @@ -121,6 +123,7 @@ public int blockID; public FixedWithNextNode firstInstruction; + public FrameStateBuilder entryState; public ArrayList successors = new ArrayList<>(2); public int normalSuccessors; @@ -136,6 +139,11 @@ public Block retSuccessor; public boolean endsWithRet = false; + public BitMap localsLiveIn; + public BitMap localsLiveOut; + private BitMap localsLiveGen; + private BitMap localsLiveKill; + public Block copy() { try { Block block = (Block) super.clone(); @@ -182,6 +190,8 @@ public final RiResolvedMethod method; + private final BytecodeStream stream; + private final RiExceptionHandler[] exceptionHandlers; private Block[] blockMap; @@ -201,6 +211,7 @@ public BciBlockMapping(RiResolvedMethod method, boolean useBranchPrediction) { this.method = method; exceptionHandlers = method.exceptionHandlers(); + stream = new BytecodeStream(method.code()); this.blockMap = new Block[method.codeSize()]; this.canTrap = new BitSet(blockMap.length); this.blocks = new ArrayList<>(); @@ -232,6 +243,15 @@ // Discard big arrays so that they can be GCed blockMap = null; + + if (GraalOptions.OptLivenessAnalysis) { + Debug.scope("LivenessAnalysis", new Runnable() { + @Override + public void run() { + computeLiveness(); + } + }); + } } private void initializeBlockIds() { @@ -640,4 +660,187 @@ return loops; } + + + private void computeLiveness() { + for (Block block : blocks) { + computeLocalLiveness(block); + } + + boolean changed; + int iteration = 0; + do { + Debug.log("Iteration %d", iteration); + changed = false; + for (int i = blocks.size() - 1; i >= 0; i--) { + Block block = blocks.get(i); + Debug.log(" start B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.blockID, block.startBci, block.endBci, block.localsLiveIn, block.localsLiveOut, block.localsLiveGen, block.localsLiveKill); + + boolean blockChanged = (iteration == 0); + for (Block sux : block.successors) { + Debug.log(" Successor B%d: %s", sux.blockID, sux.localsLiveIn); + blockChanged = block.localsLiveOut.setUnionWithResult(sux.localsLiveIn) || blockChanged; + } + + if (blockChanged) { + block.localsLiveIn.setFrom(block.localsLiveOut); + block.localsLiveIn.setDifference(block.localsLiveKill); + block.localsLiveIn.setUnion(block.localsLiveGen); + + for (Block sux : block.successors) { + if (sux instanceof ExceptionBlock) { + // Exception handler blocks can be reached from anywhere within the block jumping to them, + // so we conservatively assume local variables require by the exception handler are live both + // at the beginning and end of the block. + blockChanged = block.localsLiveIn.setUnionWithResult(sux.localsLiveIn) || blockChanged; + } + } + Debug.log(" end B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.blockID, block.startBci, block.endBci, block.localsLiveIn, block.localsLiveOut, block.localsLiveGen, block.localsLiveKill); + } + changed |= blockChanged; + } + iteration++; + } while (changed); + } + + private void computeLocalLiveness(Block block) { + block.localsLiveIn = new BitMap(method.maxLocals()); + block.localsLiveOut = new BitMap(method.maxLocals()); + block.localsLiveGen = new BitMap(method.maxLocals()); + block.localsLiveKill = new BitMap(method.maxLocals()); + + if (block.startBci < 0 || block.endBci < 0) { + return; + } + + stream.setBCI(block.startBci); + while (stream.currentBCI() <= block.endBci) { + switch (stream.currentBC()) { + case RETURN: + if (method.isConstructor() && method.holder().superType() == null) { + // return from Object.init implicitly registers a finalizer + // for the receiver if needed, so keep it alive. + loadOne(block, 0); + } + break; + + case LLOAD: + case DLOAD: + loadTwo(block, stream.readLocalIndex()); + break; + case LLOAD_0: + case DLOAD_0: + loadTwo(block, 0); + break; + case LLOAD_1: + case DLOAD_1: + loadTwo(block, 1); + break; + case LLOAD_2: + case DLOAD_2: + loadTwo(block, 2); + break; + case LLOAD_3: + case DLOAD_3: + loadTwo(block, 3); + break; + case ILOAD: + case IINC: + case FLOAD: + case ALOAD: + case RET: + loadOne(block, stream.readLocalIndex()); + break; + case ILOAD_0: + case FLOAD_0: + case ALOAD_0: + loadOne(block, 0); + break; + case ILOAD_1: + case FLOAD_1: + case ALOAD_1: + loadOne(block, 1); + break; + case ILOAD_2: + case FLOAD_2: + case ALOAD_2: + loadOne(block, 2); + break; + case ILOAD_3: + case FLOAD_3: + case ALOAD_3: + loadOne(block, 3); + break; + + case LSTORE: + case DSTORE: + storeTwo(block, stream.readLocalIndex()); + break; + case LSTORE_0: + case DSTORE_0: + storeTwo(block, 0); + break; + case LSTORE_1: + case DSTORE_1: + storeTwo(block, 1); + break; + case LSTORE_2: + case DSTORE_2: + storeTwo(block, 2); + break; + case LSTORE_3: + case DSTORE_3: + storeTwo(block, 3); + break; + case ISTORE: + case FSTORE: + case ASTORE: + storeOne(block, stream.readLocalIndex()); + break; + case ISTORE_0: + case FSTORE_0: + case ASTORE_0: + storeOne(block, 0); + break; + case ISTORE_1: + case FSTORE_1: + case ASTORE_1: + storeOne(block, 1); + break; + case ISTORE_2: + case FSTORE_2: + case ASTORE_2: + storeOne(block, 2); + break; + case ISTORE_3: + case FSTORE_3: + case ASTORE_3: + storeOne(block, 3); + break; + } + stream.next(); + } + } + + private static void loadTwo(Block block, int local) { + loadOne(block, local); + loadOne(block, local + 1); + } + + private static void loadOne(Block block, int local) { + if (!block.localsLiveKill.get(local)) { + block.localsLiveGen.set(local); + } + } + + private static void storeTwo(Block block, int local) { + storeOne(block, local); + storeOne(block, local + 1); + } + + private static void storeOne(Block block, int local) { + if (!block.localsLiveGen.get(local)) { + block.localsLiveKill.set(local); + } + } } diff -r df0deec2af08 -r b11561111585 graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/FrameStateBuilder.java --- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/FrameStateBuilder.java Mon Mar 05 14:38:43 2012 +0100 +++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/FrameStateBuilder.java Mon Mar 05 09:55:54 2012 -0800 @@ -29,32 +29,29 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.graph.Node.Verbosity; +import com.oracle.max.graal.graph.iterators.*; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.PhiNode.PhiType; -import com.oracle.max.graal.nodes.spi.*; import com.oracle.max.graal.nodes.type.*; - -public class FrameStateBuilder implements FrameStateAccess { - +public class FrameStateBuilder { + private final RiResolvedMethod method; private final StructuredGraph graph; private final ValueNode[] locals; private final ValueNode[] stack; - - private int stackIndex; + private int stackSize; private boolean rethrowException; - private final RiResolvedMethod method; - - public FrameStateBuilder(RiResolvedMethod method, int maxLocals, int maxStackSize, StructuredGraph graph, boolean eagerResolve) { + public FrameStateBuilder(RiResolvedMethod method, StructuredGraph graph, boolean eagerResolve) { assert graph != null; this.method = method; this.graph = graph; - this.locals = new ValueNode[maxLocals]; + this.locals = new ValueNode[method.maxLocals()]; // we always need at least one stack slot (for exceptions) - int stackSize = Math.max(1, maxStackSize); - this.stack = new ValueNode[stackSize]; + this.stack = new ValueNode[Math.max(1, method.maxStackSize())]; int javaIndex = 0; int index = 0; @@ -88,33 +85,256 @@ } } - @Override - public String toString() { - return String.format("FrameStateBuilder[stackSize=%d]", stackIndex); + private FrameStateBuilder(RiResolvedMethod method, StructuredGraph graph, ValueNode[] locals, ValueNode[] stack, int stackSize, boolean rethrowException) { + assert locals.length == method.maxLocals(); + assert stack.length == Math.max(1, method.maxStackSize()); + + this.method = method; + this.graph = graph; + this.locals = locals; + this.stack = stack; + this.stackSize = stackSize; + this.rethrowException = rethrowException; } - public void initializeFrom(FrameState other) { - assert locals.length == other.localsSize() : "expected: " + locals.length + ", actual: " + other.localsSize(); - assert stack.length >= other.stackSize() : "expected: <=" + stack.length + ", actual: " + other.stackSize(); - - this.stackIndex = other.stackSize(); - for (int i = 0; i < other.localsSize(); i++) { - locals[i] = other.localAt(i); + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[locals: ["); + for (int i = 0; i < locals.length; i++) { + sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString(Verbosity.Id)); } - for (int i = 0; i < other.stackSize(); i++) { - stack[i] = other.stackAt(i); + sb.append("] stack: ["); + for (int i = 0; i < stackSize; i++) { + sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString(Verbosity.Id)); } - this.rethrowException = other.rethrowException(); + sb.append("]"); + if (rethrowException) { + sb.append(" rethrowException"); + } + sb.append("]"); + return sb.toString(); } public FrameState create(int bci) { - return graph.add(new FrameState(method, bci, locals, stack, stackIndex, rethrowException, false)); + return graph.add(new FrameState(method, bci, locals, stack, stackSize, rethrowException, false)); + } + + public FrameState duplicateWithoutStack(int bci) { + return graph.add(new FrameState(method, bci, locals, new ValueNode[0], 0, false, false)); + } + + + public FrameStateBuilder copy() { + return new FrameStateBuilder(method, graph, Arrays.copyOf(locals, locals.length), Arrays.copyOf(stack, stack.length), stackSize, rethrowException); + } + + public FrameStateBuilder copyWithException(ValueNode exceptionObject) { + ValueNode[] newStack = new ValueNode[stack.length]; + newStack[0] = exceptionObject; + return new FrameStateBuilder(method, graph, Arrays.copyOf(locals, locals.length), newStack, 1, true); + } + + + public boolean isCompatibleWith(FrameStateBuilder other) { + assert method == other.method && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method"; + + if (stackSize() != other.stackSize()) { + return false; + } + for (int i = 0; i < stackSize(); i++) { + ValueNode x = stackAt(i); + ValueNode y = other.stackAt(i); + if (x != y && ValueUtil.typeMismatch(x, y)) { + return false; + } + } + return true; + } + + public void merge(MergeNode block, FrameStateBuilder other) { + assert isCompatibleWith(other); + + for (int i = 0; i < localsSize(); i++) { + storeLocal(i, merge(localAt(i), other.localAt(i), block)); + } + for (int i = 0; i < stackSize(); i++) { + storeStack(i, merge(stackAt(i), other.stackAt(i), block)); + } + } + + private ValueNode merge(ValueNode currentValue, ValueNode otherValue, MergeNode block) { + if (currentValue == null) { + return null; + + } else if (block.isPhiAtMerge(currentValue)) { + if (otherValue == null || currentValue.kind() != otherValue.kind()) { + deletePhi(currentValue); + return null; + } + ((PhiNode) currentValue).addInput(otherValue); + return currentValue; + + } else if (currentValue != otherValue) { + assert !(block instanceof LoopBeginNode) : "Phi functions for loop headers are create eagerly for all locals and stack slots"; + if (otherValue == null || currentValue.kind() != otherValue.kind()) { + return null; + } + + PhiNode phi = graph.unique(new PhiNode(currentValue.kind(), block, PhiType.Value)); + for (int i = 0; i < block.phiPredecessorCount(); i++) { + phi.addInput(currentValue); + } + phi.addInput(otherValue); + assert phi.valueCount() == block.phiPredecessorCount() + 1 : "valueCount=" + phi.valueCount() + " predSize= " + block.phiPredecessorCount(); + return phi; + + } else { + return currentValue; + } + } + + private void deletePhi(Node phi) { + // Collect all phi functions that use this phi so that we can delete them recursively (after we delete ourselfs to avoid circles). + List phiUsages = phi.usages().filter(NodePredicates.isA(PhiNode.class)).snapshot(); + + // Remove the phi function from all FrameStates where it is used and then delete it. + assert phi.usages().filter(NodePredicates.isNotA(FrameState.class)).filter(NodePredicates.isNotA(PhiNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; + phi.replaceAtUsages(null); + phi.safeDelete(); + + for (Node phiUsage : phiUsages) { + deletePhi(phiUsage); + } + } + + public void insertLoopPhis(LoopBeginNode loopBegin) { + for (int i = 0; i < localsSize(); i++) { + storeLocal(i, createLoopPhi(loopBegin, localAt(i))); + } + for (int i = 0; i < stackSize(); i++) { + storeStack(i, createLoopPhi(loopBegin, stackAt(i))); + } } - public FrameState duplicateWithException(int bci, ValueNode exceptionObject) { - FrameState frameState = graph.add(new FrameState(method, bci, locals, new ValueNode[]{exceptionObject}, 1, true, false)); - frameState.setOuterFrameState(outerFrameState()); - return frameState; + private PhiNode createLoopPhi(MergeNode block, ValueNode value) { + if (value == null) { + return null; + } + assert !block.isPhiAtMerge(value) : "phi function for this block already created"; + + PhiNode phi = graph.unique(new PhiNode(value.kind(), block, PhiType.Value)); + phi.addInput(value); + return phi; + } + + public void cleanupDeletedPhis() { + for (int i = 0; i < localsSize(); i++) { + if (localAt(i) != null && localAt(i).isDeleted()) { + assert localAt(i) instanceof PhiNode : "Only phi functions can be deleted during parsing"; + storeLocal(i, null); + } + } + } + + public void clearNonLiveLocals(BitMap liveness) { + if (liveness == null) { + return; + } + assert liveness.size() == locals.length; + for (int i = 0; i < locals.length; i++) { + if (!liveness.get(i)) { + locals[i] = null; + } + } + } + + public boolean rethrowException() { + return rethrowException; + } + + public void setRethrowException(boolean b) { + rethrowException = b; + } + + + /** + * Returns the size of the local variables. + * + * @return the size of the local variables + */ + public int localsSize() { + return locals.length; + } + + /** + * Gets the current size (height) of the stack. + */ + public int stackSize() { + return stackSize; + } + + /** + * Gets the value in the local variables at the specified index, without any sanity checking. + * + * @param i the index into the locals + * @return the instruction that produced the value for the specified local + */ + protected final ValueNode localAt(int i) { + return locals[i]; + } + + /** + * Get the value on the stack at the specified stack index. + * + * @param i the index into the stack, with {@code 0} being the bottom of the stack + * @return the instruction at the specified position in the stack + */ + protected final ValueNode stackAt(int i) { + return stack[i]; + } + + /** + * Loads the local variable at the specified index, checking that the returned value is non-null + * and that two-stack values are properly handled. + * + * @param i the index of the local variable to load + * @return the instruction that produced the specified local + */ + public ValueNode loadLocal(int i) { + ValueNode x = locals[i]; + assert !x.isDeleted(); + assert !isTwoSlot(x.kind()) || locals[i + 1] == null; + assert i == 0 || locals[i - 1] == null || !isTwoSlot(locals[i - 1].kind()); + return x; + } + + /** + * Stores a given local variable at the specified index. If the value is a {@linkplain CiKind#isDoubleWord() double word}, + * then the next local variable index is also overwritten. + * + * @param i the index at which to store + * @param x the instruction which produces the value for the local + */ + public void storeLocal(int i, ValueNode x) { + assert x == null || x.kind() != CiKind.Void && x.kind() != CiKind.Illegal : "unexpected value: " + x; + locals[i] = x; + if (x != null && isTwoSlot(x.kind())) { + // if this is a double word, then kill i+1 + locals[i + 1] = null; + } + if (x != null && i > 0) { + ValueNode p = locals[i - 1]; + if (p != null && isTwoSlot(p.kind())) { + // if there was a double word at i - 1, then kill it + locals[i - 1] = null; + } + } + } + + private void storeStack(int i, ValueNode x) { + assert x == null || stack[i] == null || x.kind() == stack[i].kind() : "Method does not handle changes from one-slot to two-slot values"; + stack[i] = x; } /** @@ -123,7 +343,7 @@ * @param x the instruction to push onto the stack */ public void push(CiKind kind, ValueNode x) { - assert kind != CiKind.Void; + assert !x.isDeleted() && x.kind() != CiKind.Void && x.kind() != CiKind.Illegal; xpush(assertKind(kind, x)); if (isTwoSlot(kind)) { xpush(null); @@ -135,9 +355,8 @@ * @param x the instruction to push onto the stack */ public void xpush(ValueNode x) { - assert x == null || !x.isDeleted(); - assert x == null || (x.kind() != CiKind.Void && x.kind() != CiKind.Illegal) : "unexpected value: " + x; - stack[stackIndex++] = x; + assert x == null || (!x.isDeleted() && x.kind() != CiKind.Void && x.kind() != CiKind.Illegal); + stack[stackSize++] = x; } /** @@ -215,7 +434,7 @@ * @return x the instruction popped off the stack */ public ValueNode xpop() { - ValueNode result = stack[--stackIndex]; + ValueNode result = stack[--stackSize]; assert result == null || !result.isDeleted(); return result; } @@ -276,7 +495,7 @@ * @return an array containing the arguments off of the stack */ public ValueNode[] popArguments(int slotSize, int argSize) { - int base = stackIndex - slotSize; + int base = stackSize - slotSize; ValueNode[] r = new ValueNode[argSize]; int argIndex = 0; int stackindex = 0; @@ -286,7 +505,7 @@ r[argIndex++] = element; stackindex += stackSlots(element.kind()); } - stackIndex = base; + stackSize = base; return r; } @@ -309,173 +528,10 @@ } /** - * Truncates this stack to the specified size. - * @param size the size to truncate to - */ - public void truncateStack(int size) { - stackIndex = size; - assert stackIndex >= 0; - } - - /** * Clears all values on this stack. */ public void clearStack() { - stackIndex = 0; - } - - /** - * Loads the local variable at the specified index. - * - * @param i the index of the local variable to load - * @return the instruction that produced the specified local - */ - public ValueNode loadLocal(int i) { - ValueNode x = locals[i]; - if (x != null) { - if (x instanceof PhiNode) { - assert ((PhiNode) x).type() == PhiType.Value; - if (x.isDeleted()) { - return null; - } - } - assert !isTwoSlot(x.kind()) || locals[i + 1] == null || locals[i + 1] instanceof PhiNode; - } - return x; - } - - /** - * Stores a given local variable at the specified index. If the value is a {@linkplain CiKind#isDoubleWord() double word}, - * then the next local variable index is also overwritten. - * - * @param i the index at which to store - * @param x the instruction which produces the value for the local - */ - public void storeLocal(int i, ValueNode x) { - assert x.kind() != CiKind.Void && x.kind() != CiKind.Illegal : "unexpected value: " + x; - locals[i] = x; - if (isTwoSlot(x.kind())) { - // (tw) if this was a double word then kill i+1 - locals[i + 1] = null; - } - if (i > 0) { - // if there was a double word at i - 1, then kill it - ValueNode p = locals[i - 1]; - if (p != null && isTwoSlot(p.kind())) { - locals[i - 1] = null; - } - } - } - - /** - * Get the value on the stack at the specified stack index. - * - * @param i the index into the stack, with {@code 0} being the bottom of the stack - * @return the instruction at the specified position in the stack - */ - public final ValueNode stackAt(int i) { - return stack[i]; - } - - /** - * Gets the value in the local variables at the specified index. - * - * @param i the index into the locals - * @return the instruction that produced the value for the specified local - */ - public final ValueNode localAt(int i) { - return locals[i]; - } - - /** - * Returns the size of the local variables. - * - * @return the size of the local variables - */ - public int localsSize() { - return locals.length; - } - - /** - * Gets the current size (height) of the stack. - */ - public int stackSize() { - return stackIndex; - } - - public Iterator locals() { - return new ValueArrayIterator(locals); - } - - public Iterator stack() { - return new ValueArrayIterator(locals); - } - - - private static class ValueArrayIterator implements Iterator { - private final ValueNode[] array; - private int index; - - public ValueArrayIterator(ValueNode[] array, int length) { - assert length <= array.length; - this.array = array; - this.index = 0; - } - - public ValueArrayIterator(ValueNode[] array) { - this(array, array.length); - } - - @Override - public boolean hasNext() { - return index < array.length; - } - - @Override - public ValueNode next() { - return array[index++]; - } - - @Override - public void remove() { - throw new UnsupportedOperationException("cannot remove from array"); - } - - } - - - @Override - public FrameState duplicate(int bci) { - return create(bci); - } - - @Override - public ValueNode valueAt(int i) { - if (i < locals.length) { - return locals[i]; - } else { - return stack[i - locals.length]; - } - } - - @Override - public FrameState outerFrameState() { - return null; - } - - public FrameState duplicateWithoutStack(int bci) { - FrameState frameState = graph.add(new FrameState(method, bci, locals, new ValueNode[0], 0, false, false)); - frameState.setOuterFrameState(outerFrameState()); - return frameState; - } - - @Override - public boolean rethrowException() { - return rethrowException; - } - - public void setRethrowException(boolean b) { - rethrowException = b; + stackSize = 0; } public static int stackSlots(CiKind kind) { diff -r df0deec2af08 -r b11561111585 graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java Mon Mar 05 14:38:43 2012 +0100 +++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java Mon Mar 05 09:55:54 2012 -0800 @@ -47,7 +47,7 @@ import com.oracle.max.graal.nodes.extended.*; import com.oracle.max.graal.nodes.java.*; import com.oracle.max.graal.nodes.java.MethodCallTargetNode.InvokeKind; -import com.oracle.max.graal.nodes.spi.*; +import com.oracle.max.graal.nodes.type.*; /** * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph. @@ -80,30 +80,32 @@ private FrameStateBuilder frameState; // the current execution state private Block currentBlock; - private int nextBlockNumber; - private ValueNode methodSynchronizedObject; private ExceptionBlock unwindBlock; private Block returnBlock; - // the worklist of blocks, sorted by depth first number - private final PriorityQueue workList = new PriorityQueue<>(10, new Comparator() { - public int compare(Block o1, Block o2) { - return o1.blockID - o2.blockID; - } - }); - private FixedWithNextNode lastInstr; // the last instruction added - private Set blocksOnWorklist; - private Set blocksVisited; - private BitSet canTrapBitSet; public static final Map cachedGraphs = new WeakHashMap<>(); private final GraphBuilderConfiguration config; + + /** + * Node that marks the begin of block during bytecode parsing. When a block is identified the first + * time as a jump target, the placeholder is created and used as the successor for the jump. When the + * block is seen the second time, a MergeNode is created to correctly merge the now two different + * predecessor states. + */ + private static class BlockPlaceholderNode extends FixedWithNextNode implements Node.IterableNodeType { + public BlockPlaceholderNode() { + super(StampFactory.illegal()); + } + } + + public GraphBuilderPhase(RiRuntime runtime) { this(runtime, GraphBuilderConfiguration.getDefault()); } @@ -121,14 +123,12 @@ assert method.code() != null : "method must contain bytecodes: " + method; this.stream = new BytecodeStream(method.code()); this.constantPool = method.getConstantPool(); - this.blocksOnWorklist = new HashSet<>(); - this.blocksVisited = new HashSet<>(); unwindBlock = null; returnBlock = null; methodSynchronizedObject = null; exceptionHandlers = null; this.currentGraph = graph; - this.frameState = new FrameStateBuilder(method, method.maxLocals(), method.maxStackSize(), graph, config.eagerResolving()); + this.frameState = new FrameStateBuilder(method, graph, config.eagerResolving()); build(); } @@ -140,12 +140,8 @@ private BciBlockMapping createBlockMap() { BciBlockMapping map = new BciBlockMapping(method, config.useBranchPrediction()); map.build(); + Debug.dump(map, CiUtil.format("After block building %f %R %H.%n(%P)", method)); -// if (currentContext.isObserved()) { -// String label = CiUtil.format("BlockListBuilder %f %R %H.%n(%P)", method); -// currentContext.observable.fireCompilationEvent(label, map); -// } - // TODO(tw): Reinstall this logging code when debug framework is finished. return map; } @@ -161,8 +157,6 @@ exceptionHandlers = blockMap.exceptionHandlers(); - nextBlockNumber = blockMap.blocks.size(); - lastInstr = currentGraph.start(); if (isSynchronized(method.accessFlags())) { // add a monitor enter to the start block @@ -170,6 +164,7 @@ methodSynchronizedObject = synchronizedObject(frameState, method); lastInstr = genMonitorEnter(methodSynchronizedObject); } + frameState.clearNonLiveLocals(blockMap.startBlock.localsLiveIn); // finish the start block ((AbstractStateSplit) lastInstr).setStateAfter(frameState.create(0)); @@ -177,14 +172,21 @@ appendGoto(createTarget(blockMap.startBlock, frameState)); } else { blockMap.startBlock.firstInstruction = lastInstr; + blockMap.startBlock.entryState = frameState; } - addToWorkList(blockMap.startBlock); - iterateAllBlocks(); + for (Block block : blockMap.blocks) { + processBlock(block); + } + processBlock(returnBlock); + processBlock(unwindBlock); + + Debug.dump(currentGraph, "After bytecode parsing"); + connectLoopEndToBegin(); // remove Placeholders (except for loop exits) - for (PlaceholderNode n : currentGraph.getNodes(PlaceholderNode.class)) { + for (BlockPlaceholderNode n : currentGraph.getNodes(BlockPlaceholderNode.class)) { currentGraph.removeFixed(n); } @@ -200,18 +202,13 @@ } } - private int nextBlockNumber() { - return nextBlockNumber++; - } - private Block unwindBlock(int bci) { if (unwindBlock == null) { unwindBlock = new ExceptionBlock(); unwindBlock.startBci = -1; unwindBlock.endBci = -1; unwindBlock.deoptBci = bci; - unwindBlock.blockID = nextBlockNumber(); - addToWorkList(unwindBlock); + unwindBlock.blockID = Integer.MAX_VALUE; } return unwindBlock; } @@ -221,80 +218,11 @@ returnBlock = new Block(); returnBlock.startBci = bci; returnBlock.endBci = bci; - returnBlock.blockID = nextBlockNumber(); - addToWorkList(returnBlock); + returnBlock.blockID = Integer.MAX_VALUE; } return returnBlock; } - private void markOnWorkList(Block block) { - blocksOnWorklist.add(block); - } - - private boolean isOnWorkList(Block block) { - return blocksOnWorklist.contains(block); - } - - private void markVisited(Block block) { - blocksVisited.add(block); - } - - private boolean isVisited(Block block) { - return blocksVisited.contains(block); - } - - public void mergeOrClone(Block target, FrameStateAccess newState, StateSplit first) { - - int bci = target.startBci; - if (target instanceof ExceptionBlock) { - bci = ((ExceptionBlock) target).deoptBci; - } - - FrameState existingState = first.stateAfter(); - if (existingState == null) { - // There was no state : new target - // copy state because it is modified - first.setStateAfter(newState.duplicate(bci)); - return; - } else { - if (!GraalOptions.AssumeVerifiedBytecode && !existingState.isCompatibleWith(newState)) { - // stacks or locks do not match--bytecodes would not verify - TTY.println(existingState.toString()); - TTY.println(newState.duplicate(0).toString()); - throw new CiBailout("stack or locks do not match"); - } - assert existingState.localsSize() == newState.localsSize(); - assert existingState.stackSize() == newState.stackSize(); - - if (first instanceof PlaceholderNode) { - // there is no merge yet here - PlaceholderNode p = (PlaceholderNode) first; - if (p.predecessor() == null) { - //nothing seems to come here, yet there's a state? - Debug.log("Funky control flow going to @bci %d : we already have a state but no predecessor", bci); - p.setStateAfter(newState.duplicate(bci)); - return; - } else { - //create a merge - MergeNode merge = currentGraph.add(new MergeNode()); - FixedNode next = p.next(); - if (p.predecessor() != null) { - EndNode end = currentGraph.add(new EndNode()); - p.setNext(end); - merge.addForwardEnd(end); - } - merge.setNext(next); - FrameState mergeState = existingState.duplicate(bci); - merge.setStateAfter(mergeState); - mergeState.merge(merge, newState); - target.firstInstruction = merge; - } - } else { - existingState.merge((MergeNode) first, newState); - } - } - } - public BytecodeStream stream() { return stream; } @@ -371,9 +299,9 @@ } else { currentExceptionObject = exceptionObject; } - FrameState stateWithException = frameState.duplicateWithException(bci, currentExceptionObject); + FrameStateBuilder stateWithException = frameState.copyWithException(currentExceptionObject); if (newObj != null) { - newObj.setStateAfter(stateWithException); + newObj.setStateAfter(stateWithException.create(bci)); } FixedNode target = createTarget(dispatchBlock, stateWithException); if (exceptionObject == null) { @@ -596,7 +524,7 @@ private void genIncrement() { int index = stream().readLocalIndex(); int delta = stream().readIncrement(); - ValueNode x = frameState.localAt(index); + ValueNode x = frameState.loadLocal(index); ValueNode y = append(ConstantNode.forInt(delta, currentGraph)); frameState.storeLocal(index, append(currentGraph.unique(new IntegerAddNode(CiKind.Int, x, y)))); } @@ -757,7 +685,7 @@ InstanceOfNode instanceOfNode = new InstanceOfNode(hub, (RiResolvedType) type, object, hints, Util.isFinalClass(resolvedType), false); frameState.ipush(append(MaterializeNode.create(currentGraph.unique(instanceOfNode), currentGraph))); } else { - PlaceholderNode trueSucc = currentGraph.add(new PlaceholderNode()); + BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode()); DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile)); IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new NullCheckNode(object, true)), trueSucc, deopt, 1)); append(ifNode); @@ -861,8 +789,8 @@ } private ExceptionInfo emitNullCheck(ValueNode receiver) { - PlaceholderNode trueSucc = currentGraph.add(new PlaceholderNode()); - PlaceholderNode falseSucc = currentGraph.add(new PlaceholderNode()); + BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode()); + BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode()); IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new NullCheckNode(receiver, false)), trueSucc, falseSucc, 1)); append(ifNode); @@ -873,15 +801,15 @@ return new ExceptionInfo(falseSucc, exception); } else { RuntimeCallNode call = currentGraph.add(new RuntimeCallNode(CiRuntimeCall.CreateNullPointerException)); - call.setStateAfter(frameState.duplicate(bci())); + call.setStateAfter(frameState.create(bci())); falseSucc.setNext(call); return new ExceptionInfo(call, call); } } private ExceptionInfo emitBoundsCheck(ValueNode index, ValueNode length) { - PlaceholderNode trueSucc = currentGraph.add(new PlaceholderNode()); - PlaceholderNode falseSucc = currentGraph.add(new PlaceholderNode()); + BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode()); + BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode()); IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new CompareNode(index, Condition.BT, length)), trueSucc, falseSucc, 1)); append(ifNode); @@ -892,7 +820,7 @@ return new ExceptionInfo(falseSucc, exception); } else { RuntimeCallNode call = currentGraph.add(new RuntimeCallNode(CiRuntimeCall.CreateOutOfBoundsException, new ValueNode[] {index})); - call.setStateAfter(frameState.duplicate(bci())); + call.setStateAfter(frameState.create(bci())); falseSucc.setNext(call); return new ExceptionInfo(call, call); } @@ -922,7 +850,7 @@ merge.addForwardEnd(end); phi.addInput(info.exception); } - merge.setStateAfter(frameState.duplicate(bci())); + merge.setStateAfter(frameState.create(bci())); exception = new ExceptionInfo(merge, phi); } @@ -930,7 +858,7 @@ if (entry != null) { exception.exceptionEdge.setNext(entry); } else { - exception.exceptionEdge.setNext(createTarget(unwindBlock(bci()), frameState.duplicateWithException(bci(), exception.exception))); + exception.exceptionEdge.setNext(createTarget(unwindBlock(bci()), frameState.copyWithException(exception.exception))); } Debug.metric("ExplicitExceptions").increment(); } @@ -1098,6 +1026,10 @@ result = append(invoke); frameState.pushReturn(resultType, result); Block nextBlock = currentBlock.successors.get(0); + + assert bci() == currentBlock.endBci; + frameState.clearNonLiveLocals(currentBlock.localsLiveOut); + invoke.setNext(createTarget(nextBlock, frameState)); invoke.setStateAfter(frameState.create(nextBlock.startBci)); } else { @@ -1251,130 +1183,148 @@ return x; } - private FixedNode createTarget(Block block, FrameStateAccess stateAfter) { + private FixedNode createTarget(Block block, FrameStateBuilder stateAfter) { assert block != null && stateAfter != null; - assert block.isLoopHeader || block.firstInstruction == null || block.firstInstruction.next() == null : - "non-loop block must be iterated after all its predecessors. startBci=" + block.startBci + ", " + block.getClass().getSimpleName() + ", " + block.firstInstruction.next(); - - if (block.isExceptionEntry) { - assert stateAfter.stackSize() == 1; - } + assert !block.isExceptionEntry || stateAfter.stackSize() == 1; if (block.firstInstruction == null) { - if (block.isLoopHeader) { - LoopBeginNode loop = currentGraph.add(new LoopBeginNode()); - EndNode end = currentGraph.add(new EndNode()); - loop.addForwardEnd(end); - PlaceholderNode p = currentGraph.add(new PlaceholderNode()); - p.setNext(end); - block.firstInstruction = p; - } else { - block.firstInstruction = currentGraph.add(new PlaceholderNode()); - } + // This is the first time we see this block as a branch target. + // Create and return a placeholder that later can be replaced with a MergeNode when we see this block again. + block.firstInstruction = currentGraph.add(new BlockPlaceholderNode()); + block.entryState = stateAfter.copy(); + block.entryState.clearNonLiveLocals(block.localsLiveIn); + + Debug.log("createTarget %s: first visit, result: %s", block, block.firstInstruction); + return block.firstInstruction; } - LoopEndNode loopend = null; - StateSplit mergeAt = null; - if (block.isLoopHeader && isVisited(block)) { // backedge - loopend = currentGraph.add(new LoopEndNode(loopBegin(block))); - mergeAt = loopBegin(block); - } else { - mergeAt = (StateSplit) block.firstInstruction; + + // We already saw this block before, so we have to merge states. + if (!block.entryState.isCompatibleWith(stateAfter)) { + throw new CiBailout("stacks do not match; bytecodes would not verify"); } - mergeOrClone(block, stateAfter, mergeAt); - addToWorkList(block); + if (block.firstInstruction instanceof LoopBeginNode) { + assert block.isLoopHeader && currentBlock.blockID >= block.blockID : "must be backward branch"; + // Backward loop edge. We need to create a special LoopEndNode and merge with the loop begin node created before. + LoopBeginNode loopBegin = (LoopBeginNode) block.firstInstruction; + LoopEndNode result = currentGraph.add(new LoopEndNode(loopBegin)); + block.entryState.merge(loopBegin, stateAfter); + + Debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result); + return result; + } + assert currentBlock == null || currentBlock.blockID < block.blockID : "must not be backward branch"; + assert block.firstInstruction.next() == null : "bytecodes already parsed for block"; - FixedNode result = null; - if (loopend != null) { - result = loopend; - } else { - result = block.firstInstruction; + if (block.firstInstruction instanceof BlockPlaceholderNode) { + // This is the second time we see this block. Create the actual MergeNode and the End Node for the already existing edge. + // For simplicity, we leave the placeholder in the graph and just append the new nodes after the placeholder. + BlockPlaceholderNode placeholder = (BlockPlaceholderNode) block.firstInstruction; + + // The EndNode for the already existing edge. + EndNode end = currentGraph.add(new EndNode()); + // The MergeNode that replaces the placeholder. + MergeNode mergeNode = currentGraph.add(new MergeNode()); + FixedNode next = placeholder.next(); + + placeholder.setNext(end); + mergeNode.addForwardEnd(end); + mergeNode.setNext(next); + + block.firstInstruction = mergeNode; } - if (result instanceof MergeNode) { - EndNode end = currentGraph.add(new EndNode()); - ((MergeNode) result).addForwardEnd(end); - result = end; - } - assert !(result instanceof MergeNode); - Debug.log("createTarget(%s, state) = %s", block, result); + MergeNode mergeNode = (MergeNode) block.firstInstruction; + + // The EndNode for the newly merged edge. + EndNode result = currentGraph.add(new EndNode()); + block.entryState.merge(mergeNode, stateAfter); + mergeNode.addForwardEnd(result); + + Debug.log("createTarget %s: merging state, result: %s", block, result); return result; } - private ValueNode synchronizedObject(FrameStateAccess state, RiResolvedMethod target) { + private ValueNode synchronizedObject(FrameStateBuilder state, RiResolvedMethod target) { if (isStatic(target.accessFlags())) { return append(ConstantNode.forCiConstant(target.holder().getEncoding(Representation.JavaClass), runtime, currentGraph)); } else { - return state.localAt(0); + return state.loadLocal(0); } } - private void iterateAllBlocks() { - Block block; - while ((block = removeFromWorkList()) != null) { - // remove blocks that have no predecessors by the time it their bytecodes are parsed - if (block.firstInstruction == null) { - markVisited(block); - continue; - } + private void processBlock(Block block) { + // Ignore blocks that have no predecessors by the time it their bytecodes are parsed + if (block == null || block.firstInstruction == null) { + Debug.log("Ignoring block %s", block); + return; + } + Debug.log("Parsing block %s firstInstruction: %s loopHeader: %b", block, block.firstInstruction, block.isLoopHeader); + + lastInstr = block.firstInstruction; + frameState = block.entryState; + currentBlock = block; - if (!isVisited(block)) { - markVisited(block); - // now parse the block - if (block.isLoopHeader) { - LoopBeginNode begin = loopBegin(block); - FrameState preLoopState = ((StateSplit) block.firstInstruction).stateAfter(); - FrameState loopState = preLoopState.duplicate(preLoopState.bci); - begin.setStateAfter(loopState); - loopState.insertLoopPhis(begin); - lastInstr = begin; - } else { - lastInstr = block.firstInstruction; - } - frameState.initializeFrom(((StateSplit) lastInstr).stateAfter()); - assert lastInstr.next() == null : "instructions already appended at block " + block.blockID; + frameState.cleanupDeletedPhis(); + if (lastInstr instanceof MergeNode) { + int bci = block.startBci; + if (block instanceof ExceptionBlock) { + bci = ((ExceptionBlock) block).deoptBci; + } + ((MergeNode) lastInstr).setStateAfter(frameState.create(bci)); + } - if (block == returnBlock) { - frameState.setRethrowException(false); - createReturn(); - } else if (block == unwindBlock) { - frameState.setRethrowException(false); - createUnwind(); - } else if (block instanceof ExceptionBlock) { - createExceptionDispatch((ExceptionBlock) block); - } else if (block instanceof DeoptBlock) { - createDeopt(); - } else { - frameState.setRethrowException(false); - iterateBytecodesForBlock(block); - } - } + if (block == returnBlock) { + frameState.setRethrowException(false); + createReturn(); + } else if (block == unwindBlock) { + frameState.setRethrowException(false); + createUnwind(); + } else if (block instanceof ExceptionBlock) { + createExceptionDispatch((ExceptionBlock) block); + } else if (block instanceof DeoptBlock) { + createDeopt(); + } else { + frameState.setRethrowException(false); + iterateBytecodesForBlock(block); } } private void connectLoopEndToBegin() { for (LoopBeginNode begin : currentGraph.getNodes(LoopBeginNode.class)) { if (begin.loopEnds().isEmpty()) { -// This can happen with degenerated loops like this one: -// for (;;) { -// try { -// break; -// } catch (UnresolvedException iioe) { -// } -// } - - // Remove the loop begin or transform it into a merge. - assert begin.forwardEndCount() > 0; + // Remove loop header without loop ends. + // This can happen with degenerated loops like this one: + // for (;;) { + // try { + // break; + // } catch (UnresolvedException iioe) { + // } + // } + assert begin.forwardEndCount() == 1; currentGraph.reduceDegenerateLoopBegin(begin); } else { - begin.stateAfter().simplifyLoopState(); + // Delete unnecessary loop phi functions, i.e., phi functions where all inputs are either the same or the phi itself. + for (PhiNode phi : begin.stateAfter().values().filter(PhiNode.class).snapshot()) { + checkRedundantPhi(phi); + } } } } - private static LoopBeginNode loopBegin(Block block) { - LoopBeginNode loopBegin = (LoopBeginNode) ((EndNode) block.firstInstruction.next()).merge(); - return loopBegin; + private static void checkRedundantPhi(PhiNode phiNode) { + if (phiNode.isDeleted() || phiNode.valueCount() == 1) { + return; + } + + ValueNode singleValue = phiNode.singleValue(); + if (singleValue != null) { + Collection phiUsages = phiNode.usages().filter(PhiNode.class).snapshot(); + ((StructuredGraph) phiNode.graph()).replaceFloating(phiNode, singleValue); + for (PhiNode phi : phiUsages) { + checkRedundantPhi(phi); + } + } } private void createDeopt() { @@ -1472,9 +1422,30 @@ } private void iterateBytecodesForBlock(Block block) { - assert frameState != null; + if (block.isLoopHeader) { + // Create the loop header block, which later will merge the backward branches of the loop. + EndNode preLoopEnd = currentGraph.add(new EndNode()); + LoopBeginNode loopBegin = currentGraph.add(new LoopBeginNode()); + lastInstr.setNext(preLoopEnd); + // Add the single non-loop predecessor of the loop header. + loopBegin.addForwardEnd(preLoopEnd); + lastInstr = loopBegin; - currentBlock = block; + // Create phi functions for all local variables and operand stack slots. + frameState.insertLoopPhis(loopBegin); + loopBegin.setStateAfter(frameState.create(block.startBci)); + + // We have seen all forward branches. All subsequent backward branches will merge to the loop header. + // This ensures that the loop header has exactly one non-loop predecessor. + block.firstInstruction = loopBegin; + // We need to preserve the frame state builder of the loop header so that we can merge values for + // phi functions, so make a copy of it. + block.entryState = frameState.copy(); + + Debug.log(" created loop header %s", loopBegin); + } + assert lastInstr.next() == null : "instructions already appended at block " + block; + Debug.log(" frameState: %s", frameState); int endBCI = stream.endBCI(); @@ -1761,31 +1732,4 @@ private void genArrayLength() { frameState.ipush(append(currentGraph.add(new ArrayLengthNode(frameState.apop())))); } - - /** - * Adds a block to the worklist, if it is not already in the worklist. - * This method will keep the worklist topologically stored (i.e. the lower - * DFNs are earlier in the list). - * @param block the block to add to the work list - */ - private void addToWorkList(Block block) { - if (!isOnWorkList(block)) { - markOnWorkList(block); - sortIntoWorkList(block); - } - } - - private void sortIntoWorkList(Block top) { - workList.offer(top); - } - - /** - * Removes the next block from the worklist. The list is sorted topologically, so the - * block with the lowest depth first number in the list will be removed and returned. - * @return the next block from the worklist; {@code null} if there are no blocks - * in the worklist - */ - private Block removeFromWorkList() { - return workList.poll(); - } } diff -r df0deec2af08 -r b11561111585 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/FrameState.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/FrameState.java Mon Mar 05 14:38:43 2012 +0100 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/FrameState.java Mon Mar 05 09:55:54 2012 -0800 @@ -28,7 +28,6 @@ import com.oracle.max.cri.ri.*; import com.oracle.max.graal.graph.*; import com.oracle.max.graal.graph.iterators.*; -import com.oracle.max.graal.nodes.PhiNode.PhiType; import com.oracle.max.graal.nodes.spi.*; import com.oracle.max.graal.nodes.virtual.*; @@ -36,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 FrameStateAccess, Node.IterableNodeType, LIRLowerable { +public final class FrameState extends Node implements Node.IterableNodeType, LIRLowerable { protected final int localsSize; @@ -114,9 +113,11 @@ this.stackSize = stackSize; final ValueNode[] newValues = new ValueNode[locals.length + stackSize]; for (int i = 0; i < locals.length; i++) { + assert locals[i] == null || !locals[i].isDeleted(); newValues[i] = locals[i]; } for (int i = 0; i < stackSize; i++) { + assert stack[i] == null || !stack[i].isDeleted(); newValues[localsSize + i] = stack[i]; } this.values = new NodeInputList<>(this, newValues); @@ -126,6 +127,10 @@ assert !rethrowException || stackSize == 1 : "must have exception on top of the stack"; } + public NodeIterable values() { + return values; + } + public FrameState outerFrameState() { return outerFrameState; } @@ -135,15 +140,7 @@ this.outerFrameState = x; } - public FrameState outermostFrameState() { - FrameState fs = this; - while (fs.outerFrameState() != null) { - fs = fs.outerFrameState(); - } - return fs; - } - - public void setValueAt(int i, ValueNode x) { + private void setValueAt(int i, ValueNode x) { values.set(i, x); } @@ -199,18 +196,22 @@ return other; } - @Override - public FrameState duplicateWithException(int newBci, ValueNode exceptionObject) { - return duplicateModified(newBci, true, CiKind.Void, exceptionObject); - } - /** * Creates a copy of this frame state with one stack element of type popKind popped from the stack and the * values in pushedValues pushed on the stack. The pushedValues are expected to be in slot encoding: a long * or double is followed by a null slot. */ public FrameState duplicateModified(int newBci, boolean newRethrowException, CiKind popKind, ValueNode... pushedValues) { - int popSlots = popKind == CiKind.Void ? 0 : isTwoSlot(popKind) ? 2 : 1; + int popSlots = 0; + if (popKind != CiKind.Void) { + if (stackAt(stackSize() - 1) == null) { + popSlots = 2; + } else { + popSlots = 1; + } + assert stackAt(stackSize() - popSlots).kind().stackKind() == popKind.stackKind(); + } + 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++) { @@ -228,40 +229,6 @@ return other; } - public boolean isCompatibleWith(FrameStateAccess other) { - if (stackSize() != other.stackSize() || localsSize() != other.localsSize()) { - return false; - } - for (int i = 0; i < stackSize(); i++) { - ValueNode x = stackAt(i); - ValueNode y = other.stackAt(i); - if (x != y && ValueUtil.typeMismatch(x, y)) { - return false; - } - } - if (other.outerFrameState() != outerFrameState()) { - return false; - } - return true; - } - - public boolean equals(FrameStateAccess other) { - if (stackSize() != other.stackSize() || localsSize() != other.localsSize()) { - return false; - } - for (int i = 0; i < stackSize(); i++) { - ValueNode x = stackAt(i); - ValueNode y = other.stackAt(i); - if (x != y) { - return false; - } - } - if (other.outerFrameState() != outerFrameState()) { - return false; - } - return true; - } - /** * Gets the size of the local variables. */ @@ -277,52 +244,14 @@ } /** - * Invalidates the local variable at the specified index. If the specified index refers to a doubleword local, then - * invalidates the high word as well. - * - * @param i the index of the local to invalidate - */ - public void invalidateLocal(int i) { - // note that for double word locals, the high slot should already be null - // unless the local is actually dead and the high slot is being reused; - // in either case, it is not necessary to null the high slot - setValueAt(i, null); - } - - /** - * Stores a given local variable at the specified index. If the value is a {@linkplain CiKind#isDoubleWord() double word}, - * then the next local variable index is also overwritten. - * - * @param i the index at which to store - * @param x the instruction which produces the value for the local - */ - // TODO this duplicates code in FrameStateBuilder and needs to go away - public void storeLocal(int i, ValueNode x) { - assert i < localsSize : "local variable index out of range: " + i; - invalidateLocal(i); - setValueAt(i, x); - if (isTwoSlot(x.kind())) { - // (tw) if this was a double word then kill i+1 - setValueAt(i + 1, null); - } - if (i > 0) { - // if there was a double word at i - 1, then kill it - ValueNode p = localAt(i - 1); - if (p != null && isTwoSlot(p.kind())) { - setValueAt(i - 1, null); - } - } - } - - /** * Gets the value in the local variables at the specified index. * * @param i the index into the locals * @return the instruction that produced the value for the specified local */ public ValueNode localAt(int i) { - assert i < localsSize : "local variable index out of range: " + i; - return valueAt(i); + assert i >= 0 && i < localsSize : "local variable index out of range: " + i; + return values.get(i); } /** @@ -332,233 +261,38 @@ * @return the instruction at the specified position in the stack */ public ValueNode stackAt(int i) { - assert i >= 0 && i < (localsSize + stackSize); - return valueAt(localsSize + i); - } - - /** - * Inserts a phi statement into the stack at the specified stack index. - * @param block the block begin for which we are creating the phi - * @param i the index into the stack for which to create a phi - */ - public PhiNode setupLoopPhiForStack(MergeNode block, int i) { - ValueNode p = stackAt(i); - if (p != null) { - if (p instanceof PhiNode) { - PhiNode phi = (PhiNode) p; - if (phi.merge() == block) { - return phi; - } - } - PhiNode phi = graph().unique(new PhiNode(p.kind(), block, PhiType.Value)); - phi.addInput(p); - setValueAt(localsSize + i, phi); - return phi; - } - return null; - } - - /** - * Inserts a phi statement for the local at the specified index. - * @param block the block begin for which we are creating the phi - * @param i the index of the local variable for which to create the phi - */ - public PhiNode setupLoopPhiForLocal(MergeNode block, int i) { - ValueNode p = localAt(i); - if (p instanceof PhiNode) { - PhiNode phi = (PhiNode) p; - if (phi.merge() == block) { - return phi; - } - } - PhiNode phi = graph().unique(new PhiNode(p.kind(), block, PhiType.Value)); - phi.addInput(p); - storeLocal(i, phi); - return phi; - } - - /** - * Gets the value at a specified index in the set of operand stack and local values represented by this frame. - * This method should only be used to iterate over all the values in this frame, irrespective of whether - * they are on the stack or in local variables. - * To iterate the stack slots, the {@link #stackAt(int)} and {@link #stackSize()} methods should be used. - * To iterate the local variables, the {@link #localAt(int)} and {@link #localsSize()} methods should be used. - * - * @param i a value in the range {@code [0 .. valuesSize()]} - * @return the value at index {@code i} which may be {@code null} - */ - public ValueNode valueAt(int i) { - assert i < (localsSize + stackSize); - return values.isEmpty() ? null : values.get(i); - } - - /** - * The number of operand stack slots and local variables in this frame. - * This method should typically only be used in conjunction with {@link #valueAt(int)}. - * To iterate the stack slots, the {@link #stackAt(int)} and {@link #stackSize()} methods should be used. - * To iterate the local variables, the {@link #localAt(int)} and {@link #localsSize()} methods should be used. - * - * @return the number of local variables in this frame - */ - public int valuesSize() { - return localsSize + stackSize; - } - - private boolean checkSize(FrameStateAccess other) { - assert other.stackSize() == stackSize() : "stack sizes do not match"; - assert other.localsSize() == localsSize : "local sizes do not match"; - return true; - } - - public void merge(MergeNode block, FrameStateAccess other) { - assert checkSize(other); - for (int i = 0; i < valuesSize(); i++) { - ValueNode currentValue = valueAt(i); - ValueNode otherValue = other.valueAt(i); - if (currentValue != otherValue || block instanceof LoopBeginNode) { - if (block.isPhiAtMerge(currentValue)) { - addToPhi((PhiNode) currentValue, otherValue, block instanceof LoopBeginNode); - } else { - setValueAt(i, combineValues(currentValue, otherValue, block)); - } - } - } - } - - public void simplifyLoopState() { - for (PhiNode phi : values.filter(PhiNode.class).snapshot()) { - checkRedundantPhi(phi); - } - } - - private static ValueNode combineValues(ValueNode currentValue, ValueNode otherValue, MergeNode block) { - if (currentValue == null || otherValue == null || currentValue.kind() != otherValue.kind()) { - return null; - } - - PhiNode phi = currentValue.graph().add(new PhiNode(currentValue.kind(), block, PhiType.Value)); - for (int j = 0; j < block.phiPredecessorCount(); ++j) { - phi.addInput(currentValue); - } - phi.addInput(otherValue); - assert phi.valueCount() == block.phiPredecessorCount() + 1 : "valueCount=" + phi.valueCount() + " predSize= " + block.phiPredecessorCount(); - return phi; - } - - private static void addToPhi(PhiNode phiNode, ValueNode otherValue, boolean recursiveInvalidCheck) { - if (otherValue == null || otherValue.kind() != phiNode.kind()) { - if (recursiveInvalidCheck) { - deleteInvalidPhi(phiNode); - } else { - phiNode.replaceAtUsages(null); - phiNode.safeDelete(); - } - } else { - phiNode.addInput(otherValue); - } - } - - public static void deleteRedundantPhi(PhiNode redundantPhi, ValueNode phiValue) { - Collection phiUsages = redundantPhi.usages().filter(PhiNode.class).snapshot(); - ((StructuredGraph) redundantPhi.graph()).replaceFloating(redundantPhi, phiValue); - for (PhiNode phi : phiUsages) { - checkRedundantPhi(phi); - } - } - - private static void checkRedundantPhi(PhiNode phiNode) { - if (phiNode.isDeleted() || phiNode.valueCount() == 1) { - return; - } - - ValueNode singleValue = phiNode.singleValue(); - if (singleValue != null) { - deleteRedundantPhi(phiNode, singleValue); - } - } - - private static void deleteInvalidPhi(PhiNode phiNode) { - if (!phiNode.isDeleted()) { - Collection phiUsages = phiNode.usages().filter(PhiNode.class).snapshot(); - phiNode.replaceAtUsages(null); - phiNode.safeDelete(); - for (Node n : phiUsages) { - deleteInvalidPhi((PhiNode) n); - } - } + assert i >= 0 && i < stackSize; + return values.get(localsSize + i); } public MergeNode block() { return usages().filter(MergeNode.class).first(); } - public StateSplit stateSplit() { - return (StateSplit) usages().filterInterface(StateSplit.class).first(); - } - public NodeIterable innerFrameStates() { return usages().filter(FrameState.class); } - /** - * The interface implemented by a client of {@link FrameState#forEachPhi(MergeNode, PhiProcedure)} and - * {@link FrameState#forEachLivePhi(MergeNode, PhiProcedure)}. - */ - public interface PhiProcedure { - boolean doPhi(PhiNode phi); - } - - /** - * Checks whether this frame state has any {@linkplain PhiNode phi} statements. - */ - public boolean hasPhis() { - for (int i = 0; i < valuesSize(); i++) { - ValueNode value = valueAt(i); - if (value instanceof PhiNode) { - return true; - } - } - return false; - } - - public String toDetailedString() { - StringBuilder sb = new StringBuilder(); - String nl = String.format("%n"); - sb.append("[bci: ").append(bci).append("]"); - if (rethrowException()) { - sb.append(" rethrows Exception"); - } - sb.append(nl); - for (int i = 0; i < localsSize(); ++i) { - ValueNode value = localAt(i); - sb.append(String.format(" local[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind().javaName, value)); - } - for (int i = 0; i < stackSize(); ++i) { - ValueNode value = stackAt(i); - sb.append(String.format(" stack[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind().javaName, value)); - } - return sb.toString(); - } - @Override public void generate(LIRGeneratorTool gen) { // Nothing to do, frame states are processed as part of the handling of AbstractStateSplit nodes. } - public static String toString(FrameState frameState) { + private static String toString(FrameState frameState) { StringBuilder sb = new StringBuilder(); String nl = CiUtil.NEW_LINE; FrameState fs = frameState; while (fs != null) { CiUtil.appendLocation(sb, fs.method, fs.bci).append(nl); - for (int i = 0; i < fs.localsSize(); ++i) { - ValueNode value = fs.localAt(i); - sb.append(String.format(" local[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind().javaName, value)); + sb.append("locals: ["); + for (int i = 0; i < fs.localsSize(); i++) { + sb.append(i == 0 ? "" : ", ").append(fs.localAt(i) == null ? "_" : fs.localAt(i).toString(Verbosity.Id)); } - for (int i = 0; i < fs.stackSize(); ++i) { - ValueNode value = fs.stackAt(i); - sb.append(String.format(" stack[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind().javaName, value)); + sb.append("]").append(nl).append("stack: "); + for (int i = 0; i < fs.stackSize(); i++) { + sb.append(i == 0 ? "" : ", ").append(fs.stackAt(i) == null ? "_" : fs.stackAt(i).toString(Verbosity.Id)); } + sb.append(nl); fs = fs.outerFrameState(); } return sb.toString(); @@ -575,22 +309,6 @@ } } - public void insertLoopPhis(LoopBeginNode loopBegin) { - for (int i = 0; i < stackSize(); i++) { - // always insert phis for the stack - ValueNode x = stackAt(i); - if (x != null) { - setupLoopPhiForStack(loopBegin, i); - } - } - for (int i = 0; i < localsSize(); i++) { - ValueNode x = localAt(i); - if (x != null) { - setupLoopPhiForLocal(loopBegin, i); - } - } - } - @Override public Map getDebugProperties() { Map properties = super.getDebugProperties(); @@ -600,41 +318,27 @@ } else { properties.put("method", "None"); } - StringBuilder str = new StringBuilder(); + StringBuilder sb = new StringBuilder(); for (int i = 0; i < localsSize(); i++) { - str.append(i == 0 ? "" : ", ").append(localAt(i) == null ? "_" : localAt(i).toString(Verbosity.Id)); + sb.append(i == 0 ? "" : ", ").append(localAt(i) == null ? "_" : localAt(i).toString(Verbosity.Id)); } - properties.put("locals", str.toString()); - str = new StringBuilder(); + properties.put("locals", sb.toString()); + sb = new StringBuilder(); for (int i = 0; i < stackSize(); i++) { - str.append(i == 0 ? "" : ", ").append(stackAt(i) == null ? "_" : stackAt(i).toString(Verbosity.Id)); + sb.append(i == 0 ? "" : ", ").append(stackAt(i) == null ? "_" : stackAt(i).toString(Verbosity.Id)); } - properties.put("stack", str.toString()); + properties.put("stack", sb.toString()); properties.put("rethrowException", rethrowException); properties.put("duringCall", duringCall); return properties; } - public CiCodePos toCodePos() { - FrameState caller = outerFrameState(); - CiCodePos callerCodePos = null; - if (caller != null) { - callerCodePos = caller.toCodePos(); - } - return new CiCodePos(callerCodePos, method, bci); - } - @Override public boolean verify() { for (ValueNode value : values) { + assert assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes"); assert assertTrue(value == null || value instanceof VirtualObjectNode || (value.kind() != CiKind.Void && value.kind() != CiKind.Illegal), "unexpected value: %s", value); } return super.verify(); } - - // TODO this duplicates code in FrameStateBuilder and needs to go away - public static boolean isTwoSlot(CiKind kind) { - assert kind != CiKind.Void && kind != CiKind.Illegal; - return kind == CiKind.Long || kind == CiKind.Double; - } } diff -r df0deec2af08 -r b11561111585 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/PlaceholderNode.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/PlaceholderNode.java Mon Mar 05 14:38:43 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +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.max.graal.nodes; - -import com.oracle.max.graal.graph.*; -import com.oracle.max.graal.nodes.spi.*; -import com.oracle.max.graal.nodes.type.*; - - -public class PlaceholderNode extends AbstractStateSplit implements Node.IterableNodeType, LIRLowerable { - - public PlaceholderNode() { - super(StampFactory.illegal()); - } - - @Override - public void generate(LIRGeneratorTool gen) { - // nothing to do - } -} diff -r df0deec2af08 -r b11561111585 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/FrameStateAccess.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/FrameStateAccess.java Mon Mar 05 14:38:43 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 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.max.graal.nodes.spi; - -import com.oracle.max.graal.nodes.*; - -public interface FrameStateAccess { - - FrameState duplicate(int newBci); - - int localsSize(); - - int stackSize(); - - boolean rethrowException(); - - ValueNode valueAt(int i); - - ValueNode localAt(int i); - - ValueNode stackAt(int i); - - FrameState outerFrameState(); - - FrameState duplicateWithException(int bci, ValueNode exceptionObject); - -}