use of org.graalvm.compiler.nodes.PiNode in project graal by oracle.
the class GraphEffectList method replaceAtUsages.
/**
* Replaces the given node at its usages without deleting it. If the current node is a fixed
* node it will be disconnected from the control flow, so that it will be deleted by a
* subsequent {@link DeadCodeEliminationPhase}
*
* @param node The node to be replaced.
* @param replacement The node that should replace the original value. If the replacement is a
* non-connected {@link FixedWithNextNode} it will be added to the control flow.
* @param insertBefore
*/
public void replaceAtUsages(ValueNode node, ValueNode replacement, FixedNode insertBefore) {
assert node != null && replacement != null : node + " " + replacement;
assert node.stamp(NodeView.DEFAULT).isCompatible(replacement.stamp(NodeView.DEFAULT)) : "Replacement node stamp not compatible " + node.stamp(NodeView.DEFAULT) + " vs " + replacement.stamp(NodeView.DEFAULT);
add("replace at usages", (graph, obsoleteNodes) -> {
assert node.isAlive();
ValueNode replacementNode = graph.addOrUniqueWithInputs(replacement);
assert replacementNode.isAlive();
assert insertBefore != null;
if (replacementNode instanceof FixedWithNextNode && ((FixedWithNextNode) replacementNode).next() == null) {
graph.addBeforeFixed(insertBefore, (FixedWithNextNode) replacementNode);
}
/*
* Keep the (better) stamp information when replacing a node with another one if the
* replacement has a less precise stamp than the original node. This can happen for
* example in the context of read nodes and unguarded pi nodes where the pi will be used
* to improve the stamp information of the read. Such a read might later be replaced
* with a read with a less precise stamp.
*/
if (!node.stamp(NodeView.DEFAULT).equals(replacementNode.stamp(NodeView.DEFAULT))) {
replacementNode = graph.unique(new PiNode(replacementNode, node.stamp(NodeView.DEFAULT)));
}
node.replaceAtUsages(replacementNode);
if (node instanceof FixedWithNextNode) {
GraphUtil.unlinkFixedNode((FixedWithNextNode) node);
}
obsoleteNodes.add(node);
});
}
use of org.graalvm.compiler.nodes.PiNode in project graal by oracle.
the class SubstrateGraphBuilderPlugins method registerKnownIntrinsicsPlugins.
private static void registerKnownIntrinsicsPlugins(InvocationPlugins plugins, boolean analysis) {
Registration r = new Registration(plugins, KnownIntrinsics.class);
r.register0("heapBase", new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
b.addPush(JavaKind.Object, ReadRegisterFixedNode.forHeapBase());
return true;
}
});
r.register1("readArrayLength", Object.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode array) {
b.addPush(JavaKind.Int, new ArrayLengthNode(array));
return true;
}
});
r.register1("readHub", Object.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
ValueNode nonNullObject = b.nullCheckedValue(object);
b.addPush(JavaKind.Object, new LoadHubNode(b.getStampProvider(), nonNullObject));
return true;
}
});
r.register3("formatObject", Pointer.class, Class.class, boolean.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode memory, ValueNode hub, ValueNode rememberedSet) {
b.addPush(JavaKind.Object, new FormatObjectNode(memory, hub, rememberedSet));
return true;
}
});
r.register5("formatArray", Pointer.class, Class.class, int.class, boolean.class, boolean.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode memory, ValueNode hub, ValueNode length, ValueNode rememberedSet, ValueNode unaligned) {
b.addPush(JavaKind.Object, new FormatArrayNode(memory, hub, length, rememberedSet, unaligned));
return true;
}
});
r.register2("unsafeCast", Object.class, Class.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode toTypeNode) {
/*
* We need to make sure that the updated type information does not flow up, because
* it can depend on any condition before (and we do not know which condition, so we
* cannot anchor at a particular block).
*/
ResolvedJavaType toType = typeValue(b.getConstantReflection(), b, targetMethod, toTypeNode, "toType");
TypeReference toTypeRef = TypeReference.createTrustedWithoutAssumptions(toType);
b.addPush(JavaKind.Object, new FixedValueAnchorNode(object, StampFactory.object(toTypeRef)));
return true;
}
});
r.register1("nonNullPointer", Pointer.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
b.addPush(JavaKind.Object, new PiNode(object, nonZeroWord()));
return true;
}
});
r.register0("readStackPointer", new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
b.addPush(JavaKind.Object, new ReadStackPointerNode());
return true;
}
});
r.register1("writeStackPointer", Pointer.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
b.add(new WriteStackPointerNode(value));
return true;
}
});
r.register0("readInstructionPointer", new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
b.addPush(JavaKind.Object, new ReadInstructionPointerNode());
return true;
}
});
r.register0("readCallerStackPointer", new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
b.addPush(JavaKind.Object, new ReadCallerStackPointerNode());
return true;
}
});
r.register0("readReturnAddress", new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
b.addPush(JavaKind.Object, new ReadReturnAddressNode());
return true;
}
});
r.register3("farReturn", Object.class, Pointer.class, CodePointer.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode result, ValueNode sp, ValueNode ip) {
b.add(new FarReturnNode(result, sp, ip));
return true;
}
});
r.register0("testDeoptimize", new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
b.add(new TestDeoptimizeNode());
return true;
}
});
r.register0("isDeoptimizationTarget", new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
if (b.getGraph().method() instanceof SharedMethod) {
SharedMethod method = (SharedMethod) b.getGraph().method();
if (method.isDeoptTarget()) {
b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(true));
} else {
b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(false));
}
} else {
// In analysis the value is always true.
b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(true));
}
return true;
}
});
r.register2("convertUnknownValue", Object.class, Class.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode typeNode) {
ResolvedJavaType type = typeValue(b.getConstantReflection(), b, targetMethod, typeNode, "type");
TypeReference typeRef = TypeReference.createTrustedWithoutAssumptions(type);
Stamp stamp = StampFactory.object(typeRef);
if (analysis) {
b.addPush(JavaKind.Object, new ConvertUnknownValueNode(object, stamp));
} else {
b.addPush(JavaKind.Object, PiNode.create(object, stamp));
}
return true;
}
});
}
use of org.graalvm.compiler.nodes.PiNode in project graal by oracle.
the class CInterfaceEnumTool method createEnumLookupInvoke.
public ValueNode createEnumLookupInvoke(HostedGraphKit kit, ResolvedJavaType enumType, EnumInfo enumInfo, JavaKind parameterKind, ValueNode arg) {
InvokeNode invoke = invokeEnumLookup(kit, CallTargetFactory.from(kit), kit.getFrameState(), kit.bci(), enumInfo, parameterKind, arg);
ObjectStamp resultStamp = StampFactory.object(TypeReference.create(null, enumType), false);
return kit.unique(new PiNode(invoke, resultStamp));
}
use of org.graalvm.compiler.nodes.PiNode in project graal by oracle.
the class StrengthenStampsPhase method run.
@Override
protected void run(StructuredGraph graph) {
for (Node n : graph.getNodes()) {
if (n instanceof ValueNode && !(n instanceof LimitedValueProxy) && !(n instanceof PhiNode)) {
/*
* The stamp of proxy nodes and phi nodes is inferred automatically, so we do not
* need to improve them.
*/
ValueNode node = (ValueNode) n;
/*
* First ask the node to improve the stamp itself, to incorporate already improved
* input stamps.
*/
node.inferStamp();
Stamp newStamp = strengthen(node.stamp(NodeView.DEFAULT));
if (newStamp != null) {
node.setStamp(newStamp);
}
}
if (n instanceof LoadFieldNode) {
LoadFieldNode node = (LoadFieldNode) n;
updateStamp(node, toHosted(node.field()).getFieldTypeProfile());
} else if (n instanceof InstanceOfNode) {
InstanceOfNode node = (InstanceOfNode) n;
ObjectStamp newStamp = (ObjectStamp) strengthen(node.getCheckedStamp());
if (newStamp != null) {
node.strengthenCheckedStamp(newStamp);
}
} else if (n instanceof PiNode) {
PiNode node = (PiNode) n;
Stamp newStamp = strengthen(node.piStamp());
if (newStamp != null) {
node.strengthenPiStamp(newStamp);
}
}
}
}
use of org.graalvm.compiler.nodes.PiNode in project graal by oracle.
the class IntrinsifyMethodHandlesInvocationPlugin method processInvokeWithMethodHandle.
@SuppressWarnings("try")
private void processInvokeWithMethodHandle(GraphBuilderContext b, BytecodeProvider bytecodeProvider, ResolvedJavaMethod methodHandleMethod, ValueNode[] methodHandleArguments) {
Plugins graphBuilderPlugins = new Plugins(((ReplacementsImpl) originalProviders.getReplacements()).getGraphBuilderPlugins());
registerInvocationPlugins(graphBuilderPlugins.getInvocationPlugins(), bytecodeProvider);
graphBuilderPlugins.prependParameterPlugin(new MethodHandlesParameterPlugin(methodHandleArguments));
graphBuilderPlugins.clearInlineInvokePlugins();
graphBuilderPlugins.prependInlineInvokePlugin(new MethodHandlesInlineInvokePlugin());
graphBuilderPlugins.prependNodePlugin(new MethodHandlePlugin(originalProviders.getConstantReflection().getMethodHandleAccess(), false));
/* We do all the word type rewriting because parameters to the lambda can be word types. */
SnippetReflectionProvider originalSnippetReflection = GraalAccess.getOriginalSnippetReflection();
WordOperationPlugin wordOperationPlugin = new WordOperationPlugin(originalSnippetReflection, new WordTypes(originalProviders.getMetaAccess(), FrameAccess.getWordKind()));
graphBuilderPlugins.appendInlineInvokePlugin(wordOperationPlugin);
graphBuilderPlugins.appendTypePlugin(wordOperationPlugin);
graphBuilderPlugins.appendTypePlugin(new TrustedInterfaceTypePlugin());
graphBuilderPlugins.appendNodePlugin(wordOperationPlugin);
GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getSnippetDefault(graphBuilderPlugins);
GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(originalProviders.getMetaAccess(), originalProviders.getStampProvider(), originalProviders.getConstantReflection(), originalProviders.getConstantFieldProvider(), graphBuilderConfig, OptimisticOptimizations.NONE, null);
DebugContext debug = b.getDebug();
StructuredGraph graph = new StructuredGraph.Builder(b.getOptions(), debug).method(toOriginal(methodHandleMethod)).build();
try (DebugContext.Scope s = debug.scope("IntrinsifyMethodHandles", graph)) {
graphBuilder.apply(graph);
/*
* We do not care about the improved type information from Pi nodes, so we just delete
* them to simplify our graph.
*/
for (PiNode pi : graph.getNodes(PiNode.TYPE)) {
pi.replaceAndDelete(pi.object());
}
/*
* Support for MethodHandle that adapt the input type to a more generic type, i.e., a
* MethodHandle that does a dynamic type check on a parameter.
*/
for (UnaryOpLogicNode node : graph.getNodes().filter(UnaryOpLogicNode.class).filter(v -> v instanceof IsNullNode || v instanceof InstanceOfNode)) {
ValueNode value = node.getValue();
if (value instanceof ParameterNode) {
/*
* We just assume that the InstanceOfNode or IsNullNode are used in an If and
* the true-successor is actually the branch we want. If that assumption is
* wrong, nothing bad happens - we will just continue to report the invocation
* as unsupported because the updated stamp for the parameter will not simplify
* the graph.
*/
if (node instanceof InstanceOfNode) {
InstanceOfNode inst = (InstanceOfNode) node;
TypeReference typeRef = inst.type();
value.setStamp(new ObjectStamp(typeRef.getType(), typeRef.isExact(), !inst.allowsNull(), false));
} else {
assert node instanceof IsNullNode;
ResolvedJavaType type = value.stamp(NodeView.DEFAULT).javaType(originalProviders.getMetaAccess());
value.setStamp(new ObjectStamp(type, false, /* non-null */
true, false));
}
}
}
/*
* The canonicalizer converts unsafe field accesses for get/set method handles back to
* high-level field load and store nodes.
*/
new CanonicalizerPhase().apply(graph, new PhaseContext(originalProviders));
for (FixedGuardNode guard : graph.getNodes(FixedGuardNode.TYPE)) {
if (guard.next() instanceof AccessFieldNode && guard.condition() instanceof IsNullNode && guard.isNegated() && ((IsNullNode) guard.condition()).getValue() == ((AccessFieldNode) guard.next()).object()) {
/*
* Method handles to load and stores fields have null checks. Remove them, since
* the null check is implicitly done by the field access.
*/
GraphUtil.removeFixedWithUnusedInputs(guard);
}
}
debug.dump(DebugContext.VERY_DETAILED_LEVEL, graph, "Final intrinisfication graph");
/*
* After parsing (and recursive inlining during parsing), the graph must contain only
* one invocation (and therefore only one MethodCallTargetNode), plus the parameters,
* constants, start, and return nodes.
*/
Node singleFunctionality = null;
ReturnNode singleReturn = null;
for (Node node : graph.getNodes()) {
if (node == graph.start() || node instanceof ParameterNode || node instanceof ConstantNode || node instanceof FrameState) {
/* Ignore the allowed framework around the nodes we care about. */
continue;
} else if (node instanceof Invoke) {
/* We check the MethodCallTargetNode, so we can ignore the invoke. */
continue;
} else if ((node instanceof MethodCallTargetNode || node instanceof LoadFieldNode || node instanceof StoreFieldNode) && singleFunctionality == null) {
singleFunctionality = node;
continue;
} else if (node instanceof ReturnNode && singleReturn == null) {
singleReturn = (ReturnNode) node;
continue;
}
throw new UnsupportedFeatureException("Invoke with MethodHandle argument could not be reduced to at most a single call: " + methodHandleMethod.format("%H.%n(%p)"));
}
if (singleFunctionality instanceof MethodCallTargetNode) {
MethodCallTargetNode singleCallTarget = (MethodCallTargetNode) singleFunctionality;
assert singleReturn.result() == null || singleReturn.result() == singleCallTarget.invoke();
/*
* Replace the originalTarget with the replacementTarget. Note that the
* replacementTarget node belongs to a different graph than originalTarget, so we
* need to match parameter back to the original graph and allocate a new
* MethodCallTargetNode for the original graph.
*/
ValueNode[] replacedArguments = new ValueNode[singleCallTarget.arguments().size()];
for (int i = 0; i < replacedArguments.length; i++) {
replacedArguments[i] = lookup(b, methodHandleArguments, singleCallTarget.arguments().get(i));
}
b.handleReplacedInvoke(singleCallTarget.invokeKind(), lookup(singleCallTarget.targetMethod()), replacedArguments, false);
} else if (singleFunctionality instanceof LoadFieldNode) {
LoadFieldNode fieldLoad = (LoadFieldNode) singleFunctionality;
b.addPush(b.getInvokeReturnType().getJavaKind(), LoadFieldNode.create(null, lookup(b, methodHandleArguments, fieldLoad.object()), lookup(fieldLoad.field())));
} else if (singleFunctionality instanceof StoreFieldNode) {
StoreFieldNode fieldStore = (StoreFieldNode) singleFunctionality;
b.add(new StoreFieldNode(lookup(b, methodHandleArguments, fieldStore.object()), lookup(fieldStore.field()), lookup(b, methodHandleArguments, fieldStore.value())));
} else if (singleReturn.result() != null) {
/* Replace the invocation with he constant result. */
JavaConstant constantResult = singleReturn.result().asJavaConstant();
assert b.getInvokeReturnType().getJavaKind() == constantResult.getJavaKind();
b.addPush(constantResult.getJavaKind(), ConstantNode.forConstant(lookup(constantResult), universeProviders.getMetaAccess()));
} else {
/* No invoke and no return value, so nothing to do. */
assert b.getInvokeReturnType().getJavaKind() == JavaKind.Void;
}
} catch (Throwable ex) {
throw debug.handle(ex);
}
}
Aggregations