/** * Similar to {@link #deverbosifyInputsInPlace(com.oracle.graal.nodes.ValueNode)}, except that not * the parent but a fresh clone is updated upon any of its children changing. * * @return the original parent if no updated took place, a copy-on-write version of it otherwise. */ private MethodCallTargetNode deverbosifyInputsCopyOnWrite(MethodCallTargetNode parent) { final CallTargetNode.InvokeKind ik = parent.invokeKind(); final boolean shouldTryDevirt = (ik == CallTargetNode.InvokeKind.Interface || ik == CallTargetNode.InvokeKind.Virtual); boolean shouldDowncastReceiver = shouldTryDevirt; MethodCallTargetNode changed = null; for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(parent)) { ValueNode j = (ValueNode) reasoner.deverbosify(i); if (shouldDowncastReceiver) { shouldDowncastReceiver = false; j = reasoner.downcast(j); } if (i != j) { assert j != parent; if (changed == null) { changed = (MethodCallTargetNode) parent.copyWithInputs(); reasoner.added.add(changed); // copyWithInputs() implies graph.unique(changed) assert changed.isAlive(); assert FlowUtil.lacksUsages(changed); } FlowUtil.replaceInPlace(changed, i, j); } } if (changed == null) { return parent; } FlowUtil.inferStampAndCheck(changed); /* * No need to rememberSubstitution() because not called from deverbosify(). In detail, it's * only deverbosify() that skips visited nodes (thus we'd better have recorded any * substitutions we want for them). Not this case. */ return changed; }
/** * Reduce input nodes based on the state at the program point for the argument (ie, based on * "valid facts" only, without relying on any floating-guard-assumption). * * <p>For each (direct or indirect) child, a copy-on-write version is made in case any of its * children changed, with the copy accommodating the updated children. If the parent was shared, * copy-on-write prevents the updates from becoming visible to anyone but the invoker of this * method. * * <p><b> Please note the parent node is mutated upon any descendant changing. No copy-on-write is * performed for the parent node itself. </b> * * <p>In more detail, for each direct {@link com.oracle.graal.nodes.ValueNode} input of the node * at hand, * * <ol> * <li>Obtain a lazy-copied version (via spanning tree) of the DAG rooted at the input-usage in * question. Lazy-copying is done by walking a spanning tree of the original DAG, stopping * at non-FloatingNodes but transitively walking FloatingNodes and their inputs. Upon * arriving at a (floating) node N, the state's facts are checked to determine whether a * constant C can be used instead in the resulting lazy-copied DAG. A NodeBitMap is used to * realize the spanning tree. * <li>Provided one or more N-to-C node replacements took place, the resulting lazy-copied DAG * has a parent different from the original (ie different object identity) which indicates * the (copied, updated) DAG should replace the original via replaceFirstInput(), and * inferStamp() should be invoked to reflect the updated inputs. * </ol> * * @return whether any reduction was performed on the inputs of the arguments. */ public boolean deverbosifyInputsInPlace(ValueNode parent) { boolean changed = false; for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(parent)) { assert !(i instanceof GuardNode) : "This phase not intended to run during MidTier"; ValueNode j = (ValueNode) reasoner.deverbosify(i); if (i != j) { changed = true; FlowUtil.replaceInPlace(parent, i, j); } } if (changed) { FlowUtil.inferStampAndCheck(parent); } return changed; }