diff options
Diffstat (limited to 'src/jdk/nashorn/internal/codegen/types/Range.java')
-rw-r--r-- | src/jdk/nashorn/internal/codegen/types/Range.java | 705 |
1 files changed, 0 insertions, 705 deletions
diff --git a/src/jdk/nashorn/internal/codegen/types/Range.java b/src/jdk/nashorn/internal/codegen/types/Range.java deleted file mode 100644 index 2845d902..00000000 --- a/src/jdk/nashorn/internal/codegen/types/Range.java +++ /dev/null @@ -1,705 +0,0 @@ -/* - * Copyright (c) 2010, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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 jdk.nashorn.internal.codegen.types; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import jdk.nashorn.internal.runtime.DebugLogger; -import jdk.nashorn.internal.runtime.JSType; - -/** - * Represents the value range of a symbol. - */ -public abstract class Range { - - private static final Range GENERIC_RANGE = new Range() { - @Override - public Type getType() { - return Type.OBJECT; - } - }; - - private static final Range NUMBER_RANGE = new Range() { - @Override - public Type getType() { - return Type.NUMBER; - } - }; - - private static final Range UNKNOWN_RANGE = new Range() { - @Override - public Type getType() { - return Type.UNKNOWN; - } - - @Override - public boolean isUnknown() { - return true; - } - }; - - private static class IntegerRange extends Range { - private final long min; - private final long max; - private final Type type; - - private IntegerRange(final long min, final long max) { - assert min <= max; - this.min = min; - this.max = max; - this.type = typeFromRange(min, max); - } - - private static Type typeFromRange(final long from, final long to) { - if (from >= Integer.MIN_VALUE && to <= Integer.MAX_VALUE) { - return Type.INT; - } - return Type.LONG; - } - - @Override - public Type getType() { - return type; - } - - public long getMin() { - return min; - } - - public long getMax() { - return max; - } - - @Override - public boolean isIntegerConst() { - return getMin() == getMax(); - } - - private long getBitMask() { - if (min == max) { - return min; - } - - if (min < 0) { - return ~0L; - } - - long mask = 1; - while (mask < max) { - mask = (mask << 1) | 1; - } - return mask; - } - - @Override - public boolean equals(final Object obj) { - if (obj instanceof IntegerRange) { - final IntegerRange other = (IntegerRange)obj; - return this.type == other.type && this.min == other.min && this.max == other.max; - } - return false; - } - - @Override - public int hashCode() { - return Long.hashCode(min) ^ Long.hashCode(max); - } - - @Override - public String toString() { - return super.toString() + "[" + min +", " + max + "]"; - } - } - - /** - * Get narrowest type for this range - * @return type - */ - public abstract Type getType(); - - /** - * Is this range unknown - * @return true if unknown - */ - public boolean isUnknown() { - return false; - } - - /** - * Check if an integer is enough to span this range - * @return true if integer is enough - */ - public boolean isIntegerType() { - return this instanceof IntegerRange; - } - - /** - * Check if an integer is enough to span this range - * @return true if integer is enough - */ - public boolean isIntegerConst() { - return false; - } - - /** - * Create an unknown range - this is most likely a singleton object - * and it represents "we have no known range information" - * @return the range - */ - public static Range createUnknownRange() { - return UNKNOWN_RANGE; - } - - /** - * Create a constant range: [value, value] - * @param value value - * @return the range - */ - public static Range createRange(final int value) { - return createIntegerRange(value, value); - } - - /** - * Create a constant range: [value, value] - * @param value value - * @return the range - */ - public static Range createRange(final long value) { - return createIntegerRange(value, value); - } - - /** - * Create a constant range: [value, value] - * @param value value - * @return the range - */ - public static Range createRange(final double value) { - if (isRepresentableAsLong(value)) { - return createIntegerRange((long) value, (long) value); - } - return createNumberRange(); - } - - /** - * Create a constant range: [value, value] - * @param value value - * @return the range - */ - public static Range createRange(final Object value) { - if (value instanceof Integer) { - return createRange((int)value); - } else if (value instanceof Long) { - return createRange((long)value); - } else if (value instanceof Double) { - return createRange((double)value); - } - - return createGenericRange(); - } - - /** - * Create a generic range - object symbol that carries no range - * information - * @return the range - */ - public static Range createGenericRange() { - return GENERIC_RANGE; - } - - /** - * Create a number range - number symbol that carries no range - * information - * @return the range - */ - public static Range createNumberRange() { - return NUMBER_RANGE; - } - - /** - * Create an integer range [min, max] - * @param min minimum value, inclusive - * @param max maximum value, inclusive - * @return the range - */ - public static IntegerRange createIntegerRange(final long min, final long max) { - return new IntegerRange(min, max); - } - - /** - * Create an integer range of maximum type width for the given type - * @param type the type - * @return the range - */ - public static IntegerRange createIntegerRange(final Type type) { - assert type.isNumeric() && !type.isNumber(); - final long min; - final long max; - if (type.isInteger()) { - min = Integer.MIN_VALUE; - max = Integer.MAX_VALUE; - } else if (type.isLong()) { - min = Long.MIN_VALUE; - max = Long.MAX_VALUE; - } else { - throw new AssertionError(); //type incompatible with integer range - } - return new IntegerRange(min, max); - } - - /** - * Create an range of maximum type width for the given type - * @param type the type - * @return the range - */ - public static Range createTypeRange(final Type type) { - if (type.isNumber()) { - return createNumberRange(); - } else if (type.isNumeric()) { - return createIntegerRange(type); - } else { - return createGenericRange(); - } - } - - // check that add doesn't overflow - private static boolean checkAdd(final long a, final long b) { - final long result = a + b; - return ((a ^ result) & (b ^ result)) >= 0; - } - - // check that sub doesn't overflow - private static boolean checkSub(final long a, final long b) { - final long result = a - b; - return ((a ^ result) & (b ^ result)) >= 0; - } - - private static boolean checkMul(final long a, final long b) { - // TODO correct overflow check - return a >= Integer.MIN_VALUE && a <= Integer.MAX_VALUE && b >= Integer.MIN_VALUE && b <= Integer.MAX_VALUE; - } - - /** - * The range functionality class responsible for merging ranges and drawing - * range conclusions from operations executed - */ - public static class Functionality { - /** logger */ - protected final DebugLogger log; - - /** - * Constructor - * @param log logger - */ - public Functionality(final DebugLogger log) { - this.log = log; - } - - /** - * Join two ranges - * @param a first range - * @param b second range - * @return the joined range - */ - public Range join(final Range a, final Range b) { - if (a.equals(b)) { - return a; - } - - Type joinedType = a.getType(); - if (a.getType() != b.getType()) { - if (a.isUnknown()) { - return b; - } - if (b.isUnknown()) { - return a; - } - - joinedType = Type.widest(a.getType(), b.getType()); - } - - if (joinedType.isInteger() || joinedType.isLong()) { - return createIntegerRange( - Math.min(((IntegerRange) a).getMin(), ((IntegerRange) b).getMin()), - Math.max(((IntegerRange) a).getMax(), ((IntegerRange) b).getMax())); - } - - return createTypeRange(joinedType); - } - - /** - * Add operation - * @param a range of first symbol to be added - * @param b range of second symbol to be added - * @return resulting range representing the value range after add - */ - public Range add(final Range a, final Range b) { - if (a.isIntegerType() && b.isIntegerType()) { - final IntegerRange lhs = (IntegerRange)a; - final IntegerRange rhs = (IntegerRange)b; - if (checkAdd(lhs.getMin(), rhs.getMin()) && checkAdd(lhs.getMax(), rhs.getMax())) { - return createIntegerRange(lhs.getMin() + rhs.getMin(), lhs.getMax() + rhs.getMax()); - } - } - - if (a.getType().isNumeric() && b.getType().isNumeric()) { - return createNumberRange(); - } - - return createGenericRange(); - } - - /** - * Sub operation - * @param a range of first symbol to be subtracted - * @param b range of second symbol to be subtracted - * @return resulting range representing the value range after subtraction - */ - public Range sub(final Range a, final Range b) { - if (a.isIntegerType() && b.isIntegerType()) { - final IntegerRange lhs = (IntegerRange)a; - final IntegerRange rhs = (IntegerRange)b; - if (checkSub(lhs.getMin(), rhs.getMax()) && checkSub(lhs.getMax(), rhs.getMin())) { - return createIntegerRange(lhs.getMin() - rhs.getMax(), lhs.getMax() - rhs.getMin()); - } - } - - if (a.getType().isNumeric() && b.getType().isNumeric()) { - return createNumberRange(); - } - - return createGenericRange(); - } - - /** - * Mul operation - * @param a range of first symbol to be multiplied - * @param b range of second symbol to be multiplied - * @return resulting range representing the value range after multiplication - */ - public Range mul(final Range a, final Range b) { - if (a.isIntegerType() && b.isIntegerType()) { - final IntegerRange lhs = (IntegerRange)a; - final IntegerRange rhs = (IntegerRange)b; - - //ensure that nothing ever overflows or underflows - if (checkMul(lhs.getMin(), rhs.getMin()) && - checkMul(lhs.getMax(), rhs.getMax()) && - checkMul(lhs.getMin(), rhs.getMax()) && - checkMul(lhs.getMax(), rhs.getMin())) { - - final List<Long> results = - Arrays.asList( - lhs.getMin() * rhs.getMin(), - lhs.getMin() * rhs.getMax(), - lhs.getMax() * rhs.getMin(), - lhs.getMax() * rhs.getMax()); - return createIntegerRange(Collections.min(results), Collections.max(results)); - } - } - - if (a.getType().isNumeric() && b.getType().isNumeric()) { - return createNumberRange(); - } - - return createGenericRange(); - } - - /** - * Neg operation - * @param a range of value symbol to be negated - * @return resulting range representing the value range after neg - */ - public Range neg(final Range a) { - if (a.isIntegerType()) { - final IntegerRange rhs = (IntegerRange)a; - if (rhs.getMin() != Long.MIN_VALUE && rhs.getMax() != Long.MIN_VALUE) { - return createIntegerRange(-rhs.getMax(), -rhs.getMin()); - } - } - - if (a.getType().isNumeric()) { - return createNumberRange(); - } - - return createGenericRange(); - } - - /** - * Bitwise and operation - * @param a range of first symbol to be and:ed - * @param b range of second symbol to be and:ed - * @return resulting range representing the value range after and - */ - public Range and(final Range a, final Range b) { - if (a.isIntegerType() && b.isIntegerType()) { - final int resultMask = (int) (((IntegerRange)a).getBitMask() & ((IntegerRange)b).getBitMask()); - if (resultMask >= 0) { - return createIntegerRange(0, resultMask); - } - } else if (a.isUnknown() && b.isIntegerType()) { - final long operandMask = ((IntegerRange)b).getBitMask(); - if (operandMask >= 0) { - return createIntegerRange(0, operandMask); - } - } else if (a.isIntegerType() && b.isUnknown()) { - final long operandMask = ((IntegerRange)a).getBitMask(); - if (operandMask >= 0) { - return createIntegerRange(0, operandMask); - } - } - - return createTypeRange(Type.INT); - } - - /** - * Bitwise or operation - * @param a range of first symbol to be or:ed - * @param b range of second symbol to be or:ed - * @return resulting range representing the value range after or - */ - public Range or(final Range a, final Range b) { - if (a.isIntegerType() && b.isIntegerType()) { - final int resultMask = (int)(((IntegerRange)a).getBitMask() | ((IntegerRange)b).getBitMask()); - if (resultMask >= 0) { - return createIntegerRange(0, resultMask); - } - } - - return createTypeRange(Type.INT); - } - - /** - * Bitwise xor operation - * @param a range of first symbol to be xor:ed - * @param b range of second symbol to be xor:ed - * @return resulting range representing the value range after and - */ - public Range xor(final Range a, final Range b) { - if (a.isIntegerConst() && b.isIntegerConst()) { - return createRange(((IntegerRange)a).getMin() ^ ((IntegerRange)b).getMin()); - } - - if (a.isIntegerType() && b.isIntegerType()) { - final int resultMask = (int)(((IntegerRange)a).getBitMask() | ((IntegerRange)b).getBitMask()); - if (resultMask >= 0) { - return createIntegerRange(0, createIntegerRange(0, resultMask).getBitMask()); - } - } - return createTypeRange(Type.INT); - } - - /** - * Bitwise shl operation - * @param a range of first symbol to be shl:ed - * @param b range of second symbol to be shl:ed - * @return resulting range representing the value range after shl - */ - public Range shl(final Range a, final Range b) { - if (b.isIntegerType() && b.isIntegerConst()) { - final IntegerRange left = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT)); - final int shift = (int)((IntegerRange) b).getMin() & 0x1f; - final int min = (int)left.getMin() << shift; - final int max = (int)left.getMax() << shift; - if (min >> shift == left.getMin() && max >> shift == left.getMax()) { - return createIntegerRange(min, max); - } - } - - return createTypeRange(Type.INT); - } - - /** - * Bitwise shr operation - * @param a range of first symbol to be shr:ed - * @param b range of second symbol to be shr:ed - * @return resulting range representing the value range after shr - */ - public Range shr(final Range a, final Range b) { - if (b.isIntegerType() && b.isIntegerConst()) { - final long shift = ((IntegerRange) b).getMin() & 0x1f; - final IntegerRange left = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT)); - if (left.getMin() >= 0) { - long min = left.getMin() >>> shift; - long max = left.getMax() >>> shift; - return createIntegerRange(min, max); - } else if (shift >= 1) { - return createIntegerRange(0, JSType.MAX_UINT >>> shift); - } - } - - return createTypeRange(Type.INT); - } - - /** - * Bitwise sar operation - * @param a range of first symbol to be sar:ed - * @param b range of second symbol to be sar:ed - * @return resulting range representing the value range after sar - */ - public Range sar(final Range a, final Range b) { - if (b.isIntegerType() && b.isIntegerConst()) { - final IntegerRange left = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT)); - final long shift = ((IntegerRange) b).getMin() & 0x1f; - final long min = left.getMin() >> shift; - final long max = left.getMax() >> shift; - return createIntegerRange(min, max); - } - - return createTypeRange(Type.INT); - } - - /** - * Modulo operation - * @param a range of first symbol to the mod operation - * @param b range of second symbol to be mod operation - * @return resulting range representing the value range after mod - */ - public Range mod(final Range a, final Range b) { - if (a.isIntegerType() && b.isIntegerType()) { - final IntegerRange rhs = (IntegerRange) b; - if (rhs.getMin() > 0 || rhs.getMax() < 0) { // divisor range must not include 0 - final long absmax = Math.max(Math.abs(rhs.getMin()), Math.abs(rhs.getMax())) - 1; - return createIntegerRange(rhs.getMin() > 0 ? 0 : -absmax, rhs.getMax() < 0 ? 0 : +absmax); - } - } - return createTypeRange(Type.NUMBER); - } - - /** - * Division operation - * @param a range of first symbol to the division - * @param b range of second symbol to be division - * @return resulting range representing the value range after division - */ - public Range div(final Range a, final Range b) { - // TODO - return createTypeRange(Type.NUMBER); - } - } - - /** - * Simple trace functionality that will log range creation - */ - public static class TraceFunctionality extends Functionality { - TraceFunctionality(final DebugLogger log) { - super(log); - } - - private Range trace(final Range result, final String operation, final Range... operands) { - log.fine("range::" + operation + Arrays.toString(operands) + " => " + result); - return result; - } - - @Override - public Range join(final Range a, final Range b) { - final Range result = super.join(a, b); - if (!a.equals(b)) { - trace(result, "join", a, b); - } - return result; - } - - @Override - public Range add(final Range a, final Range b) { - return trace(super.add(a, b), "add", a, b); - } - - @Override - public Range sub(final Range a, final Range b) { - return trace(super.sub(a, b), "sub", a, b); - } - - @Override - public Range mul(final Range a, final Range b) { - return trace(super.mul(a, b), "mul", a, b); - } - - @Override - public Range neg(final Range a) { - return trace(super.neg(a), "neg", a); - } - - @Override - public Range and(final Range a, final Range b) { - return trace(super.and(a, b), "and", a, b); - } - - @Override - public Range or(final Range a, final Range b) { - return trace(super.or(a, b), "or", a, b); - } - - @Override - public Range xor(final Range a, final Range b) { - return trace(super.xor(a, b), "xor", a, b); - } - - @Override - public Range shl(final Range a, final Range b) { - return trace(super.shl(a, b), "shl", a, b); - } - - @Override - public Range shr(final Range a, final Range b) { - return trace(super.shr(a, b), "shr", a, b); - } - - @Override - public Range sar(final Range a, final Range b) { - return trace(super.sar(a, b), "sar", a, b); - } - - @Override - public Range mod(final Range a, final Range b) { - return trace(super.mod(a, b), "mod", a, b); - } - - @Override - public Range div(final Range a, final Range b) { - return trace(super.div(a, b), "div", a, b); - } - } - - @Override - public String toString() { - return String.valueOf(getType()); - } - - @SuppressWarnings("unused") - private static boolean isRepresentableAsInt(final double number) { - return (int)number == number && !isNegativeZero(number); - } - - private static boolean isRepresentableAsLong(final double number) { - return (long)number == number && !isNegativeZero(number); - } - - private static boolean isNegativeZero(final double number) { - return Double.doubleToLongBits(number) == Double.doubleToLongBits(-0.0); - } -} |