use of org.graalvm.compiler.nodes.MergeNode in project graal by oracle.
the class OptimizeExceptionCallsPhase method setBranchProbability.
/**
* Sets the branch probability of the guarding IfNode to a small value. The effect is that the
* exception call block is put at the end of the method. The other block (= the regular path)
* gets the fall-through block of the IfNode. This should give a better performance - and it
* looks nicer in the disassembly.
*/
private static void setBranchProbability(Node endNode) {
Node node = endNode;
Node predecessor = node.predecessor();
// Go "up" the graph until we find an IfNode
while (predecessor != null) {
if (predecessor instanceof IfNode && node instanceof BeginNode) {
// We found an IfNode which branches to our runtime exception call
IfNode ifNode = (IfNode) predecessor;
ifNode.setTrueSuccessorProbability(node == ifNode.trueSuccessor() ? 0.00001 : 0.99999);
return;
}
if (predecessor instanceof MergeNode || predecessor instanceof ControlSplitNode) {
// Any other split or merge is suspicious: we abort
return;
}
node = predecessor;
predecessor = node.predecessor();
}
}
use of org.graalvm.compiler.nodes.MergeNode in project graal by oracle.
the class SimpleCFGTest method testImplies.
@Test
public void testImplies() {
OptionValues options = getInitialOptions();
DebugContext debug = DebugContext.create(options, new GraalDebugHandlersFactory(getSnippetReflection()));
StructuredGraph graph = new StructuredGraph.Builder(options, debug, AllowAssumptions.YES).build();
EndNode trueEnd = graph.add(new EndNode());
EndNode falseEnd = graph.add(new EndNode());
AbstractBeginNode trueBegin = graph.add(new BeginNode());
trueBegin.setNext(trueEnd);
AbstractBeginNode falseBegin = graph.add(new BeginNode());
falseBegin.setNext(falseEnd);
IfNode ifNode = graph.add(new IfNode(null, trueBegin, falseBegin, 0.5));
graph.start().setNext(ifNode);
AbstractMergeNode merge = graph.add(new MergeNode());
merge.addForwardEnd(trueEnd);
merge.addForwardEnd(falseEnd);
ReturnNode returnNode = graph.add(new ReturnNode(null));
merge.setNext(returnNode);
dumpGraph(graph);
ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
Block[] blocks = cfg.getBlocks();
// check number of blocks
assertDeepEquals(4, blocks.length);
// check block - node assignment
assertDeepEquals(blocks[0], cfg.blockFor(graph.start()));
assertDeepEquals(blocks[0], cfg.blockFor(ifNode));
assertDeepEquals(blocks[1], cfg.blockFor(trueBegin));
assertDeepEquals(blocks[1], cfg.blockFor(trueEnd));
assertDeepEquals(blocks[2], cfg.blockFor(falseBegin));
assertDeepEquals(blocks[2], cfg.blockFor(falseEnd));
assertDeepEquals(blocks[3], cfg.blockFor(merge));
assertDeepEquals(blocks[3], cfg.blockFor(returnNode));
// check dominators
assertDominator(blocks[0], null);
assertDominator(blocks[1], blocks[0]);
assertDominator(blocks[2], blocks[0]);
assertDominator(blocks[3], blocks[0]);
// check dominated
assertDominatedSize(blocks[0], 3);
assertDominatedSize(blocks[1], 0);
assertDominatedSize(blocks[2], 0);
assertDominatedSize(blocks[3], 0);
// check postdominators
assertPostdominator(blocks[0], blocks[3]);
assertPostdominator(blocks[1], blocks[3]);
assertPostdominator(blocks[2], blocks[3]);
assertPostdominator(blocks[3], null);
}
use of org.graalvm.compiler.nodes.MergeNode in project graal by oracle.
the class BytecodeParser method parseAndInlineCallee.
protected void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) {
FixedWithNextNode calleeBeforeUnwindNode = null;
ValueNode calleeUnwindValue = null;
try (IntrinsicScope s = calleeIntrinsicContext != null && !parsingIntrinsic() ? new IntrinsicScope(this, targetMethod.getSignature().toParameterKinds(!targetMethod.isStatic()), args) : null) {
BytecodeParser parser = graphBuilderInstance.createBytecodeParser(graph, this, targetMethod, INVOCATION_ENTRY_BCI, calleeIntrinsicContext);
FrameStateBuilder startFrameState = new FrameStateBuilder(parser, parser.code, graph);
if (!targetMethod.isStatic()) {
args[0] = nullCheckedValue(args[0]);
}
startFrameState.initializeFromArgumentsArray(args);
parser.build(this.lastInstr, startFrameState);
if (parser.returnDataList == null) {
/* Callee does not return. */
lastInstr = null;
} else {
ValueNode calleeReturnValue;
MergeNode returnMergeNode = null;
if (s != null) {
s.returnDataList = parser.returnDataList;
}
if (parser.returnDataList.size() == 1) {
/* Callee has a single return, we can continue parsing at that point. */
ReturnToCallerData singleReturnData = parser.returnDataList.get(0);
lastInstr = singleReturnData.beforeReturnNode;
calleeReturnValue = singleReturnData.returnValue;
} else {
assert parser.returnDataList.size() > 1;
/* Callee has multiple returns, we need to insert a control flow merge. */
returnMergeNode = graph.add(new MergeNode());
calleeReturnValue = ValueMergeUtil.mergeValueProducers(returnMergeNode, parser.returnDataList, returnData -> returnData.beforeReturnNode, returnData -> returnData.returnValue);
}
if (calleeReturnValue != null) {
frameState.push(targetMethod.getSignature().getReturnKind().getStackKind(), calleeReturnValue);
}
if (returnMergeNode != null) {
returnMergeNode.setStateAfter(createFrameState(stream.nextBCI(), returnMergeNode));
lastInstr = finishInstruction(returnMergeNode, frameState);
}
}
/*
* Propagate any side effects into the caller when parsing intrinsics.
*/
if (parser.frameState.isAfterSideEffect() && parsingIntrinsic()) {
for (StateSplit sideEffect : parser.frameState.sideEffects()) {
frameState.addSideEffect(sideEffect);
}
}
calleeBeforeUnwindNode = parser.getBeforeUnwindNode();
if (calleeBeforeUnwindNode != null) {
calleeUnwindValue = parser.getUnwindValue();
assert calleeUnwindValue != null;
}
}
/*
* Method handleException will call createTarget, which wires this exception edge to the
* corresponding exception dispatch block in the caller. In the case where it wires to the
* caller's unwind block, any FrameState created meanwhile, e.g., FrameState for
* LoopExitNode, would be instantiated with AFTER_EXCEPTION_BCI. Such frame states should
* not be fixed by IntrinsicScope.close, as they denote the states of the caller. Thus, the
* following code should be placed outside the IntrinsicScope, so that correctly created
* FrameStates are not replaced.
*/
if (calleeBeforeUnwindNode != null) {
calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci(), false));
}
}
use of org.graalvm.compiler.nodes.MergeNode in project graal by oracle.
the class BytecodeParser method afterInvocationPluginExecution.
/**
* Performs any action required after execution of an invocation plugin. This includes
* {@linkplain InvocationPluginAssertions#check checking} invocation plugin invariants as well
* as weaving the {@code else} branch of the code woven by {@link #guardIntrinsic} if
* {@code guard != null}.
*/
protected void afterInvocationPluginExecution(boolean pluginHandledInvoke, InvocationPluginAssertions assertions, IntrinsicGuard intrinsicGuard, InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) {
assert assertions.check(pluginHandledInvoke);
if (intrinsicGuard != null) {
if (pluginHandledInvoke) {
if (intrinsicGuard.nonIntrinsicBranch != null) {
// Intrinsic emitted: emit a virtual call to the target method and
// merge it with the intrinsic branch
EndNode intrinsicEnd = append(new EndNode());
FrameStateBuilder intrinsicState = null;
FrameStateBuilder nonIntrinisicState = null;
if (resultType != JavaKind.Void) {
intrinsicState = frameState.copy();
frameState.pop(resultType);
nonIntrinisicState = frameState;
}
lastInstr = intrinsicGuard.nonIntrinsicBranch;
createNonInlinedInvoke(getActionForInvokeExceptionEdge(null), bci(), args, targetMethod, invokeKind, resultType, returnType, intrinsicGuard.profile);
EndNode nonIntrinsicEnd = append(new EndNode());
AbstractMergeNode mergeNode = graph.add(new MergeNode());
mergeNode.addForwardEnd(intrinsicEnd);
if (intrinsicState != null) {
intrinsicState.merge(mergeNode, nonIntrinisicState);
frameState = intrinsicState;
}
mergeNode.addForwardEnd(nonIntrinsicEnd);
mergeNode.setStateAfter(frameState.create(stream.nextBCI(), mergeNode));
lastInstr = mergeNode;
}
} else {
// Intrinsic was not applied: remove intrinsic guard
// and restore the original receiver node in the arguments array
intrinsicGuard.lastInstr.setNext(null);
GraphUtil.removeNewNodes(graph, intrinsicGuard.mark);
lastInstr = intrinsicGuard.lastInstr;
args[0] = intrinsicGuard.receiver;
}
}
}
use of org.graalvm.compiler.nodes.MergeNode in project graal by oracle.
the class BytecodeParser method iterateBytecodesForBlock.
@SuppressWarnings("try")
protected void iterateBytecodesForBlock(BciBlock block) {
if (block.isLoopHeader) {
// Create the loop header block, which later will merge the backward branches of
// the loop.
controlFlowSplit = true;
LoopBeginNode loopBegin = appendLoopBegin(this.lastInstr, block.startBci);
lastInstr = loopBegin;
// Create phi functions for all local variables and operand stack slots.
frameState.insertLoopPhis(liveness, block.loopId, loopBegin, forceLoopPhis(), stampFromValueForForcedPhis());
loopBegin.setStateAfter(createFrameState(block.startBci, loopBegin));
/*
* We have seen all forward branches. All subsequent backward branches will merge to the
* loop header. This ensures that the loop header has exactly one non-loop predecessor.
*/
setFirstInstruction(block, loopBegin);
/*
* We need to preserve the frame state builder of the loop header so that we can merge
* values for phi functions, so make a copy of it.
*/
setEntryState(block, frameState.copy());
debug.log(" created loop header %s", loopBegin);
} else if (lastInstr instanceof MergeNode) {
/*
* All inputs of non-loop phi nodes are known by now. We can infer the stamp for the
* phi, so that parsing continues with more precise type information.
*/
frameState.inferPhiStamps((AbstractMergeNode) lastInstr);
}
assert lastInstr.next() == null : "instructions already appended at block " + block;
debug.log(" frameState: %s", frameState);
lastInstr = finishInstruction(lastInstr, frameState);
int endBCI = stream.endBCI();
stream.setBCI(block.startBci);
int bci = block.startBci;
BytecodesParsed.add(debug, block.endBci - bci);
/* Reset line number for new block */
if (graphBuilderConfig.insertFullInfopoints()) {
previousLineNumber = -1;
}
while (bci < endBCI) {
try (DebugCloseable context = openNodeContext()) {
if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) {
currentLineNumber = lnt != null ? lnt.getLineNumber(bci) : -1;
if (currentLineNumber != previousLineNumber) {
genInfoPointNode(InfopointReason.BYTECODE_POSITION, null);
previousLineNumber = currentLineNumber;
}
}
// read the opcode
int opcode = stream.currentBC();
assert traceState();
assert traceInstruction(bci, opcode, bci == block.startBci);
if (parent == null && bci == entryBCI) {
if (block.getJsrScope() != JsrScope.EMPTY_SCOPE) {
throw new JsrNotSupportedBailout("OSR into a JSR scope is not supported");
}
EntryMarkerNode x = append(new EntryMarkerNode());
frameState.insertProxies(value -> graph.unique(new EntryProxyNode(value, x)));
x.setStateAfter(createFrameState(bci, x));
}
processBytecode(bci, opcode);
} catch (BailoutException e) {
// Don't wrap bailouts as parser errors
throw e;
} catch (Throwable e) {
throw throwParserError(e);
}
if (lastInstr == null || lastInstr.next() != null) {
break;
}
stream.next();
bci = stream.currentBCI();
assert block == currentBlock;
assert checkLastInstruction();
lastInstr = finishInstruction(lastInstr, frameState);
if (bci < endBCI) {
if (bci > block.endBci) {
assert !block.getSuccessor(0).isExceptionEntry;
assert block.numNormalSuccessors() == 1;
// we fell through to the next block, add a goto and break
appendGoto(block.getSuccessor(0));
break;
}
}
}
}
Aggregations