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