blob: cc6a6e1a61944a45f75a335ac9c67a5f81660baf [file] [log] [blame]
/*
* 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<? extends ValueNode> 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<? extends ValueNode> values, ValueNode selfValue) {
Iterator<? extends ValueNode> 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;
}
}