summaryrefslogtreecommitdiff
path: root/deps/v8/src/builtins/number.tq
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/builtins/number.tq')
-rw-r--r--deps/v8/src/builtins/number.tq138
1 files changed, 105 insertions, 33 deletions
diff --git a/deps/v8/src/builtins/number.tq b/deps/v8/src/builtins/number.tq
index 37dfea20be..3d0122d60e 100644
--- a/deps/v8/src/builtins/number.tq
+++ b/deps/v8/src/builtins/number.tq
@@ -51,9 +51,7 @@ extern macro NaNStringConstant(): String;
extern macro ZeroStringConstant(): String;
extern macro InfinityStringConstant(): String;
extern macro MinusInfinityStringConstant(): String;
-
-const kAsciiZero: constexpr int32 = 48; // '0' (ascii)
-const kAsciiLowerCaseA: constexpr int32 = 97; // 'a' (ascii)
+extern macro Log10OffsetTable(): RawPtr<uint64>;
transitioning macro ThisNumberValue(implicit context: Context)(
receiver: JSAny, method: constexpr string): Number {
@@ -61,35 +59,91 @@ transitioning macro ThisNumberValue(implicit context: Context)(
ToThisValue(receiver, PrimitiveType::kNumber, method));
}
-macro ToCharCode(input: int32): char8 {
- dcheck(0 <= input && input < 36);
- return input < 10 ?
- %RawDownCast<char8>(Unsigned(input + kAsciiZero)) :
- %RawDownCast<char8>(Unsigned(input - 10 + kAsciiLowerCaseA));
+macro ToCharCode(input: uint32): char8 {
+ dcheck(input < 36);
+ // 48 == '0', 97 == 'a'.
+ return input < 10 ? %RawDownCast<char8>(input + 48) :
+ %RawDownCast<char8>(input - 10 + 97);
+}
+
+macro IntToDecimalStringImpl(
+ x: int32, log10OffsetsTable: RawPtr<uint64>,
+ isPositive: constexpr bool): String {
+ dcheck(isPositive == (x >= 0));
+ let n: uint32 = isPositive ? Unsigned(x) : Unsigned(0 - x);
+ const log2: int32 = 31 - math::Word32Clz(Signed(n) | 1);
+ const tableEntry: uint64 = log10OffsetsTable[Convert<intptr>(log2)];
+ const digitCount: uint64 = (Convert<uint64>(n) + tableEntry) >>> 32;
+ let length = Convert<uint32>(digitCount);
+ if constexpr (!isPositive) length++; // For the '-'.
+ const string = AllocateNonEmptySeqOneByteString(length);
+ if constexpr (isPositive) {
+ string.raw_hash_field = MakeArrayIndexHash(n, length);
+ }
+ const lengthIntptr = Convert<intptr>(Signed(length));
+ let cursor: intptr = lengthIntptr - 1;
+ const rawChars = &string.chars;
+ while (true) {
+ const kInverse: uint64 = 0xcccccccd;
+ const quotient = Convert<uint32>((Convert<uint64>(n) * kInverse) >>> 35);
+ const remainder = n - quotient * 10;
+ const nextChar = %RawDownCast<char8>(remainder | 48); // 48 == '0'
+ // Writing to string.chars[cursor] directly would implicitly emit a
+ // bounds check, and we don't want no bounds check, thank you very much.
+ *UnsafeConstCast(rawChars.UncheckedAtIndex(cursor)) = nextChar;
+ cursor--;
+ n = quotient;
+ if (n == 0) break;
+ }
+ if constexpr (!isPositive) {
+ *UnsafeConstCast(rawChars.UncheckedAtIndex(0)) = 45; // 45 == '-'
+ }
+ return string;
}
@export
-macro NumberToStringSmi(x: int32, radix: int32): String labels Slow {
+macro IntToDecimalString(x: int32): String {
+ if constexpr (Is64()) {
+ const log10OffsetsTable: RawPtr<uint64> = Log10OffsetTable();
+ if (x >= 0) {
+ if (x < 10) {
+ if (x == 0) {
+ return ZeroStringConstant();
+ }
+ return StringFromSingleCharCode(ToCharCode(Unsigned(x)));
+ }
+ return IntToDecimalStringImpl(x, log10OffsetsTable, true);
+ } else {
+ return IntToDecimalStringImpl(x, log10OffsetsTable, false);
+ }
+ } else {
+ // The generic implementation doesn't rely on 64-bit instructions.
+ return IntToString(x, 10);
+ }
+}
+
+macro IntToString(x: int32, radix: uint32): String {
+ if constexpr (Is64()) {
+ dcheck(radix != 10); // Use IntToDecimalString otherwise.
+ }
const isNegative: bool = x < 0;
- let n: int32 = x;
+ let n: uint32;
if (!isNegative) {
// Fast case where the result is a one character string.
- if (x < radix) {
- if (x == 0) {
+ n = Unsigned(x);
+ if (n < radix) {
+ if (n == 0) {
return ZeroStringConstant();
}
return StringFromSingleCharCode(ToCharCode(n));
}
} else {
dcheck(isNegative);
- if (n == kMinInt32) {
- goto Slow;
- }
- n = 0 - n;
+ n = Unsigned(0 - x);
}
// Calculate length and pre-allocate the result string.
- let temp: int32 = n;
+ let temp: uint32 = n;
let length: int32 = isNegative ? Convert<int32>(1) : Convert<int32>(0);
while (temp > 0) {
temp = temp / radix;
@@ -99,7 +153,7 @@ macro NumberToStringSmi(x: int32, radix: int32): String labels Slow {
const strSeq = AllocateNonEmptySeqOneByteString(Unsigned(length));
let cursor: intptr = Convert<intptr>(length) - 1;
while (n > 0) {
- const digit: int32 = n % radix;
+ const digit: uint32 = n % radix;
n = n / radix;
*UnsafeConstCast(&strSeq.chars[cursor]) = ToCharCode(digit);
cursor = cursor - 1;
@@ -110,11 +164,12 @@ macro NumberToStringSmi(x: int32, radix: int32): String labels Slow {
*UnsafeConstCast(&strSeq.chars[0]) = 45;
} else {
dcheck(cursor == -1);
- // In sync with Factory::SmiToString: If radix = 10 and positive number,
- // update hash for string.
- if (radix == 10) {
- dcheck(strSeq.raw_hash_field == kNameEmptyHashField);
- strSeq.raw_hash_field = MakeArrayIndexHash(Unsigned(x), Unsigned(length));
+ if constexpr (!Is64()) {
+ if (radix == 10) {
+ dcheck(strSeq.raw_hash_field == kNameEmptyHashField);
+ strSeq.raw_hash_field =
+ MakeArrayIndexHash(Unsigned(x), Unsigned(length));
+ }
}
}
return strSeq;
@@ -146,8 +201,8 @@ transitioning javascript builtin NumberPrototypeToString(
// value using the radix specified by radixNumber.
if (TaggedIsSmi(x)) {
- return NumberToStringSmi(Convert<int32>(x), Convert<int32>(radixNumber))
- otherwise return runtime::DoubleToStringWithRadix(x, radixNumber);
+ return IntToString(
+ Convert<int32>(x), Unsigned(Convert<int32>(radixNumber)));
}
if (x == -0) {
@@ -311,8 +366,6 @@ transitioning javascript builtin NumberParseInt(
}
extern builtin NonNumberToNumeric(implicit context: Context)(JSAny): Numeric;
-extern builtin BitwiseAnd(implicit context: Context)(Number, Number): Number;
-extern builtin BitwiseXor(implicit context: Context)(Number, Number): Number;
extern builtin Subtract(implicit context: Context)(Number, Number): Number;
extern builtin Add(implicit context: Context)(Number, Number): Number;
extern builtin StringAddConvertLeft(implicit context: Context)(
@@ -323,6 +376,7 @@ extern builtin StringAddConvertRight(implicit context: Context)(
extern macro BitwiseOp(int32, int32, constexpr Operation): Number;
extern macro RelationalComparison(
constexpr Operation, JSAny, JSAny, Context): Boolean;
+extern macro TruncateNumberToWord32(Number): int32;
// TODO(bbudge) Use a simpler macro structure that doesn't loop when converting
// non-numbers, if such a code sequence doesn't make the builtin bigger.
@@ -699,7 +753,7 @@ builtin BitwiseNot(implicit context: Context)(value: JSAny): Numeric {
try {
UnaryOp1(value) otherwise Number, BigInt;
} label Number(n: Number) {
- tail BitwiseXor(n, -1);
+ return BitwiseOp(TruncateNumberToWord32(n), -1, Operation::kBitwiseXor);
} label BigInt(b: BigInt) {
return runtime::BigIntUnaryOp(
context, b, SmiTag<Operation>(Operation::kBitwiseNot));
@@ -754,20 +808,38 @@ builtin BitwiseAnd(implicit context: Context)(
try {
BinaryOp1(left, right) otherwise Number, AtLeastOneBigInt;
} label Number(left: Number, right: Number) {
- tail BitwiseAnd(left, right);
+ return BitwiseOp(
+ TruncateNumberToWord32(left), TruncateNumberToWord32(right),
+ Operation::kBitwiseAnd);
} label AtLeastOneBigInt(left: Numeric, right: Numeric) {
tail bigint::BigIntBitwiseAnd(left, right);
}
}
builtin BitwiseOr(implicit context: Context)(
- left: JSAny, right: JSAny): Object {
- return Generate_BitwiseBinaryOp(Operation::kBitwiseOr, left, right, context);
+ left: JSAny, right: JSAny): Numeric {
+ try {
+ BinaryOp1(left, right) otherwise Number, AtLeastOneBigInt;
+ } label Number(left: Number, right: Number) {
+ return BitwiseOp(
+ TruncateNumberToWord32(left), TruncateNumberToWord32(right),
+ Operation::kBitwiseOr);
+ } label AtLeastOneBigInt(left: Numeric, right: Numeric) {
+ tail bigint::BigIntBitwiseOr(left, right);
+ }
}
builtin BitwiseXor(implicit context: Context)(
- left: JSAny, right: JSAny): Object {
- return Generate_BitwiseBinaryOp(Operation::kBitwiseXor, left, right, context);
+ left: JSAny, right: JSAny): Numeric {
+ try {
+ BinaryOp1(left, right) otherwise Number, AtLeastOneBigInt;
+ } label Number(left: Number, right: Number) {
+ return BitwiseOp(
+ TruncateNumberToWord32(left), TruncateNumberToWord32(right),
+ Operation::kBitwiseXor);
+ } label AtLeastOneBigInt(left: Numeric, right: Numeric) {
+ tail bigint::BigIntBitwiseXor(left, right);
+ }
}
// Relational builtins.