# HG changeset patch # User Christian Wimmer # Date 1325811778 28800 # Node ID fa53d5e4aa353fc6914ecf345fa53f1ea8c388ed # Parent 382523fc390c72bf69884d32ee2bd35d554083c4 Remove lock information from frame states, and compute it instead when LIR is generated. diff -r 382523fc390c -r fa53d5e4aa35 graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiValueUtil.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiValueUtil.java Thu Jan 05 17:02:13 2012 -0800 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiValueUtil.java Thu Jan 05 17:02:58 2012 -0800 @@ -37,6 +37,10 @@ return value instanceof CiVirtualObject; } + public static CiVirtualObject asVirtualObject(CiValue value) { + assert value != null; + return (CiVirtualObject) value; + } public static boolean isConstant(CiValue value) { assert value != null; diff -r 382523fc390c -r fa53d5e4aa35 graal/com.oracle.max.criutils/src/com/oracle/max/criutils/CompilationPrinter.java --- a/graal/com.oracle.max.criutils/src/com/oracle/max/criutils/CompilationPrinter.java Thu Jan 05 17:02:13 2012 -0800 +++ b/graal/com.oracle.max.criutils/src/com/oracle/max/criutils/CompilationPrinter.java Thu Jan 05 17:02:58 2012 -0800 @@ -22,7 +22,10 @@ */ package com.oracle.max.criutils; +import static com.oracle.max.cri.ci.CiValueUtil.*; + import java.io.*; +import java.util.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; @@ -124,6 +127,7 @@ if (codePos != null) { CiCodePos curCodePos = codePos; + List virtualObjects = new ArrayList<>(); do { sb.append(CiUtil.toLocation(curCodePos.method, curCodePos.bci)); sb.append('\n'); @@ -132,35 +136,47 @@ if (frame.numStack > 0) { sb.append("stack: "); for (int i = 0; i < frame.numStack; i++) { - sb.append(valueToString(frame.getStackValue(i))).append(' '); + sb.append(valueToString(frame.getStackValue(i), virtualObjects)).append(' '); } sb.append("\n"); } - + sb.append("locals: "); + for (int i = 0; i < frame.numLocals; i++) { + sb.append(valueToString(frame.getLocalValue(i), virtualObjects)).append(' '); + } + sb.append("\n"); if (frame.numLocks > 0) { sb.append("locks: "); for (int i = 0; i < frame.numLocks; ++i) { - sb.append(valueToString(frame.getLockValue(i))).append(' '); + sb.append(valueToString(frame.getLockValue(i), virtualObjects)).append(' '); } sb.append("\n"); } - sb.append("locals: "); - for (int i = 0; i < frame.numLocals; i++) { - sb.append(valueToString(frame.getLocalValue(i))).append(' '); - } - sb.append("\n"); } curCodePos = curCodePos.caller; } while (curCodePos != null); + + for (int i = 0; i < virtualObjects.size(); i++) { + CiVirtualObject obj = virtualObjects.get(i); + sb.append(obj).append(" ").append(obj.type().name()).append(" "); + for (int j = 0; j < obj.values().length; j++) { + sb.append(valueToString(obj.values()[j], virtualObjects)).append(' '); + } + sb.append("\n"); + + } } return sb.toString(); } - protected String valueToString(CiValue value) { + protected String valueToString(CiValue value, List virtualObjects) { if (value == null) { return "-"; } + if (isVirtualObject(value) && !virtualObjects.contains(asVirtualObject(value))) { + virtualObjects.add(asVirtualObject(value)); + } return value.toString(); } diff -r 382523fc390c -r fa53d5e4aa35 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompilation.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompilation.java Thu Jan 05 17:02:13 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompilation.java Thu Jan 05 17:02:58 2012 -0800 @@ -84,7 +84,7 @@ this.method = method; this.stats = stats == null ? new CiStatistics() : stats; this.registerConfig = method == null ? compiler.compilerStubRegisterConfig : compiler.runtime.getRegisterConfig(method); - this.placeholderState = debugInfoLevel == DebugInfoLevel.REF_MAPS ? new FrameState(method, 0, 0, 0, 0, false) : null; + this.placeholderState = debugInfoLevel == DebugInfoLevel.REF_MAPS ? new FrameState(method, 0, 0, 0, false) : null; if (context().isObserved() && method != null) { context().observable.fireCompilationStarted(this); @@ -394,25 +394,6 @@ return null; } - /** - * Gets the maximum number of locks in the graph's frame states. - */ - public int maxLocks() { - int maxLocks = 0; - for (FrameState node : graph.getNodes(FrameState.class)) { - int lockCount = 0; - FrameState current = node; - while (current != null) { - lockCount += current.locksSize(); - current = current.outerFrameState(); - } - if (lockCount > maxLocks) { - maxLocks = lockCount; - } - } - return maxLocks; - } - private GraalContext context() { return compiler.context; } diff -r 382523fc390c -r fa53d5e4aa35 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 Thu Jan 05 17:02:13 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/DebugInfoBuilder.java Thu Jan 05 17:02:58 2012 -0800 @@ -27,6 +27,7 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.gen.LIRGenerator.*; import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.graph.*; import com.oracle.max.graal.nodes.*; @@ -35,32 +36,20 @@ public class DebugInfoBuilder { public final GraalCompilation compilation; - private final NodeMap lockDataMap; - public DebugInfoBuilder(GraalCompilation compilation) { this.compilation = compilation; - this.lockDataMap = new NodeMap<>(compilation.graph); - } - - public CiStackSlot lockDataFor(MonitorObject object) { - CiStackSlot result = lockDataMap.get(object); - if (result == null) { - result = compilation.frameMap().allocateStackBlock(compilation.compiler.runtime.sizeOfLockData(), false); - lockDataMap.set(object, result); - } - return result; } private HashMap virtualObjects = new HashMap<>(); - public LIRDebugInfo build(FrameState topState, List pointerSlots, LabelRef exceptionEdge) { + public LIRDebugInfo build(FrameState topState, LockScope locks, List pointerSlots, LabelRef exceptionEdge) { if (compilation.placeholderState != null) { return null; } assert virtualObjects.size() == 0; - CiFrame frame = computeFrameForState(topState); + CiFrame frame = computeFrameForState(topState, locks); CiVirtualObject[] virtualObjectsArray = null; if (virtualObjects.size() != 0) { @@ -121,28 +110,37 @@ return new LIRDebugInfo(frame, virtualObjectsArray, pointerSlots, exceptionEdge); } - private CiFrame computeFrameForState(FrameState state) { - CiValue[] values = new CiValue[state.valuesSize() + state.locksSize()]; + private CiFrame computeFrameForState(FrameState state, LockScope locks) { + 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)); } - for (int i = 0; i < state.locksSize(); i++) { - MonitorObject monitorObject = state.lockAt(i); - CiValue owner = toCiValue(monitorObject.owner()); - CiValue lockData = lockDataFor(monitorObject); - boolean eliminated = owner instanceof CiVirtualObject; + LockScope nextLock = locks; + for (int i = numLocks - 1; i >= 0; i--) { + assert locks != null && nextLock.callerState == state.outerFrameState() && nextLock.stateDepth == i; - values[valueIndex++] = new CiMonitorValue(owner, lockData, eliminated); + 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); + + nextLock = nextLock.outer; } CiFrame caller = null; if (state.outerFrameState() != null) { - caller = computeFrameForState(state.outerFrameState()); + caller = computeFrameForState(state.outerFrameState(), nextLock); + } else { + if (nextLock != null) { + throw new CiBailout("unbalanced monitors: found monitor for unknown frame"); + } } - CiFrame frame = new CiFrame(caller, state.method(), state.bci, state.rethrowException(), values, state.localsSize(), state.stackSize(), state.locksSize()); + CiFrame frame = new CiFrame(caller, state.method(), state.bci, state.rethrowException(), values, state.localsSize(), state.stackSize(), numLocks); return frame; } diff -r 382523fc390c -r fa53d5e4aa35 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 Thu Jan 05 17:02:13 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Thu Jan 05 17:02:58 2012 -0800 @@ -74,6 +74,62 @@ private ValueNode lastInstructionPrinted; // Debugging only private FrameState lastState; + /** + * Class used to reconstruct the nesting of locks that is required for debug information. + */ + public static class LockScope { + /** + * Linked list of locks. {@link LIRGenerator#curLocks} is the head of the list. + */ + public final LockScope outer; + + /** + * The frame state of the caller of the method performing the lock, or null if the outermost method + * performs the lock. This information is used to compute the {@link CiFrame} that this lock belongs to. + * We cannot use the actual frame state of the locking method, because it is now unique for a method. The + * caller frame states are unique, i.e., all frame states of an inlined methods refer to the same caller frame state. + */ + public final FrameState callerState; + + /** + * The number of locks already found for this frame state. + */ + public final int stateDepth; + + /** + * The monitor enter node, with information about the object that is locked and the elimination status. + */ + public final MonitorEnterNode monitor; + + /** + * Space in the stack frame needed by the VM to perform the locking. + */ + public final CiStackSlot lockData; + + public LockScope(LockScope outer, FrameState callerState, MonitorEnterNode monitor, CiStackSlot lockData) { + this.outer = outer; + this.callerState = callerState; + this.monitor = monitor; + this.lockData = lockData; + if (outer != null && outer.callerState == callerState) { + this.stateDepth = outer.stateDepth + 1; + } else { + this.stateDepth = 0; + } + } + } + + /** + * Mapping from blocks to the lock state at the end of the block, indexed by the id number of the block. + */ + private LockScope[] blockLocks; + + /** + * The list of currently locked monitors. + */ + private LockScope curLocks; + + public LIRGenerator(GraalCompilation compilation, RiXirGenerator xir) { this.context = compilation.compiler.context; this.compilation = compilation; @@ -81,6 +137,7 @@ this.xir = xir; this.xirSupport = new XirSupport(); this.debugInfoBuilder = new DebugInfoBuilder(compilation); + this.blockLocks = new LockScope[lir.linearScanOrder().size()]; } @Override @@ -88,6 +145,13 @@ return compilation.compiler.target; } + private LockScope locksFor(LIRBlock block) { + return blockLocks[block.blockID()]; + } + + private void setLocksFor(LIRBlock block, LockScope locks) { + blockLocks[block.blockID()] = locks; + } /** * Returns the operand that has been previously initialized by {@link #setResult()} @@ -176,7 +240,7 @@ } public LIRDebugInfo stateFor(FrameState state, List pointerSlots, LabelRef exceptionEdge) { - return debugInfoBuilder.build(state, pointerSlots, exceptionEdge); + return debugInfoBuilder.build(state, curLocks, pointerSlots, exceptionEdge); } /** @@ -223,9 +287,15 @@ } if (block == lir.startBlock()) { + assert block.getPredecessors().size() == 0; emitPrologue(); - } else if (block.getPredecessors().size() > 0) { + curLocks = null; + + } else { + assert block.getPredecessors().size() > 0; FrameState fs = null; + curLocks = locksFor(block.predAt(0)); + for (Block p : block.getPredecessors()) { LIRBlock pred = (LIRBlock) p; if (fs == null) { @@ -234,6 +304,9 @@ fs = null; break; } + if (curLocks != locksFor(pred)) { + throw new CiBailout("unbalanced monitors: predecessor blocks have different monitor states"); + } } if (GraalOptions.TraceLIRGeneratorLevel >= 2) { if (fs == null) { @@ -308,6 +381,7 @@ TTY.println("END Generating LIR for block B" + block.blockID()); } + setLocksFor(currentBlock, curLocks); block.setLastState(lastState); currentBlock = null; @@ -400,18 +474,46 @@ @Override public void visitMonitorEnter(MonitorEnterNode x) { - XirArgument obj = toXirArgument(x.object().owner()); - XirArgument lockAddress = toXirArgument(emitLea(debugInfoBuilder.lockDataFor(x.object()))); + CiStackSlot lockData = compilation.frameMap().allocateStackBlock(compilation.compiler.runtime.sizeOfLockData(), false); + if (x.eliminated()) { + // No code is emitted for elimianted locks, but for proper debug information generation we need to + // register the monitor and its lock data. + curLocks = new LockScope(curLocks, x.stateAfter().outerFrameState(), x, lockData); + return; + } + + XirArgument obj = toXirArgument(x.object()); + XirArgument lockAddress = lockData == null ? null : toXirArgument(emitLea(lockData)); + + LIRDebugInfo stateBefore = state(); + // The state before the monitor enter is used for null checks, so it must not contain the newly locked object. + curLocks = new LockScope(curLocks, x.stateAfter().outerFrameState(), x, lockData); + // The state after the monitor enter is used for deotpimization, after the montior has blocked, so it must contain the newly locked object. + LIRDebugInfo stateAfter = stateFor(x.stateAfter()); + XirSnippet snippet = xir.genMonitorEnter(site(x), obj, lockAddress); - emitXir(snippet, x, state(), stateFor(x.stateAfter()), null, true); + emitXir(snippet, x, stateBefore, stateAfter, null, true); } @Override public void visitMonitorExit(MonitorExitNode x) { - XirArgument obj = toXirArgument(x.object().owner()); - XirArgument lockAddress = toXirArgument(emitLea(debugInfoBuilder.lockDataFor(x.object()))); + if (curLocks == null || curLocks.monitor.object() != x.object() || curLocks.monitor.eliminated() != x.eliminated()) { + throw new CiBailout("unbalanced monitors: attempting to unlock an object that is not on top of the locking stack"); + } + if (x.eliminated()) { + curLocks = curLocks.outer; + return; + } + + CiStackSlot lockData = curLocks.lockData; + XirArgument obj = toXirArgument(x.object()); + XirArgument lockAddress = lockData == null ? null : toXirArgument(emitLea(lockData)); + + LIRDebugInfo stateBefore = state(); + curLocks = curLocks.outer; + XirSnippet snippet = xir.genMonitorExit(site(x), obj, lockAddress); - emitXir(snippet, x, state(), null, true); + emitXir(snippet, x, stateBefore, null, true); } @Override diff -r 382523fc390c -r fa53d5e4aa35 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java Thu Jan 05 17:02:13 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java Thu Jan 05 17:02:58 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -294,23 +294,12 @@ } return false; } - if (invoke.stateAfter().locksSize() > 0) { - if (GraalOptions.TraceInlining) { - TTY.println("not inlining %s because of locks", methodName(invoke.callTarget().targetMethod(), invoke)); - } - return false; - } if (invoke.predecessor() == null) { if (GraalOptions.TraceInlining) { TTY.println("not inlining %s because the invoke is dead code", methodName(invoke.callTarget().targetMethod(), invoke)); } return false; } - if (invoke.stateAfter() == null) { - if (GraalOptions.TraceInlining) { - TTY.println("not inlining %s because of missing frame state", methodName(invoke.callTarget().targetMethod(), invoke)); - } - } return true; } diff -r 382523fc390c -r fa53d5e4aa35 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 Thu Jan 05 17:02:13 2012 -0800 +++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/FrameStateBuilder.java Thu Jan 05 17:02:58 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -41,7 +41,6 @@ private final ValueNode[] locals; private final ValueNode[] stack; - private final ArrayList locks; private int stackIndex; private boolean rethrowException; @@ -84,7 +83,6 @@ javaIndex += stackSlots(kind); index++; } - this.locks = new ArrayList<>(); } @Override @@ -103,19 +101,15 @@ for (int i = 0; i < other.stackSize(); i++) { stack[i] = other.stackAt(i); } - locks.clear(); - for (int i = 0; i < other.locksSize(); i++) { - locks.add(other.lockAt(i)); - } this.rethrowException = other.rethrowException(); } public FrameState create(int bci) { - return graph.add(new FrameState(method, bci, locals, stack, stackIndex, locks, rethrowException)); + return graph.add(new FrameState(method, bci, locals, stack, stackIndex, rethrowException)); } public FrameState duplicateWithException(int bci, ValueNode exceptionObject) { - FrameState frameState = graph.add(new FrameState(method, bci, locals, new ValueNode[]{exceptionObject}, 1, locks, true)); + FrameState frameState = graph.add(new FrameState(method, bci, locals, new ValueNode[]{exceptionObject}, 1, true)); frameState.setOuterFrameState(outerFrameState()); return frameState; } @@ -371,24 +365,6 @@ } /** - * Locks a new object within the specified IRScope. - * @param scope the IRScope in which this locking operation occurs - * @param obj the object being locked - */ - public void lock(MonitorObject obj) { - assert obj == null || (obj.kind() != CiKind.Void && obj.kind() != CiKind.Illegal) : "unexpected value: " + obj; - locks.add(obj); - } - - /** - * Unlock the lock on the top of the stack. - */ - public void unlock(MonitorObject obj) { - assert locks.get(locks.size() - 1) == obj; - locks.remove(locks.size() - 1); - } - - /** * 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 @@ -409,15 +385,6 @@ } /** - * Retrieves the lock at the specified index in the lock stack. - * @param i the index into the lock stack - * @return the instruction which produced the object at the specified location in the lock stack - */ - public final MonitorObject lockAt(int i) { - return locks.get(i); - } - - /** * Returns the size of the local variables. * * @return the size of the local variables @@ -427,13 +394,6 @@ } /** - * Gets number of locks held by this frame state. - */ - public int locksSize() { - return locks.size(); - } - - /** * Gets the current size (height) of the stack. */ public int stackSize() { @@ -448,10 +408,6 @@ return new ValueArrayIterator(locals); } - public List locks() { - return Collections.unmodifiableList(locks); - } - private static class ValueArrayIterator implements Iterator { private final ValueNode[] array; @@ -494,10 +450,8 @@ public ValueNode valueAt(int i) { if (i < locals.length) { return locals[i]; - } else if (i < locals.length + stackIndex) { + } else { return stack[i - locals.length]; - } else { - return locks.get(i - locals.length - stack.length); } } @@ -507,7 +461,7 @@ } public FrameState duplicateWithoutStack(int bci) { - FrameState frameState = graph.add(new FrameState(method, bci, locals, new ValueNode[0], 0, locks, false)); + FrameState frameState = graph.add(new FrameState(method, bci, locals, new ValueNode[0], 0, false)); frameState.setOuterFrameState(outerFrameState()); return frameState; } diff -r 382523fc390c -r fa53d5e4aa35 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 Thu Jan 05 17:02:13 2012 -0800 +++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java Thu Jan 05 17:02:58 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -1091,26 +1091,14 @@ } private MonitorEnterNode genMonitorEnter(ValueNode x) { - MonitorObject monitorObject = currentGraph.add(new MonitorObject(x)); - MonitorEnterNode monitorEnter = currentGraph.add(new MonitorEnterNode(monitorObject)); - frameState.lock(monitorObject); + MonitorEnterNode monitorEnter = currentGraph.add(new MonitorEnterNode(x)); appendWithBCI(monitorEnter); return monitorEnter; } private MonitorExitNode genMonitorExit(ValueNode x) { - if (frameState.locksSize() <= 0) { - throw new CiBailout("monitor stack underflow"); - } - MonitorObject monitorObject = frameState.lockAt(frameState.locksSize() - 1); - - // We only compile methods with balanced monitors. However, x might be a phi function - // that can be optimized away later on, so we have to disable the check for phi functions. - assert x == monitorObject.owner() || x instanceof PhiNode; - - MonitorExitNode monitorExit = currentGraph.add(new MonitorExitNode(monitorObject)); + MonitorExitNode monitorExit = currentGraph.add(new MonitorExitNode(x)); appendWithBCI(monitorExit); - frameState.unlock(monitorObject); return monitorExit; } @@ -1475,10 +1463,6 @@ ValueNode value = frameState.stackAt(i); log.println(String.format("| stack[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind().javaName, value)); } - for (int i = 0; i < frameState.locksSize(); ++i) { - ValueNode value = frameState.lockAt(i); - log.println(String.format("| lock[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind().javaName, value)); - } } } diff -r 382523fc390c -r fa53d5e4aa35 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 Thu Jan 05 17:02:13 2012 -0800 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/FrameState.java Thu Jan 05 17:02:58 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -41,8 +41,6 @@ protected final int stackSize; - protected final int locksSize; - private boolean rethrowException; /** @@ -112,38 +110,32 @@ * @param bci the bytecode index of the frame state * @param localsSize number of locals * @param stackSize size of the stack - * @param lockSize number of locks * @param rethrowException if true the VM should re-throw the exception on top of the stack when deopt'ing using this framestate */ - public FrameState(RiResolvedMethod method, int bci, int localsSize, int stackSize, int locksSize, boolean rethrowException) { + public FrameState(RiResolvedMethod method, int bci, int localsSize, int stackSize, boolean rethrowException) { assert stackSize >= 0; this.method = method; this.bci = bci; this.localsSize = localsSize; this.stackSize = stackSize; - this.locksSize = locksSize; - this.values = new NodeInputList<>(this, localsSize + stackSize + locksSize); + this.values = new NodeInputList<>(this, localsSize + stackSize); this.virtualObjectMappings = new NodeInputList<>(this); this.rethrowException = rethrowException; assert !rethrowException || stackSize == 1 : "must have exception on top of the stack"; } - public FrameState(RiResolvedMethod method, int bci, ValueNode[] locals, ValueNode[] stack, int stackSize, List locks, boolean rethrowException) { + public FrameState(RiResolvedMethod method, int bci, ValueNode[] locals, ValueNode[] stack, int stackSize, boolean rethrowException) { this.method = method; this.bci = bci; this.localsSize = locals.length; this.stackSize = stackSize; - this.locksSize = locks.size(); - final ValueNode[] newValues = new ValueNode[locals.length + stackSize + locks.size()]; + final ValueNode[] newValues = new ValueNode[locals.length + stackSize]; for (int i = 0; i < locals.length; i++) { newValues[i] = locals[i]; } for (int i = 0; i < stackSize; i++) { newValues[localsSize + i] = stack[i]; } - for (int i = 0; i < locks.size(); i++) { - newValues[locals.length + stackSize + i] = locks.get(i); - } this.values = new NodeInputList<>(this, newValues); this.virtualObjectMappings = new NodeInputList<>(this); this.rethrowException = rethrowException; @@ -183,7 +175,7 @@ } public FrameState duplicate(int newBci, boolean duplicateOuter) { - FrameState other = graph().add(new FrameState(method, newBci, localsSize, stackSize, locksSize, rethrowException)); + FrameState other = graph().add(new FrameState(method, newBci, localsSize, stackSize, rethrowException)); other.values.setAll(values); other.virtualObjectMappings.setAll(virtualObjectMappings); FrameState newOuterFrameState = outerFrameState(); @@ -207,7 +199,7 @@ public FrameState duplicateModified(int newBci, boolean newRethrowException, CiKind popKind, ValueNode... pushedValues) { int popSlots = popKind == CiKind.Void ? 0 : isTwoSlot(popKind) ? 2 : 1; int pushSlots = pushedValues.length; - FrameState other = graph().add(new FrameState(method, newBci, localsSize, stackSize - popSlots + pushSlots, locksSize(), newRethrowException)); + FrameState other = graph().add(new FrameState(method, newBci, localsSize, stackSize - popSlots + pushSlots, newRethrowException)); for (int i = 0; i < localsSize; i++) { other.setValueAt(i, localAt(i)); } @@ -218,16 +210,13 @@ for (int i = 0; i < pushSlots; i++) { other.setValueAt(slot++, pushedValues[i]); } - for (int i = 0; i < locksSize; i++) { - other.setValueAt(localsSize + other.stackSize + i, lockAt(i)); - } other.virtualObjectMappings.setAll(virtualObjectMappings); other.setOuterFrameState(outerFrameState()); return other; } public boolean isCompatibleWith(FrameStateAccess other) { - if (stackSize() != other.stackSize() || localsSize() != other.localsSize() || locksSize() != other.locksSize()) { + if (stackSize() != other.stackSize() || localsSize() != other.localsSize()) { return false; } for (int i = 0; i < stackSize(); i++) { @@ -237,11 +226,6 @@ return false; } } - for (int i = 0; i < locksSize(); i++) { - if (lockAt(i) != other.lockAt(i)) { - return false; - } - } if (other.outerFrameState() != outerFrameState()) { return false; } @@ -249,7 +233,7 @@ } public boolean equals(FrameStateAccess other) { - if (stackSize() != other.stackSize() || localsSize() != other.localsSize() || locksSize() != other.locksSize()) { + if (stackSize() != other.stackSize() || localsSize() != other.localsSize()) { return false; } for (int i = 0; i < stackSize(); i++) { @@ -259,11 +243,6 @@ return false; } } - for (int i = 0; i < locksSize(); i++) { - if (lockAt(i) != other.lockAt(i)) { - return false; - } - } if (other.outerFrameState() != outerFrameState()) { return false; } @@ -285,13 +264,6 @@ } /** - * Gets number of locks held by this frame state. - */ - public int locksSize() { - return locksSize; - } - - /** * Invalidates the local variable at the specified index. If the specified index refers to a doubleword local, then * invalidates the high word as well. * @@ -352,16 +324,6 @@ } /** - * Retrieves the lock at the specified index in the lock stack. - * @param i the index into the lock stack - * @return the instruction which produced the object at the specified location in the lock stack - */ - public MonitorObject lockAt(int i) { - assert i >= 0; - return (MonitorObject) valueAt(localsSize + stackSize + 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 @@ -411,7 +373,7 @@ * @return the value at index {@code i} which may be {@code null} */ public ValueNode valueAt(int i) { - assert i < (localsSize + stackSize + locksSize); + assert i < (localsSize + stackSize); return values.isEmpty() ? null : values.get(i); } @@ -607,10 +569,6 @@ ValueNode value = stackAt(i); sb.append(String.format(" stack[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind().javaName, value)); } - for (int i = 0; i < locksSize(); ++i) { - ValueNode value = lockAt(i); - sb.append(String.format(" lock[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind().javaName, value)); - } return sb.toString(); } @@ -633,10 +591,6 @@ ValueNode value = fs.stackAt(i); sb.append(String.format(" stack[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind().javaName, value)); } - for (int i = 0; i < fs.locksSize(); ++i) { - ValueNode value = fs.lockAt(i); - sb.append(String.format(" lock[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind().javaName, value)); - } fs = fs.outerFrameState(); } return sb.toString(); @@ -684,11 +638,6 @@ str.append(i == 0 ? "" : ", ").append(stackAt(i) == null ? "_" : stackAt(i).toString(Verbosity.Id)); } properties.put("stack", str.toString()); - str = new StringBuilder(); - for (int i = 0; i < locksSize(); i++) { - str.append(i == 0 ? "" : ", ").append(lockAt(i) == null ? "_" : lockAt(i).toString(Verbosity.Id)); - } - properties.put("locks", str.toString()); properties.put("rethrowException", rethrowException); return properties; } diff -r 382523fc390c -r fa53d5e4aa35 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/MonitorObject.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/MonitorObject.java Thu Jan 05 17:02:13 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2011, 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.nodes.java.*; -import com.oracle.max.graal.nodes.spi.*; - -/** - * Encapsulates the object that is locked and unlocked. This node is referenced by a {@link MonitorEnterNode}, - * all {@link MonitorExitNode} that correspond to this monitor enter, and in all {@link FrameState}s in between - * the monitor enter and monitor exits. - */ -public class MonitorObject extends ValueNode implements LIRLowerable { - @Input private ValueNode owner; - - public ValueNode owner() { - return owner; - } - - /** - * Creates a new MonitorObjectNode. - * - * @param object The object that is processed by the monitor operation. - */ - public MonitorObject(ValueNode object) { - super(object.stamp()); - this.owner = object; - } - - @Override - public void generate(LIRGeneratorTool gen) { - // Nothing to do, monitor objects are processed as part of the monitor enter / monitor exit nodes. - } -} diff -r 382523fc390c -r fa53d5e4aa35 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/AccessMonitorNode.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/AccessMonitorNode.java Thu Jan 05 17:02:13 2012 -0800 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/AccessMonitorNode.java Thu Jan 05 17:02:58 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,19 +22,42 @@ */ package com.oracle.max.graal.nodes.java; +import com.oracle.max.cri.ci.*; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.extended.*; import com.oracle.max.graal.nodes.type.*; /** * The {@code AccessMonitorNode} is the base class of both monitor acquisition and release. + *
+ * The VM needs information about monitors in the debug information. This information is built from + * the nesting level of {@link MonitorEnterNode} when the LIR is constructed. Therefore, monitor + * nodes must not be removed from the graph unless it is guaranteed that the nesting level does not change. + * For example, you must not remove a {@link MonitorEnterNode} for a thread-local object or for a recursive locking. + * Instead, mark the node as {@link #eliminated}. This makes sure that the meta data still contains the complete + * locking hierarchy. + *
+ * The Java bytecode specification allows non-balanced locking. Graal does not handle such cases and throws a + * {@link CiBailout} instead. Detecting non-balanced monitors during bytecode parsing is difficult, since the + * node flowing into the {@link MonitorExitNode} can be a phi function hiding the node that was flowing into the + * {@link MonitorEnterNode}. Optimization phases are free to throw {@link CiBailout} if they detect such cases. + * Otherwise, they are detected during LIR construction. */ public abstract class AccessMonitorNode extends AbstractStateSplit implements MemoryCheckpoint { - @Input private MonitorObject object; + @Input private ValueNode object; + @Data private boolean eliminated; + + public ValueNode object() { + return object; + } - public MonitorObject object() { - return object; + public boolean eliminated() { + return eliminated; + } + + public void makeEliminated() { + eliminated = true; } /** @@ -42,7 +65,7 @@ * * @param object the instruction producing the object */ - public AccessMonitorNode(MonitorObject object) { + public AccessMonitorNode(ValueNode object) { super(StampFactory.illegal()); this.object = object; } diff -r 382523fc390c -r fa53d5e4aa35 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/MonitorEnterNode.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/MonitorEnterNode.java Thu Jan 05 17:02:13 2012 -0800 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/MonitorEnterNode.java Thu Jan 05 17:02:58 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -35,7 +35,7 @@ * * @param object the instruction producing the object */ - public MonitorEnterNode(MonitorObject object) { + public MonitorEnterNode(ValueNode object) { super(object); } diff -r 382523fc390c -r fa53d5e4aa35 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/MonitorExitNode.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/MonitorExitNode.java Thu Jan 05 17:02:13 2012 -0800 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/MonitorExitNode.java Thu Jan 05 17:02:58 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -36,7 +36,7 @@ * * @param object the instruction produces the object value */ - public MonitorExitNode(MonitorObject object) { + public MonitorExitNode(ValueNode object) { super(object); } diff -r 382523fc390c -r fa53d5e4aa35 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/EscapeOp.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/EscapeOp.java Thu Jan 05 17:02:13 2012 -0800 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/EscapeOp.java Thu Jan 05 17:02:58 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -46,8 +46,8 @@ } else if (usage instanceof FrameState) { assert ((FrameState) usage).inputs().contains(node); return true; - } else if (usage instanceof MonitorObject) { - assert ((MonitorObject) usage).owner() == node; + } else if (usage instanceof AccessMonitorNode) { + assert ((AccessMonitorNode) usage).object() == node; return false; } else if (usage instanceof LoadFieldNode) { assert ((LoadFieldNode) usage).object() == node; @@ -107,14 +107,8 @@ IsTypeNode x = (IsTypeNode) usage; assert x.type() == ((ValueNode) node).exactType(); x.replaceAndDelete(ConstantNode.forBoolean(true, node.graph())); - } else if (usage instanceof MonitorObject) { - // delete all MonitorEnterNode and MonitorExitNode - for (Node n : usage.usages().snapshot()) { - if (n instanceof AccessMonitorNode) { - AccessMonitorNode x = (AccessMonitorNode) n; - x.replaceAndDelete(x.next()); - } - } + } else if (usage instanceof AccessMonitorNode) { + ((AccessMonitorNode) usage).makeEliminated(); } } diff -r 382523fc390c -r fa53d5e4aa35 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 Thu Jan 05 17:02:13 2012 -0800 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/FrameStateAccess.java Thu Jan 05 17:02:58 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,16 +32,12 @@ int stackSize(); - int locksSize(); - boolean rethrowException(); ValueNode valueAt(int i); ValueNode localAt(int i); - ValueNode lockAt(int i); - ValueNode stackAt(int i); FrameState outerFrameState(); diff -r 382523fc390c -r fa53d5e4aa35 graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinter.java --- a/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinter.java Thu Jan 05 17:02:13 2012 -0800 +++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinter.java Thu Jan 05 17:02:58 2012 -0800 @@ -316,14 +316,6 @@ buf.append("\n"); } - if (curState.locksSize() > 0) { - buf.append("locks: "); - for (int i = 0; i < curState.locksSize(); ++i) { - buf.append(stateValueToString(curState.lockAt(i))).append(' '); - } - buf.append("\n"); - } - buf.append("locals: "); for (int i = 0; i < curState.localsSize(); i++) { buf.append(stateValueToString(curState.localAt(i))).append(' ');