* r2 := r3 becomes r1 := r2
* r1 := r2 r2 := r3
@@ -104,7 +104,7 @@
}
}
- private final LIRGenerator gen;
+ private final LIRGeneratorTool gen;
/**
* The operand loop header phi for the operand currently being process in {@link #dispose()}.
@@ -121,7 +121,7 @@
*/
private final HashMap operandToNodeMap = new HashMap<>();
- public PhiResolver(LIRGenerator gen) {
+ public PhiResolver(LIRGeneratorTool gen) {
this.gen = gen;
temp = ILLEGAL;
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchResult.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchResult.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.compiler.match;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+
+/*
+ * A closure that can be evaluated to produce the LIR for some complex match. Using a closure
+ * allows normal evaluation in NodeLIRBuilder for all the simple nodes with the complex nodes
+ * evaluated at the proper time.
+ */
+public interface ComplexMatchResult {
+ Value evaluate(NodeLIRBuilder gen);
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.compiler.match;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+
+/**
+ * A wrapper value for the lazy evaluation of a complex match. There's an intermediate class for the
+ * closure because Value is serializable which is a hassle for the little inner classes which
+ * usually occur here.
+ */
+public class ComplexMatchValue extends Value {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -4734670273590368770L;
+
+ final ComplexMatchResult result;
+
+ public ComplexMatchValue(ComplexMatchResult result) {
+ super(Kind.Illegal);
+ this.result = result;
+ }
+
+ public Value evaluate(NodeLIRBuilder builder) {
+ return result.evaluate(builder);
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.compiler.match;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+
+/**
+ * Helper class to describe the matchable nodes in the core Graal IR. These could possibly live in
+ * their respective classes but for simplicity in the {@link MatchProcessor} they are grouped here.
+ */
+@MatchableNode(shortName = "Constant", value = ConstantNode.class, inputs = 0)
+@MatchableNode(shortName = "FloatConvert", value = FloatConvertNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
+@MatchableNode(shortName = "FloatSub", value = FloatSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
+@MatchableNode(shortName = "FloatingRead", value = FloatingReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class)
+@MatchableNode(shortName = "If", value = IfNode.class, inputs = 1, adapter = GraalMatchableNodes.IfNodeAdapter.class)
+@MatchableNode(shortName = "IntegerSub", value = IntegerSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
+@MatchableNode(shortName = "LeftShift", value = LeftShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
+@MatchableNode(shortName = "Narrow", value = NarrowNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
+@MatchableNode(shortName = "Read", value = ReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class)
+@MatchableNode(shortName = "Reinterpret", value = ReinterpretNode.class, inputs = 1, adapter = GraalMatchableNodes.ReinterpretNodeAdapter.class)
+@MatchableNode(shortName = "SignExtend", value = SignExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
+@MatchableNode(shortName = "UnsignedRightShift", value = UnsignedRightShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
+@MatchableNode(shortName = "Write", value = WriteNode.class, inputs = 2, adapter = GraalMatchableNodes.WriteNodeAdapter.class)
+@MatchableNode(shortName = "ZeroExtend", value = ZeroExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
+@MatchableNode(shortName = "And", value = AndNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "FloatAdd", value = FloatAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "FloatEquals", value = FloatEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "FloatLessThan", value = FloatLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "FloatMul", value = FloatMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "IntegerAdd", value = IntegerAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "IntegerBelowThan", value = IntegerBelowThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "IntegerEquals", value = IntegerEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "IntegerLessThan", value = IntegerLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "IntegerMul", value = IntegerMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "IntegerTest", value = IntegerTestNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "ObjectEquals", value = ObjectEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "Or", value = OrNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(shortName = "Xor", value = XorNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+public class GraalMatchableNodes {
+ public static class BinaryNodeAdapter extends MatchNodeAdapter {
+ @Override
+ protected ValueNode getFirstInput(ValueNode node) {
+ return ((BinaryNode) node).x();
+ }
+
+ @Override
+ protected ValueNode getSecondInput(ValueNode node) {
+ return ((BinaryNode) node).y();
+ }
+ }
+
+ public static class WriteNodeAdapter extends MatchNodeAdapter {
+
+ @Override
+ protected ValueNode getFirstInput(ValueNode node) {
+ return ((WriteNode) node).object();
+ }
+
+ @Override
+ protected ValueNode getSecondInput(ValueNode node) {
+ return ((WriteNode) node).value();
+ }
+ }
+
+ public static class ConvertNodeAdapter extends MatchNodeAdapter {
+
+ @Override
+ protected ValueNode getFirstInput(ValueNode node) {
+ return ((ConvertNode) node).getInput();
+ }
+ }
+
+ public static class ReinterpretNodeAdapter extends MatchNodeAdapter {
+
+ @Override
+ protected ValueNode getFirstInput(ValueNode node) {
+ return ((ReinterpretNode) node).value();
+ }
+ }
+
+ public static class IfNodeAdapter extends MatchNodeAdapter {
+
+ @Override
+ protected ValueNode getFirstInput(ValueNode node) {
+ return ((IfNode) node).condition();
+ }
+ }
+
+ public static class ReadNodeAdapter extends MatchNodeAdapter {
+
+ @Override
+ protected ValueNode getFirstInput(ValueNode node) {
+ return ((Access) node).object();
+ }
+ }
+
+ public static class BinaryOpLogicNodeAdapter extends MatchNodeAdapter {
+
+ @Override
+ protected ValueNode getFirstInput(ValueNode node) {
+ return ((BinaryOpLogicNode) node).x();
+ }
+
+ @Override
+ protected ValueNode getSecondInput(ValueNode node) {
+ return ((BinaryOpLogicNode) node).y();
+ }
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.compiler.match;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.MatchPattern.Result;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.virtual.*;
+
+/**
+ * Container for state captured during a match.
+ */
+public class MatchContext {
+ private final ArrayList consumed = new ArrayList<>();
+ private final List nodes;
+ private final ValueNode root;
+ private List names;
+ private List> types;
+ private List values;
+ private final MatchStatement rule;
+ private int startIndex;
+ private int endIndex;
+ private final NodeLIRBuilder builder;
+
+ public MatchContext(NodeLIRBuilder builder, MatchStatement rule, ValueNode node, List nodes) {
+ this.builder = builder;
+ this.rule = rule;
+ this.root = node;
+ this.nodes = nodes;
+ // The root should be the last index since all the inputs must be scheduled before.
+ startIndex = endIndex = nodes.indexOf(node);
+ }
+
+ public ValueNode getRoot() {
+ return root;
+ }
+
+ public Result captureNamedValue(String name, Class extends ValueNode> type, ValueNode value) {
+ if (names == null) {
+ names = new ArrayList<>(2);
+ values = new ArrayList<>(2);
+ types = new ArrayList<>(2);
+ }
+ int index = names.indexOf(name);
+ if (index == -1) {
+ names.add(name);
+ values.add(value);
+ types.add(type);
+ return Result.OK;
+ } else {
+ if (values.get(index) != value) {
+ return Result.NAMED_VALUE_MISMATCH(value, rule.getPattern());
+ }
+ return Result.OK;
+ }
+ }
+
+ public Result validate() {
+ // Ensure that there's no unsafe work in between these operations.
+ for (int i = startIndex; i <= endIndex; i++) {
+ ScheduledNode node = getNodes().get(i);
+ if (node instanceof ConstantNode || node instanceof LocationNode || node instanceof VirtualObjectNode || node instanceof ParameterNode) {
+ // these can be evaluated lazily so don't worry about them. This should probably be
+ // captured by some interface that indicates that their generate method is empty.
+ continue;
+ } else if (!consumed.contains(node) && node != root) {
+ // This is too verbose for normal logging.
+ // Debug.log("unexpected node %s", node);
+ // for (int j = startIndex; j <= endIndex; j++) {
+ // ScheduledNode theNode = getNodes().get(j);
+ // Debug.log("%s(%s) %1s", (consumed.contains(theNode) || theNode == root) ? "*" :
+ // " ",
+ // theNode.usages().count(), theNode);
+ // }
+ return Result.NOT_SAFE(node, rule.getPattern());
+ }
+ }
+ return Result.OK;
+ }
+
+ /**
+ * Transfers the captured value into the MatchGenerator instance. The reflective information
+ * should really be generated and checking during construction of the MatchStatement but this is
+ * ok for now.
+ */
+ public void transferState(MatchGenerator generator) {
+ try {
+ for (int i = 0; i < names.size(); i++) {
+ String name = names.get(i);
+ try {
+ Field field = generator.getClass().getDeclaredField(name);
+ field.setAccessible(true);
+ field.set(generator, values.get(i));
+ } catch (NoSuchFieldException e) {
+ // Doesn't exist so the generator doesn't care about the value.
+ }
+ }
+ } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
+ throw new GraalInternalError(e);
+ }
+ try {
+ Field field = generator.getClass().getDeclaredField("root");
+ field.setAccessible(true);
+ field.set(generator, getRoot());
+ } catch (NoSuchFieldException e) {
+ // Doesn't exist
+ } catch (SecurityException | IllegalAccessException | IllegalArgumentException e) {
+ throw new GraalInternalError(e);
+ }
+ }
+
+ public void setResult(ComplexMatchResult result) {
+ setResult(new ComplexMatchValue(result));
+ }
+
+ /**
+ * Mark the interior nodes with INTERIOR_MATCH and set the Value of the root to be the result.
+ * During final LIR generation it will be evaluated to produce the actual LIR value.
+ *
+ * @param result
+ */
+ public void setResult(ComplexMatchValue result) {
+ Debug.log("matched %s %s", rule.getName(), rule.getPattern());
+ // Debug.log("%s", rule.formatMatch(root));
+ for (ValueNode node : consumed) {
+ // All the interior nodes should be skipped during the normal doRoot calls in
+ // NodeLIRBuilder so mark them as interior matches. The root of the match will get a
+ // closure which will be evaluated to produce the final LIR.
+ getBuilder().setMatchResult(node, Value.INTERIOR_MATCH);
+ }
+ getBuilder().setMatchResult(root, result);
+ }
+
+ /**
+ * Mark a node as consumed by the match. Consumed nodes will never be evaluated.
+ *
+ * @return Result.OK if the node can be safely consumed.
+ */
+ public Result consume(ValueNode node) {
+ if (node.usages().count() != 1) {
+ return Result.TOO_MANY_USERS(node, rule.getPattern());
+ }
+
+ if (getBuilder().hasOperand(node)) {
+ return Result.ALREADY_USED(node, rule.getPattern());
+ }
+
+ int index = getNodes().indexOf(node);
+ if (index == -1) {
+ return Result.NOT_IN_BLOCK(node, rule.getPattern());
+ }
+ startIndex = Math.min(startIndex, index);
+ consumed.add(node);
+ return Result.OK;
+ }
+
+ private NodeLIRBuilder getBuilder() {
+ return builder;
+ }
+
+ private List getNodes() {
+ return nodes;
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchGenerator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchGenerator.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.compiler.match;
+
+import com.oracle.graal.compiler.gen.*;
+
+/**
+ * Code generator for complex match patterns.
+ */
+public interface MatchGenerator {
+ /**
+ * @returns null if the match can't be generated or a {@link ComplexMatchResult} that can be
+ * evaluated during LIR generation to produce the final LIR value.
+ */
+ ComplexMatchResult match(NodeLIRBuilder gen);
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchNodeAdapter.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchNodeAdapter.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.compiler.match;
+
+import com.oracle.graal.nodes.*;
+
+/**
+ * Helper class to visit the matchable inputs of a node in a specified order. This may not be needed
+ * in the end since this could probably be done using the inputs iterator but it simplifies things
+ * for the moment.
+ */
+public class MatchNodeAdapter {
+ @SuppressWarnings("unused")
+ protected ValueNode getFirstInput(ValueNode node) {
+ throw new InternalError();
+ }
+
+ @SuppressWarnings("unused")
+ protected ValueNode getSecondInput(ValueNode node) {
+ throw new InternalError();
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.compiler.match;
+
+import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.nodes.*;
+
+/**
+ * A simple recursive pattern matcher for a DAG of nodes.
+ */
+
+public class MatchPattern {
+
+ enum MatchResultCode {
+ OK,
+ WRONG_CLASS,
+ NAMED_VALUE_MISMATCH,
+ TOO_MANY_USERS,
+ NOT_IN_BLOCK,
+ NOT_SAFE,
+ ALREADY_USED,
+ }
+
+ /**
+ * A descriptive result for match failures. This can be helpful for debugging why a match
+ * doesn't work as expected.
+ */
+ static class Result {
+ final MatchResultCode code;
+ final ScheduledNode node;
+ final MatchPattern matcher;
+
+ Result(MatchResultCode result, ScheduledNode node, MatchPattern matcher) {
+ this.code = result;
+ this.node = node;
+ this.matcher = matcher;
+ }
+
+ static final Result OK = new Result(MatchResultCode.OK, null, null);
+
+ static Result WRONG_CLASS(ValueNode node, MatchPattern matcher) {
+ return new Result(MatchResultCode.WRONG_CLASS, node, matcher);
+ }
+
+ static Result NAMED_VALUE_MISMATCH(ValueNode node, MatchPattern matcher) {
+ return new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher);
+ }
+
+ static Result TOO_MANY_USERS(ValueNode node, MatchPattern matcher) {
+ return new Result(MatchResultCode.TOO_MANY_USERS, node, matcher);
+ }
+
+ static Result NOT_IN_BLOCK(ScheduledNode node, MatchPattern matcher) {
+ return new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher);
+ }
+
+ static Result NOT_SAFE(ScheduledNode node, MatchPattern matcher) {
+ return new Result(MatchResultCode.NOT_SAFE, node, matcher);
+ }
+
+ static Result ALREADY_USED(ValueNode node, MatchPattern matcher) {
+ return new Result(MatchResultCode.ALREADY_USED, node, matcher);
+ }
+
+ @Override
+ public String toString() {
+ if (code == MatchResultCode.OK) {
+ return "OK";
+ }
+ return code + " " + node.toString(Verbosity.Id) + "|" + node.getClass().getSimpleName() + " " + matcher;
+ }
+ }
+
+ /**
+ * The expected type of the node. It must match exactly.
+ */
+ private final Class extends ValueNode> nodeClass;
+ /**
+ * An optional name for this node. A name can occur multiple times in a match and that name must
+ * always refer to the same node of the match will fail.
+ */
+ private final String name;
+ /**
+ * An optional pattern for the first input.
+ */
+ private final MatchPattern first;
+ /**
+ * An optional pattern for the second input.
+ */
+ private final MatchPattern second;
+ /**
+ * Helper class to visit the inputs.
+ */
+ private final MatchNodeAdapter adapter;
+ /**
+ * Can there only be one user of the node. Constant nodes can be matched even if there are other
+ * users.
+ */
+ private final boolean singleUser;
+
+ public MatchPattern(String name, boolean singleUser) {
+ this(null, name, null, null, null, singleUser);
+ }
+
+ public MatchPattern(Class extends ValueNode> nodeClass, String name, boolean singleUser) {
+ this(nodeClass, name, null, null, null, singleUser);
+ }
+
+ public MatchPattern(Class extends ValueNode> nodeClass, String name, MatchPattern first, MatchNodeAdapter adapter, boolean singleUser) {
+ this(nodeClass, name, first, null, adapter, singleUser);
+ }
+
+ public MatchPattern(Class extends ValueNode> nodeClass, String name, MatchPattern first, MatchPattern second, MatchNodeAdapter adapter, boolean singleUser) {
+ this.nodeClass = nodeClass;
+ this.name = name;
+ this.singleUser = singleUser;
+ this.first = first;
+ this.second = second;
+ this.adapter = adapter;
+ }
+
+ Class extends ValueNode> nodeClass() {
+ return nodeClass;
+ }
+
+ Result match(ValueNode node, MatchContext context) {
+ return matchTree(node, context, true);
+ }
+
+ private Result matchTree(ValueNode node, MatchContext context, boolean atRoot) {
+ Result result = Result.OK;
+ if (nodeClass != null && node.getClass() != nodeClass) {
+ return Result.WRONG_CLASS(node, this);
+ }
+ if (singleUser && !atRoot) {
+ result = context.consume(node);
+ if (result != Result.OK) {
+ return result;
+ }
+ }
+
+ if (name != null) {
+ result = context.captureNamedValue(name, nodeClass, node);
+ }
+
+ if (first != null) {
+ result = first.matchTree(adapter.getFirstInput(node), context, false);
+ if (result == Result.OK && second != null) {
+ result = second.matchTree(adapter.getSecondInput(node), context, false);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * For a node starting at root, produce a String showing the inputs that matched against this
+ * rule. It's assumed that a match has already succeeded against this rule, otherwise the
+ * printing may produce exceptions.
+ */
+ public String formatMatch(ValueNode root) {
+ String result = String.format("%s", root);
+ if (first == null && second == null) {
+ return result;
+ } else {
+ return "(" + result + (first != null ? " " + first.formatMatch(adapter.getFirstInput(root)) : "") + (second != null ? " " + second.formatMatch(adapter.getSecondInput(root)) : "") + ")";
+ }
+ }
+
+ @Override
+ public String toString() {
+ if (nodeClass == null) {
+ return name;
+ } else {
+ String pre = first != null || second != null ? "(" : "";
+ String post = first != null || second != null ? ")" : "";
+ String nodeName = nodeClass.getSimpleName();
+ return pre + nodeName + (name != null ? "=\"" + name + "\"" : "") + (first != null ? (" " + first.toString()) : "") + (second != null ? (" " + second.toString()) : "") + post;
+ }
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,574 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.compiler.match;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+import javax.annotation.processing.*;
+import javax.lang.model.*;
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.*;
+
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Processes classes annotated with {@link MatchRule}. A {@link MatchStatementSet} service is
+ * generated for each top level class containing at least one such field. These service objects can
+ * be retrieved as follows:
+ *
+ *
+ *
+ * All matched nodes except the root of the match and {@link ConstantNode}s must have a single user.
+ * All matched nodes must be in the same block.
+ */
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Repeatable(value = MatchRules.class)
+public @interface MatchRule {
+ String value();
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.compiler.match;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.nodes.*;
+
+public class MatchRuleRegistry {
+
+ private static final HashMap, Map, List>> registry = new HashMap<>();
+
+ /**
+ * Collect all the {@link MatchStatement}s defined by the superclass chain of theClass.
+ *
+ * @param theClass
+ * @return the set of {@link MatchStatement}s applicable to theClass.
+ */
+ public synchronized static Map, List> lookup(Class extends NodeLIRBuilder> theClass) {
+ Map, List> result = registry.get(theClass);
+
+ if (result == null) {
+ HashMap, List> localRules = new HashMap<>();
+ ServiceLoader sl = ServiceLoader.loadInstalled(MatchStatementSet.class);
+ for (MatchStatementSet rules : sl) {
+ localRules.put(rules.forClass(), rules.statements());
+ }
+
+ // Walk the class hierarchy collecting lists and merge them together. The subclass
+ // rules are first which gives them preference over earlier rules.
+ Map, List> rules = new HashMap<>();
+ Class> currentClass = theClass;
+ do {
+ List statements = localRules.get(currentClass);
+ if (statements != null) {
+ for (MatchStatement statement : statements) {
+ Class extends ValueNode> nodeClass = statement.getPattern().nodeClass();
+ List current = rules.get(nodeClass);
+ if (current == null) {
+ current = new ArrayList<>();
+ rules.put(nodeClass, current);
+ }
+ current.add(statement);
+ }
+ }
+ currentClass = currentClass.getSuperclass();
+ } while (currentClass != NodeLIRBuilder.class);
+ registry.put(theClass, rules);
+ assert registry.get(theClass) == rules;
+ result = rules;
+ }
+
+ if (result.size() == 0) {
+ return null;
+ }
+ return result;
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRules.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRules.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+/**
+ * The repeatable representation of {@link MatchRule}. Should never be used directly.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface MatchRules {
+ MatchRule[] value();
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.compiler.match;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.MatchPattern.Result;
+import com.oracle.graal.nodes.*;
+
+/**
+ * A named {@link MatchPattern} along with a {@link MatchGenerator} that can be evaluated to replace
+ * one or more {@link ValueNode}s with a single {@link Value}.
+ */
+
+public class MatchStatement {
+ private final String name;
+ private final MatchPattern pattern;
+ private final Class extends MatchGenerator> generatorClass;
+
+ public MatchStatement(String name, MatchPattern pattern) {
+ this.name = name;
+ this.pattern = pattern;
+ this.generatorClass = null;
+ }
+
+ public MatchStatement(String name, MatchPattern pattern, Class extends MatchGenerator> generator) {
+ this.name = name;
+ this.pattern = pattern;
+ this.generatorClass = generator;
+ }
+
+ /**
+ * Attempt to match the current statement against a Node.
+ *
+ * @param builder the current builder instance.
+ * @param node the node to be matched
+ * @param nodes the nodes in the current block
+ * @return true if the statement matched something and set a {@link ComplexMatchResult} to be
+ * evaluated by the NodeLIRBuilder.
+ */
+ public boolean generate(NodeLIRBuilder builder, ValueNode node, List nodes) {
+ MatchContext context = new MatchContext(builder, this, node, nodes);
+ Result result = pattern.match(node, context);
+ if (result == Result.OK) {
+ result = context.validate();
+ }
+ if (result == Result.OK) {
+ MatchGenerator generator = null;
+ try {
+ generator = generatorClass.newInstance();
+ // Transfer values into gen
+ context.transferState(generator);
+ ComplexMatchResult value = generator.match(builder);
+ if (value != null) {
+ context.setResult(value);
+ return true;
+ }
+ } catch (InstantiationException | IllegalAccessException e) {
+ throw new GraalInternalError(e);
+ }
+ } else {
+ // This is fairly verbose for normal usage.
+ // if (result.code != MatchResultCode.WRONG_CLASS) {
+ // // Don't bother logging if it's just the wrong shape.
+ // Debug.log("while matching %s|%s %s %s %s", context.getRoot().toString(Verbosity.Id),
+ // context.getRoot().getClass().getSimpleName(), getName(), result, node.graph());
+ // }
+ }
+ return false;
+ }
+
+ public String formatMatch(ValueNode root) {
+ return pattern.formatMatch(root);
+ }
+
+ public MatchPattern getPattern() {
+ return pattern;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.compiler.match;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.gen.*;
+
+public interface MatchStatementSet {
+ /**
+ * @return the {@link NodeLIRBuilder} subclass which defined this set of {@link MatchStatement}
+ * instances.
+ */
+ public Class extends NodeLIRBuilder> forClass();
+
+ /**
+ * @return the {@link MatchStatement}s available with this {@link NodeLIRBuilder} subclass.
+ */
+ public List statements();
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+import com.oracle.graal.nodes.*;
+
+/**
+ * Describes the properties of a node for use when building a {@link MatchPattern}s.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Repeatable(value = MatchableNodes.class)
+public @interface MatchableNode {
+
+ /**
+ * The {@link ValueNode} subclass this annotation describes. These annotations might work better
+ * if they were directly on the node being described but that may complicate the annotation
+ * processing.
+ */
+ Class extends ValueNode> value();
+
+ /**
+ * The name used in match patterns. Defaults to class.getSimpleName() with the word Node removed
+ * from the end.
+ */
+ String shortName() default "";
+
+ /**
+ * The number of matchable inputs, which may be less than the real number of inputs.
+ */
+ int inputs() default 0;
+
+ /**
+ * A helper class to visit the inputs in a specified order. Should be a subclass of
+ * {@link MatchNodeAdapter}.
+ */
+ Class> adapter() default MatchableNode.class;
+
+ /**
+ * Can a pattern be matched with the operands swapped. This will cause swapped versions of
+ * patterns to be automatically generated.
+ */
+ boolean commutative() default false;
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodeImport.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodeImport.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+/**
+ * A list of classes which contain one or more {@link MatchableNode} annotations describing nodes
+ * that may be used in match expressions. Those {@link MatchableNode} declarations are parsed before
+ * processing any {@link MatchRule}s.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface MatchableNodeImport {
+ String[] value() default {};
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodes.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodes.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+/**
+ * The repeatable representation of {@link MatchableNode}. Should never be used directly.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface MatchableNodes {
+ MatchableNode[] value() default {};
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Tue Apr 29 18:35:10 2014 +0200
@@ -30,6 +30,7 @@
import com.oracle.graal.options.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.cfs.IterativeFlowSensitiveReductionPhase;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.virtual.phases.ea.*;
@@ -57,9 +58,14 @@
appendPhase(new InliningPhase(canonicalizer));
appendPhase(new DeadCodeEliminationPhase());
- if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) {
+ boolean reduceOrEliminate = FlowSensitiveReduction.getValue() || ConditionalElimination.getValue();
+ if (reduceOrEliminate && OptCanonicalizer.getValue()) {
appendPhase(canonicalizer);
- appendPhase(new IterativeConditionalEliminationPhase(canonicalizer));
+ if (FlowSensitiveReduction.getValue()) {
+ appendPhase(new IterativeFlowSensitiveReductionPhase(canonicalizer));
+ } else {
+ appendPhase(new IterativeConditionalEliminationPhase(canonicalizer));
+ }
}
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Tue Apr 29 18:35:10 2014 +0200
@@ -32,6 +32,7 @@
import com.oracle.graal.lir.asm.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.phases.util.*;
@@ -72,17 +73,17 @@
*/
public abstract FrameMap newFrameMap(RegisterConfig registerConfig);
- public abstract LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes);
+ public abstract LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes);
public abstract LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub);
- public abstract NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen);
+ public abstract NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen);
/**
* @param gen the LIRGenerator the BytecodeLIRBuilder should use
* @param parser the bytecode parser the BytecodeLIRBuilder should use
*/
- public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) {
+ public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) {
throw GraalInternalError.unimplemented("Baseline compilation is not available for this Backend!");
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java Tue Apr 29 18:23:17 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.oracle.graal.compiler.target;
-
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * An alternative to {@link LIRLowerable} for lowering that is tightly coupled to
- * {@link LIRGenerator} and {@link LIRInstruction}.
- */
-public interface LIRGenLowerable {
-
- void generate(NodeLIRBuilder generator);
-}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenResLowerable.java
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenResLowerable.java Tue Apr 29 18:23:17 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.oracle.graal.compiler.target;
-
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * An alternative to {@link LIRLowerable} for lowering that is tightly coupled to
- * {@link LIRGenerationResult} and {@link LIRInstruction}.
- */
-public interface LIRGenResLowerable {
-
- void generate(NodeLIRBuilderTool generator, LIRGenerationResult genRes);
-}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Tue Apr 29 18:35:10 2014 +0200
@@ -184,7 +184,6 @@
class NodeUsageIterator implements Iterator {
- private final int expectedModCount = usageModCount();
int index = -1;
Node current;
@@ -207,12 +206,10 @@
}
public boolean hasNext() {
- assert expectedModCount == usageModCount();
return current != null;
}
public Node next() {
- assert expectedModCount == usageModCount();
Node result = current;
if (result == null) {
throw new NoSuchElementException();
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Tue Apr 29 18:35:10 2014 +0200
@@ -48,6 +48,7 @@
import com.oracle.graal.lir.asm.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
/**
* HotSpot AMD64 specific backend.
@@ -71,7 +72,7 @@
}
@Override
- public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+ public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
return new AMD64HotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
}
@@ -81,12 +82,12 @@
}
@Override
- public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+ public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
return new AMD64HotSpotNodeLIRBuilder(graph, lirGen);
}
@Override
- public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) {
+ public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) {
return new AMD64HotSpotBytecodeLIRBuilder(gen, parser);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBytecodeLIRBuilder.java
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBytecodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBytecodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200
@@ -33,7 +33,7 @@
public class AMD64HotSpotBytecodeLIRBuilder extends BytecodeLIRBuilder {
- public AMD64HotSpotBytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) {
+ public AMD64HotSpotBytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) {
super(gen, parser);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Tue Apr 29 18:35:10 2014 +0200
@@ -26,17 +26,20 @@
import static com.oracle.graal.api.code.ValueUtil.*;
import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
import static com.oracle.graal.hotspot.nodes.UncommonTrapCallNode.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
import java.util.*;
import com.oracle.graal.amd64.*;
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
import com.oracle.graal.compiler.amd64.*;
import com.oracle.graal.compiler.common.*;
import com.oracle.graal.compiler.common.calc.*;
import com.oracle.graal.hotspot.*;
import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
+import com.oracle.graal.hotspot.data.*;
import com.oracle.graal.hotspot.meta.*;
import com.oracle.graal.hotspot.nodes.type.*;
import com.oracle.graal.hotspot.stubs.*;
@@ -44,6 +47,7 @@
import com.oracle.graal.lir.StandardOp.NoOp;
import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp;
import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp;
@@ -52,6 +56,7 @@
import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp;
import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp;
import com.oracle.graal.lir.amd64.AMD64Move.StoreOp;
+import com.oracle.graal.lir.asm.*;
import com.oracle.graal.lir.gen.*;
/**
@@ -281,7 +286,8 @@
result = super.emitForeignCall(hotspotLinkage, deoptInfo, args);
append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread));
} else {
- result = super.emitForeignCall(hotspotLinkage, deoptInfo, args);
+ assert deoptInfo == null;
+ result = super.emitForeignCall(hotspotLinkage, null, args);
}
if (destroysRegisters) {
@@ -542,6 +548,14 @@
return result;
}
+ public static Register asNarrowReg(Value value) {
+ if (value.getPlatformKind() != NarrowOopStamp.NarrowOop) {
+ throw new InternalError("needed NarrowOop got: " + value.getKind());
+ } else {
+ return asRegister(value);
+ }
+ }
+
public Value emitAtomicReadAndWrite(Value address, Value newValue) {
PlatformKind kind = newValue.getPlatformKind();
Kind memKind = getMemoryKind(kind);
@@ -551,4 +565,59 @@
return result;
}
+ public static class CompareMemoryCompressedOp extends AMD64LIRInstruction {
+ @Alive({COMPOSITE}) protected AMD64AddressValue x;
+ @Use({CONST, REG}) protected Value y;
+ @State protected LIRFrameState state;
+
+ public CompareMemoryCompressedOp(AMD64AddressValue x, Value y, LIRFrameState state) {
+ assert HotSpotGraalRuntime.runtime().getConfig().useCompressedOops;
+ this.x = x;
+ this.y = y;
+ this.state = state;
+ }
+
+ @Override
+ protected void verify() {
+ assert y instanceof Constant || y.getPlatformKind() == NarrowOopStamp.NarrowOop;
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+ if (state != null) {
+ crb.recordImplicitException(masm.position(), state);
+ }
+ if (y instanceof Constant) {
+ Constant constant = (Constant) y;
+ if (constant.isNull()) {
+ masm.cmpl(x.toAddress(), 0);
+ } else {
+ if (y.getKind() == Kind.Object) {
+ crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(constant), true));
+ } else if (y.getKind() == Kind.Long) {
+ crb.recordInlineDataInCode(new MetaspaceData(0, constant.asLong(), HotSpotMetaspaceConstant.getMetaspaceObject(constant), true));
+ } else {
+ throw GraalInternalError.shouldNotReachHere();
+ }
+ masm.cmpl(x.toAddress(), 0xdeaddead);
+ }
+ } else {
+ masm.cmpl(asNarrowReg(y), x.toAddress());
+ }
+ }
+ }
+
+ protected void emitCompareBranchMemoryCompressed(Value left, Value right, Condition cond, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability, LIRFrameState state) {
+ boolean mirrored = false;
+ if (left instanceof AMD64AddressValue) {
+ append(new CompareMemoryCompressedOp((AMD64AddressValue) left, right, state));
+ } else {
+ assert right instanceof AMD64AddressValue;
+ append(new CompareMemoryCompressedOp((AMD64AddressValue) right, left, state));
+ mirrored = true;
+ }
+
+ Condition finalCondition = mirrored ? cond.mirror() : cond;
+ append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
+ }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMemoryPeephole.java
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMemoryPeephole.java Tue Apr 29 18:23:17 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 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 com.oracle.graal.hotspot.amd64;
-
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.compiler.amd64.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.data.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.type.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
-import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * Specialized code gen for comparison with compressed memory.
- */
-
-public class AMD64HotSpotMemoryPeephole extends AMD64MemoryPeephole {
- public static class CompareMemoryCompressedOp extends AMD64LIRInstruction {
- @Alive({COMPOSITE}) protected AMD64AddressValue x;
- @Use({CONST}) protected Value y;
- @State protected LIRFrameState state;
-
- public CompareMemoryCompressedOp(AMD64AddressValue x, Constant y, LIRFrameState state) {
- assert HotSpotGraalRuntime.runtime().getConfig().useCompressedOops;
- this.x = x;
- this.y = y;
- this.state = state;
- }
-
- @Override
- public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
- Constant constant = (Constant) y;
- if (constant.isNull()) {
- masm.cmpl(x.toAddress(), 0);
- } else {
- if (y.getKind() == Kind.Object) {
- crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(constant), true));
- } else if (y.getKind() == Kind.Long) {
- crb.recordInlineDataInCode(new MetaspaceData(0, constant.asLong(), HotSpotMetaspaceConstant.getMetaspaceObject(constant), true));
- } else {
- throw GraalInternalError.shouldNotReachHere();
- }
- if (state != null) {
- crb.recordImplicitException(masm.position(), state);
- }
- masm.cmpl(x.toAddress(), 0xdeaddead);
- }
- }
- }
-
- AMD64HotSpotMemoryPeephole(AMD64NodeLIRBuilder gen) {
- super(gen);
- }
-
- @Override
- protected Kind getMemoryKind(Access access) {
- PlatformKind kind = gen.getLIRGenerator().getPlatformKind(access.asNode().stamp());
- if (kind == NarrowOopStamp.NarrowOop) {
- return Kind.Int;
- } else {
- return (Kind) kind;
- }
- }
-
- @Override
- protected boolean emitCompareBranchMemory(ValueNode left, ValueNode right, Access access, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
- double trueLabelProbability) {
- if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) {
- ValueNode other = selectOtherInput(left, right, access);
- Kind kind = getMemoryKind(access);
-
- if (other.isConstant() && kind == Kind.Object && access.isCompressible()) {
- ensureEvaluated(other);
- gen.append(new CompareMemoryCompressedOp(makeAddress(access), other.asConstant(), getState(access)));
- Condition finalCondition = right == access ? cond.mirror() : cond;
- gen.append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
- return true;
- }
- }
-
- return super.emitCompareBranchMemory(left, right, access, cond, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability);
- }
-}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200
@@ -32,7 +32,9 @@
import com.oracle.graal.asm.*;
import com.oracle.graal.asm.amd64.AMD64Address.Scale;
import com.oracle.graal.compiler.amd64.*;
+import com.oracle.graal.compiler.common.calc.*;
import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.*;
import com.oracle.graal.debug.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.hotspot.*;
@@ -45,16 +47,56 @@
import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
/**
* LIR generator specialized for AMD64 HotSpot.
*/
+@MatchableNodeImport({"com.oracle.graal.hotspot.nodes.HotSpotMatchableNodes"})
public class AMD64HotSpotNodeLIRBuilder extends AMD64NodeLIRBuilder implements HotSpotNodeLIRBuilder {
- public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator gen) {
+ private static ValueNode filterCompression(ValueNode node) {
+ ValueNode result = node;
+ while (result instanceof CompressionNode) {
+ result = ((CompressionNode) result).getInput();
+ }
+ return result;
+ }
+
+ private void emitCompareCompressedMemory(IfNode ifNode, ValueNode valueNode, Access access, CompareNode compare) {
+ Value value;
+ // This works by embedding the compressed form for constants, so force a constant instead of
+ // respecting what operand() would return.
+ if (valueNode.isConstant()) {
+ value = valueNode.asConstant();
+ } else {
+ value = gen.load(operand(valueNode));
+ }
+ AMD64AddressValue address = makeAddress(access);
+
+ Condition cond = compare.condition();
+ Value left;
+ Value right;
+ if (access == filterCompression(compare.x())) {
+ left = value;
+ right = address;
+ } else {
+ assert access == filterCompression(compare.y());
+ left = address;
+ right = value;
+ cond = cond.mirror();
+ }
+
+ LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
+ LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
+ double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
+ getGen().emitCompareBranchMemoryCompressed(left, right, cond, trueLabel, falseLabel, trueLabelProbability, getState(access));
+ }
+
+ public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
super(graph, gen);
- memoryPeephole = new AMD64HotSpotMemoryPeephole(this);
assert gen instanceof AMD64HotSpotLIRGenerator;
assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder;
((AMD64HotSpotLIRGenerator) gen).setLockStack(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack());
@@ -201,4 +243,40 @@
gen.emitMove(result, raxLocal);
setResult(x, result);
}
+
+ /**
+ * Helper class to convert the NodeLIRBuilder into the current subclass.
+ */
+ static abstract class AMD64HotSpotMatchGenerator implements MatchGenerator {
+ public AMD64HotSpotMatchGenerator() {
+ }
+
+ public ComplexMatchResult match(NodeLIRBuilder gen) {
+ return match((AMD64HotSpotNodeLIRBuilder) gen);
+ }
+
+ abstract public ComplexMatchResult match(AMD64HotSpotNodeLIRBuilder gen);
+ }
+
+ @MatchRule("(If (ObjectEquals=compare Constant=value (Compression Read=access)))")
+ @MatchRule("(If (ObjectEquals=compare Constant=value (Compression FloatingRead=access)))")
+ @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression Read=access)))")
+ @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression FloatingRead=access)))")
+ public static class IfCompareMemory extends AMD64HotSpotMatchGenerator {
+ IfNode root;
+ Access access;
+ ValueNode value;
+ CompareNode compare;
+
+ @Override
+ public ComplexMatchResult match(AMD64HotSpotNodeLIRBuilder gen) {
+ if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) {
+ return builder -> {
+ gen.emitCompareCompressedMemory(root, value, access, compare);
+ return null;
+ };
+ }
+ return null;
+ }
+ }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -27,12 +27,11 @@
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.amd64.*;
import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
-public class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRGenLowerable {
+public class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
private final Constant functionPointer;
@Input private final NodeInputList args;
@@ -44,7 +43,7 @@
}
@Override
- public void generate(NodeLIRBuilder generator) {
+ public void generate(NodeLIRBuilderTool generator) {
AMD64NodeLIRBuilder gen = (AMD64NodeLIRBuilder) generator;
Value[] parameter = new Value[args.count()];
JavaType[] parameterTypes = new JavaType[args.count()];
@@ -55,7 +54,7 @@
ResolvedJavaType returnType = stamp().javaType(gen.getLIRGeneratorTool().getMetaAccess());
CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(Type.NativeCall, returnType, parameterTypes,
generator.getLIRGeneratorTool().target(), false);
- ((AMD64LIRGenerator) gen.getLIRGeneratorTool()).emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args));
+ gen.getLIRGeneratorTool().emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args));
if (this.getKind() != Kind.Void) {
generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn()));
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Tue Apr 29 18:35:10 2014 +0200
@@ -49,7 +49,6 @@
import com.oracle.graal.compiler.common.*;
import com.oracle.graal.compiler.common.cfg.*;
import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
import com.oracle.graal.debug.*;
import com.oracle.graal.debug.Debug.Scope;
import com.oracle.graal.gpu.*;
@@ -70,6 +69,7 @@
import com.oracle.graal.nodes.calc.*;
import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.options.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.tiers.*;
@@ -302,9 +302,8 @@
for (CodeAnnotation annotation : hostCode.getAnnotations()) {
result.addAnnotation(annotation);
}
- CompilationResult.Mark[] noMarks = {};
for (Mark mark : hostCode.getMarks()) {
- result.recordMark(mark.pcOffset, mark.id, noMarks);
+ result.recordMark(mark.pcOffset, mark.id);
}
for (ExceptionHandler handler : hostCode.getExceptionHandlers()) {
result.recordExceptionHandler(handler.pcOffset, handler.handlerPos);
@@ -376,7 +375,7 @@
}
@Override
- public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+ public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
return new HSAILHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
}
@@ -386,7 +385,7 @@
}
@Override
- public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+ public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
return new HSAILHotSpotNodeLIRBuilder(graph, lirGen);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java Tue Apr 29 18:35:10 2014 +0200
@@ -151,6 +151,7 @@
return nodeResult;
}
+ @Override
public Value emitAtomicReadAndAdd(Value address, Value delta) {
PlatformKind kind = delta.getPlatformKind();
Kind memKind = getMemoryKind(kind);
@@ -161,6 +162,16 @@
}
@Override
+ public Value emitAtomicReadAndWrite(Value address, Value newValue) {
+ PlatformKind kind = newValue.getPlatformKind();
+ Kind memKind = getMemoryKind(kind);
+ Variable result = newVariable(kind);
+ HSAILAddressValue addressValue = asAddressValue(address);
+ append(new HSAILMove.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue)));
+ return result;
+ }
+
+ @Override
public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state) {
emitDeoptimizeInner(actionAndReason, state, "emitDeoptimize");
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRBuilder.java
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200
@@ -44,7 +44,7 @@
*/
public class HSAILHotSpotNodeLIRBuilder extends HSAILNodeLIRBuilder implements HotSpotNodeLIRBuilder {
- public HSAILHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+ public HSAILHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
super(graph, lirGen);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java Tue Apr 29 18:35:10 2014 +0200
@@ -38,7 +38,6 @@
import com.oracle.graal.asm.ptx.*;
import com.oracle.graal.compiler.common.*;
import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.gen.*;
import com.oracle.graal.debug.*;
import com.oracle.graal.debug.Debug.Scope;
import com.oracle.graal.gpu.*;
@@ -55,6 +54,7 @@
import com.oracle.graal.lir.ptx.PTXControlFlow.PTXPredicatedLIRInstruction;
import com.oracle.graal.lir.ptx.PTXMemOp.LoadReturnAddrOp;
import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
import com.oracle.graal.phases.tiers.*;
@@ -356,12 +356,12 @@
}
@Override
- public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+ public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
return new PTXHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
}
@Override
- public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+ public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
return new PTXHotSpotNodeLIRBuilder(graph, lirGen);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotNodeLIRBuilder.java
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotNodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotNodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200
@@ -35,7 +35,7 @@
*/
public class PTXHotSpotNodeLIRBuilder extends PTXNodeLIRBuilder implements HotSpotNodeLIRBuilder {
- protected PTXHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+ protected PTXHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
super(graph, lirGen);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizationStub.java
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizationStub.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizationStub.java Tue Apr 29 18:35:10 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 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
@@ -35,11 +35,14 @@
public SPARCDeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
super(providers, target, linkage);
- registerConfig = new SPARCHotSpotRegisterConfig(target, new Register[]{o0, o1, o2, o3, o4, o5, o7, l0, l1, l2, l3, l4, l5, l6, l7, i0, i1, i2, i3, i4, i5, f0, f1, f2, f3, f4, f5, f6, f7});
+ // This is basically the maximum we can spare. All other G and O register are used.
+ Register[] allocatable = new Register[]{g1, g3, g4, g5, o0, o1, o2, o3, o4};
+ registerConfig = new SPARCHotSpotRegisterConfig(target, allocatable);
}
@Override
public RegisterConfig getRegisterConfig() {
return registerConfig;
}
+
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Tue Apr 29 18:35:10 2014 +0200
@@ -44,7 +44,6 @@
import com.oracle.graal.asm.sparc.SPARCMacroAssembler.RestoreWindow;
import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.gen.*;
import com.oracle.graal.hotspot.*;
import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
import com.oracle.graal.hotspot.meta.*;
@@ -55,6 +54,7 @@
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.lir.sparc.*;
import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
/**
* HotSpot SPARC specific backend.
@@ -78,12 +78,17 @@
}
@Override
- public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+ public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
return new SPARCHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
}
@Override
- public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+ public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
+ return new SPARCHotSpotLIRGenerationResult(lir, frameMap, stub);
+ }
+
+ @Override
+ public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
return new SPARCHotSpotNodeLIRBuilder(graph, lirGen);
}
@@ -190,11 +195,6 @@
}
@Override
- public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
- return new LIRGenerationResultBase(lir, frameMap);
- }
-
- @Override
public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) {
SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
FrameMap frameMap = crb.frameMap;
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java Tue Apr 29 18:35:10 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -48,9 +48,8 @@
@Override
public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-
// Save last Java frame.
- new Add(stackPointer, new SPARCAddress(stackPointer, 0).getDisplacement(), g4).emit(masm);
+ new Add(stackPointer, STACK_BIAS, g4).emit(masm);
new Stx(g4, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm);
// Save the thread register when calling out to the runtime.
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.sparc.SPARC.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Emits code that enters a stack frame which is tailored to call the C++ method
+ * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME")
+final class SPARCHotSpotEnterUnpackFramesStackFrameOp extends SPARCLIRInstruction {
+
+ private final Register thread;
+ private final int threadLastJavaSpOffset;
+ private final int threadLastJavaPcOffset;
+ @Alive(REG) AllocatableValue framePc;
+ @Alive(REG) AllocatableValue senderSp;
+ @Temp(REG) AllocatableValue scratch;
+
+ SPARCHotSpotEnterUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue scratch) {
+ this.thread = thread;
+ this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+ this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+ this.framePc = framePc;
+ this.senderSp = senderSp;
+ this.scratch = scratch;
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+ final int totalFrameSize = crb.frameMap.totalFrameSize();
+ Register framePcRegister = asRegister(framePc);
+ Register senderSpRegister = asRegister(senderSp);
+ Register scratchRegister = asRegister(scratch);
+
+ // Save final sender SP to O5_savedSP.
+ new Mov(senderSpRegister, o5).emit(masm);
+
+ // Load final frame PC.
+ new Mov(framePcRegister, o7).emit(masm);
+
+ // Allocate a full sized frame.
+ new Save(sp, -totalFrameSize, sp).emit(masm);
+
+ new Mov(i0, o0).emit(masm);
+ new Mov(i1, o1).emit(masm);
+ new Mov(i2, o2).emit(masm);
+ new Mov(i3, o3).emit(masm);
+ new Mov(i4, o4).emit(masm);
+
+ // Set up last Java values.
+ new Add(sp, STACK_BIAS, scratchRegister).emit(masm);
+ new Stx(scratchRegister, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm);
+
+ // Clear last Java PC.
+ new Stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset)).emit(masm);
+
+ /*
+ * Safe thread register manually since we are not using LEAF_SP for {@link
+ * DeoptimizationStub#UNPACK_FRAMES}.
+ */
+ new Mov(thread, l7).emit(masm);
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java Tue Apr 29 18:35:10 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 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
@@ -22,14 +22,49 @@
*/
package com.oracle.graal.hotspot.sparc;
+import java.util.*;
+
import com.oracle.graal.api.code.*;
import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.*;
import com.oracle.graal.lir.gen.*;
-public interface SPARCHotSpotLIRGenerationResult extends LIRGenerationResult {
+public class SPARCHotSpotLIRGenerationResult extends LIRGenerationResultBase {
+
+ /**
+ * The slot reserved for storing the original return address when a frame is marked for
+ * deoptimization. The return address slot in the callee is overwritten with the address of a
+ * deoptimization stub.
+ */
+ private StackSlot deoptimizationRescueSlot;
+ private final Object stub;
+
+ /**
+ * Map from debug infos that need to be updated with callee save information to the operations
+ * that provide the information.
+ */
+ private Map calleeSaveInfo = new HashMap<>();
- StackSlot getDeoptimizationRescueSlot();
+ public SPARCHotSpotLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
+ super(lir, frameMap);
+ this.stub = stub;
+ }
+
+ StackSlot getDeoptimizationRescueSlot() {
+ return deoptimizationRescueSlot;
+ }
- Stub getStub();
+ public final void setDeoptimizationRescueSlot(StackSlot deoptimizationRescueSlot) {
+ this.deoptimizationRescueSlot = deoptimizationRescueSlot;
+ }
+
+ Stub getStub() {
+ return (Stub) stub;
+ }
+
+ Map getCalleeSaveInfo() {
+ return calleeSaveInfo;
+ }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Tue Apr 29 18:35:10 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -24,6 +24,8 @@
import static com.oracle.graal.api.code.ValueUtil.*;
import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.nodes.UncommonTrapCallNode.*;
+import static com.oracle.graal.sparc.SPARC.*;
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
@@ -264,38 +266,78 @@
throw GraalInternalError.unimplemented();
}
+ /**
+ * @param savedRegisters the registers saved by this operation which may be subject to pruning
+ * @param savedRegisterLocations the slots to which the registers are saved
+ * @param supportsRemove determines if registers can be pruned
+ */
+ protected SPARCSaveRegistersOp emitSaveRegisters(Register[] savedRegisters, StackSlot[] savedRegisterLocations, boolean supportsRemove) {
+ SPARCSaveRegistersOp save = new SPARCSaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
+ append(save);
+ return save;
+ }
+
public SaveRegistersOp emitSaveAllRegisters() {
- // TODO Auto-generated method stub
- throw GraalInternalError.unimplemented();
+ // We save all registers that were not saved by the save instruction.
+ // @formatter:off
+ Register[] savedRegisters = {
+ // CPU
+ g1, g3, g4, g5,
+ // FPU
+ f0, f1, f2, f3, f4, f5, f6, f7,
+ f8, f9, f10, f11, f12, f13, f14, f15,
+ f16, f17, f18, f19, f20, f21, f22, f23,
+ f24, f25, f26, f27, f28, f29, f30, f31
+ };
+ // @formatter:on
+ StackSlot[] savedRegisterLocations = new StackSlot[savedRegisters.length];
+ for (int i = 0; i < savedRegisters.length; i++) {
+ PlatformKind kind = target().arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory());
+ assert kind != Kind.Illegal;
+ StackSlot spillSlot = getResult().getFrameMap().allocateSpillSlot(kind);
+ savedRegisterLocations[i] = spillSlot;
+ }
+ return emitSaveRegisters(savedRegisters, savedRegisterLocations, false);
}
public void emitLeaveCurrentStackFrame() {
- // TODO Auto-generated method stub
- throw GraalInternalError.unimplemented();
+ append(new SPARCHotSpotLeaveCurrentStackFrameOp());
}
public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
- // TODO Auto-generated method stub
- throw GraalInternalError.unimplemented();
+ append(new SPARCHotSpotLeaveDeoptimizedStackFrameOp());
}
public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
- // TODO Auto-generated method stub
- throw GraalInternalError.unimplemented();
+ Register thread = getProviders().getRegisters().getThreadRegister();
+ Variable framePcVariable = load(framePc);
+ Variable senderSpVariable = load(senderSp);
+ Variable scratchVariable = newVariable(getHostWordKind());
+ append(new SPARCHotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), framePcVariable, senderSpVariable, scratchVariable));
}
public void emitLeaveUnpackFramesStackFrame() {
- // TODO Auto-generated method stub
- throw GraalInternalError.unimplemented();
+ Register thread = getProviders().getRegisters().getThreadRegister();
+ append(new SPARCHotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset()));
}
public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
- // TODO Auto-generated method stub
- throw GraalInternalError.unimplemented();
+ Variable frameSizeVariable = load(frameSize);
+ Variable framePcVariable = load(framePc);
+ Variable senderSpVariable = load(senderSp);
+ Variable initialInfoVariable = load(initialInfo);
+ append(new SPARCHotSpotPushInterpreterFrameOp(frameSizeVariable, framePcVariable, senderSpVariable, initialInfoVariable));
}
public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
- // TODO Auto-generated method stub
- throw GraalInternalError.unimplemented();
+ ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(UNCOMMON_TRAP);
+
+ Register threadRegister = getProviders().getRegisters().getThreadRegister();
+ Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister();
+ append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister));
+ Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(Kind.Long), trapRequest);
+ append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister));
+
+ return result;
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.sparc.SPARC.*;
+
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Pops the current frame off the stack.
+ */
+@Opcode("LEAVE_CURRENT_STACK_FRAME")
+final class SPARCHotSpotLeaveCurrentStackFrameOp extends SPARCHotSpotEpilogueOp {
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+ // Save O registers over restore.
+ new Mov(o0, i0).emit(masm);
+ new Mov(o1, i1).emit(masm);
+ new Mov(o2, i2).emit(masm);
+ new Mov(o3, i3).emit(masm);
+ new Mov(o4, i4).emit(masm);
+
+ leaveFrame(crb);
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.sparc.SPARC.*;
+
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Pops the current frame off the stack including the return address.
+ */
+@Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME")
+final class SPARCHotSpotLeaveDeoptimizedStackFrameOp extends SPARCHotSpotEpilogueOp {
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+ // Save O registers over restore.
+ new Mov(o0, i0).emit(masm);
+ new Mov(o1, i1).emit(masm);
+ new Mov(o2, i2).emit(masm);
+ new Mov(o3, i3).emit(masm);
+ new Mov(o4, i4).emit(masm);
+
+ new RestoreWindow().emit(masm);
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.sparc.SPARC.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Emits code that leaves a stack frame which is tailored to call the C++ method
+ * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME")
+final class SPARCHotSpotLeaveUnpackFramesStackFrameOp extends SPARCLIRInstruction {
+
+ private final Register thread;
+ private final int threadLastJavaSpOffset;
+ private final int threadLastJavaPcOffset;
+ private final int threadJavaFrameAnchorFlagsOffset;
+
+ SPARCHotSpotLeaveUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadJavaFrameAnchorFlagsOffset) {
+ this.thread = thread;
+ this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+ this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+ this.threadJavaFrameAnchorFlagsOffset = threadJavaFrameAnchorFlagsOffset;
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+ /*
+ * Safe thread register manually since we are not using LEAF_SP for {@link
+ * DeoptimizationStub#UNPACK_FRAMES}.
+ */
+ new Mov(l7, thread).emit(masm);
+
+ // Clear last Java frame values.
+ new Stx(g0, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm);
+ new Stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset)).emit(masm);
+ new Stw(g0, new SPARCAddress(thread, threadJavaFrameAnchorFlagsOffset)).emit(masm);
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200
@@ -43,7 +43,7 @@
public class SPARCHotSpotNodeLIRBuilder extends SPARCNodeLIRBuilder implements HotSpotNodeLIRBuilder {
- public SPARCHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+ public SPARCHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
super(graph, lirGen);
assert gen instanceof SPARCHotSpotLIRGenerator;
assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder;
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013, 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 com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.sparc.SPARC.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Pushes an interpreter frame to the stack.
+ */
+@Opcode("PUSH_INTERPRETER_FRAME")
+final class SPARCHotSpotPushInterpreterFrameOp extends SPARCLIRInstruction {
+
+ @Alive(REG) AllocatableValue frameSize;
+ @Alive(REG) AllocatableValue framePc;
+ @Alive(REG) AllocatableValue senderSp;
+ @Alive(REG) AllocatableValue initialInfo;
+
+ SPARCHotSpotPushInterpreterFrameOp(AllocatableValue frameSize, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue initialInfo) {
+ this.frameSize = frameSize;
+ this.framePc = framePc;
+ this.senderSp = senderSp;
+ this.initialInfo = initialInfo;
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+ final Register frameSizeRegister = asRegister(frameSize);
+ final Register framePcRegister = asRegister(framePc);
+ final Register senderSpRegister = asRegister(senderSp);
+
+ // Save sender SP to O5_savedSP.
+ new Mov(senderSpRegister, o5).emit(masm);
+
+ new Neg(frameSizeRegister).emit(masm);
+ new Save(sp, frameSizeRegister, sp).emit(masm);
+
+ new Mov(i0, o0).emit(masm);
+ new Mov(i1, o1).emit(masm);
+ new Mov(i2, o2).emit(masm);
+ new Mov(i3, o3).emit(masm);
+ new Mov(i4, o4).emit(masm);
+
+ // NOTE: Don't touch I5 as it contains valuable saved SP!
+
+ // Move frame's new PC into i7
+ new Mov(framePcRegister, i7).emit(masm);
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java Tue Apr 29 18:35:10 2014 +0200
@@ -98,25 +98,27 @@
private static Register[] initAllocatable(boolean reserveForHeapBase) {
Register[] registers = null;
- // @formatter:off
if (reserveForHeapBase) {
- registers = new Register[] {
+ // @formatter:off
+ registers = new Register[]{
// TODO this is not complete
o0, o1, o2, o3, o4, o5, /*o6,*/ o7,
l0, l1, l2, l3, l4, l5, l6, l7,
i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/
f0, f1, f2, f3, f4, f5, f6, f7
- };
+ };
+ // @formatter:on
} else {
- registers = new Register[] {
+ // @formatter:off
+ registers = new Register[]{
// TODO this is not complete
o0, o1, o2, o3, o4, o5, /*o6,*/ o7,
l0, l1, l2, l3, l4, l5, l6, l7,
i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/
f0, f1, f2, f3, f4, f5, f6, f7
- };
+ };
+ // @formatter:on
}
- // @formatter:on
if (RegisterPressure.getValue() != null) {
String[] names = RegisterPressure.getValue().split(",");
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java Tue Apr 29 18:35:10 2014 +0200
@@ -36,6 +36,8 @@
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.lir.sparc.*;
+import edu.umd.cs.findbugs.annotations.*;
+
/**
* Emits a safepoint poll.
*/
@@ -43,7 +45,7 @@
public class SPARCHotSpotSafepointOp extends SPARCLIRInstruction {
@State protected LIRFrameState state;
- @Temp({OperandFlag.REG}) private AllocatableValue temp;
+ @SuppressFBWarnings(value = "BC_IMPOSSIBLE_CAST", justification = "changed by the register allocator") @Temp({OperandFlag.REG}) private AllocatableValue temp;
private final HotSpotVMConfig config;
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Tue Apr 29 18:35:10 2014 +0200
@@ -63,7 +63,7 @@
try (Scope s = Debug.scope("RegisterReplacements", new DebugDumpScope("RegisterReplacements"))) {
ServiceLoader sl = ServiceLoader.loadInstalled(ReplacementsProvider.class);
for (ReplacementsProvider replacementsProvider : sl) {
- replacementsProvider.registerReplacements(providers.getMetaAccess(), lowerer, replacements, providers.getCodeCache().getTarget());
+ replacementsProvider.registerReplacements(providers.getMetaAccess(), lowerer, providers.getSnippetReflection(), replacements, providers.getCodeCache().getTarget());
}
if (BootstrapReplacements.getValue()) {
for (ResolvedJavaMethod method : replacements.getAllReplacements()) {
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Tue Apr 29 18:35:10 2014 +0200
@@ -794,6 +794,7 @@
// offsets, ...
@HotSpotVMFlag(name = "StackShadowPages") @Stable public int stackShadowPages;
@HotSpotVMFlag(name = "UseStackBanging") @Stable public boolean useStackBanging;
+ @HotSpotVMConstant(name = "STACK_BIAS") @Stable public int stackBias;
@HotSpotVMField(name = "oopDesc::_mark", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int markOffset;
@HotSpotVMField(name = "oopDesc::_metadata._klass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int hubOffset;
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Tue Apr 29 18:35:10 2014 +0200
@@ -99,7 +99,6 @@
private static final boolean DUMP_STATIC = false;
- public static String excludedClassPrefix = null;
public static boolean enabled = false;
public static final ConcurrentHashMap indexes = new ConcurrentHashMap<>();
@@ -108,14 +107,23 @@
public static final ArrayList staticCounters = new ArrayList<>();
@SuppressFBWarnings(value = "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION", justification = "concurrent abstraction calls are in synchronized block")
- public static int getIndex(DynamicCounterNode counter) {
+ private static int getIndex(DynamicCounterNode counter) {
if (!enabled) {
throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled: " + counter.getGroup() + ", " + counter.getName());
}
- String name = counter.getName();
+ String name;
String group = counter.getGroup();
- name = counter.isWithContext() && counter.graph().method() != null ? name + " @ " + counter.graph().graphId() + ":" + MetaUtil.format("%h.%n", counter.graph().method()) + "#" + group : name +
- "#" + group;
+ if (counter.isWithContext()) {
+ StructuredGraph graph = counter.graph();
+ name = counter.getName() + " @ " + graph.graphId() + ":" + (graph.method() == null ? "" : MetaUtil.format("%h.%n", graph.method()));
+ if (graph.name != null) {
+ name += " (" + graph.name + ")";
+ }
+ name += "#" + group;
+
+ } else {
+ name = counter.getName() + "#" + group;
+ }
Integer index = indexes.get(name);
if (index == null) {
synchronized (BenchmarkCounters.class) {
@@ -135,7 +143,7 @@
return index;
}
- public static synchronized void dump(PrintStream out, double seconds, long[] counters, int maxRows) {
+ private static synchronized void dump(PrintStream out, double seconds, long[] counters, int maxRows) {
if (!groups.isEmpty()) {
out.println("====== dynamic counters (" + staticCounters.size() + " in total) ======");
for (String group : new TreeSet<>(groups)) {
@@ -152,7 +160,7 @@
}
}
- public static synchronized void clear(long[] counters) {
+ private static synchronized void clear(long[] counters) {
delta = counters;
}
@@ -228,7 +236,7 @@
return (counter * 200 + 1) / sum / 2;
}
- public abstract static class CallbackOutputStream extends OutputStream {
+ private abstract static class CallbackOutputStream extends OutputStream {
protected final PrintStream delegate;
private final byte[][] patterns;
@@ -281,25 +289,30 @@
final class BenchmarkCountersOutputStream extends CallbackOutputStream {
private long startTime;
+ private boolean running;
private boolean waitingForEnd;
private BenchmarkCountersOutputStream(PrintStream delegate, String start, String end) {
- super(delegate, new String[]{start, end, "\n"});
+ super(delegate, new String[]{"\n", end, start});
}
@Override
protected void patternFound(int index) {
switch (index) {
- case 0:
+ case 2:
startTime = System.nanoTime();
BenchmarkCounters.clear(compilerToVM.collectCounters());
+ running = true;
break;
case 1:
- waitingForEnd = true;
+ if (running) {
+ waitingForEnd = true;
+ }
break;
- case 2:
+ case 0:
if (waitingForEnd) {
waitingForEnd = false;
+ running = false;
BenchmarkCounters.dump(delegate, (System.nanoTime() - startTime) / 1000000000d, compilerToVM.collectCounters(), 100);
}
break;
@@ -321,7 +334,6 @@
throw new GraalInternalError("invalid arguments to BenchmarkDynamicCounters: err|out");
}
}
- excludedClassPrefix = "Lcom/oracle/graal/";
enabled = true;
}
if (Options.GenericDynamicCounters.getValue()) {
@@ -363,26 +375,24 @@
public static void lower(DynamicCounterNode counter, HotSpotRegistersProvider registers, HotSpotVMConfig config, Kind wordKind) {
StructuredGraph graph = counter.graph();
- if (excludedClassPrefix == null || (counter.graph().method() != null && !counter.graph().method().getDeclaringClass().getName().startsWith(excludedClassPrefix))) {
- ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), wordKind, true, false));
+ ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), wordKind, true, false));
- int index = BenchmarkCounters.getIndex(counter);
- if (index >= config.graalCountersSize) {
- throw new GraalInternalError("too many counters, reduce number of counters or increase -XX:GraalCounterSize=... (current value: " + config.graalCountersSize + ")");
- }
- ConstantLocationNode arrayLocation = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, config.graalCountersThreadOffset, graph);
- ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE, false));
- ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph);
- ReadNode read = graph.add(new ReadNode(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false));
- IntegerAddNode add = graph.unique(new IntegerAddNode(StampFactory.forKind(Kind.Long), read, counter.getIncrement()));
- WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE, false));
+ int index = BenchmarkCounters.getIndex(counter);
+ if (index >= config.graalCountersSize) {
+ throw new GraalInternalError("too many counters, reduce number of counters or increase -XX:GraalCounterSize=... (current value: " + config.graalCountersSize + ")");
+ }
+ ConstantLocationNode arrayLocation = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, wordKind, config.graalCountersThreadOffset, graph);
+ ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE, false));
+ ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph);
+ ReadNode read = graph.add(new ReadNode(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false));
+ IntegerAddNode add = graph.unique(new IntegerAddNode(StampFactory.forKind(Kind.Long), read, counter.getIncrement()));
+ WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE, false));
- graph.addBeforeFixed(counter, thread);
- graph.addBeforeFixed(counter, readArray);
- graph.addBeforeFixed(counter, read);
- graph.addBeforeFixed(counter, write);
- }
+ graph.addBeforeFixed(counter, thread);
+ graph.addBeforeFixed(counter, readArray);
+ graph.addBeforeFixed(counter, read);
+ graph.addBeforeFixed(counter, write);
graph.removeFixed(counter);
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Tue Apr 29 18:35:10 2014 +0200
@@ -192,8 +192,10 @@
if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
newObjectSnippets.lower((NewMultiArrayNode) n, tool);
}
- } else if (n instanceof LoadExceptionObjectNode) {
- exceptionObjectSnippets.lower((LoadExceptionObjectNode) n, registers, tool);
+ } else if (n instanceof ExceptionObjectNode) {
+ if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+ lowerExceptionObjectNode((ExceptionObjectNode) n, tool);
+ }
} else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) {
// Nothing to do for division nodes. The HotSpot signal handler catches divisions by
// zero and the MIN_VALUE / -1 cases.
@@ -732,6 +734,19 @@
}
}
+ private void lowerExceptionObjectNode(ExceptionObjectNode n, LoweringTool tool) {
+ LocationIdentity locationsKilledByInvoke = ((InvokeWithExceptionNode) n.predecessor()).getLocationIdentity();
+ BeginNode entry = n.graph().add(new KillingBeginNode(locationsKilledByInvoke));
+ LoadExceptionObjectNode loadException = n.graph().add(new LoadExceptionObjectNode(StampFactory.declaredNonNull(metaAccess.lookupJavaType(Throwable.class))));
+
+ loadException.setStateAfter(n.stateAfter());
+ n.replaceAtUsages(InputType.Value, loadException);
+ n.graph().replaceFixedWithFixed(n, entry);
+ entry.graph().addAfterFixed(entry, loadException);
+
+ exceptionObjectSnippets.lower(loadException, registers, tool);
+ }
+
public static void finishAllocatedObjects(LoweringTool tool, CommitAllocationNode commit, ValueNode[] allocations) {
StructuredGraph graph = commit.graph();
for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java Tue Apr 29 18:35:10 2014 +0200
@@ -286,4 +286,8 @@
public String disassemble(ResolvedJavaMethod method) {
return new BytecodeDisassembler().disassemble(method);
}
+
+ public SpeculationLog createSpeculationLog() {
+ return new HotSpotSpeculationLog();
+ }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Tue Apr 29 18:35:10 2014 +0200
@@ -119,7 +119,14 @@
registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
registerForeignCall(UNCOMMON_TRAP, c.deoptimizationUncommonTrap, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+
+ /*
+ * We cannot use LEAF_SP here because on some architectures we have to align the stack
+ * manually before calling into the VM. See {@link
+ * AMD64HotSpotEnterUnpackFramesStackFrameOp#emitCode}.
+ */
registerForeignCall(UNPACK_FRAMES, c.deoptimizationUnpackFrames, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+
registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS);
link(new NewInstanceStub(providers, target, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -27,9 +27,7 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.target.*;
import com.oracle.graal.hotspot.*;
-import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.spi.*;
@@ -37,7 +35,7 @@
* Reserves a block of memory in the stack frame of a method. The block is reserved in the frame for
* the entire execution of the associated method.
*/
-public final class AllocaNode extends FixedWithNextNode implements LIRGenResLowerable {
+public final class AllocaNode extends FixedWithNextNode implements LIRLowerable {
/**
* The number of slots in block.
@@ -58,8 +56,8 @@
}
@Override
- public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
- StackSlot array = res.getFrameMap().allocateStackSlots(slots, objects, null);
+ public void generate(NodeLIRBuilderTool gen) {
+ StackSlot array = gen.getLIRGeneratorTool().getResult().getFrameMap().allocateStackSlots(slots, objects, null);
Value result = gen.getLIRGeneratorTool().emitAddress(array);
gen.setResult(this, result);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -24,12 +24,11 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.hotspot.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.word.*;
/**
@@ -39,7 +38,7 @@
* check on the object.
*/
@NodeInfo(allowedUsageTypes = {InputType.Memory})
-public final class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRGenLowerable, MonitorEnter, MemoryCheckpoint.Single {
+public final class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRLowerable, MonitorEnter, MemoryCheckpoint.Single {
private int lockDepth;
@@ -59,7 +58,7 @@
}
@Override
- public void generate(NodeLIRBuilder gen) {
+ public void generate(NodeLIRBuilderTool gen) {
assert lockDepth != -1;
HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
StackSlot slot = hsGen.getLockSlot(lockDepth);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -23,8 +23,6 @@
package com.oracle.graal.hotspot.nodes;
import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
import com.oracle.graal.nodes.calc.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.word.*;
@@ -32,7 +30,7 @@
/**
* Converts a compile-time constant Java string into a C string installed with the generated code.
*/
-public final class CStringNode extends FloatingNode implements LIRGenLowerable {
+public final class CStringNode extends FloatingNode implements LIRLowerable {
private final String string;
@@ -41,7 +39,7 @@
this.string = string;
}
- public void generate(NodeLIRBuilder gen) {
+ public void generate(NodeLIRBuilderTool gen) {
gen.setResult(this, emitCString(gen, string));
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -93,6 +93,10 @@
throw GraalInternalError.shouldNotReachHere();
}
+ public ValueNode getInput() {
+ return input;
+ }
+
@Override
public Node canonical(CanonicalizerTool tool) {
if (input instanceof CompressionNode) {
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -28,7 +28,6 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.target.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.spi.*;
@@ -38,7 +37,7 @@
* Intrinsic for allocating an on-stack array of integers to hold the dimensions of a multianewarray
* instruction.
*/
-public final class DimensionsNode extends FixedWithNextNode implements LIRGenResLowerable {
+public final class DimensionsNode extends FixedWithNextNode implements LIRLowerable {
private final int rank;
@@ -48,12 +47,13 @@
}
@Override
- public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
+ public void generate(NodeLIRBuilderTool gen) {
+ LIRGeneratorTool lirGen = gen.getLIRGeneratorTool();
int size = rank * 4;
- int wordSize = gen.getLIRGeneratorTool().target().wordSize;
+ int wordSize = lirGen.target().wordSize;
int slots = roundUp(size, wordSize) / wordSize;
- StackSlot array = res.getFrameMap().allocateStackSlots(slots, new BitSet(0), null);
- Value result = gen.getLIRGeneratorTool().emitAddress(array);
+ StackSlot array = lirGen.getResult().getFrameMap().allocateStackSlots(slots, new BitSet(0), null);
+ Value result = lirGen.emitAddress(array);
gen.setResult(this, result);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -23,13 +23,12 @@
package com.oracle.graal.hotspot.nodes;
import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.hotspot.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.word.*;
/**
@@ -39,7 +38,7 @@
* expected value or the compared against value instead of a boolean.
*/
@NodeInfo(allowedUsageTypes = {InputType.Memory})
-public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRGenLowerable, MemoryCheckpoint.Single {
+public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
@Input private ValueNode object;
@Input private ValueNode offset;
@@ -79,7 +78,7 @@
}
@Override
- public void generate(NodeLIRBuilder gen) {
+ public void generate(NodeLIRBuilderTool gen) {
((HotSpotNodeLIRBuilder) gen).visitDirectCompareAndSwap(this);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.hotspot.nodes;
+
+import com.oracle.graal.compiler.match.*;
+import com.oracle.graal.nodes.*;
+
+@MatchableNode(shortName = "Compression", value = CompressionNode.class, inputs = 1, adapter = HotSpotMatchableNodes.CompressionNodeAdapter.class)
+public class HotSpotMatchableNodes {
+ public static class CompressionNodeAdapter extends MatchNodeAdapter {
+ @Override
+ protected ValueNode getFirstInput(ValueNode node) {
+ return ((CompressionNode) node).getInput();
+ }
+ }
+
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LoadExceptionObjectNode.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LoadExceptionObjectNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2009, 2011, 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 com.oracle.graal.hotspot.nodes;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+public class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable {
+
+ public LoadExceptionObjectNode(Stamp stamp) {
+ super(stamp);
+ }
+
+ @Override
+ public void lower(LoweringTool tool) {
+ tool.getLowerer().lower(this, tool);
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -26,8 +26,6 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.calc.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.word.*;
@@ -35,16 +33,16 @@
/**
* Node that is used to maintain a stack based counter of how many locks are currently held.
*/
-public final class MonitorCounterNode extends FloatingNode implements LIRGenResLowerable {
+public final class MonitorCounterNode extends FloatingNode implements LIRLowerable {
private MonitorCounterNode() {
super(null);
}
@Override
- public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
+ public void generate(NodeLIRBuilderTool gen) {
assert graph().getNodes().filter(MonitorCounterNode.class).count() == 1 : "monitor counters not canonicalized to single instance";
- StackSlot counter = res.getFrameMap().allocateStackSlots(1, new BitSet(0), null);
+ StackSlot counter = gen.getLIRGeneratorTool().getResult().getFrameMap().allocateStackSlots(1, new BitSet(0), null);
Value result = gen.getLIRGeneratorTool().emitAddress(counter);
gen.setResult(this, result);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java Tue Apr 29 18:35:10 2014 +0200
@@ -25,18 +25,17 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
import com.oracle.graal.hotspot.meta.*;
import com.oracle.graal.hotspot.stubs.*;
import com.oracle.graal.lir.*;
import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.word.*;
/**
* A call to the {@link NewArrayStub}.
*/
-public class NewArrayStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
+public class NewArrayStubCall extends DeoptimizingStubCall implements LIRLowerable {
private static final Stamp defaultStamp = StampFactory.objectNonNull();
@@ -61,9 +60,9 @@
}
@Override
- public void generate(NodeLIRBuilder gen) {
+ public void generate(NodeLIRBuilderTool gen) {
ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(NEW_ARRAY);
- Variable result = gen.getLIRGenerator().emitForeignCall(linkage, gen.state(this), gen.operand(hub), gen.operand(length));
+ Variable result = gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(hub), gen.operand(length));
gen.setResult(this, result);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -24,13 +24,12 @@
package com.oracle.graal.hotspot.nodes;
import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
import com.oracle.graal.hotspot.*;
import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.word.*;
-public class PrefetchAllocateNode extends FixedWithNextNode implements LIRGenLowerable {
+public class PrefetchAllocateNode extends FixedWithNextNode implements LIRLowerable {
@Input private ValueNode distance;
@Input private ValueNode address;
@@ -42,7 +41,7 @@
}
@Override
- public void generate(NodeLIRBuilder gen) {
+ public void generate(NodeLIRBuilderTool gen) {
((HotSpotNodeLIRBuilder) gen).emitPrefetchAllocate(address, distance);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -29,7 +29,6 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.target.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.hotspot.*;
import com.oracle.graal.java.*;
@@ -41,7 +40,7 @@
* Performs a tail call to the specified target compiled method, with the parameter taken from the
* supplied FrameState.
*/
-public class TailcallNode extends FixedWithNextNode implements LIRGenResLowerable {
+public class TailcallNode extends FixedWithNextNode implements LIRLowerable {
@Input(InputType.State) private FrameState frameState;
@Input private ValueNode target;
@@ -58,20 +57,21 @@
this.frameState = frameState;
}
- public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
+ public void generate(NodeLIRBuilderTool gen) {
HotSpotVMConfig config = runtime().getConfig();
+ LIRGeneratorTool lirGen = gen.getLIRGeneratorTool();
ResolvedJavaMethod method = frameState.method();
boolean isStatic = method.isStatic();
JavaType[] signature = MetaUtil.signatureToTypes(method.getSignature(), isStatic ? null : method.getDeclaringClass());
- CallingConvention cc = res.getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, signature, gen.getLIRGeneratorTool().target(), false);
+ CallingConvention cc = lirGen.getResult().getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, signature, lirGen.target(), false);
List parameters = new ArrayList<>();
for (int i = 0, slot = 0; i < cc.getArgumentCount(); i++, slot += HIRFrameStateBuilder.stackSlots(frameState.localAt(slot).getKind())) {
parameters.add(frameState.localAt(slot));
}
Value[] args = gen.visitInvokeArguments(cc, parameters);
- Value address = gen.getLIRGeneratorTool().emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0);
- Value entry = gen.getLIRGeneratorTool().emitLoad(Kind.Long, address, null);
+ Value address = lirGen.emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0);
+ Value entry = lirGen.emitLoad(Kind.Long, address, null);
HotSpotLIRGenerator hsgen = (HotSpotLIRGenerator) gen;
hsgen.emitTailcall(args, entry);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java Tue Apr 29 18:35:10 2014 +0200
@@ -34,7 +34,7 @@
public class CallSiteSubstitutions implements ReplacementsProvider {
@Override
- public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, Replacements replacements, TargetDescription target) {
+ public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
replacements.registerSubstitutions(ConstantCallSiteSubstitutions.class);
replacements.registerSubstitutions(MutableCallSiteSubstitutions.class);
replacements.registerSubstitutions(VolatileCallSiteSubstitutions.class);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Tue Apr 29 18:35:10 2014 +0200
@@ -24,6 +24,7 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
import com.oracle.graal.api.runtime.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.replacements.*;
@@ -32,7 +33,7 @@
public class HotSpotSubstitutions implements ReplacementsProvider {
@Override
- public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, Replacements replacements, TargetDescription target) {
+ public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
replacements.registerSubstitutions(ObjectSubstitutions.class);
replacements.registerSubstitutions(SystemSubstitutions.class);
replacements.registerSubstitutions(ThreadSubstitutions.class);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java Tue Apr 29 18:35:10 2014 +0200
@@ -30,9 +30,9 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.compiler.common.type.*;
import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.replacements.*;
import com.oracle.graal.replacements.Snippet.ConstantParameter;
@@ -44,6 +44,12 @@
/**
* Snippet for loading the exception object at the start of an exception dispatcher.
+ *
* Base Contents
- *
+ *
* : : -----
* caller | incoming overflow argument n | ^
* frame : ... : | positive
@@ -88,8 +89,7 @@
@Override
protected int alignFrameSize(int size) {
- int x = size + (target.stackAlignment - 1);
- return (x / target.stackAlignment) * target.stackAlignment;
+ return NumUtil.roundUp(size, target.stackAlignment);
}
@Override
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Tue Apr 29 18:35:10 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -23,32 +23,14 @@
package com.oracle.graal.lir.sparc;
import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
import static com.oracle.graal.sparc.SPARC.*;
import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CompilationResult.*;
import com.oracle.graal.api.meta.*;
import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Add;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Lddf;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldf;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsb;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsh;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsw;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Lduh;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldx;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Membar;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Rdpc;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Stb;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Sth;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Stw;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Stx;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Cas;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Casx;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Clr;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Mov;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setuw;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
import com.oracle.graal.compiler.common.*;
import com.oracle.graal.lir.*;
import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
@@ -154,32 +136,33 @@
@Override
public void emitMemAccess(SPARCMacroAssembler masm) {
- SPARCAddress addr = address.toAddress();
+ final SPARCAddress addr = address.toAddress();
+ final Register dst = asRegister(result);
switch (kind) {
case Boolean:
case Byte:
- new Ldsb(addr, asRegister(result)).emit(masm);
+ new Ldsb(addr, dst).emit(masm);
break;
case Short:
- new Ldsh(addr, asRegister(result)).emit(masm);
+ new Ldsh(addr, dst).emit(masm);
break;
case Char:
- new Lduh(addr, asRegister(result)).emit(masm);
+ new Lduh(addr, dst).emit(masm);
break;
case Int:
- new Ldsw(addr, asRegister(result)).emit(masm);
+ new Ldsw(addr, dst).emit(masm);
break;
case Long:
- new Ldx(addr, asRegister(result)).emit(masm);
+ new Ldx(addr, dst).emit(masm);
break;
case Float:
- new Ldf(addr, asRegister(result)).emit(masm);
+ new Ldf(addr, dst).emit(masm);
break;
case Double:
- new Lddf(addr, asRegister(result)).emit(masm);
+ new Lddf(addr, dst).emit(masm);
break;
case Object:
- new Ldx(addr, asRegister(result)).emit(masm);
+ new Ldx(addr, dst).emit(masm);
break;
default:
throw GraalInternalError.shouldNotReachHere();
@@ -208,6 +191,26 @@
}
}
+ public static class LoadDataAddressOp extends SPARCLIRInstruction {
+
+ @Def({REG}) protected AllocatableValue result;
+ private final byte[] data;
+
+ public LoadDataAddressOp(AllocatableValue result, byte[] data) {
+ this.result = result;
+ this.data = data;
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+ RawData rawData = new RawData(data, 16);
+ SPARCAddress addr = (SPARCAddress) crb.recordDataReferenceInCode(rawData);
+ assert addr == masm.getPlaceholder();
+ final boolean forceRelocatable = true;
+ new Setx(0, asRegister(result), forceRelocatable).emit(masm);
+ }
+ }
+
public static class MembarOp extends SPARCLIRInstruction {
private final int barriers;
@@ -395,19 +398,25 @@
}
private static void reg2reg(SPARCAssembler masm, Value result, Value input) {
- if (asRegister(input).equals(asRegister(result))) {
+ final Register src = asRegister(input);
+ final Register dst = asRegister(result);
+ if (src.equals(dst)) {
return;
}
switch (input.getKind()) {
case Int:
case Long:
case Object:
- new Mov(asRegister(input), asRegister(result)).emit(masm);
+ new Mov(src, dst).emit(masm);
break;
case Float:
+ new Fmovs(src, dst).emit(masm);
+ break;
case Double:
+ new Fmovd(src, dst).emit(masm);
+ break;
default:
- throw GraalInternalError.shouldNotReachHere("missing: " + input.getKind());
+ throw GraalInternalError.shouldNotReachHere();
}
}
@@ -423,7 +432,11 @@
new Stx(src, dst).emit(masm);
break;
case Float:
+ new Stf(src, dst).emit(masm);
+ break;
case Double:
+ new Stdf(src, dst).emit(masm);
+ break;
default:
throw GraalInternalError.shouldNotReachHere();
}
@@ -461,7 +474,7 @@
}
}
break;
- case Long: {
+ case Long:
if (crb.codeCache.needsDataPatch(input)) {
crb.recordInlineDataInCode(input);
new Setx(input.asLong(), asRegister(result), true).emit(masm);
@@ -473,8 +486,10 @@
}
}
break;
- }
- case Object: {
+ case Float:
+ new Ldf((SPARCAddress) crb.asFloatConstRef(input), asFloatReg(result)).emit(masm);
+ break;
+ case Object:
if (input.isNull()) {
new Clr(asRegister(result)).emit(masm);
} else if (crb.target.inlineObjects) {
@@ -488,7 +503,6 @@
throw GraalInternalError.shouldNotReachHere("the patched offset might be too big for the load");
}
break;
- }
default:
throw GraalInternalError.shouldNotReachHere("missing: " + input.getKind());
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 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 com.oracle.graal.lir.sparc;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Saves registers to stack slots.
+ */
+@Opcode("SAVE_REGISTER")
+public class SPARCSaveRegistersOp extends SPARCLIRInstruction implements SaveRegistersOp {
+
+ /**
+ * The registers (potentially) saved by this operation.
+ */
+ protected final Register[] savedRegisters;
+
+ /**
+ * The slots to which the registers are saved.
+ */
+ @Def(STACK) protected final StackSlot[] slots;
+
+ /**
+ * Specifies if {@link #remove(Set)} should have an effect.
+ */
+ protected final boolean supportsRemove;
+
+ /**
+ *
+ * @param savedRegisters the registers saved by this operation which may be subject to
+ * {@linkplain #remove(Set) pruning}
+ * @param slots the slots to which the registers are saved
+ * @param supportsRemove determines if registers can be {@linkplain #remove(Set) pruned}
+ */
+ public SPARCSaveRegistersOp(Register[] savedRegisters, StackSlot[] slots, boolean supportsRemove) {
+ this.savedRegisters = savedRegisters;
+ this.slots = slots;
+ this.supportsRemove = supportsRemove;
+ }
+
+ private static void saveRegister(CompilationResultBuilder crb, SPARCMacroAssembler masm, StackSlot result, Register register) {
+ RegisterValue input = register.asValue(result.getKind());
+ SPARCMove.move(crb, masm, result, input);
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+ for (int i = 0; i < savedRegisters.length; i++) {
+ if (savedRegisters[i] != null) {
+ saveRegister(crb, masm, slots[i], savedRegisters[i]);
+ }
+ }
+ }
+
+ public StackSlot[] getSlots() {
+ return slots;
+ }
+
+ public boolean supportsRemove() {
+ return supportsRemove;
+ }
+
+ public int remove(Set doNotSave) {
+ if (!supportsRemove) {
+ throw new UnsupportedOperationException();
+ }
+ return prune(doNotSave, savedRegisters);
+ }
+
+ static int prune(Set toRemove, Register[] registers) {
+ int pruned = 0;
+ for (int i = 0; i < registers.length; i++) {
+ if (registers[i] != null) {
+ if (toRemove.contains(registers[i])) {
+ registers[i] = null;
+ pruned++;
+ }
+ }
+ }
+ return pruned;
+ }
+
+ public RegisterSaveLayout getMap(FrameMap frameMap) {
+ int total = 0;
+ for (int i = 0; i < savedRegisters.length; i++) {
+ if (savedRegisters[i] != null) {
+ total++;
+ }
+ }
+ Register[] keys = new Register[total];
+ int[] values = new int[total];
+ if (total != 0) {
+ int mapIndex = 0;
+ for (int i = 0; i < savedRegisters.length; i++) {
+ if (savedRegisters[i] != null) {
+ keys[mapIndex] = savedRegisters[i];
+ values[mapIndex] = frameMap.indexForStackSlot(slots[i]);
+ mapIndex++;
+ }
+ }
+ assert mapIndex == total;
+ }
+ return new RegisterSaveLayout(keys, values);
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Tue Apr 29 18:35:10 2014 +0200
@@ -92,14 +92,8 @@
compilationResult.setTotalFrameSize(frameSize);
}
- private static final CompilationResult.Mark[] NO_REFS = {};
-
public CompilationResult.Mark recordMark(Object id) {
- return compilationResult.recordMark(asm.position(), id, NO_REFS);
- }
-
- public CompilationResult.Mark recordMark(Object id, CompilationResult.Mark... references) {
- return compilationResult.recordMark(asm.position(), id, references);
+ return compilationResult.recordMark(asm.position(), id);
}
public void blockComment(String s) {
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java Tue Apr 29 18:35:10 2014 +0200
@@ -48,7 +48,7 @@
/**
* This class traverses the HIR instructions and generates LIR instructions from them.
*/
-public abstract class LIRGenerator implements ArithmeticLIRGenerator, LIRGeneratorTool, PlatformKindTool {
+public abstract class LIRGenerator implements LIRGeneratorTool, PlatformKindTool {
public static class Options {
// @formatter:off
@@ -62,9 +62,7 @@
private final CodeGenProviders providers;
private final CallingConvention cc;
- protected AbstractBlock> currentBlock;
- public final int traceLevel;
- public final boolean printIRWithLIR;
+ private AbstractBlock> currentBlock;
/**
* Handle for an operation that loads a constant into a variable. The operation starts in the
@@ -173,8 +171,6 @@
this.res = res;
this.providers = providers;
this.cc = cc;
- this.traceLevel = Options.TraceLIRGeneratorLevel.getValue();
- this.printIRWithLIR = Options.PrintIRWithLIR.getValue();
}
/**
@@ -272,7 +268,7 @@
}
public void append(LIRInstruction op) {
- if (printIRWithLIR && !TTY.isSuppressed()) {
+ if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) {
TTY.println(op.toStringWithIdPrefix());
TTY.println();
}
@@ -289,7 +285,7 @@
}
public final void doBlockStart(AbstractBlock> block) {
- if (printIRWithLIR) {
+ if (Options.PrintIRWithLIR.getValue()) {
TTY.print(block.toString());
}
@@ -301,20 +297,20 @@
append(new LabelOp(new Label(block.getId()), block.isAligned()));
- if (traceLevel >= 1) {
+ if (Options.TraceLIRGeneratorLevel.getValue() >= 1) {
TTY.println("BEGIN Generating LIR for block B" + block.getId());
}
}
public final void doBlockEnd(AbstractBlock> block) {
- if (traceLevel >= 1) {
+ if (Options.TraceLIRGeneratorLevel.getValue() >= 1) {
TTY.println("END Generating LIR for block B" + block.getId());
}
currentBlock = null;
- if (printIRWithLIR) {
+ if (Options.PrintIRWithLIR.getValue()) {
TTY.println();
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java Tue Apr 29 18:35:10 2014 +0200
@@ -22,13 +22,21 @@
*/
package com.oracle.graal.lir.gen;
+import java.util.*;
+
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.compiler.common.spi.*;
import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.LIRGenerator.*;
public interface LIRGeneratorTool extends ArithmeticLIRGenerator {
+ CodeGenProviders getProviders();
+
TargetDescription target();
MetaAccessProvider getMetaAccess();
@@ -37,6 +45,20 @@
ForeignCallsProvider getForeignCalls();
+ AbstractBlock> getCurrentBlock();
+
+ LIRGenerationResult getResult();
+
+ boolean hasBlockEnd(AbstractBlock> block);
+
+ void doBlockStart(AbstractBlock> block);
+
+ void doBlockEnd(AbstractBlock> block);
+
+ Map getConstantLoads();
+
+ void setConstantLoads(Map constantLoads);
+
Value emitLoad(PlatformKind kind, Value address, LIRFrameState state);
void emitStore(PlatformKind kind, Value address, Value input, LIRFrameState state);
@@ -65,7 +87,7 @@
void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state);
- Value emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args);
+ Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args);
/**
* Checks whether the supplied constant can be used without loading it into a register for most
@@ -81,9 +103,9 @@
RegisterAttributes attributes(Register register);
- AllocatableValue newVariable(PlatformKind kind);
+ Variable newVariable(PlatformKind kind);
- AllocatableValue emitMove(Value input);
+ Variable emitMove(Value input);
void emitMove(AllocatableValue dst, Value src);
@@ -116,4 +138,62 @@
* correct location.
*/
void emitReturn(Value input);
+
+ AllocatableValue asAllocatable(Value value);
+
+ Variable load(Value value);
+
+ Value loadNonConst(Value value);
+
+ /**
+ * Returns true if the redundant move elimination optimization should be done after register
+ * allocation.
+ */
+ boolean canEliminateRedundantMoves();
+
+ /**
+ * Determines if only oop maps are required for the code generated from the LIR.
+ */
+ boolean needOnlyOopMaps();
+
+ /**
+ * Gets the ABI specific operand used to return a value of a given kind from a method.
+ *
+ * @param kind the kind of value being returned
+ * @return the operand representing the ABI defined location used return a value of kind
+ * {@code kind}
+ */
+ AllocatableValue resultOperandFor(Kind kind);
+
+ void append(LIRInstruction op);
+
+ void emitJump(LabelRef label);
+
+ void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+ double trueDestinationProbability);
+
+ void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability);
+
+ void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability);
+
+ Variable emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue);
+
+ Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue);
+
+ void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value);
+
+ void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget);
+
+ CallingConvention getCallingConvention();
+
+ void emitBitCount(Variable result, Value operand);
+
+ void emitBitScanForward(Variable result, Value operand);
+
+ void emitBitScanReverse(Variable result, Value operand);
+
+ void emitByteSwap(Variable result, Value operand);
+
+ void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
+
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java Tue Apr 29 18:35:10 2014 +0200
@@ -114,7 +114,7 @@
FrameState exitState = exit.stateAfter();
if (exitState != null) {
exitState.applyToVirtual(v -> {
- if (v.usages().filter(n -> nodes.isMarked(n) && !(n instanceof VirtualState && exitState.isPartOfThisState((VirtualState) n))).isEmpty()) {
+ if (v.usages().filter(n -> nodes.isMarked(n) && n != exit).isEmpty()) {
nodes.clear(v);
}
});
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryLogicNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryLogicNode.java Tue Apr 29 18:23:17 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.oracle.graal.nodes;
-
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-
-public abstract class BinaryLogicNode extends LogicNode implements LIRLowerable, MemoryArithmeticLIRLowerable {
-
- @Input private ValueNode x;
- @Input private ValueNode y;
-
- public ValueNode x() {
- return x;
- }
-
- public ValueNode y() {
- return y;
- }
-
- protected void setX(ValueNode x) {
- updateUsages(this.x, x);
- this.x = x;
- }
-
- protected void setY(ValueNode y) {
- updateUsages(this.y, y);
- this.y = y;
- }
-
- public BinaryLogicNode(ValueNode x, ValueNode y) {
- assert x != null && y != null && x.getKind() == y.getKind();
- this.x = x;
- this.y = y;
- }
-
- @Override
- public boolean verify() {
- assertTrue(x.stamp().isCompatible(y.stamp()), "stamps not compatible: %s, %s", x.stamp(), y.stamp());
- return super.verify();
- }
-
- @Override
- public void generate(NodeLIRBuilderTool gen) {
- }
-
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- return false;
- }
-}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011, 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 com.oracle.graal.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.spi.*;
+
+public abstract class BinaryOpLogicNode extends LogicNode implements LIRLowerable, Canonicalizable {
+
+ @Input private ValueNode x;
+ @Input private ValueNode y;
+
+ public ValueNode x() {
+ return x;
+ }
+
+ public ValueNode y() {
+ return y;
+ }
+
+ protected void setX(ValueNode x) {
+ updateUsages(this.x, x);
+ this.x = x;
+ }
+
+ protected void setY(ValueNode y) {
+ updateUsages(this.y, y);
+ this.y = y;
+ }
+
+ public BinaryOpLogicNode(ValueNode x, ValueNode y) {
+ assert x != null && y != null && x.getKind() == y.getKind();
+ this.x = x;
+ this.y = y;
+ }
+
+ public abstract TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY);
+
+ @Override
+ public boolean verify() {
+ assertTrue(x.stamp().isCompatible(y.stamp()), "stamps not compatible: %s, %s", x.stamp(), y.stamp());
+ return super.verify();
+ }
+
+ @Override
+ public Node canonical(CanonicalizerTool tool) {
+ switch (evaluate(tool.getConstantReflection(), x(), y())) {
+ case FALSE:
+ return LogicConstantNode.contradiction(graph());
+ case TRUE:
+ return LogicConstantNode.tautology(graph());
+ }
+ return this;
+ }
+
+ @Override
+ public void generate(NodeLIRBuilderTool gen) {
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Tue Apr 29 18:35:10 2014 +0200
@@ -95,8 +95,8 @@
this.virtualObjectMappings = new NodeInputList<>(this, virtualObjectMappings);
this.rethrowException = rethrowException;
this.duringCall = duringCall;
- assert !rethrowException || stackSize == 1 : "must have exception on top of the stack";
- assert values.size() - localsSize - stackSize == monitorIds.size();
+ assert !this.rethrowException || this.stackSize == 1 : "must have exception on top of the stack";
+ assert this.locksSize() == this.monitorIds.size();
}
/**
@@ -220,6 +220,19 @@
* correctly in slot encoding: a long or double will be followed by a null slot.
*/
public FrameState duplicateModified(int newBci, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) {
+ return duplicateModified(newBci, method, newRethrowException, popKind, pushedValues);
+ }
+
+ /**
+ * Creates a copy of this frame state with one stack element of type popKind popped from the
+ * stack and the values in pushedValues pushed on the stack. The pushedValues will be formatted
+ * correctly in slot encoding: a long or double will be followed by a null slot.
+ */
+ public FrameState duplicateModified(Kind popKind, ValueNode... pushedValues) {
+ return duplicateModified(bci, method, rethrowException, popKind, pushedValues);
+ }
+
+ private FrameState duplicateModified(int newBci, ResolvedJavaMethod newMethod, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) {
ArrayList copy = new ArrayList<>(values.subList(0, localsSize + stackSize));
if (popKind != Kind.Void) {
if (stackAt(stackSize() - 1) == null) {
@@ -238,7 +251,7 @@
int newStackSize = copy.size() - localsSize;
copy.addAll(values.subList(localsSize + stackSize, values.size()));
- FrameState other = graph().add(new FrameState(method, newBci, copy, localsSize, newStackSize, newRethrowException, false, monitorIds, virtualObjectMappings));
+ FrameState other = graph().add(new FrameState(newMethod, newBci, copy, localsSize, newStackSize, newRethrowException, false, monitorIds, virtualObjectMappings));
other.setOuterFrameState(outerFrameState());
return other;
}
@@ -386,7 +399,7 @@
@Override
public boolean verify() {
- assertTrue(values.size() - localsSize - stackSize == monitorIds.size(), "mismatch in number of locks");
+ assertTrue(locksSize() == monitorIds.size(), "mismatch in number of locks");
for (ValueNode value : values) {
assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes");
assertTrue(value == null || value instanceof VirtualObjectNode || (value.getKind() != Kind.Void), "unexpected value: %s", value);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -107,7 +107,8 @@
} else if (condition() instanceof LogicConstantNode) {
LogicConstantNode c = (LogicConstantNode) condition();
if (c.getValue() != negated) {
- return graph().start();
+ this.replaceAtUsages(null);
+ return null;
}
}
return this;
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -77,7 +77,7 @@
@Override
public Node canonical(CanonicalizerTool tool) {
- if (getGuard() == graph().start() || getGuard() == null) {
+ if (getGuard() == null) {
if (stamp().equals(object().stamp())) {
return object();
} else {
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -51,6 +51,18 @@
return condition;
}
+ public boolean isNegated() {
+ return negated;
+ }
+
+ public DeoptimizationReason getReason() {
+ return reason;
+ }
+
+ public DeoptimizationAction getAction() {
+ return action;
+ }
+
/**
* Constructor for {@link #guardingNonNull(Object)} node intrinsic.
*/
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -34,7 +34,6 @@
import com.oracle.graal.graph.iterators.*;
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.java.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.nodes.util.*;
@@ -43,7 +42,7 @@
* The {@code IfNode} represents a branch that can go one of two directions depending on the outcome
* of a comparison.
*/
-public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, MemoryArithmeticLIRLowerable {
+public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable {
@Successor private BeginNode trueSuccessor;
@Successor private BeginNode falseSuccessor;
@@ -132,11 +131,6 @@
}
@Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- return gen.emitIfMemory(this, access);
- }
-
- @Override
public boolean verify() {
assertTrue(condition() != null, "missing condition");
assertTrue(trueSuccessor() != null, "missing trueSuccessor");
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -43,6 +43,6 @@
@Override
public String targetName() {
- return "Indirect#" + ((JavaMethod) target()).getName();
+ return MetaUtil.format("Indirect#%h.%n", target());
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -37,7 +37,7 @@
private static final double EXCEPTION_PROBA = 1e-5;
@Successor private BeginNode next;
- @Successor private DispatchBeginNode exceptionEdge;
+ @Successor private BeginNode exceptionEdge;
@Input(InputType.Extension) private CallTargetNode callTarget;
@Input(InputType.State) private FrameState stateDuring;
@Input(InputType.State) private FrameState stateAfter;
@@ -47,7 +47,7 @@
private boolean useForInlining;
private double exceptionProbability;
- public InvokeWithExceptionNode(CallTargetNode callTarget, DispatchBeginNode exceptionEdge, int bci) {
+ public InvokeWithExceptionNode(CallTargetNode callTarget, BeginNode exceptionEdge, int bci) {
super(callTarget.returnStamp());
this.exceptionEdge = exceptionEdge;
this.bci = bci;
@@ -57,11 +57,11 @@
this.exceptionProbability = EXCEPTION_PROBA;
}
- public DispatchBeginNode exceptionEdge() {
+ public BeginNode exceptionEdge() {
return exceptionEdge;
}
- public void setExceptionEdge(DispatchBeginNode x) {
+ public void setExceptionEdge(BeginNode x) {
updatePredecessor(exceptionEdge, x);
exceptionEdge = x;
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -155,7 +155,7 @@
return;
}
for (PhiNode phi : phis()) {
- if (phi.usages().filter(isNotA(FrameState.class)).and(node -> !merge.isPhiAtMerge(node)).isNotEmpty()) {
+ if (phi.usages().filter(isNotA(VirtualState.class)).and(node -> !merge.isPhiAtMerge(node)).isNotEmpty()) {
return;
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnaryOpLogicNode.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnaryOpLogicNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2011, 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 com.oracle.graal.nodes;
+
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.nodes.spi.*;
+
+public abstract class UnaryOpLogicNode extends LogicNode implements LIRLowerable {
+
+ @Input private ValueNode object;
+
+ public ValueNode object() {
+ return object;
+ }
+
+ protected void setX(ValueNode object) {
+ updateUsages(this.object, object);
+ this.object = object;
+ }
+
+ public UnaryOpLogicNode(ValueNode object) {
+ assert object != null;
+ this.object = object;
+ }
+
+ public abstract TriState evaluate(ValueNode forObject);
+
+ @Override
+ public void generate(NodeLIRBuilderTool gen) {
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java Tue Apr 29 18:35:10 2014 +0200
@@ -45,6 +45,10 @@
public abstract void applyToNonVirtual(NodeClosure super ValueNode> closure);
+ /**
+ * Performs a pre-order iteration over all elements reachable from this state that are a
+ * subclass of {@link VirtualState}.
+ */
public abstract void applyToVirtual(VirtualClosure closure);
public abstract boolean isPartOfThisState(VirtualState state);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -28,7 +28,6 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.nodes.type.*;
@@ -93,13 +92,4 @@
public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
builder.setResult(this, gen.emitAnd(builder.operand(x()), builder.operand(y())));
}
-
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitAndMemory(x(), y(), access);
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -30,7 +30,7 @@
/**
* The {@code LogicNode} class definition.
*/
-public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable, NarrowableArithmeticNode {
+public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
/**
* Constructs a new logic operation node.
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -23,6 +23,7 @@
package com.oracle.graal.nodes.calc;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
import com.oracle.graal.compiler.common.*;
import com.oracle.graal.compiler.common.calc.*;
import com.oracle.graal.graph.*;
@@ -35,7 +36,7 @@
* Compare should probably be made a value (so that it can be canonicalized for example) and in later stages some Compare usage should be transformed
* into variants that do not materialize the value (CompareIf, CompareGuard...)
*/
-public abstract class CompareNode extends BinaryLogicNode implements Canonicalizable {
+public abstract class CompareNode extends BinaryOpLogicNode {
/**
* Constructs a new Compare instruction.
@@ -90,9 +91,18 @@
}
@Override
+ public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+ if (x().isConstant() && y().isConstant()) {
+ return TriState.get(condition().foldCondition(x().asConstant(), y().asConstant(), constantReflection, unorderedIsTrue()));
+ }
+ return TriState.UNKNOWN;
+ }
+
+ @Override
public Node canonical(CanonicalizerTool tool) {
- if (x().isConstant() && y().isConstant() && tool.getMetaAccess() != null) {
- return LogicConstantNode.forBoolean(condition().foldCondition(x().asConstant(), y().asConstant(), tool.getConstantReflection(), unorderedIsTrue()), graph());
+ Node result = super.canonical(tool);
+ if (result != this) {
+ return result;
}
if (x().isConstant()) {
if (y() instanceof ConditionalNode) {
@@ -110,7 +120,7 @@
if (x() instanceof ConvertNode && y() instanceof ConvertNode) {
ConvertNode convertX = (ConvertNode) x();
ConvertNode convertY = (ConvertNode) y();
- if (convertX.isLossless() && convertY.isLossless() && convertX.getInput().stamp().isCompatible(convertY.getInput().stamp())) {
+ if (convertX.preservesOrder(condition()) && convertY.preservesOrder(condition()) && convertX.getInput().stamp().isCompatible(convertY.getInput().stamp())) {
setX(convertX.getInput());
setY(convertY.getInput());
}
@@ -132,8 +142,8 @@
return this;
}
- private static ConstantNode canonicalConvertConstant(ConvertNode convert, Constant constant) {
- if (convert.isLossless()) {
+ private ConstantNode canonicalConvertConstant(ConvertNode convert, Constant constant) {
+ if (convert.preservesOrder(condition())) {
Constant reverseConverted = convert.reverse(constant);
if (convert.convert(reverseConverted).equals(constant)) {
return ConstantNode.forPrimitive(convert.getInput().stamp(), reverseConverted, convert.graph());
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -24,6 +24,7 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.calc.*;
import com.oracle.graal.compiler.common.type.*;
import com.oracle.graal.nodes.*;
@@ -47,8 +48,23 @@
public abstract Constant reverse(Constant c);
+ /**
+ * Check whether a conversion is lossless.
+ *
+ * @return true iff reverse(convert(c)) == c for all c
+ */
public abstract boolean isLossless();
+ /**
+ * Check whether a conversion preserves comparison order.
+ *
+ * @param op a comparison operator
+ * @return true iff (c1 op c2) == (convert(c1) op convert(c2)) for all c1, c2
+ */
+ public boolean preservesOrder(Condition op) {
+ return isLossless();
+ }
+
@Override
public Constant evalConst(Constant... inputs) {
assert inputs.length == 1;
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -28,7 +28,6 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
@NodeInfo(shortName = "+")
@@ -85,13 +84,4 @@
}
return false;
}
-
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitAddMemory(x(), y(), access);
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -26,7 +26,7 @@
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.spi.*;
-public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
+public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
private final boolean isStrictFP;
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -30,14 +30,13 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
/**
* A {@code FloatConvert} converts between integers and floating point numbers according to Java
* semantics.
*/
-public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
+public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable {
private final FloatConvert op;
@@ -167,12 +166,4 @@
public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
builder.setResult(this, gen.emitFloatConvert(op, builder.operand(getInput())));
}
-
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitFloatConvertMemory(getOp(), access);
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -28,7 +28,6 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
@NodeInfo(shortName = "/")
@@ -61,13 +60,4 @@
public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
builder.setResult(this, gen.emitDiv(builder.operand(x()), builder.operand(y()), null));
}
-
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitDivMemory(x(), y(), access);
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -22,17 +22,20 @@
*/
package com.oracle.graal.nodes.calc;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
import com.oracle.graal.compiler.common.calc.*;
import com.oracle.graal.compiler.common.type.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
@NodeInfo(shortName = "==")
public final class FloatEqualsNode extends CompareNode {
/**
* Constructs a new floating point equality comparison node.
- *
+ *
* @param x the instruction producing the first input to the instruction
* @param y the instruction that produces the second input to this instruction
*/
@@ -51,4 +54,18 @@
public boolean unorderedIsTrue() {
return false;
}
+
+ @Override
+ public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+ if (forX.stamp() instanceof FloatStamp && forY.stamp() instanceof FloatStamp) {
+ FloatStamp xStamp = (FloatStamp) forX.stamp();
+ FloatStamp yStamp = (FloatStamp) forY.stamp();
+ if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && xStamp.isNonNaN() && yStamp.isNonNaN()) {
+ return TriState.TRUE;
+ } else if (xStamp.alwaysDistinct(yStamp)) {
+ return TriState.FALSE;
+ }
+ }
+ return super.evaluate(constantReflection, forX, forY);
+ }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -22,11 +22,13 @@
*/
package com.oracle.graal.nodes.calc;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
import com.oracle.graal.compiler.common.calc.*;
import com.oracle.graal.compiler.common.type.*;
import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
@NodeInfo(shortName = "<")
public final class FloatLessThanNode extends CompareNode {
@@ -35,7 +37,7 @@
/**
* Constructs a new floating point comparison node.
- *
+ *
* @param x the instruction producing the first input to the instruction
* @param y the instruction that produces the second input to this instruction
* @param unorderedIsTrue whether a comparison that is undecided (involving NaNs, etc.) leads to
@@ -59,10 +61,10 @@
}
@Override
- public Node canonical(CanonicalizerTool tool) {
- if (x() == y() && !unorderedIsTrue()) {
- return LogicConstantNode.contradiction(graph());
+ public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+ if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && !unorderedIsTrue()) {
+ return TriState.FALSE;
}
- return super.canonical(tool);
+ return super.evaluate(constantReflection, forX, forY);
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -28,7 +28,6 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
@NodeInfo(shortName = "*")
@@ -71,13 +70,4 @@
}
builder.setResult(this, gen.emitMul(op1, op2));
}
-
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitMulMemory(x(), y(), access);
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -28,7 +28,6 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
@NodeInfo(shortName = "%")
@@ -61,13 +60,4 @@
public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
builder.setResult(this, gen.emitRem(builder.operand(x()), builder.operand(y()), null));
}
-
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitRemMemory(x(), y(), access);
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -28,7 +28,6 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
@NodeInfo(shortName = "-")
@@ -80,13 +79,4 @@
public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
builder.setResult(this, gen.emitSub(builder.operand(x()), builder.operand(y())));
}
-
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitSubMemory(x(), y(), access);
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -28,7 +28,6 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.nodes.type.*;
@@ -102,13 +101,4 @@
}
builder.setResult(this, gen.emitAdd(op1, op2));
}
-
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitAddMemory(x(), y(), access);
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -27,7 +27,7 @@
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.nodes.type.*;
-public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
+public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
public IntegerArithmeticNode(Stamp stamp, ValueNode x, ValueNode y) {
super(stamp, x, y);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -23,18 +23,20 @@
package com.oracle.graal.nodes.calc;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
import com.oracle.graal.compiler.common.calc.*;
import com.oracle.graal.compiler.common.type.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
@NodeInfo(shortName = "|<|")
public final class IntegerBelowThanNode extends CompareNode {
/**
* Constructs a new unsigned integer comparison node.
- *
+ *
* @param x the instruction producing the first input to the instruction
* @param y the instruction that produces the second input to this instruction
*/
@@ -55,28 +57,33 @@
}
@Override
- public Node canonical(CanonicalizerTool tool) {
- if (x() == y()) {
- return LogicConstantNode.contradiction(graph());
- } else {
- if (x().isConstant() && x().asConstant().asLong() == 0) {
- // 0 |<| y is the same as 0 != y
- return graph().unique(new LogicNegationNode(CompareNode.createCompareNode(graph(), Condition.EQ, x(), y())));
- }
-
- if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) {
- IntegerStamp xStamp = (IntegerStamp) x().stamp();
- IntegerStamp yStamp = (IntegerStamp) y().stamp();
- if (yStamp.isPositive()) {
- if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) {
- return LogicConstantNode.tautology(graph());
- } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) {
- return LogicConstantNode.contradiction(graph());
- }
+ public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+ if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+ return TriState.FALSE;
+ } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+ IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+ IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+ if (yStamp.isPositive()) {
+ if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) {
+ return TriState.TRUE;
+ } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) {
+ return TriState.FALSE;
}
}
}
+ return super.evaluate(constantReflection, forX, forY);
+ }
- return super.canonical(tool);
+ @Override
+ public Node canonical(CanonicalizerTool tool) {
+ Node result = super.canonical(tool);
+ if (result != this) {
+ return result;
+ }
+ if (x().isConstant() && x().asConstant().asLong() == 0) {
+ // 0 |<| y is the same as 0 != y
+ return graph().unique(new LogicNegationNode(CompareNode.createCompareNode(graph(), Condition.EQ, x(), y())));
+ }
+ return this;
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -31,7 +31,7 @@
/**
* An {@code IntegerConvert} converts an integer to an integer of different width.
*/
-public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable, MemoryArithmeticLIRLowerable {
+public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable {
private final int resultBits;
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -23,6 +23,7 @@
package com.oracle.graal.nodes.calc;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
import com.oracle.graal.compiler.common.calc.*;
import com.oracle.graal.compiler.common.type.*;
import com.oracle.graal.graph.*;
@@ -35,7 +36,7 @@
/**
* Constructs a new integer equality comparison node.
- *
+ *
* @param x the instruction producing the first input to the instruction
* @param y the instruction that produces the second input to this instruction
*/
@@ -71,24 +72,28 @@
}
@Override
+ public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+ if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+ return TriState.TRUE;
+ } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
+ return TriState.FALSE;
+ }
+ return super.evaluate(constantReflection, forX, forY);
+ }
+
+ @Override
public Node canonical(CanonicalizerTool tool) {
- if (GraphUtil.unproxify(x()) == GraphUtil.unproxify(y())) {
- return LogicConstantNode.tautology(graph());
- } else if (x().stamp().alwaysDistinct(y().stamp())) {
- return LogicConstantNode.contradiction(graph());
- }
-
- ValueNode result = canonicalizeSymmetric(x(), y());
- if (result != null) {
+ Node result = super.canonical(tool);
+ if (result != this) {
return result;
}
- result = canonicalizeSymmetric(y(), x());
- if (result != null) {
+ result = canonicalizeSymmetric(x(), y());
+ if (result != this) {
return result;
}
- return super.canonical(tool);
+ return canonicalizeSymmetric(y(), x());
}
private ValueNode canonicalizeSymmetric(ValueNode x, ValueNode y) {
@@ -133,6 +138,6 @@
}
}
}
- return null;
+ return this;
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -23,18 +23,20 @@
package com.oracle.graal.nodes.calc;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
import com.oracle.graal.compiler.common.calc.*;
import com.oracle.graal.compiler.common.type.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
@NodeInfo(shortName = "<")
public final class IntegerLessThanNode extends CompareNode {
/**
* Constructs a new integer comparison node.
- *
+ *
* @param x the instruction producing the first input to the instruction
* @param y the instruction that produces the second input to this instruction
*/
@@ -71,22 +73,32 @@
}
@Override
+ public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+ if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+ return TriState.FALSE;
+ } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+ IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+ IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+ if (xStamp.upperBound() < yStamp.lowerBound()) {
+ return TriState.TRUE;
+ } else if (xStamp.lowerBound() >= yStamp.upperBound()) {
+ return TriState.FALSE;
+ }
+ }
+ return super.evaluate(constantReflection, forX, forY);
+ }
+
+ @Override
public Node canonical(CanonicalizerTool tool) {
- if (x() == y()) {
- return LogicConstantNode.contradiction(graph());
+ Node result = super.canonical(tool);
+ if (result != this) {
+ return result;
}
if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) {
- IntegerStamp xStamp = (IntegerStamp) x().stamp();
- IntegerStamp yStamp = (IntegerStamp) y().stamp();
- if (xStamp.upperBound() < yStamp.lowerBound()) {
- return LogicConstantNode.tautology(graph());
- } else if (xStamp.lowerBound() >= yStamp.upperBound()) {
- return LogicConstantNode.contradiction(graph());
- }
- if (IntegerStamp.sameSign(xStamp, yStamp)) {
+ if (IntegerStamp.sameSign((IntegerStamp) x().stamp(), (IntegerStamp) y().stamp())) {
return graph().unique(new IntegerBelowThanNode(x(), y()));
}
}
- return super.canonical(tool);
+ return this;
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -29,7 +29,6 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
@NodeInfo(shortName = "*")
@@ -86,13 +85,4 @@
}
builder.setResult(this, gen.emitMul(op1, op2));
}
-
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitMulMemory(x(), y(), access);
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -28,7 +28,6 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.nodes.type.*;
@@ -122,13 +121,4 @@
public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
builder.setResult(this, gen.emitSub(builder.operand(x()), builder.operand(y())));
}
-
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitSubMemory(x(), y(), access);
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -22,9 +22,9 @@
*/
package com.oracle.graal.nodes.calc;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
import com.oracle.graal.nodes.*;
/**
@@ -32,7 +32,7 @@
* expression "(x & y) == 0", meaning that it will return true if (and only if) no bit is set in
* both x and y.
*/
-public class IntegerTestNode extends BinaryLogicNode implements Canonicalizable {
+public class IntegerTestNode extends BinaryOpLogicNode {
/**
* Constructs a new Test instruction.
@@ -45,19 +45,19 @@
}
@Override
- public Node canonical(CanonicalizerTool tool) {
- if (x().isConstant() && y().isConstant()) {
- return LogicConstantNode.forBoolean((x().asConstant().asLong() & y().asConstant().asLong()) == 0, graph());
+ public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+ if (forX.isConstant() && forY.isConstant()) {
+ return TriState.get((forX.asConstant().asLong() & forY.asConstant().asLong()) == 0);
}
if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) {
- IntegerStamp xStamp = (IntegerStamp) x().stamp();
- IntegerStamp yStamp = (IntegerStamp) y().stamp();
+ IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+ IntegerStamp yStamp = (IntegerStamp) forY.stamp();
if ((xStamp.upMask() & yStamp.upMask()) == 0) {
- return LogicConstantNode.tautology(graph());
+ return TriState.TRUE;
} else if ((xStamp.downMask() & yStamp.downMask()) != 0) {
- return LogicConstantNode.contradiction(graph());
+ return TriState.FALSE;
}
}
- return this;
+ return TriState.UNKNOWN;
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -23,6 +23,7 @@
package com.oracle.graal.nodes.calc;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
import com.oracle.graal.compiler.common.type.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.graph.spi.*;
@@ -33,21 +34,15 @@
/**
* An IsNullNode will be true if the supplied value is null, and false if it is non-null.
*/
-public final class IsNullNode extends LogicNode implements Canonicalizable, LIRLowerable, Virtualizable, PiPushable {
-
- @Input private ValueNode object;
-
- public ValueNode object() {
- return object;
- }
+public final class IsNullNode extends UnaryOpLogicNode implements Canonicalizable, LIRLowerable, Virtualizable, PiPushable {
/**
* Constructs a new IsNullNode instruction.
- *
+ *
* @param object the instruction producing the object to check against null
*/
public IsNullNode(ValueNode object) {
- this.object = object;
+ super(object);
}
@Override
@@ -64,20 +59,31 @@
@Override
public Node canonical(CanonicalizerTool tool) {
- Constant constant = object().asConstant();
- if (constant != null) {
- assert constant.getKind() == Kind.Object;
- return LogicConstantNode.forBoolean(constant.isNull(), graph());
- }
- if (StampTool.isObjectNonNull(object.stamp())) {
- return LogicConstantNode.contradiction(graph());
+ switch (evaluate(object())) {
+ case FALSE:
+ return LogicConstantNode.contradiction(graph());
+ case TRUE:
+ return LogicConstantNode.tautology(graph());
}
return this;
}
@Override
+ public TriState evaluate(ValueNode forObject) {
+ Constant constant = forObject.asConstant();
+ if (constant != null) {
+ assert constant.getKind() == Kind.Object;
+ return TriState.get(constant.isNull());
+ }
+ if (StampTool.isObjectNonNull(forObject.stamp())) {
+ return TriState.FALSE;
+ }
+ return TriState.UNKNOWN;
+ }
+
+ @Override
public void virtualize(VirtualizerTool tool) {
- if (tool.getObjectState(object) != null) {
+ if (tool.getObjectState(object()) != null) {
tool.replaceWithValue(LogicConstantNode.contradiction(graph()));
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -28,7 +28,6 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.nodes.type.*;
@@ -109,13 +108,4 @@
public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
builder.setResult(this, gen.emitNarrow(builder.operand(getInput()), getResultBits()));
}
-
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitNarrowMemory(getResultBits(), access);
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -23,19 +23,21 @@
package com.oracle.graal.nodes.calc;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
import com.oracle.graal.compiler.common.calc.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
@NodeInfo(shortName = "==")
public final class ObjectEqualsNode extends CompareNode implements Virtualizable {
/**
* Constructs a new object equality comparison node.
- *
+ *
* @param x the instruction producing the first input to the instruction
* @param y the instruction that produces the second input to this instruction
*/
@@ -56,21 +58,28 @@
}
@Override
+ public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+ if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+ return TriState.TRUE;
+ } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
+ return TriState.FALSE;
+ } else {
+ return super.evaluate(constantReflection, forX, forY);
+ }
+ }
+
+ @Override
public Node canonical(CanonicalizerTool tool) {
- if (x() == y()) {
- return LogicConstantNode.tautology(graph());
+ Node result = super.canonical(tool);
+ if (result != this) {
+ return result;
}
-
if (StampTool.isObjectAlwaysNull(x())) {
return graph().unique(new IsNullNode(y()));
} else if (StampTool.isObjectAlwaysNull(y())) {
return graph().unique(new IsNullNode(x()));
}
- if (x().stamp().alwaysDistinct(y().stamp())) {
- return LogicConstantNode.contradiction(graph());
- }
-
- return super.canonical(tool);
+ return this;
}
private void virtualizeNonVirtualComparison(State state, ValueNode other, VirtualizerTool tool) {
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -28,7 +28,6 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.nodes.type.*;
@@ -78,13 +77,4 @@
public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
builder.setResult(this, gen.emitOr(builder.operand(x()), builder.operand(y())));
}
-
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitOrMemory(x(), y(), access);
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -29,7 +29,6 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
/**
@@ -37,7 +36,7 @@
* of a primitive value to some other incompatible stamp. The new stamp must have the same width as
* the old stamp.
*/
-public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
+public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable {
@Input private ValueNode value;
@@ -109,15 +108,6 @@
builder.setResult(this, gen.emitReinterpret(kind, builder.operand(value())));
}
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitReinterpretMemory(stamp(), access);
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
-
public static ValueNode reinterpret(Kind toKind, ValueNode value) {
return value.graph().unique(new ReinterpretNode(toKind, value));
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -28,7 +28,6 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.nodes.type.*;
@@ -110,13 +109,4 @@
public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
builder.setResult(this, gen.emitSignExtend(builder.operand(getInput()), getInputBits(), getResultBits()));
}
-
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitSignExtendMemory(access, getInputBits(), getResultBits());
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -28,7 +28,6 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.nodes.type.*;
@@ -77,13 +76,4 @@
public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
builder.setResult(this, gen.emitXor(builder.operand(x()), builder.operand(y())));
}
-
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitXorMemory(x(), y(), access);
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -23,12 +23,12 @@
package com.oracle.graal.nodes.calc;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.calc.*;
import com.oracle.graal.compiler.common.type.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.nodes.type.*;
@@ -65,6 +65,19 @@
}
@Override
+ public boolean preservesOrder(Condition op) {
+ switch (op) {
+ case GE:
+ case GT:
+ case LE:
+ case LT:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ @Override
public Node canonical(CanonicalizerTool tool) {
ValueNode ret = canonicalConvert();
if (ret != null) {
@@ -103,13 +116,4 @@
public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
builder.setResult(this, gen.emitZeroExtend(builder.operand(getInput()), getInputBits(), getResultBits()));
}
-
- @Override
- public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
- Value result = gen.emitZeroExtendMemory(getInputBits(), getResultBits(), access);
- if (result != null) {
- gen.setResult(this, result);
- }
- return result != null;
- }
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Tue Apr 29 18:35:10 2014 +0200
@@ -25,8 +25,8 @@
import java.util.*;
import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
public final class Block extends AbstractBlockBase {
@@ -67,7 +67,8 @@
}
public boolean isExceptionEntry() {
- return getBeginNode() instanceof ExceptionObjectNode;
+ Node predecessor = getBeginNode().predecessor();
+ return predecessor != null && predecessor instanceof InvokeWithExceptionNode && getBeginNode() == ((InvokeWithExceptionNode) predecessor).exceptionEdge();
}
public Block getFirstPredecessor() {
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -30,7 +30,7 @@
* This node can be used to add a counter to the code that will estimate the dynamic number of calls
* by adding an increment to the compiled code. This should of course only be used for
* debugging/testing purposes.
- *
+ *
* A unique counter will be created for each unique name passed to the constructor. Depending on the
* value of withContext, the name of the root method is added to the counter's name.
*/
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -38,8 +38,8 @@
@NodeInfo(nameTemplate = "AddLoc {p#locationIdentity/s}")
public final class AddLocationNode extends LocationNode implements Canonicalizable {
- @Input private ValueNode x;
- @Input private ValueNode y;
+ @Input(InputType.Association) private ValueNode x;
+ @Input(InputType.Association) private ValueNode y;
protected LocationNode getX() {
return (LocationNode) x;
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardedNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardedNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardedNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -22,12 +22,13 @@
*/
package com.oracle.graal.nodes.extended;
+import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
/**
* A node that may be guarded by a {@linkplain GuardingNode guarding node}.
*/
-public interface GuardedNode {
+public interface GuardedNode extends NodeInterface {
GuardingNode getGuard();
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java Tue Apr 29 18:35:10 2014 +0200
@@ -40,7 +40,7 @@
/**
* This method is used to determine which memory location is killed by this node. Returning
* the special value {@link LocationIdentity#ANY_LOCATION} will kill all memory locations.
- *
+ *
* @return the identity of the location killed by this node.
*/
LocationIdentity getLocationIdentity();
@@ -53,7 +53,7 @@
* This method is used to determine which set of memory locations is killed by this node.
* Returning the special value {@link LocationIdentity#ANY_LOCATION} will kill all memory
* locations.
- *
+ *
* @return the identities of all locations killed by this node.
*/
LocationIdentity[] getLocationIdentities();
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -22,12 +22,13 @@
*/
package com.oracle.graal.nodes.extended;
+import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
/**
* This interface marks nodes that are part of the memory graph.
*/
-public interface MemoryNode {
+public interface MemoryNode extends NodeInterface {
ValueNode asNode();
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -22,13 +22,9 @@
*/
package com.oracle.graal.nodes.java;
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.common.type.*;
import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
@@ -37,6 +33,7 @@
* The entry to an exception handler with the exception coming from a call (as opposed to a local
* throw instruction or implicit exception).
*/
+@NodeInfo(allowedUsageTypes = {InputType.Memory})
public class ExceptionObjectNode extends DispatchBeginNode implements Lowerable, MemoryCheckpoint.Single {
public ExceptionObjectNode(MetaAccessProvider metaAccess) {
@@ -49,56 +46,13 @@
}
@Override
- public void simplify(SimplifierTool tool) {
- //
- }
-
- private boolean isLowered() {
- return (stamp() == StampFactory.forVoid());
- }
-
- /**
- * The frame state upon entry to an exception handler is such that it is a
- * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly
- * the exception object (per the JVM spec) to rethrow. This means that the code creating this
- * state (i.e. the {@link LoadExceptionObjectNode}) cannot cause a deoptimization as the
- * runtime/interpreter would not have a valid location for the exception object to be rethrown.
- */
- @Override
public void lower(LoweringTool tool) {
- if (isLowered()) {
- return;
- }
- LoadExceptionObjectNode loadException = graph().add(new LoadExceptionObjectNode(stamp()));
- loadException.setStateAfter(stateAfter());
- List guardedNodes = new ArrayList<>();
- for (Node usage : usages().snapshot()) {
- if (usage instanceof GuardedNode) {
- // can't replace the guard with LoadExceptionObjectNode as it is not a GuardingNode
- // so temporarily change it to remove the GuardedNode from usages
- GuardedNode guardedNode = (GuardedNode) usage;
- guardedNode.setGuard(graph().add(new BeginNode()));
- guardedNodes.add(guardedNode);
- }
- }
- replaceAtUsages(loadException);
- for (GuardedNode guardedNode : guardedNodes) {
- BeginNode dummyGuard = (BeginNode) guardedNode.getGuard();
- guardedNode.setGuard(this);
- graph().removeFixed(dummyGuard);
- }
- graph().addAfterFixed(this, loadException);
- setStateAfter(null);
- setStamp(StampFactory.forVoid());
- loadException.lower(tool);
+ tool.getLowerer().lower(this, tool);
}
@Override
public boolean verify() {
- if (isLowered()) {
- return true;
- }
- assertTrue(stateAfter() != null || stamp() == StampFactory.forVoid(), "an exception handler needs a frame state");
+ assertTrue(stateAfter() != null, "an exception handler needs a frame state");
return super.verify();
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -23,6 +23,7 @@
package com.oracle.graal.nodes.java;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
import com.oracle.graal.compiler.common.type.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.graph.spi.*;
@@ -33,21 +34,20 @@
/**
* The {@code InstanceOfNode} represents an instanceof test.
*/
-public final class InstanceOfNode extends LogicNode implements Canonicalizable, Lowerable, Virtualizable {
+public final class InstanceOfNode extends UnaryOpLogicNode implements Canonicalizable, Lowerable, Virtualizable {
- @Input private ValueNode object;
private final ResolvedJavaType type;
private JavaTypeProfile profile;
/**
* Constructs a new InstanceOfNode.
- *
+ *
* @param type the target type of the instanceof check
* @param object the object being tested by the instanceof
*/
public InstanceOfNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) {
+ super(object);
this.type = type;
- this.object = object;
this.profile = profile;
assert type != null;
}
@@ -59,13 +59,39 @@
@Override
public Node canonical(CanonicalizerTool tool) {
- Stamp stamp = object().stamp();
+ switch (evaluate(object())) {
+ case FALSE:
+ return LogicConstantNode.contradiction(graph());
+ case TRUE:
+ return LogicConstantNode.tautology(graph());
+ case UNKNOWN:
+ Stamp stamp = object().stamp();
+ if (stamp instanceof ObjectStamp) {
+ ObjectStamp objectStamp = (ObjectStamp) stamp;
+ ResolvedJavaType stampType = objectStamp.type();
+ if (stampType != null && type().isAssignableFrom(stampType)) {
+ if (!objectStamp.nonNull()) {
+ // the instanceof matches if the object is non-null, so return true
+ // depending on the null-ness.
+ IsNullNode isNull = graph().unique(new IsNullNode(object()));
+ return graph().unique(new LogicNegationNode(isNull));
+ }
+ }
+ }
+ return this;
+ }
+ return this;
+ }
+
+ @Override
+ public TriState evaluate(ValueNode forObject) {
+ Stamp stamp = forObject.stamp();
if (!(stamp instanceof ObjectStamp)) {
- return this;
+ return TriState.UNKNOWN;
}
ObjectStamp objectStamp = (ObjectStamp) stamp;
if (objectStamp.alwaysNull()) {
- return LogicConstantNode.contradiction(graph());
+ return TriState.FALSE;
}
ResolvedJavaType stampType = objectStamp.type();
@@ -74,34 +100,25 @@
if (subType) {
if (objectStamp.nonNull()) {
// the instanceOf matches, so return true
- return LogicConstantNode.tautology(graph());
- } else {
- // the instanceof matches if the object is non-null, so return true depending on
- // the null-ness.
- IsNullNode isNull = graph().unique(new IsNullNode(object()));
- return graph().unique(new LogicNegationNode(isNull));
+ return TriState.TRUE;
}
} else {
if (objectStamp.isExactType()) {
// since this type check failed for an exact type we know that it can never
// succeed at run time. we also don't care about null values, since they will
// also make the check fail.
- return LogicConstantNode.contradiction(graph());
+ return TriState.FALSE;
} else {
boolean superType = stampType.isAssignableFrom(type());
if (!superType && !stampType.isInterface() && !type().isInterface()) {
- return LogicConstantNode.contradiction(graph());
+ return TriState.FALSE;
}
// since the subtype comparison was only performed on a declared type we don't
// really know if it might be true at run time...
}
}
}
- return this;
- }
-
- public ValueNode object() {
- return object;
+ return TriState.UNKNOWN;
}
/**
@@ -121,7 +138,7 @@
@Override
public void virtualize(VirtualizerTool tool) {
- State state = tool.getObjectState(object);
+ State state = tool.getObjectState(object());
if (state != null) {
tool.replaceWithValue(LogicConstantNode.forBoolean(type().isAssignableFrom(state.getVirtualObject().type()), graph()));
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java Tue Apr 29 18:23:17 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2009, 2011, 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 com.oracle.graal.nodes.java;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * Loads an exception object passed by the runtime from a callee to an exception handler in a
- * caller. The node is only produced when lowering an {@link ExceptionObjectNode}.
- *
- * The frame state upon entry to an exception handler is such that it is a
- * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly the
- * exception object (per the JVM spec) to rethrow. This means that the code generated for this node
- * must not cause a deoptimization as the runtime/interpreter would not have a valid location to
- * find the exception object to be rethrown.
- */
-public class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable {
-
- public LoadExceptionObjectNode(Stamp stamp) {
- super(stamp);
- }
-
- @Override
- public void lower(LoweringTool tool) {
- tool.getLowerer().lower(this, tool);
- }
-}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java Tue Apr 29 18:35:10 2014 +0200
@@ -22,13 +22,14 @@
*/
package com.oracle.graal.nodes.spi;
+import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
/**
* Interface implemented by nodes that can replace themselves with lower level nodes during a phase
* that transforms a graph to replace higher level nodes with lower level nodes.
*/
-public interface Lowerable {
+public interface Lowerable extends NodeInterface {
/**
* Expand this node into lower level nodes expressing the same semantics. If the introduced
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerable.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerable.java Tue Apr 29 18:23:17 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 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 com.oracle.graal.nodes.spi;
-
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * Marks nodes which may be lowered in combination with a memory operation.
- */
-public interface MemoryArithmeticLIRLowerable {
-
- /**
- * Attempt to generate a memory form of a node operation. On platforms that support it this will
- * be called when the merging is safe.
- *
- * @param gen
- * @param access the memory input which can potentially merge into this operation.
- * @return null if it's not possible to emit a memory form of this operation. A non-null value
- * will be set as the operand of this node.
- */
- boolean generate(MemoryArithmeticLIRLowerer gen, Access access);
-}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerer.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerer.java Tue Apr 29 18:23:17 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 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 com.oracle.graal.nodes.spi;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * This interface can be used to generate LIR for arithmetic operations where one of the operations
- * is load (@see ArithmeticLIRLowerable).
- */
-public interface MemoryArithmeticLIRLowerer {
-
- Value setResult(ValueNode x, Value operand);
-
- Value emitAddMemory(ValueNode x, ValueNode y, Access access);
-
- Value emitMulMemory(ValueNode x, ValueNode y, Access access);
-
- Value emitSubMemory(ValueNode x, ValueNode y, Access access);
-
- Value emitDivMemory(ValueNode x, ValueNode y, Access access);
-
- Value emitRemMemory(ValueNode x, ValueNode y, Access access);
-
- Value emitXorMemory(ValueNode x, ValueNode y, Access access);
-
- Value emitOrMemory(ValueNode x, ValueNode y, Access access);
-
- Value emitAndMemory(ValueNode x, ValueNode y, Access access);
-
- Value emitReinterpretMemory(Stamp stamp, Access access);
-
- Value emitSignExtendMemory(Access access, int fromBits, int toBits);
-
- Value emitNarrowMemory(int resultBits, Access access);
-
- Value emitZeroExtendMemory(int inputBits, int resultBits, Access access);
-
- Value emitFloatConvertMemory(FloatConvert op, Access access);
-
- boolean memoryPeephole(Access valueNode, MemoryArithmeticLIRLowerable operation, List deferred);
-
- boolean emitIfMemory(IfNode ifNode, Access access);
-
-}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java Tue Apr 29 18:35:10 2014 +0200
@@ -26,10 +26,12 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.cfg.*;
import com.oracle.graal.lir.*;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.cfg.*;
import com.oracle.graal.nodes.extended.*;
public interface NodeLIRBuilderTool extends NodeMappableLIRBuilder {
@@ -68,5 +70,13 @@
Value[] visitInvokeArguments(CallingConvention cc, Collection arguments);
- MemoryArithmeticLIRLowerer getMemoryLowerer();
+ Variable newVariable(Kind kind);
+
+ void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
+
+ void emitBitCount(Variable result, Value operand);
+
+ void emitBitScanForward(Variable result, Value operand);
+
+ void doBlock(Block block, StructuredGraph graph, BlockMap> blockMap);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java Tue Apr 29 18:35:10 2014 +0200
@@ -29,9 +29,7 @@
/**
* Interface for nodes which have {@link FrameState} nodes as input.
*/
-public interface NodeWithState {
-
- Node asNode();
+public interface NodeWithState extends NodeInterface {
default NodeIterable states() {
return asNode().inputs().filter(FrameState.class);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ReplacementsProvider.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ReplacementsProvider.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ReplacementsProvider.java Tue Apr 29 18:35:10 2014 +0200
@@ -24,11 +24,12 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
/**
* Interface for service providers that register replacements with the compiler.
*/
public interface ReplacementsProvider {
- void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, Replacements replacements, TargetDescription target);
+ void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java Tue Apr 29 18:35:10 2014 +0200
@@ -506,22 +506,22 @@
}
/**
- * Returns the {@linkplain ResolvedJavaType java type} this {@linkplain ValueNode} has if it is
+ * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain ValueNode} has if it is
* a {@linkplain Stamp#isLegal() legal} Object value.
*
* @param node the node to check
- * @return the javat type this value has if it is a legal Object type, null otherwise
+ * @return the Java type this value has if it is a legal Object type, null otherwise
*/
public static ResolvedJavaType typeOrNull(ValueNode node) {
return typeOrNull(node.stamp());
}
/**
- * Returns the {@linkplain ResolvedJavaType java type} this {@linkplain Stamp} has if it is a
+ * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain Stamp} has if it is a
* {@linkplain Stamp#isLegal() legal} Object stamp.
*
* @param stamp the stamp to check
- * @return the java type this stamp has if it is a legal Object stamp, null otherwise
+ * @return the Java type this stamp has if it is a legal Object stamp, null otherwise
*/
public static ResolvedJavaType typeOrNull(Stamp stamp) {
if (stamp instanceof ObjectStamp && stamp.isLegal()) {
@@ -532,12 +532,12 @@
/**
* Checks whether this {@link ValueNode} represents a {@linkplain Stamp#isLegal() legal} Object
- * value whose java type is known exactly. If this method returns true then the
- * {@linkplain ResolvedJavaType java type} returned by {@link #typeOrNull(ValueNode)} is the
- * concrete dynamic/runtime java type of this value.
+ * value whose Java type is known exactly. If this method returns true then the
+ * {@linkplain ResolvedJavaType Java type} returned by {@link #typeOrNull(ValueNode)} is the
+ * concrete dynamic/runtime Java type of this value.
*
* @param node the node to check
- * @return true if this node represents a legal object value whose java type is known exactly
+ * @return true if this node represents a legal object value whose Java type is known exactly
*/
public static boolean isExactType(ValueNode node) {
return isExactType(node.stamp());
@@ -545,12 +545,12 @@
/**
* Checks whether this {@link Stamp} represents a {@linkplain Stamp#isLegal() legal} Object
- * stamp whose {@linkplain ResolvedJavaType java type} is known exactly. If this method returns
- * true then the java type returned by {@link #typeOrNull(Stamp)} is the only concrete
- * dynamic/runtime java type possible for values of this stamp.
+ * stamp whose {@linkplain ResolvedJavaType Java type} is known exactly. If this method returns
+ * true then the Java type returned by {@link #typeOrNull(Stamp)} is the only concrete
+ * dynamic/runtime Java type possible for values of this stamp.
*
* @param stamp the stamp to check
- * @return true if this node represents a legal object stamp whose java type is known exactly
+ * @return true if this node represents a legal object stamp whose Java type is known exactly
*/
public static boolean isExactType(Stamp stamp) {
if (stamp instanceof ObjectStamp && stamp.isLegal()) {
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Tue Apr 29 18:35:10 2014 +0200
@@ -27,6 +27,7 @@
import com.oracle.graal.api.meta.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.graph.spi.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.calc.*;
import com.oracle.graal.nodes.java.*;
@@ -42,12 +43,12 @@
}
};
- public static void killCFG(Node node) {
+ public static void killCFG(Node node, SimplifierTool tool) {
assert node.isAlive();
if (node instanceof AbstractEndNode) {
// We reached a control flow end.
AbstractEndNode end = (AbstractEndNode) node;
- killEnd(end);
+ killEnd(end, tool);
} else {
// Normal control flow node.
/*
@@ -57,13 +58,17 @@
* while processing one branch.
*/
for (Node successor : node.successors()) {
- killCFG(successor);
+ killCFG(successor, tool);
}
}
propagateKill(node);
}
- private static void killEnd(AbstractEndNode end) {
+ public static void killCFG(Node node) {
+ killCFG(node, null);
+ }
+
+ private static void killEnd(AbstractEndNode end, SimplifierTool tool) {
MergeNode merge = end.merge();
if (merge != null) {
merge.removeEnd(end);
@@ -85,12 +90,17 @@
killCFG(loopBody);
}
begin.safeDelete();
- } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { // not
- // a
- // loop
- // anymore
+ } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) {
+ // not a loop anymore
+ if (tool != null) {
+ merge.phis().forEach(phi -> phi.usages().forEach(usage -> tool.addToWorkList(usage)));
+ }
graph.reduceDegenerateLoopBegin((LoopBeginNode) merge);
- } else if (merge.phiPredecessorCount() == 1) { // not a merge anymore
+ } else if (merge.phiPredecessorCount() == 1) {
+ // not a merge anymore
+ if (tool != null) {
+ merge.phis().forEach(phi -> phi.usages().forEach(usage -> tool.addToWorkList(usage)));
+ }
graph.reduceTrivialMerge(merge);
}
}
@@ -333,6 +343,14 @@
return v;
}
+ public static boolean tryKillUnused(Node node) {
+ if (node.isAlive() && isFloatingNode().apply(node) && node.recordsUsages() && node.usages().isEmpty()) {
+ killWithUnusedFloatingInputs(node);
+ return true;
+ }
+ return false;
+ }
+
/**
* Exhaustive search for {@link GraphUtil#originalValue(ValueNode)} when a simple search fails.
* This can happen in the presence of complicated phi/proxy/phi constructs.
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java
--- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java Tue Apr 29 18:35:10 2014 +0200
@@ -40,8 +40,10 @@
*
*
* ServiceLoader<Options> sl = ServiceLoader.loadInstalled(Options.class);
- * for (OptionDescriptor desc : sl) {
- * // use desc
+ * for (Options opts : sl) {
+ * for (OptionDescriptor desc : sl) {
+ * // use desc
+ * }
* }
*
*/
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Tue Apr 29 18:35:10 2014 +0200
@@ -178,7 +178,7 @@
}
StructuredGraph graph = (StructuredGraph) node.graph();
Mark mark = graph.getMark();
- if (!tryKillUnused(node)) {
+ if (!GraphUtil.tryKillUnused(node)) {
if (!tryCanonicalize(node, nodeClass)) {
if (node instanceof ValueNode) {
ValueNode valueNode = (ValueNode) node;
@@ -200,14 +200,6 @@
}
}
- private static boolean tryKillUnused(Node node) {
- if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.recordsUsages() && node.usages().isEmpty()) {
- GraphUtil.killWithUnusedFloatingInputs(node);
- return true;
- }
- return false;
- }
-
public static boolean tryGlobalValueNumbering(Node node, NodeClass nodeClass) {
if (nodeClass.valueNumberable() && !nodeClass.isLeafNode()) {
Node newNode = node.graph().findDuplicate(node);
@@ -354,7 +346,7 @@
@Override
public void deleteBranch(Node branch) {
branch.predecessor().replaceFirstSuccessor(branch, null);
- GraphUtil.killCFG(branch);
+ GraphUtil.killCFG(branch, this);
}
/**
@@ -383,7 +375,7 @@
@Override
public void removeIfUnused(Node node) {
- tryKillUnused(node);
+ GraphUtil.tryKillUnused(node);
}
@Override
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Tue Apr 29 18:35:10 2014 +0200
@@ -1316,8 +1316,6 @@
assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal();
assert !invokeNode.graph().isAfterFloatingReadPhase() : "inline isn't handled correctly after floating reads phase";
- Kind returnKind = invokeNode.getKind();
-
FrameState stateAfter = invoke.stateAfter();
assert stateAfter == null || stateAfter.isAlive();
if (receiverNullCheck && !((MethodCallTargetNode) invoke.callTarget()).isStatic()) {
@@ -1401,38 +1399,8 @@
}
if (stateAfter != null) {
- FrameState outerFrameState = null;
+ processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge);
int callerLockDepth = stateAfter.nestedLockDepth();
- for (FrameState original : inlineGraph.getNodes(FrameState.class)) {
- FrameState frameState = (FrameState) duplicates.get(original);
- if (frameState != null && frameState.isAlive()) {
- assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
- if (frameState.bci == BytecodeFrame.AFTER_BCI) {
- frameState.replaceAndDelete(returnKind == Kind.Void ? stateAfter : stateAfter.duplicateModified(stateAfter.bci, stateAfter.rethrowException(), returnKind,
- frameState.stackAt(0)));
- } else if (frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.method().isSynchronized())) {
- if (stateAtExceptionEdge != null) {
- frameState.replaceAndDelete(stateAtExceptionEdge);
- } else {
- handleMissingAfterExceptionFrameState(frameState);
- }
- } else if (frameState.bci == BytecodeFrame.UNWIND_BCI) {
- handleMissingAfterExceptionFrameState(frameState);
- } else {
- // only handle the outermost frame states
- if (frameState.outerFrameState() == null) {
- assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method());
- assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && frameState.bci != BytecodeFrame.BEFORE_BCI && frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI &&
- frameState.bci != BytecodeFrame.UNWIND_BCI : frameState.bci;
- if (outerFrameState == null) {
- outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invokeNode.getKind());
- outerFrameState.setDuringCall(true);
- }
- frameState.setOuterFrameState(outerFrameState);
- }
- }
- }
- }
if (callerLockDepth != 0) {
for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.class)) {
MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original);
@@ -1470,10 +1438,61 @@
return duplicates;
}
- protected static void handleMissingAfterExceptionFrameState(FrameState nonReplacableFrameState) {
- Graph graph = nonReplacableFrameState.graph();
+ protected static void processFrameStates(Invoke invoke, StructuredGraph inlineGraph, Map duplicates, FrameState stateAtExceptionEdge) {
+ FrameState stateAtReturn = invoke.stateAfter();
+ FrameState outerFrameState = null;
+ Kind invokeReturnKind = invoke.asNode().getKind();
+ for (FrameState original : inlineGraph.getNodes(FrameState.class)) {
+ FrameState frameState = (FrameState) duplicates.get(original);
+ if (frameState != null && frameState.isAlive()) {
+ if (frameState.bci == BytecodeFrame.AFTER_BCI) {
+ /*
+ * pop return kind from invoke's stateAfter and replace with this frameState's
+ * return value (top of stack)
+ */
+ FrameState stateAfterReturn = stateAtReturn;
+ if (invokeReturnKind != Kind.Void && frameState.stackSize() > 0 && stateAfterReturn.stackAt(0) != frameState.stackAt(0)) {
+ stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, frameState.stackAt(0));
+ }
+ frameState.replaceAndDelete(stateAfterReturn);
+ } else if (stateAtExceptionEdge != null && isStateAfterException(frameState)) {
+ /*
+ * pop exception object from invoke's stateAfter and replace with this
+ * frameState's exception object (top of stack)
+ */
+ FrameState stateAfterException = stateAtExceptionEdge;
+ if (frameState.stackSize() > 0 && stateAtExceptionEdge.stackAt(0) != frameState.stackAt(0)) {
+ stateAfterException = stateAtExceptionEdge.duplicateModified(Kind.Object, frameState.stackAt(0));
+ }
+ frameState.replaceAndDelete(stateAfterException);
+ } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
+ handleMissingAfterExceptionFrameState(frameState);
+ } else {
+ // only handle the outermost frame states
+ if (frameState.outerFrameState() == null) {
+ assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
+ assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method());
+ assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && frameState.bci != BytecodeFrame.BEFORE_BCI && frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI &&
+ frameState.bci != BytecodeFrame.UNWIND_BCI : frameState.bci;
+ if (outerFrameState == null) {
+ outerFrameState = stateAtReturn.duplicateModified(invoke.bci(), stateAtReturn.rethrowException(), invokeReturnKind);
+ outerFrameState.setDuringCall(true);
+ }
+ frameState.setOuterFrameState(outerFrameState);
+ }
+ }
+ }
+ }
+ }
+
+ private static boolean isStateAfterException(FrameState frameState) {
+ return frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.method().isSynchronized());
+ }
+
+ protected static void handleMissingAfterExceptionFrameState(FrameState nonReplaceableFrameState) {
+ Graph graph = nonReplaceableFrameState.graph();
NodeWorkList workList = graph.createNodeWorkList();
- workList.add(nonReplacableFrameState);
+ workList.add(nonReplaceableFrameState);
for (Node node : workList) {
FrameState fs = (FrameState) node;
for (Node usage : fs.usages().snapshot()) {
@@ -1494,7 +1513,10 @@
GraphUtil.killCFG(end);
}
} else {
- DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+ FixedNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+ if (fixedStateSplit instanceof BeginNode) {
+ deoptimizeNode = BeginNode.begin(deoptimizeNode);
+ }
fixedStateSplit.replaceAtPredecessor(deoptimizeNode);
GraphUtil.killCFG(fixedStateSplit);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java Tue Apr 29 18:35:10 2014 +0200
@@ -62,7 +62,7 @@
canonicalizer.applyIncremental(graph, context, listener.getChangedNodes());
listener.getChangedNodes().clear();
if (++count > MAX_ITERATIONS) {
- throw new BailoutException("Number of iterations in conditional elimination phase exceeds " + MAX_ITERATIONS);
+ throw new BailoutException("Number of iterations in ConditionalEliminationPhase phase exceeds " + MAX_ITERATIONS);
}
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Tue Apr 29 18:35:10 2014 +0200
@@ -240,14 +240,20 @@
private final PhaseContext context;
private final SchedulePhase schedule;
+ private final int iteration;
private Round(int iteration, PhaseContext context) {
- super("LoweringIteration" + iteration);
+ this.iteration = iteration;
this.context = context;
this.schedule = new SchedulePhase();
}
@Override
+ protected CharSequence createName() {
+ return "LoweringIteration" + iteration;
+ }
+
+ @Override
public void run(StructuredGraph graph) {
schedule.apply(graph, false);
processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java Tue Apr 29 18:35:10 2014 +0200
@@ -55,8 +55,11 @@
private static final String GROUP_NAME = "~profiled weight";
private static final String GROUP_NAME_WITHOUT = "~profiled weight (invoke-free sections)";
+ private static final String GROUP_NAME_INVOKES = "~profiled invokes";
private static final boolean WITH_SECTION_HEADER = false;
+ private static boolean WITH_INVOKE_FREE_SECTIONS = false;
+ private static boolean WITH_INVOKES = true;
@Override
protected void run(StructuredGraph graph) {
@@ -72,7 +75,22 @@
addSectionCounters(loop.header.getBeginNode(), loop.blocks, loop.children, schedule, probabilities);
}
}
- addSectionCounters(graph.start(), Arrays.asList(cfg.getBlocks()), cfg.getLoops(), schedule, probabilities);
+ // don't put the counter increase directly after the start (problems with OSR)
+ FixedWithNextNode current = graph.start();
+ while (current.next() instanceof FixedWithNextNode) {
+ current = (FixedWithNextNode) current.next();
+ }
+ addSectionCounters(current, Arrays.asList(cfg.getBlocks()), cfg.getLoops(), schedule, probabilities);
+
+ if (WITH_INVOKES) {
+ for (Node node : graph.getNodes()) {
+ if (node instanceof Invoke) {
+ Invoke invoke = (Invoke) node;
+ DynamicCounterNode.addCounterBefore(GROUP_NAME_INVOKES, invoke.callTarget().targetName(), 1, true, invoke.asNode());
+
+ }
+ }
+ }
}
private static void addSectionCounters(FixedWithNextNode start, Collection sectionBlocks, Collection> childLoops, SchedulePhase schedule, NodesToDoubles probabilities) {
@@ -82,7 +100,7 @@
}
double weight = getSectionWeight(schedule, probabilities, blocks) / probabilities.get(start);
DynamicCounterNode.addCounterBefore(GROUP_NAME, sectionHead(start), (long) weight, true, start.next());
- if (!hasInvoke(blocks)) {
+ if (WITH_INVOKE_FREE_SECTIONS && !hasInvoke(blocks)) {
DynamicCounterNode.addCounterBefore(GROUP_NAME_WITHOUT, sectionHead(start), (long) weight, true, start.next());
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/BaseReduction.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/BaseReduction.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2012, 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 com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.spi.CanonicalizerTool;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.phases.graph.PostOrderNodeIterator;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+import java.util.ArrayList;
+
+/**
+ *
+ * For readability purposes the code realizing control-flow-sensitive reductions is chopped into
+ * several classes in an inheritance hierarchy, this class being their common ancestor. That way,
+ * many dependencies can be ruled out immediately (e.g., private members of a class aren't needed by
+ * other classes). The whole thing is reminiscent of trait-based patterns, minus their
+ * disadvantages.
+ *
+ *
+ *
+ *
+ * This class makes available little more than a few fields and a few utility methods used
+ * throughout the remaining components making up control-flow sensitive reductions.
+ *
+ */
+public abstract class BaseReduction extends PostOrderNodeIterator {
+
+ protected static final DebugMetric metricCheckCastRemoved = Debug.metric("CheckCastRemoved");
+ protected static final DebugMetric metricGuardingPiNodeRemoved = Debug.metric("GuardingPiNodeRemoved");
+ protected static final DebugMetric metricFixedGuardNodeRemoved = Debug.metric("FixedGuardNodeRemoved");
+ protected static final DebugMetric metricMethodResolved = Debug.metric("MethodResolved");
+
+ /**
+ *
+ * Upon visiting a {@link com.oracle.graal.nodes.FixedNode FixedNode} in
+ * {@link #node(com.oracle.graal.nodes.FixedNode)}, an impossible path may be detected. We'd
+ * like to insert an unconditional deoptimizing node as a hint for Dead Code Elimination to kill
+ * that branch. However that can't be made on the go (a
+ * {@link com.oracle.graal.nodes.ControlSinkNode} can't have successors). Thus their insertion
+ * is postponed till the end of a round of
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction}.
+ *
+ *
+ * @see State#impossiblePath()
+ * @see com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#finished()
+ */
+ public static class PostponedDeopt {
+
+ private final boolean goesBeforeFixed;
+ private final FixedWithNextNode fixed;
+ private final DeoptimizationReason deoptReason;
+
+ public PostponedDeopt(boolean goesBeforeFixed, FixedWithNextNode fixed, DeoptimizationReason deoptReason) {
+ this.goesBeforeFixed = goesBeforeFixed;
+ this.fixed = fixed;
+ this.deoptReason = deoptReason;
+ }
+
+ public void doRewrite(LogicNode falseConstant) {
+ StructuredGraph graph = fixed.graph();
+ // have to insert a FixedNode other than a ControlSinkNode
+ FixedGuardNode buckStopsHere = graph.add(new FixedGuardNode(falseConstant, deoptReason, DeoptimizationAction.None));
+ if (goesBeforeFixed) {
+ fixed.replaceAtPredecessor(buckStopsHere);
+ } else {
+ graph.addAfterFixed(fixed, buckStopsHere);
+ }
+ }
+
+ }
+
+ protected static class PostponedDeopts extends ArrayList {
+
+ private static final long serialVersionUID = 7188324432387121238L;
+
+ /**
+ * Enqueue adding a {@link com.oracle.graal.nodes.DeoptimizeNode} right before the fixed
+ * argument, will be done once we're done traversing the graph.
+ *
+ * @see #finished()
+ */
+ void addDeoptBefore(FixedWithNextNode fixed, DeoptimizationReason deoptReason) {
+ add(new PostponedDeopt(true, fixed, deoptReason));
+ }
+
+ /**
+ * Enqueue adding a {@link com.oracle.graal.nodes.DeoptimizeNode} right after the fixed
+ * argument, will be done once we're done traversing the graph.
+ *
+ * @see #finished()
+ */
+ void addDeoptAfter(FixedWithNextNode fixed, DeoptimizationReason deoptReason) {
+ add(new PostponedDeopt(false, fixed, deoptReason));
+ }
+
+ }
+
+ /**
+ *
+ * One of the promises of
+ * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)}
+ * is that a "maximally reduced" node is returned. That is achieved in part by leveraging
+ * {@link com.oracle.graal.graph.Node#canonical(com.oracle.graal.graph.spi.CanonicalizerTool)}.
+ * Doing so, in turn, requires this subclass of
+ * {@link com.oracle.graal.graph.spi.CanonicalizerTool}.
+ *
+ */
+ public final class Tool implements CanonicalizerTool {
+
+ private final PhaseContext context;
+
+ public Tool(PhaseContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public Assumptions assumptions() {
+ return context.getAssumptions();
+ }
+
+ @Override
+ public MetaAccessProvider getMetaAccess() {
+ return context.getMetaAccess();
+ }
+
+ @Override
+ public ConstantReflectionProvider getConstantReflection() {
+ return context.getConstantReflection();
+ }
+
+ /**
+ * Postpone
+ * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)}
+ * until {@link FlowSensitiveReduction#finished()} for the reasons covered there.
+ */
+ @Override
+ public void removeIfUnused(Node node) {
+ // GraphUtil.tryKillUnused(node);
+ }
+
+ @Override
+ public boolean canonicalizeReads() {
+ return false;
+ }
+ } // end of class FlowSensitiveReduction.Tool
+
+ protected final LogicConstantNode trueConstant;
+ protected final LogicConstantNode falseConstant;
+ protected final ConstantNode nullConstant;
+
+ protected final CanonicalizerTool tool;
+ protected final StructuredGraph graph;
+
+ protected EquationalReasoner reasoner;
+
+ protected final PostponedDeopts postponedDeopts = new PostponedDeopts();
+
+ protected BaseReduction(FixedNode start, State initialState, PhaseContext context) {
+ super(start, initialState);
+ graph = start.graph();
+ trueConstant = LogicConstantNode.tautology(graph);
+ falseConstant = LogicConstantNode.contradiction(graph);
+ nullConstant = ConstantNode.defaultForKind(Kind.Object, graph); // ConstantNode.forObject(null,
+ // metaAccess, graph);
+ tool = new Tool(context);
+ reasoner = new EquationalReasoner(graph, tool, trueConstant, falseConstant, nullConstant);
+ }
+
+ /**
+ *
+ * Test whether the output's stamp is an upcast of that of the input. For example, upon
+ * replacing a CheckCastNode in
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#lowerCheckCastAnchorFriendlyWay(com.oracle.graal.nodes.java.CheckCastNode, com.oracle.graal.nodes.ValueNode)}
+ * we don't want to be left with an upcast, as it loses precision.
+ *
+ *
+ *
+ * As usual with object stamps, they can be compared along different dimensions (alwaysNull,
+ * etc.) It's enough for one such dimension to show precision loss for the end result to be
+ * reported as such.
+ *
+ *
+ */
+ protected static boolean precisionLoss(ValueNode input, ValueNode output) {
+ ObjectStamp inputStamp = (ObjectStamp) input.stamp();
+ ObjectStamp outputStamp = (ObjectStamp) output.stamp();
+ if (FlowUtil.isMorePrecise(inputStamp.type(), outputStamp.type())) {
+ return true;
+ }
+ if (lessThan(outputStamp.alwaysNull(), inputStamp.alwaysNull())) {
+ return true;
+ }
+ if (lessThan(outputStamp.nonNull(), inputStamp.nonNull())) {
+ return true;
+ }
+ if (lessThan(outputStamp.isExactType(), inputStamp.isExactType())) {
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean lessThan(boolean a, boolean b) {
+ return a == false && b == true;
+ }
+
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CastCheckExtractor.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CastCheckExtractor.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2012, 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 com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.nodes.LogicNode;
+import com.oracle.graal.nodes.ShortCircuitOrNode;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.java.InstanceOfNode;
+
+/**
+ * @see #extract(com.oracle.graal.nodes.LogicNode)
+ */
+class CastCheckExtractor {
+
+ public final ResolvedJavaType type;
+ public final ValueNode subject;
+
+ CastCheckExtractor(ResolvedJavaType type, ValueNode subject) {
+ this.type = type;
+ this.subject = subject;
+ }
+
+ private static CastCheckExtractor extractCastCheckInfo(LogicNode x, LogicNode y) {
+ if (x instanceof IsNullNode) {
+ IsNullNode isNull = (IsNullNode) x;
+ ValueNode subject = isNull.object();
+ if (isInstanceOfCheckOn(y, subject)) {
+ InstanceOfNode iOf = (InstanceOfNode) y;
+ return new CastCheckExtractor(iOf.type(), subject);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * This method detects whether the argument realizes the CheckCast pattern. If so, distills and
+ * returns the essentials of such check, otherwise returns null.
+ */
+ static CastCheckExtractor extract(LogicNode cond) {
+ if (!(cond instanceof ShortCircuitOrNode)) {
+ return null;
+ }
+ ShortCircuitOrNode orNode = (ShortCircuitOrNode) cond;
+ if (orNode.isXNegated() || orNode.isYNegated()) {
+ return null;
+ }
+ CastCheckExtractor result = extractCastCheckInfo(orNode.getX(), orNode.getY());
+ if (result != null) {
+ return result;
+ }
+ result = extractCastCheckInfo(orNode.getY(), orNode.getX());
+ return result;
+ }
+
+ /**
+ * Porcelain method.
+ */
+ static boolean isInstanceOfCheckOn(LogicNode cond, ValueNode subject) {
+ if (!(cond instanceof InstanceOfNode)) {
+ return false;
+ }
+ InstanceOfNode io = (InstanceOfNode) cond;
+ return io.object() == subject;
+ }
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2012, 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 com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+import static com.oracle.graal.api.meta.DeoptimizationAction.InvalidateReprofile;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
+
+/**
+ *
+ * This class implements control-flow sensitive reductions for
+ * {@link com.oracle.graal.nodes.java.CheckCastNode}.
+ *
+ * This phase is able to refine the types of reference-values at use sites provided a
+ * {@link com.oracle.graal.nodes.extended.GuardingNode GuardingNode} is available witnessing
+ * that fact.
+ *
+ *
+ *
+ * This method turns non-redundant {@link com.oracle.graal.nodes.java.CheckCastNode}s into
+ * {@link com.oracle.graal.nodes.GuardingPiNode}s. Once such lowering has been performed (during
+ * run N of this phase) follow-up runs attempt to further simplify the resulting node, see
+ * {@link EquationalReasoner#downcastGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode, Witness)}
+ * and {@link #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}
+ *
+ *
+ *
+ * Precondition: the inputs (ie, object) hasn't been deverbosified yet.
+ *
+ */
+ protected final void visitCheckCastNode(CheckCastNode checkCast) {
+
+ /*
+ * checkCast.object() hasn't been deverbosified yet.
+ */
+
+ if (!FlowUtil.hasLegalObjectStamp(checkCast)) {
+ // This situation is exercised by test Class_cast01
+ return;
+ }
+
+ final ValueNode subject = checkCast.object();
+ final ResolvedJavaType toType = checkCast.type();
+ ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
+ ResolvedJavaType subjectType = subjectStamp.type();
+
+ // --------- checkCast deemed redundant by subject-stamp alone ---------
+ // --------- in particular due to stamp informing always null ----------
+ boolean isRedundantPerStamp = StampTool.isObjectAlwaysNull(subject) || (subjectType != null && toType.isAssignableFrom(subjectType));
+ if (isRedundantPerStamp) {
+ metricCheckCastRemoved.increment();
+ checkCast.replaceAtUsages(subject);
+ graph.removeFixed(checkCast);
+ return;
+ }
+
+ assert !StampTool.isObjectAlwaysNull(subject) : "Null as per stamp subjects should have been handled above";
+
+ // --------- checkCast deemed unsatisfiable by subject-stamp alone ---------
+ if (state.knownNotToConform(subject, toType)) {
+ postponedDeopts.addDeoptBefore(checkCast, checkCast.isForStoreCheck() ? ArrayStoreException : ClassCastException);
+ state.impossiblePath();
+ // let FixedGuardNode(false).simplify() prune the dead-code control-path
+ return;
+ }
+
+ /*
+ * Remark: subject may be TypeProxyNode, GuardedValueNode, ProxyNode, GuardingPiNode, among
+ * others.
+ */
+
+ PiNode untrivialNull = reasoner.nonTrivialNull(subject);
+ if (untrivialNull != null) {
+ metricCheckCastRemoved.increment();
+ checkCast.replaceAtUsages(untrivialNull);
+ graph.removeFixed(checkCast);
+ return;
+ }
+
+ Witness w = state.typeInfo(subject);
+
+ if (w == null) {
+ /*
+ * If there's no witness, attempting `downcast(subject)` is futile.
+ */
+ visitCheckCastNodeLackingWitness(checkCast);
+ return;
+ }
+
+ visitCheckCastNodeWithWitness(checkCast);
+
+ }
+
+ /**
+ * Given that no witness is available for the {@link com.oracle.graal.nodes.java.CheckCastNode}
+ * 's subject there's no point in downcasting such subject, ie no
+ * {@link com.oracle.graal.nodes.PiNode} can be fabricated for the subject.
+ *
+ * @see #lowerCheckCastAnchorFriendlyWay(com.oracle.graal.nodes.java.CheckCastNode,
+ * com.oracle.graal.nodes.ValueNode)
+ *
+ */
+ private void visitCheckCastNodeLackingWitness(CheckCastNode checkCast) {
+ final ValueNode subject = checkCast.object();
+ final ResolvedJavaType toType = checkCast.type();
+ if (toType.isInterface()) {
+ return;
+ }
+ assert reasoner.downcast(subject) == subject;
+ lowerCheckCastAnchorFriendlyWay(checkCast, subject);
+ }
+
+ /**
+ * Porcelain method.
+ *
+ *
+ * Rather than tracking the CheckCastNode via {@link com.oracle.graal.phases.common.cfs.State
+ * State} (doing so woud add a special case because a
+ * {@link com.oracle.graal.nodes.java.CheckCastNode} isn't a
+ * {@link com.oracle.graal.nodes.extended.GuardingNode}) this method creates an anchor by
+ * lowering the CheckCastNode into a FixedGuardNode. Not the same way as done by
+ * {@link com.oracle.graal.nodes.java.CheckCastNode#lower(com.oracle.graal.nodes.spi.LoweringTool)}
+ * which lowers into a {@link com.oracle.graal.nodes.GuardingPiNode} (which is not a
+ * {@link com.oracle.graal.nodes.extended.GuardingNode}).
+ *
+ *
+ *
+ * With that, state tracking can proceed as usual.
+ *
+ *
+ * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+ *
+ */
+ public void lowerCheckCastAnchorFriendlyWay(CheckCastNode checkCast, ValueNode subject) {
+ ValueNode originalCheckCastObject = checkCast.object();
+
+ ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
+ final ResolvedJavaType toType = checkCast.type();
+ ObjectStamp resultStamp = (ObjectStamp) StampFactory.declared(toType);
+ JavaTypeProfile profile = checkCast.profile();
+
+ assert FlowUtil.isLegalObjectStamp(subjectStamp);
+ assert subjectStamp.type() == null || !toType.isAssignableFrom(subjectStamp.type()) : "No need to lower in an anchor-friendly way in the first place";
+
+ /*
+ * Depending on what is known about the subject:
+ *
+ * (a) definitely-non-null
+ *
+ * (b) null-not-seen-in-profiling
+ *
+ * (c) runtime-null-check-needed
+ *
+ * the condition (of the cast-guard to be emitted) and the stamp (of the PiNode to be
+ * emitted) are going to be different. Each of the three branches below deals with one of
+ * the cases above.
+ */
+ LogicNode condition;
+ if (subjectStamp.nonNull()) {
+ /*
+ * (1 of 3) definitely-non-null
+ */
+ // addWithoutUnique for the same reason as in CheckCastNode.lower()
+ condition = graph.addWithoutUnique(new InstanceOfNode(toType, subject, profile));
+ reasoner.added.add(condition);
+ resultStamp = FlowUtil.asNonNullStamp(resultStamp);
+ // TODO fix in CheckCastNode.lower()
+ } else {
+ if (profile != null && profile.getNullSeen() == ProfilingInfo.TriState.FALSE) {
+ /*
+ * (2 of 3) null-not-seen-in-profiling
+ */
+ IsNullNode isNN = graph.unique(new IsNullNode(subject));
+ reasoner.added.add(isNN);
+ FixedGuardNode nullCheck = graph.add(new FixedGuardNode(isNN, UnreachedCode, InvalidateReprofile, true));
+ graph.addBeforeFixed(checkCast, nullCheck);
+ // not calling wrapInPiNode() because we don't want to rememberSubstitution()
+ PiNode nonNullGuarded = graph.unique(new PiNode(subject, FlowUtil.asNonNullStamp(subjectStamp), nullCheck));
+ reasoner.added.add(nonNullGuarded);
+ // addWithoutUnique for the same reason as in CheckCastNode.lower()
+ condition = graph.addWithoutUnique(new InstanceOfNode(toType, nonNullGuarded, profile));
+ reasoner.added.add(condition);
+ resultStamp = FlowUtil.asNonNullStamp(resultStamp);
+ } else {
+ /*
+ * (3 of 3) runtime-null-check-needed
+ */
+ // addWithoutUnique for the same reason as in CheckCastNode.lower()
+ InstanceOfNode typeTest = graph.addWithoutUnique(new InstanceOfNode(toType, subject, profile));
+ reasoner.added.add(typeTest);
+ LogicNode nullTest = graph.unique(new IsNullNode(subject));
+ reasoner.added.add(nullTest);
+ // TODO (ds) replace with probability of null-seen when available
+ final double shortCircuitProbability = NOT_FREQUENT_PROBABILITY;
+ condition = LogicNode.or(nullTest, typeTest, shortCircuitProbability);
+ reasoner.added.add(condition);
+ }
+ }
+
+ /*
+ * Add a cast-guard (checking only what needs to be checked) and a PiNode (to be used in
+ * place of the CheckCastNode).
+ */
+ FixedGuardNode castGuard = graph.add(new FixedGuardNode(condition, checkCast.isForStoreCheck() ? ArrayStoreException : ClassCastException, InvalidateReprofile));
+ graph.addBeforeFixed(checkCast, castGuard);
+
+ assert FlowUtil.isLegalObjectStamp(resultStamp);
+ Witness w = state.typeInfo(subject);
+ assert !isTypeOfWitnessBetter(w, resultStamp);
+
+ if (!FlowUtil.lacksUsages(checkCast)) {
+ // not calling wrapInPiNode() because we don't want to rememberSubstitution()
+ PiNode checkedObject = graph.unique(new PiNode(subject, resultStamp, castGuard));
+ reasoner.added.add(checkedObject);
+ assert !precisionLoss(originalCheckCastObject, checkedObject);
+ assert !precisionLoss(subject, checkedObject);
+ checkCast.replaceAtUsages(checkedObject);
+ }
+
+ graph.removeFixed(checkCast);
+
+ if (resultStamp.nonNull()) {
+ state.trackIO(subject, toType, castGuard);
+ } else {
+ state.trackCC(subject, toType, castGuard);
+ }
+ }
+
+ /**
+ * Porcelain method.
+ */
+ public static boolean isTypeOfWitnessBetter(Witness w, ObjectStamp stamp) {
+ if (w == null) {
+ return false;
+ }
+ return FlowUtil.isMorePrecise(w.type(), stamp.type());
+ }
+
+ /**
+ *
+ * Please note in this method "subject" refers to the downcasted input to the checkCast.
+ *
+ * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+ */
+ private void visitCheckCastNodeWithWitness(CheckCastNode checkCast) {
+
+ final ResolvedJavaType toType = checkCast.type();
+
+ ValueNode subject;
+ if (checkCast.object() instanceof CheckCastNode) {
+ subject = reasoner.downcast(checkCast);
+ if (subject == checkCast) {
+ subject = reasoner.downcast(checkCast.object());
+ }
+ } else {
+ subject = reasoner.downcast(checkCast.object());
+ }
+
+ ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
+ ResolvedJavaType subjectType = subjectStamp.type();
+
+ // TODO move this check to downcast()
+ assert !precisionLoss(checkCast.object(), subject);
+
+ /*
+ * At this point, two sources of (partial) information: the witness and the stamp of
+ * subject. The latter might be more precise than the witness (eg, subject might be
+ * GuardedValueNode)
+ */
+
+ // --------- checkCast made redundant by downcasting its input ---------
+ if (subjectType != null && toType.isAssignableFrom(subjectType)) {
+ checkCast.replaceAtUsages(subject);
+ graph.removeFixed(checkCast);
+ return;
+ }
+
+ /*
+ * At this point, `downcast()` might or might not have delivered a more precise value. If
+ * more precise, it wasn't precise enough to conform to `toType`. Even so, for the
+ * `toType.isInterface()` case (dealt with below) we'll replace the checkCast's input with
+ * that value (its class-stamp being more precise than the original).
+ */
+
+ if (toType.isInterface()) {
+ boolean wasDowncasted = (subject != checkCast.object());
+ if (wasDowncasted) {
+ FlowUtil.replaceInPlace(checkCast, checkCast.object(), subject);
+ }
+ return;
+ }
+
+ lowerCheckCastAnchorFriendlyWay(checkCast, subject);
+
+ }
+
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,946 @@
+/*
+ * Copyright (c) 2012, 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 com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.NodeBitMap;
+import com.oracle.graal.graph.spi.CanonicalizerTool;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.FloatingNode;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.calc.ObjectEqualsNode;
+import com.oracle.graal.nodes.extended.GuardedNode;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.nodes.java.CheckCastNode;
+import com.oracle.graal.nodes.java.InstanceOfNode;
+import com.oracle.graal.nodes.spi.ValueProxy;
+import com.oracle.graal.compiler.common.type.IllegalStamp;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.nodes.util.GraphUtil;
+
+import java.util.IdentityHashMap;
+import java.util.Set;
+
+/**
+ *
+ * This class implements a simple partial evaluator that recursively reduces a given
+ * {@link com.oracle.graal.nodes.calc.FloatingNode} into a simpler one based on the current state.
+ * Such evaluator comes handy when visiting a {@link com.oracle.graal.nodes.FixedNode} N, just
+ * before updating the state for N. At the pre-state, an {@link EquationalReasoner} can be used to
+ * reduce N's inputs (actually only those inputs of Value and Condition
+ * {@link com.oracle.graal.graph.InputType InputType}). For an explanation of where it's warranted
+ * to replace "old input" with "reduced input", see the inline comments in method
+ * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node n) deverbosify(Node n)}
+ *
+ *
+ *
+ * The name {@link EquationalReasoner EquationalReasoner} was chosen because it conveys what it
+ * does.
+ *
+ */
+public final class EquationalReasoner {
+
+ private static final DebugMetric metricInstanceOfRemoved = Debug.metric("InstanceOfRemoved");
+ private static final DebugMetric metricNullCheckRemoved = Debug.metric("NullCheckRemoved");
+ private static final DebugMetric metricObjectEqualsRemoved = Debug.metric("ObjectEqualsRemoved");
+ private static final DebugMetric metricEquationalReasoning = Debug.metric("EquationalReasoning");
+ private static final DebugMetric metricDowncasting = Debug.metric("Downcasting");
+
+ private final StructuredGraph graph;
+ private final CanonicalizerTool tool;
+ private final LogicConstantNode trueConstant;
+ private final LogicConstantNode falseConstant;
+ private final ConstantNode nullConstant;
+
+ private State state;
+ private NodeBitMap visited;
+
+ /**
+ * The reduction of a {@link com.oracle.graal.nodes.calc.FloatingNode} performed by
+ * {@link EquationalReasoner EquationalReasoner} may result in a FloatingNode being added to the
+ * graph. Those nodes aren't tracked in the {@link EquationalReasoner#visited visited}
+ * {@link com.oracle.graal.graph.NodeBitMap NodeBitMap} but in this set instead (those nodes are
+ * added after the {@link com.oracle.graal.graph.NodeBitMap} was obtained).
+ */
+ final Set added = java.util.Collections.newSetFromMap(new IdentityHashMap());
+
+ /**
+ * The reduction of a FloatingNode performed by {@link EquationalReasoner EquationalReasoner}
+ * may result in a FloatingNode being added to the graph. Those nodes are tracked in this map,
+ * to avoid recomputing them.
+ *
+ * The substitutions tracked in this field become invalid as described in
+ * {@link #updateState(com.oracle.graal.phases.common.cfs.State) updateState(State)}
+ */
+ private final IdentityHashMap substs = new IdentityHashMap<>();
+
+ public EquationalReasoner(StructuredGraph graph, CanonicalizerTool tool, LogicConstantNode trueConstant, LogicConstantNode falseConstant, ConstantNode nullConstant) {
+ this.graph = graph;
+ this.tool = tool;
+ this.trueConstant = trueConstant;
+ this.falseConstant = falseConstant;
+ this.nullConstant = nullConstant;
+ }
+
+ /**
+ * {@link #added} grows during a run of
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase
+ * FlowSensitiveReductionPhase}, and doesn't survive across runs.
+ */
+ public void forceState(State s) {
+ state = s;
+ substs.clear();
+ added.clear();
+ visited = null;
+ versionNrAsofLastForce = s.versionNr;
+ }
+
+ /**
+ *
+ * Gaining more precise type information about an SSA value doesn't "invalidate" as such any of
+ * the substitutions tracked in {@link EquationalReasoner#substs substs}, at least not in the
+ * sense of making the value tracked by one such entry "wrong". However, clearing the
+ * {@link EquationalReasoner#substs substs} is still justified because next time they are
+ * computed, the newly computed reduction could (in principle) be more effective (due to the
+ * more precise type information).
+ *
+ *
+ *
+ * Between clearings of cached substitutions, it is expected they get applied a number of times
+ * to justify the bookkeeping cost.
+ *
+ *
+ */
+ public void updateState(State s) {
+ assert s != null;
+ if (state == null || state != s || state.versionNr != versionNrAsofLastForce) {
+ forceState(s);
+ }
+ }
+
+ private int versionNrAsofLastForce = 0;
+
+ /**
+ * Reduce the argument based on the state at the program point where the argument is consumed.
+ * For most FixedNodes, that's how their inputs can be reduced. Two exceptions:
+ *
+ *
+ * the condition of a {@link com.oracle.graal.nodes.GuardingPiNode}, see
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}
+ *
+ *
+ * the condition of a {@link com.oracle.graal.nodes.FixedGuardNode}, see
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode)}
+ *
+ *
+ *
+ *
+ *
+ *
+ * Part of the reduction work is delegated to baseCase-style reducers, whose contract explicitly
+ * requires them not to deverbosify the argument's inputs --- the decision is made based on the
+ * argument only (thus "base case"). Returning the unmodified argument is how a baseCase-style
+ * tells this method to fall to the default case (for a floating node only: walk into the
+ * argument's inputs, canonicalize followed by
+ * {@link #rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)
+ * rememberSubstitution()} if any input changed).
+ *
+ *
+ *
+ * This method must behave as a function (idempotent query method), ie refrain from mutating the
+ * state other than updating caches:
+ *
{@link EquationalReasoner#visited EquationalReasoner#visited} and
+ *
the cache updated via
+ * {@link EquationalReasoner#rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)
+ * EquationalReasoner#rememberSubstitution(ValueNode, FloatingNode)}.
+ *
+ *
+ *
+ *
+ * In turn, baseCase-style reducers are even more constrained: besides behaving as functions,
+ * their contract prevents them from updating any caches (basically because they already grab
+ * the answer from caches, if the answer isn't there they should just return their unmodified
+ * argument).
+ *
+ *
+ *
+ * This method returns:
+ *
+ *
+ * the original argument, in case no reduction possible.
+ *
+ * a {@link com.oracle.graal.nodes.ValueNode ValueNode} different from the argument, in case the
+ * conditions for a reduction were met. The node being returned might be already in the graph.
+ * In any case it's canonicalized already, the caller need not perform that again.
+ *
+ * the unmodified argument, in case no reduction was made. Otherwise, a maximally reduced
+ * {@link com.oracle.graal.nodes.ValueNode}.
+ *
+ *
+ *
+ * @see com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#deverbosifyInputsInPlace(com.oracle.graal.nodes.ValueNode)
+ *
+ * @see com.oracle.graal.phases.common.cfs.BaseReduction.Tool
+ *
+ */
+ public Node deverbosify(final Node n) {
+
+ // --------------------------------------------------------------------
+ // cases that don't initiate any call-chain that may enter this method
+ // --------------------------------------------------------------------
+
+ if (n == null) {
+ return null;
+ }
+ assert !(n instanceof GuardNode) : "This phase not yet ready to run during MidTier";
+ if (!(n instanceof ValueNode)) {
+ return n;
+ }
+ ValueNode v = (ValueNode) n;
+ if (v.stamp() instanceof IllegalStamp) {
+ return v;
+ }
+ if (FlowUtil.isLiteralNode(v)) {
+ return v;
+ }
+ ValueNode result = substs.get(v);
+ if (result != null) {
+ // picked cached substitution
+ return result;
+ }
+ if ((visited != null && visited.contains(n)) || added.contains(v)) {
+ return v;
+ }
+
+ // --------------------------------------------------------------------
+ // stack overflow prevention via added, visited
+ // --------------------------------------------------------------------
+
+ if (visited == null) {
+ visited = graph.createNodeBitMap();
+ }
+ visited.mark(n);
+
+ /*
+ * Past this point, if we ever want `n` to be deverbosified, it must be looked-up by one of
+ * the cases above. One sure way to achieve that is with `rememberSubstitution(old, new)`
+ */
+ if (v instanceof ValueProxy) {
+ return downcast(v);
+ }
+
+ if (n instanceof FloatingNode) {
+ /*
+ * `deverbosifyFloatingNode()` will drill down over floating inputs, when that not
+ * possible anymore it resorts to calling `downcast()`. Thus it's ok to take the
+ * `deverbosifyFloatingNode()` route first, as no downcasting opportunity will be
+ * missed.
+ */
+ return deverbosifyFloatingNode((FloatingNode) n);
+ }
+
+ if (FlowUtil.hasLegalObjectStamp(v)) {
+ return downcast(v);
+ }
+
+ return n;
+ }
+
+ /**
+ * This method:
+ *
+ *
+ *
+ * Recurses only over floating inputs to attempt reductions, leave anything else as is.
+ *
+ * Performs copy-on-write aka lazy-DAG-copying as described in source comments, in-line.
+ *
+ * Usage: must be called only from {@link #deverbosify(com.oracle.graal.graph.Node)
+ * deverbosify(Node)}.
+ *
+ */
+ public Node deverbosifyFloatingNode(final FloatingNode n) {
+
+ assert n != null : "Should have been caught in deverbosify()";
+ assert !(n instanceof ValueProxy) : "Should have been caught in deverbosify()";
+ assert !FlowUtil.isLiteralNode(n) : "Should have been caught in deverbosify()";
+
+ if (n instanceof PhiNode) {
+ /*
+ * Each input to a PhiNode should be deverbosified with the state applicable to the path
+ * providing such input, as done in visitAbstractEndNode()
+ */
+ return n;
+ }
+
+ final FloatingNode f = baseCaseFloating(n);
+ if (f != n) {
+ return f;
+ }
+
+ FloatingNode changed = null;
+ for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(f)) {
+ /*
+ * Although deverbosify() is invoked below, it's only for floating inputs. That way, the
+ * state can't be used to make invalid conclusions.
+ */
+ Node j = (i instanceof FloatingNode) ? deverbosify(i) : i;
+ if (i != j) {
+ assert j != f;
+ if (changed == null) {
+ changed = (FloatingNode) f.copyWithInputs();
+ added.add(changed);
+ // copyWithInputs() implies graph.unique(changed)
+ assert changed.isAlive();
+ assert FlowUtil.lacksUsages(changed);
+ }
+ /*
+ * Note: we don't trade i for j at each usage of i (doing so would change meaning)
+ * but only at those usages consumed by `changed`. In turn, `changed` won't replace
+ * `n` at arbitrary usages, but only where such substitution is valid as per the
+ * state holding there. In practice, this means the buck stops at the "root"
+ * FixedNode on whose inputs deverbosify() is invoked for the first time, via
+ * deverbosifyInputsInPlace().
+ */
+ FlowUtil.replaceInPlace(changed, i, j);
+ }
+ }
+ if (changed == null) {
+ assert visited.contains(f) || added.contains(f);
+ if (FlowUtil.hasLegalObjectStamp(f)) {
+ /*
+ * No input has changed doesn't imply there's no witness to refine the
+ * floating-object value.
+ */
+ ValueNode d = downcast(f);
+ return d;
+ } else {
+ return f;
+ }
+ }
+ FlowUtil.inferStampAndCheck(changed);
+ added.add(changed);
+ ValueNode canon = (ValueNode) changed.canonical(tool);
+ // might be already in `added`, no problem adding it again.
+ added.add(canon);
+ rememberSubstitution(f, canon);
+ return canon;
+ }
+
+ /**
+ * In case of doubt (on whether a reduction actually triggered) it's always ok to invoke "
+ * rememberSubstitution(f, downcast(f))": this method records a map entry only if
+ * pre-image and image differ.
+ *
+ * @return the image of the substitution (ie, the second argument) unmodified.
+ */
+ private M rememberSubstitution(ValueNode from, M to) {
+ assert from != null && to != null;
+ if (from == to) {
+ return to;
+ }
+ // we don't track literals because they map to themselves
+ if (FlowUtil.isLiteralNode(from)) {
+ assert from == to;
+ return to;
+ }
+ /*
+ * It's ok for different keys (which were not unique in the graph after all) to map to the
+ * same value. However any given key can't map to different values.
+ */
+ ValueNode image = substs.get(from);
+ if (image != null) {
+ assert image == to;
+ return to;
+ }
+ substs.put(from, to);
+ return to;
+ }
+
+ /**
+ * The contract for this baseCase-style method is covered in
+ * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+ * EquationalReasoner#deverbosify()}
+ *
+ * @return a {@link com.oracle.graal.nodes.calc.FloatingNode} different from the argument, in
+ * case a reduction was made. The node being returned might be already in the graph. In
+ * any case it's canonicalized already, the caller need not perform that again. In case
+ * no reduction was made, this method returns the unmodified argument.
+ */
+ private FloatingNode baseCaseFloating(final FloatingNode f) {
+ if (f instanceof LogicNode) {
+ FloatingNode result = baseCaseLogicNode((LogicNode) f);
+ return rememberSubstitution(f, result);
+ }
+ return f;
+ }
+
+ /**
+ *
+ * Reduce the argument based on the state at the program point for it (ie, based on
+ * "valid facts" only, without relying on any floating-guard-assumption).
+ *
+ *
+ *
+ * The inputs of the argument aren't traversed into, for that
+ * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+ * EquationalReasoner#deverbosify()} should be used instead.
+ *
+ *
+ * This method must behave as a function (idempotent query method): it should refrain from
+ * changing the state, as well as from updating caches (other than DebugMetric-s).
+ *
+ *
+ * @return a {@link com.oracle.graal.nodes.LogicNode} different from the argument, in case a
+ * reduction was made. The node being returned might be already in the graph. In any
+ * case it's canonicalized already, the caller need not perform that again. In case no
+ * reduction was made, this method returns the unmodified argument.
+ *
+ */
+ public FloatingNode baseCaseLogicNode(LogicNode condition) {
+ assert condition != null;
+ if (condition instanceof LogicConstantNode) {
+ return condition;
+ } else if (state.trueFacts.containsKey(condition)) {
+ metricEquationalReasoning.increment();
+ return trueConstant;
+ } else if (state.falseFacts.containsKey(condition)) {
+ metricEquationalReasoning.increment();
+ return falseConstant;
+ } else {
+ if (condition instanceof InstanceOfNode) {
+ return baseCaseInstanceOfNode((InstanceOfNode) condition);
+ } else if (condition instanceof IsNullNode) {
+ return baseCaseIsNullNode((IsNullNode) condition);
+ } else if (condition instanceof ObjectEqualsNode) {
+ return baseCaseObjectEqualsNode((ObjectEqualsNode) condition);
+ }
+ }
+ return condition;
+ }
+
+ /**
+ * Actually the same result delivered by this method could be obtained by just letting
+ * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+ * EquationalReasoner#deverbosify()} handle the argument in the default case for floating nodes
+ * (ie, deverbosify inputs followed by canonicalize). However it's done here for metrics
+ * purposes.
+ *
+ * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was made;
+ * otherwise the unmodified argument.
+ *
+ */
+ private LogicNode baseCaseInstanceOfNode(InstanceOfNode instanceOf) {
+ ValueNode scrutinee = GraphUtil.unproxify(instanceOf.object());
+ if (!FlowUtil.hasLegalObjectStamp(scrutinee)) {
+ return instanceOf;
+ }
+ if (state.isNull(scrutinee)) {
+ metricInstanceOfRemoved.increment();
+ return falseConstant;
+ } else if (state.isNonNull(scrutinee) && state.knownToConform(scrutinee, instanceOf.type())) {
+ metricInstanceOfRemoved.increment();
+ return trueConstant;
+ }
+ return instanceOf;
+ }
+
+ /**
+ * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was
+ * performed; otherwise the unmodified argument.
+ *
+ */
+ private FloatingNode baseCaseIsNullNode(IsNullNode isNull) {
+ ValueNode object = isNull.object();
+ if (!FlowUtil.hasLegalObjectStamp(object)) {
+ return isNull;
+ }
+ ValueNode scrutinee = GraphUtil.unproxify(isNull.object());
+ GuardingNode evidence = nonTrivialNullAnchor(scrutinee);
+ if (evidence != null) {
+ metricNullCheckRemoved.increment();
+ return trueConstant;
+ } else if (state.isNonNull(scrutinee)) {
+ metricNullCheckRemoved.increment();
+ return falseConstant;
+ }
+ return isNull;
+ }
+
+ /**
+ * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was made;
+ * otherwise the unmodified argument.
+ */
+ private LogicNode baseCaseObjectEqualsNode(ObjectEqualsNode equals) {
+ if (!FlowUtil.hasLegalObjectStamp(equals.x()) || !FlowUtil.hasLegalObjectStamp(equals.y())) {
+ return equals;
+ }
+ ValueNode x = GraphUtil.unproxify(equals.x());
+ ValueNode y = GraphUtil.unproxify(equals.y());
+ if (state.isNull(x) && state.isNonNull(y) || state.isNonNull(x) && state.isNull(y)) {
+ metricObjectEqualsRemoved.increment();
+ return falseConstant;
+ } else if (state.isNull(x) && state.isNull(y)) {
+ metricObjectEqualsRemoved.increment();
+ return trueConstant;
+ }
+ return equals;
+ }
+
+ /**
+ * It's always ok to use "downcast(object)" instead of " object"
+ * because this method re-wraps the argument in a {@link com.oracle.graal.nodes.PiNode} only if
+ * the new stamp is strictly more refined than the original.
+ *
+ *
+ * This method does not
+ * {@link #rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)}
+ * .
+ *
+ *
+ * @return One of:
+ *
+ *
a {@link com.oracle.graal.nodes.PiNode} with more precise stamp than the input if
+ * the state warrants such downcasting
+ *
a {@link com.oracle.graal.nodes.java.CheckCastNode CheckCastNode} for the same
+ * scrutinee in question
+ *
the unmodified argument otherwise.
+ *
+ */
+ ValueNode downcast(final ValueNode object) {
+
+ // -------------------------------------------------
+ // actions based only on the stamp of the input node
+ // -------------------------------------------------
+
+ if (!FlowUtil.hasLegalObjectStamp(object)) {
+ return object;
+ }
+ if (FlowUtil.isLiteralNode(object)) {
+ return object;
+ }
+ if (StampTool.isObjectAlwaysNull(object.stamp())) {
+ return nonTrivialNull(object);
+ }
+
+ // ------------------------------------------
+ // actions based on the stamp and the witness
+ // ------------------------------------------
+
+ ValueNode scrutinee = GraphUtil.unproxify(object);
+
+ PiNode untrivialNull = nonTrivialNull(scrutinee);
+ if (untrivialNull != null) {
+ return untrivialNull;
+ }
+
+ Witness w = state.typeInfo(scrutinee);
+ if (w == null) {
+ // no additional hints being tracked for the scrutinee
+ return object;
+ }
+
+ assert !w.clueless();
+
+ ObjectStamp inputStamp = (ObjectStamp) object.stamp();
+ ObjectStamp witnessStamp = w.asStamp();
+ if (inputStamp.equals(witnessStamp) || !FlowUtil.isMorePrecise(witnessStamp, inputStamp)) {
+ // the witness offers no additional precision over current one
+ fixupTypeProfileStamp(object);
+ return object;
+ }
+
+ assert !FlowUtil.isMorePrecise(inputStamp.type(), w.type());
+
+ ValueNode result;
+ if (object instanceof ValueProxy) {
+ result = downcastValueProxy((ValueProxy) object, w);
+ } else {
+ result = downcastedUtil(object, w);
+ }
+
+ return result;
+ }
+
+ /**
+ * TODO TypeProfileProxyNode.inferStamp doesn't infer non-null from non-null payload
+ *
+ *
+ * And there's a bunch of asserts in
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase} that assert no
+ * type-precision gets lost. Thus the need to fix-up on our own, as done here.
+ *
+ * Utility to create, add to the graph,
+ * {@link EquationalReasoner#rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)}
+ * , and return a {@link com.oracle.graal.nodes.PiNode} that narrows into the given stamp,
+ * anchoring the payload.
+ *
+ *
+ *
+ * The resulting node might not have been in the graph already.
+ *
+ */
+ private PiNode wrapInPiNode(ValueNode payload, GuardingNode anchor, ObjectStamp newStamp, boolean remember) {
+ try (Debug.Scope s = Debug.scope("Downcast", payload)) {
+ assert payload != anchor : payload.graph().toString();
+ metricDowncasting.increment();
+ PiNode result = graph.unique(new PiNode(payload, newStamp, anchor.asNode()));
+ // we've possibly got a new node in the graph --- bookkeeping is in order.
+ added.add(result);
+ if (remember) {
+ rememberSubstitution(payload, result);
+ }
+ Debug.log("Downcasting from %s to %s", payload, result);
+ return result;
+ } catch (Throwable e) {
+ throw Debug.handle(e);
+ }
+ }
+
+ /**
+ *
+ * If the argument is known null due to its stamp, there's no need to have an anchor for that
+ * fact and this method returns null.
+ *
+ *
+ *
+ * Otherwise, if an anchor is found it is returned, null otherwise.
+ *
ValueProxys can be classified along two dimensions,
+ * in addition to the fixed-floating dichotomy.
+ *
+ *
+ * First, we might be interested in separating those ValueProxys
+ * that are entitled to change (usually narrow) their stamp from those that aren't.
+ * In the first category are:
+ * PiNode, PiArrayNode, GuardingPiNode,
+ * CheckCastNode, UnsafeCastNode, and
+ * GuardedValueNode.
+ *
+ *
+ *
+ * A note on stamp-narrowing ValueProxys:
+ * our state abstraction tracks only the type refinements induced by CheckCastNode and GuardingPiNode
+ * (which are fixed nodes, unlike the other stamp-narrowing ValueProxys;
+ * the reason being that the state abstraction can be updated only at fixed nodes).
+ * As a result, the witness for a (PiNode, PiArrayNode, UnsafeCastNode, or GuardedValueNode)
+ * may be less precise than the proxy's stamp. We don't want to lose such precision,
+ * thus downcast(proxy) == proxy in such cases.
+ *
+ *
+ *
+ * The second classification focuses on
+ * the additional information that travels with the proxy
+ * (in addition to its "payload", ie getOriginalValue(), and any narrowing-stamp).
+ * Such additional information boils down to:
+ *
+ * (a) type profile (TypeProfileProxyNode)
+ * (b) type profile (CheckCastNode)
+ * (c) anchor (GuardedValueNode)
+ * (d) anchor (PiNode)
+ * (e) anchor and array length (PiArrayNode)
+ * (f) optional anchor (UnsafeCastNode)
+ * (g) deopt-condition (GuardingPiNode)
+ * (h) LocationIdentity (MemoryProxyNOde)
+ * (i) control-flow dependency (FixedValueAnchorNode)
+ * (j) proxyPoint (ProxyNode -- think loops)
+ *
+ * Why would we want to downcast a GuardingPiNode? Is it even possible? Like, for example, a
+ * GuardingPiNode originating in the lowering of a CheckCastNode (carried out by
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+ * visitCheckCastNode()}).
+ *
+ *
+ *
+ * It's both possible and desirable. Example:
+ * Number n = (Number) o;
+ * if (n instanceof Integer) {
+ * return n.intValue();
+ * }
+ *
+ *
+ * The receiver of intValue() is a usage of a previous checkCast, for which the current witness
+ * provides a more refined type (and an anchor). In this case, the advantage of downcasting a
+ * GuardingPiNode is clear: devirtualizing the `intValue()` callsite.
+ *
+ *
+ * @see #downcastValueProxy
+ */
+ public ValueNode downcastGuardingPiNode(GuardingPiNode envelope, Witness w) {
+ assert envelope != w.guard().asNode() : "The stamp of " + envelope + " would lead to downcasting with that very same GuardingPiNode as guard.";
+ return downcastedUtil(envelope, w);
+ }
+
+ /**
+ *
+ * This method accepts both {@link com.oracle.graal.nodes.PiNode} and
+ * {@link com.oracle.graal.nodes.PiArrayNode} argument.
+ *
+ *
+ *
+ * In case a witness reveals a strictly more precise type than the
+ * {@link com.oracle.graal.nodes.PiNode}'s stamp, this method wraps the argument in a new
+ * {@link com.oracle.graal.nodes.PiNode} with updated stamp, and returns it.
+ *
+ *
+ *
+ * A {@link com.oracle.graal.nodes.PiArrayNode} argument ends up wrapped in a
+ * {@link com.oracle.graal.nodes.PiNode}. Thus, the
+ * {@link com.oracle.graal.nodes.PiArrayNode#length} information doesn't get lost.
+ *
+ *
+ *
+ * Note: {@link com.oracle.graal.nodes.PiNode}'s semantics allow un-packing its payload as soon
+ * as it type conforms to that of the {@link com.oracle.graal.nodes.PiNode} (that's what
+ * {@link com.oracle.graal.nodes.PiNode#canonical(com.oracle.graal.graph.spi.CanonicalizerTool)
+ * PiNode.canonical()} does). Not clear the benefits of duplicating that logic here.
+ *
+ * In a case the payload of the {@link com.oracle.graal.nodes.TypeProfileProxyNode} can be
+ * downcasted, this method returns a copy-on-write version with the downcasted payload.
+ *
+ *
+ *
+ * Otherwise returns the unmodified argument.
+ *
+ *
+ * @see #downcastValueProxy
+ */
+ private ValueNode downcastTypeProfileProxyNode(TypeProfileProxyNode envelope) {
+ ValueNode payload = envelope.getOriginalNode();
+ ValueNode d = downcast(payload);
+ if (payload != d) {
+ TypeProfileProxyNode changed = (TypeProfileProxyNode) envelope.copyWithInputs();
+ added.add(changed);
+ // copyWithInputs() implies graph.unique(changed)
+ FlowUtil.replaceInPlace(changed, payload, d);
+ FlowUtil.inferStampAndCheck(changed);
+ fixupTypeProfileStamp(changed);
+ /*
+ * It's not prudent to (1) obtain the canonical() of the (changed) TypeProfileProxyNode
+ * to (2) replace its usages; because we're potentially walking a DAG (after all,
+ * TypeProfileProxyNode is a floating-node). Those steps, which admittedly are needed,
+ * are better performed upon replacing in-place the inputs of a FixedNode, or during
+ * Canonicalize.
+ */
+ return changed;
+ }
+ fixupTypeProfileStamp(envelope);
+ return envelope;
+ }
+
+ /**
+ *
+ * Re-wrap the checkCast in a type-refining {@link com.oracle.graal.nodes.PiNode PiNode} only if
+ * the downcasted scrutinee does not conform to the checkCast's target-type.
+ *
+ * This method wraps the argument in a new {@link com.oracle.graal.nodes.PiNode PiNode} (created
+ * to hold an updated stamp) provided the argument's stamp can be strictly refined, and returns
+ * it.
+ *
+ */
+ private ValueNode downcastedUtil(ValueNode subject, Witness w) {
+
+ ObjectStamp originalStamp = (ObjectStamp) subject.stamp();
+ ObjectStamp outgoingStamp = originalStamp;
+
+ if (w.isNonNull() && !outgoingStamp.nonNull()) {
+ outgoingStamp = FlowUtil.asNonNullStamp(outgoingStamp);
+ }
+ if (FlowUtil.isMorePrecise(w.type(), outgoingStamp.type())) {
+ outgoingStamp = FlowUtil.asRefinedStamp(outgoingStamp, w.type());
+ }
+
+ if (outgoingStamp != originalStamp) {
+ assert FlowUtil.isMorePrecise(outgoingStamp, originalStamp);
+
+ boolean isWitnessGuardAnAliasForScrutinee = false;
+ if (w.guard() instanceof GuardingPiNode || w.guard() instanceof PiNode) {
+ /*
+ * The guard offered by the witness canonicalizes into its subject (a possibly
+ * type-refined scrutinee) provided its subject conforms as per stamp.
+ */
+ if (w.guard().asNode().stamp().equals(outgoingStamp)) {
+ isWitnessGuardAnAliasForScrutinee = true;
+ }
+ }
+
+ ValueNode result;
+ if (isWitnessGuardAnAliasForScrutinee) {
+ result = w.guard().asNode();
+ assert !w.knowsBetterThan(result);
+ return result; // TODO this works. explain why.
+ } else {
+ result = wrapInPiNode(subject, w.guard(), outgoingStamp, true);
+ assert !w.knowsBetterThan(result);
+ return result;
+ }
+
+ } else {
+ assert !w.knowsBetterThan(subject);
+ return subject;
+ }
+ }
+
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FixedGuardReduction.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FixedGuardReduction.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2012, 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 com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+/**
+ *
+ * This class implements control-flow sensitive reductions for
+ * {@link com.oracle.graal.nodes.FixedGuardNode}.
+ *
+ *
+ * @see #visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode)
+ */
+public abstract class FixedGuardReduction extends CheckCastReduction {
+
+ public FixedGuardReduction(FixedNode start, State initialState, PhaseContext context) {
+ super(start, initialState, context);
+ }
+
+ /**
+ * In case the condition is constant,
+ * {@link com.oracle.graal.nodes.FixedGuardNode#simplify(com.oracle.graal.graph.spi.SimplifierTool)
+ * FixedGuardNode#simplify(SimplifierTool)} will eventually remove the
+ * {@link com.oracle.graal.nodes.FixedGuardNode} ("always succeeds") or kill the code that
+ * should be killed ("always fails").
+ *
+ *
+ * The only thing we do here is tracking as true fact (from this program point onwards) the
+ * condition of the {@link com.oracle.graal.nodes.FixedGuardNode FixedGuardNode}.
+ *
+ *
+ *
+ * Precondition: the condition hasn't been deverbosified yet.
+ *
+ */
+ protected final void visitFixedGuardNode(FixedGuardNode f) {
+
+ /*
+ * A FixedGuardNode with LogicConstantNode condition is left untouched.
+ */
+
+ if (f.condition() instanceof LogicConstantNode) {
+ if (FlowUtil.alwaysFails(f.isNegated(), f.condition())) {
+ state.impossiblePath();
+ // let FixedGuardNode(false).simplify() prune the dead-code control-path
+ return;
+ }
+ assert FlowUtil.alwaysSucceeds(f.isNegated(), f.condition());
+ return;
+ }
+
+ /*
+ * Attempt to eliminate the current FixedGuardNode by using another GuardingNode already in
+ * scope and with equivalent condition.
+ */
+
+ GuardingNode existingGuard = f.isNegated() ? state.falseFacts.get(f.condition()) : state.trueFacts.get(f.condition());
+ if (existingGuard != null) {
+ // assert existingGuard instanceof FixedGuardNode;
+ metricFixedGuardNodeRemoved.increment();
+ f.replaceAtUsages(existingGuard.asNode());
+ graph.removeFixed(f);
+ return;
+ }
+
+ final LogicNode cond = f.condition();
+ final boolean isTrue = !f.isNegated();
+
+ /*
+ * FixedGuardNode requires handling similar to that of GuardingPiNode, (ie the condition
+ * can't simply be deverbosified in place). A replacement anchor is needed, ie an anchor
+ * that amounts to the same combination of (negated, condition) for the FixedGuardNode at
+ * hand.
+ */
+
+ // TODO what about isDependencyTainted
+
+ if (cond instanceof IsNullNode) {
+ final IsNullNode isNullNode = (IsNullNode) cond;
+ if (isTrue) {
+ // grab an anchor attesting nullness
+ final GuardingNode replacement = reasoner.nonTrivialNullAnchor(isNullNode.object());
+ if (replacement != null) {
+ removeFixedGuardNode(f, replacement);
+ return;
+ }
+ if (state.isNonNull(isNullNode.object())) {
+ markFixedGuardNodeAlwaysFails(f);
+ return;
+ }
+ // can't produce evidence, fall-through to addFact
+ } else {
+ // grab an anchor attesting non-nullness
+ final Witness w = state.typeInfo(isNullNode.object());
+ if (w != null && w.isNonNull()) {
+ removeFixedGuardNode(f, w.guard());
+ return;
+ }
+ if (state.isNull(isNullNode.object())) {
+ markFixedGuardNodeAlwaysFails(f);
+ return;
+ }
+ // can't produce evidence, fall-through to addFact
+ }
+ } else if (cond instanceof InstanceOfNode) {
+ final InstanceOfNode iOf = (InstanceOfNode) cond;
+ final Witness w = state.typeInfo(iOf.object());
+ if (isTrue) {
+ // grab an anchor attesting instanceof
+ if (w != null) {
+ if (w.isNonNull() && w.type() != null) {
+ if (iOf.type().isAssignableFrom(w.type())) {
+ removeFixedGuardNode(f, w.guard());
+ return;
+ }
+ if (State.knownNotToConform(w.type(), iOf.type())) {
+ markFixedGuardNodeAlwaysFails(f);
+ return;
+ }
+ }
+ }
+ if (state.isNull(iOf.object())) {
+ markFixedGuardNodeAlwaysFails(f);
+ return;
+ }
+ // can't produce evidence, fall-through to addFact
+ } else {
+ // grab an anchor attesting not-instanceof
+ // (1 of 2) attempt determining nullness
+ final GuardingNode nullGuard = reasoner.nonTrivialNullAnchor(iOf.object());
+ if (nullGuard != null) {
+ removeFixedGuardNode(f, nullGuard);
+ return;
+ }
+ // (2 of 2) attempt determining known-not-to-conform
+ if (w != null && !w.cluelessAboutType()) {
+ if (State.knownNotToConform(w.type(), iOf.type())) {
+ removeFixedGuardNode(f, w.guard());
+ return;
+ }
+ }
+ // can't produce evidence, fall-through to addFact
+ }
+ } else if (isTrue && cond instanceof ShortCircuitOrNode) {
+ CastCheckExtractor cce = CastCheckExtractor.extract(cond);
+ if (cce != null && !State.isDependencyTainted(cce.subject, f)) {
+ // grab an anchor attesting check-cast
+ Witness w = state.typeInfo(cce.subject);
+ if (w != null && w.type() != null) {
+ if (cce.type.isAssignableFrom(w.type())) {
+ removeFixedGuardNode(f, w.guard());
+ return;
+ }
+ if (State.knownNotToConform(w.type(), cce.type)) {
+ markFixedGuardNodeAlwaysFails(f);
+ return;
+ }
+ }
+ }
+ // can't produce evidence, fall-through to addFact
+ }
+
+ state.addFact(isTrue, cond, f);
+ }
+
+ /**
+ * Porcelain method.
+ */
+ private void markFixedGuardNodeAlwaysFails(FixedGuardNode f) {
+ metricFixedGuardNodeRemoved.increment();
+ state.impossiblePath();
+ f.setCondition(f.isNegated() ? trueConstant : falseConstant);
+ // `f.condition()` if unused will be removed in finished()
+ }
+
+ /**
+ * Porcelain method.
+ *
+ *
+ * The `replacement` guard must be such that it implies the `old` guard.
+ *
+ */
+ private void removeFixedGuardNode(FixedGuardNode old, GuardingNode replacement) {
+ if (replacement == null) {
+ return;
+ }
+ metricFixedGuardNodeRemoved.increment();
+ old.replaceAtUsages(replacement.asNode());
+ graph.removeFixed(old);
+ // `old.condition()` if unused will be removed in finished()
+ }
+
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,545 @@
+/*
+ * Copyright (c) 2012, 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 com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.FloatingNode;
+import com.oracle.graal.nodes.extended.LoadHubNode;
+import com.oracle.graal.nodes.extended.NullCheckNode;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.compiler.common.type.IllegalStamp;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+import java.lang.reflect.Modifier;
+
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+
+/**
+ *
+ * All control-flow-sensitive reductions follow the common pattern of
+ *
+ *
Recognizing properties of interest (ie, LogicNode-s) at control-flow splits, as well as upon
+ * check-casts and fixed-guards.
+ *
Using the information thus tracked to simplify
+ *
+ *
side-effects free expressions, via
+ * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)}
+ *
+ *
control-flow, eg. by eliminating redundant fixed-guards and check-casts, ie which are known
+ * always to hold.
+ * This method performs two kinds of cleanup:
+ *
+ *
+ * marking as unreachable certain code-paths, as described in
+ * {@link com.oracle.graal.phases.common.cfs.BaseReduction.PostponedDeopt}
+ *
+ * Removing nodes not in use that were added during this phase, as described next.
+ *
+ *
+ *
+ *
+ *
+ * Methods like
+ * {@link com.oracle.graal.phases.common.cfs.FlowUtil#replaceInPlace(com.oracle.graal.graph.Node, com.oracle.graal.graph.Node, com.oracle.graal.graph.Node)}
+ * may result in old inputs becoming disconnected from the graph. It's not advisable to
+ * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)} at
+ * that moment, because one of the inputs that might get killed is one of {@link #nullConstant},
+ * {@link #falseConstant}, or {@link #trueConstant}; which thus could get killed too early,
+ * before another invocation of
+ * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)}
+ * needs them. To recap,
+ * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)} also
+ * recursively visits the inputs of the its argument.
+ *
+ *
+ *
+ * This method goes over all of the nodes that deverbosification might have added, which are
+ * either:
+ *
+ *
+ * {@link com.oracle.graal.nodes.calc.FloatingNode}, added by
+ * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosifyFloatingNode(com.oracle.graal.nodes.calc.FloatingNode)}
+ * ; or
+ *
+ * {@link com.oracle.graal.nodes.java.MethodCallTargetNode}, added by
+ * {@link #deverbosifyInputsCopyOnWrite(com.oracle.graal.nodes.java.MethodCallTargetNode)}
+ *
+ *
+ * Checking if they aren't in use, proceeding to remove them in that case.
+ *
+ *
+ */
+ @Override
+ public void finished() {
+ if (!postponedDeopts.isEmpty()) {
+ for (PostponedDeopt postponed : postponedDeopts) {
+ postponed.doRewrite(falseConstant);
+ }
+ new DeadCodeEliminationPhase().apply(graph);
+ }
+ for (MethodCallTargetNode mcn : graph.getNodes().filter(MethodCallTargetNode.class)) {
+ if (mcn.isAlive() && FlowUtil.lacksUsages(mcn)) {
+ mcn.safeDelete();
+ }
+ }
+ for (Node n : graph.getNodes().filter(FloatingNode.class)) {
+ GraphUtil.tryKillUnused(n);
+ }
+ assert !isAliveWithoutUsages(trueConstant);
+ assert !isAliveWithoutUsages(falseConstant);
+ assert !isAliveWithoutUsages(nullConstant);
+ }
+
+ private static boolean isAliveWithoutUsages(FloatingNode node) {
+ return node.isAlive() && node.usages().isEmpty();
+ }
+
+ private void registerControlSplit(Node pred, BeginNode begin) {
+ assert pred != null && begin != null;
+ assert !state.isUnreachable;
+
+ if (begin instanceof LoopExitNode) {
+ state.clear();
+ }
+
+ if (pred instanceof IfNode) {
+ registerIfNode((IfNode) pred, begin);
+ } else if (pred instanceof TypeSwitchNode) {
+ registerTypeSwitchNode((TypeSwitchNode) pred, begin);
+ }
+ }
+
+ private void registerIfNode(IfNode ifNode, BeginNode begin) {
+ final boolean isThenBranch = (begin == ifNode.trueSuccessor());
+
+ if (ifNode.condition() instanceof LogicConstantNode) {
+ final LogicConstantNode constCond = (LogicConstantNode) ifNode.condition();
+ if (isThenBranch != constCond.getValue()) {
+ state.impossiblePath();
+ // let IfNode(constant) prune the dead-code control-path
+ }
+ }
+
+ if (state.isUnreachable) {
+ if (!(ifNode.condition() instanceof LogicConstantNode)) {
+ // if condition constant, no need to add a Deopt node
+ postponedDeopts.addDeoptAfter(begin, UnreachedCode);
+ }
+ } else {
+ state.addFact(isThenBranch, ifNode.condition(), begin);
+ }
+ }
+
+ /**
+ * TODO When tracking integer-stamps, the state at each successor of a TypeSwitchNode should
+ * track an integer-stamp for the LoadHubNode (meet over the constants leading to that
+ * successor). However, are LoadHubNode-s shared frequently enough?
+ */
+ private void registerTypeSwitchNode(TypeSwitchNode typeSwitch, BeginNode begin) {
+ if (typeSwitch.value() instanceof LoadHubNode) {
+ LoadHubNode loadHub = (LoadHubNode) typeSwitch.value();
+ ResolvedJavaType type = null;
+ for (int i = 0; i < typeSwitch.keyCount(); i++) {
+ if (typeSwitch.keySuccessor(i) == begin) {
+ if (type == null) {
+ type = typeSwitch.typeAt(i);
+ } else {
+ type = FlowUtil.widen(type, typeSwitch.typeAt(i));
+ }
+ }
+ }
+ if (type == null) {
+ // `begin` denotes the default case of the TypeSwitchNode
+ return;
+ }
+ // preferable would be trackExact, but not there yet
+ state.addNullness(false, loadHub.object(), begin);
+ if (state.knownNotToConform(loadHub.object(), type)) {
+ postponedDeopts.addDeoptAfter(begin, UnreachedCode);
+ state.impossiblePath();
+ return;
+ }
+ if (type.isInterface()) {
+ state.trackNN(loadHub.object(), begin);
+ } else {
+ state.trackIO(loadHub.object(), type, begin);
+ }
+ }
+ }
+
+ /**
+ *
+ *
+ * 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).
+ *
+ *
+ *
+ * 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.
+ *
+ *
+ *
+ * Please note the parent node is mutated upon any descendant changing. No copy-on-write is
+ * performed for the parent node itself.
+ *
+ *
+ *
+ * In more detail, for each direct {@link com.oracle.graal.nodes.ValueNode} input of the node at
+ * hand,
+ *
+ *
+ *
+ * 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.
+ *
+ *
+ * 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.
+ *
+ *
+ *
+ *
+ * @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) : "ConditionalElim shouldn't run in MidTier";
+ ValueNode j = (ValueNode) reasoner.deverbosify(i);
+ if (i != j) {
+ changed = true;
+ FlowUtil.replaceInPlace(parent, i, j);
+ }
+ }
+ if (changed) {
+ FlowUtil.inferStampAndCheck(parent);
+ }
+ return changed;
+ }
+
+ /**
+ * 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) {
+ MethodCallTargetNode changed = null;
+ for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(parent)) {
+ Node j = reasoner.deverbosify(i);
+ 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;
+ }
+
+ /**
+ * Precondition: This method assumes that either:
+ *
+ *
+ *
the state has already stabilized (ie no more pending iterations in the "iterative"
+ * dataflow algorithm); or
+ *
any rewritings made based on the state in its current form are conservative enough to be
+ * safe.
+ *
+ *
+ *
+ * The overarching goal is to perform just enough rewriting to trigger other phases (
+ * {@link com.oracle.graal.graph.spi.SimplifierTool SimplifierTool},
+ * {@link com.oracle.graal.phases.common.DeadCodeEliminationPhase DeadCodeEliminationPhase},
+ * etc) to perform the bulk of rewriting, thus lowering the maintenance burden.
+ *
+ *
+ */
+ @Override
+ protected void node(FixedNode node) {
+
+ assert node.isAlive();
+
+ /*-------------------------------------------------------------------------------------
+ * Step 1: Unreachable paths are still visited (PostOrderNodeIterator requires all ends
+ * of a merge to have been visited), but time is saved by neither updating the state nor
+ * rewriting anything while on an an unreachable path.
+ *-------------------------------------------------------------------------------------
+ */
+ if (state.isUnreachable) {
+ return;
+ }
+
+ /*-------------------------------------------------------------------------------------
+ * Step 2: For an AbstractBeginNode, determine whether this path is reachable, register
+ * any associated guards.
+ *-------------------------------------------------------------------------------------
+ */
+ if (node instanceof BeginNode) {
+ BeginNode begin = (BeginNode) node;
+ Node pred = node.predecessor();
+
+ if (pred != null) {
+ registerControlSplit(pred, begin);
+ }
+ return;
+ }
+
+ /*-------------------------------------------------------------------------------------
+ * Step 3: Check whether EquationalReasoner caches should be cleared upon state updates.
+ *-------------------------------------------------------------------------------------
+ */
+ reasoner.updateState(state);
+
+ /*-------------------------------------------------------------------------------------
+ * Step 4: Whatever special-case handling makes sense for the FixedNode at hand before
+ * its inputs are reduced.
+ *-------------------------------------------------------------------------------------
+ */
+
+ if (node instanceof AbstractEndNode) {
+ visitAbstractEndNode((AbstractEndNode) node);
+ return;
+ } else if (node instanceof Invoke) {
+ visitInvoke((Invoke) node);
+ return;
+ } else if (node instanceof CheckCastNode) {
+ // it's important not to call deverbosification for visitCheckCastNode()
+ visitCheckCastNode((CheckCastNode) node);
+ return;
+ } else if (node instanceof GuardingPiNode) {
+ visitGuardingPiNode((GuardingPiNode) node);
+ return;
+ } else if (node instanceof NullCheckNode) {
+ visitNullCheckNode((NullCheckNode) node);
+ return;
+ } else if (node instanceof FixedGuardNode) {
+ visitFixedGuardNode((FixedGuardNode) node);
+ return;
+ } else if (node instanceof ConditionAnchorNode) {
+ // ConditionAnchorNode shouldn't occur during HighTier
+ return;
+ }
+
+ /*-------------------------------------------------------------------------------------
+ * Step 5: After special-case handling, we do our best for those FixedNode-s
+ * where the effort to reduce their inputs might pay off.
+ *
+ * Why is this useful? For example, by the time the AbstractBeginNode for an If-branch
+ * is visited (in general a ControlSplitNode), the If-condition will have gone already
+ * through simplification (and thus potentially have been reduced to a
+ * LogicConstantNode).
+ *-------------------------------------------------------------------------------------
+ */
+ boolean paysOffToReduce = false;
+ if (node instanceof ControlSplitNode) {
+ // desire to simplify control flow
+ paysOffToReduce = true;
+ } else if (node instanceof ReturnNode) {
+ paysOffToReduce = true;
+ } else if (node instanceof AccessFieldNode || node instanceof AccessArrayNode) {
+ // desire to remove null-checks
+ paysOffToReduce = true;
+ }
+
+ // TODO comb the remaining FixedWithNextNode subclasses, pick those with good changes of
+ // paying-off
+
+ // TODO UnsafeLoadNode takes a condition
+
+ if (paysOffToReduce) {
+ deverbosifyInputsInPlace(node);
+ }
+
+ /*---------------------------------------------------------------------------------------
+ * Step 6: Any additional special-case handling, this time after having inputs reduced.
+ * For example, leverage anchors provided by the FixedNode, to add facts to the factbase.
+ *---------------------------------------------------------------------------------------
+ */
+
+ // TODO some nodes are GuardingNodes (eg, FixedAccessNode) we could use them to track state
+ // TODO others are additionally guarded (eg JavaReadNode), thus *their* guards could be
+ // simplified.
+
+ }
+
+ /**
+ * In case the scrutinee:
+ *
+ *
+ *
is known to be null, an unconditional deopt is added.
+ *
is known to be non-null, the NullCheckNode is removed.
+ *
+ *
+ *
+ * Precondition: the input (ie, object) hasn't been deverbosified yet.
+ *
+ */
+ private void visitNullCheckNode(NullCheckNode ncn) {
+ ValueNode object = ncn.getObject();
+ if (state.isNull(object)) {
+ postponedDeopts.addDeoptBefore(ncn, NullCheckException);
+ state.impossiblePath();
+ return;
+ }
+ if (state.isNonNull(object)) {
+ /*
+ * Redundant NullCheckNode. Unlike GuardingPiNode or FixedGuardNode, NullCheckNode-s
+ * aren't used as GuardingNode-s, thus in this case can be removed without further ado.
+ */
+ assert FlowUtil.lacksUsages(ncn);
+ graph.removeFixed(ncn);
+ return;
+ }
+ // TODO ANCHOR NEEDED: state.trackNN(object, ncn);
+ }
+
+ /**
+ * The {@link com.oracle.graal.nodes.AbstractEndNode} at the end of the current code path
+ * contributes values to {@link com.oracle.graal.nodes.PhiNode}s. Now is a good time to
+ * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+ * EquationalReasoner#deverbosify} those values.
+ *
+ *
+ * Precondition: inputs haven't been deverbosified yet.
+ *
+ */
+ private void visitAbstractEndNode(AbstractEndNode endNode) {
+ MergeNode merge = endNode.merge();
+ for (PhiNode phi : merge.phis()) {
+ if (phi instanceof ValuePhiNode && phi.getKind() == Kind.Object) {
+ assert phi.verify();
+ int index = merge.phiPredecessorIndex(endNode);
+ ValueNode original = phi.valueAt(index);
+ ValueNode reduced = (ValueNode) reasoner.deverbosify(original);
+ if (reduced != original) {
+ phi.setValueAt(index, reduced);
+ // `original` if unused will be removed in finished()
+ }
+ }
+ }
+ }
+
+ /**
+ * One or more arguments at `invoke` may have control-flow sensitive simplifications. In such
+ * case, a new {@link com.oracle.graal.nodes.java.MethodCallTargetNode MethodCallTargetNode} is
+ * prepared just for this callsite, consuming reduced arguments. This proves useful in
+ * connection with inlining, in order to specialize callees on the types of arguments other than
+ * the receiver (examples: multi-methods, the inlining problem, lambdas as arguments).
+ *
+ *
+ * Precondition: inputs haven't been deverbosified yet.
+ *
+ */
+ private void visitInvoke(Invoke invoke) {
+ if (invoke.asNode().stamp() instanceof IllegalStamp) {
+ return; // just to be safe
+ }
+ boolean isMethodCallTarget = invoke.callTarget() instanceof MethodCallTargetNode;
+ if (!isMethodCallTarget) {
+ return;
+ }
+ FlowUtil.replaceInPlace(invoke.asNode(), invoke.callTarget(), deverbosifyInputsCopyOnWrite((MethodCallTargetNode) invoke.callTarget()));
+ MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+ if (callTarget.invokeKind() != MethodCallTargetNode.InvokeKind.Interface && callTarget.invokeKind() != MethodCallTargetNode.InvokeKind.Virtual) {
+ return;
+ }
+ ValueNode receiver = callTarget.receiver();
+ if (receiver == null) {
+ return;
+ }
+ if (!FlowUtil.hasLegalObjectStamp(receiver)) {
+ return;
+ }
+ Witness w = state.typeInfo(receiver);
+ ResolvedJavaType type;
+ ResolvedJavaType stampType = StampTool.typeOrNull(receiver);
+ if (w == null || w.cluelessAboutType()) {
+ // can't improve on stamp but wil try to devirtualize anyway
+ type = stampType;
+ } else {
+ type = FlowUtil.tighten(w.type(), stampType);
+ }
+ if (type == null) {
+ return;
+ }
+ ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod());
+ if (method == null) {
+ return;
+ }
+ if (method.canBeStaticallyBound() || Modifier.isFinal(type.getModifiers())) {
+ metricMethodResolved.increment();
+ callTarget.setInvokeKind(MethodCallTargetNode.InvokeKind.Special);
+ callTarget.setTargetMethod(method);
+ }
+ }
+
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReductionPhase.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReductionPhase.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012, 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 com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+public class FlowSensitiveReductionPhase extends BasePhase {
+
+ private final MetaAccessProvider metaAccess;
+
+ public MetaAccessProvider getMetaAccess() {
+ return metaAccess;
+ }
+
+ public FlowSensitiveReductionPhase(MetaAccessProvider metaAccess) {
+ this.metaAccess = metaAccess;
+ }
+
+ @Override
+ protected final void run(StructuredGraph graph, PhaseContext context) {
+ try (Debug.Scope s = Debug.scope("FlowSensitiveReduction")) {
+ Debug.dump(graph, "FlowSensitiveReduction initial");
+ new FlowSensitiveReduction(graph.start(), new State(), context).apply();
+ Debug.dump(graph, "FlowSensitiveReduction done");
+ } catch (Throwable e) {
+ throw Debug.handle(e);
+ }
+ }
+
+}
\ No newline at end of file
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2012, 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 com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugConfig;
+import com.oracle.graal.debug.DebugConfigScope;
+import com.oracle.graal.debug.internal.DebugScope;
+import com.oracle.graal.graph.InputType;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.compiler.common.type.Stamp;
+import com.oracle.graal.compiler.common.type.StampFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class FlowUtil {
+
+ private FlowUtil() {
+ // no instances of this class
+ }
+
+ public static boolean lacksUsages(Node n) {
+ return n.recordsUsages() && n.usages().isEmpty();
+ }
+
+ public static ResolvedJavaType widen(ResolvedJavaType a, ResolvedJavaType b) {
+ if (a == null || b == null) {
+ return null;
+ } else if (a.equals(b)) {
+ return a;
+ } else {
+ return a.findLeastCommonAncestor(b);
+ }
+ }
+
+ /**
+ * @return whether the first argument is strictly more precise than the second.
+ */
+ public static boolean isMorePrecise(ResolvedJavaType a, ResolvedJavaType b) {
+ if (a == null) {
+ return false;
+ }
+ if (b == null) {
+ return true;
+ }
+ assert !a.isPrimitive();
+ assert !b.isPrimitive();
+ if (a.equals(b)) {
+ return false;
+ }
+ if (b.isInterface()) {
+ return b.isAssignableFrom(a);
+ }
+ if (a.isInterface()) {
+ return b.isInterface() && b.isAssignableFrom(a);
+ }
+ return b.isAssignableFrom(a);
+ }
+
+ public static ResolvedJavaType tighten(ResolvedJavaType a, ResolvedJavaType b) {
+ if (a == null) {
+ assert b == null || !b.isPrimitive();
+ return b;
+ }
+ if (b == null) {
+ assert !a.isPrimitive();
+ return a;
+ }
+ assert !a.isPrimitive();
+ assert !b.isPrimitive();
+ if (a.equals(b)) {
+ return a;
+ }
+ if (isMorePrecise(a, b)) {
+ return a;
+ } else if (isMorePrecise(b, a)) {
+ return b;
+ } else {
+ /*
+ * Not comparable, two cases:
+ *
+ * Example 1: 'a' standing for j.l.Number and 'b' for j.l.String We return null for lack
+ * of a value representing NullType, the right answer. Same goes when both arguments are
+ * non-comparable interfaces.
+ *
+ * Example 2: 'a' standing for sun/nio/ch/DirectBuffer (an interface) and b for
+ * java/nio/Buffer (an abstract class). The class always takes precedence.
+ */
+ if (a.isInterface()) {
+ return b.isInterface() ? null : b;
+ }
+ if (b.isInterface()) {
+ return a.isInterface() ? null : a;
+ }
+ return null; // a and b aren't comparable, can't tighten() them
+ }
+ }
+
+ /**
+ *
+ * There are "illegal" stamps that are not of type IllegalStamp.
+ *
+ * For example, there may be an IntegerStamp with upperBound < lowerBound that returns
+ * !isLegal() but we still know it's an integer and thus not of type IllegalStamp.
+ *
+ * An IllegalStamp should never happen. In contrast, !isLegal() values could happen due to dead
+ * code not yet removed, or upon some non-sideeffecting instructions floating out of a dead
+ * branch.
+ */
+ public static boolean isLegalObjectStamp(Stamp s) {
+ return isObjectStamp(s) && s.isLegal();
+ }
+
+ public static boolean hasLegalObjectStamp(ValueNode v) {
+ return isLegalObjectStamp(v.stamp());
+ }
+
+ public static boolean isObjectStamp(Stamp stamp) {
+ return stamp instanceof ObjectStamp;
+ }
+
+ public static void inferStampAndCheck(ValueNode n) {
+ n.inferStamp();
+ if (n.stamp() instanceof ObjectStamp) {
+ ObjectStamp objectStamp = (ObjectStamp) n.stamp();
+ assert !objectStamp.isExactType() || objectStamp.type() != null;
+ }
+ }
+
+ /**
+ * Compares the arguments along three dimensions (nullness, exactness, and type). For the first
+ * argument to be more precise than the second, it may not score lower in any dimension and must
+ * score higher in at least one dimension.
+ *
+ * When comparing types s and t, sameness counts as 0; while being more precise is awarded with
+ * a score of 1. In all other cases (non-comparable, or supertype) the score is -1.
+ *
+ * @return whether the first argument is strictly more precise than the second.
+ */
+ public static boolean isMorePrecise(ObjectStamp a, ObjectStamp b) {
+ int d0 = MINUS(a.alwaysNull(), b.alwaysNull());
+ if (d0 == -1) {
+ return false;
+ }
+ int d1 = MINUS(a.nonNull(), b.nonNull());
+ if (d1 == -1) {
+ return false;
+ }
+ int d2 = MINUS(a.isExactType(), b.isExactType());
+ if (d2 == -1) {
+ return false;
+ }
+ int d3;
+ ResolvedJavaType ta = a.type();
+ ResolvedJavaType tb = b.type();
+ if (ta == null) {
+ d3 = (tb == null) ? 0 : -1;
+ } else if (tb == null) {
+ d3 = 1;
+ } else if (isMorePrecise(ta, tb)) {
+ d3 = 1;
+ } else if (ta.equals(tb)) {
+ d3 = 0;
+ } else {
+ d3 = -1;
+ }
+ if (d3 == -1) {
+ return false;
+ }
+ int maxScore = Math.max(Math.max(d0, d1), Math.max(d2, d3));
+ return maxScore > 0;
+ }
+
+ private static int MINUS(boolean a, boolean b) {
+ int aa = a ? 1 : 0;
+ int bb = b ? 1 : 0;
+ return aa - bb;
+ }
+
+ public static LogicConstantNode asLogicConstantNode(LogicNode cond) {
+ return (cond instanceof LogicConstantNode) ? (LogicConstantNode) cond : null;
+ }
+
+ public static boolean isLiteralNode(ValueNode f) {
+ return f instanceof ConstantNode || f instanceof LogicConstantNode;
+ }
+
+ public static boolean isConstantTrue(LogicNode cond) {
+ LogicConstantNode c = asLogicConstantNode(cond);
+ return (c != null) && c.getValue();
+ }
+
+ public static boolean isConstantFalse(LogicNode cond) {
+ LogicConstantNode c = asLogicConstantNode(cond);
+ return (c != null) && !c.getValue();
+ }
+
+ public static boolean alwaysFails(boolean isNegated, LogicNode cond) {
+ LogicConstantNode c = asLogicConstantNode(cond);
+ return (c != null) && (c.getValue() == isNegated);
+ }
+
+ public static boolean alwaysSucceeds(boolean isNegated, LogicNode cond) {
+ LogicConstantNode c = asLogicConstantNode(cond);
+ return (c != null) && (c.getValue() != isNegated);
+ }
+
+ /**
+ * Returns (preserving order) the ValueNodes without duplicates found among the argument's
+ * direct inputs.
+ */
+ @SuppressWarnings("unchecked")
+ public static List distinctValueAndConditionInputs(Node n) {
+ ArrayList result = null;
+ NodeClass.NodeClassIterator iter = n.inputs().iterator();
+ while (iter.hasNext()) {
+ NodeClass.Position pos = iter.nextPosition();
+ InputType inputType = pos.getInputType(n);
+ boolean isReducibleInput = (inputType == InputType.Value || inputType == InputType.Condition);
+ if (isReducibleInput) {
+ ValueNode i = (ValueNode) pos.get(n);
+ if (!isLiteralNode(i)) {
+ if (result == null) {
+ result = new ArrayList<>();
+ }
+ if (!result.contains(i)) {
+ result.add(i);
+ }
+ }
+ }
+ }
+ return result == null ? Collections.EMPTY_LIST : result;
+ }
+
+ public static ObjectStamp asNonNullStamp(ObjectStamp stamp) {
+ ObjectStamp result = (ObjectStamp) stamp.join(StampFactory.objectNonNull());
+ assert result.isLegal();
+ return result;
+ }
+
+ public static ObjectStamp asRefinedStamp(ObjectStamp stamp, ResolvedJavaType joinType) {
+ assert !joinType.isInterface();
+ ObjectStamp result = (ObjectStamp) stamp.join(StampFactory.declared(joinType));
+ assert result.isLegal();
+ return result;
+ }
+
+ /**
+ * Start situation: the parent node has oldInput among its (direct) inputs. After
+ * this method has run, all such occurrences have been replaced with newInput. In
+ * case that makes oldInput disconnected, it is removed from the graph.
+ */
+ public static void replaceInPlace(Node parent, Node oldInput, Node newInput) {
+ assert parent != null;
+ assert parent.inputs().contains(oldInput);
+ if (oldInput == newInput) {
+ return;
+ }
+ assert oldInput != null && newInput != null;
+ assert !isLiteralNode((ValueNode) oldInput);
+ do {
+ parent.replaceFirstInput(oldInput, newInput);
+ } while (parent.inputs().contains(oldInput));
+ // `oldInput` if unused wil be removed in finished()
+ }
+
+ public static StructuredGraph visualize(StructuredGraph graph, String title) {
+ DebugConfig debugConfig = DebugScope.getConfig();
+ DebugConfig fixedConfig = Debug.fixedConfig(false, true, false, false, debugConfig.dumpHandlers(), debugConfig.output());
+ try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
+ Debug.dump(graph, title);
+
+ return graph;
+ }
+ }
+
+ public static final String ANSI_RESET = "\u001B[0m";
+ public static final String ANSI_BLACK = "\u001B[30m";
+ public static final String ANSI_RED = "\u001B[31m";
+ public static final String ANSI_GREEN = "\u001B[32m";
+ public static final String ANSI_YELLOW = "\u001B[33m";
+ public static final String ANSI_BLUE = "\u001B[34m";
+ public static final String ANSI_PURPLE = "\u001B[35m";
+ public static final String ANSI_CYAN = "\u001B[36m";
+ public static final String ANSI_WHITE = "\u001B[37m";
+
+ public static void highlightInRed(String msg) {
+ System.out.println(ANSI_RED + msg + ANSI_RESET);
+ }
+
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/GuardingPiReduction.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/GuardingPiReduction.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2012, 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 com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+/**
+ *
+ * This class implements control-flow sensitive reductions for
+ * {@link com.oracle.graal.nodes.GuardingPiNode}.
+ *
+ * By the time a {@link com.oracle.graal.nodes.GuardingPiNode GuardingPiNode} is visited, the
+ * available type refinements may allow reductions similar to those performed for
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+ * CheckCastNode}.
+ *
+ *
+ *
+ *
+ * If the condition needs no reduction (ie, it's already a
+ * {@link com.oracle.graal.nodes.LogicConstantNode LogicConstantNode}), this method basically
+ * gives up (thus letting other phases take care of it).
+ *
+ * Otherwise, an attempt is made to find a {@link com.oracle.graal.nodes.extended.GuardingNode}
+ * that implies the combination of (negated, condition) of the
+ * {@link com.oracle.graal.nodes.GuardingPiNode} being visited. Details in
+ * {@link #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}. If found, the node
+ * can be removed.
+ *
+ * Otherwise, the node is lowered to a {@link com.oracle.graal.nodes.FixedGuardNode} and its
+ * usages replaced with {@link com.oracle.graal.nodes.PiNode}. Details in
+ * {@link #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}.
+ *
+ *
+ *
+ * Precondition: the condition hasn't been deverbosified yet.
+ *
+ *
+ */
+ protected final void visitGuardingPiNode(GuardingPiNode envelope) {
+
+ if (!FlowUtil.hasLegalObjectStamp(envelope)) {
+ // this situation exercised by com.oracle.graal.jtt.optimize.NCE_FlowSensitive02
+ return;
+ }
+ if (!FlowUtil.hasLegalObjectStamp(envelope.object())) {
+ return;
+ }
+
+ /*
+ * (1 of 3) Cover the case of GuardingPiNode(LogicConstantNode, ...)
+ */
+
+ if (envelope.condition() instanceof LogicConstantNode) {
+ if (FlowUtil.alwaysFails(envelope.isNegated(), envelope.condition())) {
+ state.impossiblePath();
+ // let GuardingPiNode(false).canonical() prune the dead-code control-path
+ return;
+ }
+ // if not always-fails and condition-constant, then it always-succeeds!
+ assert FlowUtil.alwaysSucceeds(envelope.isNegated(), envelope.condition());
+ // let GuardingPiNode(true).canonical() replaceAtUsages
+ return;
+ }
+
+ /*
+ * The trick used in visitFixedGuardNode to look up an equivalent GuardingNode for the
+ * combination of (negated, condition) at hand doesn't work for GuardingPiNode, because the
+ * condition showing up here (a ShortCircuitOrNode that can be detected by
+ * CastCheckExtractor) doesn't appear as key in trueFacts, falseFacts. Good thing we have
+ * CastCheckExtractor!
+ */
+
+ /*
+ * (2 of 3) Cover the case of the condition known-to-be-false or known-to-be-true, but not
+ * LogicConstantNode.
+ *
+ * If deverbosify(condition) == falseConstant, it would be safe to set:
+ * `envelope.setCondition(falseConstant)` (only the API won't allow).
+ *
+ * On the other hand, it's totally unsafe to do something like that for trueConstant. What
+ * we can do about that case is the province of `tryRemoveGuardingPiNode(envelope)`
+ */
+
+ if (tryRemoveGuardingPiNode(envelope)) {
+ return;
+ }
+
+ /*
+ * Experience has shown that an attempt to eliminate the current GuardingPiNode by using a
+ * GuardingNode already in scope and with equivalent condition (grabbed from `trueFacts`
+ * resp. `falseFacts`) proves futile. Therefore we're not even attempting that here.
+ */
+
+ /*
+ * (3 of 3) Neither always-succeeds nor always-fails, ie we don't known. Converting to
+ * FixedGuardNode allows tracking the condition via a GuardingNode, thus potentially
+ * triggering simplifications down the road.
+ */
+ FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(envelope.condition(), envelope.getReason(), envelope.getAction(), envelope.isNegated()));
+ graph.addBeforeFixed(envelope, fixedGuard);
+
+ if (!FlowUtil.lacksUsages(envelope)) {
+ // not calling wrapInPiNode() because we don't want to rememberSubstitution()
+ PiNode replacement = graph.unique(new PiNode(envelope.object(), envelope.stamp(), fixedGuard));
+ reasoner.added.add(replacement);
+ // before removing the GuardingPiNode replace its usages
+ envelope.replaceAtUsages(replacement);
+ }
+
+ graph.removeFixed(envelope);
+
+ state.addFact(!fixedGuard.isNegated(), fixedGuard.condition(), fixedGuard);
+
+ }
+
+ /**
+ *
+ * Based on flow-sensitive knowledge, two pre-requisites have to be fulfilled in order to remove
+ * a {@link com.oracle.graal.nodes.GuardingPiNode}:
+ *
+ *
+ *
the condition must refer only to the payload of the
+ * {@link com.oracle.graal.nodes.GuardingPiNode}
+ *
the condition must check properties about which the state tracks not only a true/false
+ * answer, but also an anchor witnessing that fact
+ *
the condition may not check anything else beyond what's stated in the items above.
+ *
+ *
+ *
+ *
+ * Provided a condition as above can be reduced to a constant (and an anchor obtained in the
+ * process), this method replaces all usages of the
+ * {@link com.oracle.graal.nodes.GuardingPiNode} (necessarily of
+ * {@link com.oracle.graal.graph.InputType#Value}) with a {@link com.oracle.graal.nodes.PiNode}
+ * that wraps the payload and the anchor in question.
+ *
+ *
+ *
+ * Precondition: the condition hasn't been deverbosified yet.
+ *
+ *
+ * @see #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
+ *
+ */
+ private boolean tryRemoveGuardingPiNode(GuardingPiNode envelope) {
+
+ LogicNode cond = envelope.condition();
+ ValueNode payload = envelope.object();
+
+ ObjectStamp outgoingStamp = (ObjectStamp) envelope.stamp();
+ ObjectStamp payloadStamp = (ObjectStamp) payload.stamp();
+
+ if (isNullCheckOn(cond, payload)) {
+ if (envelope.isNegated()) {
+ /*
+ * GuardingPiNode succeeds if payload non-null
+ */
+ if (!outgoingStamp.equals(FlowUtil.asNonNullStamp(payloadStamp))) {
+ warnAboutOutOfTheBlueGuardingPiNode(envelope);
+ }
+ return tryRemoveGuardingPiNodeNonNullCond(envelope);
+ } else {
+ /*
+ * GuardingPiNode succeeds if payload null
+ */
+ ValueNode replacement = StampTool.isObjectAlwaysNull(payload) ? payload : reasoner.nonTrivialNull(payload);
+ if (replacement != null) {
+ // replacement == null means !isKnownNull(payload)
+ removeGuardingPiNode(envelope, replacement);
+ return true;
+ }
+ return false;
+ }
+ } else if (CastCheckExtractor.isInstanceOfCheckOn(cond, payload)) {
+ if (envelope.isNegated()) {
+ return false;
+ }
+ /*
+ * GuardingPiNode succeeds if payload instanceof
+ */
+ InstanceOfNode io = (InstanceOfNode) cond;
+ assert io.type() != null;
+ Witness w = state.typeInfo(payload);
+ if (w != null && w.isNonNull() && isEqualOrMorePrecise(w.type(), io.type())) {
+ ValueNode d = reasoner.downcast(payload);
+ removeGuardingPiNode(envelope, d);
+ return true;
+ }
+ return false;
+ } else if (cond instanceof ShortCircuitOrNode) {
+ if (envelope.isNegated()) {
+ return false;
+ }
+ CastCheckExtractor cce = CastCheckExtractor.extract(cond);
+ if (cce == null || cce.subject != payload) {
+ return false;
+ }
+ /*
+ * GuardingPiNode succeeds if payload check-casts toType
+ */
+ return tryRemoveGuardingPiNodeCheckCastCond(envelope, cce.type);
+ }
+
+ return false;
+ }
+
+ /**
+ * Porcelain method.
+ *
+ * This method handles the case where the GuardingPiNode succeeds if payload known to be
+ * non-null.
+ *
+ * @see #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
+ */
+ private boolean tryRemoveGuardingPiNodeNonNullCond(GuardingPiNode envelope) {
+
+ ValueNode payload = envelope.object();
+
+ if (state.isNull(payload)) {
+ // the GuardingPiNode fails always
+ postponedDeopts.addDeoptBefore(envelope, envelope.getReason());
+ state.impossiblePath();
+ return true;
+ }
+
+ if (StampTool.isObjectNonNull(payload)) {
+ // payload needs no downcasting, it satisfies as-is the GuardingPiNode's condition.
+ if (precisionLoss(envelope, payload)) {
+ /*
+ * TODO The GuardingPiNode has an outgoing stamp whose narrowing goes beyond what
+ * the condition checks. That's suspicious.
+ */
+ PiNode replacement = graph.unique(new PiNode(payload, envelope.stamp()));
+ reasoner.added.add(replacement);
+ removeGuardingPiNode(envelope, replacement);
+ return true;
+ } else {
+ removeGuardingPiNode(envelope, payload);
+ return true;
+ }
+ }
+ // if a non-null witness available, the GuardingPiNode can be removed
+
+ Witness w = state.typeInfo(payload);
+ GuardingNode nonNullAnchor = (w != null && w.isNonNull()) ? w.guard() : null;
+ if (nonNullAnchor != null) {
+ PiNode replacement = graph.unique(new PiNode(payload, envelope.stamp(), nonNullAnchor.asNode()));
+ reasoner.added.add(replacement);
+ removeGuardingPiNode(envelope, replacement);
+ return true;
+ }
+
+ /*
+ * TODO What about, nodes that always denote non-null values? (Even though their stamp
+ * forgot to make that clear) Candidates: ObjectGetClassNode, Parameter(0) on instance
+ */
+
+ return false;
+ }
+
+ /**
+ * Porcelain method.
+ *
+ * This method handles the case where the GuardingPiNode succeeds if payload null or its actual
+ * type equal or subtype of `toType`
+ *
+ * @see #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
+ *
+ */
+ private boolean tryRemoveGuardingPiNodeCheckCastCond(GuardingPiNode envelope, ResolvedJavaType toType) {
+ assert toType != null;
+ ValueNode payload = envelope.object();
+
+ ObjectStamp outgoingStamp = (ObjectStamp) envelope.stamp();
+ ObjectStamp payloadStamp = (ObjectStamp) payload.stamp();
+
+ if (!outgoingStamp.equals(FlowUtil.asRefinedStamp(payloadStamp, toType))) {
+ warnAboutOutOfTheBlueGuardingPiNode(envelope);
+ }
+
+ ValueNode d = reasoner.downcast(payload);
+ if (d == null) {
+ return false;
+ }
+
+ if (StampTool.isObjectAlwaysNull(d)) {
+ removeGuardingPiNode(envelope, d);
+ return true;
+ }
+ ObjectStamp dStamp = (ObjectStamp) d.stamp();
+ if (isEqualOrMorePrecise(dStamp.type(), toType)) {
+ removeGuardingPiNode(envelope, d);
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ * TODO There should be an assert in GuardingPiNode to detect that as soon as it happens
+ * (constructor, setStamp).
+ */
+ private static void warnAboutOutOfTheBlueGuardingPiNode(GuardingPiNode envelope) {
+ Debug.log(String.format("GuardingPiNode has an outgoing stamp whose narrowing goes beyond what its condition checks: %s", envelope));
+ }
+
+ private static boolean isNullCheckOn(LogicNode cond, ValueNode subject) {
+ if (!(cond instanceof IsNullNode)) {
+ return false;
+ }
+ IsNullNode isNull = (IsNullNode) cond;
+ return isNull.object() == subject;
+ }
+
+ /**
+ * Porcelain method.
+ */
+ private void removeGuardingPiNode(GuardingPiNode envelope, ValueNode replacement) {
+ assert !precisionLoss(envelope, replacement);
+ metricGuardingPiNodeRemoved.increment();
+ envelope.replaceAtUsages(replacement);
+ assert FlowUtil.lacksUsages(envelope);
+ graph.removeFixed(envelope);
+ }
+
+ public static boolean isEqualOrMorePrecise(ResolvedJavaType a, ResolvedJavaType b) {
+ return a.equals(b) || FlowUtil.isMorePrecise(a, b);
+ }
+
+ public static boolean isEqualOrMorePrecise(ObjectStamp a, ObjectStamp b) {
+ return a.equals(b) || FlowUtil.isMorePrecise(a, b);
+ }
+
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Histogram.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Histogram.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2012, 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 com.oracle.graal.phases.common.cfs;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+public class Histogram extends TreeMap {
+
+ private static final long serialVersionUID = 7188324319057387738L;
+
+ private final String prefix;
+
+ public Histogram(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public void tick(int bucket) {
+ Integer entry = get(bucket);
+ put(bucket, entry == null ? 1 : entry + 1);
+ }
+
+ public void print() {
+
+ // printing takes time, allow concurrent updates during printing
+ Histogram histogram = clone();
+
+ float casesTotal = 0;
+ for (int i : histogram.values()) {
+ casesTotal += i;
+ }
+ for (Map.Entry entry : histogram.entrySet()) {
+ int numCases = entry.getValue();
+ int percentOut = (int) (numCases / casesTotal * 100);
+ String msg = prefix + String.format("%d iters in %4d cases (%2d %%)", entry.getKey(), numCases, percentOut);
+ if (entry.getKey() > 3) {
+ FlowUtil.highlightInRed(msg);
+ } else {
+ System.out.println(msg);
+ }
+ }
+ System.out.println(prefix + "--------------------------");
+ }
+
+ @Override
+ public Histogram clone() {
+ return (Histogram) super.clone();
+ }
+
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/IterativeFlowSensitiveReductionPhase.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/IterativeFlowSensitiveReductionPhase.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012, 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 com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.common.util.*;
+import com.oracle.graal.phases.tiers.*;
+
+public class IterativeFlowSensitiveReductionPhase extends BasePhase {
+
+ private static final int MAX_ITERATIONS = 256;
+
+ private final CanonicalizerPhase canonicalizer;
+
+ public IterativeFlowSensitiveReductionPhase(CanonicalizerPhase canonicalizer) {
+ this.canonicalizer = canonicalizer;
+ }
+
+ public static class CountingListener extends HashSetNodeChangeListener {
+
+ public int count;
+
+ @Override
+ public void nodeChanged(Node node) {
+ super.nodeChanged(node);
+ }
+
+ }
+
+ // private Histogram histogram = new Histogram("FSR-");
+
+ @Override
+ protected void run(StructuredGraph graph, PhaseContext context) {
+ FlowSensitiveReductionPhase eliminate = new FlowSensitiveReductionPhase(context.getMetaAccess());
+ CountingListener listener = new CountingListener();
+ int count = 1;
+ while (true) {
+ listener.count = count;
+ graph.trackInputChange(listener);
+ graph.trackUsagesDroppedZero(listener);
+ eliminate.apply(graph, context);
+ graph.stopTrackingInputChange();
+ graph.stopTrackingUsagesDroppedZero();
+ if (listener.getChangedNodes().isEmpty()) {
+ // histogram.tick(count);
+ break;
+ }
+ for (Node node : graph.getNodes()) {
+ if (node instanceof Simplifiable) {
+ listener.getChangedNodes().add(node);
+ }
+ }
+ canonicalizer.applyIncremental(graph, context, listener.getChangedNodes());
+ listener.getChangedNodes().clear();
+ if (++count > MAX_ITERATIONS) {
+ // System.out.println("Bailing out IterativeFlowSensitiveReductionPhase for graph: "
+ // + graph);
+ // FlowUtil.visualize(graph, "Bailout");
+ throw new BailoutException("Number of iterations in FlowSensitiveReductionPhase exceeds " + MAX_ITERATIONS);
+ }
+ }
+ // histogram.print();
+ }
+
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,824 @@
+/*
+ * Copyright (c) 2012, 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 com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.Kind;
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.calc.ObjectEqualsNode;
+import com.oracle.graal.nodes.extended.GuardedNode;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.nodes.java.InstanceOfNode;
+import com.oracle.graal.nodes.spi.ValueProxy;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.phases.graph.MergeableState;
+
+import java.lang.reflect.Modifier;
+import java.util.*;
+
+/**
+ * A State instance is mutated in place as each FixedNode is visited in a basic block of
+ * instructions. Basic block: starts with a {@link com.oracle.graal.nodes.BeginNode BeginNode}, ends
+ * at an {@link com.oracle.graal.nodes.EndNode EndNode} or
+ * {@link com.oracle.graal.nodes.ControlSinkNode ControlSinkNode} and lacks intervening control
+ * splits or merges.
+ */
+public final class State extends MergeableState implements Cloneable {
+
+ private static final DebugMetric metricTypeRegistered = Debug.metric("TypeRegistered");
+ private static final DebugMetric metricNullnessRegistered = Debug.metric("NullnessRegistered");
+ private static final DebugMetric metricObjectEqualsRegistered = Debug.metric("ObjectEqualsRegistered");
+ private static final DebugMetric metricImpossiblePathDetected = Debug.metric("ImpossiblePathDetected");
+
+ /**
+ *
+ * Each state update results in a higher {@link State#versionNr versionNr}. The
+ * {@link State#versionNr versionNr} of different State instances can't be meaningfully compared
+ * (ie, same {@link State#versionNr versionNr} just indicates they've gone through the same
+ * number of updates). In particular, the {@link State#versionNr versionNr} of a merged state
+ * doesn't guarantee any more than being different from those of the states being merged.
+ *
+ *
+ *
+ * Still, {@link State#versionNr versionNr} proves useful in two cases:
+ *
+ *
+ *
recording the {@link State#versionNr versionNr} right after {@link State State} cloning,
+ * allows finding out afterwards whether (a) both states have diverged, (b) just one of them, or
+ * (c) none of them.
+ *
a {@link State State} may become {@link State#isUnreachable isUnreachable}. In such case,
+ * it may make a difference whether any updates were performed on the state from the time it was
+ * cloned. Those updates indicate information not available in the state is was cloned from. For
+ * the purposes of {@link FlowSensitiveReduction FlowSensitiveReduction} an unreachable state
+ * need not be merged with any other (because control-flow won't reach the merge point over the
+ * path of the unreachable state).
+ *
+ *
+ *
+ */
+ int versionNr = 0;
+
+ boolean isUnreachable = false;
+
+ /**
+ * Getting here implies an opportunity was detected for dead-code-elimination. A counterpoint
+ * argument goes as follows: perhaps we don't get here that often, in which case the effort to
+ * detect an "impossible path" could be shaved off.
+ *
+ * @see com.oracle.graal.phases.common.cfs.BaseReduction.PostponedDeopt
+ */
+ void impossiblePath() {
+ isUnreachable = true;
+ metricImpossiblePathDetected.increment();
+ }
+
+ /**
+ *
+ * This map semantically tracks "facts" (ie, properties valid for the program-point the state
+ * refers to) as opposed to floating-guard-dependent properties. The
+ * {@link com.oracle.graal.nodes.extended.GuardingNode} being tracked comes handy at
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode)}
+ * .
+ *
+ *
+ *
+ * On a related note, {@link #typeRefinements} also captures information the way
+ * {@link #trueFacts} and {@link #falseFacts} do, including "witnessing" guards. Why not just
+ * standardize on one of them, and drop the other? Because the {@link #typeRefinements} eagerly
+ * aggregates information for easier querying afterwards, e.g. when producing a "downcasted"
+ * value (which involves building a {@link com.oracle.graal.nodes.PiNode}, see
+ * {@link EquationalReasoner#downcast(com.oracle.graal.nodes.ValueNode) downcast()}
+ *
+ *
+ */
+ private IdentityHashMap typeRefinements;
+
+ IdentityHashMap knownNull;
+ IdentityHashMap trueFacts;
+ IdentityHashMap falseFacts;
+
+ public State() {
+ this.typeRefinements = new IdentityHashMap<>();
+ this.knownNull = new IdentityHashMap<>();
+ this.trueFacts = new IdentityHashMap<>();
+ this.falseFacts = new IdentityHashMap<>();
+ }
+
+ public State(State other) {
+ this.isUnreachable = other.isUnreachable;
+ this.versionNr = other.versionNr;
+ this.typeRefinements = new IdentityHashMap<>();
+ for (Map.Entry entry : other.typeRefinements.entrySet()) {
+ this.typeRefinements.put(entry.getKey(), new Witness(entry.getValue()));
+ }
+ this.knownNull = new IdentityHashMap<>(other.knownNull);
+ this.trueFacts = new IdentityHashMap<>(other.trueFacts);
+ this.falseFacts = new IdentityHashMap<>(other.falseFacts);
+ }
+
+ /**
+ * @return A new list containing only those states that are reachable.
+ */
+ private static ArrayList reachableStates(List states) {
+ ArrayList result = new ArrayList<>(states);
+ Iterator iter = result.iterator();
+ while (iter.hasNext()) {
+ if (iter.next().isUnreachable) {
+ iter.remove();
+ }
+ }
+ return result;
+ }
+
+ private IdentityHashMap mergeKnownTypes(MergeNode merge, ArrayList withReachableStates) {
+ IdentityHashMap newKnownTypes = new IdentityHashMap<>();
+
+ for (Map.Entry entry : typeRefinements.entrySet()) {
+ ValueNode node = entry.getKey();
+ Witness type = new Witness(entry.getValue());
+
+ for (State other : withReachableStates) {
+ Witness otherType = other.typeInfo(node);
+ if (otherType == null) {
+ type = null;
+ break;
+ }
+ type.merge(otherType, merge);
+ }
+ if (type != null && type.knowsBetterThan(node)) {
+ assert node == GraphUtil.unproxify(node);
+ newKnownTypes.put(node, type);
+ }
+ }
+
+ return newKnownTypes;
+ }
+
+ private IdentityHashMap mergeKnownNull(MergeNode merge, ArrayList withReachableStates) {
+ // newKnownNull starts empty
+ IdentityHashMap newKnownNull = new IdentityHashMap<>();
+ for (Map.Entry entry : knownNull.entrySet()) {
+ ValueNode key = entry.getKey();
+ GuardingNode newGN = entry.getValue();
+ boolean missing = false;
+
+ for (State other : withReachableStates) {
+ GuardingNode otherGuard = other.knownNull.get(key);
+ if (otherGuard == null) {
+ missing = true;
+ break;
+ }
+ if (otherGuard != newGN) {
+ newGN = merge;
+ }
+ }
+ if (!missing) {
+ newKnownNull.put(key, newGN);
+ }
+ }
+ return newKnownNull;
+ }
+
+ /**
+ *
+ * This method handles phis, by adding to the resulting state any information that can be gained
+ * (about type-refinement and nullness) based on the data available at each of the incoming
+ * branches.
+ *
+ *
+ *
+ * In more detail, FlowSensitiveReduction#visitAbstractEndNode() has already
+ * deverbosified the phi-values contributed by each reachable branch. The paths that
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction} determined to be
+ * unreachable will be eliminated by canonicalization and dead code elimination. For now they
+ * still exist, thus polluting the result of
+ * {@link com.oracle.graal.nodes.ValuePhiNode#inferPhiStamp()} but we are careful to skip them
+ * when merging type-witnesses and known-null maps.
+ *
+ */
+ private void mergePhis(MergeNode merge, List withStates, IdentityHashMap newKnownPhiTypes, IdentityHashMap newKnownNullPhis) {
+
+ if (merge instanceof LoopBeginNode) {
+ return;
+ }
+
+ for (PhiNode phi : merge.phis()) {
+ assert phi == GraphUtil.unproxify(phi);
+ if (phi instanceof ValuePhiNode && phi.getKind() == Kind.Object) {
+ ArrayList reachingValues = new ArrayList<>();
+ if (!isUnreachable) {
+ reachingValues.add(phi.valueAt(0));
+ }
+ for (int i = 0; i < withStates.size(); i++) {
+ State otherState = withStates.get(i);
+ if (!otherState.isUnreachable) {
+ reachingValues.add(phi.valueAt(i + 1));
+ }
+ }
+ assert !reachingValues.isEmpty();
+ ObjectStamp phiStamp = (ObjectStamp) phi.stamp();
+ ObjectStamp nonPollutedStamp = (ObjectStamp) StampTool.meet(reachingValues);
+ Witness w = new Witness(nonPollutedStamp, merge);
+ if (FlowUtil.isMorePrecise(w.type(), phiStamp.type())) {
+ // precision gain regarding type
+ newKnownPhiTypes.put(phi, w);
+ // confirm no precision loss regarding nullness
+ assert implies(phiStamp.nonNull(), w.isNonNull());
+ } else if (w.isNonNull() && !phiStamp.nonNull()) {
+ // precision gain regarding nullness
+ newKnownPhiTypes.put(phi, w);
+ // confirm no precision loss regarding type
+ assert !FlowUtil.isMorePrecise(phiStamp.type(), w.type());
+ }
+ if (nonPollutedStamp.alwaysNull()) {
+ newKnownNullPhis.put(phi, merge);
+ }
+ }
+ }
+
+ }
+
+ private static boolean implies(boolean a, boolean b) {
+ return !a || b;
+ }
+
+ @Override
+ public boolean merge(MergeNode merge, List withStates) {
+
+ ArrayList withReachableStates = reachableStates(withStates);
+ if (withReachableStates.isEmpty()) {
+ return true;
+ }
+
+ for (State state : withReachableStates) {
+ versionNr = Math.max(versionNr, state.versionNr) + 1;
+ isUnreachable &= state.isUnreachable;
+ }
+
+ if (isUnreachable) {
+ typeRefinements.clear();
+ knownNull.clear();
+ trueFacts.clear();
+ falseFacts.clear();
+ return true;
+ }
+
+ // may also get updated in a moment, during processing of phi nodes.
+ IdentityHashMap newKnownTypes = mergeKnownTypes(merge, withReachableStates);
+ // may also get updated in a moment, during processing of phi nodes.
+ IdentityHashMap newKnownNull = mergeKnownNull(merge, withReachableStates);
+ mergePhis(merge, withStates, newKnownTypes, newKnownNull);
+ this.typeRefinements = newKnownTypes;
+ this.knownNull = newKnownNull;
+
+ this.trueFacts = mergeTrueFacts(withReachableStates, merge);
+ this.falseFacts = mergeFalseFacts(withReachableStates, merge);
+ return true;
+ }
+
+ private IdentityHashMap mergeTrueFacts(ArrayList withReachableStates, GuardingNode merge) {
+ IdentityHashMap newTrueConditions = new IdentityHashMap<>();
+ for (Map.Entry entry : trueFacts.entrySet()) {
+ LogicNode check = entry.getKey();
+ GuardingNode guard = entry.getValue();
+
+ for (State other : withReachableStates) {
+ GuardingNode otherGuard = other.trueFacts.get(check);
+ if (otherGuard == null) {
+ guard = null;
+ break;
+ }
+ if (otherGuard != guard) {
+ guard = merge;
+ }
+ }
+ if (guard != null) {
+ newTrueConditions.put(check, guard);
+ }
+ }
+ return newTrueConditions;
+ }
+
+ private IdentityHashMap mergeFalseFacts(ArrayList withReachableStates, GuardingNode merge) {
+ IdentityHashMap newFalseConditions = new IdentityHashMap<>();
+ for (Map.Entry entry : falseFacts.entrySet()) {
+ LogicNode check = entry.getKey();
+ GuardingNode guard = entry.getValue();
+
+ for (State other : withReachableStates) {
+ GuardingNode otherGuard = other.falseFacts.get(check);
+ if (otherGuard == null) {
+ guard = null;
+ break;
+ }
+ if (otherGuard != guard) {
+ guard = merge;
+ }
+ }
+ if (guard != null) {
+ newFalseConditions.put(check, guard);
+ }
+ }
+ return newFalseConditions;
+ }
+
+ /**
+ * @return null if no type-witness available for the argument, the witness otherwise.
+ */
+ public Witness typeInfo(ValueNode object) {
+ assert FlowUtil.hasLegalObjectStamp(object);
+ return typeRefinements.get(GraphUtil.unproxify(object));
+ }
+
+ /**
+ * @return true iff the argument is known to stand for null.
+ */
+ public boolean isNull(ValueNode object) {
+ assert FlowUtil.hasLegalObjectStamp(object);
+ return StampTool.isObjectAlwaysNull(object) || knownNull.containsKey(GraphUtil.unproxify(object));
+ }
+
+ /**
+ *
+ * It makes a difference calling {@link Witness#isNonNull()} as opposed to
+ * {@link State#isNonNull(com.oracle.graal.nodes.ValueNode)}. The former guarantees the witness
+ * provides a guard certifying non-nullness. The latter just tells us there exists some guard
+ * that certifies the property we asked about.
+ *
+ *
+ *
+ * TODO improvement: isKnownNonNull could be made smarter by noticing some nodes always denote a
+ * non-null value (eg, ObjectGetClassNode). Similarly for isKnownNull. Code that looks at the
+ * stamp as well as code that looks for a non-null-witness would benefit from also checking such
+ * extended isKnownNonNull. Alternatively, the stamp of those nodes should always have
+ * is-non-null set.
+ *
+ *
+ * @return true iff the argument is known to stand for non-null.
+ */
+ public boolean isNonNull(ValueNode object) {
+ assert FlowUtil.hasLegalObjectStamp(object);
+ if (StampTool.isObjectNonNull(object)) {
+ return true;
+ }
+ Witness w = typeInfo(object);
+ return w == null ? false : w.isNonNull();
+ }
+
+ /**
+ * @return true iff the argument is known to stand for an object conforming to the given type.
+ */
+ public boolean knownToConform(ValueNode object, ResolvedJavaType to) {
+ assert FlowUtil.hasLegalObjectStamp(object);
+ assert !to.isPrimitive();
+ ResolvedJavaType stampType = StampTool.typeOrNull(object);
+ if (stampType != null && to.isAssignableFrom(stampType)) {
+ return true;
+ }
+ final ValueNode scrutinee = GraphUtil.unproxify(object);
+ if (isNull(scrutinee)) {
+ return true;
+ }
+ Witness w = typeInfo(scrutinee);
+ boolean witnessAnswer = w != null && w.type() != null && to.isAssignableFrom(w.type());
+ if (witnessAnswer) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @return true iff the argument is known to stand for an object that definitely does not
+ * conform to the given type.
+ */
+ public boolean knownNotToConform(ValueNode object, ResolvedJavaType to) {
+ assert FlowUtil.hasLegalObjectStamp(object);
+ assert !to.isPrimitive();
+ final ValueNode scrutinee = GraphUtil.unproxify(object);
+ if (isNull(scrutinee)) {
+ return false;
+ }
+ ResolvedJavaType stampType = StampTool.typeOrNull(object);
+ if (stampType != null && knownNotToConform(stampType, to)) {
+ return true;
+ }
+ Witness w = typeInfo(scrutinee);
+ boolean witnessAnswer = w != null && !w.cluelessAboutType() && knownNotToConform(w.type(), to);
+ if (witnessAnswer) {
+ return true;
+ }
+ return false;
+ }
+
+ // @formatter:off
+ /**
+ * \ | | | |
+ * \ b| | | |
+ * a \ | | | |
+ * \|iface|final|non-f|
+ * -----+-----------------|
+ * iface| F | F | F |
+ * -----+-----------------|
+ * final| C | C | C |
+ * -----+-----------------|
+ * non-f| F | C | C |
+ * -----------------------+
+ *
+ * where:
+ * F: false
+ * C: check
+ * iface: interface
+ * final: exact non-interface reference-type
+ * non-f: non-exact non-interface reference-type
+ *
+ * @return true iff the first argument is known not to conform to the second argument.
+ */
+ // @formatter:on
+ public static boolean knownNotToConform(ResolvedJavaType a, ResolvedJavaType b) {
+ assert !a.isPrimitive();
+ assert !b.isPrimitive();
+ if (b.isAssignableFrom(a)) {
+ return false;
+ }
+ if (a.isInterface()) {
+ return false;
+ }
+ boolean aFinal = Modifier.isFinal(a.getModifiers());
+ if (b.isInterface() && !aFinal) {
+ return false;
+ }
+ if (a.isAssignableFrom(b)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ @Override
+ public State clone() {
+ return new State(this);
+ }
+
+ /**
+ * Porcelain method.
+ */
+ private Witness getOrElseAddTypeInfo(ValueNode object) {
+ ValueNode scrutinee = GraphUtil.unproxify(object);
+ Witness w = typeRefinements.get(scrutinee);
+ if (w == null) {
+ w = new Witness();
+ typeRefinements.put(scrutinee, w);
+ }
+ return w;
+ }
+
+ /**
+ *
+ * Updates this {@link State State} to account for an observation about the scrutinee being
+ * non-null. In case instanceof was observed,
+ * {@link #trackIO(com.oracle.graal.nodes.ValueNode, com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+ * trackIO(ResolvedJavaType, GuardingNode)} should be invoked instead.
+ *
+ *
+ *
+ * No check is made on whether a contradiction would be introduced into the factbase (in which
+ * case the state should be marked unreachable), the caller takes care of that.
+ *
+ *
+ * @return whether state was updated (iff the observation added any new information)
+ */
+ public boolean trackNN(ValueNode object, GuardingNode anchor) {
+ if (isDependencyTainted(object, anchor)) {
+ return false;
+ }
+ assert anchor instanceof FixedNode;
+ ResolvedJavaType stampType = StampTool.typeOrNull(object);
+ if (stampType != null && !stampType.isInterface()) {
+ return trackIO(object, stampType, anchor);
+ }
+ Witness w = getOrElseAddTypeInfo(object);
+ if (w.trackNN(anchor)) {
+ versionNr++;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Updates this {@link State State} to account for an observation about the scrutinee conforming
+ * to a type. In case instanceof was observed,
+ * {@link #trackIO(com.oracle.graal.nodes.ValueNode, com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+ * trackIO(ResolvedJavaType, GuardingNode)} should be invoked instead.
+ *
+ *
+ * No check is made on whether a contradiction would be introduced into the factbase (in which
+ * case the state should be marked unreachable), the caller must take care of that.
+ *
+ *
+ * @return false iff the observed type is an interface, or doesn't provide any new information
+ * not already known. Ie, this method returns true iff the observation resulted in
+ * information gain.
+ */
+ public boolean trackCC(ValueNode object, ResolvedJavaType observed, GuardingNode anchor) {
+ if (observed.isInterface()) {
+ return false;
+ }
+ if (isDependencyTainted(object, anchor)) {
+ return false;
+ }
+ assert anchor instanceof FixedNode;
+ Witness w = getOrElseAddTypeInfo(object);
+ if (w.trackCC(observed, anchor)) {
+ versionNr++;
+ metricTypeRegistered.increment();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Updates this {@link State State} to account for an observation about the non-null scrutinee
+ * conforming to a type.
+ *
+ *
+ * No check is made on whether a contradiction would be introduced into the factbase (in which
+ * case the state should be marked unreachable), the caller must take care of that.
+ *
+ *
+ * @return whether state was updated (iff the observation added any new information)
+ */
+ public boolean trackIO(ValueNode object, ResolvedJavaType observed, GuardingNode anchor) {
+ assert !observed.isInterface() : "no infrastructure yet in State.Witness to support interfaces in general";
+ if (isDependencyTainted(object, anchor)) {
+ return false;
+ }
+ assert anchor instanceof FixedNode;
+ Witness w = getOrElseAddTypeInfo(object);
+ if (w.trackIO(observed, anchor)) {
+ versionNr++;
+ metricTypeRegistered.increment();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * This method increases {@link #versionNr} (thus potentially invalidating
+ * {@link EquationalReasoner EquationalReasoner}'s caches) only if the fact wasn't known
+ * already.
+ *
+ *
+ * No check is made on whether a contradiction would be introduced into the factbase (in which
+ * case the state should be marked unreachable), the caller must take care of that.
+ *
track inferred less-than edges from (accumulated) CompareNode-s
+ *
track set-representative for equality classes determined by (chained) IntegerTestNode
+ *
+ *
+ */
+ public void addFact(boolean isTrue, LogicNode condition, GuardingNode anchor) {
+ assert anchor != null;
+ assert anchor instanceof FixedNode;
+ assert !isUnreachable;
+
+ if (condition instanceof LogicConstantNode) {
+ if (((LogicConstantNode) condition).getValue() != isTrue) {
+ impossiblePath();
+ }
+ return;
+ }
+
+ if (condition instanceof LogicNegationNode) {
+ addFact(!isTrue, ((LogicNegationNode) condition).getInput(), anchor);
+ } else if (condition instanceof ShortCircuitOrNode) {
+ /*
+ * We can register the conditions being or-ed as long as the anchor is a fixed node,
+ * because floating guards will be registered at a BeginNode but might be "valid" only
+ * later due to data flow dependencies. Therefore, registering both conditions of a
+ * ShortCircuitOrNode for a floating guard could lead to cycles in data flow, because
+ * the guard will be used as anchor for both conditions, and one condition could be
+ * depending on the other.
+ */
+ if (isTrue) {
+ CastCheckExtractor cce = CastCheckExtractor.extract(condition);
+ if (cce == null || isDependencyTainted(cce.subject, anchor)) {
+ addFactPrimordial(condition, isTrue ? trueFacts : falseFacts, anchor);
+ } else {
+ trackCC(cce.subject, cce.type, anchor);
+ }
+ } else {
+ ShortCircuitOrNode disjunction = (ShortCircuitOrNode) condition;
+ addFact(disjunction.isXNegated(), disjunction.getX(), anchor);
+ // previous addFact might have resulted in impossiblePath()
+ if (isUnreachable) {
+ return;
+ }
+ addFact(disjunction.isYNegated(), disjunction.getY(), anchor);
+ }
+ } else if (condition instanceof InstanceOfNode) {
+ addFactInstanceOf(isTrue, (InstanceOfNode) condition, anchor);
+ } else if (condition instanceof IsNullNode) {
+ IsNullNode nullCheck = (IsNullNode) condition;
+ addNullness(isTrue, nullCheck.object(), anchor);
+ } else if (condition instanceof ObjectEqualsNode) {
+ addFactObjectEqualsNode(isTrue, (ObjectEqualsNode) condition, anchor);
+ } else {
+ addFactPrimordial(condition, isTrue ? trueFacts : falseFacts, anchor);
+ }
+ }
+
+ /**
+ * An instanceof hint is tracked differently depending on whether it's an interface-test or not
+ * (because type-refinements currently lacks the ability to track interface types).
+ *
+ */
+ private void addFactInstanceOf(boolean isTrue, InstanceOfNode instanceOf, GuardingNode anchor) {
+ ValueNode object = instanceOf.object();
+ if (isTrue) {
+ if (knownNotToConform(object, instanceOf.type())) {
+ impossiblePath();
+ return;
+ }
+ addNullness(false, object, anchor);
+ if (instanceOf.type().isInterface()) {
+ if (!knownToConform(object, instanceOf.type())) {
+ addFactPrimordial(instanceOf, trueFacts, anchor);
+ }
+ } else {
+ trackIO(object, instanceOf.type(), anchor);
+ }
+ } else {
+ if (knownToConform(object, instanceOf.type())) {
+ impossiblePath(); // TODO this used to be a bug
+ return;
+ }
+ if (instanceOf.type().isInterface()) {
+ if (!knownNotToConform(object, instanceOf.type())) {
+ addFactPrimordial(instanceOf, falseFacts, anchor);
+ }
+ }
+ }
+ }
+
+ private void addFactObjectEqualsNode(boolean isTrue, ObjectEqualsNode equals, GuardingNode anchor) {
+ if (isDependencyTainted(equals.x(), anchor)) {
+ return;
+ }
+ if (isDependencyTainted(equals.y(), anchor)) {
+ return;
+ }
+ assert anchor instanceof FixedNode;
+ ValueNode x = GraphUtil.unproxify(equals.x());
+ ValueNode y = GraphUtil.unproxify(equals.y());
+ if (isTrue) {
+ if (isNull(x) && isNonNull(y)) {
+ impossiblePath();
+ return;
+ }
+ if (isNonNull(x) && isNull(y)) {
+ impossiblePath();
+ return;
+ }
+ if (isNull(x) || isNull(y)) {
+ metricObjectEqualsRegistered.increment();
+ addNullness(true, equals.x(), anchor);
+ addNullness(true, equals.y(), anchor);
+ } else if (isNonNull(x) || isNonNull(y)) {
+ metricObjectEqualsRegistered.increment();
+ addNullness(false, equals.x(), anchor);
+ addNullness(false, equals.y(), anchor);
+ }
+ Witness wx = typeInfo(x);
+ Witness wy = typeInfo(y);
+ if (wx == null && wy == null) {
+ return;
+ } else if (wx != null && wy != null) {
+ // tighten their type-hints, provided at least one available
+ // both witnesses may have seen == null, ie they may be NN witnesses
+ ResolvedJavaType best = FlowUtil.tighten(wx.type(), wy.type());
+ if (best != null) {
+ assert !best.isInterface();
+ // type tightening is enough, nullness already taken care of
+ trackCC(equals.x(), best, anchor);
+ trackCC(equals.y(), best, anchor);
+ }
+ } else if (wx == null) {
+ typeRefinements.put(x, new Witness(wy));
+ } else if (wy == null) {
+ typeRefinements.put(y, new Witness(wx));
+ }
+ } else {
+ if (isNull(x) && !isNonNull(y)) {
+ metricObjectEqualsRegistered.increment();
+ addNullness(false, equals.y(), anchor);
+ } else if (!isNonNull(x) && isNull(y)) {
+ metricObjectEqualsRegistered.increment();
+ addNullness(false, equals.x(), anchor);
+ }
+ }
+ }
+
+ /**
+ * Adds information about the nullness of a value. If isNull is true then the value is known to
+ * be null, otherwise the value is known to be non-null.
+ */
+ public void addNullness(boolean isNull, ValueNode value, GuardingNode anchor) {
+ if (isDependencyTainted(value, anchor)) {
+ return;
+ }
+ assert anchor instanceof FixedNode;
+ ValueNode original = GraphUtil.unproxify(value);
+ boolean wasNull = isNull(original);
+ boolean wasNonNull = isNonNull(original);
+ if (isNull) {
+ if (wasNonNull) {
+ impossiblePath();
+ } else {
+ metricNullnessRegistered.increment();
+ versionNr++;
+ knownNull.put(original, anchor);
+ }
+ } else {
+ if (wasNull) {
+ impossiblePath();
+ } else {
+ metricNullnessRegistered.increment();
+ trackNN(original, anchor);
+ }
+ }
+ }
+
+ /**
+ *
+ * @return true iff `value` may lose dependency not covered by `anchor`.
+ */
+ public static boolean isDependencyTainted(ValueNode value, GuardingNode anchor) {
+ assert anchor instanceof FixedNode;
+ if (value instanceof ValueProxy) {
+ if (value instanceof GuardedNode) {
+ GuardedNode gn = (GuardedNode) value;
+ GuardingNode guardian = gn.getGuard();
+ if (guardian != null) {
+ boolean isGuardedByFixed = guardian instanceof FixedNode;
+ if (!isGuardedByFixed) {
+ return true;
+ }
+ }
+ }
+ // if (value instanceof GuardingNode) {
+ // return true;
+ // }
+ ValueProxy proxy = (ValueProxy) value;
+ return isDependencyTainted(proxy.getOriginalNode(), anchor);
+ }
+ return false;
+ }
+
+ public void clear() {
+ versionNr = 0;
+ isUnreachable = false;
+ typeRefinements.clear();
+ knownNull.clear();
+ trueFacts.clear();
+ falseFacts.clear();
+ }
+
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Witness.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Witness.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2012, 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 com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+
+/**
+ *
+ * A witness progressively tracks more detailed properties about an object value (the scrutinee);
+ * the properties in question comprise whether the scrutinee has been observed:
+ *
+ *
+ *
as non-null,
+ *
in a successful checkcast, or
+ *
in a successful instanceof.
+ *
+ *
+ *
+ *
+ * A witness is updated only when doing so increases the information content of the witness. For
+ * example, upon visiting a {@link com.oracle.graal.nodes.java.CheckCastNode CheckCastNode} the
+ * witness gets a chance to become updated.
+ *
+ *
+ *
+ * Therefore, at any given time, a witness represents the most detailed knowledge available so far
+ * about the scrutinee, which is the knowledge most relevant for upcoming program-points.
+ *
+ *
+ *
+ * The availability of witnesses about both non-nullness and checkcast (for a given scrutinee)
+ * promotes to an instanceof-style witness . The "levels" of knowledge a witness may exhibit are
+ * captured by {@link com.oracle.graal.phases.common.cfs.Witness.LEVEL}. For conciseness, the
+ * following query methods are available for a {@link com.oracle.graal.phases.common.cfs.Witness}:
+ *
+ *
{@link #atNonNull()}
+ *
{@link #atCheckCast()}
+ *
{@link #atInstanceOf()}
+ *
+ *
+ *
+ *
+ * Only non-interface object types (ie, class and array types) are tracked. Small extensions are
+ * required to track interfaces, extensions that might be added after the current scheme proves
+ * itself.
+ *
+ *
+ *
+ * Some useful facts about the Statechart implemented by {@link Witness Witness}:
+ *
+ *
+ *
the start-state is "clueless"
+ *
+ * A self-transition via trackCC from whichever the current state is to itself, without information
+ * gain, is always possible. Just give {@link Object java.lang.Object} as observed type.
+ *
+ *
+ *
+ */
+public class Witness implements Cloneable {
+
+ private static enum LEVEL {
+ CLUELESS,
+ NN,
+ CC,
+ IO
+ }
+
+ private boolean atNonNull() {
+ return level == LEVEL.NN;
+ }
+
+ private boolean atCheckCast() {
+ return level == LEVEL.CC;
+ }
+
+ private boolean atInstanceOf() {
+ return level == LEVEL.IO;
+ }
+
+ private void transition(LEVEL to, GuardingNode newAnchor) {
+ this.level = to;
+ this.gn = newAnchor;
+ assert repOK();
+ }
+
+ public Witness() {
+ }
+
+ public Witness(Witness other) {
+ level = other.level;
+ seen = other.seen;
+ gn = other.gn;
+ }
+
+ /**
+ * Counterpart to {@link #asStamp()}
+ */
+ public Witness(ObjectStamp stamp, GuardingNode anchor) {
+ assert stamp.isLegal();
+ assert anchor != null;
+ boolean isNonIface = (stamp.type() != null && !stamp.type().isInterface());
+ if (stamp.nonNull()) {
+ if (isNonIface) {
+ seen = stamp.type();
+ transition(LEVEL.IO, anchor);
+ } else {
+ seen = null;
+ transition(LEVEL.NN, anchor);
+ }
+ } else {
+ if (isNonIface) {
+ seen = stamp.type();
+ transition(LEVEL.CC, anchor);
+ } else {
+ seen = null;
+ transition(LEVEL.CLUELESS, null);
+ assert clueless();
+ }
+ }
+ assert repOK();
+ }
+
+ /**
+ * Type-witnesses aren't tracked for known-to-be-null. Therefore, although method
+ * {@link #isNonNull() isNonNull()} can be found in this class there's on purpose no companion
+ * isNull() .
+ */
+ public boolean isNonNull() {
+ return atNonNull() || atInstanceOf();
+ }
+
+ /**
+ * The most precise type known so far about the scrutinee. (Please notice that nothing can be
+ * deduced about the non-nullness-status of the scrutinee from invoking this method alone).
+ */
+ public ResolvedJavaType type() {
+ return seen;
+ }
+
+ public ObjectStamp asStamp() {
+ boolean isKnownExact = (seen != null && seen.equals(seen.asExactType()));
+ return new ObjectStamp(seen, isKnownExact, isNonNull(), false);
+ }
+
+ private LEVEL level = LEVEL.CLUELESS;
+ private ResolvedJavaType seen = null;
+
+ /**
+ * Evidence (ie, a {@link com.oracle.graal.nodes.extended.GuardingNode}) attesting to the status
+ * reported by this witness.
+ *
+ * May be one of:
+ *
+ *
{@link com.oracle.graal.nodes.MergeNode MergeNode}, resulting from merging two witnesses
+ * with different values for this anchor
+ *
+ *
+ *
+ * An {@link com.oracle.graal.nodes.calc.ObjectEqualsNode ObjectEqualsNode} test results in the
+ * more-clueless of both scrutinees having its witness upgraded to that of the other (both
+ * scrutinees share the same {@link Witness Witness} instance from then on). For this reason,
+ * this field may also hold the anchors associated to an
+ * {@link com.oracle.graal.nodes.calc.ObjectEqualsNode ObjectEqualsNode} occurrence, ie nodes
+ * that can serve as {@link com.oracle.graal.nodes.extended.GuardingNode GuardingNode} for the
+ * purposes of building a {@link com.oracle.graal.nodes.PiNode PiNode}.
+ *
+ *
+ */
+ private GuardingNode gn = null;
+
+ /**
+ * Invariants of this class:
+ *
+ *
All fields holding null is ok, the hallmark of a {@link #clueless() clueless} witness.
+ * Another way for a witness to be clueless is by recording java.lang.Object as the
+ * seen type and nothing more.
+ *
{@link #seen seen} may be null as long as the only hint being recorded is non-nullness
+ *
A non-null value for {@link #seen seen} can't be tracked with NN, that combination
+ * amounts to IO and is tracked as such
+ *
At most one of NN, CC, IO may be tracked at any given time
+ *
A non-null CC or a non-null IO force {@link #seen seen} to be non-null
+ *
{@link #seen seen} must be null or denote a non-interface reference type (ie, either a
+ * class-type or an array-type)
+ *
+ */
+ private boolean repOK() {
+ if (clueless()) {
+ assert level == LEVEL.CLUELESS;
+ return true;
+ }
+ if (level == LEVEL.NN) {
+ assert seen == null;
+ }
+ if (seen != null) {
+ assert !seen.isInterface();
+ assert !seen.isPrimitive();
+ }
+ boolean gnOK = gn instanceof BeginNode || gn instanceof LoopExitNode || gn instanceof MergeNode || gn instanceof FixedGuardNode;
+ assert gnOK;
+ return true;
+ }
+
+ /**
+ * Helper method for readability in complex conditions.
+ */
+ public boolean clueless() {
+ return cluelessAboutType() && cluelessAboutNonNullness();
+ }
+
+ /**
+ * Helper method for readability in complex conditions.
+ */
+ public boolean cluelessAboutType() {
+ // TODO also clueless when `seen` is `java.lang.Object`
+ return seen == null;
+ }
+
+ /**
+ * Helper method for readability in complex conditions.
+ */
+ public boolean cluelessAboutNonNullness() {
+ return !atNonNull() && !atInstanceOf();
+ }
+
+ /**
+ * Whether this {@link Witness Witness} tracks information strictly more precise than that in
+ * the given {@link com.oracle.graal.compiler.common.type.ObjectStamp}.
+ */
+ boolean knowsBetterThan(ObjectStamp other) {
+ return FlowUtil.isMorePrecise(asStamp(), other);
+ }
+
+ /**
+ * Whether this {@link Witness Witness} tracks information strictly more precise than that in
+ * the {@link com.oracle.graal.compiler.common.type.ObjectStamp} of the given argument.
+ */
+ boolean knowsBetterThan(ValueNode other) {
+ return knowsBetterThan((ObjectStamp) other.stamp());
+ }
+
+ /**
+ * Porcelain method for internal use only, invoked upon a Facade method being notified about
+ * checkcast or instanceof.
+ *
+ * @return whether the state was updated (iff the observation adds any new information)
+ */
+ private boolean refinesSeenType(ResolvedJavaType observed) {
+ if (cluelessAboutType() || FlowUtil.isMorePrecise(observed, seen)) {
+ seen = observed;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Updates this {@link Witness Witness} to account for an observation about the scrutinee being
+ * non-null. In case instanceof was observed,
+ * {@link #trackIO(com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+ * trackIO(ResolvedJavaType, GuardingNode)} should be invoked instead
+ *
+ * @return whether this {@link Witness Witness} was updated (iff the observation adds any new
+ * information)
+ */
+ public boolean trackNN(GuardingNode anchor) {
+ assert repOK();
+ try {
+ if (atInstanceOf()) {
+ return false;
+ }
+ if (atCheckCast()) {
+ transition(LEVEL.IO, anchor);
+ return true;
+ }
+ if (!atNonNull()) {
+ transition(LEVEL.NN, anchor);
+ return true;
+ }
+ return false;
+ } finally {
+ assert repOK();
+ }
+ }
+
+ /**
+ * Updates this {@link Witness Witness} to account for an observation about the scrutinee
+ * conforming to the provided type. In case instanceof was observed,
+ * {@link #trackIO(com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+ * trackIO(ResolvedJavaType, GuardingNode)} should be invoked instead.
+ *
+ * @return true iff information was gained.
+ */
+ public boolean trackCC(ResolvedJavaType observed, GuardingNode anchor) {
+ assert !observed.isInterface();
+ assert anchor != null;
+ assert repOK();
+ try {
+ boolean anchorObsolete = refinesSeenType(observed);
+ if (atInstanceOf()) {
+ /*
+ * Statechart: self-transition at IO, potential information gain.
+ */
+ if (anchorObsolete) {
+ transition(LEVEL.IO, anchor);
+ return true;
+ }
+ return false;
+ }
+ if (anchorObsolete) {
+ if (!atNonNull()) {
+ /* Statechart: transition from clueless to CC. */
+ transition(LEVEL.CC, anchor);
+ return true;
+ } else {
+ /* Statechart: transition from NN to IO. */
+ transition(LEVEL.IO, anchor);
+ return true;
+ }
+ }
+ /*
+ * Statechart: self-transition from whichever the current state is to itself, without
+ * information gain.
+ */
+ return false;
+ } finally {
+ assert repOK();
+ }
+ }
+
+ /**
+ * Updates this {@link Witness Witness} to account for an observation about the non-null
+ * scrutinee conforming to a type.
+ *
+ * @return whether this {@link Witness Witness} was updated (iff the observation adds any new
+ * information)
+ */
+ public boolean trackIO(ResolvedJavaType observed, GuardingNode anchor) {
+ assert repOK();
+ try {
+ boolean gotMorePreciseType = refinesSeenType(observed);
+ if (!atInstanceOf() || gotMorePreciseType) {
+ transition(LEVEL.IO, anchor);
+ return true;
+ }
+ return gotMorePreciseType;
+ } finally {
+ assert repOK();
+ }
+ }
+
+ /**
+ * Shallow cloning is enough because what's reachable from {@link Witness} is primitive or used
+ * read-only when merging states.
+ */
+ @Override
+ public Witness clone() {
+ return new Witness(this);
+ }
+
+ /**
+ * @return null for a clueless method, non-null otherwise.
+ */
+ GuardingNode guard() {
+ return gn;
+ }
+
+ /**
+ * Merges another state into this one, by mutating this object, the other is left as is.
+ */
+ public void merge(Witness that, MergeNode merge) {
+ assert this.repOK();
+ assert that.repOK();
+
+ if (clueless()) {
+ return;
+ }
+
+ // umbrella type over the observations from both witnesses
+ ResolvedJavaType newSeen = (seen == null || that.seen == null) ? null : FlowUtil.widen(seen, that.seen);
+
+ // preserve guarding node only if matches other, otherwise settle on `merge`
+ final GuardingNode resultGuard = guard() == that.guard() ? guard() : merge;
+
+ /*
+ * guarantee on (both conformance and non-nullness) required from each input in order for
+ * the result to be able to offer such guarantee
+ */
+ final boolean resultIO = atInstanceOf() && that.atInstanceOf();
+ /* failing that, attempt to rescue type-conformance */
+ final boolean resultCC = !resultIO && (!cluelessAboutType() && !that.cluelessAboutType());
+ /* if all else fails, attempt to rescue non-nullness */
+ final boolean resultNN = !resultIO && !resultCC && (isNonNull() && that.isNonNull());
+
+ seen = newSeen;
+ level = resultIO ? LEVEL.IO : resultCC ? LEVEL.CC : resultNN ? LEVEL.NN : LEVEL.CLUELESS;
+ gn = resultGuard;
+
+ assert repOK();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(cluelessAboutType() ? "seen=?" : "seen=" + seen);
+ sb.append(";");
+ sb.append("gn=" + gn);
+ return sb.toString();
+ }
+
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java Tue Apr 29 18:35:10 2014 +0200
@@ -72,7 +72,7 @@
try (TimerCloseable a = phaseTimer.start(); Scope s = Debug.scope(getClass(), this)) {
BasePhase.this.run(graph, context);
phaseMetric.increment();
- if (dumpGraph) {
+ if (dumpGraph && Debug.isDumpEnabled()) {
Debug.dump(graph, "After phase %s", getName());
}
assert graph.verify();
@@ -81,13 +81,17 @@
}
}
+ protected CharSequence createName() {
+ String s = BasePhase.this.getClass().getSimpleName();
+ if (s.endsWith("Phase")) {
+ s = s.substring(0, s.length() - "Phase".length());
+ }
+ return s;
+ }
+
public final CharSequence getName() {
if (name == null) {
- String s = BasePhase.this.getClass().getSimpleName();
- if (s.endsWith("Phase")) {
- s = s.substring(0, s.length() - "Phase".length());
- }
- name = s;
+ name = createName();
}
return name;
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Tue Apr 29 18:35:10 2014 +0200
@@ -888,37 +888,114 @@
return true;
}
+ private static class SortState {
+ private Block block;
+ private NodeBitMap visited;
+ private NodeBitMap beforeLastLocation;
+ private List sortedInstructions;
+ private List reads;
+
+ SortState(Block block, NodeBitMap visited, NodeBitMap beforeLastLocation, List sortedInstructions) {
+ this.block = block;
+ this.visited = visited;
+ this.beforeLastLocation = beforeLastLocation;
+ this.sortedInstructions = sortedInstructions;
+ this.reads = null;
+ }
+
+ public Block currentBlock() {
+ return block;
+ }
+
+ void markVisited(Node n) {
+ visited.mark(n);
+ }
+
+ boolean isVisited(Node n) {
+ return visited.isMarked(n);
+ }
+
+ void markBeforeLastLocation(FloatingReadNode n) {
+ beforeLastLocation.mark(n);
+ }
+
+ void clearBeforeLastLocation(FloatingReadNode frn) {
+ beforeLastLocation.clear(frn);
+ }
+
+ boolean isBeforeLastLocation(FloatingReadNode n) {
+ return beforeLastLocation.isMarked(n);
+ }
+
+ void addRead(FloatingReadNode n) {
+ if (reads == null) {
+ reads = new ArrayList<>();
+ }
+ reads.add(n);
+ }
+
+ int readsSize() {
+ if (reads == null) {
+ return 0;
+ }
+ return reads.size();
+ }
+
+ void removeRead(ScheduledNode i) {
+ assert reads != null;
+ reads.remove(i);
+ }
+
+ List readsSnapshot() {
+ assert reads != null;
+ return new ArrayList<>(reads);
+ }
+
+ List getSortedInstructions() {
+ return sortedInstructions;
+ }
+
+ boolean containsInstruction(ScheduledNode i) {
+ return sortedInstructions.contains(i);
+ }
+
+ void addInstruction(ScheduledNode i) {
+ sortedInstructions.add(i);
+ }
+ }
+
/**
* Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over
* all inputs. This means that a node is added to the list after all its inputs have been
* processed.
*/
private List sortNodesWithinBlockLatest(Block b, NodeBitMap visited, NodeBitMap beforeLastLocation) {
+ SortState state = new SortState(b, visited, beforeLastLocation, new ArrayList<>(blockToNodesMap.get(b).size() + 2));
List instructions = blockToNodesMap.get(b);
- List sortedInstructions = new ArrayList<>(blockToNodesMap.get(b).size() + 2);
- List reads = new ArrayList<>();
if (memsched == MemoryScheduling.OPTIMAL) {
for (ScheduledNode i : instructions) {
if (i instanceof FloatingReadNode) {
FloatingReadNode frn = (FloatingReadNode) i;
if (frn.location().getLocationIdentity() != FINAL_LOCATION) {
- reads.add(frn);
+ state.addRead(frn);
if (nodesFor(b).contains(frn.getLastLocationAccess())) {
- assert !beforeLastLocation.isMarked(frn);
- beforeLastLocation.mark(frn);
+ assert !state.isBeforeLastLocation(frn);
+ state.markBeforeLastLocation(frn);
}
}
}
}
}
+
for (ScheduledNode i : instructions) {
- addToLatestSorting(b, i, sortedInstructions, visited, reads, beforeLastLocation);
+ addToLatestSorting(i, state);
}
- assert reads.size() == 0 : "not all reads are scheduled";
+ assert state.readsSize() == 0 : "not all reads are scheduled";
// Make sure that last node gets really last (i.e. when a frame state successor hangs off
// it).
+ List sortedInstructions = state.getSortedInstructions();
Node lastSorted = sortedInstructions.get(sortedInstructions.size() - 1);
if (lastSorted != b.getEndNode()) {
int idx = sortedInstructions.indexOf(b.getEndNode());
@@ -944,40 +1021,39 @@
return sortedInstructions;
}
- private void processKillLocation(Block b, Node node, LocationIdentity identity, List sortedInstructions, NodeBitMap visited, List reads,
- NodeBitMap beforeLastLocation) {
- for (FloatingReadNode frn : new ArrayList<>(reads)) { // TODO: change to iterator?
+ private void processKillLocation(Node node, LocationIdentity identity, SortState state) {
+ for (FloatingReadNode frn : state.readsSnapshot()) {
LocationIdentity readLocation = frn.location().getLocationIdentity();
assert readLocation != FINAL_LOCATION;
if (frn.getLastLocationAccess() == node) {
assert identity == ANY_LOCATION || readLocation == identity : "location doesn't match: " + readLocation + ", " + identity;
- beforeLastLocation.clear(frn);
- } else if (!beforeLastLocation.isMarked(frn) && (readLocation == identity || (node != getCFG().graph.start() && ANY_LOCATION == identity))) {
- reads.remove(frn);
- addToLatestSorting(b, frn, sortedInstructions, visited, reads, beforeLastLocation);
+ state.clearBeforeLastLocation(frn);
+ } else if (!state.isBeforeLastLocation(frn) && (readLocation == identity || (node != getCFG().graph.start() && ANY_LOCATION == identity))) {
+ state.removeRead(frn);
+ addToLatestSorting(frn, state);
}
}
}
- private void addUnscheduledToLatestSorting(Block b, VirtualState state, List sortedInstructions, NodeBitMap visited, List reads, NodeBitMap beforeLastLocation) {
+ private void addUnscheduledToLatestSorting(VirtualState state, SortState sortState) {
if (state != null) {
// UnscheduledNodes should never be marked as visited.
- if (visited.isMarked(state)) {
+ if (sortState.isVisited(state)) {
throw new SchedulingError();
}
for (Node input : state.inputs()) {
if (input instanceof VirtualState) {
- addUnscheduledToLatestSorting(b, (VirtualState) input, sortedInstructions, visited, reads, beforeLastLocation);
+ addUnscheduledToLatestSorting((VirtualState) input, sortState);
} else {
- addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation);
+ addToLatestSorting((ScheduledNode) input, sortState);
}
}
}
}
- private void addToLatestSorting(Block b, ScheduledNode i, List sortedInstructions, NodeBitMap visited, List reads, NodeBitMap beforeLastLocation) {
- if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode) {
+ private void addToLatestSorting(ScheduledNode i, SortState state) {
+ if (i == null || state.isVisited(i) || cfg.getNodeToBlock().get(i) != state.currentBlock() || i instanceof PhiNode) {
return;
}
@@ -988,45 +1064,45 @@
if (i instanceof LoopExitNode) {
for (ProxyNode proxy : ((LoopExitNode) i).proxies()) {
- addToLatestSorting(b, proxy, sortedInstructions, visited, reads, beforeLastLocation);
+ addToLatestSorting(proxy, state);
}
}
for (Node input : i.inputs()) {
if (input instanceof FrameState) {
if (input != stateAfter) {
- addUnscheduledToLatestSorting(b, (FrameState) input, sortedInstructions, visited, reads, beforeLastLocation);
+ addUnscheduledToLatestSorting((FrameState) input, state);
}
} else {
if (!(i instanceof ProxyNode && input instanceof LoopExitNode)) {
- addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation);
+ addToLatestSorting((ScheduledNode) input, state);
}
}
}
- if (memsched == MemoryScheduling.OPTIMAL && reads.size() != 0) {
+ if (memsched == MemoryScheduling.OPTIMAL && state.readsSize() != 0) {
if (i instanceof MemoryCheckpoint.Single) {
LocationIdentity identity = ((MemoryCheckpoint.Single) i).getLocationIdentity();
- processKillLocation(b, i, identity, sortedInstructions, visited, reads, beforeLastLocation);
+ processKillLocation(i, identity, state);
} else if (i instanceof MemoryCheckpoint.Multi) {
for (LocationIdentity identity : ((MemoryCheckpoint.Multi) i).getLocationIdentities()) {
- processKillLocation(b, i, identity, sortedInstructions, visited, reads, beforeLastLocation);
+ processKillLocation(i, identity, state);
}
}
assert MemoryCheckpoint.TypeAssertion.correctType(i);
}
- addToLatestSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited, reads, beforeLastLocation);
- visited.mark(i);
- addUnscheduledToLatestSorting(b, stateAfter, sortedInstructions, visited, reads, beforeLastLocation);
+ addToLatestSorting((ScheduledNode) i.predecessor(), state);
+ state.markVisited(i);
+ addUnscheduledToLatestSorting(stateAfter, state);
// Now predecessors and inputs are scheduled => we can add this node.
- if (!sortedInstructions.contains(i)) {
- sortedInstructions.add(i);
+ if (!state.containsInstruction(i)) {
+ state.addInstruction(i);
}
- if (i instanceof FloatingReadNode) {
- reads.remove(i);
+ if (state.readsSize() != 0 && i instanceof FloatingReadNode) {
+ state.removeRead(i);
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java Tue Apr 29 18:35:10 2014 +0200
@@ -27,6 +27,7 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
import com.oracle.graal.api.runtime.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.replacements.*;
@@ -37,7 +38,7 @@
@ServiceProvider(ReplacementsProvider.class)
public class AMD64Substitutions implements ReplacementsProvider {
- public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, Replacements replacements, TargetDescription target) {
+ public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
if (Intrinsify.getValue()) {
replacements.registerSubstitutions(ArraysSubstitutions.class);
replacements.registerSubstitutions(StringSubstitutions.class);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java Tue Apr 29 18:35:10 2014 +0200
@@ -22,10 +22,11 @@
*/
package com.oracle.graal.replacements.test;
+import org.junit.*;
+
import com.oracle.graal.api.meta.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.test.*;
/**
* Tests the implementation of checkcast, allowing profiling information to be manually specified.
@@ -41,7 +42,7 @@
}
}
- @LongTest
+ @Test
public void test1() {
test("asNumber", profile(), 111);
test("asNumber", profile(Integer.class), 111);
@@ -51,7 +52,7 @@
test("asNumberExt", profile(Long.class, Short.class), 111);
}
- @LongTest
+ @Test
public void test2() {
test("asString", profile(), "111");
test("asString", profile(String.class), "111");
@@ -67,27 +68,27 @@
test("asStringExt", profile(String.class), "111");
}
- @LongTest
+ @Test
public void test3() {
test("asNumber", profile(), "111");
}
- @LongTest
+ @Test
public void test4() {
test("asString", profile(String.class), 111);
}
- @LongTest
+ @Test
public void test5() {
test("asNumberExt", profile(), "111");
}
- @LongTest
+ @Test
public void test6() {
test("asStringExt", profile(String.class), 111);
}
- @LongTest
+ @Test
public void test7() {
Throwable throwable = new Exception();
test("asThrowable", profile(), throwable);
@@ -95,12 +96,12 @@
test("asThrowable", profile(Exception.class, Error.class), throwable);
}
- @LongTest
+ @Test
public void test8() {
test("arrayStore", new Object[100], "111");
}
- @LongTest
+ @Test
public void test801() {
test("arrayFill", new Object[100], "111");
}
@@ -197,7 +198,7 @@
return (Cloneable) o;
}
- @LongTest
+ @Test
public void test9() {
Object o = new Depth13();
test("asDepth12", profile(), o);
@@ -205,7 +206,7 @@
test("asDepth12", profile(Depth13.class, Depth14.class), o);
}
- @LongTest
+ @Test
public void test10() {
Object o = new Depth13[3][];
test("asDepth12Arr", o);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfDynamicTest.java
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfDynamicTest.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfDynamicTest.java Tue Apr 29 18:35:10 2014 +0200
@@ -22,9 +22,10 @@
*/
package com.oracle.graal.replacements.test;
+import org.junit.*;
+
import com.oracle.graal.compiler.test.*;
import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.test.*;
/**
* Tests for {@link InstanceOfDynamicNode}.
@@ -35,7 +36,7 @@
return value;
}
- @LongTest
+ @Test
public void test100() {
final Object nul = null;
test("isStringDynamic", nul);
@@ -43,7 +44,7 @@
test("isStringDynamic", Object.class);
}
- @LongTest
+ @Test
public void test101() {
final Object nul = null;
test("isStringIntDynamic", nul);
@@ -51,7 +52,7 @@
test("isStringIntDynamic", Object.class);
}
- @LongTest
+ @Test
public void test103() {
test("isInstanceDynamic", String.class, null);
test("isInstanceDynamic", String.class, "object");
@@ -61,7 +62,7 @@
test("isInstanceDynamic", int.class, Object.class);
}
- @LongTest
+ @Test
public void test104() {
test("isInstanceIntDynamic", String.class, null);
test("isInstanceIntDynamic", String.class, "object");
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java Tue Apr 29 18:35:10 2014 +0200
@@ -24,6 +24,8 @@
import java.util.*;
+import org.junit.*;
+
import com.oracle.graal.api.code.CompilationResult.Call;
import com.oracle.graal.api.code.CompilationResult.Mark;
import com.oracle.graal.api.code.CompilationResult.Site;
@@ -34,7 +36,6 @@
import com.oracle.graal.replacements.test.CheckCastTest.Depth12;
import com.oracle.graal.replacements.test.CheckCastTest.Depth13;
import com.oracle.graal.replacements.test.CheckCastTest.Depth14;
-import com.oracle.graal.test.*;
/**
* Tests the implementation of instanceof, allowing profiling information to be manually specified.
@@ -54,7 +55,7 @@
}
}
- @LongTest
+ @Test
public void test1() {
test("isString", profile(), "object");
test("isString", profile(String.class), "object");
@@ -63,7 +64,7 @@
test("isString", profile(String.class), Object.class);
}
- @LongTest
+ @Test
public void test2() {
test("isStringInt", profile(), "object");
test("isStringInt", profile(String.class), "object");
@@ -72,7 +73,7 @@
test("isStringInt", profile(String.class), Object.class);
}
- @LongTest
+ @Test
public void test201() {
test("isStringIntComplex", profile(), "object");
test("isStringIntComplex", profile(String.class), "object");
@@ -81,7 +82,7 @@
test("isStringIntComplex", profile(String.class), Object.class);
}
- @LongTest
+ @Test
public void test3() {
Throwable throwable = new Exception();
test("isThrowable", profile(), throwable);
@@ -93,7 +94,7 @@
test("isThrowable", profile(Exception.class, Error.class), Object.class);
}
- @LongTest
+ @Test
public void test301() {
onlyFirstIsException(new Exception(), new Error());
test("onlyFirstIsException", profile(), new Exception(), new Error());
@@ -102,7 +103,7 @@
test("onlyFirstIsException", profile(), new Error(), new Error());
}
- @LongTest
+ @Test
public void test4() {
Throwable throwable = new Exception();
test("isThrowableInt", profile(), throwable);
@@ -114,7 +115,7 @@
test("isThrowableInt", profile(Exception.class, Error.class), Object.class);
}
- @LongTest
+ @Test
public void test5() {
Map, ?> map = new HashMap<>();
test("isMap", profile(), map);
@@ -127,7 +128,7 @@
test("isMap", profile(String.class, HashMap.class), Object.class);
}
- @LongTest
+ @Test
public void test6() {
Map, ?> map = new HashMap<>();
test("isMapInt", profile(), map);
@@ -139,7 +140,7 @@
test("isMapInt", profile(TreeMap.class, HashMap.class), Object.class);
}
- @LongTest
+ @Test
public void test7() {
Object o = new Depth13();
test("isDepth12", profile(), o);
@@ -153,7 +154,7 @@
test("isDepth12", profile(String.class, HashMap.class), o);
}
- @LongTest
+ @Test
public void test8() {
Object o = new Depth13();
test("isDepth12Int", profile(), o);
@@ -259,7 +260,7 @@
}
}
- @LongTest
+ @Test
public void test9() {
MyCall callAt63 = new MyCall(63);
MyMark markAt63 = new MyMark(63);
@@ -276,11 +277,10 @@
return s1.offset - s2.offset;
}
- @LongTest
+ @Test
public void test10() {
- Mark[] noMarks = {};
Call callAt63 = new Call(null, 63, 5, true, null);
- Mark markAt63 = new Mark(63, "1", noMarks);
+ Mark markAt63 = new Mark(63, "1");
test("compareSites", callAt63, callAt63);
test("compareSites", callAt63, markAt63);
test("compareSites", markAt63, callAt63);
@@ -301,7 +301,7 @@
* The test exists in this source file as the transformation was originally motivated by the
* need to remove use of special JumpNodes in the {@code InstanceOfSnippets}.
*/
- @LongTest
+ @Test
public void testRemoveIntermediateMaterialization() {
List list = Arrays.asList("1", "2", "3", "4");
test("removeIntermediateMaterialization", profile(), list, "2", "yes", "no");
@@ -356,7 +356,7 @@
return o instanceof D[];
}
- @LongTest
+ @Test
public void testArray() {
Object aArray = new A[10];
test("isArrayOfA", aArray);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java Tue Apr 29 18:35:10 2014 +0200
@@ -25,7 +25,6 @@
import org.junit.*;
import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.test.*;
/**
* Tests the implementation of {@code [A]NEWARRAY}.
@@ -58,7 +57,7 @@
}
}
- @LongTest
+ @Test
public void test1() {
for (String type : new String[]{"Byte", "Char", "Short", "Int", "Float", "Long", "Double", "String"}) {
test("new" + type + "Array7");
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java Tue Apr 29 18:35:10 2014 +0200
@@ -27,7 +27,6 @@
import org.junit.*;
import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.test.*;
/**
* Tests the implementation of {@code NEW}.
@@ -57,12 +56,12 @@
}
}
- @LongTest
+ @Test
public void test1() {
test("newObject");
}
- @LongTest
+ @Test
public void test2() {
test("newObjectTwice");
}
@@ -71,37 +70,37 @@
return new Object();
}
- @LongTest
+ @Test
public void test3() {
test("newObjectLoop", 100);
}
- @LongTest
+ @Test
public void test4() {
test("newBigObject");
}
- @LongTest
+ @Test
public void test5() {
test("newSomeObject");
}
- @LongTest
+ @Test
public void test6() {
test("newEmptyString");
}
- @LongTest
+ @Test
public void test7() {
test("newString", "value");
}
- @LongTest
+ @Test
public void test8() {
test("newHashMap", 31);
}
- @LongTest
+ @Test
public void test9() {
test("newRegression", true);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewMultiArrayTest.java
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewMultiArrayTest.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewMultiArrayTest.java Tue Apr 29 18:35:10 2014 +0200
@@ -25,12 +25,13 @@
import java.lang.reflect.*;
import java.util.*;
+import org.junit.*;
+
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.test.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.test.*;
/**
* Tests the lowering of the MULTIANEWARRAY instruction.
@@ -86,7 +87,7 @@
Class> bottomClass;
int[] dimensions;
- @LongTest
+ @Test
public void test1() {
for (Class> clazz : new Class[]{byte.class, char.class, short.class, int.class, float.class, long.class, double.class, String.class}) {
bottomClass = clazz;
@@ -117,7 +118,7 @@
return new Object[10][9][8];
}
- @LongTest
+ @Test
public void test2() {
test("newMultiArrayException");
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Tue Apr 29 18:35:10 2014 +0200
@@ -24,6 +24,8 @@
import java.lang.reflect.*;
+import org.junit.*;
+
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.test.*;
@@ -31,7 +33,6 @@
import com.oracle.graal.replacements.*;
import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
-import com.oracle.graal.test.*;
import com.oracle.graal.word.*;
/**
@@ -53,7 +54,7 @@
return installer.makeGraph(resolvedMethod, null, resolvedMethod, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect);
}
- @LongTest
+ @Test
public void construction() {
long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L,
Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L};
@@ -65,7 +66,7 @@
}
}
- @LongTest
+ @Test
public void testArithmetic() {
long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L,
Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L};
@@ -102,7 +103,7 @@
}
}
- @LongTest
+ @Test
public void testCompare() {
long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE};
for (long word1 : words) {
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java Tue Apr 29 18:35:10 2014 +0200
@@ -26,6 +26,7 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
import com.oracle.graal.api.runtime.*;
import com.oracle.graal.nodes.spi.*;
@@ -35,7 +36,7 @@
@ServiceProvider(ReplacementsProvider.class)
public class GraalMethodSubstitutions implements ReplacementsProvider {
- public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, Replacements replacements, TargetDescription target) {
+ public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
for (Class> clazz : BoxingSubstitutions.getClasses()) {
replacements.registerSubstitutions(clazz);
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java Tue Apr 29 18:35:10 2014 +0200
@@ -32,15 +32,13 @@
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.common.*;
import com.oracle.graal.replacements.Snippet.Fold;
-import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.word.*;
/**
* A counter that can be safely {@linkplain #inc() incremented} from within a snippet for gathering
* snippet specific metrics.
*/
public class SnippetCounter implements Comparable {
- private static final LocationIdentity SNIPPET_COUNTER_LOCATION = new NamedLocationIdentity("SnippetCounter");
-
/**
* A group of related counters.
*/
@@ -107,7 +105,7 @@
/**
* Creates a counter.
- *
+ *
* @param group the group to which the counter belongs. If this is null, the newly created
* counter is disabled and {@linkplain #inc() incrementing} is a no-op.
* @param name the name of the counter
@@ -130,12 +128,20 @@
}
/**
+ * We do not want to use the {@link LocationIdentity} of the {@link #value} field, so that the
+ * usage in snippets is always possible. If a method accesses the counter via the field and the
+ * snippet, the result might not be correct though.
+ */
+ protected static final LocationIdentity SNIPPET_COUNTER_LOCATION = new NamedLocationIdentity("SnippetCounter");
+
+ /**
* Increments the value of this counter. This method can be safely used in a snippet if it is
* invoked on a compile-time constant {@link SnippetCounter} object.
*/
public void inc() {
if (group != null) {
- DirectObjectStoreNode.storeLong(this, countOffset(), 0, value + 1, SNIPPET_COUNTER_LOCATION);
+ long loadedValue = ObjectAccess.readLong(this, countOffset(), SNIPPET_COUNTER_LOCATION);
+ ObjectAccess.writeLong(this, countOffset(), loadedValue + 1, SNIPPET_COUNTER_LOCATION);
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Tue Apr 29 18:35:10 2014 +0200
@@ -23,9 +23,11 @@
package com.oracle.graal.replacements;
import static com.oracle.graal.api.meta.LocationIdentity.*;
+
import static com.oracle.graal.api.meta.MetaUtil.*;
import static com.oracle.graal.debug.Debug.*;
import static java.util.FormattableFlags.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
import java.io.*;
import java.lang.reflect.*;
@@ -40,8 +42,8 @@
import com.oracle.graal.debug.*;
import com.oracle.graal.debug.Debug.Scope;
import com.oracle.graal.debug.internal.*;
+import com.oracle.graal.graph.Graph.Mark;
import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Graph.Mark;
import com.oracle.graal.loop.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
@@ -965,7 +967,15 @@
* if no FloatingReadNode is reading from this location, the kill to this location is fine.
*/
for (FloatingReadNode frn : replacee.graph().getNodes(FloatingReadNode.class)) {
- assert !(kills.contains(frn.location().getLocationIdentity())) : frn + " reads from " + frn.location().getLocationIdentity() + " but " + replacee + " does not kill this location";
+ LocationIdentity locationIdentity = frn.location().getLocationIdentity();
+ if (SnippetCounters.getValue()) {
+ // accesses to snippet counters are artificially introduced and violate the memory
+ // semantics.
+ if (locationIdentity == SnippetCounter.SNIPPET_COUNTER_LOCATION) {
+ continue;
+ }
+ }
+ assert !kills.contains(locationIdentity) : frn + " reads from location \"" + locationIdentity + "\" but " + replacee + " does not kill this location";
}
return true;
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -24,8 +24,6 @@
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.*;
@@ -36,7 +34,7 @@
/**
* Compares two arrays with the same length.
*/
-public class ArrayEqualsNode extends FixedWithNextNode implements LIRGenLowerable, Canonicalizable, Virtualizable {
+public class ArrayEqualsNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable {
/** {@link Kind} of the arrays to compare. */
private final Kind kind;
@@ -131,7 +129,7 @@
public static native boolean equals(double[] array1, double[] array2, int length);
@Override
- public void generate(NodeLIRBuilder gen) {
+ public void generate(NodeLIRBuilderTool gen) {
Variable result = gen.newVariable(Kind.Int);
gen.emitArrayEquals(kind, result, gen.operand(array1), gen.operand(array2), gen.operand(length));
gen.setResult(this, result);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -24,15 +24,14 @@
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
-public class BitCountNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class BitCountNode extends FloatingNode implements LIRLowerable, Canonicalizable {
@Input private ValueNode value;
@@ -65,7 +64,7 @@
}
@Override
- public void generate(NodeLIRBuilder gen) {
+ public void generate(NodeLIRBuilderTool gen) {
Variable result = gen.newVariable(Kind.Int);
gen.emitBitCount(result, gen.operand(value));
gen.setResult(this, result);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -24,15 +24,14 @@
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
-public class BitScanForwardNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class BitScanForwardNode extends FloatingNode implements LIRLowerable, Canonicalizable {
@Input private ValueNode value;
@@ -72,7 +71,7 @@
}
@Override
- public void generate(NodeLIRBuilder gen) {
+ public void generate(NodeLIRBuilderTool gen) {
Variable result = gen.newVariable(Kind.Int);
gen.emitBitScanForward(result, gen.operand(value));
gen.setResult(this, result);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -24,15 +24,14 @@
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
-public class BitScanReverseNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class BitScanReverseNode extends FloatingNode implements LIRLowerable, Canonicalizable {
@Input private ValueNode value;
@@ -79,7 +78,7 @@
}
@Override
- public void generate(NodeLIRBuilder gen) {
+ public void generate(NodeLIRBuilderTool gen) {
Variable result = gen.newVariable(Kind.Int);
gen.getLIRGeneratorTool().emitBitScanReverse(result, gen.operand(value));
gen.setResult(this, result);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -24,15 +24,14 @@
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.lir.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
-public class ReverseBytesNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class ReverseBytesNode extends FloatingNode implements LIRLowerable, Canonicalizable {
@Input private ValueNode value;
@@ -66,9 +65,9 @@
}
@Override
- public void generate(NodeLIRBuilder gen) {
+ public void generate(NodeLIRBuilderTool gen) {
Variable result = gen.newVariable(value.getKind());
- gen.getLIRGenerator().emitByteSwap(result, gen.operand(value));
+ gen.getLIRGeneratorTool().emitByteSwap(result, gen.operand(value));
gen.setResult(this, result);
}
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java
--- a/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java Tue Apr 29 18:35:10 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -35,28 +35,28 @@
*/
public class SPARC extends Architecture {
- // @formatter:off
-
public static final RegisterCategory CPU = new RegisterCategory("CPU");
public static final RegisterCategory FPU = new RegisterCategory("FPU");
// General purpose registers
- public static final Register r0 = new Register(0, 0, "g0", CPU);
- public static final Register r1 = new Register(1, 1, "g1", CPU);
- public static final Register r2 = new Register(2, 2, "g2", CPU);
- public static final Register r3 = new Register(3, 3, "g3", CPU);
- public static final Register r4 = new Register(4, 4, "g4", CPU);
- public static final Register r5 = new Register(5, 5, "g5", CPU);
- public static final Register r6 = new Register(6, 6, "g6", CPU);
- public static final Register r7 = new Register(7, 7, "g7", CPU);
- public static final Register r8 = new Register(8, 8, "o0", CPU);
- public static final Register r9 = new Register(9, 9, "o1", CPU);
+ public static final Register r0 = new Register(0, 0, "g0", CPU);
+ public static final Register r1 = new Register(1, 1, "g1", CPU);
+ public static final Register r2 = new Register(2, 2, "g2", CPU);
+ public static final Register r3 = new Register(3, 3, "g3", CPU);
+ public static final Register r4 = new Register(4, 4, "g4", CPU);
+ public static final Register r5 = new Register(5, 5, "g5", CPU);
+ public static final Register r6 = new Register(6, 6, "g6", CPU);
+ public static final Register r7 = new Register(7, 7, "g7", CPU);
+
+ public static final Register r8 = new Register(8, 8, "o0", CPU);
+ public static final Register r9 = new Register(9, 9, "o1", CPU);
public static final Register r10 = new Register(10, 10, "o2", CPU);
public static final Register r11 = new Register(11, 11, "o3", CPU);
public static final Register r12 = new Register(12, 12, "o4", CPU);
public static final Register r13 = new Register(13, 13, "o5", CPU);
public static final Register r14 = new Register(14, 14, "o6", CPU);
public static final Register r15 = new Register(15, 15, "o7", CPU);
+
public static final Register r16 = new Register(16, 16, "l0", CPU);
public static final Register r17 = new Register(17, 17, "l1", CPU);
public static final Register r18 = new Register(18, 18, "l2", CPU);
@@ -65,6 +65,7 @@
public static final Register r21 = new Register(21, 21, "l5", CPU);
public static final Register r22 = new Register(22, 22, "l6", CPU);
public static final Register r23 = new Register(23, 23, "l7", CPU);
+
public static final Register r24 = new Register(24, 24, "i0", CPU);
public static final Register r25 = new Register(25, 25, "i1", CPU);
public static final Register r26 = new Register(26, 26, "i2", CPU);
@@ -113,12 +114,14 @@
public static final Register sp = o6;
public static final Register fp = i6;
+ // @formatter:off
public static final Register[] cpuRegisters = {
r0, r1, r2, r3, r4, r5, r6, r7,
r8, r9, r10, r11, r12, r13, r14, r15,
r16, r17, r18, r19, r20, r21, r22, r23,
r24, r25, r26, r27, r28, r29, r30, r31
};
+ // @formatter:on
// Floating point registers
public static final Register f0 = new Register(32, 0, "f0", FPU);
@@ -130,6 +133,43 @@
public static final Register f6 = new Register(38, 6, "f6", FPU);
public static final Register f7 = new Register(39, 7, "f7", FPU);
+ public static final Register f8 = new Register(40, 8, "f8", FPU);
+ public static final Register f9 = new Register(41, 9, "f9", FPU);
+ public static final Register f10 = new Register(42, 10, "f10", FPU);
+ public static final Register f11 = new Register(43, 11, "f11", FPU);
+ public static final Register f12 = new Register(44, 12, "f12", FPU);
+ public static final Register f13 = new Register(45, 13, "f13", FPU);
+ public static final Register f14 = new Register(46, 14, "f14", FPU);
+ public static final Register f15 = new Register(47, 15, "f15", FPU);
+
+ public static final Register f16 = new Register(48, 16, "f16", FPU);
+ public static final Register f17 = new Register(49, 17, "f17", FPU);
+ public static final Register f18 = new Register(50, 18, "f18", FPU);
+ public static final Register f19 = new Register(51, 19, "f19", FPU);
+ public static final Register f20 = new Register(52, 20, "f20", FPU);
+ public static final Register f21 = new Register(53, 21, "f21", FPU);
+ public static final Register f22 = new Register(54, 22, "f22", FPU);
+ public static final Register f23 = new Register(55, 23, "f23", FPU);
+
+ public static final Register f24 = new Register(56, 24, "f24", FPU);
+ public static final Register f25 = new Register(57, 25, "f25", FPU);
+ public static final Register f26 = new Register(58, 26, "f26", FPU);
+ public static final Register f27 = new Register(59, 27, "f27", FPU);
+ public static final Register f28 = new Register(60, 28, "f28", FPU);
+ public static final Register f29 = new Register(61, 29, "f29", FPU);
+ public static final Register f30 = new Register(62, 30, "f30", FPU);
+ public static final Register f31 = new Register(63, 31, "f31", FPU);
+
+ // @formatter:off
+ public static final Register[] fpuRegisters = {
+ f0, f1, f2, f3, f4, f5, f6, f7,
+ f8, f9, f10, f11, f12, f13, f14, f15,
+ f16, f17, f18, f19, f20, f21, f22, f23,
+ f24, f25, f26, f27, f28, f29, f30, f31
+ };
+ // @formatter:on
+
+ // @formatter:off
public static final Register[] allRegisters = {
// CPU
r0, r1, r2, r3, r4, r5, r6, r7,
@@ -138,9 +178,16 @@
r24, r25, r26, r27, r28, r29, r30, r31,
// FPU
f0, f1, f2, f3, f4, f5, f6, f7,
+ f8, f9, f10, f11, f12, f13, f14, f15,
+ f16, f17, f18, f19, f20, f21, f22, f23,
+ f24, f25, f26, f27, f28, f29, f30, f31
};
+ // @formatter:on
- // @formatter:on
+ /**
+ * Stack bias for stack and frame pointer loads.
+ */
+ public static final int STACK_BIAS = 0x7ff;
public SPARC() {
super("SPARC", 8, ByteOrder.BIG_ENDIAN, false, allRegisters, LOAD_STORE | STORE_STORE, 1, r31.encoding + 1, 8);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalLongUnitTest.java
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalLongUnitTest.java Tue Apr 29 18:23:17 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2013, 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 com.oracle.graal.test;
-
-import java.util.*;
-
-import org.junit.*;
-import org.junit.runners.*;
-import org.junit.runners.model.*;
-
-public class GraalLongUnitTest extends BlockJUnit4ClassRunner {
-
- public GraalLongUnitTest(Class> klass) throws InitializationError {
- super(klass);
- }
-
- @Override
- protected List computeTestMethods() {
- List methods = new ArrayList<>(5);
- methods.addAll(getTestClass().getAnnotatedMethods(Test.class));
- methods.addAll(getTestClass().getAnnotatedMethods(LongTest.class));
- return methods;
- }
-}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java Tue Apr 29 18:35:10 2014 +0200
@@ -26,14 +26,12 @@
import java.util.*;
import org.junit.*;
-import org.junit.runner.*;
/**
* Base class for Graal tests.
*
* This contains common utility methods that are used in multiple test projects.
*/
-@RunWith(GraalLongUnitTest.class)
public class GraalTest {
protected Method getMethod(String methodName) {
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.test/src/com/oracle/graal/test/LongTest.java
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/LongTest.java Tue Apr 29 18:23:17 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2013, 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 com.oracle.graal.test;
-
-import java.lang.annotation.*;
-
-/* copy of org.junit.Test */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.METHOD})
-public @interface LongTest {
-
- static final class None extends Throwable {
-
- private static final long serialVersionUID = 1L;
-
- private None() {
- }
- }
-
- Class extends Throwable> expected() default None.class;
-
- long timeout() default 0L;
-}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java Tue Apr 29 18:35:10 2014 +0200
@@ -88,13 +88,12 @@
public abstract CallTarget getTargetCallTarget();
- public DirectCallNode getCallNode() {
+ public Node getCallNode() {
Object receiver = stackFrame.getLocal(getNotifyIndex());
- if (receiver instanceof DirectCallNode) {
- return (DirectCallNode) receiver;
- } else {
- return null;
+ if (receiver instanceof DirectCallNode || receiver instanceof IndirectCallNode) {
+ return (Node) receiver;
}
+ return null;
}
/**
@@ -146,10 +145,9 @@
}
/**
- * This class represents a frame that is taken from the
- * {@link RootCallTarget#callProxy(VirtualFrame)} method.
+ * This class represents a frame that is taken from the {@link OptimizedCallTarget#callProxy}
+ * method.
*/
- @SuppressWarnings("javadoc")
public static final class CallTargetFrame extends HotSpotFrameInstance {
public static final Method METHOD;
static {
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Tue Apr 29 18:35:10 2014 +0200
@@ -241,7 +241,6 @@
if (inliningPerformed) {
return;
}
- inliningPerformed = true;
TruffleInliningHandler handler = new TruffleInliningHandler(new DefaultInliningPolicy());
TruffleInliningResult result = handler.decideInlining(this, 0);
performInlining(result);
@@ -249,6 +248,10 @@
}
private static void performInlining(TruffleInliningResult result) {
+ if (result.getCallTarget().inliningPerformed) {
+ return;
+ }
+ result.getCallTarget().inliningPerformed = true;
for (TruffleInliningProfile profile : result) {
profile.getCallNode().inline();
TruffleInliningResult recursiveResult = profile.getRecursiveResult();
@@ -272,7 +275,7 @@
if (profiledReturnTypeAssumption == null) {
if (TruffleReturnTypeSpeculation.getValue()) {
CompilerDirectives.transferToInterpreter();
- profiledReturnType = result.getClass();
+ profiledReturnType = (result == null ? null : result.getClass());
profiledReturnTypeAssumption = Truffle.getRuntime().createAssumption("Profiled Return Type");
}
} else if (profiledReturnType != null) {
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Tue Apr 29 18:35:10 2014 +0200
@@ -63,7 +63,7 @@
private final RuntimeProvider runtime;
private final TruffleCache truffleCache;
- private static final Class>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class};
+ private static final Class>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class, IllegalArgumentException.class};
public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability,
OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Tue Apr 29 18:35:10 2014 +0200
@@ -54,7 +54,7 @@
@Option(help = "Enable automatic inlining of call targets")
public static final OptionValue TruffleFunctionInlining = new OptionValue<>(true);
@Option(help = "Maximum number of Graal IR nodes during partial evaluation")
- public static final OptionValue TruffleGraphMaxNodes = new OptionValue<>(45000);
+ public static final OptionValue TruffleGraphMaxNodes = new OptionValue<>(200000);
@Option(help = "Stop inlining if caller's cumulative tree size would exceed this limit")
public static final OptionValue TruffleInliningMaxCallerSize = new OptionValue<>(2250);
@Option(help = "Skip inlining candidate if its tree size exceeds this limit")
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java Tue Apr 29 18:35:10 2014 +0200
@@ -94,7 +94,7 @@
int deepNodeCount;
TruffleInliningResult recursiveResult;
boolean recursiveCall = false;
- if (depth > MAXIMUM_RECURSIVE_DEPTH) {
+ if (target.inliningPerformed || depth > MAXIMUM_RECURSIVE_DEPTH) {
deepNodeCount = OptimizedCallUtils.countNonTrivialNodes(target, true);
recursiveResult = null;
} else {
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -23,11 +23,10 @@
package com.oracle.graal.truffle.nodes.frame;
import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
-public class ForceMaterializeNode extends FixedWithNextNode implements LIRGenLowerable {
+public class ForceMaterializeNode extends FixedWithNextNode implements LIRLowerable {
@Input private ValueNode object;
@@ -36,7 +35,7 @@
this.object = object;
}
- public void generate(NodeLIRBuilder generator) {
+ public void generate(NodeLIRBuilderTool generator) {
// nothing to do
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java Tue Apr 29 18:35:10 2014 +0200
@@ -31,6 +31,7 @@
import com.oracle.graal.debug.Debug.Scope;
import com.oracle.graal.nodes.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.cfs.IterativeFlowSensitiveReductionPhase;
import com.oracle.graal.phases.tiers.*;
public class IterativeInliningPhase extends AbstractInliningPhase {
@@ -70,9 +71,14 @@
new DeadCodeEliminationPhase().apply(graph);
- if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) {
+ boolean reduceOrEliminate = FlowSensitiveReduction.getValue() || ConditionalElimination.getValue();
+ if (reduceOrEliminate && OptCanonicalizer.getValue()) {
canonicalizer.apply(graph, context);
- new IterativeConditionalEliminationPhase(canonicalizer).apply(graph, context);
+ if (FlowSensitiveReduction.getValue()) {
+ new IterativeFlowSensitiveReductionPhase(canonicalizer).apply(graph, context);
+ } else {
+ new IterativeConditionalEliminationPhase(canonicalizer).apply(graph, context);
+ }
}
if (!progress) {
break;
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Tue Apr 29 18:35:10 2014 +0200
@@ -579,15 +579,29 @@
} else {
// all inputs are virtual: check if they're compatible and without identity
boolean compatible = true;
+ boolean hasIdentity = false;
ObjectState firstObj = objStates[0];
for (int i = 0; i < objStates.length; i++) {
ObjectState obj = objStates[i];
- boolean hasIdentity = obj.virtual.hasIdentity() && mergedVirtualObjects.contains(obj.virtual);
- if (hasIdentity || !firstObj.virtual.type().equals(obj.virtual.type()) || firstObj.virtual.entryCount() != obj.virtual.entryCount() || !firstObj.locksEqual(obj)) {
+ hasIdentity |= obj.virtual.hasIdentity();
+ boolean identitySurvives = obj.virtual.hasIdentity() && mergedVirtualObjects.contains(obj.virtual);
+ if (identitySurvives || !firstObj.virtual.type().equals(obj.virtual.type()) || firstObj.virtual.entryCount() != obj.virtual.entryCount() || !firstObj.locksEqual(obj)) {
compatible = false;
break;
}
}
+ if (compatible && hasIdentity) {
+ // we still need to check whether this value is referenced by any other phi
+ outer: for (PhiNode otherPhi : merge.phis().filter(otherPhi -> otherPhi != phi)) {
+ for (int i = 0; i < objStates.length; i++) {
+ ObjectState otherPhiValueState = getObjectState(states.get(i), otherPhi.valueAt(i));
+ if (Arrays.asList(objStates).contains(otherPhiValueState)) {
+ compatible = false;
+ break outer;
+ }
+ }
+ }
+ }
if (compatible) {
VirtualObjectNode virtual = getValueObjectVirtual(phi, getObjectState(states.get(0), phi.valueAt(0)).virtual);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/OnAdoptTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/OnAdoptTest.java Tue Apr 29 18:35:10 2014 +0200
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 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 com.oracle.truffle.api.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ *
Inserting Extra Nodes into the AST Transparently
+ *
+ *
+ * The {@link Node} class provides a callback that is invoked whenever a node is adopted in an AST
+ * by insertion or replacement. Node classes can override the {@code onAdopt()} method to run extra
+ * functionality upon adoption.
+ *
+ *
+ *
+ * This test demonstrates how node instances of a specific class can be automatically wrapped in
+ * extra nodes when they are inserted into the AST.
+ *
+ */
+public class OnAdoptTest {
+
+ static class Root extends RootNode {
+
+ @Child private Base child1;
+ @Child private Base child2;
+
+ public Root(Base child1, Base child2) {
+ super(null);
+ this.child1 = child1;
+ this.child2 = child2;
+ }
+
+ @Override
+ public Object execute(VirtualFrame frame) {
+ return child1.executeInt(frame) + child2.executeInt(frame);
+ }
+
+ }
+
+ abstract static class Base extends Node {
+ public abstract int executeInt(VirtualFrame frame);
+ }
+
+ static class Wrapper extends Base {
+
+ @Child private Base wrappee;
+
+ public Wrapper(Base wrappee) {
+ this.wrappee = wrappee;
+ }
+
+ @Override
+ public int executeInt(VirtualFrame frame) {
+ return 1 + wrappee.executeInt(frame);
+ }
+
+ }
+
+ abstract static class GenBase extends Base {
+
+ private final int k;
+
+ public GenBase(int k) {
+ this.k = k;
+ }
+
+ @Override
+ public int executeInt(VirtualFrame frame) {
+ return k;
+ }
+
+ }
+
+ static class Gen extends GenBase {
+ public Gen(int k) {
+ super(k);
+ }
+ }
+
+ static class GenWrapped extends GenBase {
+
+ public GenWrapped(int k) {
+ super(k);
+ }
+
+ @Override
+ protected void onAdopt() {
+ Wrapper w = new Wrapper(this);
+ this.replace(w);
+ }
+
+ }
+
+ @Test
+ public void testOnInsert() {
+ TruffleRuntime runtime = Truffle.getRuntime();
+ Base b1 = new Gen(11);
+ Base b2 = new GenWrapped(11);
+ Root r = new Root(b1, b2);
+ CallTarget ct = runtime.createCallTarget(r);
+ Object result = ct.call();
+ Assert.assertEquals(23, result);
+ }
+
+}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java Tue Apr 29 18:35:10 2014 +0200
@@ -34,12 +34,21 @@
/**
* Returns the name of this resource holding a guest language program. An example would be the
* name of a guest language source code file.
- *
+ *
* @return the name of the guest language program
*/
String getName();
/**
+ * Returns a short version of the name of the resource holding a guest language program (as
+ * described in @getName). For example, this could be just the name of the file, rather than a
+ * full path.
+ *
+ * @return the short name of the guest language program
+ */
+ String getShortName();
+
+ /**
* The normalized, canonical name of the file.
*/
String getPath();
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java Tue Apr 29 18:35:10 2014 +0200
@@ -31,21 +31,21 @@
/**
* Returns the object representing the source program that contains this section.
- *
+ *
* @return the source object
*/
Source getSource();
/**
* Returns 1-based line number of the first character in this source section (inclusive).
- *
+ *
* @return the starting line number
*/
int getStartLine();
/**
* Returns the 1-based column number of the first character in this source section (inclusive).
- *
+ *
* @return the starting column number
*/
int getStartColumn();
@@ -55,7 +55,7 @@
*
* The complete text of the source that contains this section can be retrieved via
* {@link Source#getCode()}.
- *
+ *
* @return the starting character index
*/
int getCharIndex();
@@ -65,7 +65,7 @@
*
* The complete text of the source that contains this section can be retrieved via
* {@link Source#getCode()}.
- *
+ *
* @return the number of characters in the section
*/
int getCharLength();
@@ -73,42 +73,54 @@
/**
* Returns the index of the text position immediately following the last character in the
* section.
- *
+ *
* @return the end position of the section
*/
int getCharEndIndex();
/**
* Returns the identifier of this source section that is used for printing the section.
- *
+ *
* @return the identifier of the section
*/
String getIdentifier();
/**
* Returns text of the code represented by this source section.
- *
+ *
* @return the code as a String object
*/
String getCode();
/**
+ * Returns a short description of the source section, using just the file name, rather than its
+ * full path.
+ *
+ * @return a short description of the source section
+ */
+ String getShortDescription();
+
+ /**
* Singleton instance with no content.
*/
SourceSection NULL = new NullSourceSection() {
+ @Override
public Source getSource() {
return null;
}
+ @Override
public int getStartLine() {
return 0;
}
+ @Override
public int getStartColumn() {
return 0;
}
+ @Override
public int getCharIndex() {
return 0;
}
@@ -118,18 +130,26 @@
return 0;
}
+ @Override
public int getCharEndIndex() {
return 0;
}
+ @Override
public String getIdentifier() {
return null;
}
+ @Override
public String getCode() {
return null;
}
+ @Override
+ public String getShortDescription() {
+ return "short";
+ }
+
};
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java Tue Apr 29 18:35:10 2014 +0200
@@ -40,9 +40,7 @@
boolean isVirtualFrame();
- DirectCallNode getCallNode();
+ Node getCallNode();
CallTarget getCallTarget();
-
- CallTarget getTargetCallTarget();
}
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java Tue Apr 29 18:35:10 2014 +0200
@@ -53,7 +53,7 @@
* a character index. The (row,column) coordinates of a newline character should never appear in
* a text section.
*
- *
+ *
* @param source object representing the complete source program that contains this section
* @param identifier an identifier used when printing the section
* @param startLine the 1-based number of the start line of the section
@@ -102,6 +102,10 @@
return getSource().getCode().substring(charIndex, charIndex + charLength);
}
+ public final String getShortDescription() {
+ return String.format("%s:%d", source.getShortName(), startLine);
+ }
+
@Override
public String toString() {
return String.format("%s:%d", source.getName(), startLine);
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Tue Apr 29 18:35:10 2014 +0200
@@ -191,8 +191,12 @@
if (newChild == this) {
throw new IllegalStateException("The parent of a node can never be the node itself.");
}
+ boolean isInserted = newChild.parent == null;
newChild.parent = this;
newChild.adoptHelper();
+ if (isInserted) {
+ newChild.onAdopt();
+ }
}
private void adoptHelper() {
@@ -209,8 +213,12 @@
if (newChild == this) {
throw new IllegalStateException("The parent of a node can never be the node itself.");
}
+ boolean isInserted = newChild.parent == null;
newChild.parent = this;
newChild.adoptUnadoptedHelper();
+ if (isInserted) {
+ newChild.onAdopt();
+ }
}
private void adoptUnadoptedHelper() {
@@ -332,7 +340,6 @@
}
private void traceRewrite(Node newNode, CharSequence reason) {
-
if (TruffleOptions.TraceRewritesFilterFromCost != null) {
if (filterByKind(this, TruffleOptions.TraceRewritesFilterFromCost)) {
return;
@@ -352,8 +359,21 @@
return;
}
+ final SourceSection reportedSourceSection = getEncapsulatingSourceSection();
+
PrintStream out = System.out;
- out.printf("[truffle] rewrite %-50s |From %-40s |To %-40s |Reason %s.%n", this.toString(), formatNodeInfo(this), formatNodeInfo(newNode), reason);
+ out.printf("[truffle] rewrite %-50s |From %-40s |To %-40s |Reason %s%s%n", this.toString(), formatNodeInfo(this), formatNodeInfo(newNode), reason != null && reason.length() > 0 ? reason
+ : "unknown", reportedSourceSection != null ? " at " + reportedSourceSection.getShortDescription() : "");
+ }
+
+ /**
+ * Subclasses of {@link Node} can implement this method to execute extra functionality when a
+ * node is effectively inserted into the AST. The {@code onAdopt} callback is called after the
+ * node has been effectively inserted, and it is guaranteed to be called only once for any given
+ * node.
+ */
+ protected void onAdopt() {
+ // empty default
}
private static String formatNodeInfo(Node node) {
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java Tue Apr 29 18:35:10 2014 +0200
@@ -70,7 +70,7 @@
/**
* Gets the canonical representation of a source file, whose contents will be read lazily and
* then cached.
- *
+ *
* @param reset forces any existing {@link Source} cache to be cleared, forcing a re-read
*/
public Source get(String fileName, boolean reset) {
@@ -227,6 +227,11 @@
}
@Override
+ public String getShortName() {
+ return name;
+ }
+
+ @Override
public String getCode() {
return code;
}
@@ -292,6 +297,11 @@
}
@Override
+ public String getShortName() {
+ return file.getName();
+ }
+
+ @Override
public String getCode() {
if (code == null || timeStamp != file.lastModified()) {
try {
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java Tue Apr 29 18:35:10 2014 +0200
@@ -44,7 +44,7 @@
*
After execution of function {@code f2}: {@code I->D(f1)->D(f2)->U}
*
After execution of function {@code f3}: {@code I->G}
*
- * */
+ */
public abstract class SLAbstractDispatchNode extends Node {
protected static final int INLINE_CACHE_SIZE = 2;
diff -r 34ae63dda6e8 -r 10023073e858 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java Tue Apr 29 18:23:17 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java Tue Apr 29 18:35:10 2014 +0200
@@ -29,7 +29,7 @@
* there is always the danger of a spurious {@link NullPointerException}. Representing the guest
* language {@code null} as a singleton, as in {@link #SINGLETON this class}, is the recommended
* practice.
- * */
+ */
public final class SLNull {
/**
diff -r 34ae63dda6e8 -r 10023073e858 mx.cmd
--- a/mx.cmd Tue Apr 29 18:23:17 2014 +0200
+++ b/mx.cmd Tue Apr 29 18:35:10 2014 +0200
@@ -1,1 +1,1 @@
-python mxtool/mx.py %*
+python %~dp0/mxtool/mx.py %*
diff -r 34ae63dda6e8 -r 10023073e858 mx/mx_graal.py
--- a/mx/mx_graal.py Tue Apr 29 18:23:17 2014 +0200
+++ b/mx/mx_graal.py Tue Apr 29 18:35:10 2014 +0200
@@ -26,7 +26,7 @@
#
# ----------------------------------------------------------------------------------------------------
-import os, sys, shutil, zipfile, tempfile, re, time, datetime, platform, subprocess, multiprocessing, StringIO
+import os, sys, shutil, zipfile, tarfile, tempfile, re, time, datetime, platform, subprocess, multiprocessing, StringIO, socket
from os.path import join, exists, dirname, basename, getmtime
from argparse import ArgumentParser, RawDescriptionHelpFormatter, REMAINDER
from outputparser import OutputParser, ValuesMatcher
@@ -35,6 +35,7 @@
import sanitycheck
import itertools
import json, textwrap
+import fnmatch
# This works because when mx loads this file, it makes sure __file__ gets an absolute path
_graal_home = dirname(dirname(__file__))
@@ -162,49 +163,124 @@
rmIfExists(mx.distribution('GRAAL').path)
def export(args):
- """create a GraalVM zip file for distribution"""
+ """create archives of builds split by vmbuild and vm"""
parser = ArgumentParser(prog='mx export')
- parser.add_argument('--omit-vm-build', action='store_false', dest='vmbuild', help='omit VM build step')
- parser.add_argument('--omit-dist-init', action='store_false', dest='distInit', help='omit class files and IDE configurations from distribution')
- parser.add_argument('zipfile', nargs=REMAINDER, metavar='zipfile')
-
args = parser.parse_args(args)
- tmp = tempfile.mkdtemp(prefix='tmp', dir=_graal_home)
- if args.vmbuild:
- # Make sure the product VM binary is up to date
- with VM(vmbuild='product'):
- build([])
+ # collect data about export
+ infos = dict()
+ infos['timestamp'] = time.time()
+
+ hgcfg = mx.HgConfig()
+ hgcfg.check()
+ infos['revision'] = hgcfg.tip('.') + ('+' if hgcfg.isDirty('.') else '')
+ # TODO: infos['repository']
+
+ infos['jdkversion'] = str(mx.java().version)
+
+ infos['architecture'] = _arch()
+ infos['platform'] = mx.get_os()
+
+ if mx.get_os != 'windows':
+ pass
+ # infos['ccompiler']
+ # infos['linker']
+
+ infos['hostname'] = socket.gethostname()
- mx.log('Copying Java sources and mx files...')
- mx.run(('hg archive -I graal -I mx -I mxtool -I mx.sh ' + tmp).split())
+ def _writeJson(suffix, properties):
+ d = infos.copy()
+ for k, v in properties.iteritems():
+ assert not d.has_key(k)
+ d[k] = v
+
+ jsonFileName = 'export-' + suffix + '.json'
+ with open(jsonFileName, 'w') as f:
+ print >> f, json.dumps(d)
+ return jsonFileName
+
+
+ def _genFileName(archivtype, middle):
+ idPrefix = infos['revision'] + '_'
+ idSuffix = '.tar.gz'
+ return join(_graal_home, "graalvm_" + archivtype + "_" + idPrefix + middle + idSuffix)
+
+ def _genFileArchPlatformName(archivtype, middle):
+ return _genFileName(archivtype, infos['platform'] + '_' + infos['architecture'] + '_' + middle)
+
+
+ # archive different build types of hotspot
+ for vmBuild in _vmbuildChoices:
+ jdkpath = join(_jdksDir(), vmBuild)
+ if not exists(jdkpath):
+ mx.logv("skipping " + vmBuild)
+ continue
- # Copy the GraalVM JDK
- mx.log('Copying GraalVM JDK...')
- src = _jdk()
- dst = join(tmp, basename(src))
- shutil.copytree(src, dst)
- zfName = join(_graal_home, 'graalvm-' + mx.get_os() + '.zip')
- zf = zipfile.ZipFile(zfName, 'w')
- for root, _, files in os.walk(tmp):
- for f in files:
- name = join(root, f)
- arcname = name[len(tmp) + 1:]
- zf.write(join(tmp, name), arcname)
+ tarName = _genFileArchPlatformName('basejdk', vmBuild)
+ mx.logv("creating basejdk " + tarName)
+ vmSet = set()
+ with tarfile.open(tarName, 'w:gz') as tar:
+ for root, _, files in os.walk(jdkpath):
+ if basename(root) in _vmChoices.keys():
+ # TODO: add some assert to check path assumption
+ vmSet.add(root)
+ continue
+
+ for f in files:
+ name = join(root, f)
+ # print name
+ tar.add(name, name)
+
+ n = _writeJson("basejdk-" + vmBuild, {'vmbuild' : vmBuild})
+ tar.add(n, n)
+
+ # create a separate archive for each VM
+ for vm in vmSet:
+ bVm = basename(vm)
+ vmTarName = _genFileArchPlatformName('vm', vmBuild + '_' + bVm)
+ mx.logv("creating vm " + vmTarName)
- # create class files and IDE configurations
- if args.distInit:
- mx.log('Creating class files...')
- mx.run('mx build'.split(), cwd=tmp)
- mx.log('Creating IDE configurations...')
- mx.run('mx ideinit'.split(), cwd=tmp)
+ debugFiles = set()
+ with tarfile.open(vmTarName, 'w:gz') as tar:
+ for root, _, files in os.walk(vm):
+ for f in files:
+ # TODO: mac, windows, solaris?
+ if any(map(f.endswith, [".debuginfo"])):
+ debugFiles.add(f)
+ else:
+ name = join(root, f)
+ # print name
+ tar.add(name, name)
+
+ n = _writeJson("vm-" + vmBuild + "-" + bVm, {'vmbuild' : vmBuild, 'vm' : bVm})
+ tar.add(n, n)
- # clean up temp directory
- mx.log('Cleaning up...')
- shutil.rmtree(tmp)
+ if len(debugFiles) > 0:
+ debugTarName = _genFileArchPlatformName('debugfilesvm', vmBuild + '_' + bVm)
+ mx.logv("creating debugfilesvm " + debugTarName)
+ with tarfile.open(debugTarName, 'w:gz') as tar:
+ for f in debugFiles:
+ name = join(root, f)
+ # print name
+ tar.add(name, name)
+
+ n = _writeJson("debugfilesvm-" + vmBuild + "-" + bVm, {'vmbuild' : vmBuild, 'vm' : bVm})
+ tar.add(n, n)
- mx.log('Created distribution in ' + zfName)
+ # graal directory
+ graalDirTarName = _genFileName('classfiles', 'javac')
+ mx.logv("creating graal " + graalDirTarName)
+ with tarfile.open(graalDirTarName, 'w:gz') as tar:
+ for root, _, files in os.walk("graal"):
+ for f in [f for f in files if not f.endswith('.java')]:
+ name = join(root, f)
+ # print name
+ tar.add(name, name)
+
+ n = _writeJson("graal", {'javacompiler' : 'javac'})
+ tar.add(n, n)
+
def _run_benchmark(args, availableBenchmarks, runBenchmark):
@@ -861,7 +937,7 @@
projectscp = mx.classpath(projs)
if whitelist:
- classes = list(set(classes) & set(whitelist))
+ classes = [c for c in classes if any((glob.match(c) for glob in whitelist))]
if len(classes) != 0:
f_testfile = open(testfile, 'w')
@@ -905,10 +981,8 @@
_unittestHelpSuffix = """
Unittest options:
- --short-only run short testcases only
- --long-only run long testcases only
- --baseline-whitelist run only testcases which are known to
- work with the baseline compiler
+ --whitelist run only testcases which are included
+ in the given whitelist
To avoid conflicts with VM options '--' can be used as delimiter.
@@ -945,10 +1019,7 @@
formatter_class=RawDescriptionHelpFormatter,
epilog=_unittestHelpSuffix,
)
- group = parser.add_mutually_exclusive_group()
- group.add_argument('--short-only', action='store_true', help='run short testcases only')
- group.add_argument('--long-only', action='store_true', help='run long testcases only')
- parser.add_argument('--baseline-whitelist', action='store_true', help='run baseline testcases only')
+ parser.add_argument('--whitelist', help='run testcases specified in whitelist only', metavar='')
ut_args = []
delimiter = False
@@ -968,33 +1039,19 @@
parsed_args, args = parser.parse_known_args(ut_args)
whitelist = None
- if parsed_args.baseline_whitelist:
- baseline_whitelist_file = 'test/baseline_whitelist.txt'
+ if parsed_args.whitelist:
try:
- with open(join(_graal_home, baseline_whitelist_file)) as fp:
- whitelist = [l.rstrip() for l in fp.readlines()]
+ with open(join(_graal_home, parsed_args.whitelist)) as fp:
+ whitelist = [re.compile(fnmatch.translate(l.rstrip())) for l in fp.readlines() if not l.startswith('#')]
except IOError:
- mx.log('warning: could not read baseline whitelist: ' + baseline_whitelist_file)
+ mx.log('warning: could not read whitelist: ' + parsed_args.whitelist)
- if parsed_args.long_only:
- annotations = ['@LongTest', '@Parameters']
- elif parsed_args.short_only:
- annotations = ['@Test']
- else:
- annotations = ['@Test', '@LongTest', '@Parameters']
-
- _unittest(args, annotations, whitelist=whitelist)
+ _unittest(args, ['@Test', '@Parameters'], whitelist=whitelist)
def shortunittest(args):
- """alias for 'unittest --short-only'{0}"""
-
- args.insert(0, '--short-only')
- unittest(args)
+ """alias for 'unittest --whitelist test/whitelist_shortunittest.txt'{0}"""
-def longunittest(args):
- """alias for 'unittest --long-only'{0}"""
-
- args.insert(0, '--long-only')
+ args = ['--whitelist', 'test/whitelist_shortunittest.txt'] + args
unittest(args)
def buildvms(args):
@@ -1104,6 +1161,11 @@
unittest([])
tasks.append(t.stop())
+ with VM('server', 'product'): # hosted mode
+ t = Task('UnitTests-BaselineCompiler:hosted-product')
+ unittest(['--whitelist', 'test/whitelist_baseline.txt', '-G:+UseBaselineCompiler'])
+ tasks.append(t.stop())
+
for vmbuild in ['fastdebug', 'product']:
for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild) + sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild):
t = Task(str(test) + ':' + vmbuild)
@@ -1723,14 +1785,14 @@
"""make truffle.jar"""
# Test with the built classes
- _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@LongTest', '@Parameters'])
+ _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@Parameters'])
# We use the DSL processor as the starting point for the classpath - this
# therefore includes the DSL processor, the DSL and the API.
packagejar(mx.classpath("com.oracle.truffle.dsl.processor").split(os.pathsep), "truffle.jar", None, "com.oracle.truffle.dsl.processor.TruffleProcessor")
# Test with the JAR
- _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@LongTest', '@Parameters'], "truffle.jar:")
+ _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@Parameters'], "truffle.jar:")
def isGraalEnabled(vm):
@@ -1953,7 +2015,6 @@
'gate' : [gate, '[-options]'],
'bench' : [bench, '[-resultfile file] [all(default)|dacapo|specjvm2008|bootstrap]'],
'unittest' : [unittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix],
- 'longunittest' : [longunittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix],
'makejmhdeps' : [makejmhdeps, ''],
'shortunittest' : [shortunittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix],
'jacocoreport' : [jacocoreport, '[output directory]'],
diff -r 34ae63dda6e8 -r 10023073e858 mx/projects
--- a/mx/projects Tue Apr 29 18:23:17 2014 +0200
+++ b/mx/projects Tue Apr 29 18:35:10 2014 +0200
@@ -42,19 +42,19 @@
library@DACAPO_SCALA@urls=http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20120216.103539-3.jar
library@DACAPO_SCALA@sha1=59b64c974662b5cf9dbd3cf9045d293853dd7a51
-library@OKRA@path=lib/okra-1.8.jar
-library@OKRA@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.8.jar
-library@OKRA@sourcePath=lib/okra-1.8-src.jar
-library@OKRA@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-src.jar
+library@OKRA@path=lib/okra-1.9.jar
+library@OKRA@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.9.jar
+library@OKRA@sourcePath=lib/okra-1.9-src.jar
+library@OKRA@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-src.jar
-library@OKRA_WITH_SIM@path=lib/okra-1.8-with-sim.jar
-library@OKRA_WITH_SIM@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-with-sim.jar
-library@OKRA_WITH_SIM@sourcePath=lib/okra-1.8-with-sim-src.jar
-library@OKRA_WITH_SIM@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-with-sim-src.jar
+library@OKRA_WITH_SIM@path=lib/okra-1.9-with-sim.jar
+library@OKRA_WITH_SIM@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim.jar
+library@OKRA_WITH_SIM@sourcePath=lib/okra-1.9-with-sim-src.jar
+library@OKRA_WITH_SIM@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim-src.jar
library@JAVA_ALLOCATION_INSTRUMENTER@path=lib/java-allocation-instrumenter.jar
-library@JAVA_ALLOCATION_INSTRUMENTER@urls=http://lafo.ssw.uni-linz.ac.at/java-allocation-instrumenter/java-allocation-instrumenter-8f0db117e64e.jar
-library@JAVA_ALLOCATION_INSTRUMENTER@sha1=64c0a5329fbcb8284640e58d83252e0a3b08c23e
+library@JAVA_ALLOCATION_INSTRUMENTER@urls=http://lafo.ssw.uni-linz.ac.at/java-allocation-instrumenter/java-allocation-instrumenter-c7e3525a6b90.jar
+library@JAVA_ALLOCATION_INSTRUMENTER@sha1=128eb20a4cd3362a4d8b94614e66647808a2e37c
library@VECMATH@path=lib/vecmath-1.3.1.jar
library@VECMATH@urls=http://mirrors.ibiblio.org/pub/mirrors/maven/java3d/jars/vecmath-1.3.1.jar
@@ -426,6 +426,7 @@
project@com.oracle.graal.compiler@checkstyle=com.oracle.graal.graph
project@com.oracle.graal.compiler@javaCompliance=1.8
project@com.oracle.graal.compiler@annotationProcessors=com.oracle.graal.service.processor
+project@com.oracle.graal.compiler@annotationProcessorForDependents=true
project@com.oracle.graal.compiler@workingSets=Graal
# graal.compiler.amd64
diff -r 34ae63dda6e8 -r 10023073e858 mxtool/mx.py
--- a/mxtool/mx.py Tue Apr 29 18:23:17 2014 +0200
+++ b/mxtool/mx.py Tue Apr 29 18:35:10 2014 +0200
@@ -608,6 +608,17 @@
else:
return None
+ def isDirty(self, sDir, abortOnError=True):
+ try:
+ return len(subprocess.check_output(['hg', 'status', '-R', sDir])) > 0
+ except OSError:
+ warn(self.missing)
+ except subprocess.CalledProcessError:
+ if abortOnError:
+ abort('failed to get status')
+ else:
+ return None
+
class Suite:
def __init__(self, mxDir, primary, load=True):
self.dir = dirname(mxDir)
@@ -1800,11 +1811,13 @@
parser.add_argument('--only', action='store', help='comma separated projects to build, without checking their dependencies (omit to build all projects)')
parser.add_argument('--no-java', action='store_false', dest='java', help='do not build Java projects')
parser.add_argument('--no-native', action='store_false', dest='native', help='do not build native projects')
- parser.add_argument('--force-javac', action='store_true', dest='javac', help='use javac despite ecj.jar is found or not')
- parser.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler (default: ' + defaultEcjPath + ')', default=defaultEcjPath, metavar='')
parser.add_argument('--jdt-warning-as-error', action='store_true', help='convert all Eclipse batch compiler warnings to errors')
parser.add_argument('--jdt-show-task-tags', action='store_true', help='show task tags as Eclipse batch compiler warnings')
- parser.add_argument('--error-prone', dest='error_prone', help='path to error-prone.jar', metavar='')
+ compilerSelect = parser.add_mutually_exclusive_group()
+ compilerSelect.add_argument('--error-prone', dest='error_prone', help='path to error-prone.jar', metavar='')
+ compilerSelect.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler (default: ' + defaultEcjPath + ')', default=defaultEcjPath, metavar='')
+ compilerSelect.add_argument('--force-javac', action='store_true', dest='javac', help='use javac despite ecj.jar is found or not')
+
if suppliedParser:
parser.add_argument('remainder', nargs=REMAINDER, metavar='...')
@@ -1886,12 +1899,11 @@
cp = classpath(p.name, includeSelf=True)
sourceDirs = p.source_dirs()
- mustBuild = args.force
- if not mustBuild:
+ buildReason = 'forced build' if args.force else None
+ if not buildReason:
for dep in p.all_deps([], False):
if dep.name in built:
- mustBuild = True
-
+ buildReason = dep.name + ' rebuilt'
jasminAvailable = None
javafilelist = []
@@ -1940,20 +1952,19 @@
if exists(dirname(dst)) and (not exists(dst) or os.path.getmtime(dst) < os.path.getmtime(src)):
shutil.copyfile(src, dst)
- if not mustBuild:
+ if not buildReason:
for javafile in javafiles:
classfile = TimeStampFile(outputDir + javafile[len(sourceDir):-len('java')] + 'class')
if not classfile.exists() or classfile.isOlderThan(javafile):
- mustBuild = True
+ buildReason = 'class file(s) out of date'
break
aps = p.annotation_processors()
apsOutOfDate = p.update_current_annotation_processors_file()
if apsOutOfDate:
- logv('[annotation processors for {0} changed]'.format(p.name))
- mustBuild = True
-
- if not mustBuild:
+ buildReason = 'annotation processor(s) changed'
+
+ if not buildReason:
logv('[all class files for {0} are up to date - skipping]'.format(p.name))
continue
@@ -1985,10 +1996,14 @@
toBeDeleted = [argfileName]
try:
+
+ def logCompilation(p, compiler, reason):
+ log('Compiling Java sources for {} with {}... [{}]'.format(p.name, compiler, reason))
+
if not jdtJar:
mainJava = java()
if not args.error_prone:
- log('Compiling Java sources for {0} with javac...'.format(p.name))
+ logCompilation(p, 'javac', buildReason)
javacCmd = [mainJava.javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
if jdk.debug_port is not None:
javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)]
@@ -1999,7 +2014,7 @@
javacCmd.append('-XDignore.symbol.file')
run(javacCmd)
else:
- log('Compiling Java sources for {0} with javac (with error-prone)...'.format(p.name))
+ logCompilation(p, 'javac (with error-prone)', buildReason)
javaArgs = ['-Xmx1g']
javacArgs = ['-g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
javacArgs += processorArgs
@@ -2008,7 +2023,7 @@
javacArgs.append('-XDignore.symbol.file')
run_java(javaArgs + ['-cp', os.pathsep.join([mainJava.toolsjar, args.error_prone]), 'com.google.errorprone.ErrorProneCompiler'] + javacArgs)
else:
- log('Compiling Java sources for {0} with JDT...'.format(p.name))
+ logCompilation(p, 'JDT', buildReason)
jdtVmArgs = ['-Xmx1g', '-jar', jdtJar]
@@ -3843,7 +3858,7 @@
def ideinit(args, refreshOnly=False, buildProcessorJars=True):
- """(re)generate Eclipse and NetBeans project configurations"""
+ """(re)generate Eclipse, NetBeans and Intellij project configurations"""
eclipseinit(args, refreshOnly=refreshOnly, buildProcessorJars=buildProcessorJars)
netbeansinit(args, refreshOnly=refreshOnly, buildProcessorJars=buildProcessorJars)
intellijinit(args, refreshOnly=refreshOnly)
@@ -3981,7 +3996,13 @@
try:
log('Generating {2} for {0} in {1}'.format(p.name, out, docDir))
projectJava = java(p.javaCompliance)
- run([java().javadoc, memory,
+
+ # Once https://bugs.openjdk.java.net/browse/JDK-8041628 is fixed,
+ # this should be reverted to:
+ # javadocExe = java().javadoc
+ javadocExe = projectJava.javadoc
+
+ run([javadocExe, memory,
'-XDignore.symbol.file',
'-classpath', cp,
'-quiet',
@@ -3991,6 +4012,7 @@
'-source', str(projectJava.javaCompliance),
'-bootclasspath', projectJava.bootclasspath(),
'-extdirs', projectJava.extdirs()] +
+ ([] if projectJava.javaCompliance < JavaCompliance('1.8') else ['-Xdoclint:none']) +
links +
extraArgs +
nowarnAPI +
@@ -4028,115 +4050,19 @@
'-quiet',
'-d', out,
'-sourcepath', sp] +
+ ([] if java().javaCompliance < JavaCompliance('1.8') else ['-Xdoclint:none']) +
links +
extraArgs +
nowarnAPI +
list(pkgs))
log('Generated {2} for {0} in {1}'.format(', '.join(names), out, docDir))
-class Chunk:
- def __init__(self, content, ldelim, rdelim=None):
- lindex = content.find(ldelim)
- if rdelim is not None:
- rindex = content.find(rdelim)
- else:
- rindex = lindex + len(ldelim)
- self.ldelim = ldelim
- self.rdelim = rdelim
- if lindex != -1 and rindex != -1 and rindex > lindex:
- self.text = content[lindex + len(ldelim):rindex]
- else:
- self.text = None
-
- def replace(self, content, repl):
- lindex = content.find(self.ldelim)
- if self.rdelim is not None:
- rindex = content.find(self.rdelim)
- rdelimLen = len(self.rdelim)
- else:
- rindex = lindex + len(self.ldelim)
- rdelimLen = 0
- old = content[lindex:rindex + rdelimLen]
- return content.replace(old, repl)
-
-# Post-process an overview-summary.html file to move the
-# complete overview to the top of the page
-def _fix_overview_summary(path, topLink):
- """
- Processes an "overview-summary.html" generated by javadoc to put the complete
- summary text above the Packages table.
- """
-
- # This uses scraping and so will break if the relevant content produced by javadoc changes in any way!
- with open(path) as fp:
- content = fp.read()
-
- chunk1 = Chunk(content, """
-""")
-
- assert chunk1.text, 'Could not find header section in ' + path
- assert chunk2.text, 'Could not find footer section in ' + path
-
- content = chunk1.replace(content, '
' + topLink + chunk2.text + '
')
- content = chunk2.replace(content, '')
-
- with open(path, 'w') as fp:
- fp.write(content)
-
-
-# Post-process a package-summary.html file to move the
-# complete package description to the top of the page
-def _fix_package_summary(path):
- """
- Processes an "overview-summary.html" generated by javadoc to put the complete
- summary text above the Packages table.
- """
-
- # This uses scraping and so will break if the relevant content produced by javadoc changes in any way!
- with open(path) as fp:
- content = fp.read()
-
- chunk1 = Chunk(content, """