diff options
Diffstat (limited to 'deps/v8/src/builtins/number.tq')
-rw-r--r-- | deps/v8/src/builtins/number.tq | 138 |
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. |