--- /dev/null 2017-01-22 10:16:57.869617664 -0800 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/StampTool.java 2017-02-15 17:07:58.110111599 -0800 @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.nodes.type; + +import java.util.Iterator; + +import org.graalvm.compiler.core.common.type.AbstractObjectStamp; +import org.graalvm.compiler.core.common.type.AbstractPointerStamp; +import org.graalvm.compiler.core.common.type.IntegerStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.common.type.TypeReference; +import org.graalvm.compiler.nodes.ValueNode; + +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Helper class that is used to keep all stamp-related operations in one place. + */ +public class StampTool { + + public static Stamp meet(Iterable values) { + Stamp stamp = meetOrNull(values, null); + if (stamp == null) { + return StampFactory.forVoid(); + } + return stamp; + } + + /** + * Meet a collection of {@link ValueNode}s optionally excluding {@code selfValue}. If no values + * are encountered then return {@code null}. + */ + public static Stamp meetOrNull(Iterable values, ValueNode selfValue) { + Iterator iterator = values.iterator(); + Stamp stamp = null; + while (iterator.hasNext()) { + ValueNode nextValue = iterator.next(); + if (nextValue != selfValue) { + if (stamp == null) { + stamp = nextValue.stamp(); + } else { + stamp = stamp.meet(nextValue.stamp()); + } + } + } + return stamp; + } + + /** + * Compute the stamp resulting from the unsigned comparison being true. + * + * @return null if it's can't be true or it nothing useful can be encoded. + */ + public static Stamp unsignedCompare(Stamp stamp, Stamp stamp2) { + IntegerStamp x = (IntegerStamp) stamp; + IntegerStamp y = (IntegerStamp) stamp2; + if (x == x.unrestricted() && y == y.unrestricted()) { + // Don't know anything. + return null; + } + // c <| n, where c is a constant and n is known to be positive. + if (x.lowerBound() == x.upperBound()) { + if (y.isPositive()) { + if (x.lowerBound() == (1 << x.getBits()) - 1) { + // Constant is MAX_VALUE which must fail. + return null; + } + if (x.lowerBound() <= y.lowerBound()) { + // Test will fail. Return illegalStamp instead? + return null; + } + // If the test succeeds then this proves that n is at greater than c so the bounds + // are [c+1..-n.upperBound)]. + return StampFactory.forInteger(x.getBits(), x.lowerBound() + 1, y.upperBound()); + } + return null; + } + // n <| c, where c is a strictly positive constant + if (y.lowerBound() == y.upperBound() && y.isStrictlyPositive()) { + // The test proves that n is positive and less than c, [0..c-1] + return StampFactory.forInteger(y.getBits(), 0, y.lowerBound() - 1); + } + return null; + } + + public static Stamp stampForLeadingZeros(IntegerStamp valueStamp) { + long mask = CodeUtil.mask(valueStamp.getBits()); + // Don't count zeros from the mask in the result. + int adjust = Long.numberOfLeadingZeros(mask); + assert adjust == 0 || adjust == 32; + int min = Long.numberOfLeadingZeros(valueStamp.upMask() & mask) - adjust; + int max = Long.numberOfLeadingZeros(valueStamp.downMask() & mask) - adjust; + return StampFactory.forInteger(JavaKind.Int, min, max); + } + + public static Stamp stampForTrailingZeros(IntegerStamp valueStamp) { + long mask = CodeUtil.mask(valueStamp.getBits()); + int min = Long.numberOfTrailingZeros(valueStamp.upMask() & mask); + int max = Long.numberOfTrailingZeros(valueStamp.downMask() & mask); + return StampFactory.forInteger(JavaKind.Int, min, max); + } + + /** + * Checks whether this {@link ValueNode} represents a {@linkplain Stamp#hasValues() legal} + * pointer value which is known to be always null. + * + * @param node the node to check + * @return true if this node represents a legal object value which is known to be always null + */ + public static boolean isPointerAlwaysNull(ValueNode node) { + return isPointerAlwaysNull(node.stamp()); + } + + /** + * Checks whether this {@link Stamp} represents a {@linkplain Stamp#hasValues() legal} pointer + * stamp whose values are known to be always null. + * + * @param stamp the stamp to check + * @return true if this stamp represents a legal object stamp whose values are known to be + * always null + */ + public static boolean isPointerAlwaysNull(Stamp stamp) { + if (stamp instanceof AbstractPointerStamp && stamp.hasValues()) { + return ((AbstractPointerStamp) stamp).alwaysNull(); + } + return false; + } + + /** + * Checks whether this {@link ValueNode} represents a {@linkplain Stamp#hasValues() legal} + * pointer value which is known to never be null. + * + * @param node the node to check + * @return true if this node represents a legal object value which is known to never be null + */ + public static boolean isPointerNonNull(ValueNode node) { + return isPointerNonNull(node.stamp()); + } + + /** + * Checks whether this {@link Stamp} represents a {@linkplain Stamp#hasValues() legal} pointer + * stamp whose values are known to never be null. + * + * @param stamp the stamp to check + * @return true if this stamp represents a legal object stamp whose values are known to be + * always null + */ + public static boolean isPointerNonNull(Stamp stamp) { + if (stamp instanceof AbstractPointerStamp) { + return ((AbstractPointerStamp) stamp).nonNull(); + } + return false; + } + + /** + * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain ValueNode} has if it is + * a {@linkplain Stamp#hasValues() legal} Object value. + * + * @param node the node to check + * @return the Java type this value has if it is a legal Object type, null otherwise + */ + public static TypeReference typeReferenceOrNull(ValueNode node) { + return typeReferenceOrNull(node.stamp()); + } + + public static ResolvedJavaType typeOrNull(ValueNode node) { + return typeOrNull(node.stamp()); + } + + public static ResolvedJavaType typeOrNull(Stamp stamp) { + TypeReference type = typeReferenceOrNull(stamp); + return type == null ? null : type.getType(); + } + + public static ResolvedJavaType typeOrNull(Stamp stamp, MetaAccessProvider metaAccess) { + if (stamp instanceof AbstractObjectStamp && stamp.hasValues()) { + AbstractObjectStamp abstractObjectStamp = (AbstractObjectStamp) stamp; + ResolvedJavaType type = abstractObjectStamp.type(); + if (type == null) { + return metaAccess.lookupJavaType(Object.class); + } else { + return type; + } + } + return null; + } + + public static ResolvedJavaType typeOrNull(ValueNode node, MetaAccessProvider metaAccess) { + return typeOrNull(node.stamp(), metaAccess); + } + + /** + * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain Stamp} has if it is a + * {@linkplain Stamp#hasValues() 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 + */ + public static TypeReference typeReferenceOrNull(Stamp stamp) { + if (stamp instanceof AbstractObjectStamp && stamp.hasValues()) { + AbstractObjectStamp abstractObjectStamp = (AbstractObjectStamp) stamp; + if (abstractObjectStamp.isExactType()) { + return TypeReference.createExactTrusted(abstractObjectStamp.type()); + } else { + return TypeReference.createTrustedWithoutAssumptions(abstractObjectStamp.type()); + } + } + return null; + } + + /** + * Checks whether this {@link ValueNode} represents a {@linkplain Stamp#hasValues() legal} + * Object value whose Java type is known exactly. If this method returns true then the + * {@linkplain ResolvedJavaType Java type} returned by {@link #typeReferenceOrNull(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 + */ + public static boolean isExactType(ValueNode node) { + return isExactType(node.stamp()); + } + + /** + * Checks whether this {@link Stamp} represents a {@linkplain Stamp#hasValues() legal} Object + * stamp whose {@linkplain ResolvedJavaType Java type} is known exactly. If this method returns + * true then the Java type returned by {@link #typeReferenceOrNull(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 + */ + public static boolean isExactType(Stamp stamp) { + if (stamp instanceof AbstractObjectStamp && stamp.hasValues()) { + return ((AbstractObjectStamp) stamp).isExactType(); + } + return false; + } +}