Port ToString to Torque
Change-Id: I9480650b23da4f5aa38a0634c1a7662bf88189d7 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1551407 Reviewed-by: Georg Neis <neis@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Commit-Queue: Shiyu Zhang <shiyu.zhang@intel.com> Cr-Commit-Position: refs/heads/master@{#60952}
This commit is contained in:
parent
e79197b831
commit
9320f3a1b0
@ -811,6 +811,8 @@ const kProxyHandlerOrTargetRevoked: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kProxyHandlerOrTargetRevoked';
|
||||
const kConstructorNotFunction: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kConstructorNotFunction';
|
||||
const kSymbolToString: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kSymbolToString';
|
||||
|
||||
const kMaxArrayIndex:
|
||||
constexpr uint32 generates 'JSArray::kMaxArrayIndex';
|
||||
@ -1138,7 +1140,12 @@ extern macro ToObject_Inline(Context, Object): JSReceiver;
|
||||
extern macro IsNullOrUndefined(Object): bool;
|
||||
extern macro IsTheHole(Object): bool;
|
||||
extern macro IsString(HeapObject): bool;
|
||||
extern builtin ToString(Context, Object): String;
|
||||
transitioning builtin ToString(context: Context, o: Object): String {
|
||||
return ToStringImpl(context, o);
|
||||
}
|
||||
extern transitioning runtime ToStringRT(Context, Object): String;
|
||||
extern transitioning builtin NonPrimitiveToPrimitive_String(
|
||||
Context, Object): Object;
|
||||
|
||||
extern transitioning runtime NormalizeElements(Context, JSObject);
|
||||
extern transitioning runtime TransitionElementsKindWithKind(
|
||||
@ -1521,6 +1528,18 @@ Cast<String>(o: HeapObject): String
|
||||
return HeapObjectToString(o) otherwise CastError;
|
||||
}
|
||||
|
||||
Cast<Oddball>(o: HeapObject): Oddball
|
||||
labels CastError {
|
||||
if (IsOddball(o)) return %RawDownCast<Oddball>(o);
|
||||
goto CastError;
|
||||
}
|
||||
|
||||
Cast<Symbol>(o: HeapObject): Symbol
|
||||
labels CastError {
|
||||
if (IsSymbol(o)) return %RawDownCast<Symbol>(o);
|
||||
goto CastError;
|
||||
}
|
||||
|
||||
Cast<DirectString>(o: HeapObject): DirectString
|
||||
labels CastError {
|
||||
return TaggedToDirectString(o) otherwise CastError;
|
||||
@ -2283,6 +2302,8 @@ extern macro IsHeapNumber(HeapObject): bool;
|
||||
extern macro IsFixedArray(HeapObject): bool;
|
||||
extern macro IsNumber(Object): bool;
|
||||
extern macro IsNumberNormalized(Number): bool;
|
||||
extern macro IsOddball(HeapObject): bool;
|
||||
extern macro IsSymbol(HeapObject): bool;
|
||||
extern macro IsJSArrayMap(Map): bool;
|
||||
extern macro IsExtensibleMap(Map): bool;
|
||||
extern macro IsCustomElementsReceiverInstanceType(int32): bool;
|
||||
@ -2455,3 +2476,31 @@ transitioning builtin FastCreateDataProperty(implicit context: Context)(
|
||||
}
|
||||
return Undefined;
|
||||
}
|
||||
|
||||
transitioning macro ToStringImpl(context: Context, o: Object): String {
|
||||
let result: Object = o;
|
||||
while (true) {
|
||||
typeswitch (result) {
|
||||
case (str: String): {
|
||||
return str;
|
||||
}
|
||||
case (num: Number): {
|
||||
return NumberToString(num);
|
||||
}
|
||||
case (oddball: Oddball): {
|
||||
return oddball.to_string;
|
||||
}
|
||||
case (Symbol): {
|
||||
ThrowTypeError(kSymbolToString);
|
||||
}
|
||||
case (JSReceiver): {
|
||||
result = NonPrimitiveToPrimitive_String(context, result);
|
||||
continue;
|
||||
}
|
||||
case (Object): {
|
||||
return ToStringRT(context, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ToStringRT(context, o);
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ TF_BUILTIN(ToName, CodeStubAssembler) {
|
||||
{
|
||||
// We don't have a fast-path for BigInt currently, so just
|
||||
// tail call to the %ToString runtime function here for now.
|
||||
TailCallRuntime(Runtime::kToString, context, input);
|
||||
TailCallRuntime(Runtime::kToStringRT, context, input);
|
||||
}
|
||||
|
||||
BIND(&if_inputisname);
|
||||
@ -211,14 +211,6 @@ TF_BUILTIN(NumberToString, CodeStubAssembler) {
|
||||
Return(NumberToString(input));
|
||||
}
|
||||
|
||||
// ES section #sec-tostring
|
||||
TF_BUILTIN(ToString, CodeStubAssembler) {
|
||||
Node* context = Parameter(Descriptor::kContext);
|
||||
Node* input = Parameter(Descriptor::kArgument);
|
||||
|
||||
Return(ToString(context, input));
|
||||
}
|
||||
|
||||
// 7.1.1.1 OrdinaryToPrimitive ( O, hint )
|
||||
void ConversionBuiltinsAssembler::Generate_OrdinaryToPrimitive(
|
||||
Node* context, Node* input, OrdinaryToPrimitiveHint hint) {
|
||||
|
@ -202,7 +202,6 @@ namespace internal {
|
||||
TFC(ToNumberConvertBigInt, TypeConversion) \
|
||||
TFC(ToNumeric, TypeConversion) \
|
||||
TFC(NumberToString, TypeConversion) \
|
||||
TFC(ToString, TypeConversion) \
|
||||
TFC(ToInteger, TypeConversion) \
|
||||
TFC(ToInteger_TruncateMinusZero, TypeConversion) \
|
||||
TFC(ToLength, TypeConversion) \
|
||||
|
@ -302,7 +302,8 @@ TF_BUILTIN(StringAdd_ConvertLeft, StringBuiltinsAssembler) {
|
||||
Node* context = Parameter(Descriptor::kContext);
|
||||
// TODO(danno): The ToString and JSReceiverToPrimitive below could be
|
||||
// combined to avoid duplicate smi and instance type checks.
|
||||
left = ToString(context, JSReceiverToPrimitive(context, left));
|
||||
left =
|
||||
ToStringImpl(CAST(context), CAST(JSReceiverToPrimitive(context, left)));
|
||||
TailCallBuiltin(Builtins::kStringAdd_CheckNone, context, left, right);
|
||||
}
|
||||
|
||||
@ -312,7 +313,8 @@ TF_BUILTIN(StringAdd_ConvertRight, StringBuiltinsAssembler) {
|
||||
Node* context = Parameter(Descriptor::kContext);
|
||||
// TODO(danno): The ToString and JSReceiverToPrimitive below could be
|
||||
// combined to avoid duplicate smi and instance type checks.
|
||||
right = ToString(context, JSReceiverToPrimitive(context, right));
|
||||
right =
|
||||
ToStringImpl(CAST(context), CAST(JSReceiverToPrimitive(context, right)));
|
||||
TailCallBuiltin(Builtins::kStringAdd_CheckNone, context, left, right);
|
||||
}
|
||||
|
||||
|
@ -7818,71 +7818,6 @@ TNode<Number> CodeStubAssembler::ToUint32(SloppyTNode<Context> context,
|
||||
return CAST(var_result.value());
|
||||
}
|
||||
|
||||
TNode<String> CodeStubAssembler::ToString(SloppyTNode<Context> context,
|
||||
SloppyTNode<Object> input) {
|
||||
TVARIABLE(Object, result, input);
|
||||
Label loop(this, &result), done(this);
|
||||
Goto(&loop);
|
||||
BIND(&loop);
|
||||
{
|
||||
// Load the current {input} value.
|
||||
TNode<Object> input = result.value();
|
||||
|
||||
// Dispatch based on the type of the {input.}
|
||||
Label if_inputisnumber(this), if_inputisoddball(this),
|
||||
if_inputissymbol(this), if_inputisreceiver(this, Label::kDeferred),
|
||||
runtime(this, Label::kDeferred);
|
||||
GotoIf(TaggedIsSmi(input), &if_inputisnumber);
|
||||
TNode<Int32T> input_instance_type = LoadInstanceType(CAST(input));
|
||||
GotoIf(IsStringInstanceType(input_instance_type), &done);
|
||||
GotoIf(IsJSReceiverInstanceType(input_instance_type), &if_inputisreceiver);
|
||||
GotoIf(IsHeapNumberInstanceType(input_instance_type), &if_inputisnumber);
|
||||
GotoIf(IsOddballInstanceType(input_instance_type), &if_inputisoddball);
|
||||
Branch(IsSymbolInstanceType(input_instance_type), &if_inputissymbol,
|
||||
&runtime);
|
||||
|
||||
BIND(&if_inputisnumber);
|
||||
{
|
||||
// Convert the Number {input} to a String.
|
||||
TNode<Number> number_input = CAST(input);
|
||||
result = NumberToString(number_input);
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&if_inputisoddball);
|
||||
{
|
||||
// Just return the {input}'s string representation.
|
||||
result = LoadObjectField(CAST(input), Oddball::kToStringOffset);
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&if_inputissymbol);
|
||||
{
|
||||
// Throw a type error when {input} is a Symbol.
|
||||
ThrowTypeError(context, MessageTemplate::kSymbolToString);
|
||||
}
|
||||
|
||||
BIND(&if_inputisreceiver);
|
||||
{
|
||||
// Convert the JSReceiver {input} to a primitive first,
|
||||
// and then run the loop again with the new {input},
|
||||
// which is then a primitive value.
|
||||
result = CallBuiltin(Builtins::kNonPrimitiveToPrimitive_String, context,
|
||||
input);
|
||||
Goto(&loop);
|
||||
}
|
||||
|
||||
BIND(&runtime);
|
||||
{
|
||||
result = CallRuntime(Runtime::kToString, context, input);
|
||||
Goto(&done);
|
||||
}
|
||||
}
|
||||
|
||||
BIND(&done);
|
||||
return CAST(result.value());
|
||||
}
|
||||
|
||||
TNode<String> CodeStubAssembler::ToString_Inline(SloppyTNode<Context> context,
|
||||
SloppyTNode<Object> input) {
|
||||
VARIABLE(var_result, MachineRepresentation::kTagged, input);
|
||||
|
@ -2399,8 +2399,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
SloppyTNode<Object> input);
|
||||
|
||||
// Convert any object to a String.
|
||||
TNode<String> ToString(SloppyTNode<Context> context,
|
||||
SloppyTNode<Object> input);
|
||||
TNode<String> ToString_Inline(SloppyTNode<Context> context,
|
||||
SloppyTNode<Object> input);
|
||||
|
||||
|
@ -72,7 +72,7 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
|
||||
return ReduceToLength(node);
|
||||
case Runtime::kInlineToObject:
|
||||
return ReduceToObject(node);
|
||||
case Runtime::kInlineToString:
|
||||
case Runtime::kInlineToStringRT:
|
||||
return ReduceToString(node);
|
||||
case Runtime::kInlineCall:
|
||||
return ReduceCall(node);
|
||||
|
@ -1816,7 +1816,7 @@ Type Typer::Visitor::TypeJSCallRuntime(Node* node) {
|
||||
return TypeUnaryOp(node, ToNumber);
|
||||
case Runtime::kInlineToObject:
|
||||
return TypeUnaryOp(node, ToObject);
|
||||
case Runtime::kInlineToString:
|
||||
case Runtime::kInlineToStringRT:
|
||||
return TypeUnaryOp(node, ToString);
|
||||
case Runtime::kHasInPrototypeChain:
|
||||
return Type::Boolean();
|
||||
|
@ -248,7 +248,7 @@ bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
|
||||
V(ToLength) \
|
||||
V(ToNumber) \
|
||||
V(ToObject) \
|
||||
V(ToString) \
|
||||
V(ToStringRT) \
|
||||
/* Type checks */ \
|
||||
V(IsArray) \
|
||||
V(IsFunction) \
|
||||
|
@ -207,7 +207,7 @@ Node* IntrinsicsGenerator::HasProperty(
|
||||
args, context, Builtins::CallableFor(isolate(), Builtins::kHasProperty));
|
||||
}
|
||||
|
||||
Node* IntrinsicsGenerator::ToString(
|
||||
Node* IntrinsicsGenerator::ToStringRT(
|
||||
const InterpreterAssembler::RegListNodePair& args, Node* context) {
|
||||
return IntrinsicAsStubCall(
|
||||
args, context, Builtins::CallableFor(isolate(), Builtins::kToString));
|
||||
|
@ -36,7 +36,7 @@ namespace interpreter {
|
||||
V(IsJSReceiver, is_js_receiver, 1) \
|
||||
V(IsSmi, is_smi, 1) \
|
||||
V(IsTypedArray, is_typed_array, 1) \
|
||||
V(ToString, to_string, 1) \
|
||||
V(ToStringRT, to_string, 1) \
|
||||
V(ToLength, to_length, 1) \
|
||||
V(ToObject, to_object, 1)
|
||||
|
||||
|
@ -631,7 +631,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
|
||||
if (expr->IsStringLiteral()) return expr;
|
||||
ScopedPtrList<Expression> args(pointer_buffer());
|
||||
args.Add(expr);
|
||||
return factory()->NewCallRuntime(Runtime::kInlineToString, args,
|
||||
return factory()->NewCallRuntime(Runtime::kInlineToStringRT, args,
|
||||
expr->position());
|
||||
}
|
||||
|
||||
|
@ -1045,15 +1045,13 @@ RUNTIME_FUNCTION(Runtime_ToLength) {
|
||||
RETURN_RESULT_OR_FAILURE(isolate, Object::ToLength(isolate, input));
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ToString) {
|
||||
RUNTIME_FUNCTION(Runtime_ToStringRT) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
|
||||
RETURN_RESULT_OR_FAILURE(isolate, Object::ToString(isolate, input));
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ToName) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
|
@ -326,7 +326,7 @@ namespace internal {
|
||||
I(ToNumber, 1, 1) \
|
||||
F(ToNumeric, 1, 1) \
|
||||
I(ToObject, 1, 1) \
|
||||
I(ToString, 1, 1) \
|
||||
I(ToStringRT, 1, 1) \
|
||||
F(TryMigrateInstance, 1, 1)
|
||||
|
||||
#define FOR_EACH_INTRINSIC_OPERATORS(F, I) \
|
||||
|
@ -85,9 +85,8 @@ void ImplementationVisitor::BeginNamespaceFile(Namespace* nspace) {
|
||||
<< "\n";
|
||||
|
||||
header << "class ";
|
||||
if (nspace->IsTestNamespace()) {
|
||||
header << "V8_EXPORT_PRIVATE ";
|
||||
}
|
||||
// TODO(sigurds): Decide which assemblers we should export for testing.
|
||||
header << "V8_EXPORT_PRIVATE ";
|
||||
header << nspace->ExternalName() << " {\n";
|
||||
header << " public:\n";
|
||||
header << " explicit " << nspace->ExternalName()
|
||||
|
@ -367,7 +367,8 @@ TEST(ToString) {
|
||||
const int kNumParams = 1;
|
||||
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
||||
CodeStubAssembler m(asm_tester.state());
|
||||
m.Return(m.ToString(m.Parameter(kNumParams + 2), m.Parameter(0)));
|
||||
m.Return(m.ToStringImpl(m.CAST(m.Parameter(kNumParams + 2)),
|
||||
m.CAST(m.Parameter(0))));
|
||||
|
||||
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
||||
|
||||
|
@ -4,51 +4,51 @@
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
assertEquals("1", %ToString(1));
|
||||
assertEquals("1", %_ToString(1));
|
||||
assertEquals("1", %ToStringRT(1));
|
||||
assertEquals("1", %_ToStringRT(1));
|
||||
|
||||
assertEquals("0.5", %ToString(.5));
|
||||
assertEquals("0.5", %_ToString(.5));
|
||||
assertEquals("0.5", %ToStringRT(.5));
|
||||
assertEquals("0.5", %_ToStringRT(.5));
|
||||
|
||||
assertEquals("null", %ToString(null));
|
||||
assertEquals("null", %_ToString(null));
|
||||
assertEquals("null", %ToStringRT(null));
|
||||
assertEquals("null", %_ToStringRT(null));
|
||||
|
||||
assertEquals("true", %ToString(true));
|
||||
assertEquals("true", %_ToString(true));
|
||||
assertEquals("true", %ToStringRT(true));
|
||||
assertEquals("true", %_ToStringRT(true));
|
||||
|
||||
assertEquals("false", %ToString(false));
|
||||
assertEquals("false", %_ToString(false));
|
||||
assertEquals("false", %ToStringRT(false));
|
||||
assertEquals("false", %_ToStringRT(false));
|
||||
|
||||
assertEquals("undefined", %ToString(undefined));
|
||||
assertEquals("undefined", %_ToString(undefined));
|
||||
assertEquals("undefined", %ToStringRT(undefined));
|
||||
assertEquals("undefined", %_ToStringRT(undefined));
|
||||
|
||||
assertEquals("random text", %ToString("random text"));
|
||||
assertEquals("random text", %_ToString("random text"));
|
||||
assertEquals("random text", %ToStringRT("random text"));
|
||||
assertEquals("random text", %_ToStringRT("random text"));
|
||||
|
||||
assertThrows(function() { %ToString(Symbol.toPrimitive) }, TypeError);
|
||||
assertThrows(function() { %_ToString(Symbol.toPrimitive) }, TypeError);
|
||||
assertThrows(function() { %ToStringRT(Symbol.toPrimitive) }, TypeError);
|
||||
assertThrows(function() { %_ToStringRT(Symbol.toPrimitive) }, TypeError);
|
||||
|
||||
var a = { toString: function() { return "xyz" }};
|
||||
assertEquals("xyz", %ToString(a));
|
||||
assertEquals("xyz", %_ToString(a));
|
||||
assertEquals("xyz", %ToStringRT(a));
|
||||
assertEquals("xyz", %_ToStringRT(a));
|
||||
|
||||
var b = { valueOf: function() { return 42 }};
|
||||
assertEquals("[object Object]", %ToString(b));
|
||||
assertEquals("[object Object]", %_ToString(b));
|
||||
assertEquals("[object Object]", %ToStringRT(b));
|
||||
assertEquals("[object Object]", %_ToStringRT(b));
|
||||
|
||||
var c = {
|
||||
toString: function() { return "x"},
|
||||
valueOf: function() { return 123 }
|
||||
};
|
||||
assertEquals("x", %ToString(c));
|
||||
assertEquals("x", %_ToString(c));
|
||||
assertEquals("x", %ToStringRT(c));
|
||||
assertEquals("x", %_ToStringRT(c));
|
||||
|
||||
var d = {
|
||||
[Symbol.toPrimitive]: function(hint) { return hint }
|
||||
};
|
||||
assertEquals("string", %ToString(d));
|
||||
assertEquals("string", %_ToString(d));
|
||||
assertEquals("string", %ToStringRT(d));
|
||||
assertEquals("string", %_ToStringRT(d));
|
||||
|
||||
var e = new Date(0);
|
||||
assertEquals(e.toString(), %ToString(e));
|
||||
assertEquals(e.toString(), %_ToString(e));
|
||||
assertEquals(e.toString(), %ToStringRT(e));
|
||||
assertEquals(e.toString(), %_ToStringRT(e));
|
||||
|
Loading…
Reference in New Issue
Block a user