--- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java 2016-12-09 00:47:17.040483173 -0800 @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2011, 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.core.common.type; + +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Signature; + +public class StampFactory { + + /* + * The marker stamp for node intrinsics must be its own class, so that it is never equal() to a + * regular ObjectStamp. + */ + static final class NodeIntrinsicStamp extends ObjectStamp { + protected static final Stamp SINGLETON = new NodeIntrinsicStamp(); + + private NodeIntrinsicStamp() { + super(null, false, false, false); + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + @Override + public boolean equals(Object obj) { + return this == obj; + } + } + + // JaCoCo Exclude + + private static final Stamp[] stampCache = new Stamp[JavaKind.values().length]; + private static final Stamp[] emptyStampCache = new Stamp[JavaKind.values().length]; + private static final Stamp objectStamp = new ObjectStamp(null, false, false, false); + private static final Stamp objectNonNullStamp = new ObjectStamp(null, false, true, false); + private static final Stamp objectAlwaysNullStamp = new ObjectStamp(null, false, false, true); + private static final Stamp positiveInt = forInteger(JavaKind.Int, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE); + private static final Stamp booleanTrue = forInteger(JavaKind.Boolean, -1, -1, 1, 1); + private static final Stamp booleanFalse = forInteger(JavaKind.Boolean, 0, 0, 0, 0); + private static final Stamp rawPointer = new RawPointerStamp(); + + private static void setCache(JavaKind kind, Stamp stamp) { + stampCache[kind.ordinal()] = stamp; + } + + private static void setIntCache(JavaKind kind) { + int bits = kind.getStackKind().getBitCount(); + long mask; + if (kind.isUnsigned()) { + mask = CodeUtil.mask(kind.getBitCount()); + } else { + mask = CodeUtil.mask(bits); + } + setCache(kind, new IntegerStamp(bits, kind.getMinValue(), kind.getMaxValue(), 0, mask)); + } + + private static void setFloatCache(JavaKind kind) { + setCache(kind, new FloatStamp(kind.getBitCount())); + } + + static { + setIntCache(JavaKind.Boolean); + setIntCache(JavaKind.Byte); + setIntCache(JavaKind.Short); + setIntCache(JavaKind.Char); + setIntCache(JavaKind.Int); + setIntCache(JavaKind.Long); + + setFloatCache(JavaKind.Float); + setFloatCache(JavaKind.Double); + + setCache(JavaKind.Object, objectStamp); + setCache(JavaKind.Void, VoidStamp.getInstance()); + setCache(JavaKind.Illegal, IllegalStamp.getInstance()); + + for (JavaKind k : JavaKind.values()) { + if (stampCache[k.ordinal()] != null) { + emptyStampCache[k.ordinal()] = stampCache[k.ordinal()].empty(); + } + } + } + + public static Stamp tautology() { + return booleanTrue; + } + + public static Stamp contradiction() { + return booleanFalse; + } + + /** + * Return a stamp for a Java kind, as it would be represented on the bytecode stack. + */ + public static Stamp forKind(JavaKind kind) { + assert stampCache[kind.ordinal()] != null : "unexpected forKind(" + kind + ")"; + return stampCache[kind.ordinal()]; + } + + /** + * Return the stamp for the {@code void} type. This will return a singleton instance than can be + * compared using {@code ==}. + */ + public static Stamp forVoid() { + return VoidStamp.getInstance(); + } + + /** + * A stamp used only in the graph of intrinsics, e.g., snippets. It is then replaced by an + * actual stamp when the intrinsic is used, i.e., when the snippet template is instantiated. + */ + public static Stamp forNodeIntrinsic() { + return NodeIntrinsicStamp.SINGLETON; + } + + public static Stamp intValue() { + return forKind(JavaKind.Int); + } + + public static Stamp positiveInt() { + return positiveInt; + } + + public static Stamp empty(JavaKind kind) { + return emptyStampCache[kind.ordinal()]; + } + + public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound, long downMask, long upMask) { + return new IntegerStamp(kind.getBitCount(), lowerBound, upperBound, downMask, upMask); + } + + public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound) { + return forInteger(kind.getBitCount(), lowerBound, upperBound); + } + + /** + * Create a new stamp use {@code newLowerBound} and {@code newUpperBound} computing the + * appropriate {@link IntegerStamp#upMask} and {@link IntegerStamp#downMask} and incorporating + * any mask information from {@code maskStamp}. + * + * @param bits + * @param newLowerBound + * @param newUpperBound + * @param maskStamp + * @return a new stamp with the appropriate bounds and masks + */ + public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, IntegerStamp maskStamp) { + IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound); + return new IntegerStamp(bits, newLowerBound, newUpperBound, limit.downMask() | maskStamp.downMask(), limit.upMask() & maskStamp.upMask()); + } + + public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, long newDownMask, long newUpMask) { + IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound); + return new IntegerStamp(bits, newLowerBound, newUpperBound, limit.downMask() | newDownMask, limit.upMask() & newUpMask); + } + + public static IntegerStamp forInteger(int bits) { + return new IntegerStamp(bits, CodeUtil.minValue(bits), CodeUtil.maxValue(bits), 0, CodeUtil.mask(bits)); + } + + public static IntegerStamp forInteger(int bits, long lowerBound, long upperBound) { + long defaultMask = CodeUtil.mask(bits); + if (lowerBound == upperBound) { + return new IntegerStamp(bits, lowerBound, lowerBound, lowerBound & defaultMask, lowerBound & defaultMask); + } + final long downMask; + final long upMask; + if (lowerBound >= 0) { + int upperBoundLeadingZeros = Long.numberOfLeadingZeros(upperBound); + long differentBits = lowerBound ^ upperBound; + int sameBitCount = Long.numberOfLeadingZeros(differentBits << upperBoundLeadingZeros); + + upMask = upperBound | -1L >>> (upperBoundLeadingZeros + sameBitCount); + downMask = upperBound & ~(-1L >>> (upperBoundLeadingZeros + sameBitCount)); + } else { + if (upperBound >= 0) { + upMask = defaultMask; + downMask = 0; + } else { + int lowerBoundLeadingOnes = Long.numberOfLeadingZeros(~lowerBound); + long differentBits = lowerBound ^ upperBound; + int sameBitCount = Long.numberOfLeadingZeros(differentBits << lowerBoundLeadingOnes); + + upMask = lowerBound | -1L >>> (lowerBoundLeadingOnes + sameBitCount) | ~(-1L >>> lowerBoundLeadingOnes); + downMask = lowerBound & ~(-1L >>> (lowerBoundLeadingOnes + sameBitCount)) | ~(-1L >>> lowerBoundLeadingOnes); + } + } + return new IntegerStamp(bits, lowerBound, upperBound, downMask & defaultMask, upMask & defaultMask); + } + + public static FloatStamp forFloat(JavaKind kind, double lowerBound, double upperBound, boolean nonNaN) { + assert kind.isNumericFloat(); + return new FloatStamp(kind.getBitCount(), lowerBound, upperBound, nonNaN); + } + + public static Stamp forConstant(JavaConstant value) { + JavaKind kind = value.getJavaKind(); + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + long mask = value.asLong() & CodeUtil.mask(kind.getBitCount()); + return forInteger(kind.getStackKind(), value.asLong(), value.asLong(), mask, mask); + case Float: + return forFloat(kind, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat())); + case Double: + return forFloat(kind, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble())); + case Illegal: + return forKind(JavaKind.Illegal); + case Object: + if (value.isNull()) { + return alwaysNull(); + } else { + return objectNonNull(); + } + default: + throw new GraalError("unexpected kind: %s", kind); + } + } + + public static Stamp forConstant(JavaConstant value, MetaAccessProvider metaAccess) { + if (value.getJavaKind() == JavaKind.Object) { + ResolvedJavaType type = value.isNull() ? null : metaAccess.lookupJavaType(value); + return new ObjectStamp(type, value.isNonNull(), value.isNonNull(), value.isNull()); + } else { + return forConstant(value); + } + } + + public static Stamp object() { + return objectStamp; + } + + public static Stamp objectNonNull() { + return objectNonNullStamp; + } + + public static Stamp alwaysNull() { + return objectAlwaysNullStamp; + } + + public static ObjectStamp object(TypeReference type) { + return object(type, false); + } + + public static ObjectStamp objectNonNull(TypeReference type) { + return object(type, true); + } + + public static ObjectStamp object(TypeReference type, boolean nonNull) { + if (type == null) { + return new ObjectStamp(null, false, nonNull, false); + } else { + return new ObjectStamp(type.getType(), type.isExact(), nonNull, false); + } + } + + public static Stamp[] createParameterStamps(Assumptions assumptions, ResolvedJavaMethod method) { + Signature sig = method.getSignature(); + Stamp[] result = new Stamp[sig.getParameterCount(!method.isStatic())]; + int index = 0; + + if (!method.isStatic()) { + result[index++] = StampFactory.objectNonNull(TypeReference.create(assumptions, method.getDeclaringClass())); + } + + int max = sig.getParameterCount(false); + ResolvedJavaType accessingClass = method.getDeclaringClass(); + for (int i = 0; i < max; i++) { + JavaType type = sig.getParameterType(i, accessingClass); + JavaKind kind = type.getJavaKind(); + Stamp stamp; + if (kind == JavaKind.Object && type instanceof ResolvedJavaType) { + stamp = StampFactory.object(TypeReference.create(assumptions, (ResolvedJavaType) type)); + } else { + stamp = StampFactory.forKind(kind); + } + result[index++] = stamp; + } + + return result; + } + + public static Stamp pointer() { + return rawPointer; + } + + public static StampPair forDeclaredType(Assumptions assumptions, JavaType returnType, boolean nonNull) { + if (returnType.getJavaKind() == JavaKind.Object && returnType instanceof ResolvedJavaType) { + ResolvedJavaType resolvedJavaType = (ResolvedJavaType) returnType; + TypeReference reference = TypeReference.create(assumptions, resolvedJavaType); + if (resolvedJavaType.isInterface()) { + ResolvedJavaType implementor = resolvedJavaType.getSingleImplementor(); + if (implementor != null && !resolvedJavaType.equals(implementor)) { + TypeReference uncheckedType = TypeReference.createTrusted(assumptions, implementor); + return StampPair.create(StampFactory.object(reference, nonNull), StampFactory.object(uncheckedType, nonNull)); + } + } + return StampPair.createSingle(StampFactory.object(reference, nonNull)); + } else { + return StampPair.createSingle(StampFactory.forKind(returnType.getJavaKind())); + } + } +}