Commit 93d1508d authored by Shiyu Zhang's avatar Shiyu Zhang Committed by Commit Bot

[builtins] Reimplement ToString as CSA to optimize performance

Currently, if input types are not string or number, ToString builtin
will fall into runtime and a loop of ToPrimitive and type-checks is
done in runtime, which is slow.

This CL reimplements ToString to add support for that ToPrimitive and
type-checks loop in CSA instead of runtime to improve performance. This
will benefit Array.prototype.toString/join a lot when the array elements
are objects.

This Cl improves the performance of Speedometer2.0 EmberJS-Debug case
by ~14% on Atom.

Change-Id: I27c2669097be1e542e30119cdffcf79c0d16a0eb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1498698
Commit-Queue: Shiyu Zhang <shiyu.zhang@intel.com>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60144}
parent ac8e98e4
......@@ -7752,36 +7752,63 @@ TNode<Number> CodeStubAssembler::ToUint32(SloppyTNode<Context> context,
TNode<String> CodeStubAssembler::ToString(SloppyTNode<Context> context,
SloppyTNode<Object> input) {
Label is_number(this);
Label runtime(this, Label::kDeferred), done(this);
VARIABLE(result, MachineRepresentation::kTagged);
GotoIf(TaggedIsSmi(input), &is_number);
TNode<Map> input_map = LoadMap(CAST(input));
TNode<Int32T> input_instance_type = LoadMapInstanceType(input_map);
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);
result.Bind(input);
GotoIf(IsStringInstanceType(input_instance_type), &done);
BIND(&if_inputisnumber);
{
// Convert the Number {input} to a String.
TNode<Number> number_input = CAST(input);
result = NumberToString(number_input);
Goto(&done);
}
Label not_heap_number(this);
Branch(IsHeapNumberMap(input_map), &is_number, &not_heap_number);
BIND(&if_inputisoddball);
{
// Just return the {input}'s string representation.
result = LoadObjectField(CAST(input), Oddball::kToStringOffset);
Goto(&done);
}
BIND(&is_number);
TNode<Number> number_input = CAST(input);
result.Bind(NumberToString(number_input));
Goto(&done);
BIND(&if_inputissymbol);
{
// Throw a type error when {input} is a Symbol.
ThrowTypeError(context, MessageTemplate::kSymbolToString);
}
BIND(&not_heap_number);
{
GotoIfNot(InstanceTypeEqual(input_instance_type, ODDBALL_TYPE), &runtime);
result.Bind(LoadObjectField(CAST(input), Oddball::kToStringOffset));
Goto(&done);
}
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.Bind(CallRuntime(Runtime::kToString, context, input));
Goto(&done);
BIND(&runtime);
{
result = CallRuntime(Runtime::kToString, context, input);
Goto(&done);
}
}
BIND(&done);
......
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