use of org.graalvm.compiler.graph.NodeBitMap in project graal by oracle.
the class LoopFragment method computeNodes.
protected static void computeNodes(NodeBitMap nodes, Graph graph, Iterable<AbstractBeginNode> blocks, Iterable<AbstractBeginNode> earlyExits) {
for (AbstractBeginNode b : blocks) {
if (b.isDeleted()) {
continue;
}
for (Node n : b.getBlockNodes()) {
if (n instanceof Invoke) {
nodes.mark(((Invoke) n).callTarget());
}
if (n instanceof NodeWithState) {
NodeWithState withState = (NodeWithState) n;
withState.states().forEach(state -> state.applyToVirtual(node -> nodes.mark(node)));
}
if (n instanceof AbstractMergeNode) {
// if a merge is in the loop, all of its phis are also in the loop
for (PhiNode phi : ((AbstractMergeNode) n).phis()) {
nodes.mark(phi);
}
}
nodes.mark(n);
}
}
for (AbstractBeginNode earlyExit : earlyExits) {
if (earlyExit.isDeleted()) {
continue;
}
nodes.mark(earlyExit);
if (earlyExit instanceof LoopExitNode) {
LoopExitNode loopExit = (LoopExitNode) earlyExit;
FrameState stateAfter = loopExit.stateAfter();
if (stateAfter != null) {
stateAfter.applyToVirtual(node -> nodes.mark(node));
}
for (ProxyNode proxy : loopExit.proxies()) {
nodes.mark(proxy);
}
}
}
final NodeBitMap nonLoopNodes = graph.createNodeBitMap();
Deque<WorkListEntry> worklist = new ArrayDeque<>();
for (AbstractBeginNode b : blocks) {
if (b.isDeleted()) {
continue;
}
for (Node n : b.getBlockNodes()) {
if (n instanceof CommitAllocationNode) {
for (VirtualObjectNode obj : ((CommitAllocationNode) n).getVirtualObjects()) {
markFloating(worklist, obj, nodes, nonLoopNodes);
}
}
if (n instanceof MonitorEnterNode) {
markFloating(worklist, ((MonitorEnterNode) n).getMonitorId(), nodes, nonLoopNodes);
}
if (n instanceof AbstractMergeNode) {
/*
* Since we already marked all phi nodes as being in the loop to break cycles,
* we also have to iterate over their usages here.
*/
for (PhiNode phi : ((AbstractMergeNode) n).phis()) {
for (Node usage : phi.usages()) {
markFloating(worklist, usage, nodes, nonLoopNodes);
}
}
}
for (Node usage : n.usages()) {
markFloating(worklist, usage, nodes, nonLoopNodes);
}
}
}
}
use of org.graalvm.compiler.graph.NodeBitMap in project graal by oracle.
the class MethodTypeFlowBuilder method apply.
protected void apply() {
// assert method.getAnnotation(Fold.class) == null : method;
if (method.getAnnotation(NodeIntrinsic.class) != null) {
graph.getDebug().log("apply MethodTypeFlow on node intrinsic %s", method);
AnalysisType returnType = (AnalysisType) method.getSignature().getReturnType(method.getDeclaringClass());
if (returnType.getJavaKind() == JavaKind.Object) {
/*
* This is a method used in a snippet, so most likely the return value does not
* matter at all. However, some methods return an object, and the snippet continues
* to work with the object. So pretend that this method returns an object of the
* exact return type.
*/
TypeFlow<?> returnTypeFlow = methodFlow.getResultFlow().getDeclaredType().getTypeFlow(this.bb, true);
returnTypeFlow = new ProxyTypeFlow(null, returnTypeFlow);
FormalReturnTypeFlow resultFlow = new FormalReturnTypeFlow(null, returnType, method);
returnTypeFlow.addOriginalUse(this.bb, resultFlow);
methodFlow.addMiscEntry(returnTypeFlow);
methodFlow.setResult(resultFlow);
}
return;
}
if (!parse()) {
return;
}
this.bb.getUnsupportedFeatures().checkMethod(method, graph);
processedNodes = new NodeBitMap(graph);
TypeFlowsOfNodes typeFlows = new TypeFlowsOfNodes();
for (Node n : graph.getNodes()) {
if (n instanceof ParameterNode) {
ParameterNode node = (ParameterNode) n;
if (node.getStackKind() == JavaKind.Object) {
TypeFlowBuilder<?> paramBuilder = TypeFlowBuilder.create(bb, node, FormalParamTypeFlow.class, () -> {
boolean isStatic = Modifier.isStatic(method.getModifiers());
int index = node.index();
FormalParamTypeFlow parameter;
if (!isStatic && index == 0) {
AnalysisType paramType = method.getDeclaringClass();
parameter = new FormalReceiverTypeFlow(node, paramType, method);
} else {
int offset = isStatic ? 0 : 1;
AnalysisType paramType = (AnalysisType) method.getSignature().getParameterType(index - offset, method.getDeclaringClass());
parameter = new FormalParamTypeFlow(node, paramType, method, index);
}
methodFlow.setParameter(index, parameter);
return parameter;
});
typeFlowGraphBuilder.checkFormalParameterBuilder(paramBuilder);
typeFlows.add(node, paramBuilder);
}
} else if (n instanceof BoxNode) {
BoxNode node = (BoxNode) n;
Object key = uniqueKey(node);
BytecodeLocation boxSite = bb.analysisPolicy().createAllocationSite(bb, key, methodFlow.getMethod());
AnalysisType type = (AnalysisType) StampTool.typeOrNull(node);
TypeFlowBuilder<?> boxBuilder = TypeFlowBuilder.create(bb, node, BoxTypeFlow.class, () -> {
BoxTypeFlow boxFlow = new BoxTypeFlow(node, type, boxSite);
methodFlow.addAllocation(boxFlow);
return boxFlow;
});
typeFlows.add(node, boxBuilder);
}
for (Node input : n.inputs()) {
/*
* TODO change the handling of constants so that the SourceTypeFlow is created on
* demand, with the optimization that only one SourceTypeFlow is created ever for
* every distinct object (using, e.g., caching in a global IdentityHashMap).
*/
if (input instanceof ConstantNode && !typeFlows.contains((ConstantNode) input)) {
ConstantNode node = (ConstantNode) input;
if (node.asJavaConstant().isNull()) {
TypeFlowBuilder<SourceTypeFlow> sourceBuilder = TypeFlowBuilder.create(bb, node, SourceTypeFlow.class, () -> {
SourceTypeFlow constantSource = new SourceTypeFlow(node, TypeState.forNull());
methodFlow.addSource(constantSource);
return constantSource;
});
typeFlows.add(node, sourceBuilder);
} else if (node.asJavaConstant().getJavaKind() == JavaKind.Object) {
/*
* TODO a SubstrateObjectConstant wrapping a PrimitiveConstant has kind
* equals to Object. Do we care about the effective value of these primitive
* constants in the analysis?
*/
assert StampTool.isExactType(node);
AnalysisType type = (AnalysisType) StampTool.typeOrNull(node);
assert type.isInstantiated();
TypeFlowBuilder<SourceTypeFlow> sourceBuilder = TypeFlowBuilder.create(bb, node, SourceTypeFlow.class, () -> {
SourceTypeFlow constantSource = new SourceTypeFlow(node, TypeState.forConstant(this.bb, node.asJavaConstant(), type));
methodFlow.addSource(constantSource);
return constantSource;
});
typeFlows.add(node, sourceBuilder);
}
}
}
}
// Propagate the type flows through the method's graph
new NodeIterator(graph.start(), typeFlows).apply();
/* Prune the method graph. Eliminate nodes with no uses. */
typeFlowGraphBuilder.build();
/*
* Make sure that all existing InstanceOfNodes are registered even when only used as an
* input of a conditional.
*/
for (Node n : graph.getNodes()) {
if (n instanceof InstanceOfNode) {
InstanceOfNode instanceOf = (InstanceOfNode) n;
markFieldsUsedInComparison(instanceOf.getValue());
} else if (n instanceof ObjectEqualsNode) {
ObjectEqualsNode compareNode = (ObjectEqualsNode) n;
markFieldsUsedInComparison(compareNode.getX());
markFieldsUsedInComparison(compareNode.getY());
}
}
}
use of org.graalvm.compiler.graph.NodeBitMap in project graal by oracle.
the class GraphUtil method originalValueSimple.
private static ValueNode originalValueSimple(ValueNode value) {
/* The very simple case: look through proxies. */
ValueNode cur = originalValueForProxy(value);
while (cur instanceof PhiNode) {
/*
* We found a phi function. Check if we can analyze it without allocating temporary data
* structures.
*/
PhiNode phi = (PhiNode) cur;
ValueNode phiSingleValue = null;
int count = phi.valueCount();
for (int i = 0; i < count; ++i) {
ValueNode phiCurValue = originalValueForProxy(phi.valueAt(i));
if (phiCurValue == phi) {
/* Simple cycle, we can ignore the input value. */
} else if (phiSingleValue == null) {
/* The first input. */
phiSingleValue = phiCurValue;
} else if (phiSingleValue != phiCurValue) {
if (phiSingleValue instanceof PhiNode || phiCurValue instanceof PhiNode) {
/*
* We have two different input values for the phi function, and at least one
* of the inputs is another phi function. We need to do a complicated
* exhaustive check.
*/
return originalValueForComplicatedPhi(phi, new NodeBitMap(value.graph()));
} else {
/*
* We have two different input values for the phi function, but none of them
* is another phi function. This phi function cannot be reduce any further,
* so the phi function is the original value.
*/
return phi;
}
}
}
/*
* Successfully reduced the phi function to a single input value. The single input value
* can itself be a phi function again, so we might take another loop iteration.
*/
assert phiSingleValue != null;
cur = phiSingleValue;
}
/* We reached a "normal" node, which is the original value. */
assert !(cur instanceof LimitedValueProxy) && !(cur instanceof PhiNode);
return cur;
}
use of org.graalvm.compiler.graph.NodeBitMap in project graal by oracle.
the class CFGPrinter method printSchedule.
public void printSchedule(String message, ScheduleResult theSchedule) {
schedule = theSchedule;
cfg = schedule.getCFG();
printedNodes = new NodeBitMap(cfg.graph);
begin("cfg");
out.print("name \"").print(message).println('"');
for (Block b : schedule.getCFG().getBlocks()) {
if (schedule.nodesFor(b) != null) {
printScheduledBlock(b, schedule.nodesFor(b));
}
}
end("cfg");
schedule = null;
cfg = null;
printedNodes = null;
}
Aggregations