use of org.graalvm.compiler.nodes.virtual.CommitAllocationNode in project graal by oracle.
the class EscapeAnalysisTest method testFullyUnrolledLoop.
@Test
public void testFullyUnrolledLoop() {
prepareGraph("testFullyUnrolledLoopSnippet", false);
new LoopFullUnrollPhase(new CanonicalizerPhase(), new DefaultLoopPolicies()).apply(graph, context);
new PartialEscapePhase(false, new CanonicalizerPhase(), graph.getOptions()).apply(graph, context);
Assert.assertEquals(1, returnNodes.size());
Assert.assertTrue(returnNodes.get(0).result() instanceof AllocatedObjectNode);
CommitAllocationNode commit = ((AllocatedObjectNode) returnNodes.get(0).result()).getCommit();
Assert.assertEquals(2, commit.getValues().size());
Assert.assertEquals(1, commit.getVirtualObjects().size());
Assert.assertTrue("non-cyclic data structure expected", commit.getVirtualObjects().get(0) != commit.getValues().get(0));
}
use of org.graalvm.compiler.nodes.virtual.CommitAllocationNode in project graal by oracle.
the class DefaultJavaLoweringProvider method finishAllocatedObjects.
public void finishAllocatedObjects(LoweringTool tool, CommitAllocationNode commit, ValueNode[] allocations) {
StructuredGraph graph = commit.graph();
for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
allocations[objIndex] = anchor;
graph.addBeforeFixed(commit, anchor);
}
/*
* Note that the FrameState that is assigned to these MonitorEnterNodes isn't the correct
* state. It will be the state from before the allocation occurred instead of a valid state
* after the locking is performed. In practice this should be fine since these are newly
* allocated objects. The bytecodes themselves permit allocating an object, doing a
* monitorenter and then dropping all references to the object which would produce the same
* state, though that would normally produce an IllegalMonitorStateException. In HotSpot
* some form of fast path locking should always occur so the FrameState should never
* actually be used.
*/
ArrayList<MonitorEnterNode> enters = null;
for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
List<MonitorIdNode> locks = commit.getLocks(objIndex);
if (locks.size() > 1) {
// Ensure that the lock operations are performed in lock depth order
ArrayList<MonitorIdNode> newList = new ArrayList<>(locks);
newList.sort((a, b) -> Integer.compare(a.getLockDepth(), b.getLockDepth()));
locks = newList;
}
int lastDepth = -1;
for (MonitorIdNode monitorId : locks) {
assert lastDepth < monitorId.getLockDepth();
lastDepth = monitorId.getLockDepth();
MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], monitorId));
graph.addBeforeFixed(commit, enter);
if (enters == null) {
enters = new ArrayList<>();
}
enters.add(enter);
}
}
for (Node usage : commit.usages().snapshot()) {
if (usage instanceof AllocatedObjectNode) {
AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
addObject.replaceAtUsagesAndDelete(allocations[index]);
} else {
assert enters != null;
commit.replaceAtUsages(InputType.Memory, enters.get(enters.size() - 1));
}
}
if (enters != null) {
for (MonitorEnterNode enter : enters) {
enter.lower(tool);
}
}
assert commit.hasNoUsages();
insertAllocationBarrier(commit, graph);
}
use of org.graalvm.compiler.nodes.virtual.CommitAllocationNode in project graal by oracle.
the class PartialEscapeBlockState method materializeBefore.
/**
* Materializes the given virtual object and produces the necessary effects in the effects list.
* This transitively also materializes all other virtual objects that are reachable from the
* entries.
*/
public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, GraphEffectList materializeEffects) {
PartialEscapeClosure.COUNTER_MATERIALIZATIONS.increment(fixed.getDebug());
List<AllocatedObjectNode> objects = new ArrayList<>(2);
List<ValueNode> values = new ArrayList<>(8);
List<List<MonitorIdNode>> locks = new ArrayList<>();
List<ValueNode> otherAllocations = new ArrayList<>(2);
List<Boolean> ensureVirtual = new ArrayList<>(2);
materializeWithCommit(fixed, virtual, objects, locks, values, ensureVirtual, otherAllocations);
materializeEffects.addVirtualizationDelta(-(objects.size() + otherAllocations.size()));
materializeEffects.add("materializeBefore", new Effect() {
@Override
public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
for (ValueNode alloc : otherAllocations) {
ValueNode otherAllocation = graph.addOrUniqueWithInputs(alloc);
if (otherAllocation instanceof FixedWithNextNode) {
graph.addBeforeFixed(fixed, (FixedWithNextNode) otherAllocation);
} else {
assert otherAllocation instanceof FloatingNode;
}
}
if (!objects.isEmpty()) {
CommitAllocationNode commit;
if (fixed.predecessor() instanceof CommitAllocationNode) {
commit = (CommitAllocationNode) fixed.predecessor();
} else {
commit = graph.add(new CommitAllocationNode());
graph.addBeforeFixed(fixed, commit);
}
for (AllocatedObjectNode obj : objects) {
graph.addWithoutUnique(obj);
commit.getVirtualObjects().add(obj.getVirtualObject());
obj.setCommit(commit);
}
for (ValueNode value : values) {
commit.getValues().add(graph.addOrUniqueWithInputs(value));
}
for (List<MonitorIdNode> monitorIds : locks) {
commit.addLocks(monitorIds);
}
commit.getEnsureVirtual().addAll(ensureVirtual);
assert commit.usages().filter(AllocatedObjectNode.class).count() == commit.getUsageCount();
List<AllocatedObjectNode> materializedValues = commit.usages().filter(AllocatedObjectNode.class).snapshot();
for (int i = 0; i < commit.getValues().size(); i++) {
if (materializedValues.contains(commit.getValues().get(i))) {
commit.getValues().set(i, ((AllocatedObjectNode) commit.getValues().get(i)).getVirtualObject());
}
}
}
}
});
}
use of org.graalvm.compiler.nodes.virtual.CommitAllocationNode 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.nodes.virtual.CommitAllocationNode in project graal by oracle.
the class PartialEscapeAnalysisTest method testPartialEscapeAnalysis.
@SafeVarargs
protected final void testPartialEscapeAnalysis(String snippet, double expectedProbability, int expectedCount, Class<? extends Node>... invalidNodeClasses) {
prepareGraph(snippet, false);
for (AbstractMergeNode merge : graph.getNodes(AbstractMergeNode.TYPE)) {
merge.setStateAfter(null);
}
new DeadCodeEliminationPhase().apply(graph);
new CanonicalizerPhase().apply(graph, context);
try {
Assert.assertTrue("partial escape analysis should have removed all NewInstanceNode allocations", graph.getNodes().filter(NewInstanceNode.class).isEmpty());
Assert.assertTrue("partial escape analysis should have removed all NewArrayNode allocations", graph.getNodes().filter(NewArrayNode.class).isEmpty());
ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
double probabilitySum = 0;
int materializeCount = 0;
for (CommitAllocationNode materialize : graph.getNodes().filter(CommitAllocationNode.class)) {
probabilitySum += cfg.blockFor(materialize).probability() * materialize.getVirtualObjects().size();
materializeCount += materialize.getVirtualObjects().size();
}
Assert.assertEquals("unexpected number of MaterializeObjectNodes", expectedCount, materializeCount);
Assert.assertEquals("unexpected probability of MaterializeObjectNodes", expectedProbability, probabilitySum, 0.01);
for (Node node : graph.getNodes()) {
for (Class<? extends Node> clazz : invalidNodeClasses) {
Assert.assertFalse("instance of invalid class: " + clazz.getSimpleName(), clazz.isInstance(node) && node.usages().isNotEmpty());
}
}
} catch (AssertionError e) {
TypeSystemTest.outputGraph(graph, snippet + ": " + e.getMessage());
throw e;
}
}
Aggregations