[turbofan] Use inline allocation for closures.
This changes closure creation to lower to inline allocations when possible instead of going through the FastNewClosureStub. It allows us to leverage all advantages of inline allocations on closures. Note that it is only safe to embed the raw entry point of the compile lazy stub into the code, because that stub is immortal and immovable. R=mvstanton@chromium.org Review URL: https://codereview.chromium.org/1573153002 Cr-Commit-Position: refs/heads/master@{#35499}
This commit is contained in:
parent
290ee88f63
commit
43c7c76f1d
@ -60,6 +60,14 @@ FieldAccess AccessBuilder::ForJSObjectInObjectProperty(Handle<Map> map,
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
FieldAccess AccessBuilder::ForJSFunctionPrototypeOrInitialMap() {
|
||||
FieldAccess access = {kTaggedBase, JSFunction::kPrototypeOrInitialMapOffset,
|
||||
MaybeHandle<Name>(), Type::Any(),
|
||||
MachineType::AnyTagged()};
|
||||
return access;
|
||||
}
|
||||
|
||||
// static
|
||||
FieldAccess AccessBuilder::ForJSFunctionContext() {
|
||||
FieldAccess access = {kTaggedBase, JSFunction::kContextOffset,
|
||||
@ -77,6 +85,29 @@ FieldAccess AccessBuilder::ForJSFunctionSharedFunctionInfo() {
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
FieldAccess AccessBuilder::ForJSFunctionLiterals() {
|
||||
FieldAccess access = {kTaggedBase, JSFunction::kLiteralsOffset,
|
||||
Handle<Name>(), Type::Internal(),
|
||||
MachineType::AnyTagged()};
|
||||
return access;
|
||||
}
|
||||
|
||||
// static
|
||||
FieldAccess AccessBuilder::ForJSFunctionCodeEntry() {
|
||||
FieldAccess access = {kTaggedBase, JSFunction::kCodeEntryOffset,
|
||||
Handle<Name>(), Type::UntaggedPointer(),
|
||||
MachineType::Pointer()};
|
||||
return access;
|
||||
}
|
||||
|
||||
// static
|
||||
FieldAccess AccessBuilder::ForJSFunctionNextFunctionLink() {
|
||||
FieldAccess access = {kTaggedBase, JSFunction::kNextFunctionLinkOffset,
|
||||
Handle<Name>(), Type::Any(), MachineType::AnyTagged()};
|
||||
return access;
|
||||
}
|
||||
|
||||
// static
|
||||
FieldAccess AccessBuilder::ForJSArrayLength(ElementsKind elements_kind) {
|
||||
TypeCache const& type_cache = TypeCache::Get();
|
||||
|
@ -34,12 +34,24 @@ class AccessBuilder final : public AllStatic {
|
||||
// Provides access to JSObject inobject property fields.
|
||||
static FieldAccess ForJSObjectInObjectProperty(Handle<Map> map, int index);
|
||||
|
||||
// Provides access to JSFunction::prototype_or_initial_map() field.
|
||||
static FieldAccess ForJSFunctionPrototypeOrInitialMap();
|
||||
|
||||
// Provides access to JSFunction::context() field.
|
||||
static FieldAccess ForJSFunctionContext();
|
||||
|
||||
// Provides access to JSFunction::shared() field.
|
||||
static FieldAccess ForJSFunctionSharedFunctionInfo();
|
||||
|
||||
// Provides access to JSFunction::literals() field.
|
||||
static FieldAccess ForJSFunctionLiterals();
|
||||
|
||||
// Provides access to JSFunction::code() field.
|
||||
static FieldAccess ForJSFunctionCodeEntry();
|
||||
|
||||
// Provides access to JSFunction::next_function_link() field.
|
||||
static FieldAccess ForJSFunctionNextFunctionLink();
|
||||
|
||||
// Provides access to JSArray::length() field.
|
||||
static FieldAccess ForJSArrayLength(ElementsKind elements_kind);
|
||||
|
||||
|
@ -201,6 +201,8 @@ Reduction JSCreateLowering::Reduce(Node* node) {
|
||||
return ReduceJSCreateArguments(node);
|
||||
case IrOpcode::kJSCreateArray:
|
||||
return ReduceJSCreateArray(node);
|
||||
case IrOpcode::kJSCreateClosure:
|
||||
return ReduceJSCreateClosure(node);
|
||||
case IrOpcode::kJSCreateIterResultObject:
|
||||
return ReduceJSCreateIterResultObject(node);
|
||||
case IrOpcode::kJSCreateLiteralArray:
|
||||
@ -540,6 +542,51 @@ Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction JSCreateLowering::ReduceJSCreateClosure(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSCreateClosure, node->opcode());
|
||||
CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
|
||||
Handle<SharedFunctionInfo> shared = p.shared_info();
|
||||
|
||||
// Use inline allocation for functions that don't need literals cloning.
|
||||
if (shared->num_literals() == 0) {
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
Node* context = NodeProperties::GetContextInput(node);
|
||||
Node* native_context = effect = graph()->NewNode(
|
||||
javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
|
||||
context, context, effect);
|
||||
int function_map_index =
|
||||
Context::FunctionMapIndex(shared->language_mode(), shared->kind());
|
||||
Node* function_map = effect =
|
||||
graph()->NewNode(javascript()->LoadContext(0, function_map_index, true),
|
||||
native_context, native_context, effect);
|
||||
// Note that it is only safe to embed the raw entry point of the compile
|
||||
// lazy stub into the code, because that stub is immortal and immovable.
|
||||
Node* compile_entry = jsgraph()->IntPtrConstant(reinterpret_cast<intptr_t>(
|
||||
jsgraph()->isolate()->builtins()->CompileLazy()->entry()));
|
||||
Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant();
|
||||
Node* the_hole = jsgraph()->TheHoleConstant();
|
||||
Node* undefined = jsgraph()->UndefinedConstant();
|
||||
AllocationBuilder a(jsgraph(), effect, control);
|
||||
STATIC_ASSERT(JSFunction::kSize == 9 * kPointerSize);
|
||||
a.Allocate(JSFunction::kSize, p.pretenure());
|
||||
a.Store(AccessBuilder::ForMap(), function_map);
|
||||
a.Store(AccessBuilder::ForJSObjectProperties(), empty_fixed_array);
|
||||
a.Store(AccessBuilder::ForJSObjectElements(), empty_fixed_array);
|
||||
a.Store(AccessBuilder::ForJSFunctionLiterals(), empty_fixed_array);
|
||||
a.Store(AccessBuilder::ForJSFunctionPrototypeOrInitialMap(), the_hole);
|
||||
a.Store(AccessBuilder::ForJSFunctionSharedFunctionInfo(), shared);
|
||||
a.Store(AccessBuilder::ForJSFunctionContext(), context);
|
||||
a.Store(AccessBuilder::ForJSFunctionCodeEntry(), compile_entry);
|
||||
a.Store(AccessBuilder::ForJSFunctionNextFunctionLink(), undefined);
|
||||
RelaxControls(node);
|
||||
a.FinishAndChange(node);
|
||||
return Changed(node);
|
||||
}
|
||||
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction JSCreateLowering::ReduceJSCreateIterResultObject(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSCreateIterResultObject, node->opcode());
|
||||
Node* value = NodeProperties::GetValueInput(node, 0);
|
||||
|
@ -45,6 +45,7 @@ class JSCreateLowering final : public AdvancedReducer {
|
||||
Reduction ReduceJSCreate(Node* node);
|
||||
Reduction ReduceJSCreateArguments(Node* node);
|
||||
Reduction ReduceJSCreateArray(Node* node);
|
||||
Reduction ReduceJSCreateClosure(Node* node);
|
||||
Reduction ReduceJSCreateIterResultObject(Node* node);
|
||||
Reduction ReduceJSCreateLiteral(Node* node);
|
||||
Reduction ReduceJSCreateFunctionContext(Node* node);
|
||||
|
@ -171,6 +171,24 @@ TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedRestArray) {
|
||||
IsAllocate(IsNumberConstant(JSArray::kSize), _, control), _));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// JSCreateClosure
|
||||
|
||||
TEST_F(JSCreateLoweringTest, JSCreateClosureViaInlinedAllocation) {
|
||||
Node* const context = UndefinedConstant();
|
||||
Node* const effect = graph()->start();
|
||||
Node* const control = graph()->start();
|
||||
Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared());
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->CreateClosure(shared, NOT_TENURED),
|
||||
context, effect, control));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsFinishRegion(IsAllocate(IsNumberConstant(JSFunction::kSize),
|
||||
IsBeginRegion(_), control),
|
||||
_));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// JSCreateFunctionContext
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user