[builtins] Port Number.prototype.toString to Torque

Bug: v8:7864
Change-Id: Iaeca4ab9d098edc73b2191dc260dd37a6114f3bc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1893732
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64760}
This commit is contained in:
ajihyf 2019-11-05 17:17:41 +08:00 committed by Commit Bot
parent f1f98ce14a
commit 5b1ba2ab55
9 changed files with 102 additions and 62 deletions

View File

@ -196,6 +196,7 @@ Wiktor Garbacz <wiktor.garbacz@gmail.com>
Xiaoyin Liu <xiaoyin.l@outlook.com>
Yannic Bonenberger <contact@yannic-bonenberger.com>
Yong Wang <ccyongwang@tencent.com>
Youfeng Hao <ajihyf@gmail.com>
Yu Yin <xwafish@gmail.com>
Zac Hansen <xaxxon@gmail.com>
Zhao Jiazhong <kyslie3100@gmail.com>

View File

@ -952,6 +952,7 @@ torque_files = [
"src/builtins/internal-coverage.tq",
"src/builtins/iterator.tq",
"src/builtins/math.tq",
"src/builtins/number.tq",
"src/builtins/object-fromentries.tq",
"src/builtins/object.tq",
"src/builtins/promise-abstract-operations.tq",

View File

@ -1469,6 +1469,8 @@ const kBoolean: constexpr PrimitiveType
generates 'PrimitiveType::kBoolean';
const kSymbol: constexpr PrimitiveType
generates 'PrimitiveType::kSymbol';
const kNumber: constexpr PrimitiveType
generates 'PrimitiveType::kNumber';
const kNameDictionaryInitialCapacity:
constexpr int32 generates 'NameDictionary::kInitialCapacity';

View File

@ -670,7 +670,6 @@ namespace internal {
CPP(NumberPrototypeToFixed) \
CPP(NumberPrototypeToLocaleString) \
CPP(NumberPrototypeToPrecision) \
CPP(NumberPrototypeToString) \
/* ES6 #sec-number.prototype.valueof */ \
TFJ(NumberPrototypeValueOf, 0, kReceiver) \
TFC(Add, BinaryOp) \

View File

@ -186,65 +186,5 @@ BUILTIN(NumberPrototypeToPrecision) {
return *result;
}
// ES6 section 20.1.3.6 Number.prototype.toString ( [ radix ] )
BUILTIN(NumberPrototypeToString) {
HandleScope scope(isolate);
Handle<Object> value = args.at(0);
Handle<Object> radix = args.atOrUndefined(isolate, 1);
// Unwrap the receiver {value}.
if (value->IsJSPrimitiveWrapper()) {
value = handle(Handle<JSPrimitiveWrapper>::cast(value)->value(), isolate);
}
if (!value->IsNumber()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kNotGeneric,
isolate->factory()->NewStringFromAsciiChecked(
"Number.prototype.toString"),
isolate->factory()->Number_string()));
}
double const value_number = value->Number();
// If no {radix} was specified, just return ToString of {value}.
if (radix->IsUndefined(isolate)) {
return *isolate->factory()->NumberToString(value);
}
// Convert the {radix} to an integer first.
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, radix,
Object::ToInteger(isolate, radix));
double const radix_number = radix->Number();
// If {radix} is 10, just return ToString of {value}.
if (radix_number == 10.0) return *isolate->factory()->NumberToString(value);
// Make sure the {radix} is within the valid range.
if (radix_number < 2.0 || radix_number > 36.0) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kToRadixFormatRange));
}
// Fast case where the result is a one character string.
if ((IsUint32Double(value_number) && value_number < radix_number) ||
IsMinusZero(value_number)) {
// Character array used for conversion.
static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
return *isolate->factory()->LookupSingleCharacterStringFromCode(
kCharTable[static_cast<uint32_t>(value_number)]);
}
// Slow case.
if (std::isnan(value_number)) return ReadOnlyRoots(isolate).NaN_string();
if (std::isinf(value_number)) {
return (value_number < 0.0) ? ReadOnlyRoots(isolate).minus_Infinity_string()
: ReadOnlyRoots(isolate).Infinity_string();
}
char* const str =
DoubleToRadixCString(value_number, static_cast<int>(radix_number));
Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
DeleteArray(str);
return *result;
}
} // namespace internal
} // namespace v8

79
src/builtins/number.tq Normal file
View File

