--- /dev/null 2016-05-31 09:42:47.975716356 -0700
+++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InstanceOfSnippetsTemplates.java 2016-12-09 00:57:00.166186387 -0800
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import static org.graalvm.compiler.nodes.calc.CompareNode.createCompareNode;
+
+import java.util.List;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.ConditionAnchorNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ShortCircuitOrNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.CompareNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.java.ClassIsAssignableFromNode;
+import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.UsageReplacer;
+
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * Helper class for lowering {@link InstanceOfNode}s with snippets. The majority of the complexity
+ * in such a lowering derives from the fact that {@link InstanceOfNode} is a floating node. A
+ * snippet used to lower an {@link InstanceOfNode} will almost always incorporate control flow and
+ * replacing a floating node with control flow is not trivial.
+ *
+ * The mechanism implemented in this class ensures that the graph for an instanceof snippet is
+ * instantiated once per {@link InstanceOfNode} being lowered. The result produced is then re-used
+ * by all usages of the node. Additionally, if there is a single usage that is an {@link IfNode},
+ * the control flow in the snippet is connected directly to the true and false successors of the
+ * {@link IfNode}. This avoids materializing the instanceof test as a boolean which is then retested
+ * by the {@link IfNode}.
+ */
+public abstract class InstanceOfSnippetsTemplates extends AbstractTemplates {
+
+ public InstanceOfSnippetsTemplates(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
+ super(providers, snippetReflection, target);
+ }
+
+ /**
+ * Gets the arguments used to retrieve and instantiate an instanceof snippet template.
+ */
+ protected abstract Arguments makeArguments(InstanceOfUsageReplacer replacer, LoweringTool tool);
+
+ public void lower(FloatingNode instanceOf, LoweringTool tool) {
+ assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode || instanceOf instanceof ClassIsAssignableFromNode;
+ List usages = instanceOf.usages().snapshot();
+
+ Instantiation instantiation = new Instantiation();
+ for (Node usage : usages) {
+ final StructuredGraph graph = (StructuredGraph) usage.graph();
+
+ InstanceOfUsageReplacer replacer = createReplacer(instanceOf, instantiation, usage, graph);
+
+ if (instantiation.isInitialized()) {
+ // No need to re-instantiate the snippet - just re-use its result
+ replacer.replaceUsingInstantiation();
+ } else {
+ Arguments args = makeArguments(replacer, tool);
+ template(args).instantiate(providers.getMetaAccess(), instanceOf, replacer, tool, args);
+ }
+ }
+
+ assert instanceOf.hasNoUsages();
+ if (!instanceOf.isDeleted()) {
+ GraphUtil.killWithUnusedFloatingInputs(instanceOf);
+ }
+ }
+
+ /**
+ * Gets the specific replacer object used to replace the usage of an instanceof node with the
+ * result of an instantiated instanceof snippet.
+ */
+ protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, Instantiation instantiation, Node usage, final StructuredGraph graph) {
+ InstanceOfUsageReplacer replacer;
+ if (!canMaterialize(usage)) {
+ ValueNode trueValue = ConstantNode.forInt(1, graph);
+ ValueNode falseValue = ConstantNode.forInt(0, graph);
+ if (instantiation.isInitialized() && (trueValue != instantiation.trueValue || falseValue != instantiation.falseValue)) {
+ /*
+ * This code doesn't really care what values are used so adopt the values from the
+ * previous instantiation.
+ */
+ trueValue = instantiation.trueValue;
+ falseValue = instantiation.falseValue;
+ }
+ replacer = new NonMaterializationUsageReplacer(instantiation, trueValue, falseValue, instanceOf, usage);
+ } else {
+ assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage;
+ ConditionalNode c = (ConditionalNode) usage;
+ replacer = new MaterializationUsageReplacer(instantiation, c.trueValue(), c.falseValue(), instanceOf, c);
+ }
+ return replacer;
+ }
+
+ /**
+ * Determines if an {@code instanceof} usage can be materialized.
+ */
+ protected boolean canMaterialize(Node usage) {
+ if (usage instanceof ConditionalNode) {
+ ConditionalNode cn = (ConditionalNode) usage;
+ return cn.trueValue().isConstant() && cn.falseValue().isConstant();
+ }
+ if (usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ShortCircuitOrNode || usage instanceof ConditionAnchorNode) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * The result of instantiating an instanceof snippet. This enables a snippet instantiation to be
+ * re-used which reduces compile time and produces better code.
+ */
+ public static final class Instantiation {
+
+ private ValueNode result;
+ private LogicNode condition;
+ private ValueNode trueValue;
+ private ValueNode falseValue;
+
+ /**
+ * Determines if the instantiation has occurred.
+ */
+ boolean isInitialized() {
+ return result != null;
+ }
+
+ void initialize(ValueNode r, ValueNode t, ValueNode f) {
+ assert !isInitialized();
+ this.result = r;
+ this.trueValue = t;
+ this.falseValue = f;
+ }
+
+ /**
+ * Gets the result of this instantiation as a condition.
+ *
+ * @param testValue the returned condition is true if the result is equal to this value
+ */
+ LogicNode asCondition(ValueNode testValue) {
+ assert isInitialized();
+ if (result.isConstant()) {
+ assert testValue.isConstant();
+ return LogicConstantNode.forBoolean(result.asConstant().equals(testValue.asConstant()), result.graph());
+ }
+ if (condition == null || (!(condition instanceof CompareNode)) || ((CompareNode) condition).getY() != testValue) {
+ // Re-use previously generated condition if the trueValue for the test is the same
+ condition = createCompareNode(result.graph(), Condition.EQ, result, testValue, null);
+ }
+ return condition;
+ }
+
+ /**
+ * Gets the result of the instantiation as a materialized value.
+ *
+ * @param t the true value for the materialization
+ * @param f the false value for the materialization
+ */
+ ValueNode asMaterialization(StructuredGraph graph, ValueNode t, ValueNode f) {
+ assert isInitialized();
+ if (t == this.trueValue && f == this.falseValue) {
+ // Can simply use the phi result if the same materialized values are expected.
+ return result;
+ } else {
+ return graph.unique(new ConditionalNode(asCondition(trueValue), t, f));
+ }
+ }
+ }
+
+ /**
+ * Replaces a usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode}.
+ */
+ public abstract static class InstanceOfUsageReplacer implements UsageReplacer {
+
+ public final Instantiation instantiation;
+ public final FloatingNode instanceOf;
+ public final ValueNode trueValue;
+ public final ValueNode falseValue;
+
+ public InstanceOfUsageReplacer(Instantiation instantiation, FloatingNode instanceOf, ValueNode trueValue, ValueNode falseValue) {
+ assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode || instanceOf instanceof ClassIsAssignableFromNode;
+ this.instantiation = instantiation;
+ this.instanceOf = instanceOf;
+ this.trueValue = trueValue;
+ this.falseValue = falseValue;
+ }
+
+ /**
+ * Does the replacement based on a previously snippet instantiation.
+ */
+ public abstract void replaceUsingInstantiation();
+ }
+
+ /**
+ * Replaces the usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode} that does
+ * not materialize the result of the type test.
+ */
+ public static class NonMaterializationUsageReplacer extends InstanceOfUsageReplacer {
+
+ private final Node usage;
+
+ public NonMaterializationUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, Node usage) {
+ super(instantiation, instanceOf, trueValue, falseValue);
+ this.usage = usage;
+ }
+
+ @Override
+ public void replaceUsingInstantiation() {
+ usage.replaceFirstInput(instanceOf, instantiation.asCondition(trueValue));
+ }
+
+ @Override
+ public void replace(ValueNode oldNode, ValueNode newNode) {
+ assert newNode instanceof PhiNode;
+ assert oldNode == instanceOf;
+ newNode.inferStamp();
+ instantiation.initialize(newNode, trueValue, falseValue);
+ usage.replaceFirstInput(oldNode, instantiation.asCondition(trueValue));
+ }
+ }
+
+ /**
+ * Replaces the usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode} that does
+ * materializes the result of the type test.
+ */
+ public static class MaterializationUsageReplacer extends InstanceOfUsageReplacer {
+
+ public final ConditionalNode usage;
+
+ public MaterializationUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, ConditionalNode usage) {
+ super(instantiation, instanceOf, trueValue, falseValue);
+ this.usage = usage;
+ }
+
+ @Override
+ public void replaceUsingInstantiation() {
+ ValueNode newValue = instantiation.asMaterialization(usage.graph(), trueValue, falseValue);
+ usage.replaceAtUsages(newValue);
+ assert usage.hasNoUsages();
+ GraphUtil.killWithUnusedFloatingInputs(usage);
+ }
+
+ @Override
+ public void replace(ValueNode oldNode, ValueNode newNode) {
+ assert newNode instanceof PhiNode;
+ assert oldNode == instanceOf;
+ newNode.inferStamp();
+ instantiation.initialize(newNode, trueValue, falseValue);
+ usage.replaceAtUsages(newNode);
+ assert usage.hasNoUsages();
+ GraphUtil.killWithUnusedFloatingInputs(usage);
+ }
+ }
+}