Commit f84d519a authored by Bill Budge's avatar Bill Budge Committed by Commit Bot

[torque] Port builtins-conversion-gen to Torque

- Ports all conversions that Torque can handle (without weird linkage.)
- Moves NumberToString to number:: namespace.
- Moves ToStringImpl to string:: namespace.

Bug: v8:9891
Change-Id: I5190c545952e1d9810ca71ae7ff4a807d2d98781
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2205192
Commit-Queue: Bill Budge <bbudge@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67903}
parent 986254d2
......@@ -1030,8 +1030,9 @@ torque_files = [
"src/builtins/bigint.tq",
"src/builtins/boolean.tq",
"src/builtins/builtins-string.tq",
"src/builtins/collections.tq",
"src/builtins/cast.tq",
"src/builtins/collections.tq",
"src/builtins/conversion.tq",
"src/builtins/convert.tq",
"src/builtins/console.tq",
"src/builtins/data-view.tq",
......
......@@ -292,11 +292,11 @@ transitioning macro ArrayJoinImpl<T: type>(implicit context: Context)(
next = str;
}
case (num: Number): {
next = NumberToString(num);
next = number::NumberToString(num);
}
case (obj: JSAny): {
if (IsNullOrUndefined(obj)) continue;
next = ToString(context, obj);
next = string::ToString(context, obj);
}
}
}
......
......@@ -264,6 +264,7 @@ extern enum MessageTemplate {
kNotGeneric,
kCalledNonCallable,
kCalledOnNullOrUndefined,
kCannotConvertToPrimitive,
kProtoObjectOrNull,
kInvalidOffset,
kInvalidTypedArrayLength,
......@@ -307,6 +308,7 @@ extern enum MessageTemplate {
kProxyGetPrototypeOfNonExtensible,
kProxySetPrototypeOfNonExtensible,
kProxyDeletePropertyNonExtensible,
kUndefinedOrNullToObject,
kWeakRefsCleanupMustBeCallable,
kWasmTrapUnreachable,
kWasmTrapMemOutOfBounds,
......@@ -385,6 +387,7 @@ type Boolean = True|False;
type NumberOrUndefined = Number|Undefined;
extern macro DefaultStringConstant(): String;
extern macro EmptyStringConstant(): EmptyString;
extern macro FalseConstant(): False;
extern macro Int32FalseConstant(): bool;
......@@ -396,10 +399,15 @@ extern macro MessageStringConstant(): String;
extern macro NanConstant(): NaN;
extern macro NameStringConstant(): String;
extern macro NullConstant(): Null;
extern macro NumberStringConstant(): String;
extern macro ReturnStringConstant(): String;
extern macro StringStringConstant(): String;
extern macro TheHoleConstant(): TheHole;
extern macro ToPrimitiveSymbolConstant(): PublicSymbol;
extern macro ToStringStringConstant(): String;
extern macro TrueConstant(): True;
extern macro UndefinedConstant(): Undefined;
extern macro ValueOfStringConstant(): String;
const TheHole: TheHole = TheHoleConstant();
const Null: Null = NullConstant();
......@@ -580,10 +588,6 @@ extern builtin ToObject(Context, JSAny): JSReceiver;
extern macro ToObject_Inline(Context, JSAny): JSReceiver;
extern macro IsNullOrUndefined(Object): bool;
extern macro IsString(HeapObject): bool;
transitioning builtin ToString(context: Context, o: JSAny): String {
return ToStringImpl(context, o);
}
extern transitioning runtime ToStringRT(Context, JSAny): String;
extern transitioning builtin NonPrimitiveToPrimitive_String(
Context, JSAny): JSPrimitive;
extern transitioning builtin NonPrimitiveToPrimitive_Default(
......@@ -1371,7 +1375,6 @@ transitioning macro GetMethod(implicit context: Context)(
MessageTemplate::kPropertyNotFunction, value, symbol, o);
}
extern macro NumberToString(Number): String;
extern macro IsOneByteStringInstanceType(InstanceType): bool;
// After converting an index to an integer, calculate a relative index:
......@@ -1573,35 +1576,6 @@ transitioning builtin FastCreateDataProperty(implicit context: Context)(
return Undefined;
}
@export
transitioning macro ToStringImpl(context: Context, o: JSAny): String {
let result: JSAny = o;
while (true) {
typeswitch (result) {
case (num: Number): {
return NumberToString(num);
}
case (str: String): {
return str;
}
case (oddball: Oddball): {
return oddball.to_string;
}
case (JSReceiver): {
result = NonPrimitiveToPrimitive_String(context, result);
continue;
}
case (Symbol): {
ThrowTypeError(MessageTemplate::kSymbolToString);
}
case (JSAny): {
return ToStringRT(context, o);
}
}
}
unreachable;
}
macro VerifiedUnreachable(): never {
StaticAssert(false);
unreachable;
......
This diff is collapsed.
......@@ -197,7 +197,7 @@ TF_BUILTIN(DatePrototypeToPrimitive, CodeStubAssembler) {
hint_is_invalid(this, Label::kDeferred);
// Fast cases for internalized strings.
TNode<String> number_string = numberStringConstant();
TNode<String> number_string = NumberStringConstant();
GotoIf(TaggedEqual(hint, number_string), &hint_is_number);
TNode<String> default_string = DefaultStringConstant();
GotoIf(TaggedEqual(hint, default_string), &hint_is_string);
......
......@@ -196,22 +196,8 @@ namespace internal {
ASM(HandleDebuggerStatement, ContextOnly) \
\
/* Type conversions */ \
TFC(ToObject, TypeConversion) \
TFC(ToBoolean, TypeConversion) \
TFC(OrdinaryToPrimitive_Number, TypeConversion) \
TFC(OrdinaryToPrimitive_String, TypeConversion) \
TFC(NonPrimitiveToPrimitive_Default, TypeConversion) \
TFC(NonPrimitiveToPrimitive_Number, TypeConversion) \
TFC(NonPrimitiveToPrimitive_String, TypeConversion) \
TFC(StringToNumber, TypeConversion) \
TFC(ToName, TypeConversion) \
TFC(NonNumberToNumber, TypeConversion) \
TFC(NonNumberToNumeric, TypeConversion) \
TFC(ToNumber, TypeConversion) \
TFC(ToNumberConvertBigInt, TypeConversion) \
TFC(ToNumeric, TypeConversion) \
TFC(NumberToString, TypeConversion) \
TFC(ToLength, TypeConversion) \
TFC(Typeof, Typeof) \
TFC(GetSuperConstructor, Typeof) \
TFC(BigIntToI64, BigIntToI64) \
......
......@@ -5,6 +5,43 @@
#include 'src/builtins/builtins-string-gen.h'
namespace string {
// TODO(bbudge) Remove the 'RT' suffix on this runtime function.
extern transitioning runtime ToStringRT(Context, JSAny): String;
@export
transitioning macro ToStringImpl(context: Context, o: JSAny): String {
let result: JSAny = o;
while (true) {
typeswitch (result) {
case (num: Number): {
return number::NumberToString(num);
}
case (str: String): {
return str;
}
case (oddball: Oddball): {
return oddball.to_string;
}
case (JSReceiver): {
result = NonPrimitiveToPrimitive_String(context, result);
continue;
}
case (Symbol): {
ThrowTypeError(MessageTemplate::kSymbolToString);
}
case (JSAny): {
return ToStringRT(context, o);
}
}
}
unreachable;
}
transitioning builtin ToString(context: Context, o: JSAny): String {
return ToStringImpl(context, o);
}
extern macro StringBuiltinsAssembler::SubString(
String, uintptr, uintptr): String;
......
......@@ -425,6 +425,11 @@ Cast<NumberDictionary>(o: HeapObject): NumberDictionary
goto CastError;
}
Cast<Name>(o: HeapObject): Name
labels CastError {
if (IsName(o)) return %RawDownCast<Name>(o);
goto CastError;
}
Cast<String>(o: HeapObject): String
labels CastError {
return HeapObjectToString(o) otherwise CastError;
......
// Copyright 2020 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 ToStringRT(Context, BigInt): String;
}
// A namespace to disambiguate calls with the same name as a JS Builtin.
namespace csa {
extern macro StringToNumber(String): Number;
extern macro NonNumberToNumber(implicit context: Context)(JSAnyNotNumber):
Number;
extern macro NonNumberToNumeric(implicit context: Context)(JSAnyNotNumber):
Numeric;
}
extern enum OrdinaryToPrimitiveHint { kString, kNumber }
extern macro OrdinaryToPrimitive(implicit context: Context)(
JSAny, constexpr OrdinaryToPrimitiveHint): JSPrimitive;
namespace conversion {
builtin StringToNumber(implicit context: Context)(input: String): Number {
return csa::StringToNumber(input);
}
builtin NonNumberToNumber(implicit context: Context)(input: JSAnyNotNumber):
Number {
return csa::NonNumberToNumber(input);
}
builtin NonNumberToNumeric(implicit context: Context)(input: JSAnyNotNumber):
Numeric {
return csa::NonNumberToNumeric(input);
}
builtin ToNumeric(implicit context: Context)(input: JSAny): Numeric {
typeswitch (input) {
case (n: Number): {
return n;
}
case (h: JSAnyNotNumber): {
return NonNumberToNumeric(h);
}
}
}
// ES section #sec-tostring-applied-to-the-number-type
builtin NumberToString(implicit context: Context)(input: Number): String {
return number::NumberToString(input);
}
// ES6 section 7.1.2 ToBoolean ( argument )
builtin ToBoolean(implicit context: Context)(input: JSAny): Boolean {
BranchIfToBooleanIsTrue(input) otherwise return TrueConstant(),
return FalseConstant();
}
builtin ToLength(implicit context: Context)(input: JSAny): Number {
// We might need to loop once for ToNumber conversion.
let x: JSAny = input;
while (true) {
typeswitch (x) {
case (s: Smi): {
if (s < 0) return 0;
return s;
}
case (h: HeapNumber): {
let value: float64 = Convert<float64>(h);
// The sense of this test is important for the NaN and -0 cases.
if (!(value > 0)) return 0;
if (value > kMaxSafeInteger) return kMaxSafeInteger;
value = math::Float64Floor(value);
return ChangeFloat64ToTagged(value);
}
case (h: JSAnyNotNumber): {
x = csa::NonNumberToNumber(h);
}
}
}
VerifiedUnreachable();
}
transitioning builtin ToName(implicit context: Context)(input: JSAny): Name {
// We might need to loop once for ToNumber conversion.
let x: JSAny = input;
while (true) {
typeswitch (x) {
case (n: Name): {
return n;
}
case (n: Number): {
return number::NumberToString(n);
}
case (b: BigInt): {
// We don't have a fast-path for BigInt currently, so just
// tail call to the %ToString runtime function here for now.
tail runtime::ToStringRT(context, b);
}
case (o: Oddball): {
return o.to_string;
}
case (o: JSReceiver): {
x = NonPrimitiveToPrimitive_String(o);
}
}
}
VerifiedUnreachable();
}
const kNoConstructorFunctionIndex:
constexpr int31 generates 'Map::kNoConstructorFunctionIndex';
// ES6 section 7.1.13 ToObject (argument)
transitioning builtin ToObject(implicit context: Context)(input: JSAny):
JSReceiver {
try {
typeswitch (input) {
case (Smi): {
goto WrapPrimitive(NativeContextSlot::NUMBER_FUNCTION_INDEX);
}
case (o: JSReceiver): {
return o;
}
case (o: JSAnyNotSmi): {
const index: intptr = Convert<intptr>(
o.map.in_object_properties_start_or_constructor_function_index);
if (index != kNoConstructorFunctionIndex) goto WrapPrimitive(index);
ThrowTypeError(MessageTemplate::kUndefinedOrNullToObject, 'ToObject');
}
}
} label WrapPrimitive(constructorIndex: intptr) {
const nativeContext = LoadNativeContext(context);
const constructor = UnsafeCast<JSFunction>(nativeContext[constructorIndex]);
const map: Map = UnsafeCast<Map>(constructor.prototype_or_initial_map);
const wrapper =
UnsafeCast<JSPrimitiveWrapper>(AllocateFastOrSlowJSObjectFromMap(map));
wrapper.value = input;
return wrapper;
}
}
// ES6 section 7.1.1 ToPrimitive ( input [ , PreferredType ] )
transitioning macro TryGetExoticToPrimitive(implicit context: Context)(
input: JSAny): JSAny labels OrdinaryToPrimitive {
// Look up the @@toPrimitive property.
const exoticToPrimitive: JSAny =
GetProperty(input, ToPrimitiveSymbolConstant());
if (IsNullOrUndefined(exoticToPrimitive)) goto OrdinaryToPrimitive;
return exoticToPrimitive;
}
transitioning macro CallExoticToPrimitive(implicit context: Context)(
input: JSAny, exoticToPrimitive: JSAny, hint: String): JSPrimitive {
// Invoke the exoticToPrimitive method on the input with a string
// representation of the hint.
const result: JSAny = Call(context, exoticToPrimitive, input, hint);
// Verify that the result is primitive.
typeswitch (result) {
case (o: JSPrimitive): {
return o;
}
case (JSReceiver): {
// Somehow the @@toPrimitive method on input didn't yield a primitive.
ThrowTypeError(MessageTemplate::kCannotConvertToPrimitive);
}
}
}
transitioning builtin NonPrimitiveToPrimitive_Default(
implicit context: Context)(input: JSReceiver): JSPrimitive {
const exoticToPrimitive: JSAny = TryGetExoticToPrimitive(input)
otherwise return OrdinaryToPrimitive_Number(input);
return CallExoticToPrimitive(
input, exoticToPrimitive, DefaultStringConstant());
}
transitioning builtin NonPrimitiveToPrimitive_Number(implicit context: Context)(
input: JSReceiver): JSPrimitive {
const exoticToPrimitive: JSAny = TryGetExoticToPrimitive(input)
otherwise return OrdinaryToPrimitive_Number(input);
return CallExoticToPrimitive(
input, exoticToPrimitive, NumberStringConstant());
}
transitioning builtin NonPrimitiveToPrimitive_String(implicit context: Context)(
input: JSReceiver): JSPrimitive {
const exoticToPrimitive: JSAny = TryGetExoticToPrimitive(input)
otherwise return OrdinaryToPrimitive_String(input);
return CallExoticToPrimitive(
input, exoticToPrimitive, StringStringConstant());
}
// 7.1.1.1 OrdinaryToPrimitive ( O, hint )
transitioning macro TryToPrimitiveMethod(implicit context: Context)(
input: JSAny, name: String): JSPrimitive labels Continue {
const method: JSAny = GetProperty(input, name);
typeswitch (method) {
case (Callable): {
const value: JSAny = Call(context, method, input);
return Cast<JSPrimitive>(value) otherwise Continue;
}
case (JSAny): {
goto Continue;
}
}
}
transitioning builtin OrdinaryToPrimitive_Number(implicit context: Context)(
input: JSAny): JSPrimitive {
try {
return TryToPrimitiveMethod(input, ValueOfStringConstant())
otherwise String;
} label String {
return TryToPrimitiveMethod(input, ToStringStringConstant())
otherwise Throw;
} label Throw {
ThrowTypeError(MessageTemplate::kCannotConvertToPrimitive);
}
}
transitioning builtin OrdinaryToPrimitive_String(implicit context: Context)(
input: JSAny): JSPrimitive {
try {
return TryToPrimitiveMethod(input, ToStringStringConstant())
otherwise String;
} label String {
return TryToPrimitiveMethod(input, ValueOfStringConstant()) otherwise Throw;
} label Throw {
ThrowTypeError(MessageTemplate::kCannotConvertToPrimitive);
}
}
} // namespace conversion
......@@ -16,6 +16,8 @@ extern macro MinusInfinityStringConstant(): String;
const kAsciiZero: constexpr int32 = 48; // '0' (ascii)
const kAsciiLowerCaseA: constexpr int32 = 97; // 'a' (ascii)
extern macro NumberToString(Number): String;
transitioning macro ThisNumberValue(implicit context: Context)(
receiver: JSAny, method: constexpr string): Number {
return UnsafeCast<Number>(
......
......@@ -7299,6 +7299,12 @@ TNode<Number> CodeStubAssembler::ToLength_Inline(SloppyTNode<Context> context,
[=] { return CAST(CallBuiltin(Builtins::kToLength, context, input)); });
}
TNode<Object> CodeStubAssembler::OrdinaryToPrimitive(
TNode<Context> context, TNode<Object> input, OrdinaryToPrimitiveHint hint) {
Callable callable = CodeFactory::OrdinaryToPrimitive(isolate(), hint);
return CallStub(callable, context, input);
}
TNode<Uint32T> CodeStubAssembler::DecodeWord32(SloppyTNode<Word32T> word32,
uint32_t shift, uint32_t mask) {
DCHECK_EQ((mask >> shift) << shift, mask);
......
......@@ -168,7 +168,7 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(NoClosuresCellMap, no_closures_cell_map, NoClosuresCellMap) \
V(null_to_string, null_to_string, NullToString) \
V(NullValue, null_value, Null) \
V(number_string, number_string, numberString) \
V(number_string, number_string, NumberString) \
V(number_to_string, number_to_string, NumberToString) \
V(Object_string, Object_string, ObjectString) \
V(object_to_string, object_to_string, ObjectToString) \
......@@ -212,6 +212,8 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(SymbolMap, symbol_map, SymbolMap) \
V(TheHoleValue, the_hole_value, TheHole) \
V(then_string, then_string, ThenString) \
V(toString_string, toString_string, ToStringString) \
V(to_primitive_symbol, to_primitive_symbol, ToPrimitiveSymbol) \
V(to_string_tag_symbol, to_string_tag_symbol, ToStringTagSymbol) \
V(TransitionArrayMap, transition_array_map, TransitionArrayMap) \
V(TrueValue, true_value, True) \
......@@ -228,6 +230,7 @@ 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(valueOf_string, valueOf_string, ValueOfString) \
V(WeakFixedArrayMap, weak_fixed_array_map, WeakFixedArrayMap) \
V(zero_string, zero_string, ZeroString) \
TORQUE_INTERNAL_MAP_CSA_LIST(V)
......@@ -2847,6 +2850,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<Number> ToLength_Inline(SloppyTNode<Context> context,
SloppyTNode<Object> input);
TNode<Object> OrdinaryToPrimitive(TNode<Context> context, TNode<Object> input,
OrdinaryToPrimitiveHint hint);
// Returns a node that contains a decoded (unsigned!) value of a bit
// field |BitField| in |word32|. Returns result as an uint32 node.
template <typename BitField>
......
......@@ -36,6 +36,7 @@ extern enum NativeContextSlot extends intptr constexpr 'Context::Field' {
JS_ARRAY_PACKED_SMI_ELEMENTS_MAP_INDEX,
MATH_RANDOM_CACHE_INDEX,
MATH_RANDOM_INDEX_INDEX,
NUMBER_FUNCTION_INDEX,
PROXY_REVOCABLE_RESULT_MAP_INDEX,
REFLECT_APPLY_INDEX,
REGEXP_FUNCTION_INDEX,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment