use of org.graalvm.compiler.nodes.java.MethodCallTargetNode in project graal by oracle.
the class VerifyFrameDoesNotEscapePhase method run.
@Override
protected void run(StructuredGraph graph) {
for (NewFrameNode virtualFrame : graph.getNodes(NewFrameNode.TYPE)) {
for (MethodCallTargetNode callTarget : virtualFrame.usages().filter(MethodCallTargetNode.class)) {
if (callTarget.invoke() != null) {
String properties = callTarget.getDebugProperties().toString();
String arguments = callTarget.arguments().toString();
Throwable exception = new VerificationError("Frame escapes at: %s#%s\nproperties:%s\narguments: %s", callTarget, callTarget.targetMethod(), properties, arguments);
throw GraphUtil.approxSourceException(callTarget, exception);
}
}
}
}
use of org.graalvm.compiler.nodes.java.MethodCallTargetNode in project graal by oracle.
the class TruffleGraphBuilderPlugins method registerCompilerDirectivesPlugins.
public static void registerCompilerDirectivesPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, boolean canDelayIntrinsification) {
final ResolvedJavaType compilerDirectivesType = getRuntime().resolveType(metaAccess, "com.oracle.truffle.api.CompilerDirectives");
Registration r = new Registration(plugins, new ResolvedJavaSymbol(compilerDirectivesType));
r.register0("inInterpreter", new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(false));
return true;
}
});
r.register0("inCompiledCode", new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(true));
return true;
}
});
r.register0("inCompilationRoot", new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
GraphBuilderContext.ExternalInliningContext inliningContext = b.getExternalInliningContext();
if (inliningContext != null) {
b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(inliningContext.getInlinedDepth() == 0));
return true;
}
return false;
}
});
r.register0("transferToInterpreter", new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
b.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
return true;
}
});
r.register0("transferToInterpreterAndInvalidate", new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
return true;
}
});
r.register1("interpreterOnly", Runnable.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
return true;
}
});
r.register1("interpreterOnly", Callable.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
return true;
}
});
r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) {
b.addPush(JavaKind.Boolean, new BranchProbabilityNode(probability, condition));
return true;
}
});
r.register1("bailout", String.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode message) {
if (canDelayIntrinsification) {
/*
* We do not want to bailout yet, since we are still parsing individual methods
* and constant folding could still eliminate the call to bailout(). However, we
* also want to stop parsing, since we are sure that we will never need the
* graph beyond the bailout point.
*
* Therefore, we manually emit the call to bailout, which will be intrinsified
* later when intrinsifications can no longer be delayed. The call is followed
* by a NeverPartOfCompilationNode, which is a control sink and therefore stops
* any further parsing.
*/
StampPair returnStamp = b.getInvokeReturnStamp(b.getAssumptions());
CallTargetNode callTarget = b.add(new MethodCallTargetNode(InvokeKind.Static, targetMethod, new ValueNode[] { message }, returnStamp, null));
b.add(new InvokeNode(callTarget, b.bci()));
b.add(new NeverPartOfCompilationNode("intrinsification of call to bailout() will abort entire compilation"));
return true;
}
if (message.isConstant()) {
throw b.bailout(message.asConstant().toValueString());
}
throw b.bailout("bailout (message is not compile-time constant, so no additional information is available)");
}
});
r.register1("isCompilationConstant", Object.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
if ((value instanceof BoxNode ? ((BoxNode) value).getValue() : value).isConstant()) {
b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(true));
} else {
b.addPush(JavaKind.Boolean, new IsCompilationConstantNode(value));
}
return true;
}
});
r.register1("isPartialEvaluationConstant", Object.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
if ((value instanceof BoxNode ? ((BoxNode) value).getValue() : value).isConstant()) {
b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(true));
} else if (canDelayIntrinsification) {
return false;
} else {
b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(false));
}
return true;
}
});
r.register1("materialize", Object.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
AllowMaterializeNode materializedValue = b.append(new AllowMaterializeNode(value));
b.add(new ForceMaterializeNode(materializedValue));
return true;
}
});
r.register1("ensureVirtualized", Object.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
b.add(new EnsureVirtualizedNode(object, false));
return true;
}
});
r.register1("ensureVirtualizedHere", Object.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
b.add(new EnsureVirtualizedNode(object, true));
return true;
}
});
r.register2("castExact", Object.class, Class.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode javaClass) {
ValueNode nullCheckedClass = b.addNonNullCast(javaClass);
LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getAssumptions(), b.getConstantReflection(), nullCheckedClass, object, true, true));
if (condition.isTautology()) {
b.addPush(JavaKind.Object, object);
} else {
FixedGuardNode fixedGuard = b.add(new FixedGuardNode(condition, DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, false));
b.addPush(JavaKind.Object, DynamicPiNode.create(b.getAssumptions(), b.getConstantReflection(), object, fixedGuard, nullCheckedClass, true));
}
return true;
}
});
}
use of org.graalvm.compiler.nodes.java.MethodCallTargetNode in project graal by oracle.
the class InliningUtil method replaceInvokeCallTarget.
public static void replaceInvokeCallTarget(Invoke invoke, StructuredGraph graph, InvokeKind invokeKind, ResolvedJavaMethod targetMethod) {
MethodCallTargetNode oldCallTarget = (MethodCallTargetNode) invoke.callTarget();
MethodCallTargetNode newCallTarget = graph.add(new MethodCallTargetNode(invokeKind, targetMethod, oldCallTarget.arguments().toArray(new ValueNode[0]), oldCallTarget.returnStamp(), oldCallTarget.getProfile()));
invoke.asNode().replaceFirstInput(oldCallTarget, newCallTarget);
}
use of org.graalvm.compiler.nodes.java.MethodCallTargetNode in project graal by oracle.
the class InliningUtil method nonNullReceiver.
/**
* Gets the receiver for an invoke, adding a guard if necessary to ensure it is non-null, and
* ensuring that the resulting type is compatible with the method being invoked.
*/
@SuppressWarnings("try")
public static ValueNode nonNullReceiver(Invoke invoke) {
try (DebugCloseable position = invoke.asNode().withNodeSourcePosition()) {
MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
assert !callTarget.isStatic() : callTarget.targetMethod();
StructuredGraph graph = callTarget.graph();
ValueNode oldReceiver = callTarget.arguments().get(0);
ValueNode newReceiver = oldReceiver;
if (newReceiver.getStackKind() == JavaKind.Object) {
if (invoke.getInvokeKind() == InvokeKind.Special) {
Stamp paramStamp = newReceiver.stamp(NodeView.DEFAULT);
Stamp stamp = paramStamp.join(StampFactory.object(TypeReference.create(graph.getAssumptions(), callTarget.targetMethod().getDeclaringClass())));
if (!stamp.equals(paramStamp)) {
// The verifier and previous optimizations guarantee unconditionally that
// the
// receiver is at least of the type of the method holder for a special
// invoke.
newReceiver = graph.unique(new PiNode(newReceiver, stamp));
}
}
if (!StampTool.isPointerNonNull(newReceiver)) {
LogicNode condition = graph.unique(IsNullNode.create(newReceiver));
FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(condition, NullCheckException, InvalidateReprofile, true));
PiNode nonNullReceiver = graph.unique(new PiNode(newReceiver, StampFactory.objectNonNull(), fixedGuard));
graph.addBeforeFixed(invoke.asNode(), fixedGuard);
newReceiver = nonNullReceiver;
}
}
if (newReceiver != oldReceiver) {
callTarget.replaceFirstInput(oldReceiver, newReceiver);
}
return newReceiver;
}
}
use of org.graalvm.compiler.nodes.java.MethodCallTargetNode in project graal by oracle.
the class MultiTypeGuardInlineInfo method inlineMultipleMethods.
private EconomicSet<Node> inlineMultipleMethods(StructuredGraph graph, Providers providers) {
int numberOfMethods = concretes.size();
FixedNode continuation = invoke.next();
// setup merge and phi nodes for results and exceptions
AbstractMergeNode returnMerge = graph.add(new MergeNode());
returnMerge.setStateAfter(invoke.stateAfter());
PhiNode returnValuePhi = null;
if (invoke.asNode().getStackKind() != JavaKind.Void) {
returnValuePhi = graph.addWithoutUnique(new ValuePhiNode(invoke.asNode().stamp(NodeView.DEFAULT).unrestricted(), returnMerge));
}
AbstractMergeNode exceptionMerge = null;
PhiNode exceptionObjectPhi = null;
if (invoke instanceof InvokeWithExceptionNode) {
InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
exceptionMerge = graph.add(new MergeNode());
FixedNode exceptionSux = exceptionEdge.next();
graph.addBeforeFixed(exceptionSux, exceptionMerge);
exceptionObjectPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(JavaKind.Object), exceptionMerge));
exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, JavaKind.Object, new JavaKind[] { JavaKind.Object }, new ValueNode[] { exceptionObjectPhi }));
}
// create one separate block for each invoked method
AbstractBeginNode[] successors = new AbstractBeginNode[numberOfMethods + 1];
for (int i = 0; i < numberOfMethods; i++) {
successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, true);
}
// create the successor for an unknown type
FixedNode unknownTypeSux;
if (shouldFallbackToInvoke()) {
unknownTypeSux = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, false);
} else {
unknownTypeSux = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated));
}
successors[successors.length - 1] = BeginNode.begin(unknownTypeSux);
// replace the invoke exception edge
if (invoke instanceof InvokeWithExceptionNode) {
InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke;
ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithExceptionNode.exceptionEdge();
exceptionEdge.replaceAtUsages(exceptionObjectPhi);
exceptionEdge.setNext(null);
GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge());
}
assert invoke.asNode().isAlive();
// replace the invoke with a switch on the type of the actual receiver
boolean methodDispatch = createDispatchOnTypeBeforeInvoke(graph, successors, false, providers.getStampProvider(), providers.getConstantReflection());
assert invoke.next() == continuation;
invoke.setNext(null);
returnMerge.setNext(continuation);
if (returnValuePhi != null) {
invoke.asNode().replaceAtUsages(returnValuePhi);
}
invoke.asNode().safeDelete();
ArrayList<PiNode> replacementNodes = new ArrayList<>();
// prepare the anchors for the invokes
for (int i = 0; i < numberOfMethods; i++) {
AbstractBeginNode node = successors[i];
Invoke invokeForInlining = (Invoke) node.next();
ResolvedJavaType commonType;
if (methodDispatch) {
commonType = concretes.get(i).getDeclaringClass();
} else {
commonType = getLeastCommonType(i);
}
ValueNode receiver = ((MethodCallTargetNode) invokeForInlining.callTarget()).receiver();
boolean exact = (getTypeCount(i) == 1 && !methodDispatch);
PiNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, node, commonType, receiver, exact);
invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
assert !anchoredReceiver.isDeleted() : anchoredReceiver;
replacementNodes.add(anchoredReceiver);
}
if (shouldFallbackToInvoke()) {
replacementNodes.add(null);
}
EconomicSet<Node> canonicalizeNodes = EconomicSet.create(Equivalence.DEFAULT);
// do the actual inlining for every invoke
for (int i = 0; i < numberOfMethods; i++) {
Invoke invokeForInlining = (Invoke) successors[i].next();
canonicalizeNodes.addAll(doInline(i, invokeForInlining));
}
if (returnValuePhi != null) {
canonicalizeNodes.add(returnValuePhi);
}
return canonicalizeNodes;
}
Aggregations