[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:
parent
f1f98ce14a
commit
5b1ba2ab55
1
AUTHORS
1
AUTHORS
@ -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>
|
||||
|
1
BUILD.gn
1
BUILD.gn
@ -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",
|
||||
|
@ -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';
|
||||
|
@ -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) \
|
||||
|
@ -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
79
src/builtins/number.tq
Normal 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);
|
||||
}
|
||||
}
|
@ -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) \
|
||||
|
@ -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
|
||||
|
@ -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) \
|
||||
|
Loading…
Reference in New Issue
Block a user