Commit 3a1296a2 authored by franzih's avatar franzih Committed by Commit bot

[builtins] Object.prototype.toString() as TurboFan stub.

For angular.js on Speedometer, this results in 8.96%
speed up, i.e., the tests take on average 762ms
with this patch, 837ms without.

BUG= v8:5175

Review-Url: https://codereview.chromium.org/2134803002
Cr-Commit-Position: refs/heads/master@{#37827}
parent 4ee07936
......@@ -2482,7 +2482,7 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
Handle<JSFunction> to_string = InstallFunction(
container, "object_to_string", JS_OBJECT_TYPE, JSObject::kHeaderSize,
MaybeHandle<JSObject>(), Builtins::kObjectProtoToString);
to_string->shared()->DontAdaptArguments();
to_string->shared()->set_internal_formal_parameter_count(0);
to_string->shared()->set_length(0);
native_context->set_object_to_string(*to_string);
}
......
......@@ -6,7 +6,6 @@
#include "src/api-arguments.h"
#include "src/api-natives.h"
#include "src/api.h"
#include "src/base/ieee754.h"
#include "src/base/once.h"
#include "src/bootstrapper.h"
......@@ -389,6 +388,254 @@ void Builtins::Generate_ObjectHasOwnProperty(CodeStubAssembler* assembler) {
context, object, key));
}
namespace { // anonymous namespace for ObjectProtoToString()
void IsString(CodeStubAssembler* assembler, compiler::Node* object,
CodeStubAssembler::Label* if_string,
CodeStubAssembler::Label* if_notstring) {
typedef compiler::Node Node;
typedef CodeStubAssembler::Label Label;
Label if_notsmi(assembler);
assembler->Branch(assembler->WordIsSmi(object), if_notstring, &if_notsmi);
assembler->Bind(&if_notsmi);
{
Node* instance_type = assembler->LoadInstanceType(object);
assembler->Branch(
assembler->Int32LessThan(
instance_type, assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
if_string, if_notstring);
}
}
void ReturnToStringFormat(CodeStubAssembler* assembler, compiler::Node* context,
compiler::Node* string) {
typedef compiler::Node Node;
Node* lhs = assembler->HeapConstant(
assembler->factory()->NewStringFromStaticChars("[object "));
Node* rhs = assembler->HeapConstant(
assembler->factory()->NewStringFromStaticChars("]"));
Callable callable = CodeFactory::StringAdd(
assembler->isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
assembler->Return(assembler->CallStub(
callable, context, assembler->CallStub(callable, context, lhs, string),
rhs));
}
void ReturnIfPrimitive(CodeStubAssembler* assembler,
compiler::Node* instance_type,
CodeStubAssembler::Label* return_string,
CodeStubAssembler::Label* return_boolean,
CodeStubAssembler::Label* return_number) {
assembler->GotoIf(
assembler->Int32LessThan(instance_type,
assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
return_string);
assembler->GotoIf(assembler->Word32Equal(
instance_type, assembler->Int32Constant(ODDBALL_TYPE)),
return_boolean);
assembler->GotoIf(
assembler->Word32Equal(instance_type,
assembler->Int32Constant(HEAP_NUMBER_TYPE)),
return_number);
}
} // namespace
// ES6 section 19.1.3.6 Object.prototype.toString
void Builtins::Generate_ObjectProtoToString(CodeStubAssembler* assembler) {
typedef compiler::Node Node;
typedef CodeStubAssembler::Label Label;
typedef CodeStubAssembler::Variable Variable;
Label return_undefined(assembler, Label::kDeferred),
return_null(assembler, Label::kDeferred),
return_arguments(assembler, Label::kDeferred), return_array(assembler),
return_api(assembler, Label::kDeferred), return_object(assembler),
return_regexp(assembler), return_function(assembler),
return_error(assembler), return_date(assembler), return_string(assembler),
return_boolean(assembler), return_jsvalue(assembler),
return_jsproxy(assembler, Label::kDeferred), return_number(assembler);
Label if_isproxy(assembler, Label::kDeferred);
Label checkstringtag(assembler);
Label if_tostringtag(assembler), if_notostringtag(assembler);
Node* receiver = assembler->Parameter(0);
Node* context = assembler->Parameter(3);
assembler->GotoIf(
assembler->Word32Equal(receiver, assembler->UndefinedConstant()),
&return_undefined);
assembler->GotoIf(assembler->Word32Equal(receiver, assembler->NullConstant()),
&return_null);
assembler->GotoIf(assembler->WordIsSmi(receiver), &return_number);
Node* receiver_instance_type = assembler->LoadInstanceType(receiver);
ReturnIfPrimitive(assembler, receiver_instance_type, &return_string,
&return_boolean, &return_number);
// for proxies, check IsArray before getting @@toStringTag
Variable var_proxy_is_array(assembler, MachineRepresentation::kTagged);
var_proxy_is_array.Bind(assembler->BooleanConstant(false));
assembler->Branch(
assembler->Word32Equal(receiver_instance_type,
assembler->Int32Constant(JS_PROXY_TYPE)),
&if_isproxy, &checkstringtag);
assembler->Bind(&if_isproxy);
{
// This can throw
var_proxy_is_array.Bind(
assembler->CallRuntime(Runtime::kArrayIsArray, context, receiver));
assembler->Goto(&checkstringtag);
}
assembler->Bind(&checkstringtag);
{
Node* to_string_tag_symbol = assembler->HeapConstant(
assembler->isolate()->factory()->to_string_tag_symbol());
GetPropertyStub stub(assembler->isolate());
Callable get_property =
Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
Node* to_string_tag_value = assembler->CallStub(
get_property, context, receiver, to_string_tag_symbol);
IsString(assembler, to_string_tag_value, &if_tostringtag,
&if_notostringtag);
assembler->Bind(&if_tostringtag);
ReturnToStringFormat(assembler, context, to_string_tag_value);
}
assembler->Bind(&if_notostringtag);
{
size_t const kNumCases = 11;
Label* case_labels[kNumCases];
int32_t case_values[kNumCases];
case_labels[0] = &return_api;
case_values[0] = JS_API_OBJECT_TYPE;
case_labels[1] = &return_api;
case_values[1] = JS_SPECIAL_API_OBJECT_TYPE;
case_labels[2] = &return_arguments;
case_values[2] = JS_ARGUMENTS_TYPE;
case_labels[3] = &return_array;
case_values[3] = JS_ARRAY_TYPE;
case_labels[4] = &return_function;
case_values[4] = JS_BOUND_FUNCTION_TYPE;
case_labels[5] = &return_function;
case_values[5] = JS_FUNCTION_TYPE;
case_labels[6] = &return_error;
case_values[6] = JS_ERROR_TYPE;
case_labels[7] = &return_date;
case_values[7] = JS_DATE_TYPE;
case_labels[8] = &return_regexp;
case_values[8] = JS_REGEXP_TYPE;
case_labels[9] = &return_jsvalue;
case_values[9] = JS_VALUE_TYPE;
case_labels[10] = &return_jsproxy;
case_values[10] = JS_PROXY_TYPE;
assembler->Switch(receiver_instance_type, &return_object, case_values,
case_labels, arraysize(case_values));
assembler->Bind(&return_undefined);
assembler->Return(assembler->HeapConstant(
assembler->isolate()->factory()->undefined_to_string()));
assembler->Bind(&return_null);
assembler->Return(assembler->HeapConstant(
assembler->isolate()->factory()->null_to_string()));
assembler->Bind(&return_number);
assembler->Return(assembler->HeapConstant(
assembler->isolate()->factory()->number_to_string()));
assembler->Bind(&return_string);
assembler->Return(assembler->HeapConstant(
assembler->isolate()->factory()->string_to_string()));
assembler->Bind(&return_boolean);
assembler->Return(assembler->HeapConstant(
assembler->isolate()->factory()->boolean_to_string()));
assembler->Bind(&return_arguments);
assembler->Return(assembler->HeapConstant(
assembler->isolate()->factory()->arguments_to_string()));
assembler->Bind(&return_array);
assembler->Return(assembler->HeapConstant(
assembler->isolate()->factory()->array_to_string()));
assembler->Bind(&return_function);
assembler->Return(assembler->HeapConstant(
assembler->isolate()->factory()->function_to_string()));
assembler->Bind(&return_error);
assembler->Return(assembler->HeapConstant(
assembler->isolate()->factory()->error_to_string()));
assembler->Bind(&return_date);
assembler->Return(assembler->HeapConstant(
assembler->isolate()->factory()->date_to_string()));
assembler->Bind(&return_regexp);
assembler->Return(assembler->HeapConstant(
assembler->isolate()->factory()->regexp_to_string()));
assembler->Bind(&return_api);
{
Node* class_name =
assembler->CallRuntime(Runtime::kClassOf, context, receiver);
ReturnToStringFormat(assembler, context, class_name);
}
assembler->Bind(&return_jsvalue);
{
Node* value = assembler->LoadJSValueValue(receiver);
assembler->GotoIf(assembler->WordIsSmi(value), &return_number);
ReturnIfPrimitive(assembler, assembler->LoadInstanceType(value),
&return_string, &return_boolean, &return_number);
assembler->Goto(&return_object);
}
assembler->Bind(&return_jsproxy);
{
assembler->GotoIf(assembler->WordEqual(var_proxy_is_array.value(),
assembler->BooleanConstant(true)),
&return_array);
Node* map = assembler->LoadMap(receiver);
// Return object if the proxy {receiver} is not callable.
assembler->Branch(
assembler->Word32Equal(
assembler->Word32And(
assembler->LoadMapBitField(map),
assembler->Int32Constant(1 << Map::kIsCallable)),
assembler->Int32Constant(0)),
&return_object, &return_function);
}
// Default
assembler->Bind(&return_object);
assembler->Return(assembler->HeapConstant(
assembler->isolate()->factory()->object_to_string()));
}
}
namespace {
Object* DoArrayPush(Isolate* isolate, BuiltinArguments args) {
......@@ -4893,14 +5140,6 @@ BUILTIN(ObjectPrototypePropertyIsEnumerable) {
return isolate->heap()->ToBoolean((maybe.FromJust() & DONT_ENUM) == 0);
}
// ES6 section 19.1.3.6 Object.prototype.toString
BUILTIN(ObjectProtoToString) {
HandleScope scope(isolate);
Handle<Object> object = args.at<Object>(0);
RETURN_RESULT_OR_FAILURE(isolate,
Object::ObjectProtoToString(isolate, object));
}
// -----------------------------------------------------------------------------
// ES6 section 19.4 Symbol Objects
......
......@@ -331,8 +331,8 @@ namespace internal {
CPP(ObjectLookupGetter) \
CPP(ObjectLookupSetter) \
CPP(ObjectPreventExtensions) \
TFJ(ObjectProtoToString, 1) \
CPP(ObjectPrototypePropertyIsEnumerable) \
CPP(ObjectProtoToString) \
CPP(ObjectSeal) \
CPP(ObjectValues) \
/* Proxy */ \
......@@ -720,6 +720,9 @@ class Builtins {
// ES6 section 19.1.3.2 Object.prototype.hasOwnProperty
static void Generate_ObjectHasOwnProperty(CodeStubAssembler* assembler);
// ES6 section 19.1.3.6 Object.prototype.toString ()
static void Generate_ObjectProtoToString(CodeStubAssembler* assembler);
// ES6 section 22.1.2.2 Array.isArray
static void Generate_ArrayIsArray(CodeStubAssembler* assembler);
......
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