gecko-dev/js/js2/java/ScriptRuntime.java

128 строки
5.4 KiB
Java

class ScriptRuntime {
/*
* There's such a huge space (and some time) waste for the Foo.class
* syntax: the compiler sticks in a test of a static field in the
* enclosing class for null and the code for creating the class value.
* It has to do this since the reference has to get pushed off til
* executiontime (i.e. can't force an early load), but for the
* 'standard' classes - especially those in java.lang, we can trust
* that they won't cause problems by being loaded early.
*/
public final static Class StringClass = String.class;
public final static Class NumberClass = Number.class;
public final static Class BooleanClass = Boolean.class;
public final static Class ByteClass = Byte.class;
public final static Class ShortClass = Short.class;
public final static Class IntegerClass = Integer.class;
public final static Class LongClass = Long.class;
public final static Class FloatClass = Float.class;
public final static Class DoubleClass = Double.class;
public final static Class CharacterClass = Character.class;
public final static Class ObjectClass = Object.class;
// This definition of NaN is identical to that in java.lang.Double
// except that it is not final. This is a workaround for a bug in
// the Microsoft VM, versions 2.01 and 3.0P1, that causes some uses
// (returns at least) of Double.NaN to be converted to 1.0.
// So we use ScriptRuntime.NaN instead of Double.NaN.
public static double NaN = 0.0d / 0.0;
/*
* Helper function for toNumber, parseInt, and TokenStream.getToken.
*/
static double stringToNumber(String s, int start, int radix) {
char digitMax = '9';
char lowerCaseBound = 'a';
char upperCaseBound = 'A';
int len = s.length();
if (radix < 10) {
digitMax = (char) ('0' + radix - 1);
}
if (radix > 10) {
lowerCaseBound = (char) ('a' + radix - 10);
upperCaseBound = (char) ('A' + radix - 10);
}
int end;
double sum = 0.0;
for (end=start; end < len; end++) {
char c = s.charAt(end);
int newDigit;
if ('0' <= c && c <= digitMax)
newDigit = c - '0';
else if ('a' <= c && c < lowerCaseBound)
newDigit = c - 'a' + 10;
else if ('A' <= c && c < upperCaseBound)
newDigit = c - 'A' + 10;
else
break;
sum = sum*radix + newDigit;
}
if (start == end) {
return NaN;
}
if (sum >= 9007199254740992.0) {
if (radix == 10) {
/* If we're accumulating a decimal number and the number
* is >= 2^53, then the result from the repeated multiply-add
* above may be inaccurate. Call Java to get the correct
* answer.
*/
try {
return Double.valueOf(s.substring(start, end)).doubleValue();
} catch (NumberFormatException nfe) {
return NaN;
}
} else if (radix == 2 || radix == 4 || radix == 8 ||
radix == 16 || radix == 32)
{
/* The number may also be inaccurate for one of these bases.
* This happens if the addition in value*radix + digit causes
* a round-down to an even least significant mantissa bit
* when the first dropped bit is a one. If any of the
* following digits in the number (which haven't been added
* in yet) are nonzero then the correct action would have
* been to round up instead of down. An example of this
* occurs when reading the number 0x1000000000000081, which
* rounds to 0x1000000000000000 instead of 0x1000000000000100.
*/
BinaryDigitReader bdr = new BinaryDigitReader(radix, s, start, end);
int bit;
sum = 0.0;
/* Skip leading zeros. */
do {
bit = bdr.getNextBinaryDigit();
} while (bit == 0);
if (bit == 1) {
/* Gather the 53 significant bits (including the leading 1) */
sum = 1.0;
for (int j = 52; j != 0; j--) {
bit = bdr.getNextBinaryDigit();
if (bit < 0)
return sum;
sum = sum*2 + bit;
}
/* bit54 is the 54th bit (the first dropped from the mantissa) */
int bit54 = bdr.getNextBinaryDigit();
if (bit54 >= 0) {
double factor = 2.0;
int sticky = 0; /* sticky is 1 if any bit beyond the 54th is 1 */
int bit3;
while ((bit3 = bdr.getNextBinaryDigit()) >= 0) {
sticky |= bit3;
factor *= 2;
}
sum += bit54 & (bit | sticky);
sum *= factor;
}
}
}
/* We don't worry about inaccurate numbers for any other base. */
}
return sum;
}
}