[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:
mstarzinger 2016-04-14 08:17:28 -07:00 committed by Commit bot
parent 290ee88f63
commit 43c7c76f1d
5 changed files with 109 additions and 0 deletions

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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