[builtins] Add EmitFastNewObject

This refactors the logic from within the FastNewObject TF_BUILTIN to a
helper method which can be reused in other assemblers. This saves the
overhead of setting up the stub and calling into it.

A wrapper method is created for functions that don't need to tail call
into the runtime.

PromiseBuiltinsAssembler and RegexpBuiltinsAssembler are refactored to
use EmitFastNewObject.

Review-Url: https://codereview.chromium.org/2607233002
Cr-Commit-Position: refs/heads/master@{#42000}
This commit is contained in:
gsathya 2016-12-30 02:29:39 -08:00 committed by Commit bot
parent 1542a47f59
commit 2077b314d5
4 changed files with 54 additions and 17 deletions

View File

@ -161,30 +161,57 @@ TF_BUILTIN(FastNewObject, ConstructorBuiltinsAssembler) {
Node* target = Parameter(Descriptor::kTarget); Node* target = Parameter(Descriptor::kTarget);
Node* new_target = Parameter(Descriptor::kNewTarget); Node* new_target = Parameter(Descriptor::kNewTarget);
Label call_runtime(this);
Node* result = EmitFastNewObject(context, target, new_target, &call_runtime);
Return(result);
Bind(&call_runtime);
TailCallRuntime(Runtime::kNewObject, context, target, new_target);
}
Node* ConstructorBuiltinsAssembler::EmitFastNewObject(Node* context,
Node* target,
Node* new_target) {
Variable var_obj(this, MachineRepresentation::kTagged);
Label call_runtime(this), end(this);
Node* result = EmitFastNewObject(context, target, new_target, &call_runtime);
var_obj.Bind(result);
Goto(&end);
Bind(&call_runtime);
var_obj.Bind(CallRuntime(Runtime::kNewObject, context, target, new_target));
Goto(&end);
Bind(&end);
return var_obj.value();
}
Node* ConstructorBuiltinsAssembler::EmitFastNewObject(
Node* context, Node* target, Node* new_target,
CodeAssemblerLabel* call_runtime) {
CSA_ASSERT(this, HasInstanceType(target, JS_FUNCTION_TYPE)); CSA_ASSERT(this, HasInstanceType(target, JS_FUNCTION_TYPE));
CSA_ASSERT(this, IsJSReceiver(new_target)); CSA_ASSERT(this, IsJSReceiver(new_target));
// Verify that the new target is a JSFunction. // Verify that the new target is a JSFunction.
Label runtime(this), fast(this); Label fast(this), end(this);
GotoIf(HasInstanceType(new_target, JS_FUNCTION_TYPE), &fast); GotoIf(HasInstanceType(new_target, JS_FUNCTION_TYPE), &fast);
Goto(&runtime); Goto(call_runtime);
Bind(&runtime);
TailCallRuntime(Runtime::kNewObject, context, target, new_target);
Bind(&fast); Bind(&fast);
// Load the initial map and verify that it's in fact a map. // Load the initial map and verify that it's in fact a map.
Node* initial_map = Node* initial_map =
LoadObjectField(new_target, JSFunction::kPrototypeOrInitialMapOffset); LoadObjectField(new_target, JSFunction::kPrototypeOrInitialMapOffset);
GotoIf(TaggedIsSmi(initial_map), &runtime); GotoIf(TaggedIsSmi(initial_map), call_runtime);
GotoIf(DoesntHaveInstanceType(initial_map, MAP_TYPE), &runtime); GotoIf(DoesntHaveInstanceType(initial_map, MAP_TYPE), call_runtime);
// Fall back to runtime if the target differs from the new target's // Fall back to runtime if the target differs from the new target's
// initial map constructor. // initial map constructor.
Node* new_target_constructor = Node* new_target_constructor =
LoadObjectField(initial_map, Map::kConstructorOrBackPointerOffset); LoadObjectField(initial_map, Map::kConstructorOrBackPointerOffset);
GotoIf(WordNotEqual(target, new_target_constructor), &runtime); GotoIf(WordNotEqual(target, new_target_constructor), call_runtime);
Node* instance_size_words = ChangeUint32ToWord(LoadObjectField( Node* instance_size_words = ChangeUint32ToWord(LoadObjectField(
initial_map, Map::kInstanceSizeOffset, MachineType::Uint8())); initial_map, Map::kInstanceSizeOffset, MachineType::Uint8()));
@ -214,7 +241,7 @@ TF_BUILTIN(FastNewObject, ConstructorBuiltinsAssembler) {
Comment("no slack tracking"); Comment("no slack tracking");
InitializeFieldsWithRoot(object, IntPtrConstant(JSObject::kHeaderSize), InitializeFieldsWithRoot(object, IntPtrConstant(JSObject::kHeaderSize),
instance_size, Heap::kUndefinedValueRootIndex); instance_size, Heap::kUndefinedValueRootIndex);
Return(object); Goto(&end);
} }
{ {
@ -243,7 +270,7 @@ TF_BUILTIN(FastNewObject, ConstructorBuiltinsAssembler) {
Comment("initialize undefined fields (no finalize)"); Comment("initialize undefined fields (no finalize)");
InitializeFieldsWithRoot(object, IntPtrConstant(JSObject::kHeaderSize), InitializeFieldsWithRoot(object, IntPtrConstant(JSObject::kHeaderSize),
used_size, Heap::kUndefinedValueRootIndex); used_size, Heap::kUndefinedValueRootIndex);
Return(object); Goto(&end);
} }
{ {
@ -265,8 +292,11 @@ TF_BUILTIN(FastNewObject, ConstructorBuiltinsAssembler) {
used_size, Heap::kUndefinedValueRootIndex); used_size, Heap::kUndefinedValueRootIndex);
CallRuntime(Runtime::kFinalizeInstanceSize, context, initial_map); CallRuntime(Runtime::kFinalizeInstanceSize, context, initial_map);
Return(object); Goto(&end);
} }
Bind(&end);
return object;
} }
Node* ConstructorBuiltinsAssembler::EmitFastNewFunctionContext( Node* ConstructorBuiltinsAssembler::EmitFastNewFunctionContext(

View File

@ -44,6 +44,11 @@ class ConstructorBuiltinsAssembler : public CodeStubAssembler {
Node* properties_count); Node* properties_count);
void CreateFastCloneShallowObjectBuiltin(int properties_count); void CreateFastCloneShallowObjectBuiltin(int properties_count);
Node* EmitFastNewObject(Node* context, Node* target, Node* new_target);
Node* EmitFastNewObject(Node* context, Node* target, Node* new_target,
CodeAssemblerLabel* call_runtime);
private: private:
static const int kMaximumSlots = 0x8000; static const int kMaximumSlots = 0x8000;
static const int kSmallMaximumSlots = 10; static const int kSmallMaximumSlots = 10;

View File

@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "src/builtins/builtins-promise.h" #include "src/builtins/builtins-promise.h"
#include "src/builtins/builtins-constructor.h"
#include "src/builtins/builtins-utils.h" #include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h" #include "src/builtins/builtins.h"
#include "src/code-factory.h" #include "src/code-factory.h"
@ -742,9 +743,9 @@ TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) {
Bind(&if_targetismodified); Bind(&if_targetismodified);
{ {
Callable fast_new_object_stub = CodeFactory::FastNewObject(isolate); ConstructorBuiltinsAssembler constructor_assembler(this->state());
Node* const instance = Node* const instance = constructor_assembler.EmitFastNewObject(
CallStub(fast_new_object_stub, context, promise_fun, new_target); context, promise_fun, new_target);
var_result.Bind(instance); var_result.Bind(instance);
Goto(&init); Goto(&init);

View File

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "src/builtins/builtins-constructor.h"
#include "src/builtins/builtins-utils.h" #include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h" #include "src/builtins/builtins.h"
#include "src/code-factory.h" #include "src/code-factory.h"
@ -786,9 +787,9 @@ TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) {
Bind(&allocate_generic); Bind(&allocate_generic);
{ {
Callable fastnewobject_callable = CodeFactory::FastNewObject(isolate); ConstructorBuiltinsAssembler constructor_assembler(this->state());
Node* const regexp = CallStub(fastnewobject_callable, context, Node* const regexp = constructor_assembler.EmitFastNewObject(
regexp_function, var_new_target.value()); context, regexp_function, var_new_target.value());
var_regexp.Bind(regexp); var_regexp.Bind(regexp);
Goto(&next); Goto(&next);
} }