# HG changeset patch # User Tom Rodriguez # Date 1431392176 25200 # Node ID 7e72615e04415794ae92f3932bdaeb280e7531f9 # Parent bea2f27524ba7308466e86fb5228de4b7380159e# Parent 8eadc82f4a93a647da06e21577d21e0de7f94aa8 Merge diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java Mon May 11 17:56:16 2015 -0700 @@ -294,6 +294,9 @@ */ public static StringBuilder append(StringBuilder sb, BytecodeFrame frame) { MetaUtil.appendLocation(sb.append("at "), frame.getMethod(), frame.getBCI()); + assert sb.charAt(sb.length() - 1) == ']'; + sb.deleteCharAt(sb.length() - 1); + sb.append(", duringCall: ").append(frame.duringCall).append(", rethrow: ").append(frame.rethrowException).append(']'); if (frame.values != null && frame.values.length > 0) { sb.append(NEW_LINE); String table = tabulateValues(frame); diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Mon May 11 17:56:16 2015 -0700 @@ -23,12 +23,14 @@ package com.oracle.graal.compiler.test.ea; import java.lang.ref.*; + import org.junit.*; import com.oracle.graal.compiler.test.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.common.*; @@ -191,6 +193,23 @@ assertTrue(graph.getNodes().filter(ReturnNode.class).first().result() == graph.getParameter(0)); } + public static int testBoxLoopSnippet(int n) { + Integer sum = 0; + for (Integer i = 0; i < n; i++) { + if (sum == null) { + sum = null; + } else { + sum += i; + } + } + return sum; + } + + @Test + public void testBoxLoop() { + testPartialEscapeAnalysis("testBoxLoopSnippet", 0, 0, BoxNode.class, UnboxNode.class); + } + @SafeVarargs protected final void testPartialEscapeAnalysis(String snippet, double expectedProbability, int expectedCount, Class... invalidNodeClasses) { prepareGraph(snippet, false); diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java Mon May 11 17:56:16 2015 -0700 @@ -115,8 +115,8 @@ T equivalentValue = append(value); if (equivalentValue instanceof StateSplit) { StateSplit stateSplit = (StateSplit) equivalentValue; - if (stateSplit.stateAfter() == null) { - stateSplit.setStateAfter(createStateAfter()); + if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) { + setStateAfter(stateSplit); } } return equivalentValue; @@ -149,8 +149,8 @@ push(kind.getStackKind(), equivalentValue); if (equivalentValue instanceof StateSplit) { StateSplit stateSplit = (StateSplit) equivalentValue; - if (stateSplit.stateAfter() == null) { - stateSplit.setStateAfter(createStateAfter()); + if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) { + setStateAfter(stateSplit); } } return equivalentValue; @@ -194,9 +194,12 @@ /** * Creates a snap shot of the current frame state with the BCI of the instruction after the one - * currently being parsed. + * currently being parsed and assigns it to a given {@linkplain StateSplit#hasSideEffect() side + * effect} node. + * + * @param sideEffect a side effect node just appended to the graph */ - FrameState createStateAfter(); + void setStateAfter(StateSplit sideEffect); /** * Gets the parsing context for the method that inlines the method being parsed by this context. @@ -204,6 +207,18 @@ GraphBuilderContext getParent(); /** + * Gets the first ancestor parsing context that is not parsing a + * {@linkplain #parsingReplacement() replacement}. + */ + default GraphBuilderContext getNonReplacementAncestor() { + GraphBuilderContext ancestor = getParent(); + while (ancestor != null && ancestor.parsingReplacement()) { + ancestor = ancestor.getParent(); + } + return ancestor; + } + + /** * Gets the method currently being parsed. */ ResolvedJavaMethod getMethod(); diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java Mon May 11 17:56:16 2015 -0700 @@ -26,8 +26,9 @@ import com.oracle.graal.nodes.*; /** - * Plugin for specifying what is inlined during graph parsing or for post-processing non-inlined - * invocations that result in {@link Invoke} nodes. + * Plugin for specifying what is inlined during graph parsing. This plugin is also + * {@linkplain #notifyOfNoninlinedInvoke notified} of non-inlined invocations (i.e., those for which + * an {@link Invoke} node is created). */ public interface InlineInvokePlugin extends GraphBuilderPlugin { @@ -46,9 +47,7 @@ public final boolean isReplacement; /** - * Specifies if {@link #methodToInline} is an intrinsic for the original method. If so, any - * {@link StateSplit} node created in the (recursive) inlining scope will be given a frame - * state that restarts the interpreter just before the intrinsified invocation. + * Specifies if {@link #methodToInline} is an intrinsic for the original method. */ public final boolean isIntrinsic; diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Mon May 11 17:56:16 2015 -0700 @@ -132,7 +132,7 @@ StructuredGraph graph = new StructuredGraph(substMethod, AllowAssumptions.YES); Plugins plugins = new Plugins(((HotSpotProviders) getProviders()).getGraphBuilderPlugins()); GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); - IntrinsicContext initialReplacementContext = new IntrinsicContext(installedCodeOwner, substMethod, null, ROOT_COMPILATION_BCI); + IntrinsicContext initialReplacementContext = new IntrinsicContext(installedCodeOwner, substMethod, ROOT_COMPILATION_BCI); new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph); Assert.assertNotNull(getCode(installedCodeOwner, graph, true)); atLeastOneCompiled = true; diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Mon May 11 17:56:16 2015 -0700 @@ -305,7 +305,7 @@ } if (excludeMethodFilters != null && excludeMethodFilters.length > 0) { String exclude = Arrays.asList(excludeMethodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", ")); - println("CompileTheWorld : Excluding all methods matching one of the follwing filters: " + exclude); + println("CompileTheWorld : Excluding all methods matching one of the following filters: " + exclude); } println(); diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java Mon May 11 17:56:16 2015 -0700 @@ -35,7 +35,6 @@ import com.oracle.graal.hotspot.*; import com.oracle.graal.options.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; import com.oracle.graal.replacements.SnippetTemplate.Arguments; /** @@ -314,7 +313,7 @@ ResolvedJavaMethod initMethod = null; try { Class rjm = ResolvedJavaMethod.class; - makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm, FrameStateProcessing.class)); + makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm)); initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class)); } catch (NoSuchMethodException | SecurityException e) { throw new GraalInternalError(e); diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java Mon May 11 17:56:16 2015 -0700 @@ -119,7 +119,7 @@ * for equality. */ private boolean appendGraphEncoderTest(PhaseSuite suite) { - suite.appendPhase(new BasePhase() { + suite.appendPhase(new BasePhase("VerifyEncodingDecoding") { @Override protected void run(StructuredGraph graph, HighTierContext context) { EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, runtime.getTarget().arch); diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java Mon May 11 17:56:16 2015 -0700 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot.stubs; +import static com.oracle.graal.java.IntrinsicContext.*; + import java.lang.reflect.*; import com.oracle.graal.api.meta.*; @@ -94,7 +96,7 @@ assert SnippetGraphUnderConstruction.get() == null; SnippetGraphUnderConstruction.set(graph); - ReplacementContext initialReplacementContext = new ReplacementContext(method, method); + ReplacementContext initialReplacementContext = new IntrinsicContext(method, method, POST_PARSE_INLINE_BCI); new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph); SnippetGraphUnderConstruction.set(null); diff -r bea2f27524ba -r 7e72615e0441 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 Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Mon May 11 17:56:16 2015 -0700 @@ -52,6 +52,7 @@ import com.oracle.graal.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver; import com.oracle.graal.java.BciBlockMapping.BciBlock; import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock; +import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.CallTargetNode.InvokeKind; @@ -84,6 +85,87 @@ return graphBuilderConfig; } + static class ReplacementScope implements AutoCloseable { + FrameState stateBefore; + final Mark mark; + final BytecodeParser parser; + + static ReplacementScope create(boolean enteringReplacement, BytecodeParser parser, HIRFrameStateBuilder currentFrameState, ValueNode[] args) { + if (enteringReplacement) { + return new ReplacementScope(parser, currentFrameState, args); + } + return null; + } + + public ReplacementScope(BytecodeParser parser, HIRFrameStateBuilder currentFrameState, ValueNode[] args) { + this.parser = parser; + if (args == null) { + assert parser.parent == null; + assert parser.bci() == 0; + mark = null; + } else { + mark = parser.getGraph().getMark(); + for (ValueNode arg : args) { + currentFrameState.push(arg.getKind(), arg); + } + stateBefore = currentFrameState.create(parser.bci(), null); + for (int i = args.length - 1; i >= 0; i--) { + ValueNode arg = args[i]; + currentFrameState.pop(arg.getKind()); + } + } + } + + public void close() { + IntrinsicContext intrinsic = (IntrinsicContext) parser.replacementContext; + if (intrinsic != null && intrinsic.isPostParseInlined()) { + return; + } + + FrameState stateAfterReturn = null; + StructuredGraph graph = parser.getGraph(); + for (Node node : graph.getNewNodes(mark)) { + if (node instanceof FrameState) { + FrameState fs = (FrameState) node; + if (BytecodeFrame.isPlaceholderBci(fs.bci)) { + if (fs.bci == BytecodeFrame.AFTER_BCI) { + if (fs.stackSize() != 0) { + assert fs.usages().count() == 1; + ValueNode returnVal = fs.stackAt(0); + assert returnVal == fs.usages().first(); + + ValueNode tos = parser.frameState.pop(returnVal.getKind()); + parser.frameState.push(returnVal.getKind(), returnVal); + FrameState newFs = parser.frameState.create(parser.stream.nextBCI(), null); + fs.replaceAndDelete(newFs); + parser.frameState.pop(returnVal.getKind()); + parser.frameState.push(tos.getKind(), tos); + } else { + if (stateAfterReturn == null) { + if (intrinsic != null && intrinsic.isCompilationRoot()) { + stateAfterReturn = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI)); + } else { + stateAfterReturn = parser.frameState.create(parser.stream.nextBCI(), null); + } + } + fs.replaceAndDelete(stateAfterReturn); + } + } else if (fs.bci == BytecodeFrame.BEFORE_BCI) { + if (stateBefore == null) { + stateBefore = graph.start().stateAfter(); + } + if (stateBefore != fs) { + fs.replaceAndDelete(stateBefore); + } + } else { + assert fs.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI; + } + } + } + } + } + } + // Fully qualified name is a workaround for JDK-8056066 public static class Instance extends com.oracle.graal.phases.Phase { @@ -123,8 +205,10 @@ HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(parser, method, graph); frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || replacementContext != null, graphBuilderConfig.getPlugins().getParameterPlugin()); - parser.build(graph.start(), frameState); + try (ReplacementScope rs = ReplacementScope.create(replacementContext != null, parser, frameState, null)) { + parser.build(graph.start(), frameState); + } GraphUtil.normalizeLoops(graph); // Remove dead parameters. @@ -327,17 +411,27 @@ if (startInstruction == graph.start()) { StartNode startNode = graph.start(); if (method.isSynchronized()) { - startNode.setStateAfter(createFrameState(BytecodeFrame.BEFORE_BCI)); + assert !parsingReplacement(); + startNode.setStateAfter(createFrameState(BytecodeFrame.BEFORE_BCI, startNode)); } else { - - if (graph.method() != null && graph.method().isJavaLangObjectInit()) { - // Don't clear the receiver when Object. is the compilation - // root. The receiver is needed as input to RegisterFinalizerNode. + if (!parsingReplacement()) { + if (graph.method() != null && graph.method().isJavaLangObjectInit()) { + /* + * Don't clear the receiver when Object. is the + * compilation root. The receiver is needed as input to + * RegisterFinalizerNode. + */ + } else { + frameState.clearNonLiveLocals(startBlock, liveness, true); + } + assert bci() == 0; + startNode.setStateAfter(createFrameState(bci(), startNode)); } else { - frameState.clearNonLiveLocals(startBlock, liveness, true); + if (startNode.stateAfter() == null) { + FrameState stateAfterStart = createStateAfterStartOfReplacementGraph(); + startNode.setStateAfter(stateAfterStart); + } } - assert bci() == 0; - startNode.setStateAfter(createFrameState(bci())); } } @@ -379,6 +473,42 @@ } } + /** + * Creates the frame state after the start node of a graph for a + * {@link ReplacementContext replacement} that is the parse root (either for root + * compiling or for post-parse inlining). + */ + private FrameState createStateAfterStartOfReplacementGraph() { + assert parent == null; + assert frameState.method.equals(replacementContext.replacement); + assert bci() == 0; + assert frameState.stackSize == 0; + FrameState stateAfterStart; + if (replacementContext.isIntrinsic() && replacementContext.asIntrinsic().isPostParseInlined()) { + stateAfterStart = graph.add(new FrameState(BytecodeFrame.BEFORE_BCI)); + } else { + ResolvedJavaMethod original = replacementContext.method; + ValueNode[] locals; + if (original.getMaxLocals() == frameState.localsSize() || original.isNative()) { + locals = frameState.locals; + } else { + locals = new ValueNode[original.getMaxLocals()]; + int parameterCount = original.getSignature().getParameterCount(!original.isStatic()); + for (int i = 0; i < parameterCount; i++) { + ValueNode param = frameState.locals[i]; + locals[i] = param; + assert param == null || param instanceof ParameterNode || param.isConstant(); + } + } + ValueNode[] stack = {}; + int stackSize = 0; + ValueNode[] locks = {}; + List monitorIds = Collections.emptyList(); + stateAfterStart = graph.add(new FrameState(null, original, 0, locals, stack, stackSize, locks, monitorIds, false, false)); + } + return stateAfterStart; + } + private void detectLoops(FixedNode startInstruction) { NodeBitMap visited = graph.createNodeBitMap(); NodeBitMap active = graph.createNodeBitMap(); @@ -735,11 +865,11 @@ dispatchBegin = graph.add(new ExceptionObjectNode(metaAccess)); dispatchState.apush(dispatchBegin); dispatchState.setRethrowException(true); - dispatchBegin.setStateAfter(dispatchState.create(bci)); + dispatchBegin.setStateAfter(dispatchState.create(bci, dispatchBegin)); } else { dispatchBegin = graph.add(new DispatchBeginNode()); dispatchState.apush(exceptionObject); - dispatchBegin.setStateAfter(dispatchState.create(bci)); + dispatchBegin.setStateAfter(dispatchState.create(bci, dispatchBegin)); dispatchState.setRethrowException(true); } this.controlFlowSplit = true; @@ -953,7 +1083,7 @@ append(new IfNode(graph.unique(new IsNullNode(receiver)), exception, falseSucc, 0.01)); lastInstr = falseSucc; - exception.setStateAfter(createFrameState(bci())); + exception.setStateAfter(createFrameState(bci(), exception)); exception.setNext(handleException(exception, bci())); return nonNullReceiver; } @@ -965,7 +1095,7 @@ append(new IfNode(graph.unique(IntegerBelowNode.create(index, length, constantReflection)), trueSucc, exception, 0.99)); lastInstr = trueSucc; - exception.setStateAfter(createFrameState(bci())); + exception.setStateAfter(createFrameState(bci(), exception)); exception.setNext(handleException(exception, bci())); } @@ -978,7 +1108,7 @@ protected void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value) { StoreFieldNode storeFieldNode = new StoreFieldNode(receiver, field, value); append(storeFieldNode); - storeFieldNode.setStateAfter(this.createFrameState(stream.nextBCI())); + storeFieldNode.setStateAfter(this.createFrameState(stream.nextBCI(), storeFieldNode)); } /** @@ -1217,8 +1347,8 @@ for (Node n : newNodes) { if (n instanceof StateSplit) { StateSplit stateSplit = (StateSplit) n; - assert stateSplit.stateAfter() != null : error("%s node added by plugin for %s need to have a non-null frame state: %s", StateSplit.class.getSimpleName(), - targetMethod.format("%H.%n(%p)"), stateSplit); + assert stateSplit.stateAfter() != null || !stateSplit.hasSideEffect() : error("%s node added by plugin for %s need to have a non-null frame state: %s", + StateSplit.class.getSimpleName(), targetMethod.format("%H.%n(%p)"), stateSplit); } } try { @@ -1294,14 +1424,18 @@ if (intrinsic != null) { if (intrinsic.isCompilationRoot()) { // A root compiled intrinsic needs to deoptimize - // if the slow path is taken - DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint)); - deopt.setStateBefore(intrinsic.getInvokeStateBefore(graph, null)); + // if the slow path is taken. During frame state + // assignment, the deopt node will get its stateBefore + // from the start node of the intrinsic + append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint)); return true; } else { // Otherwise inline the original method. Any frame state created // during the inlining will exclude frame(s) in the // intrinsic method (see HIRFrameStateBuilder.create(int bci)). + if (context.method.isNative()) { + return false; + } parseAndInlineCallee(context.method, args, null); return true; } @@ -1319,8 +1453,9 @@ if (context == null && isReplacement) { assert !inlinedMethod.equals(targetMethod); if (isIntrinsic) { - context = new IntrinsicContext(targetMethod, inlinedMethod, args, bci); + context = new IntrinsicContext(targetMethod, inlinedMethod, bci); } else { + assert false; context = new ReplacementContext(targetMethod, inlinedMethod); } } @@ -1370,33 +1505,37 @@ } private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, ReplacementContext calleeReplacementContext) { - BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, calleeReplacementContext); - HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(parser, targetMethod, graph); - if (!targetMethod.isStatic()) { - args[0] = nullCheckedValue(args[0]); - } - startFrameState.initializeFromArgumentsArray(args); - parser.build(this.lastInstr, startFrameState); + try (ReplacementScope rs = ReplacementScope.create(calleeReplacementContext != null && !parsingReplacement(), this, frameState, args)) { + + BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, calleeReplacementContext); + HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(parser, targetMethod, graph); + if (!targetMethod.isStatic()) { + args[0] = nullCheckedValue(args[0]); + } + startFrameState.initializeFromArgumentsArray(args); + parser.build(this.lastInstr, startFrameState); - FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode(); - this.lastInstr = calleeBeforeReturnNode; - if (calleeBeforeReturnNode != null) { - ValueNode calleeReturnValue = parser.getReturnValue(); - if (calleeReturnValue != null) { - frameState.push(targetMethod.getSignature().getReturnKind().getStackKind(), calleeReturnValue); + FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode(); + this.lastInstr = calleeBeforeReturnNode; + Kind calleeReturnKind = targetMethod.getSignature().getReturnKind(); + if (calleeBeforeReturnNode != null) { + ValueNode calleeReturnValue = parser.getReturnValue(); + if (calleeReturnValue != null) { + frameState.push(calleeReturnKind.getStackKind(), calleeReturnValue); + } } - } - FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode(); - if (calleeBeforeUnwindNode != null) { - ValueNode calleeUnwindValue = parser.getUnwindValue(); - assert calleeUnwindValue != null; - calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci())); - } + FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode(); + if (calleeBeforeUnwindNode != null) { + ValueNode calleeUnwindValue = parser.getUnwindValue(); + assert calleeUnwindValue != null; + calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci())); + } - // Record inlined method dependency in the graph - if (graph.isInlinedMethodRecordingEnabled()) { - graph.getInlinedMethods().add(targetMethod); + // Record inlined method dependency in the graph + if (graph.isInlinedMethodRecordingEnabled()) { + graph.getInlinedMethods().add(targetMethod); + } } } @@ -1407,7 +1546,7 @@ protected InvokeNode createInvoke(CallTargetNode callTarget, Kind resultType) { InvokeNode invoke = append(new InvokeNode(callTarget, bci())); frameState.pushReturn(resultType, invoke); - invoke.setStateAfter(createFrameState(stream.nextBCI())); + invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke)); return invoke; } @@ -1415,13 +1554,35 @@ DispatchBeginNode exceptionEdge = handleException(null, bci()); InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci())); frameState.pushReturn(resultType, invoke); - invoke.setStateAfter(createFrameState(stream.nextBCI())); + invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke)); return invoke; } @Override protected void genReturn(ValueNode returnVal, Kind returnKind) { - + if (parsingReplacement() && returnVal != null) { + if (returnVal instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) returnVal; + FrameState stateAfter = stateSplit.stateAfter(); + if (stateSplit.hasSideEffect()) { + assert stateSplit != null; + if (stateAfter.bci == BytecodeFrame.AFTER_BCI) { + assert stateAfter.usages().count() == 1; + assert stateAfter.usages().first() == stateSplit; + stateAfter.replaceAtUsages(graph.add(new FrameState(BytecodeFrame.AFTER_BCI, returnVal))); + GraphUtil.killWithUnusedFloatingInputs(stateAfter); + } else { + /* + * This must be the return value from within a partial + * intrinsification. + */ + assert !BytecodeFrame.isPlaceholderBci(stateAfter.bci); + } + } else { + assert stateAfter == null; + } + } + } if (parent == null) { frameState.setRethrowException(false); frameState.clearStack(); @@ -1465,7 +1626,7 @@ MonitorIdNode monitorId = graph.add(new MonitorIdNode(frameState.lockDepth())); MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, monitorId)); frameState.pushLock(x, monitorId); - monitorEnter.setStateAfter(createFrameState(bci)); + monitorEnter.setStateAfter(createFrameState(bci, monitorEnter)); } @Override @@ -1476,7 +1637,7 @@ throw bailout(String.format("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject))); } MonitorExitNode monitorExit = append(new MonitorExitNode(x, monitorId, escapedReturnValue)); - monitorExit.setStateAfter(createFrameState(bci)); + monitorExit.setStateAfter(createFrameState(bci, monitorExit)); } @Override @@ -1627,7 +1788,7 @@ lastLoopExit = loopExit; Debug.log("Target %s Exits %s, scanning framestates...", targetBlock, loop); newState.insertLoopProxies(loopExit, getEntryState(loop, this.getCurrentDimension())); - loopExit.setStateAfter(newState.create(bci)); + loopExit.setStateAfter(newState.create(bci, loopExit)); } lastLoopExit.setNext(target); @@ -1972,7 +2133,7 @@ if (block instanceof ExceptionDispatchBlock) { bci = ((ExceptionDispatchBlock) block).deoptBci; } - abstractMergeNode.setStateAfter(createFrameState(bci)); + abstractMergeNode.setStateAfter(createFrameState(bci, abstractMergeNode)); } } @@ -2055,7 +2216,7 @@ // Create phi functions for all local variables and operand stack slots. frameState.insertLoopPhis(liveness, block.loopId, loopBegin); - loopBegin.setStateAfter(createFrameState(block.startBci)); + loopBegin.setStateAfter(createFrameState(block.startBci, loopBegin)); /* * We have seen all forward branches. All subsequent backward branches will @@ -2108,7 +2269,7 @@ } EntryMarkerNode x = append(new EntryMarkerNode()); frameState.insertProxies(x); - x.setStateAfter(createFrameState(bci)); + x.setStateAfter(createFrameState(bci, x)); } try { @@ -2125,7 +2286,7 @@ bci = stream.currentBCI(); assert block == currentBlock; - assert !(lastInstr instanceof StateSplit) || lastInstr instanceof BeginNode || ((StateSplit) lastInstr).stateAfter() != null : lastInstr; + assert checkLastInstruction(); lastInstr = finishInstruction(lastInstr, frameState); if (bci < endBCI) { if (bci > block.endBci) { @@ -2139,6 +2300,18 @@ } } + protected boolean checkLastInstruction() { + if (lastInstr instanceof BeginNode) { + // ignore + } else if (lastInstr instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) lastInstr; + if (stateSplit.hasSideEffect()) { + assert stateSplit.stateAfter() != null : "side effect " + lastInstr + " requires a non-null stateAfter"; + } + } + return true; + } + private LoopBeginNode appendLoopBegin(FixedWithNextNode fixedWithNext) { EndNode preLoopEnd = graph.add(new EndNode()); LoopBeginNode loopBegin = graph.add(new LoopBeginNode()); @@ -2161,7 +2334,7 @@ private InfopointNode createInfoPointNode(InfopointReason reason) { if (graphBuilderConfig.insertFullDebugInfo()) { - return new FullInfopointNode(reason, createFrameState(bci())); + return new FullInfopointNode(reason, createFrameState(bci(), null)); } else { BytecodePosition position = createBytecodePosition(); // Update the previous infopoint position if no new fixed nodes were inserted @@ -2423,21 +2596,23 @@ } public BailoutException bailout(String string) { - FrameState currentFrameState = createFrameState(bci()); + FrameState currentFrameState = createFrameState(bci(), null); StackTraceElement[] elements = GraphUtil.approxSourceStackTraceElement(currentFrameState); BailoutException bailout = new BailoutException(string); throw GraphUtil.createBailoutException(string, bailout, elements); } - private FrameState createFrameState(int bci) { + private FrameState createFrameState(int bci, StateSplit forStateSplit) { if (currentBlock != null && bci > currentBlock.endBci) { frameState.clearNonLiveLocals(currentBlock, liveness, false); } - return frameState.create(bci); + return frameState.create(bci, forStateSplit); } - public FrameState createStateAfter() { - return createFrameState(stream.nextBCI()); + public void setStateAfter(StateSplit sideEffect) { + assert sideEffect.hasSideEffect(); + FrameState stateAfter = createFrameState(stream.nextBCI(), sideEffect); + sideEffect.setStateAfter(stateAfter); } private BytecodePosition createBytecodePosition() { diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Mon May 11 17:56:16 2015 -0700 @@ -62,6 +62,12 @@ private FrameState outerFrameState; /** + * The closest {@link StateSplit#hasSideEffect() side-effect} predecessors. There will be more + * than one when the current block contains no side-effects but merging predecessor blocks do. + */ + protected StateSplit[] lastSideEffects; + + /** * Creates a new frame state builder for the given method and the given target graph. * * @param method the method whose frame is simulated @@ -144,14 +150,6 @@ javaIndex += kind.getSlotCount(); index++; } - - if (parser.replacementContext instanceof IntrinsicContext) { - IntrinsicContext intrinsic = (IntrinsicContext) parser.replacementContext; - if (intrinsic.isCompilationRoot()) { - // Records the parameters to an root compiled intrinsic - intrinsic.args = locals.clone(); - } - } } private HIRFrameStateBuilder(HIRFrameStateBuilder other) { @@ -202,25 +200,22 @@ return sb.toString(); } - public FrameState create(int bci) { - BytecodeParser parent = parser.getParent(); + public FrameState create(int bci, StateSplit forStateSplit) { if (parser.parsingReplacement()) { IntrinsicContext intrinsic = parser.replacementContext.asIntrinsic(); if (intrinsic != null) { - return intrinsic.getInvokeStateBefore(parser.getGraph(), parent); + return intrinsic.createFrameState(parser.getGraph(), this, forStateSplit); } } - // If this is the recursive call in a partial intrinsification - // the frame(s) of the intrinsic method are omitted - while (parent != null && parent.parsingReplacement() && parent.replacementContext.asIntrinsic() != null) { - parent = parent.getParent(); - } + + // Skip intrinsic frames + BytecodeParser parent = (BytecodeParser) parser.getNonReplacementAncestor(); return create(bci, parent, false); } public FrameState create(int bci, BytecodeParser parent, boolean duringCall) { if (outerFrameState == null && parent != null) { - outerFrameState = parent.getFrameState().create(parent.bci()); + outerFrameState = parent.getFrameState().create(parent.bci(), null); } if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0)); @@ -316,6 +311,17 @@ lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block); assert monitorIds[i] == other.monitorIds[i]; } + + if (lastSideEffects == null) { + lastSideEffects = other.lastSideEffects; + } else { + if (other.lastSideEffects != null) { + int thisLength = lastSideEffects.length; + int otherLength = other.lastSideEffects.length; + lastSideEffects = Arrays.copyOf(lastSideEffects, thisLength + otherLength); + System.arraycopy(other.lastSideEffects, 0, lastSideEffects, thisLength, otherLength); + } + } } private ValueNode merge(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) { @@ -1003,4 +1009,15 @@ } } } + + public void addLastSideEffect(StateSplit sideEffect) { + assert sideEffect != null; + assert sideEffect.hasSideEffect(); + if (lastSideEffects == null) { + lastSideEffects = new StateSplit[]{sideEffect}; + } else { + lastSideEffects = Arrays.copyOf(lastSideEffects, lastSideEffects.length + 1); + lastSideEffects[lastSideEffects.length - 1] = sideEffect; + } + } } diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.java/src/com/oracle/graal/java/IntrinsicContext.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/IntrinsicContext.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/IntrinsicContext.java Mon May 11 17:56:16 2015 -0700 @@ -22,25 +22,19 @@ */ package com.oracle.graal.java; -import static com.oracle.graal.java.HIRFrameStateBuilder.*; - -import java.util.*; +import static com.oracle.graal.api.code.BytecodeFrame.*; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.java.GraphBuilderPhase.Instance.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; /** - * Context for a replacement being inlined as a compiler intrinsic. Deoptimization within a compiler - * intrinsic must replay the intrinsified call. This context object retains the information required - * to build a frame state denoting the JVM state just before the intrinsified call. + * Context for a replacement being inlined as a compiler intrinsic. */ public class IntrinsicContext extends ReplacementContext { /** - * BCI denoting an intrinsic is being parsed for inlining after the caller has been parsed. + * BCI denoting an intrinsic is being parsed for inlining after the graph of the caller has been + * built. */ public static final int POST_PARSE_INLINE_BCI = -1; @@ -50,24 +44,15 @@ public static final int ROOT_COMPILATION_BCI = -2; /** - * The arguments to the intrinsic. - */ - ValueNode[] args; - - /** * The BCI of the intrinsified invocation, {@link #POST_PARSE_INLINE_BCI} or * {@link #ROOT_COMPILATION_BCI}. */ final int bci; - private FrameState stateBeforeCache; - - public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute, ValueNode[] args, int bci) { + public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute, int bci) { super(method, substitute); - assert bci != POST_PARSE_INLINE_BCI || args == null; - this.args = args; this.bci = bci; - assert !isCompilationRoot() || method.hasBytecodes() : "Cannot intrinsic for native or abstract method " + method.format("%H.%n(%p)"); + assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)"); } @Override @@ -83,34 +68,33 @@ return bci == ROOT_COMPILATION_BCI; } - public FrameState getInvokeStateBefore(StructuredGraph graph, BytecodeParser parent) { - if (isCompilationRoot()) { - int maxLocals = method.getMaxLocals(); - // The 'args' were initialized based on the intrinsic method but a - // frame state's 'locals' needs to have the same length as the frame - // state method's 'max_locals'. - ValueNode[] locals = maxLocals == args.length ? args : Arrays.copyOf(args, maxLocals); - ValueNode[] stack = EMPTY_ARRAY; - int stackSize = 0; - ValueNode[] locks = EMPTY_ARRAY; - List monitorIds = Collections.emptyList(); - return graph.add(new FrameState(null, method, 0, locals, stack, stackSize, locks, monitorIds, false, false)); - } else if (isPostParseInlined()) { - return graph.add(new FrameState(BytecodeFrame.BEFORE_BCI)); + public FrameState createFrameState(StructuredGraph graph, HIRFrameStateBuilder frameState, StateSplit forStateSplit) { + assert forStateSplit != graph.start(); + if (forStateSplit.hasSideEffect()) { + if (frameState.lastSideEffects != null) { + // Only the last side effect on any execution path in a replacement + // can inherit the stateAfter of the replaced node + FrameState invalid = graph.add(new FrameState(INVALID_FRAMESTATE_BCI)); + for (StateSplit lastSideEffect : frameState.lastSideEffects) { + lastSideEffect.setStateAfter(invalid); + } + } + frameState.addLastSideEffect(forStateSplit); + return graph.add(new FrameState(AFTER_BCI)); } else { - assert !parent.parsingReplacement() || parent.replacementContext instanceof IntrinsicContext; - if (stateBeforeCache == null) { - - // Find the non-intrinsic ancestor calling the intrinsified method - BytecodeParser ancestor = parent; - while (ancestor.parsingReplacement()) { - assert ancestor.replacementContext instanceof IntrinsicContext; - ancestor = ancestor.getParent(); + if (forStateSplit instanceof AbstractMergeNode) { + // Merge nodes always need a frame state + if (frameState.lastSideEffects != null) { + // A merge after one or more side effects + return graph.add(new FrameState(AFTER_BCI)); + } else { + // A merge before any side effects + return graph.add(new FrameState(BEFORE_BCI)); } - FrameState stateDuring = ancestor.getFrameState().create(ancestor.bci(), ancestor.getParent(), true); - stateBeforeCache = stateDuring.duplicateModifiedBeforeCall(bci, Kind.Void, args); + } else { + // Other non-side-effects do not need a state + return null; } - return stateBeforeCache; } } @@ -121,7 +105,6 @@ @Override public String toString() { - return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + ", bci: " + bci + (args == null ? "" : ", args: " + Arrays.toString(args)) + - (stateBeforeCache == null ? "" : ", stateBefore: " + stateBeforeCache) + "}"; + return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + ", bci: " + bci + "}"; } } diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java Mon May 11 17:56:16 2015 -0700 @@ -44,6 +44,21 @@ } @Test + public void runFirst() throws Throwable { + /* + * Execute Double.isNaN enough times to create a profile indicating that the path returning + * false is never taken. Then compile and execute the test with a NaN value to test that + * deoptimization works in the case of an uncommon trap inlined into an intrinsic. Of + * course, this relies on Double.isNaN never having yet been called with NaN. if it has, + * this test is equivalent to run0. + */ + for (int i = 0; i < 10000; i++) { + Double.isNaN(1D); + } + executeActual(getResolvedJavaMethod("test"), null, java.lang.Double.NaN); + } + + @Test public void run0() throws Throwable { runTest("test", java.lang.Double.NaN); } diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java Mon May 11 17:56:16 2015 -0700 @@ -67,7 +67,7 @@ } - @Test(timeout = 20000) + @Test public void run0() throws Throwable { runTest("test"); } diff -r bea2f27524ba -r 7e72615e0441 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 Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Mon May 11 17:56:16 2015 -0700 @@ -117,6 +117,19 @@ bci == BytecodeFrame.INVALID_FRAMESTATE_BCI; } + /** + * Creates a placeholder frame state with a single element on the stack representing a return + * value. This allows the parsing of an intrinsic to communicate the returned value in a + * {@link StateSplit#stateAfter() stateAfter} to the inlining call site. + * + * @param bci this must be {@link BytecodeFrame#AFTER_BCI} + */ + public FrameState(int bci, ValueNode returnValue) { + this(null, null, bci, 0, returnValue.getKind().getSlotCount(), 0, false, false, null, Collections. emptyList()); + assert bci == BytecodeFrame.AFTER_BCI; + this.values.initialize(0, returnValue); + } + public FrameState(FrameState outerFrameState, ResolvedJavaMethod method, int bci, ValueNode[] locals, ValueNode[] stack, int stackSize, ValueNode[] locks, List monitorIds, boolean rethrowException, boolean duringCall) { this(outerFrameState, method, bci, locals.length, stackSize, locks.length, rethrowException, duringCall, monitorIds, Collections. emptyList()); @@ -421,7 +434,11 @@ String nl = CodeUtil.NEW_LINE; FrameState fs = frameState; while (fs != null) { - MetaUtil.appendLocation(sb, fs.method, fs.bci).append(nl); + MetaUtil.appendLocation(sb, fs.method, fs.bci); + if (BytecodeFrame.isPlaceholderBci(fs.bci)) { + sb.append("//").append(getPlaceholderBciName(fs.bci)); + } + sb.append(nl); sb.append("locals: ["); for (int i = 0; i < fs.localsSize(); i++) { sb.append(i == 0 ? "" : ", ").append(fs.localAt(i) == null ? "_" : fs.localAt(i).toString(Verbosity.Id)); @@ -445,7 +462,11 @@ if (verbosity == Verbosity.Debugger) { return toString(this); } else if (verbosity == Verbosity.Name) { - return super.toString(Verbosity.Name) + "@" + bci; + String res = super.toString(Verbosity.Name) + "@" + bci; + if (BytecodeFrame.isPlaceholderBci(bci)) { + res += "[" + getPlaceholderBciName(bci) + "]"; + } + return res; } else { return super.toString(verbosity); } diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java Mon May 11 17:56:16 2015 -0700 @@ -107,6 +107,12 @@ } @Override + public void setStateAfter(FrameState x) { + assert hasSideEffect() || x == null; + super.setStateAfter(x); + } + + @Override public FrameState stateDuring() { return stateDuring; } diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Mon May 11 17:56:16 2015 -0700 @@ -468,14 +468,28 @@ Kind invokeReturnKind = invoke.asNode().getKind(); if (frameState.bci == BytecodeFrame.AFTER_BCI) { + FrameState stateAfterReturn = stateAtReturn; + if (frameState.method() == null) { + // This is a frame state for a side effect within an intrinsic + // that was parsed for post-parse intrinsification + for (Node usage : frameState.usages()) { + if (usage instanceof ForeignCallNode) { + // A foreign call inside an intrinsic needs to have + // the BCI of the invoke being intrinsified + ForeignCallNode foreign = (ForeignCallNode) usage; + foreign.setBci(invoke.bci()); + } + } + } + /* * pop return kind from invoke's stateAfter and replace with this frameState's return * value (top of stack) */ - FrameState stateAfterReturn = stateAtReturn; if (invokeReturnKind != Kind.Void && (alwaysDuplicateStateAfter || (frameState.stackSize() > 0 && stateAfterReturn.stackAt(0) != frameState.stackAt(0)))) { stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, frameState.stackAt(0)); } + frameState.replaceAndDelete(stateAfterReturn); return stateAfterReturn; } else if (stateAtExceptionEdge != null && isStateAfterException(frameState)) { @@ -581,25 +595,26 @@ ValueNode singleReturnValue = null; PhiNode returnValuePhi = null; for (ReturnNode returnNode : returnNodes) { - if (returnNode.result() != null) { - if (returnValuePhi == null && (singleReturnValue == null || singleReturnValue == returnNode.result())) { + ValueNode result = returnNode.result(); + if (result != null) { + if (returnValuePhi == null && (singleReturnValue == null || singleReturnValue == result)) { /* Only one return value, so no need yet for a phi node. */ - singleReturnValue = returnNode.result(); + singleReturnValue = result; } else if (returnValuePhi == null) { /* Found a second return value, so create phi node. */ - returnValuePhi = merge.graph().addWithoutUnique(new ValuePhiNode(returnNode.result().stamp().unrestricted(), merge)); + returnValuePhi = merge.graph().addWithoutUnique(new ValuePhiNode(result.stamp().unrestricted(), merge)); if (canonicalizedNodes != null) { canonicalizedNodes.add(returnValuePhi); } for (int i = 0; i < merge.forwardEndCount(); i++) { returnValuePhi.addInput(singleReturnValue); } - returnValuePhi.addInput(returnNode.result()); + returnValuePhi.addInput(result); } else { /* Multiple return values, just add to existing phi node. */ - returnValuePhi.addInput(returnNode.result()); + returnValuePhi.addInput(result); } } diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DynamicNewArrayTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DynamicNewArrayTest.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DynamicNewArrayTest.java Mon May 11 17:56:16 2015 -0700 @@ -55,6 +55,7 @@ @Test public void test4() { test("dynamic", Boolean.class, -7); + test("dynamicSynchronized", Boolean.class, -7); } @Test @@ -95,4 +96,8 @@ public static Object dynamic(Class elementType, int length) { return Array.newInstance(elementType, length); } + + public static synchronized Object dynamicSynchronized(Class elementType, int length) { + return Array.newInstance(elementType, length); + } } diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Mon May 11 17:56:16 2015 -0700 @@ -32,7 +32,6 @@ import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; import com.oracle.graal.word.*; /** @@ -50,7 +49,7 @@ @Override protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { - return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(m, null, null); } @Test diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Mon May 11 17:56:16 2015 -0700 @@ -35,7 +35,6 @@ import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; import com.oracle.graal.word.*; import com.oracle.graal.word.nodes.*; @@ -56,7 +55,7 @@ @Override protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { - return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(m, null, null); } @Test diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Mon May 11 17:56:16 2015 -0700 @@ -29,7 +29,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; import com.oracle.graal.word.*; /** @@ -45,7 +44,7 @@ @Override protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { - return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(m, null, null); } @Test diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java Mon May 11 12:08:25 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,240 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.replacements; - -import static com.oracle.graal.api.code.BytecodeFrame.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.graph.*; -import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo; -import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; - -/** - * This phase ensures that there's a single {@linkplain BytecodeFrame#AFTER_BCI collapsed frame - * state} per path. - * - * Removes other frame states from {@linkplain StateSplit#hasSideEffect() non-side-effecting} nodes - * in the graph, and replaces them with {@linkplain BytecodeFrame#INVALID_FRAMESTATE_BCI invalid - * frame states}. - * - * The invalid frame states ensure that no deoptimization to a snippet frame state will happen. - */ -public class CollapseFrameForSingleSideEffectPhase extends Phase { - - private static class IterationState { - public final IterationState previous; - public final Node node; - public final Collection merge; - public final boolean invalid; - - private IterationState(IterationState previous, Node node, Collection merge, boolean invalid) { - this.previous = previous; - this.node = node; - this.merge = merge; - this.invalid = invalid; - } - - public IterationState() { - this(null, null, null, false); - } - - public IterationState addSideEffect(StateSplit sideEffect) { - return new IterationState(this, sideEffect.asNode(), null, true); - } - - public IterationState addBranch(AbstractBeginNode begin) { - return new IterationState(this, begin, null, this.invalid); - } - - public static IterationState merge(AbstractMergeNode merge, Collection before, boolean invalid) { - return new IterationState(null, merge, before, invalid); - } - - public void markAll(NodeBitMap set) { - IterationState state = this; - while (state != null && state.node != null && !set.contains(state.node)) { - set.mark(state.node); - if (state.merge != null) { - for (IterationState branch : state.merge) { - branch.markAll(set); - } - } - state = state.previous; - } - } - - public void markMasked(NodeBitMap unmasked, NodeBitMap masked) { - IterationState state = this; - while (state != null && state.node != null && !masked.contains(state.node)) { - if (state.node instanceof StateSplit) { - unmasked.mark(state.node); - StateSplit split = (StateSplit) state.node; - if (split.hasSideEffect() && state.previous != null) { - state.previous.markAll(masked); - return; - } - } - - if (state.merge != null) { - for (IterationState branch : state.merge) { - branch.markMasked(unmasked, masked); - } - } - state = state.previous; - } - } - } - - @Override - protected void run(StructuredGraph graph) { - CollapseFrameForSingleSideEffectClosure closure = new CollapseFrameForSingleSideEffectClosure(); - ReentrantNodeIterator.apply(closure, graph.start(), new IterationState()); - closure.finishProcessing(graph); - } - - private static class CollapseFrameForSingleSideEffectClosure extends NodeIteratorClosure { - - private List returnStates = new ArrayList<>(); - private List unwindStates = new ArrayList<>(); - - @Override - protected IterationState processNode(FixedNode node, IterationState currentState) { - IterationState state = currentState; - if (node instanceof StateSplit) { - StateSplit stateSplit = (StateSplit) node; - FrameState frameState = stateSplit.stateAfter(); - if (frameState != null) { - if (stateSplit.hasSideEffect()) { - setStateAfter(node.graph(), stateSplit, INVALID_FRAMESTATE_BCI, false); - state = state.addSideEffect(stateSplit); - } else if (currentState.invalid) { - setStateAfter(node.graph(), stateSplit, INVALID_FRAMESTATE_BCI, false); - } else if (stateSplit instanceof StartNode) { - setStateAfter(node.graph(), stateSplit, BEFORE_BCI, false); - } else { - stateSplit.setStateAfter(null); - if (frameState.hasNoUsages()) { - GraphUtil.killWithUnusedFloatingInputs(frameState); - } - } - } - } - if (node instanceof ReturnNode) { - returnStates.add(currentState); - } else if (node instanceof UnwindNode) { - unwindStates.add(currentState); - } - return state; - } - - @Override - protected IterationState merge(AbstractMergeNode merge, List states) { - boolean invalid = false; - for (IterationState state : states) { - if (state.invalid) { - invalid = true; - break; - } - } - return IterationState.merge(merge, states, invalid); - } - - public void finishProcessing(StructuredGraph graph) { - NodeBitMap maskedSideEffects = new NodeBitMap(graph); - NodeBitMap returnSideEffects = new NodeBitMap(graph); - NodeBitMap unwindSideEffects = new NodeBitMap(graph); - - for (IterationState returnState : returnStates) { - returnState.markMasked(returnSideEffects, maskedSideEffects); - } - for (IterationState unwindState : unwindStates) { - unwindState.markMasked(unwindSideEffects, maskedSideEffects); - } - - for (Node returnSideEffect : returnSideEffects) { - if (!unwindSideEffects.contains(returnSideEffect) && !maskedSideEffects.contains(returnSideEffect)) { - StateSplit split = (StateSplit) returnSideEffect; - setStateAfter(graph, split, AFTER_BCI, true); - } - } - - for (Node unwindSideEffect : unwindSideEffects) { - if (!returnSideEffects.contains(unwindSideEffect) && !maskedSideEffects.contains(unwindSideEffect)) { - StateSplit split = (StateSplit) unwindSideEffect; - setStateAfter(graph, split, AFTER_EXCEPTION_BCI, true); - } - } - } - - @Override - protected IterationState afterSplit(AbstractBeginNode node, IterationState oldState) { - return oldState.addBranch(node); - } - - @Override - protected Map processLoop(LoopBeginNode loop, IterationState initialState) { - LoopInfo info = ReentrantNodeIterator.processLoop(this, loop, initialState); - - boolean isNowInvalid = initialState.invalid; - for (IterationState endState : info.endStates.values()) { - isNowInvalid |= endState.invalid; - } - - if (isNowInvalid) { - setStateAfter(loop.graph(), loop, INVALID_FRAMESTATE_BCI, false); - } - - IterationState endState = IterationState.merge(loop, info.endStates.values(), isNowInvalid); - return ReentrantNodeIterator.processLoop(this, loop, endState).exitStates; - } - - /** - * Creates and sets a special frame state for a node. If the existing frame state is - * non-null and has no other usages, it is deleted via - * {@link GraphUtil#killWithUnusedFloatingInputs(Node)}. - * - * @param graph the graph context - * @param node the node whose frame state is updated - * @param bci {@link BytecodeFrame#BEFORE_BCI}, {@link BytecodeFrame#AFTER_EXCEPTION_BCI} or - * {@link BytecodeFrame#INVALID_FRAMESTATE_BCI} - * @param replaceOnly only perform the update if the node currently has a non-null frame - * state - */ - private static void setStateAfter(StructuredGraph graph, StateSplit node, int bci, boolean replaceOnly) { - assert (bci == BEFORE_BCI && node instanceof StartNode) || bci == AFTER_BCI || bci == AFTER_EXCEPTION_BCI || bci == INVALID_FRAMESTATE_BCI; - FrameState currentStateAfter = node.stateAfter(); - if (currentStateAfter != null || !replaceOnly) { - node.setStateAfter(graph.add(new FrameState(bci))); - if (currentStateAfter != null && currentStateAfter.hasNoUsages()) { - GraphUtil.killWithUnusedFloatingInputs(currentStateAfter); - } - } - } - } -} diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java Mon May 11 17:56:16 2015 -0700 @@ -145,12 +145,18 @@ b.add(new UnsafeStoreNode(copy.destinationObject(), copy.destinationOffset(), value, copy.accessKind(), copy.getLocationIdentity())); return true; } else if (res instanceof ForeignCallNode) { - ForeignCallNode foreign = (ForeignCallNode) res; - foreign.setBci(b.bci()); + /* + * Need to update the BCI of a ForeignCallNode so that it gets the stateDuring in the + * case that the foreign call can deoptimize. As with all deoptimization, we need a + * state in a normal method as opposed to an intrinsic. + */ + GraphBuilderContext ancestor = b.getNonReplacementAncestor(); + if (ancestor != null) { + ForeignCallNode foreign = (ForeignCallNode) res; + foreign.setBci(ancestor.bci()); + } } - res = b.add(res); - boolean nonValueType = false; if (returnKind == Kind.Object && stamp instanceof ObjectStamp) { ResolvedJavaType type = ((ObjectStamp) stamp).type(); @@ -162,16 +168,10 @@ if (returnKind != Kind.Void) { assert nonValueType || res.getKind().getStackKind() != Kind.Void; - b.push(returnKind.getStackKind(), res); + res = b.addPush(returnKind.getStackKind(), res); } else { assert res.getKind().getStackKind() == Kind.Void; - } - - if (res instanceof StateSplit) { - StateSplit stateSplit = (StateSplit) res; - if (stateSplit.stateAfter() == null) { - stateSplit.setStateAfter(b.createStateAfter()); - } + res = b.add(res); } return true; diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Mon May 11 17:56:16 2015 -0700 @@ -152,7 +152,7 @@ if (invoke.getKind() != Kind.Void) { frameStateBuilder.push(returnType.getKind(), invoke); } - invoke.setStateAfter(frameStateBuilder.create(bci)); + invoke.setStateAfter(frameStateBuilder.create(bci, invoke)); if (invoke.getKind() != Kind.Void) { frameStateBuilder.pop(returnType.getKind()); } @@ -219,7 +219,7 @@ GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); StructuredGraph calleeGraph = new StructuredGraph(method, AllowAssumptions.NO); - IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, null, IntrinsicContext.POST_PARSE_INLINE_BCI); + IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, IntrinsicContext.POST_PARSE_INLINE_BCI); new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(calleeGraph); // Remove all frame states from inlinee diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java Mon May 11 17:56:16 2015 -0700 @@ -152,8 +152,10 @@ return graph; } - public FrameState createStateAfter() { - return getGraph().add(new FrameState(BytecodeFrame.BEFORE_BCI)); + public void setStateAfter(StateSplit sideEffect) { + assert sideEffect.hasSideEffect(); + FrameState stateAfter = getGraph().add(new FrameState(BytecodeFrame.BEFORE_BCI)); + sideEffect.setStateAfter(stateAfter); } public GraphBuilderContext getParent() { diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java Mon May 11 17:56:16 2015 -0700 @@ -178,7 +178,7 @@ } @Override - public FrameState createStateAfter() { + public void setStateAfter(StateSplit stateSplit) { throw unimplemented(); } @@ -226,10 +226,11 @@ } @Override - public FrameState createStateAfter() { + public void setStateAfter(StateSplit stateSplit) { Node stateAfter = decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId); getGraph().add(stateAfter); - return (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter); + FrameState fs = (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter); + stateSplit.setStateAfter(fs); } @Override diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Mon May 11 17:56:16 2015 -0700 @@ -25,6 +25,7 @@ import static com.oracle.graal.api.meta.MetaUtil.*; import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; +import static com.oracle.graal.java.IntrinsicContext.*; import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; import static java.lang.String.*; @@ -299,9 +300,7 @@ StructuredGraph graph = UseSnippetGraphCache ? graphs.get(method) : null; if (graph == null) { try (DebugCloseable a = SnippetPreparationTime.start()) { - FrameStateProcessing frameStateProcessing = method.getAnnotation(Snippet.class).removeAllFrameStates() ? FrameStateProcessing.Removal - : FrameStateProcessing.CollapseFrameForSingleSideEffect; - StructuredGraph newGraph = makeGraph(method, args, recursiveEntry, frameStateProcessing); + StructuredGraph newGraph = makeGraph(method, args, recursiveEntry); Debug.metric("SnippetNodeCount[%#s]", method).add(newGraph.getNodeCount()); if (!UseSnippetGraphCache || args != null) { return newGraph; @@ -346,7 +345,7 @@ } StructuredGraph graph = graphs.get(substitute); if (graph == null) { - graph = makeGraph(substitute, null, original, FrameStateProcessing.None); + graph = makeGraph(substitute, null, original); graph.freeze(); graphs.putIfAbsent(substitute, graph); graph = graphs.get(substitute); @@ -445,19 +444,18 @@ * @param args * @param original the original method if {@code method} is a {@linkplain MethodSubstitution * substitution} otherwise null - * @param frameStateProcessing controls how {@link FrameState FrameStates} should be handled. */ - public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, FrameStateProcessing frameStateProcessing) { + public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original) { try (OverrideScope s = OptionValue.override(DeoptALot, false)) { - return createGraphMaker(method, original, frameStateProcessing).makeGraph(args); + return createGraphMaker(method, original).makeGraph(args); } } /** * Can be overridden to return an object that specializes various parts of graph preprocessing. */ - protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original, FrameStateProcessing frameStateProcessing) { - return new GraphMaker(this, substitute, original, frameStateProcessing); + protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original) { + return new GraphMaker(this, substitute, original); } /** @@ -465,18 +463,6 @@ */ final ConcurrentMap graphCache = new ConcurrentHashMap<>(); - public enum FrameStateProcessing { - None, - /** - * @see CollapseFrameForSingleSideEffectPhase - */ - CollapseFrameForSingleSideEffect, - /** - * Removes frame states from all nodes in the graph. - */ - Removal - } - /** * Creates and preprocesses a graph for a replacement. */ @@ -496,16 +482,10 @@ */ protected final ResolvedJavaMethod substitutedMethod; - /** - * Controls how FrameStates are processed. - */ - private FrameStateProcessing frameStateProcessing; - - protected GraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod, FrameStateProcessing frameStateProcessing) { + protected GraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod) { this.replacements = replacements; this.method = substitute; this.substitutedMethod = substitutedMethod; - this.frameStateProcessing = frameStateProcessing; } public StructuredGraph makeGraph(Object[] args) { @@ -536,18 +516,6 @@ new ConvertDeoptimizeToGuardPhase().apply(graph, null); assert sideEffectCount == graph.getNodes().filter(e -> hasSideEffect(e)).count() : "deleted side effecting node"; - switch (frameStateProcessing) { - case Removal: - for (Node node : graph.getNodes()) { - if (node instanceof StateSplit) { - ((StateSplit) node).setStateAfter(null); - } - } - break; - case CollapseFrameForSingleSideEffect: - new CollapseFrameForSingleSideEffectPhase().apply(graph); - break; - } new DeadCodeEliminationPhase(Required).apply(graph); } @@ -629,12 +597,13 @@ OptimisticOptimizations optimisticOpts) { ReplacementContext initialReplacementContext = null; if (method.getAnnotation(Snippet.class) == null) { - // Late inlined intrinsic - initialReplacementContext = new IntrinsicContext(substitutedMethod, method, null, -1); + // Post-parse inlined intrinsic + initialReplacementContext = new IntrinsicContext(substitutedMethod, method, POST_PARSE_INLINE_BCI); } else { // Snippet ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method; - initialReplacementContext = new ReplacementContext(original, method); + // initialReplacementContext = new ReplacementContext(original, method); + initialReplacementContext = new IntrinsicContext(original, method, POST_PARSE_INLINE_BCI); } return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, initialReplacementContext); } diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Mon May 11 17:56:16 2015 -0700 @@ -24,7 +24,6 @@ import static com.oracle.graal.api.code.BytecodeFrame.*; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.compiler.common.*; @@ -114,13 +113,6 @@ StructuredGraph methodSubstitution = tool.getReplacements().getSubstitution(getTargetMethod(), true, bci); if (methodSubstitution != null) { methodSubstitution = methodSubstitution.copy(); - if (stateAfter() == null || stateAfter().bci == BytecodeFrame.AFTER_BCI) { - /* - * handles the case of a MacroNode inside a snippet used for another MacroNode - * lowering - */ - new CollapseFrameForSingleSideEffectPhase().apply(methodSubstitution); - } return lowerReplacement(methodSubstitution, tool); } return null; diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java Mon May 11 17:56:16 2015 -0700 @@ -34,8 +34,8 @@ public static final NodeClass TYPE = NodeClass.create(NeverPartOfCompilationNode.class); protected final String message; - public NeverPartOfCompilationNode(String message, FrameState stateAfter) { - super(TYPE, StampFactory.forVoid(), stateAfter); + public NeverPartOfCompilationNode(String message) { + super(TYPE, StampFactory.forVoid()); this.message = message; } diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java Mon May 11 17:56:16 2015 -0700 @@ -239,7 +239,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode message) { if (message.isConstant()) { String messageString = message.asConstant().toValueString(); - b.add(new NeverPartOfCompilationNode(messageString, b.createStateAfter())); + b.add(new NeverPartOfCompilationNode(messageString)); return true; } else if (canDelayIntrinsification) { return false; diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java Mon May 11 17:56:16 2015 -0700 @@ -182,7 +182,7 @@ /** * Collects the effects of virtualizing the given node. - * + * * @return {@code true} if the effects include removing the node, {@code false} otherwise. */ protected abstract boolean processNode(Node node, BlockT state, GraphEffectList effects, FixedWithNextNode lastFixedNode); @@ -210,6 +210,7 @@ BlockT loopEntryState = initialState; BlockT lastMergedState = cloneState(initialState); + processInitialLoopState(loop, lastMergedState); MergeProcessor mergeProcessor = createMergeProcessor(loop.getHeader()); for (int iteration = 0; iteration < 10; iteration++) { LoopInfo info = ReentrantBlockIterator.processLoop(this, loop, cloneState(lastMergedState)); @@ -245,6 +246,11 @@ throw new GraalInternalError("too many iterations at %s", loop); } + @SuppressWarnings("unused") + protected void processInitialLoopState(Loop loop, BlockT initialState) { + // nothing to do + } + private void doMergeWithoutDead(MergeProcessor mergeProcessor, List states) { int alive = 0; for (BlockT state : states) { diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java Mon May 11 17:56:16 2015 -0700 @@ -115,7 +115,7 @@ ValueNode cacheObject; ObjectState obj = closure.getObjectState(this, object); if (obj != null) { - assert !obj.isVirtual(); + assert !obj.isVirtual() : object; cacheObject = obj.getMaterializedValue(); } else { cacheObject = object; diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Mon May 11 17:56:16 2015 -0700 @@ -27,6 +27,7 @@ import java.util.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; @@ -212,6 +213,23 @@ } @Override + protected void processInitialLoopState(Loop loop, PEReadEliminationBlockState initialState) { + super.processInitialLoopState(loop, initialState); + + for (PhiNode phi : ((LoopBeginNode) loop.getHeader().getBeginNode()).phis()) { + ValueNode firstValue = phi.valueAt(0); + if (firstValue != null) { + firstValue = GraphUtil.unproxify(firstValue); + for (Map.Entry entry : new ArrayList<>(initialState.getReadCache().entrySet())) { + if (entry.getKey().object == firstValue) { + initialState.addReadCache(phi, entry.getKey().identity, entry.getKey().index, entry.getValue(), this); + } + } + } + } + } + + @Override protected void processLoopExit(LoopExitNode exitNode, PEReadEliminationBlockState initialState, PEReadEliminationBlockState exitState, GraphEffectList effects) { super.processLoopExit(exitNode, initialState, exitState, effects); diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Mon May 11 17:56:16 2015 -0700 @@ -26,6 +26,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.compiler.common.util.*; import com.oracle.graal.debug.*; @@ -359,6 +360,20 @@ } @Override + protected void processInitialLoopState(Loop loop, BlockT initialState) { + super.processInitialLoopState(loop, initialState); + + for (PhiNode phi : ((LoopBeginNode) loop.getHeader().getBeginNode()).phis()) { + if (phi.valueAt(0) != null) { + ObjectState state = getObjectState(initialState, phi.valueAt(0)); + if (state != null && state.isVirtual()) { + addAndMarkAlias(state.virtual, phi); + } + } + } + } + + @Override protected void processLoopExit(LoopExitNode exitNode, BlockT initialState, BlockT exitState, GraphEffectList effects) { if (exitNode.graph().hasValueProxies()) { Map proxies = Node.newMap(); diff -r bea2f27524ba -r 7e72615e0441 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java Mon May 11 12:08:25 2015 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java Mon May 11 17:56:16 2015 -0700 @@ -61,6 +61,11 @@ * (non-indexed) Literal .
* See {@link Source#fromReader(Reader, String)} *

+ *

  • Sub-Source: A representation of the contents of a sub-range of another + * {@link Source}.
    + * See @link {@link Source#subSource(Source, int, int)}
    + * See @link {@link Source#subSource(Source, int)}
  • + *

    *

  • AppendableSource: Literal contents are provided by the client, * incrementally, after the instance is created.
    * See {@link Source#fromAppendableText(String)}
    @@ -250,8 +255,8 @@ * @param description a note about the origin, for error messages and debugging * @return a newly created, non-indexed, initially empty, appendable source representation */ - public static AppendableSource fromAppendableText(String description) { - final AppendableSource source = new AppendableLiteralSource(description); + public static Source fromAppendableText(String description) { + final Source source = new AppendableLiteralSource(description); notifyNewSource(source).tagAs(Tags.FROM_LITERAL); return source; } @@ -281,11 +286,39 @@ * @param name string to use for indexing/lookup * @return a newly created, indexed, initially empty, appendable source representation */ - public static AppendableSource fromNamedAppendableText(String name) { + public static Source fromNamedAppendableText(String name) { final Source source = new AppendableLiteralSource(name); nameToSource.put(name, new WeakReference<>(source)); notifyNewSource(source).tagAs(Tags.FROM_LITERAL); - return (AppendableSource) source; + return source; + } + + /** + * Creates a {@linkplain Source Source instance} that represents the contents of a sub-range of + * an existing {@link Source}. + * + * @param base an existing Source instance + * @param baseCharIndex 0-based index of the first character of the sub-range + * @param length the number of characters in the sub-range + * @return a new instance representing a sub-range of another Source + * @throws IllegalArgumentException if the specified sub-range is not contained in the base + */ + public static Source subSource(Source base, int baseCharIndex, int length) { + final SubSource subSource = SubSource.create(base, baseCharIndex, length); + return subSource; + } + + /** + * Creates a {@linkplain Source Source instance} that represents the contents of a sub-range at + * the end of an existing {@link Source}. + * + * @param base an existing Source instance + * @param baseCharIndex 0-based index of the first character of the sub-range + * @return a new instance representing a sub-range at the end of another Source + * @throws IllegalArgumentException if the index is out of range + */ + public static Source subSource(Source base, int baseCharIndex) { + return subSource(base, baseCharIndex, base.getLength() - baseCharIndex); } /** @@ -418,25 +451,6 @@ return builder.toString(); } - public abstract static class AppendableSource extends Source { - - /** - * Sets the mark. - */ - public void setMark() { - } - - public abstract void appendCode(CharSequence chars); - - /** - * Gets the code from the mark to the end. - */ - public String getCodeFromMark() { - return getCode(); - } - - } - private final ArrayList tags = new ArrayList<>(); private Source() { @@ -515,7 +529,7 @@ * Gets the number of characters in the source. */ public final int getLength() { - return checkTextMap().length(); + return getTextMap().length(); } /** @@ -534,9 +548,8 @@ * Gets the text (not including a possible terminating newline) in a (1-based) numbered line. */ public final String getCode(int lineNumber) { - checkTextMap(); - final int offset = textMap.lineStartOffset(lineNumber); - final int length = textMap.lineLength(lineNumber); + final int offset = getTextMap().lineStartOffset(lineNumber); + final int length = getTextMap().lineLength(lineNumber); return getCode().substring(offset, offset + length); } @@ -545,7 +558,7 @@ * source without a terminating newline count as a line. */ public final int getLineCount() { - return checkTextMap().lineCount(); + return getTextMap().lineCount(); } /** @@ -555,7 +568,7 @@ * @throws IllegalArgumentException if the offset is outside the text contents */ public final int getLineNumber(int offset) throws IllegalArgumentException { - return checkTextMap().offsetToLine(offset); + return getTextMap().offsetToLine(offset); } /** @@ -564,7 +577,7 @@ * @throws IllegalArgumentException if the offset is outside the text contents */ public final int getColumnNumber(int offset) throws IllegalArgumentException { - return checkTextMap().offsetToCol(offset); + return getTextMap().offsetToCol(offset); } /** @@ -573,7 +586,7 @@ * @throws IllegalArgumentException if there is no such line in the text */ public final int getLineStartOffset(int lineNumber) throws IllegalArgumentException { - return checkTextMap().lineStartOffset(lineNumber); + return getTextMap().lineStartOffset(lineNumber); } /** @@ -583,7 +596,17 @@ * @throws IllegalArgumentException if there is no such line in the text */ public final int getLineLength(int lineNumber) throws IllegalArgumentException { - return checkTextMap().lineLength(lineNumber); + return getTextMap().lineLength(lineNumber); + } + + /** + * Append text to a Source explicitly created as Appendable. + * + * @param chars the text to append + * @throws UnsupportedOperationException by concrete subclasses that do not support appending + */ + public void appendCode(CharSequence chars) { + throw new UnsupportedOperationException(); } /** @@ -623,9 +646,8 @@ * @throws IllegalStateException if the source is one of the "null" instances */ public final SourceSection createSection(String identifier, int startLine, int startColumn, int length) { - checkTextMap(); - final int lineStartOffset = textMap.lineStartOffset(startLine); - if (startColumn > textMap.lineLength(startLine)) { + final int lineStartOffset = getTextMap().lineStartOffset(startLine); + if (startColumn > getTextMap().lineLength(startLine)) { throw new IllegalArgumentException("column out of range"); } final int startOffset = lineStartOffset + startColumn - 1; @@ -653,10 +675,8 @@ */ public final SourceSection createSection(String identifier, int charIndex, int length) throws IllegalArgumentException { checkRange(charIndex, length); - checkTextMap(); final int startLine = getLineNumber(charIndex); final int startColumn = charIndex - getLineStartOffset(startLine) + 1; - return new DefaultSourceSection(this, identifier, startLine, startColumn, charIndex, length); } @@ -677,9 +697,8 @@ * @throws IllegalStateException if the source is one of the "null" instances */ public final SourceSection createSection(String identifier, int lineNumber) { - checkTextMap(); - final int charIndex = textMap.lineStartOffset(lineNumber); - final int length = textMap.lineLength(lineNumber); + final int charIndex = getTextMap().lineStartOffset(lineNumber); + final int length = getTextMap().lineLength(lineNumber); return createSection(identifier, charIndex, length); } @@ -702,7 +721,7 @@ return getName(); } - protected final TextMap checkTextMap() { + protected final TextMap getTextMap() { if (textMap == null) { textMap = createTextMap(); } @@ -786,9 +805,8 @@ } } - private static final class AppendableLiteralSource extends AppendableSource { + private static final class AppendableLiteralSource extends Source { private String description; - private int mark = 0; final List codeList = new ArrayList<>(); public AppendableLiteralSource(String description) { @@ -839,20 +857,11 @@ } @Override - public String getCodeFromMark() { - return getCodeFromIndex(mark); - } - - @Override public void appendCode(CharSequence chars) { codeList.add(chars); clearTextMap(); } - @Override - public void setMark() { - mark = codeList.size(); - } } private static final class FileSource extends Source { @@ -1016,6 +1025,61 @@ } } + private static final class SubSource extends Source { + private final Source base; + private final int baseIndex; + private final int subLength; + + private static SubSource create(Source base, int baseIndex, int length) { + if (baseIndex < 0 || length < 0 || baseIndex + length > base.getLength()) { + throw new IllegalArgumentException("text positions out of range"); + } + return new SubSource(base, baseIndex, length); + } + + private SubSource(Source base, int baseIndex, int length) { + this.base = base; + this.baseIndex = baseIndex; + this.subLength = length; + } + + @Override + protected void reset() { + assert false; + } + + @Override + public String getName() { + return base.getName(); + } + + @Override + public String getShortName() { + return base.getShortName(); + } + + @Override + public String getPath() { + return base.getPath(); + } + + @Override + public URL getURL() { + return null; + } + + @Override + public Reader getReader() { + assert false; + return null; + } + + @Override + public String getCode() { + return base.getCode(baseIndex, subLength); + } + } + private static final class BytesSource extends Source { private final String name; diff -r bea2f27524ba -r 7e72615e0441 mx/mx_graal.py --- a/mx/mx_graal.py Mon May 11 12:08:25 2015 -0700 +++ b/mx/mx_graal.py Mon May 11 17:56:16 2015 -0700 @@ -1606,7 +1606,6 @@ parser = ArgumentParser(prog='mx ctw') parser.add_argument('--ctwopts', action='store', help='space separated Graal options used for CTW compilations (default: --ctwopts="' + defaultCtwopts + '")', default=defaultCtwopts, metavar='') parser.add_argument('--jar', action='store', help='jar of classes to compiled instead of rt.jar', metavar='') - parser.add_argument('vmargs', nargs=REMAINDER, metavar='VM options...') args, vmargs = parser.parse_known_args(args) diff -r bea2f27524ba -r 7e72615e0441 mxtool/mx.py --- a/mxtool/mx.py Mon May 11 12:08:25 2015 -0700 +++ b/mxtool/mx.py Mon May 11 17:56:16 2015 -0700 @@ -4157,8 +4157,8 @@ launchOut.open('launchConfiguration', {'type' : 'org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType'}) launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.capture_output', 'value': consoleOn}) launchOut.open('mapAttribute', {'key' : 'org.eclipse.debug.core.environmentVariables'}) - launchOut.element('mapEntry', {'key' : 'JAVA_HOME', 'value' : _opts.java_home}) - launchOut.element('mapEntry', {'key' : 'EXTRA_JAVA_HOMES', 'value' : _opts.extra_java_homes}) + launchOut.element('mapEntry', {'key' : 'JAVA_HOME', 'value' : _default_java_home.jdk}) + launchOut.element('mapEntry', {'key' : 'EXTRA_JAVA_HOMES', 'value' : os.pathsep.join([extraJavaHome.jdk for extraJavaHome in _extra_java_homes])}) launchOut.close('mapAttribute') if refresh: