From 43c7c76f1de26786884624df5435c766f4fe2fbe Mon Sep 17 00:00:00 2001 From: mstarzinger Date: Thu, 14 Apr 2016 08:17:28 -0700 Subject: [PATCH] [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} --- src/compiler/access-builder.cc | 31 ++++++++++++ src/compiler/access-builder.h | 12 +++++ src/compiler/js-create-lowering.cc | 47 +++++++++++++++++++ src/compiler/js-create-lowering.h | 1 + .../compiler/js-create-lowering-unittest.cc | 18 +++++++ 5 files changed, 109 insertions(+) diff --git a/src/compiler/access-builder.cc b/src/compiler/access-builder.cc index 722bbf020e..547f2d8850 100644 --- a/src/compiler/access-builder.cc +++ b/src/compiler/access-builder.cc @@ -60,6 +60,14 @@ FieldAccess AccessBuilder::ForJSObjectInObjectProperty(Handle map, } +// static +FieldAccess AccessBuilder::ForJSFunctionPrototypeOrInitialMap() { + FieldAccess access = {kTaggedBase, JSFunction::kPrototypeOrInitialMapOffset, + MaybeHandle(), 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(), Type::Internal(), + MachineType::AnyTagged()}; + return access; +} + +// static +FieldAccess AccessBuilder::ForJSFunctionCodeEntry() { + FieldAccess access = {kTaggedBase, JSFunction::kCodeEntryOffset, + Handle(), Type::UntaggedPointer(), + MachineType::Pointer()}; + return access; +} + +// static +FieldAccess AccessBuilder::ForJSFunctionNextFunctionLink() { + FieldAccess access = {kTaggedBase, JSFunction::kNextFunctionLinkOffset, + Handle(), Type::Any(), MachineType::AnyTagged()}; + return access; +} + // static FieldAccess AccessBuilder::ForJSArrayLength(ElementsKind elements_kind) { TypeCache const& type_cache = TypeCache::Get(); diff --git a/src/compiler/access-builder.h b/src/compiler/access-builder.h index 8375d37600..226456714d 100644 --- a/src/compiler/access-builder.h +++ b/src/compiler/access-builder.h @@ -34,12 +34,24 @@ class AccessBuilder final : public AllStatic { // Provides access to JSObject inobject property fields. static FieldAccess ForJSObjectInObjectProperty(Handle 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); diff --git a/src/compiler/js-create-lowering.cc b/src/compiler/js-create-lowering.cc index df5c8d07df..00e5367f88 100644 --- a/src/compiler/js-create-lowering.cc +++ b/src/compiler/js-create-lowering.cc @@ -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 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( + 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); diff --git a/src/compiler/js-create-lowering.h b/src/compiler/js-create-lowering.h index d9d184b8e2..99eb461148 100644 --- a/src/compiler/js-create-lowering.h +++ b/src/compiler/js-create-lowering.h @@ -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); diff --git a/test/unittests/compiler/js-create-lowering-unittest.cc b/test/unittests/compiler/js-create-lowering-unittest.cc index 837c5742d9..e43dd27774 100644 --- a/test/unittests/compiler/js-create-lowering-unittest.cc +++ b/test/unittests/compiler/js-create-lowering-unittest.cc @@ -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 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