# HG changeset patch # User Michael Van De Vanter # Date 1389224958 28800 # Node ID d7af2296cebba181a209d18bb385a569f7b98ae0 # Parent 1894412de0ed295c2252b886d4417bfbd846e8dd# Parent 4fc8c8bb4c32878cc04b064d2ac9ad1fce1a85e0 Merge with 4fc8c8bb4c32878cc04b064d2ac9ad1fce1a85e0 diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Wed Jan 08 15:49:18 2014 -0800 @@ -147,7 +147,6 @@ @Override public AMD64AddressValue emitAddress(Value base, long displacement, Value index, int scale) { - assert (scale >= 1 && scale <= 8) || index.equals(Value.ILLEGAL) : "invalid scale"; AllocatableValue baseRegister; long finalDisp = displacement; if (isConstant(base)) { diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Wed Jan 08 15:49:18 2014 -0800 @@ -1839,7 +1839,7 @@ /* * This is the point to enable debug logging for the whole register allocation. */ - Indent indent = Debug.logAndIndent(false, "LinearScan allocate %s", gen.getGraph().method()); + Indent indent = Debug.logAndIndent("LinearScan allocate %s", gen.getGraph().method()); try (Scope s = Debug.scope("LifetimeAnalysis")) { numberInstructions(); @@ -1942,7 +1942,7 @@ private void verifyRegisters() { // Enable this logging to get output for the verification process. - try (Indent indent = Debug.logAndIndent(false, "verifying register allocation")) { + try (Indent indent = Debug.logAndIndent("verifying register allocation")) { RegisterVerifier verifier = new RegisterVerifier(this); verifier.verify(blockAt(0)); } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java Wed Jan 08 15:49:18 2014 -0800 @@ -572,7 +572,7 @@ // ignored safely if (Debug.isLogEnabled()) { // Enable this logging to see all register states - try (Indent indent2 = Debug.logAndIndent(false, "state of registers:")) { + try (Indent indent2 = Debug.logAndIndent("state of registers:")) { for (Register register : availableRegs) { int i = register.number; Debug.log("reg %d: usePos: %d", register.number, usePos[i]); diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Wed Jan 08 15:49:18 2014 -0800 @@ -169,7 +169,7 @@ */ public static Scope scope(String name, Object... context) { if (ENABLED) { - return DebugScope.getInstance().scope(name, false, null, context); + return DebugScope.getInstance().scope(name, null, context); } else { return null; } @@ -198,7 +198,7 @@ public static Scope sandbox(String name, DebugConfig config, Object... context) { if (ENABLED) { DebugConfig sandboxConfig = config == null ? silentConfig() : config; - return DebugScope.getInstance().scope(name, true, sandboxConfig, context); + return DebugScope.getInstance().scope(name, sandboxConfig, context); } else { return null; } @@ -263,10 +263,6 @@ } @Override - public void setEnabled(boolean enabled) { - } - - @Override public Indent indent() { return this; } @@ -304,22 +300,6 @@ } /** - * Creates a new indentation level based on the last used Indent of the current DebugScope and - * turns on/off logging. - * - * @param enabled If true, logging is enabled, otherwise disabled - * @return The new indentation level - */ - public static Indent indent(boolean enabled) { - if (ENABLED) { - Indent logger = DebugScope.getInstance().pushIndentLogger(); - logger.setEnabled(enabled); - return logger; - } - return noLoggerInstance; - } - - /** * A convenience function which combines {@link #log} and {@link #indent()}. * * @param msg The format string of the log message @@ -336,28 +316,6 @@ return noLoggerInstance; } - /** - * A convenience function which combines {@link #log} and {@link #indent(boolean)}. - * - * @param enabled If true, logging is enabled, otherwise disabled - * @param msg The format string of the log message - * @param args The arguments referenced by the log message string - * @return The new indentation level - */ - public static Indent logAndIndent(boolean enabled, String msg, Object... args) { - if (ENABLED) { - DebugScope scope = DebugScope.getInstance(); - boolean saveLogEnabled = scope.isLogEnabled(); - scope.setLogEnabled(enabled); - scope.log(msg, args); - scope.setLogEnabled(saveLogEnabled); - Indent indent = scope.pushIndentLogger(); - indent.setEnabled(enabled); - return indent; - } - return noLoggerInstance; - } - public static Iterable context() { if (ENABLED) { return DebugScope.getInstance().getCurrentContext(); diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Indent.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Indent.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Indent.java Wed Jan 08 15:49:18 2014 -0800 @@ -73,13 +73,6 @@ void log(String msg, Object... args); /** - * Turns on/off logging for this indentation level. - * - * @param enabled If true, logging is enabled, otherwise disabled - */ - void setEnabled(boolean enabled); - - /** * Creates a new indentation level (by adding some spaces). * * @return The new indentation level diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java Wed Jan 08 15:49:18 2014 -0800 @@ -35,13 +35,11 @@ private static final String INDENTATION_INCREMENT = " "; final String indent; - boolean enabled; final IndentImpl parentIndent; - IndentImpl(IndentImpl parentIndent, boolean enabled) { + IndentImpl(IndentImpl parentIndent) { this.parentIndent = parentIndent; this.indent = (parentIndent == null ? "" : parentIndent.indent + INDENTATION_INCREMENT); - this.enabled = enabled; } private void printScopeName() { @@ -56,7 +54,7 @@ @Override public void log(String msg, Object... args) { - if (enabled) { + if (isLogEnabled()) { printScopeName(); output.println(indent + String.format(msg, args)); lastUsedIndent = this; @@ -64,13 +62,8 @@ } @Override - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - @Override public Indent indent() { - lastUsedIndent = new IndentImpl(this, enabled); + lastUsedIndent = new IndentImpl(this); return lastUsedIndent; } @@ -115,6 +108,7 @@ private boolean meterEnabled; private boolean timeEnabled; private boolean dumpEnabled; + private boolean logEnabled; private PrintStream output; @@ -141,10 +135,10 @@ this.context = context; this.qualifiedName = qualifiedName; if (parent != null) { - lastUsedIndent = new IndentImpl(parent.lastUsedIndent, parent.isLogEnabled()); + lastUsedIndent = new IndentImpl(parent.lastUsedIndent); logScopeName = !parent.qualifiedName.equals(qualifiedName); } else { - lastUsedIndent = new IndentImpl(null, false); + lastUsedIndent = new IndentImpl(null); logScopeName = true; } @@ -169,7 +163,7 @@ public void close() { instanceTL.set(parent); - setConfig(parentConfig); + configTL.set(parentConfig); lastClosedTL.set(this); } @@ -178,11 +172,7 @@ } public boolean isLogEnabled() { - return lastUsedIndent.enabled; - } - - public void setLogEnabled(boolean enabled) { - lastUsedIndent.setEnabled(enabled); + return logEnabled; } public boolean isMeterEnabled() { @@ -236,23 +226,21 @@ * disjoint top level scope. * * @param name the name of the new scope - * @param sandbox specifies if the scope is a child of the current scope or a top level scope - * @param sandboxConfig the configuration to use for a new top level scope (ignored if - * {@code sandbox == false}) + * @param sandboxConfig the configuration to use for a new top level scope, or null if the new + * scope should be a child scope * @param context objects to be appended to the debug context * @return the new scope which will be exited when its {@link #close()} method is called */ @SuppressWarnings("hiding") - public DebugScope scope(String name, boolean sandbox, DebugConfig sandboxConfig, Object... context) { + public DebugScope scope(String name, DebugConfig sandboxConfig, Object... context) { DebugScope newScope = null; - if (sandbox) { + if (sandboxConfig != null) { newScope = new DebugScope(name, name, this, true, context); - setConfig(sandboxConfig); + configTL.set(sandboxConfig); } else { newScope = this.createChild(name, context); } instanceTL.set(newScope); - newScope.setLogEnabled(this.isLogEnabled()); newScope.updateFlags(); return newScope; } @@ -298,17 +286,15 @@ meterEnabled = config.isMeterEnabled(); timeEnabled = config.isTimeEnabled(); dumpEnabled = config.isDumpEnabled(); + logEnabled = config.isLogEnabled(); output = config.output(); - if (config.isLogEnabled()) { - setLogEnabled(true); - } } } private RuntimeException interceptException(final Throwable e) { final DebugConfig config = getConfig(); if (config != null) { - try (DebugScope s = scope("InterceptException", false, null, e)) { + try (DebugScope s = scope("InterceptException", null, e)) { return config.interceptException(e); } catch (Throwable t) { return new RuntimeException("Exception while intercepting exception", t); diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java Wed Jan 08 15:49:18 2014 -0800 @@ -46,7 +46,7 @@ } protected NodeList(T[] elements) { - if (elements == null) { + if (elements == null || elements.length == 0) { this.size = 0; this.nodes = EMPTY_NODE_ARRAY; this.initialSize = 0; diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java Wed Jan 08 15:49:18 2014 -0800 @@ -48,13 +48,13 @@ } @Override - protected Value computeLockValue(FrameState state, int i) { - int lockDepth = i; + protected Value computeLockValue(FrameState state, int lockIndex) { + int lockDepth = lockIndex; if (state.outerFrameState() != null) { lockDepth += state.outerFrameState().nestedLockDepth(); } StackSlot slot = lockStack.makeLockSlot(lockDepth); - ValueNode lock = state.lockAt(i); + ValueNode lock = state.lockAt(lockIndex); Value object = toValue(lock); boolean eliminated = lock instanceof VirtualObjectNode; return new HotSpotMonitorValue(object, slot, eliminated); diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java Wed Jan 08 15:49:18 2014 -0800 @@ -310,67 +310,42 @@ FixedWithNextNode newObject; if (virtual instanceof VirtualInstanceNode) { newObject = graph.add(new NewInstanceNode(virtual.type(), true)); - graph.addBeforeFixed(commit, newObject); - allocations[objIndex] = newObject; - for (int i = 0; i < entryCount; i++) { - ValueNode value = commit.getValues().get(valuePos); - if (value instanceof VirtualObjectNode) { - value = allocations[commit.getVirtualObjects().indexOf(value)]; - } - if (value == null) { - omittedValues.set(valuePos); - } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { - // Constant.illegal is always the defaultForKind, so it is skipped - VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual; - Kind accessKind; - HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) virtualInstance.field(i); - if (value.kind().getStackKind() != field.getKind().getStackKind()) { - assert value.kind() == Kind.Long || value.kind() == Kind.Double; - accessKind = value.kind(); - } else { - accessKind = field.getKind(); - } - ConstantLocationNode location = ConstantLocationNode.create(INIT_LOCATION, accessKind, field.offset(), graph); - BarrierType barrierType = (virtualInstance.field(i).getKind() == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE; - WriteNode write = new WriteNode(newObject, value, location, barrierType, virtualInstance.field(i).getKind() == Kind.Object); - graph.addAfterFixed(newObject, graph.add(write)); - } - valuePos++; + } else { + newObject = graph.add(new NewArrayNode(((VirtualArrayNode) virtual).componentType(), ConstantNode.forInt(entryCount, graph), true)); + } + graph.addBeforeFixed(commit, newObject); + allocations[objIndex] = newObject; + for (int i = 0; i < entryCount; i++) { + ValueNode value = commit.getValues().get(valuePos); + if (value instanceof VirtualObjectNode) { + value = allocations[commit.getVirtualObjects().indexOf(value)]; } - } else { - ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType(); - newObject = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount, graph), true)); - graph.addBeforeFixed(commit, newObject); - allocations[objIndex] = newObject; - for (int i = 0; i < entryCount; i++) { - ValueNode value = commit.getValues().get(valuePos); - if (value instanceof VirtualObjectNode) { - value = allocations[commit.getVirtualObjects().indexOf(value)]; + if (value == null) { + omittedValues.set(valuePos); + } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { + // Constant.illegal is always the defaultForKind, so it is skipped + Kind valueKind = value.kind(); + Kind entryKind = virtual.entryKind(i); + + // Truffle requires some leniency in terms of what can be put where: + Kind accessKind = valueKind.getStackKind() == entryKind.getStackKind() ? entryKind : valueKind; + assert valueKind.getStackKind() == entryKind.getStackKind() || + (valueKind == Kind.Long || valueKind == Kind.Double || (valueKind == Kind.Int && virtual instanceof VirtualArrayNode)); + ConstantLocationNode location; + BarrierType barrierType; + if (virtual instanceof VirtualInstanceNode) { + ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i); + location = ConstantLocationNode.create(INIT_LOCATION, accessKind, ((HotSpotResolvedJavaField) field).offset(), graph); + barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE; + } else { + location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(entryKind) + i * getScalingFactor(entryKind), graph); + barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.PRECISE : BarrierType.NONE; } - if (value == null) { - omittedValues.set(valuePos); - } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { - // Constant.illegal is always the defaultForKind, so it is skipped - Kind componentKind = element.getKind(); - Kind accessKind; - Kind valueKind = value.kind(); - if (valueKind.getStackKind() != componentKind.getStackKind()) { - // Given how Truffle uses unsafe, it can happen that - // valueKind is Kind.Int - // assert valueKind == Kind.Long || valueKind == Kind.Double; - accessKind = valueKind; - } else { - accessKind = componentKind; - } + WriteNode write = new WriteNode(newObject, value, location, barrierType, entryKind == Kind.Object); + graph.addAfterFixed(newObject, graph.add(write)); + } + valuePos++; - int scale = getScalingFactor(componentKind); - ConstantLocationNode location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(componentKind) + i * scale, graph); - BarrierType barrierType = (componentKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.PRECISE : BarrierType.NONE; - WriteNode write = new WriteNode(newObject, value, location, barrierType, componentKind == Kind.Object); - graph.addAfterFixed(newObject, graph.add(write)); - } - valuePos++; - } } } valuePos = 0; @@ -379,58 +354,28 @@ VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); int entryCount = virtual.entryCount(); ValueNode newObject = allocations[objIndex]; - if (virtual instanceof VirtualInstanceNode) { - for (int i = 0; i < entryCount; i++) { - if (omittedValues.get(valuePos)) { - ValueNode value = commit.getValues().get(valuePos); - assert value instanceof VirtualObjectNode; - ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)]; - if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) { + for (int i = 0; i < entryCount; i++) { + if (omittedValues.get(valuePos)) { + ValueNode value = commit.getValues().get(valuePos); + assert value instanceof VirtualObjectNode; + ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)]; + if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) { + assert virtual.entryKind(i) == Kind.Object && allocValue.kind() == Kind.Object; + WriteNode write; + if (virtual instanceof VirtualInstanceNode) { VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual; - assert virtualInstance.field(i).getKind() == Kind.Object; - WriteNode write = new WriteNode(newObject, allocValue, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i), true), - BarrierType.IMPRECISE, true); - graph.addBeforeFixed(commit, graph.add(write)); + write = new WriteNode(newObject, allocValue, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i), true), BarrierType.IMPRECISE, true); + } else { + write = new WriteNode(newObject, allocValue, createArrayLocation(graph, virtual.entryKind(i), ConstantNode.forInt(i, graph), true), BarrierType.PRECISE, true); } + graph.addBeforeFixed(commit, graph.add(write)); } - valuePos++; } - } else { - ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType(); - for (int i = 0; i < entryCount; i++) { - if (omittedValues.get(valuePos)) { - ValueNode value = commit.getValues().get(valuePos); - assert value instanceof VirtualObjectNode; - ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)]; - if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) { - assert allocValue.kind() == Kind.Object; - WriteNode write = new WriteNode(newObject, allocValue, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph), true), BarrierType.PRECISE, - true); - graph.addBeforeFixed(commit, graph.add(write)); - } - } - valuePos++; - } + valuePos++; } } - for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { - FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex])); - allocations[objIndex] = anchor; - graph.addBeforeFixed(commit, anchor); - } - for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { - for (int lockDepth : commit.getLocks().get(objIndex)) { - MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], lockDepth)); - graph.addBeforeFixed(commit, enter); - enter.lower(tool); - } - } - for (Node usage : commit.usages().snapshot()) { - AllocatedObjectNode addObject = (AllocatedObjectNode) usage; - int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject()); - graph.replaceFloating(addObject, allocations[index]); - } + finishAllocatedObjects(tool, commit, allocations); graph.removeFixed(commit); } } else if (n instanceof OSRStartNode) { @@ -529,6 +474,27 @@ } } + protected static void finishAllocatedObjects(LoweringTool tool, CommitAllocationNode commit, ValueNode[] allocations) { + StructuredGraph graph = commit.graph(); + for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { + FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex])); + allocations[objIndex] = anchor; + graph.addBeforeFixed(commit, anchor); + } + for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { + for (MonitorIdNode monitorId : commit.getLocks(objIndex)) { + MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], monitorId)); + graph.addBeforeFixed(commit, enter); + enter.lower(tool); + } + } + for (Node usage : commit.usages().snapshot()) { + AllocatedObjectNode addObject = (AllocatedObjectNode) usage; + int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject()); + graph.replaceFloating(addObject, allocations[index]); + } + } + private static LocationNode createLocation(UnsafeAccessNode access) { ValueNode offset = access.offset(); if (offset.isConstant()) { diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Wed Jan 08 15:49:18 2014 -0800 @@ -434,7 +434,7 @@ args = new Arguments(monitorenterStub, graph.getGuardsStage(), tool.getLoweringStage()); } args.add("object", monitorenterNode.object()); - args.addConst("lockDepth", monitorenterNode.getLockDepth()); + args.addConst("lockDepth", monitorenterNode.getMonitorId().getLockDepth()); boolean tracingEnabledForMethod = stateAfter != null && (isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); args.addConst("threadRegister", registers.getThreadRegister()); args.addConst("stackPointerRegister", registers.getStackPointerRegister()); @@ -461,7 +461,7 @@ args = new Arguments(monitorexitStub, graph.getGuardsStage(), tool.getLoweringStage()); } args.add("object", monitorexitNode.object()); - args.addConst("lockDepth", monitorexitNode.getLockDepth()); + args.addConst("lockDepth", monitorexitNode.getMonitorId().getLockDepth()); args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); Map nodes = template(args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args); @@ -529,7 +529,7 @@ callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, checkCounter.getMethod(), new ValueNode[]{errMsg}, returnType)); invoke = graph.add(new InvokeNode(callTarget, 0)); List stack = Collections.emptyList(); - FrameState stateAfter = new FrameState(graph.method(), FrameState.AFTER_BCI, new ValueNode[0], stack, new ValueNode[0], false, false); + FrameState stateAfter = new FrameState(graph.method(), FrameState.AFTER_BCI, new ValueNode[0], stack, new ValueNode[0], new MonitorIdNode[0], false, false); invoke.setStateAfter(graph.add(stateAfter)); graph.addBeforeFixed(ret, invoke); diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -25,6 +25,7 @@ import static com.oracle.graal.compiler.GraalCompiler.*; import java.lang.reflect.*; +import java.util.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; @@ -138,7 +139,7 @@ newEntryState[i] = originalState.getEntry(i); } VirtualObjectNode newVirtual = originalVirtual.duplicate(); - tool.createVirtualObject(newVirtual, newEntryState, null); + tool.createVirtualObject(newVirtual, newEntryState, Collections. emptyList()); tool.replaceWithVirtual(newVirtual); } } else { @@ -159,7 +160,7 @@ state[i] = loads[i] = new LoadFieldNode(obj, fields[i]); tool.addNode(loads[i]); } - tool.createVirtualObject(newVirtual, state, null); + tool.createVirtualObject(newVirtual, state, Collections. emptyList()); tool.replaceWithVirtual(newVirtual); } } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Wed Jan 08 15:49:18 2014 -0800 @@ -34,19 +34,22 @@ import com.oracle.graal.graph.Node.Verbosity; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; public class FrameStateBuilder { private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; + private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; private final ResolvedJavaMethod method; private final StructuredGraph graph; private final ValueNode[] locals; private final ValueNode[] stack; - private ValueNode[] locks; + private ValueNode[] lockedObjects; + private MonitorIdNode[] monitorIds; private int stackSize; @@ -62,7 +65,8 @@ this.locals = new ValueNode[method.getMaxLocals()]; // we always need at least one stack slot (for exceptions) this.stack = new ValueNode[Math.max(1, method.getMaxStackSize())]; - this.locks = EMPTY_ARRAY; + this.lockedObjects = EMPTY_ARRAY; + this.monitorIds = EMPTY_MONITOR_ARRAY; int javaIndex = 0; int index = 0; @@ -100,12 +104,14 @@ graph = other.graph; locals = other.locals.clone(); stack = other.stack.clone(); - locks = other.locks == EMPTY_ARRAY ? EMPTY_ARRAY : other.locks.clone(); + lockedObjects = other.lockedObjects == EMPTY_ARRAY ? EMPTY_ARRAY : other.lockedObjects.clone(); + monitorIds = other.monitorIds == EMPTY_MONITOR_ARRAY ? EMPTY_MONITOR_ARRAY : other.monitorIds.clone(); stackSize = other.stackSize; rethrowException = other.rethrowException; assert locals.length == method.getMaxLocals(); assert stack.length == Math.max(1, method.getMaxStackSize()); + assert lockedObjects.length == monitorIds.length; } @Override @@ -120,8 +126,8 @@ sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString(Verbosity.Id)); } sb.append("] locks: ["); - for (int i = 0; i < locks.length; i++) { - sb.append(i == 0 ? "" : ",").append(locks[i] == null ? "_" : locks[i].toString(Verbosity.Id)); + for (int i = 0; i < lockedObjects.length; i++) { + sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id)); } sb.append("]"); if (rethrowException) { @@ -132,7 +138,7 @@ } public FrameState create(int bci) { - return graph.add(new FrameState(method, bci, locals, Arrays.asList(stack).subList(0, stackSize), locks, rethrowException, false)); + return graph.add(new FrameState(method, bci, locals, Arrays.asList(stack).subList(0, stackSize), lockedObjects, monitorIds, rethrowException, false)); } public FrameStateBuilder copy() { @@ -141,6 +147,7 @@ public boolean isCompatibleWith(FrameStateBuilder other) { assert method == other.method && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method"; + assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds"; if (stackSize() != other.stackSize()) { return false; @@ -152,11 +159,11 @@ return false; } } - if (locks.length != other.locks.length) { + if (lockedObjects.length != other.lockedObjects.length) { return false; } - for (int i = 0; i < locks.length; i++) { - if (GraphUtil.originalValue(locks[i]) != GraphUtil.originalValue(other.locks[i])) { + for (int i = 0; i < lockedObjects.length; i++) { + if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) { throw new BailoutException("unbalanced monitors"); } } @@ -172,8 +179,9 @@ for (int i = 0; i < stackSize(); i++) { storeStack(i, merge(stackAt(i), other.stackAt(i), block)); } - for (int i = 0; i < locks.length; i++) { - locks[i] = merge(locks[i], other.locks[i], block); + for (int i = 0; i < lockedObjects.length; i++) { + lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block); + assert monitorIds[i] == other.monitorIds[i]; } } @@ -234,8 +242,8 @@ for (int i = 0; i < stackSize(); i++) { storeStack(i, createLoopPhi(loopBegin, stackAt(i))); } - for (int i = 0; i < locks.length; i++) { - locks[i] = createLoopPhi(loopBegin, locks[i]); + for (int i = 0; i < lockedObjects.length; i++) { + lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i]); } } @@ -254,11 +262,11 @@ storeStack(i, ProxyNode.forValue(value, loopExit, graph)); } } - for (int i = 0; i < locks.length; i++) { - ValueNode value = locks[i]; + for (int i = 0; i < lockedObjects.length; i++) { + ValueNode value = lockedObjects[i]; if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { Debug.log(" inserting proxy for %s", value); - locks[i] = ProxyNode.forValue(value, loopExit, graph); + lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph); } } } @@ -278,11 +286,11 @@ storeStack(i, ProxyNode.forValue(value, begin, graph)); } } - for (int i = 0; i < locks.length; i++) { - ValueNode value = locks[i]; + for (int i = 0; i < lockedObjects.length; i++) { + ValueNode value = lockedObjects[i]; if (value != null) { Debug.log(" inserting proxy for %s", value); - locks[i] = ProxyNode.forValue(value, begin, graph); + lockedObjects[i] = ProxyNode.forValue(value, begin, graph); } } } @@ -373,10 +381,13 @@ * * @param object the object whose monitor will be locked. */ - public void pushLock(ValueNode object) { + public void pushLock(ValueNode object, MonitorIdNode monitorId) { assert object.isAlive() && object.kind() == Kind.Object : "unexpected value: " + object; - locks = Arrays.copyOf(locks, locks.length + 1); - locks[locks.length - 1] = object; + lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1); + monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1); + lockedObjects[lockedObjects.length - 1] = object; + monitorIds[monitorIds.length - 1] = monitorId; + assert lockedObjects.length == monitorIds.length; } /** @@ -386,17 +397,23 @@ */ public ValueNode popLock() { try { - return locks[locks.length - 1]; + return lockedObjects[lockedObjects.length - 1]; } finally { - locks = locks.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(locks, locks.length - 1); + lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1); + monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1); } } + public MonitorIdNode peekMonitorId() { + return monitorIds[monitorIds.length - 1]; + } + /** * @return the current lock depth */ public int lockDepth() { - return locks.length; + assert lockedObjects.length == monitorIds.length; + return lockedObjects.length; } /** @@ -660,8 +677,9 @@ return true; } } - for (int i = 0; i < locks.length; i++) { - if (locks[i] == value) { + assert lockedObjects.length == monitorIds.length; + for (int i = 0; i < lockedObjects.length; i++) { + if (lockedObjects[i] == value || monitorIds[i] == value) { return true; } } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Jan 08 15:49:18 2014 -0800 @@ -217,7 +217,7 @@ TTY.println(MetaUtil.indent(MetaUtil.profileToString(profilingInfo, method, CodeUtil.NEW_LINE), " ")); } - Indent indent = Debug.logAndIndent(false, "build graph for %s", method); + Indent indent = Debug.logAndIndent("build graph for %s", method); // compute the block map, setup exception handlers and get the entrypoint(s) BciBlockMapping blockMap = createBlockMap(); @@ -1247,17 +1247,19 @@ } private MonitorEnterNode genMonitorEnter(ValueNode x) { - MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, frameState.lockDepth())); - frameState.pushLock(x); + MonitorIdNode monitorId = currentGraph.add(new MonitorIdNode(frameState.lockDepth())); + MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, monitorId)); + frameState.pushLock(x, monitorId); return monitorEnter; } private MonitorExitNode genMonitorExit(ValueNode x, ValueNode returnValue) { + MonitorIdNode monitorId = frameState.peekMonitorId(); ValueNode lockedObject = frameState.popLock(); if (GraphUtil.originalValue(lockedObject) != GraphUtil.originalValue(x)) { throw new BailoutException("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject)); } - MonitorExitNode monitorExit = append(new MonitorExitNode(x, returnValue, frameState.lockDepth())); + MonitorExitNode monitorExit = append(new MonitorExitNode(x, monitorId, returnValue)); return monitorExit; } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java Wed Jan 08 15:49:18 2014 -0800 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.VirtualState.NodeClosure; import com.oracle.graal.nodes.VirtualState.VirtualClosure; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.virtual.*; public abstract class LoopFragment { @@ -198,11 +199,13 @@ markFloating(obj, nodes, notloopNodes); } } + if (n instanceof MonitorEnterNode) { + markFloating(((MonitorEnterNode) n).getMonitorId(), nodes, notloopNodes); + } for (Node usage : n.usages()) { markFloating(usage, nodes, notloopNodes); } } - } return nodes; diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Wed Jan 08 15:49:18 2014 -0800 @@ -28,6 +28,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.virtual.*; /** @@ -81,8 +82,13 @@ @Input private FrameState outerFrameState; + /** + * Contains the locals, the expressions and the locked objects, in this order. + */ @Input private final NodeInputList values; + @Input private final NodeInputList monitorIds; + @Input private final NodeInputList virtualObjectMappings; /** @@ -93,16 +99,20 @@ private final ResolvedJavaMethod method; /** - * Creates a {@code FrameState} for the given scope and maximum number of stack and local - * variables. + * Creates a {@code FrameState} with the given locals, stack expressions and locked monitors. * * @param method the method for this frame state * @param bci the bytecode index of the frame state - * @param stackSize size of the stack - * @param rethrowException if true the VM should re-throw the exception on top of the stack when - * deopt'ing using this framestate + * @param values the locals, stack expressions and locked objects, in this order + * @param localsSize the number of locals in the values list + * @param stackSize the number of stack expressions in the values list + * @param rethrowException if true, this FrameState will throw an exception (taken from the top + * of the expression stack) during deoptimization + * @param duringCall true if this FrameState describes the state during a call + * @param monitorIds one MonitorIdNode for each locked object + * @param virtualObjectMappings a description of the current state for every virtual object */ - public FrameState(ResolvedJavaMethod method, int bci, List values, int localsSize, int stackSize, boolean rethrowException, boolean duringCall, + public FrameState(ResolvedJavaMethod method, int bci, List values, int localsSize, int stackSize, boolean rethrowException, boolean duringCall, List monitorIds, List virtualObjectMappings) { assert stackSize >= 0; this.method = method; @@ -110,10 +120,12 @@ this.localsSize = localsSize; this.stackSize = stackSize; this.values = new NodeInputList<>(this, values); + this.monitorIds = new NodeInputList<>(this, monitorIds); this.virtualObjectMappings = new NodeInputList<>(this, virtualObjectMappings); this.rethrowException = rethrowException; this.duringCall = duringCall; assert !rethrowException || stackSize == 1 : "must have exception on top of the stack"; + assert values.size() - localsSize - stackSize == monitorIds.size(); } /** @@ -122,11 +134,12 @@ * @param bci marker bci, needs to be < 0 */ public FrameState(int bci) { - this(null, bci, Collections. emptyList(), 0, 0, false, false, Collections. emptyList()); + this(null, bci, Collections. emptyList(), 0, 0, false, false, Collections. emptyList(), Collections. emptyList()); + assert bci == BEFORE_BCI || bci == AFTER_BCI || bci == AFTER_EXCEPTION_BCI || bci == UNKNOWN_BCI || bci == INVALID_FRAMESTATE_BCI; } - public FrameState(ResolvedJavaMethod method, int bci, ValueNode[] locals, List stack, ValueNode[] locks, boolean rethrowException, boolean duringCall) { - this(method, bci, createValues(locals, stack, locks), locals.length, stack.size(), rethrowException, duringCall, Collections. emptyList()); + public FrameState(ResolvedJavaMethod method, int bci, ValueNode[] locals, List stack, ValueNode[] locks, MonitorIdNode[] monitorIds, boolean rethrowException, boolean duringCall) { + this(method, bci, createValues(locals, stack, locks), locals.length, stack.size(), rethrowException, duringCall, Arrays.asList(monitorIds), Collections. emptyList()); } private static List createValues(ValueNode[] locals, List stack, ValueNode[] locks) { @@ -198,7 +211,7 @@ * Gets a copy of this frame state. */ public FrameState duplicate(int newBci) { - FrameState other = graph().add(new FrameState(method, newBci, values, localsSize, stackSize, rethrowException, duringCall, virtualObjectMappings)); + FrameState other = graph().add(new FrameState(method, newBci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, virtualObjectMappings)); other.setOuterFrameState(outerFrameState()); return other; } @@ -224,7 +237,7 @@ for (EscapeObjectState state : virtualObjectMappings) { newVirtualMappings.add(state.duplicateWithVirtualState()); } - FrameState other = graph().add(new FrameState(method, bci, values, localsSize, stackSize, rethrowException, duringCall, newVirtualMappings)); + FrameState other = graph().add(new FrameState(method, bci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, newVirtualMappings)); other.setOuterFrameState(newOuterFrameState); return other; } @@ -248,7 +261,7 @@ int newStackSize = copy.size() - localsSize; copy.addAll(values.subList(localsSize + stackSize, values.size())); - FrameState other = graph().add(new FrameState(method, newBci, copy, localsSize, newStackSize, newRethrowException, false, virtualObjectMappings)); + FrameState other = graph().add(new FrameState(method, newBci, copy, localsSize, newStackSize, newRethrowException, false, monitorIds, virtualObjectMappings)); other.setOuterFrameState(outerFrameState()); return other; } @@ -319,6 +332,14 @@ return values.get(localsSize + stackSize + i); } + /** + * Get the MonitorIdNode that corresponds to the locked object at the specified index. + */ + public MonitorIdNode monitorIdAt(int i) { + assert i >= 0 && i < locksSize(); + return monitorIds.get(i); + } + public NodeIterable innerFrameStates() { return usages().filter(FrameState.class); } @@ -375,9 +396,10 @@ @Override public boolean verify() { + assertTrue(values.size() - localsSize - stackSize == monitorIds.size(), "mismatch in number of locks"); 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() != Kind.Void), "unexpected value: %s", value); + assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes"); + assertTrue(value == null || value instanceof VirtualObjectNode || (value.kind() != Kind.Void), "unexpected value: %s", value); } return super.verify(); } @@ -387,6 +409,9 @@ for (ValueNode value : values.nonNull()) { closure.apply(this, value); } + for (MonitorIdNode monitorId : monitorIds) { + closure.apply(this, monitorId); + } for (EscapeObjectState state : virtualObjectMappings) { state.applyToNonVirtual(closure); } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Wed Jan 08 15:49:18 2014 -0800 @@ -200,7 +200,7 @@ // Connect blocks (including loop backward edges), but ignoring dead code (blocks with id < 0). private void connectBlocks() { for (Block block : reversePostOrder) { - List predecessors = new ArrayList<>(); + List predecessors = new ArrayList<>(4); for (Node predNode : block.getBeginNode().cfgPredecessors()) { Block predBlock = nodeToBlock.get(predNode); if (predBlock.id >= 0) { @@ -217,7 +217,7 @@ } block.predecessors = predecessors; - List successors = new ArrayList<>(); + List successors = new ArrayList<>(4); for (Node suxNode : block.getEndNode().cfgSuccessors()) { Block suxBlock = nodeToBlock.get(suxNode); assert suxBlock.id >= 0; diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -22,11 +22,14 @@ */ package com.oracle.graal.nodes.extended; +import java.util.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.virtual.*; @@ -79,7 +82,7 @@ VirtualBoxingNode newVirtual = new VirtualBoxingNode(type, boxingKind); assert newVirtual.getFields().length == 1; - tool.createVirtualObject(newVirtual, new ValueNode[]{v}, null); + tool.createVirtualObject(newVirtual, new ValueNode[]{v}, Collections. emptyList()); tool.replaceWithVirtual(newVirtual); } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorReference.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorReference.java Wed Jan 08 14:03:36 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +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.graal.nodes.extended; - -/** - * Denotes an instruction that references a monitor and wants to know its lock nesting depth. - */ -public interface MonitorReference { - - /** - * Sets the depth of the lock referenced by this operation. - */ - void setLockDepth(int lockDepth); - - /** - * Gets the depth of the lock referenced by this operation. - */ - int getLockDepth(); -} diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -36,18 +36,24 @@ public abstract class AccessMonitorNode extends AbstractMemoryCheckpoint implements MemoryCheckpoint { @Input private ValueNode object; + @Input private MonitorIdNode monitorId; public ValueNode object() { return object; } + public MonitorIdNode getMonitorId() { + return monitorId; + } + /** * Creates a new AccessMonitor instruction. * * @param object the instruction producing the object */ - public AccessMonitorNode(ValueNode object) { + public AccessMonitorNode(ValueNode object, MonitorIdNode monitorId) { super(StampFactory.forVoid()); this.object = object; + this.monitorId = monitorId; } } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -30,18 +30,15 @@ /** * The {@code MonitorEnterNode} represents the acquisition of a monitor. */ -public final class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, MonitorEnter, MemoryCheckpoint.Single, MonitorReference { - - private int lockDepth; +public final class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, MonitorEnter, MemoryCheckpoint.Single { /** * Creates a new MonitorEnterNode. * * @param object the instruction producing the object */ - public MonitorEnterNode(ValueNode object, int lockDepth) { - super(object); - this.lockDepth = lockDepth; + public MonitorEnterNode(ValueNode object, MonitorIdNode monitorId) { + super(object, monitorId); } @Override @@ -54,19 +51,11 @@ tool.getLowerer().lower(this, tool); } - public int getLockDepth() { - return lockDepth; - } - - public void setLockDepth(int lockDepth) { - this.lockDepth = lockDepth; - } - @Override public void virtualize(VirtualizerTool tool) { State state = tool.getObjectState(object()); if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) { - state.addLock(getLockDepth()); + state.addLock(getMonitorId()); tool.delete(); } } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -34,19 +34,16 @@ * a synchronized method, then the return value of the method will be referenced, so that it will be * materialized before releasing the monitor. */ -public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Simplifiable, Lowerable, IterableNodeType, MonitorExit, MemoryCheckpoint.Single, MonitorReference { +public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Simplifiable, Lowerable, IterableNodeType, MonitorExit, MemoryCheckpoint.Single { @Input private ValueNode escapedReturnValue; - private int lockDepth; - /** * Creates a new MonitorExitNode. */ - public MonitorExitNode(ValueNode object, ValueNode escapedReturnValue, int lockDepth) { - super(object); + public MonitorExitNode(ValueNode object, MonitorIdNode monitorId, ValueNode escapedReturnValue) { + super(object, monitorId); this.escapedReturnValue = escapedReturnValue; - this.lockDepth = lockDepth; } public void setEscapedReturnValue(ValueNode x) { @@ -73,22 +70,17 @@ tool.getLowerer().lower(this, tool); } - public int getLockDepth() { - return lockDepth; - } - - public void setLockDepth(int lockDepth) { - this.lockDepth = lockDepth; - } - @Override public void virtualize(VirtualizerTool tool) { State state = tool.getObjectState(object()); // the monitor exit for a synchronized method should never be virtualized assert stateAfter().bci != FrameState.AFTER_BCI || state == null; if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) { - int removedLock = state.removeLock(); - assert removedLock == getLockDepth(); + MonitorIdNode removedLock = state.removeLock(); + if (removedLock != getMonitorId()) { + throw new GraalInternalError("mismatch at %s: %s vs. %s", this, removedLock, getMonitorId()); + } + assert removedLock == getMonitorId() : "mismatch at " + this + ": " + removedLock + " vs. " + getMonitorId(); tool.delete(); } } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.java; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * This node describes one locking scope; it ties the monitor enter, monitor exit and the frame + * states together. It is thus referenced from the {@link MonitorEnterNode}, from the + * {@link MonitorExitNode} and from the {@link FrameState}. + */ +public final class MonitorIdNode extends ValueNode implements IterableNodeType, LIRLowerable { + + private int lockDepth; + + public MonitorIdNode(int lockDepth) { + super(StampFactory.dependency()); + this.lockDepth = lockDepth; + } + + public int getLockDepth() { + return lockDepth; + } + + public void setLockDepth(int lockDepth) { + this.lockDepth = lockDepth; + } + + public void generate(LIRGeneratorTool generator) { + // nothing to do + } +} diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes.java; +import java.util.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; @@ -66,7 +68,7 @@ state[i] = defaultForKind; } VirtualObjectNode virtualObject = new VirtualArrayNode(elementType(), constantLength); - tool.createVirtualObject(virtualObject, state, null); + tool.createVirtualObject(virtualObject, state, Collections. emptyList()); tool.replaceWithVirtual(virtualObject); } } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -23,6 +23,7 @@ package com.oracle.graal.nodes.java; import java.lang.ref.*; +import java.util.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; @@ -74,7 +75,7 @@ for (int i = 0; i < state.length; i++) { state[i] = defaultFieldValue(fields[i]); } - tool.createVirtualObject(virtualObject, state, null); + tool.createVirtualObject(virtualObject, state, Collections. emptyList()); tool.replaceWithVirtual(virtualObject); } } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java Wed Jan 08 15:49:18 2014 -0800 @@ -23,6 +23,7 @@ package com.oracle.graal.nodes.spi; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.virtual.*; /** @@ -45,9 +46,9 @@ public abstract ValueNode getEntry(int index); - public abstract void addLock(int depth); + public abstract void addLock(MonitorIdNode monitorId); - public abstract int removeLock(); + public abstract MonitorIdNode removeLock(); public abstract ValueNode getMaterializedValue(); } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java Wed Jan 08 15:49:18 2014 -0800 @@ -22,10 +22,13 @@ */ package com.oracle.graal.nodes.spi; +import java.util.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.Virtualizable.State; import com.oracle.graal.nodes.virtual.*; @@ -66,7 +69,7 @@ * @param entryState the initial state of the virtual object's fields. * @param locks the initial locking depths. */ - void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int[] locks); + void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List locks); /** * Queries the current state of the given value: if it is virtualized (thread-local and the diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2014, 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 @@ -28,6 +28,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -36,7 +37,8 @@ @Input private final NodeInputList virtualObjects = new NodeInputList<>(this); @Input private final NodeInputList values = new NodeInputList<>(this); - private List locks = new ArrayList<>(); + @Input private final NodeInputList locks = new NodeInputList<>(this); + private ArrayList lockIndexes = new ArrayList<>(Arrays.asList(0)); public CommitAllocationNode() { super(StampFactory.forVoid()); @@ -50,13 +52,14 @@ return values; } - public List getLocks() { - return locks; + public List getLocks(int objIndex) { + return locks.subList(lockIndexes.get(objIndex), lockIndexes.get(objIndex + 1)); } @Override public boolean verify() { - assertTrue(virtualObjects.size() == locks.size(), "lockCounts size doesn't match " + virtualObjects + ", " + locks); + assertTrue(virtualObjects.size() + 1 == lockIndexes.size(), "lockIndexes size doesn't match " + virtualObjects + ", " + lockIndexes); + assertTrue(lockIndexes.get(lockIndexes.size() - 1) == locks.size(), "locks size doesn't match " + lockIndexes + ", " + locks); int valueCount = 0; for (VirtualObjectNode virtual : virtualObjects) { valueCount += virtual.entryCount(); @@ -72,7 +75,12 @@ @Override public void afterClone(Node other) { - locks = new ArrayList<>(((CommitAllocationNode) other).locks); + lockIndexes = new ArrayList<>(lockIndexes); + } + + public void addLocks(List monitorIds) { + locks.addAll(monitorIds); + lockIndexes.add(locks.size()); } @Override @@ -81,7 +89,7 @@ for (int i = 0; i < virtualObjects.size(); i++) { VirtualObjectNode virtualObject = virtualObjects.get(i); int entryCount = virtualObject.entryCount(); - tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), locks.get(i)); + tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), getLocks(i)); pos += entryCount; } tool.delete(); @@ -100,8 +108,8 @@ s.append(i == 0 ? "" : ",").append(value == null ? "_" : value.toString(Verbosity.Id)); } s.append("]"); - if (locks.get(objIndex).length > 0) { - s.append(" locked(").append(Arrays.toString(locks.get(objIndex))).append(")"); + if (!getLocks(objIndex).isEmpty()) { + s.append(" locked(").append(locks.get(objIndex)).append(")"); } properties.put("object(" + virtual.toString(Verbosity.Id) + ")", s.toString()); } @@ -150,14 +158,17 @@ if (usedCount < virtualObjects.size()) { List newVirtualObjects = new ArrayList<>(usedCount); - List newLocks = new ArrayList<>(usedCount); + List newLocks = new ArrayList<>(usedCount); + ArrayList newLockIndexes = new ArrayList<>(usedCount + 1); + newLockIndexes.add(0); List newValues = new ArrayList<>(); int valuePos = 0; for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) { VirtualObjectNode virtualObject = virtualObjects.get(objIndex); if (used[objIndex]) { newVirtualObjects.add(virtualObject); - newLocks.add(locks.get(objIndex)); + newLocks.addAll(getLocks(objIndex)); + newLockIndexes.add(newLocks.size()); newValues.addAll(values.subList(valuePos, valuePos + virtualObject.entryCount())); } valuePos += virtualObject.entryCount(); @@ -168,6 +179,7 @@ locks.addAll(newLocks); values.clear(); values.addAll(newValues); + lockIndexes = newLockIndexes; } } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/LockState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/LockState.java Wed Jan 08 15:49:18 2014 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.virtual; + +import java.util.*; + +import com.oracle.graal.nodes.java.*; + +/** + * The class implements a simple linked list of MonitorIdNodes, which can be used to describe the + * current lock state of an object. + */ +public final class LockState { + + public final MonitorIdNode monitorId; + public final LockState next; + + public LockState(MonitorIdNode monitorId, LockState next) { + this.monitorId = monitorId; + this.next = next; + } + + @Override + public String toString() { + return monitorId.getLockDepth() + (next == null ? "" : "," + next); + } + + public static List asList(LockState state) { + if (state == null) { + return Collections.emptyList(); + } else { + ArrayList result = new ArrayList<>(); + LockState a = state; + do { + result.add(a.monitorId); + a = a.next; + } while (a != null); + return result; + } + } +} diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -141,7 +141,7 @@ } @Override - public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) { + public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) { return new AllocatedObjectNode(this); } } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -41,9 +41,9 @@ } @Override - public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) { + public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) { assert entries.length == 1; - assert locks.length == 0; + assert locks == null; return new BoxNode(entries[0], type(), boxingKind); } } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -101,7 +101,7 @@ } @Override - public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) { + public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) { return new AllocatedObjectNode(this); } } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -88,7 +88,7 @@ * {@link AllocatedObjectNode} then this node will be attached to a {@link CommitAllocationNode} * , otherwise the node will just be added to the graph. */ - public abstract ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks); + public abstract ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks); @Override public void generate(LIRGeneratorTool gen) { diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Wed Jan 08 15:49:18 2014 -0800 @@ -1395,10 +1395,9 @@ if (stateAfter != null) { FrameState outerFrameState = null; int callerLockDepth = stateAfter.nestedLockDepth(); - for (Node inlinedNode : inlineGraph.getNodes()) { - Node node = duplicates.get(inlinedNode); - if (node instanceof FrameState) { - FrameState frameState = (FrameState) node; + for (FrameState original : inlineGraph.getNodes(FrameState.class)) { + FrameState frameState = (FrameState) duplicates.get(original); + if (frameState != null) { assert frameState.bci != FrameState.BEFORE_BCI : frameState; if (frameState.bci == FrameState.AFTER_BCI) { frameState.replaceAndDelete(stateAfter); @@ -1421,8 +1420,10 @@ } } } - if (callerLockDepth != 0 && node instanceof MonitorReference) { - MonitorReference monitor = (MonitorReference) node; + } + if (callerLockDepth != 0) { + for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.class)) { + MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original); monitor.setLockDepth(monitor.getLockDepth() + callerLockDepth); } } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -102,7 +102,7 @@ } @Override - public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) { + public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) { if (allowMaterialization) { return super.getMaterializedRepresentation(fixed, entries, locks); } @@ -173,9 +173,9 @@ tool.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) frameDescriptor.getVersion())); } - tool.createVirtualObject(virtualFrameObjectArray, objectArrayEntryState, null); - tool.createVirtualObject(virtualFramePrimitiveArray, primitiveArrayEntryState, null); - tool.createVirtualObject(virtualFrameTagArray, tagArrayEntryState, null); + tool.createVirtualObject(virtualFrameObjectArray, objectArrayEntryState, Collections. emptyList()); + tool.createVirtualObject(virtualFramePrimitiveArray, primitiveArrayEntryState, Collections. emptyList()); + tool.createVirtualObject(virtualFrameTagArray, tagArrayEntryState, Collections. emptyList()); assert frameFields.length == 6; ValueNode[] frameEntryState = new ValueNode[frameFields.length]; diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Wed Jan 08 15:49:18 2014 -0800 @@ -28,6 +28,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.debug.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.common.*; @@ -308,7 +309,7 @@ * @param otherAllocations A list of allocations that need to be added before the rest (used for * boxing allocations). */ - public void addMaterializationBefore(final FixedNode position, final List objects, final List locks, final List values, + public void addMaterializationBefore(final FixedNode position, final List objects, final List> locks, final List values, final List otherAllocations) { add(new Effect() { @@ -341,7 +342,9 @@ obj.setCommit(commit); } commit.getValues().addAll(values); - commit.getLocks().addAll(locks); + for (List monitorIds : locks) { + commit.addLocks(monitorIds); + } assert commit.usages().filter(AllocatedObjectNode.class).count() == commit.usages().count(); List materializedValues = commit.usages().filter(AllocatedObjectNode.class).snapshot(); diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java Wed Jan 08 15:49:18 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2014, 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 @@ -25,6 +25,7 @@ import java.util.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; @@ -36,37 +37,6 @@ */ public class ObjectState extends Virtualizable.State { - private static final int[] EMPTY_INT_ARRAY = new int[0]; - - public static final class LockState { - - public final int depth; - public final LockState next; - - private LockState(int depth, LockState next) { - this.depth = depth; - this.next = next; - } - - @Override - public String toString() { - return next == null ? String.valueOf(depth) : depth + "," + next; - } - - public static boolean equals(LockState a, LockState b) { - if ((a == null) != (b == null)) { - return false; - } - if (a != null) { - if (a.depth != b.depth) { - return false; - } - return equals(a.next, b.next); - } - return true; - } - } - final VirtualObjectNode virtual; private EscapeState state; @@ -74,17 +44,18 @@ private ValueNode materializedValue; private LockState locks; - public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, int[] locks) { + public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, List locks) { + this(virtual, entries, state, (LockState) null); + for (int i = locks.size() - 1; i >= 0; i--) { + this.locks = new LockState(locks.get(i), this.locks); + } + } + + public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, LockState locks) { this.virtual = virtual; this.entries = entries; this.state = state; - if (locks == null) { - this.locks = null; - } else { - for (int i = locks.length - 1; i >= 0; i--) { - this.locks = new LockState(locks[i], this.locks); - } - } + this.locks = locks; } public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, LockState locks) { @@ -156,37 +127,21 @@ } @Override - public void addLock(int depth) { - locks = new LockState(depth, locks); + public void addLock(MonitorIdNode monitorId) { + locks = new LockState(monitorId, locks); } @Override - public int removeLock() { + public MonitorIdNode removeLock() { try { - return locks.depth; + return locks.monitorId; } finally { locks = locks.next; } } - public int[] getLocks() { - if (locks == null) { - return EMPTY_INT_ARRAY; - } - int cnt = 0; - LockState current = locks; - while (current != null) { - cnt++; - current = current.next; - } - int[] result = new int[cnt]; - current = locks; - cnt = 0; - while (current != null) { - result[cnt++] = current.depth; - current = current.next; - } - return result; + public LockState getLocks() { + return locks; } public boolean hasLocks() { @@ -194,7 +149,13 @@ } public boolean locksEqual(ObjectState other) { - return LockState.equals(locks, other.locks); + LockState a = locks; + LockState b = other.locks; + while (a != null && b != null && a.monitorId == b.monitorId) { + a = a.next; + b = b.next; + } + return a == null && b == null; } @Override @@ -220,7 +181,7 @@ final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(entries); - result = prime * result + (locks != null ? locks.depth : 0); + result = prime * result + (locks != null ? locks.monitorId.getLockDepth() : 0); result = prime * result + ((materializedValue == null) ? 0 : materializedValue.hashCode()); result = prime * result + ((state == null) ? 0 : state.hashCode()); result = prime * result + ((virtual == null) ? 0 : virtual.hashCode()); @@ -239,7 +200,7 @@ if (!Arrays.equals(entries, other.entries)) { return false; } - if (!LockState.equals(locks, other.locks)) { + if (!locksEqual(other)) { return false; } if (materializedValue == null) { diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java Wed Jan 08 15:49:18 2014 -0800 @@ -25,6 +25,7 @@ import java.util.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; @@ -68,15 +69,15 @@ PartialEscapeClosure.METRIC_MATERIALIZATIONS.increment(); List objects = new ArrayList<>(2); List values = new ArrayList<>(8); - List locks = new ArrayList<>(2); + List> locks = new ArrayList<>(2); List otherAllocations = new ArrayList<>(2); materializeWithCommit(fixed, virtual, objects, locks, values, otherAllocations, state); materializeEffects.addMaterializationBefore(fixed, objects, locks, values, otherAllocations); } - private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List objects, List locks, List values, List otherAllocations, - EscapeState state) { + private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List objects, List> locks, List values, + List otherAllocations, EscapeState state) { ObjectState obj = getObjectState(virtual); ValueNode[] entries = obj.getEntries(); @@ -84,7 +85,7 @@ obj.escape(representation, state); if (representation instanceof AllocatedObjectNode) { objects.add((AllocatedObjectNode) representation); - locks.add(obj.getLocks()); + locks.add(LockState.asList(obj.getLocks())); int pos = values.size(); while (values.size() < pos + entries.length) { values.add(null); @@ -104,7 +105,7 @@ } else { VirtualUtil.trace("materialized %s as %s", virtual, representation); otherAllocations.add(representation); - assert obj.getLocks().length == 0; + assert obj.getLocks() == null; } } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Wed Jan 08 15:49:18 2014 -0800 @@ -24,11 +24,14 @@ import static com.oracle.graal.phases.GraalOptions.*; +import java.util.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.spi.Virtualizable.State; import com.oracle.graal.nodes.spi.*; @@ -150,7 +153,7 @@ } @Override - public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int[] locks) { + public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List locks) { VirtualUtil.trace("{{%s}} ", current); if (!virtualObject.isAlive()) { effects.addFloatingNode(virtualObject, "newVirtualObject"); diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CallNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CallNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CallNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -79,7 +79,7 @@ this.name = name; this.isSplatted = isSplatted; - dispatchHead = adoptChild(adoptChild(new DispatchHeadNode(context, section, name, isSplatted))); + dispatchHead = adoptChild(new DispatchHeadNode(context, section, name, isSplatted)); } @Override diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/BreakNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/BreakNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/BreakNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -13,6 +13,7 @@ import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.ruby.nodes.*; +import com.oracle.truffle.ruby.nodes.literal.*; import com.oracle.truffle.ruby.runtime.*; import com.oracle.truffle.ruby.runtime.control.*; @@ -28,7 +29,11 @@ @Override public Object execute(VirtualFrame frame) { - throw new BreakException(child.execute(frame)); + if (child instanceof NilNode) { + throw BreakException.NIL; + } else { + throw new BreakException(child.execute(frame)); + } } } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NextNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NextNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NextNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -13,19 +13,27 @@ import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.ruby.nodes.*; +import com.oracle.truffle.ruby.nodes.literal.*; import com.oracle.truffle.ruby.runtime.*; import com.oracle.truffle.ruby.runtime.control.*; @NodeInfo(shortName = "next") public class NextNode extends RubyNode { - public NextNode(RubyContext context, SourceSection sourceSection) { + @Child private RubyNode child; + + public NextNode(RubyContext context, SourceSection sourceSection, RubyNode child) { super(context, sourceSection); + + this.child = adoptChild(child); } @Override public Object execute(VirtualFrame frame) { - throw new NextException(); + if (child instanceof NilNode) { + throw NextException.NIL; + } else { + throw new NextException(child.execute(frame)); + } } - } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayNodes.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayNodes.java Wed Jan 08 15:49:18 2014 -0800 @@ -16,6 +16,7 @@ import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.utilities.*; import com.oracle.truffle.ruby.runtime.*; import com.oracle.truffle.ruby.runtime.control.*; import com.oracle.truffle.ruby.runtime.core.*; @@ -457,6 +458,10 @@ @CoreMethod(names = "each", needsBlock = true, maxArgs = 0) public abstract static class EachNode extends YieldingCoreMethodNode { + private final BranchProfile breakProfile = new BranchProfile(); + private final BranchProfile nextProfile = new BranchProfile(); + private final BranchProfile redoProfile = new BranchProfile(); + public EachNode(RubyContext context, SourceSection sourceSection) { super(context, sourceSection); } @@ -466,12 +471,21 @@ } @Specialization - public NilPlaceholder each(VirtualFrame frame, RubyArray array, RubyProc block) { - for (int n = 0; n < array.size(); n++) { - try { - yield(frame, block, array.get(n)); - } catch (BreakException e) { - break; + public Object each(VirtualFrame frame, RubyArray array, RubyProc block) { + outer: for (int n = 0; n < array.size(); n++) { + while (true) { + try { + yield(frame, block, array.get(n)); + continue outer; + } catch (BreakException e) { + breakProfile.enter(); + return e.getResult(); + } catch (NextException e) { + nextProfile.enter(); + continue outer; + } catch (RedoException e) { + redoProfile.enter(); + } } } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BignumNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BignumNodes.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BignumNodes.java Wed Jan 08 15:49:18 2014 -0800 @@ -14,7 +14,9 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.utilities.*; import com.oracle.truffle.ruby.runtime.*; +import com.oracle.truffle.ruby.runtime.control.*; import com.oracle.truffle.ruby.runtime.core.*; import com.oracle.truffle.ruby.runtime.core.array.*; @@ -602,6 +604,10 @@ @CoreMethod(names = "times", needsBlock = true, maxArgs = 0) public abstract static class TimesNode extends YieldingCoreMethodNode { + private final BranchProfile breakProfile = new BranchProfile(); + private final BranchProfile nextProfile = new BranchProfile(); + private final BranchProfile redoProfile = new BranchProfile(); + public TimesNode(RubyContext context, SourceSection sourceSection) { super(context, sourceSection); } @@ -611,9 +617,22 @@ } @Specialization - public BigInteger times(VirtualFrame frame, BigInteger n, RubyProc block) { - for (BigInteger i = BigInteger.ZERO; i.compareTo(n) < 0; i = i.add(BigInteger.ONE)) { - yield(frame, block, i); + public Object times(VirtualFrame frame, BigInteger n, RubyProc block) { + outer: for (BigInteger i = BigInteger.ZERO; i.compareTo(n) < 0; i = i.add(BigInteger.ONE)) { + while (true) { + try { + yield(frame, block, i); + continue outer; + } catch (BreakException e) { + breakProfile.enter(); + return e.getResult(); + } catch (NextException e) { + nextProfile.enter(); + continue outer; + } catch (RedoException e) { + redoProfile.enter(); + } + } } return n; diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FixnumNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FixnumNodes.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FixnumNodes.java Wed Jan 08 15:49:18 2014 -0800 @@ -14,7 +14,9 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.utilities.*; import com.oracle.truffle.ruby.runtime.*; +import com.oracle.truffle.ruby.runtime.control.*; import com.oracle.truffle.ruby.runtime.core.*; import com.oracle.truffle.ruby.runtime.core.array.*; @@ -755,6 +757,10 @@ @CoreMethod(names = "times", needsBlock = true, maxArgs = 0) public abstract static class TimesNode extends YieldingCoreMethodNode { + private final BranchProfile breakProfile = new BranchProfile(); + private final BranchProfile nextProfile = new BranchProfile(); + private final BranchProfile redoProfile = new BranchProfile(); + public TimesNode(RubyContext context, SourceSection sourceSection) { super(context, sourceSection); } @@ -764,9 +770,22 @@ } @Specialization - public int times(VirtualFrame frame, int n, RubyProc block) { - for (int i = 0; i < n; i++) { - yield(frame, block, i); + public Object times(VirtualFrame frame, int n, RubyProc block) { + outer: for (int i = 0; i < n; i++) { + while (true) { + try { + yield(frame, block, i); + continue outer; + } catch (BreakException e) { + breakProfile.enter(); + return e.getResult(); + } catch (NextException e) { + nextProfile.enter(); + continue outer; + } catch (RedoException e) { + redoProfile.enter(); + } + } } return n; @@ -831,6 +850,10 @@ @CoreMethod(names = "upto", needsBlock = true, minArgs = 1, maxArgs = 1) public abstract static class UpToNode extends YieldingCoreMethodNode { + private final BranchProfile breakProfile = new BranchProfile(); + private final BranchProfile nextProfile = new BranchProfile(); + private final BranchProfile redoProfile = new BranchProfile(); + public UpToNode(RubyContext context, SourceSection sourceSection) { super(context, sourceSection); } @@ -840,9 +863,22 @@ } @Specialization - public NilPlaceholder upto(VirtualFrame frame, int from, int to, RubyProc block) { - for (int i = from; i <= to; i++) { - yield(frame, block, i); + public Object upto(VirtualFrame frame, int from, int to, RubyProc block) { + outer: for (int i = from; i <= to; i++) { + while (true) { + try { + yield(frame, block, i); + continue outer; + } catch (BreakException e) { + breakProfile.enter(); + return e.getResult(); + } catch (NextException e) { + nextProfile.enter(); + continue outer; + } catch (RedoException e) { + redoProfile.enter(); + } + } } return NilPlaceholder.INSTANCE; diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/HashNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/HashNodes.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/HashNodes.java Wed Jan 08 15:49:18 2014 -0800 @@ -44,7 +44,10 @@ hash.put(keyValue.get(0), keyValue.get(1)); } } else { - assert args.length % 2 == 0; + if (args.length % 2 != 0) { + // TODO(CS): figure out what error to throw here + throw new UnsupportedOperationException(); + } for (int n = 0; n < args.length; n += 2) { hash.put(args[n], args[n + 1]); diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RangeNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RangeNodes.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RangeNodes.java Wed Jan 08 15:49:18 2014 -0800 @@ -12,8 +12,10 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.utilities.*; import com.oracle.truffle.ruby.nodes.call.*; import com.oracle.truffle.ruby.runtime.*; +import com.oracle.truffle.ruby.runtime.control.*; import com.oracle.truffle.ruby.runtime.core.*; import com.oracle.truffle.ruby.runtime.core.array.*; import com.oracle.truffle.ruby.runtime.core.range.*; @@ -50,6 +52,10 @@ @CoreMethod(names = "each", needsBlock = true, maxArgs = 0) public abstract static class EachNode extends YieldingCoreMethodNode { + private final BranchProfile breakProfile = new BranchProfile(); + private final BranchProfile nextProfile = new BranchProfile(); + private final BranchProfile redoProfile = new BranchProfile(); + public EachNode(RubyContext context, SourceSection sourceSection) { super(context, sourceSection); } @@ -59,9 +65,22 @@ } @Specialization - public FixnumRange each(VirtualFrame frame, FixnumRange range, RubyProc block) { - for (int n = range.getBegin(); n < range.getExclusiveEnd(); n++) { - yield(frame, block, n); + public Object each(VirtualFrame frame, FixnumRange range, RubyProc block) { + outer: for (int n = range.getBegin(); n < range.getExclusiveEnd(); n++) { + while (true) { + try { + yield(frame, block, n); + continue outer; + } catch (BreakException e) { + breakProfile.enter(); + return e.getResult(); + } catch (NextException e) { + nextProfile.enter(); + continue outer; + } catch (RedoException e) { + redoProfile.enter(); + } + } } return range; @@ -182,6 +201,10 @@ @CoreMethod(names = "step", needsBlock = true, minArgs = 1, maxArgs = 1) public abstract static class StepNode extends YieldingCoreMethodNode { + private final BranchProfile breakProfile = new BranchProfile(); + private final BranchProfile nextProfile = new BranchProfile(); + private final BranchProfile redoProfile = new BranchProfile(); + public StepNode(RubyContext context, SourceSection sourceSection) { super(context, sourceSection); } @@ -191,9 +214,22 @@ } @Specialization - public FixnumRange step(VirtualFrame frame, FixnumRange range, int step, RubyProc block) { - for (int n = range.getBegin(); n < range.getExclusiveEnd(); n += step) { - yield(frame, block, n); + public Object step(VirtualFrame frame, FixnumRange range, int step, RubyProc block) { + outer: for (int n = range.getBegin(); n < range.getExclusiveEnd(); n += step) { + while (true) { + try { + yield(frame, block, n); + continue outer; + } catch (BreakException e) { + breakProfile.enter(); + return e.getResult(); + } catch (NextException e) { + nextProfile.enter(); + continue outer; + } catch (RedoException e) { + redoProfile.enter(); + } + } } return range; diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/StringNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/StringNodes.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/StringNodes.java Wed Jan 08 15:49:18 2014 -0800 @@ -304,13 +304,13 @@ } @CoreMethod(names = "inspect", maxArgs = 0) - public abstract static class InpsectNode extends CoreMethodNode { + public abstract static class InspectNode extends CoreMethodNode { - public InpsectNode(RubyContext context, SourceSection sourceSection) { + public InspectNode(RubyContext context, SourceSection sourceSection) { super(context, sourceSection); } - public InpsectNode(InpsectNode prev) { + public InspectNode(InspectNode prev) { super(prev); } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchNextNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchNextNode.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchNextNode.java Wed Jan 08 15:49:18 2014 -0800 @@ -36,8 +36,7 @@ return body.execute(frame); } catch (NextException e) { nextProfile.enter(); - return NilPlaceholder.INSTANCE; + return e.getResult(); } } - } diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java --- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java Wed Jan 08 15:49:18 2014 -0800 @@ -1513,7 +1513,17 @@ @Override public Object visitNextNode(org.jrubyparser.ast.NextNode node) { - return new NextNode(context, translate(node.getPosition())); + final SourceSection sourceSection = translate(node.getPosition()); + + RubyNode resultNode; + + if (node.getValueNode() == null) { + resultNode = new NilNode(context, sourceSection); + } else { + resultNode = (RubyNode) node.getValueNode().accept(this); + } + + return new NextNode(context, sourceSection, resultNode); } @Override diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakException.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakException.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakException.java Wed Jan 08 15:49:18 2014 -0800 @@ -17,6 +17,8 @@ */ public final class BreakException extends ControlFlowException { + public static final BreakException NIL = new BreakException(NilPlaceholder.INSTANCE); + private final Object result; public BreakException(Object result) { diff -r 1894412de0ed -r d7af2296cebb graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/NextException.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/NextException.java Wed Jan 08 14:03:36 2014 -0800 +++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/NextException.java Wed Jan 08 15:49:18 2014 -0800 @@ -10,12 +10,27 @@ package com.oracle.truffle.ruby.runtime.control; import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.ruby.runtime.*; /** * Controls moving to the next iteration in a control structure or method. */ public final class NextException extends ControlFlowException { + public static final NextException NIL = new NextException(NilPlaceholder.INSTANCE); + + private final Object result; + + public NextException(Object result) { + assert RubyContext.shouldObjectBeVisible(result); + + this.result = result; + } + + public Object getResult() { + return result; + } + private static final long serialVersionUID = -302759969186731457L; } diff -r 1894412de0ed -r d7af2296cebb src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Wed Jan 08 14:03:36 2014 -0800 +++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Wed Jan 08 15:49:18 2014 -0800 @@ -1601,7 +1601,7 @@ } #endif // TIERED __ set((intptr_t)os::get_polling_page(), L0); - __ relocate(poll_return_Relocation::spec(poll_Relocation::absolute)); + __ relocate(relocInfo::poll_return_type); __ ld_ptr(L0, 0, G0); __ ret(); __ delayed()->restore(); @@ -1610,10 +1610,9 @@ int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) { __ set((intptr_t)os::get_polling_page(), tmp->as_register()); + __ relocate(relocInfo::poll_type); if (info != NULL) { add_debug_info_for_branch(info); - } else { - __ relocate(poll_Relocation::spec(poll_Relocation::absolute)); } int offset = __ offset(); diff -r 1894412de0ed -r d7af2296cebb src/cpu/sparc/vm/graalCodeInstaller_sparc.hpp --- a/src/cpu/sparc/vm/graalCodeInstaller_sparc.hpp Wed Jan 08 14:03:36 2014 -0800 +++ b/src/cpu/sparc/vm/graalCodeInstaller_sparc.hpp Wed Jan 08 15:49:18 2014 -0800 @@ -188,13 +188,13 @@ fatal("unimplemented"); } case MARK_POLL_FAR: - _instructions->relocate(pc, poll_Relocation::spec(poll_Relocation::absolute)); + _instructions->relocate(pc, relocInfo::poll_type); break; case MARK_POLL_RETURN_NEAR: { fatal("unimplemented"); } case MARK_POLL_RETURN_FAR: - _instructions->relocate(pc, poll_return_Relocation::spec(poll_Relocation::absolute)); + _instructions->relocate(pc, relocInfo::poll_return_type); break; default: fatal("invalid mark value"); diff -r 1894412de0ed -r d7af2296cebb src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Wed Jan 08 14:03:36 2014 -0800 +++ b/src/cpu/x86/vm/assembler_x86.cpp Wed Jan 08 15:49:18 2014 -0800 @@ -81,10 +81,8 @@ _rspec = runtime_call_Relocation::spec(); break; case relocInfo::poll_type: - _rspec = poll_Relocation::spec(Assembler::is_polling_page_far() ? poll_Relocation::absolute : poll_Relocation::pc_relative); - break; case relocInfo::poll_return_type: - _rspec = poll_return_Relocation::spec(Assembler::is_polling_page_far() ? poll_Relocation::absolute : poll_Relocation::pc_relative); + _rspec = Relocation::spec_simple(rtype); break; case relocInfo::none: break; diff -r 1894412de0ed -r d7af2296cebb src/cpu/x86/vm/assembler_x86.hpp diff -r 1894412de0ed -r d7af2296cebb src/cpu/x86/vm/graalCodeInstaller_x86.hpp --- a/src/cpu/x86/vm/graalCodeInstaller_x86.hpp Wed Jan 08 14:03:36 2014 -0800 +++ b/src/cpu/x86/vm/graalCodeInstaller_x86.hpp Wed Jan 08 15:49:18 2014 -0800 @@ -243,19 +243,24 @@ switch (mark) { case MARK_POLL_NEAR: { relocate_poll_near(pc); - _instructions->relocate(pc, poll_Relocation::spec(poll_Relocation::pc_relative)); + _instructions->relocate(pc, relocInfo::poll_type, Assembler::disp32_operand); break; } case MARK_POLL_FAR: - _instructions->relocate(pc, poll_Relocation::spec(poll_Relocation::absolute)); + // This is a load from a register so there is no relocatable operand. + // We just have to ensure that the format is not disp32_operand + // so that poll_Relocation::fix_relocation_after_move does the right + // thing (i.e. ignores this relocation record) + _instructions->relocate(pc, relocInfo::poll_type, Assembler::imm_operand); break; case MARK_POLL_RETURN_NEAR: { relocate_poll_near(pc); - _instructions->relocate(pc, poll_return_Relocation::spec(poll_Relocation::pc_relative)); + _instructions->relocate(pc, relocInfo::poll_return_type, Assembler::disp32_operand); break; } case MARK_POLL_RETURN_FAR: - _instructions->relocate(pc, poll_return_Relocation::spec(poll_Relocation::absolute)); + // see comment above for MARK_POLL_FAR + _instructions->relocate(pc, relocInfo::poll_return_type, Assembler::imm_operand); break; default: fatal("invalid mark value"); diff -r 1894412de0ed -r d7af2296cebb src/cpu/x86/vm/relocInfo_x86.cpp --- a/src/cpu/x86/vm/relocInfo_x86.cpp Wed Jan 08 14:03:36 2014 -0800 +++ b/src/cpu/x86/vm/relocInfo_x86.cpp Wed Jan 08 15:49:18 2014 -0800 @@ -179,17 +179,14 @@ void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { #ifdef _LP64 - if (_form == pc_relative) { - typedef Assembler::WhichOperand WhichOperand; - WhichOperand which = (WhichOperand) format(); - // This format is imm but it is really disp32 - which = Assembler::disp32_operand; + typedef Assembler::WhichOperand WhichOperand; + WhichOperand which = (WhichOperand) format(); + if (which == Assembler::disp32_operand) { address orig_addr = old_addr_for(addr(), src, dest); NativeInstruction* oni = nativeInstruction_at(orig_addr); int32_t* orig_disp = (int32_t*) Assembler::locate_operand(orig_addr, which); // This poll_addr is incorrect by the size of the instruction it is irrelevant intptr_t poll_addr = (intptr_t)oni + *orig_disp; - NativeInstruction* ni = nativeInstruction_at(addr()); intptr_t new_disp = poll_addr - (intptr_t) ni; diff -r 1894412de0ed -r d7af2296cebb src/share/vm/c1/c1_LIRAssembler.cpp --- a/src/share/vm/c1/c1_LIRAssembler.cpp Wed Jan 08 14:03:36 2014 -0800 +++ b/src/share/vm/c1/c1_LIRAssembler.cpp Wed Jan 08 15:49:18 2014 -0800 @@ -334,7 +334,6 @@ void LIR_Assembler::add_debug_info_for_branch(CodeEmitInfo* info) { - _masm->code_section()->relocate(pc(), relocInfo::poll_type); int pc_offset = code_offset(); flush_debug_info(pc_offset); info->record_debug_info(compilation()->debug_info_recorder(), pc_offset); diff -r 1894412de0ed -r d7af2296cebb src/share/vm/code/relocInfo.cpp --- a/src/share/vm/code/relocInfo.cpp Wed Jan 08 14:03:36 2014 -0800 +++ b/src/share/vm/code/relocInfo.cpp Wed Jan 08 15:49:18 2014 -0800 @@ -679,16 +679,6 @@ _target = address_from_scaled_offset(offset, base); } -void poll_Relocation::pack_data_to(CodeSection* dest) { - short* p = (short*) dest->locs_end(); - p = pack_1_int_to(p, _form); - dest->set_locs_end((relocInfo*) p); -} - -void poll_Relocation::unpack_data() { - _form = (poll_Relocation::pollingForm) unpack_1_int(); -} - //// miscellaneous methods oop* oop_Relocation::oop_addr() { int n = _oop_index; @@ -985,22 +975,6 @@ tty->print(" | [static_call=" INTPTR_FORMAT "]", r->static_call()); break; } - case relocInfo::poll_type: - case relocInfo::poll_return_type: - { - poll_Relocation* r = (poll_Relocation*) reloc(); - const char *formName = "unknown"; - switch (r->form()) { - case poll_Relocation::pc_relative: - formName = "pc_relative"; - break; - case poll_Relocation::absolute: - formName = "absolute"; - break; - } - tty->print(" | [form=%d(%s)]", r->form(), formName); - break; - } } tty->cr(); } diff -r 1894412de0ed -r d7af2296cebb src/share/vm/code/relocInfo.hpp --- a/src/share/vm/code/relocInfo.hpp Wed Jan 08 14:03:36 2014 -0800 +++ b/src/share/vm/code/relocInfo.hpp Wed Jan 08 15:49:18 2014 -0800 @@ -213,8 +213,7 @@ // relocInfo::poll_[return_]type -- a safepoint poll // Value: none // Instruction types: memory load or test -// Data: [] the associated set-oops are adjacent to the call -// [n] n is a poll_Relocation::pollingForm value +// Data: none // // For example: // @@ -1277,53 +1276,15 @@ section_word_Relocation() { } }; + class poll_Relocation : public Relocation { - public: - enum pollingForm { - pc_relative, - absolute - }; + bool is_data() { return true; } relocInfo::relocType type() { return relocInfo::poll_type; } - bool is_data() { return true; } void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest); - private: - pollingForm _form; - public: - - static RelocationHolder spec(poll_Relocation::pollingForm form) { - RelocationHolder rh = newHolder(); - new(rh) poll_Relocation(form); - return rh; - } - - poll_Relocation(poll_Relocation::pollingForm form) { - _form = form; - } - poll_Relocation::pollingForm form() { return _form; } - - void pack_data_to(CodeSection* dest); - void unpack_data(); - - protected: - friend class RelocIterator; - poll_Relocation() { } }; class poll_return_Relocation : public poll_Relocation { - public: relocInfo::relocType type() { return relocInfo::poll_return_type; } - - static RelocationHolder spec(poll_Relocation::pollingForm distance) { - RelocationHolder rh = newHolder(); - new(rh) poll_return_Relocation(distance); - return rh; - } - - poll_return_Relocation(poll_Relocation::pollingForm distance) : poll_Relocation(distance) { } - - private: - friend class RelocIterator; - poll_return_Relocation() { } }; // We know all the xxx_Relocation classes, so now we can define these: