--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java Thu Apr 06 14:31:32 2017 -0700
@@ -40,6 +40,8 @@
import java.util.function.Predicate;
import org.graalvm.compiler.core.common.Fields;
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.Fingerprint;
import org.graalvm.compiler.graph.Graph.NodeEvent;
@@ -131,7 +133,9 @@
* Denotes an injected parameter in a {@linkplain NodeIntrinsic node intrinsic} constructor. If
* the constructor is called as part of node intrinsification, the node intrinsifier will inject
* an argument for the annotated parameter. Injected parameters must precede all non-injected
- * parameters in a constructor.
+ * parameters in a constructor. If the type of the annotated parameter is {@link Stamp}, the
+ * {@linkplain Stamp#javaType type} of the injected stamp is the return type of the annotated
+ * method (which cannot be {@code void}).
*/
@java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@@ -140,40 +144,45 @@
/**
* Annotates a method that can be replaced by a compiler intrinsic. A (resolved) call to the
- * annotated method can be replaced with an instance of the node class denoted by
- * {@link #value()}. For this reason, the signature of the annotated method must match the
- * signature (excluding a prefix of {@linkplain InjectedNodeParameter injected} parameters) of a
- * constructor in the node class.
+ * annotated method will be processed by a generated {@code InvocationPlugin} that calls either
+ * a factory method or a constructor corresponding with the annotated method.
* <p>
- * If the node class has a static method {@code intrinsify} with a matching signature plus a
- * {@code GraphBuilderContext} as first argument, this method is called instead of creating the
- * node.
+ * A factory method corresponding to an annotated method is a static method named
+ * {@code intrinsify} defined in the class denoted by {@link #value()}. In order, its signature
+ * is as follows:
+ * <ol>
+ * <li>A {@code GraphBuilderContext} parameter.</li>
+ * <li>A {@code ResolvedJavaMethod} parameter.</li>
+ * <li>A sequence of zero or more {@linkplain InjectedNodeParameter injected} parameters.</li>
+ * <li>Remaining parameters that match the declared parameters of the annotated method.</li>
+ * </ol>
+ * A constructor corresponding to an annotated method is defined in the class denoted by
+ * {@link #value()}. In order, its signature is as follows:
+ * <ol>
+ * <li>A sequence of zero or more {@linkplain InjectedNodeParameter injected} parameters.</li>
+ * <li>Remaining parameters that match the declared parameters of the annotated method.</li>
+ * </ol>
+ * There must be exactly one such factory method or constructor corresponding to a
+ * {@link NodeIntrinsic} annotated method.
*/
@java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.METHOD)
public static @interface NodeIntrinsic {
/**
- * Gets the {@link Node} subclass instantiated when intrinsifying a call to the annotated
- * method. If not specified, then the class in which the annotated method is declared is
- * used (and is assumed to be a {@link Node} subclass).
+ * The class declaring the factory method or {@link Node} subclass declaring the constructor
+ * used to intrinsify a call to the annotated method. The default value is the class in
+ * which the annotated method is declared.
*/
Class<?> value() default NodeIntrinsic.class;
/**
- * Determines if the stamp of the instantiated intrinsic node has its stamp set from the
- * return type of the annotated method.
- * <p>
- * When it is set to true, the stamp that is passed in to the constructor of ValueNode is
- * ignored and can therefore safely be {@code null}.
+ * If {@code true}, the factory method or constructor selected by the annotation must have
+ * an {@linkplain InjectedNodeParameter injected} {@link Stamp} parameter. Calling
+ * {@link AbstractPointerStamp#nonNull()} on the injected stamp is guaranteed to return
+ * {@code true}.
*/
- boolean setStampFromReturnType() default false;
-
- /**
- * Determines if the stamp of the instantiated intrinsic node is guaranteed to be non-null.
- * Generally used in conjunction with {@link #setStampFromReturnType()}.
- */
- boolean returnStampIsNonNull() default false;
+ boolean injectedStampIsNonNull() default false;
}
/**
@@ -304,7 +313,7 @@
* @return an {@link NodeIterable iterable} for all non-null successor edges.
*/
public NodeIterable<Node> successors() {
- assert !this.isDeleted();
+ assert !this.isDeleted() : this;
return nodeClass.getSuccessorIterable(this);
}
@@ -328,7 +337,7 @@
if (usage1 == null) {
return 1;
}
- return 2 + extraUsagesCount;
+ return INLINE_USAGE_COUNT + extraUsagesCount;
}
/**
@@ -391,30 +400,45 @@
}
private void movUsageFromEndTo(int destIndex) {
- int lastIndex = this.getUsageCount() - 1;
- if (destIndex == 0) {
- if (lastIndex == 0) {
- usage0 = null;
- return;
- } else if (lastIndex == 1) {
- usage0 = usage1;
- usage1 = null;
- return;
- } else {
- usage0 = extraUsages[lastIndex - INLINE_USAGE_COUNT];
- }
+ if (destIndex >= INLINE_USAGE_COUNT) {
+ movUsageFromEndToExtraUsages(destIndex - INLINE_USAGE_COUNT);
} else if (destIndex == 1) {
- if (lastIndex == 1) {
- usage1 = null;
- return;
- }
- usage1 = extraUsages[lastIndex - INLINE_USAGE_COUNT];
+ movUsageFromEndToIndexOne();
} else {
- Node n = extraUsages[lastIndex - INLINE_USAGE_COUNT];
- extraUsages[destIndex - INLINE_USAGE_COUNT] = n;
+ assert destIndex == 0;
+ movUsageFromEndToIndexZero();
}
- extraUsages[lastIndex - INLINE_USAGE_COUNT] = null;
+ }
+
+ private void movUsageFromEndToExtraUsages(int destExtraIndex) {
this.extraUsagesCount--;
+ Node n = extraUsages[extraUsagesCount];
+ extraUsages[destExtraIndex] = n;
+ extraUsages[extraUsagesCount] = null;
+ }
+
+ private void movUsageFromEndToIndexZero() {
+ if (extraUsagesCount > 0) {
+ this.extraUsagesCount--;
+ usage0 = extraUsages[extraUsagesCount];
+ extraUsages[extraUsagesCount] = null;
+ } else if (usage1 != null) {
+ usage0 = usage1;
+ usage1 = null;
+ } else {
+ usage0 = null;
+ }
+ }
+
+ private void movUsageFromEndToIndexOne() {
+ if (extraUsagesCount > 0) {
+ this.extraUsagesCount--;
+ usage1 = extraUsages[extraUsagesCount];
+ extraUsages[extraUsagesCount] = null;
+ } else {
+ assert usage1 != null;
+ usage1 = null;
+ }
}
/**
@@ -425,20 +449,21 @@
*/
public boolean removeUsage(Node node) {
assert node != null;
- // It is critical that this method maintains the invariant that
- // the usage list has no null element preceding a non-null element
+ // For large graphs, usage removal is performance critical.
+ // Furthermore, it is critical that this method maintains the invariant that the usage list
+ // has no null element preceding a non-null element.
incUsageModCount();
if (usage0 == node) {
- this.movUsageFromEndTo(0);
+ movUsageFromEndToIndexZero();
return true;
}
if (usage1 == node) {
- this.movUsageFromEndTo(1);
+ movUsageFromEndToIndexOne();
return true;
}
for (int i = this.extraUsagesCount - 1; i >= 0; i--) {
if (extraUsages[i] == node) {
- this.movUsageFromEndTo(i + INLINE_USAGE_COUNT);
+ movUsageFromEndToExtraUsages(i);
return true;
}
}
@@ -537,8 +562,9 @@
assert assertTrue(id == INITIAL_ID, "unexpected id: %d", id);
this.graph = newGraph;
newGraph.register(this);
- this.getNodeClass().registerAtInputsAsUsage(this);
- this.getNodeClass().registerAtSuccessorsAsPredecessor(this);
+ NodeClass<? extends Node> nc = nodeClass;
+ nc.registerAtInputsAsUsage(this);
+ nc.registerAtSuccessorsAsPredecessor(this);
}
/**
@@ -588,7 +614,7 @@
}
public final void replaceAtUsages(Node other) {
- replaceAtUsages(other, null, null);
+ replaceAtAllUsages(other, (Node) null);
}
public final void replaceAtUsages(Node other, Predicate<Node> filter) {
@@ -606,22 +632,60 @@
}
protected void replaceAtUsages(Node other, Predicate<Node> filter, Node toBeDeleted) {
+ if (filter == null) {
+ replaceAtAllUsages(other, toBeDeleted);
+ } else {
+ replaceAtMatchingUsages(other, filter, toBeDeleted);
+ }
+ }
+
+ protected void replaceAtAllUsages(Node other, Node toBeDeleted) {
+ assert checkReplaceWith(other);
+ if (usage0 == null) {
+ return;
+ }
+ replaceAtUsage(other, toBeDeleted, usage0);
+ usage0 = null;
+
+ if (usage1 == null) {
+ return;
+ }
+ replaceAtUsage(other, toBeDeleted, usage1);
+ usage1 = null;
+
+ if (extraUsagesCount <= 0) {
+ return;
+ }
+ for (int i = 0; i < extraUsagesCount; i++) {
+ Node usage = extraUsages[i];
+ replaceAtUsage(other, toBeDeleted, usage);
+ }
+ this.extraUsages = NO_NODES;
+ this.extraUsagesCount = 0;
+ }
+
+ private void replaceAtUsage(Node other, Node toBeDeleted, Node usage) {
+ boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
+ assert assertTrue(result, "not found in inputs, usage: %s", usage);
+ /*
+ * Don't notify for nodes which are about to be deleted.
+ */
+ if (toBeDeleted == null || usage != toBeDeleted) {
+ maybeNotifyInputChanged(usage);
+ }
+ if (other != null) {
+ other.addUsage(usage);
+ }
+ }
+
+ private void replaceAtMatchingUsages(Node other, Predicate<Node> filter, Node toBeDeleted) {
+ assert filter != null;
assert checkReplaceWith(other);
int i = 0;
while (i < this.getUsageCount()) {
Node usage = this.getUsageAt(i);
if (filter == null || filter.test(usage)) {
- boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
- assert assertTrue(result, "not found in inputs, usage: %s", usage);
- /*
- * Don't notify for nodes which are about to be deleted.
- */
- if (toBeDeleted == null || usage != toBeDeleted) {
- maybeNotifyInputChanged(usage);
- }
- if (other != null) {
- other.addUsage(usage);
- }
+ replaceAtUsage(other, toBeDeleted, usage);
this.movUsageFromEndTo(i);
} else {
++i;
@@ -641,21 +705,7 @@
public void replaceAtMatchingUsages(Node other, NodePredicate usagePredicate) {
assert checkReplaceWith(other);
- int index = 0;
- while (index < this.getUsageCount()) {
- Node usage = getUsageAt(index);
- if (usagePredicate.apply(usage)) {
- boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
- assert assertTrue(result, "not found in inputs, usage: %s", usage);
- if (other != null) {
- maybeNotifyInputChanged(usage);
- other.addUsage(usage);
- }
- this.movUsageFromEndTo(index);
- } else {
- index++;
- }
- }
+ replaceAtMatchingUsages(other, usagePredicate, null);
}
public void replaceAtUsages(InputType type, Node other) {