@ -0,0 +1,79 @@
// Copyright 2019 the V8 project authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
namespace runtime {
extern transitioning runtime
DoubleToStringWithRadix(implicit context: Context)(Number, Number): String;
} // namespace runtime
namespace number {
const kToRadixFormatRange: constexpr MessageTemplate
generates 'MessageTemplate::kToRadixFormatRange';
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)
const MINUS_V8_INFINITY: constexpr float64 generates '-V8_INFINITY';
transitioning macro ThisNumberValue(implicit context: Context)(
receiver: JSAny, method: constexpr string): Number {
return UnsafeCast<Number>(ToThisValue(receiver, kNumber, method));
}
// https://tc39.github.io/ecma262/#sec-number.prototype.tostring
transitioning javascript builtin NumberPrototypeToString(
js-implicit context: Context, receiver: JSAny)(...arguments): String {
// 1. Let x be ? thisNumberValue(this value).
const x = ThisNumberValue(receiver, 'Number.prototype.toString');
// 2. If radix is not present, let radixNumber be 10.
// 3. Else if radix is undefined, let radixNumber be 10.
// 4. Else, let radixNumber be ? ToInteger(radix).
const radix: JSAny = arguments[0];
const radixNumber: Number = radix == Undefined ?
10 :
ToInteger_Inline(context, radix, kTruncateMinusZero);
// 5. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception.
if (radixNumber < 2 || radixNumber > 36) {
ThrowRangeError(kToRadixFormatRange);
}
// 6. If radixNumber = 10, return ! ToString(x).
if (radixNumber == 10) {
return NumberToString(x);
}
// 7. Return the String representation of this Number
// value using the radix specified by radixNumber.
// Fast case where the result is a one character string.
if (TaggedIsPositiveSmi(x) && x < radixNumber) {
let charCode = Convert<int32>(UnsafeCast<Smi>(x));
if (charCode < 10) {
charCode += kAsciiZero;
} else {
charCode = charCode - 10 + kAsciiLowerCaseA;
}
return StringFromSingleCharCode(charCode);
}
if (x == -0) {
return ZeroStringConstant();
} else if (NumberIsNaN(x)) {
return NaNStringConstant();
} else if (x == V8_INFINITY) {
return InfinityStringConstant();
} else if (x == MINUS_V8_INFINITY) {
return MinusInfinityStringConstant();
}
return runtime::DoubleToStringWithRadix(x, radixNumber);
}
}

View File

@ -93,6 +93,7 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(GlobalPropertyCellMap, global_property_cell_map, PropertyCellMap) \
V(has_instance_symbol, has_instance_symbol, HasInstanceSymbol) \
V(HeapNumberMap, heap_number_map, HeapNumberMap) \
V(Infinity_string, Infinity_string, InfinityString) \
V(is_concat_spreadable_symbol, is_concat_spreadable_symbol, \
IsConcatSpreadableSymbol) \
V(iterator_symbol, iterator_symbol, IteratorSymbol) \
@ -101,9 +102,11 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(match_symbol, match_symbol, MatchSymbol) \
V(megamorphic_symbol, megamorphic_symbol, MegamorphicSymbol) \
V(MetaMap, meta_map, MetaMap) \
V(minus_Infinity_string, minus_Infinity_string, MinusInfinityString) \
V(MinusZeroValue, minus_zero_value, MinusZero) \
V(name_string, name_string, NameString) \
V(NanValue, nan_value, Nan) \
V(NaN_string, NaN_string, NaNString) \
V(next_string, next_string, NextString) \
V(NoClosuresCellMap, no_closures_cell_map, NoClosuresCellMap) \
V(null_to_string, null_to_string, NullToString) \
@ -149,7 +152,8 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(undefined_to_string, undefined_to_string, UndefinedToString) \
V(UndefinedValue, undefined_value, Undefined) \
V(uninitialized_symbol, uninitialized_symbol, UninitializedSymbol) \
V(WeakFixedArrayMap, weak_fixed_array_map, WeakFixedArrayMap)
V(WeakFixedArrayMap, weak_fixed_array_map, WeakFixedArrayMap) \
V(zero_string, zero_string, ZeroString)
#define HEAP_IMMOVABLE_OBJECT_LIST(V) \
HEAP_MUTABLE_IMMOVABLE_OBJECT_LIST(V) \

View File

@ -601,5 +601,18 @@ RUNTIME_FUNCTION(Runtime_GetInitializerFunction) {
Handle<Object> initializer = JSReceiver::GetDataProperty(constructor, key);
return *initializer;
}
RUNTIME_FUNCTION(Runtime_DoubleToStringWithRadix) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_DOUBLE_ARG_CHECKED(number, 0);
CONVERT_INT32_ARG_CHECKED(radix, 1);
char* const str = DoubleToRadixCString(number, radix);
Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
DeleteArray(str);
return *result;
}
} // namespace internal
} // namespace v8

View File

@ -210,6 +210,7 @@ namespace internal {
F(AllowDynamicFunction, 1, 1) \
I(CreateAsyncFromSyncIterator, 1, 1) \
F(CreateListFromArrayLike, 1, 1) \
F(DoubleToStringWithRadix, 2, 1) \
F(FatalProcessOutOfMemoryInAllocateRaw, 0, 1) \
F(FatalProcessOutOfMemoryInvalidArrayLength, 0, 1) \
F(GetAndResetRuntimeCallStats, -1 /* <= 2 */, 1) \