diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-20 15:06:40 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-22 11:48:58 +0000 |
commit | daa093eea7c773db06799a13bd7e4e2e2a9f8f14 (patch) | |
tree | 96cc5e7b9194c1b29eab927730bfa419e7111c25 /chromium/v8/src/compiler/js-create-lowering.cc | |
parent | be59a35641616a4cf23c4a13fa0632624b021c1b (diff) | |
download | qtwebengine-chromium-daa093eea7c773db06799a13bd7e4e2e2a9f8f14.tar.gz |
BASELINE: Update Chromium to 63.0.3239.58
Change-Id: Ia93b322a00ba4dd4004f3bcf1254063ba90e1605
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/v8/src/compiler/js-create-lowering.cc')
-rw-r--r-- | chromium/v8/src/compiler/js-create-lowering.cc | 513 |
1 files changed, 352 insertions, 161 deletions
diff --git a/chromium/v8/src/compiler/js-create-lowering.cc b/chromium/v8/src/compiler/js-create-lowering.cc index 76b9a79aa04..d740f7681cb 100644 --- a/chromium/v8/src/compiler/js-create-lowering.cc +++ b/chromium/v8/src/compiler/js-create-lowering.cc @@ -214,6 +214,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::kJSCreateKeyValueArray: @@ -311,47 +313,38 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) { case CreateArgumentsType::kMappedArguments: { // TODO(mstarzinger): Duplicate parameters are not handled yet. if (shared->has_duplicate_parameters()) return NoChange(); - // If there is no aliasing, the arguments object elements are not - // special in any way, we can just return an unmapped backing store. - if (shared->internal_formal_parameter_count() == 0) { - Node* const callee = NodeProperties::GetValueInput(node, 0); - Node* effect = NodeProperties::GetEffectInput(node); - Node* const arguments_frame = - graph()->NewNode(simplified()->ArgumentsFrame()); - Node* const arguments_length = graph()->NewNode( - simplified()->ArgumentsLength(0, false), arguments_frame); - // Allocate the elements backing store. - Node* const elements = effect = - graph()->NewNode(simplified()->NewUnmappedArgumentsElements(), - arguments_frame, arguments_length, effect); - // Load the arguments object map. - Node* const arguments_map = jsgraph()->HeapConstant( - handle(native_context()->sloppy_arguments_map(), isolate())); - // Actually allocate and initialize the arguments object. - AllocationBuilder a(jsgraph(), effect, control); - Node* properties = jsgraph()->EmptyFixedArrayConstant(); - STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kPointerSize); - a.Allocate(JSSloppyArgumentsObject::kSize); - a.Store(AccessBuilder::ForMap(), arguments_map); - a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); - a.Store(AccessBuilder::ForJSObjectElements(), elements); - a.Store(AccessBuilder::ForArgumentsLength(), arguments_length); - a.Store(AccessBuilder::ForArgumentsCallee(), callee); - RelaxControls(node); - a.FinishAndChange(node); - } else { - Callable callable = Builtins::CallableFor( - isolate(), Builtins::kFastNewSloppyArguments); - Operator::Properties properties = node->op()->properties(); - CallDescriptor* desc = Linkage::GetStubCallDescriptor( - isolate(), graph()->zone(), callable.descriptor(), 0, - CallDescriptor::kNoFlags, properties); - const Operator* new_op = common()->Call(desc); - Node* stub_code = jsgraph()->HeapConstant(callable.code()); - node->InsertInput(graph()->zone(), 0, stub_code); - node->RemoveInput(3); // Remove the frame state. - NodeProperties::ChangeOp(node, new_op); - } + Node* const callee = NodeProperties::GetValueInput(node, 0); + Node* const context = NodeProperties::GetContextInput(node); + Node* effect = NodeProperties::GetEffectInput(node); + Node* const arguments_frame = + graph()->NewNode(simplified()->ArgumentsFrame()); + Node* const arguments_length = graph()->NewNode( + simplified()->ArgumentsLength( + shared->internal_formal_parameter_count(), false), + arguments_frame); + // Allocate the elements backing store. + bool has_aliased_arguments = false; + Node* const elements = effect = AllocateAliasedArguments( + effect, control, context, arguments_frame, arguments_length, shared, + &has_aliased_arguments); + // Load the arguments object map. + Node* const arguments_map = jsgraph()->HeapConstant( + handle(has_aliased_arguments + ? native_context()->fast_aliased_arguments_map() + : native_context()->sloppy_arguments_map(), + isolate())); + // Actually allocate and initialize the arguments object. + AllocationBuilder a(jsgraph(), effect, control); + Node* properties = jsgraph()->EmptyFixedArrayConstant(); + STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kPointerSize); + a.Allocate(JSSloppyArgumentsObject::kSize); + a.Store(AccessBuilder::ForMap(), arguments_map); + a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); + a.Store(AccessBuilder::ForJSObjectElements(), elements); + a.Store(AccessBuilder::ForArgumentsLength(), arguments_length); + a.Store(AccessBuilder::ForArgumentsCallee(), callee); + RelaxControls(node); + a.FinishAndChange(node); return Changed(node); } case CreateArgumentsType::kUnmappedArguments: { @@ -364,7 +357,7 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) { arguments_frame); // Allocate the elements backing store. Node* const elements = effect = - graph()->NewNode(simplified()->NewUnmappedArgumentsElements(), + graph()->NewNode(simplified()->NewArgumentsElements(0), arguments_frame, arguments_length, effect); // Load the arguments object map. Node* const arguments_map = jsgraph()->HeapConstant( @@ -386,15 +379,15 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) { Node* effect = NodeProperties::GetEffectInput(node); Node* const arguments_frame = graph()->NewNode(simplified()->ArgumentsFrame()); - int formal_parameter_count = shared->internal_formal_parameter_count(); Node* const rest_length = graph()->NewNode( - simplified()->ArgumentsLength(formal_parameter_count, true), + simplified()->ArgumentsLength( + shared->internal_formal_parameter_count(), true), arguments_frame); - // Allocate the elements backing store. Since - // NewUnmappedArgumentsElements copies from the end of the arguments - // adapter frame, this is a suffix of the actual arguments. + // Allocate the elements backing store. Since NewArgumentsElements + // copies from the end of the arguments adapter frame, this is a suffix + // of the actual arguments. Node* const elements = effect = - graph()->NewNode(simplified()->NewUnmappedArgumentsElements(), + graph()->NewNode(simplified()->NewArgumentsElements(0), arguments_frame, rest_length, effect); // Load the JSArray object map. Node* const jsarray_map = jsgraph()->HeapConstant(handle( @@ -586,29 +579,73 @@ Reduction JSCreateLowering::ReduceJSCreateGeneratorObject(Node* node) { return NoChange(); } +// Constructs an array with a variable {length} when no upper bound +// is known for the capacity. +Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length, + Handle<Map> initial_map, + PretenureFlag pretenure) { + DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode()); + Node* effect = NodeProperties::GetEffectInput(node); + Node* control = NodeProperties::GetControlInput(node); + + // Constructing an Array via new Array(N) where N is an unsigned + // integer, always creates a holey backing store. + if (!IsHoleyElementsKind(initial_map->elements_kind())) { + initial_map = Map::AsElementsKind( + initial_map, GetHoleyElementsKind(initial_map->elements_kind())); + } + + // Check that the {limit} is an unsigned integer in the valid range. + // This has to be kept in sync with src/runtime/runtime-array.cc, + // where this limit is protected. + length = effect = graph()->NewNode( + simplified()->CheckBounds(), length, + jsgraph()->Constant(JSArray::kInitialMaxFastElementArray), effect, + control); + + // Construct elements and properties for the resulting JSArray. + Node* elements = effect = + graph()->NewNode(IsDoubleElementsKind(initial_map->elements_kind()) + ? simplified()->NewDoubleElements(pretenure) + : simplified()->NewSmiOrObjectElements(pretenure), + length, effect, control); + Node* properties = jsgraph()->EmptyFixedArrayConstant(); + + // Perform the allocation of the actual JSArray object. + AllocationBuilder a(jsgraph(), effect, control); + a.Allocate(initial_map->instance_size(), pretenure); + a.Store(AccessBuilder::ForMap(), initial_map); + a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); + a.Store(AccessBuilder::ForJSObjectElements(), elements); + a.Store(AccessBuilder::ForJSArrayLength(initial_map->elements_kind()), + length); + for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) { + a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i), + jsgraph()->UndefinedConstant()); + } + RelaxControls(node); + a.FinishAndChange(node); + return Changed(node); +} + +// Constructs an array with a variable {length} when an actual +// upper bound is known for the {capacity}. Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length, int capacity, - Handle<AllocationSite> site) { + Handle<Map> initial_map, + PretenureFlag pretenure) { DCHECK(node->opcode() == IrOpcode::kJSCreateArray || node->opcode() == IrOpcode::kJSCreateEmptyLiteralArray); Node* effect = NodeProperties::GetEffectInput(node); Node* control = NodeProperties::GetControlInput(node); - // Extract transition and tenuring feedback from the {site} and add - // appropriate code dependencies on the {site} if deoptimization is - // enabled. - PretenureFlag pretenure = site->GetPretenureMode(); - ElementsKind elements_kind = site->GetElementsKind(); - DCHECK(IsFastElementsKind(elements_kind)); - if (NodeProperties::GetType(length)->Max() > 0) { + // Determine the appropriate elements kind. + ElementsKind elements_kind = initial_map->elements_kind(); + if (NodeProperties::GetType(length)->Max() > 0.0) { elements_kind = GetHoleyElementsKind(elements_kind); + initial_map = Map::AsElementsKind(initial_map, elements_kind); } - dependencies()->AssumeTenuringDecision(site); - dependencies()->AssumeTransitionStable(site); - - // Retrieve the initial map for the array. - Node* js_array_map = jsgraph()->HeapConstant( - handle(native_context()->GetInitialJSArrayMap(elements_kind), isolate())); + DCHECK(IsFastElementsKind(elements_kind)); // Setup elements and properties. Node* elements; @@ -622,11 +659,15 @@ Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length, // Perform the allocation of the actual JSArray object. AllocationBuilder a(jsgraph(), effect, control); - a.Allocate(JSArray::kSize, pretenure); - a.Store(AccessBuilder::ForMap(), js_array_map); + a.Allocate(initial_map->instance_size(), pretenure); + a.Store(AccessBuilder::ForMap(), initial_map); a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); a.Store(AccessBuilder::ForJSObjectElements(), elements); a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length); + for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) { + a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i), + jsgraph()->UndefinedConstant()); + } RelaxControls(node); a.FinishAndChange(node); return Changed(node); @@ -634,19 +675,15 @@ Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length, Reduction JSCreateLowering::ReduceNewArray(Node* node, std::vector<Node*> values, - Handle<AllocationSite> site) { + Handle<Map> initial_map, + PretenureFlag pretenure) { DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode()); Node* effect = NodeProperties::GetEffectInput(node); Node* control = NodeProperties::GetControlInput(node); - // Extract transition and tenuring feedback from the {site} and add - // appropriate code dependencies on the {site} if deoptimization is - // enabled. - PretenureFlag pretenure = site->GetPretenureMode(); - ElementsKind elements_kind = site->GetElementsKind(); + // Determine the appropriate elements kind. + ElementsKind elements_kind = initial_map->elements_kind(); DCHECK(IsFastElementsKind(elements_kind)); - dependencies()->AssumeTenuringDecision(site); - dependencies()->AssumeTransitionStable(site); // Check {values} based on the {elements_kind}. These checks are guarded // by the {elements_kind} feedback on the {site}, so it's safe to just @@ -669,10 +706,6 @@ Reduction JSCreateLowering::ReduceNewArray(Node* node, } } - // Retrieve the initial map for the array. - Node* js_array_map = jsgraph()->HeapConstant( - handle(native_context()->GetInitialJSArrayMap(elements_kind), isolate())); - // Setup elements, properties and length. Node* elements = effect = AllocateElements(effect, control, elements_kind, values, pretenure); @@ -681,11 +714,15 @@ Reduction JSCreateLowering::ReduceNewArray(Node* node, // Perform the allocation of the actual JSArray object. AllocationBuilder a(jsgraph(), effect, control); - a.Allocate(JSArray::kSize, pretenure); - a.Store(AccessBuilder::ForMap(), js_array_map); + a.Allocate(initial_map->instance_size(), pretenure); + a.Store(AccessBuilder::ForMap(), initial_map); a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); a.Store(AccessBuilder::ForJSObjectElements(), elements); a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length); + for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) { + a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i), + jsgraph()->UndefinedConstant()); + } RelaxControls(node); a.FinishAndChange(node); return Changed(node); @@ -756,52 +793,186 @@ Reduction JSCreateLowering::ReduceNewArrayToStubCall( Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) { DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode()); CreateArrayParameters const& p = CreateArrayParametersOf(node->op()); + int const arity = static_cast<int>(p.arity()); + Handle<AllocationSite> const site = p.site(); + PretenureFlag pretenure = NOT_TENURED; + Handle<JSFunction> constructor(native_context()->array_function(), isolate()); Node* target = NodeProperties::GetValueInput(node, 0); Node* new_target = NodeProperties::GetValueInput(node, 1); + Type* new_target_type = (target == new_target) + ? Type::HeapConstant(constructor, zone()) + : NodeProperties::GetType(new_target); - // TODO(bmeurer): Optimize the subclassing case. - if (target != new_target) return NoChange(); + // Extract original constructor function. + if (new_target_type->IsHeapConstant() && + new_target_type->AsHeapConstant()->Value()->IsJSFunction()) { + Handle<JSFunction> original_constructor = + Handle<JSFunction>::cast(new_target_type->AsHeapConstant()->Value()); + DCHECK(constructor->IsConstructor()); + DCHECK(original_constructor->IsConstructor()); - // Check if we have a feedback {site} on the {node}. - Handle<AllocationSite> site = p.site(); - if (!site.is_null()) { - // Attempt to inline calls to the Array constructor for the relevant cases - // where either no arguments are provided, or exactly one unsigned number - // argument is given. - if (site->CanInlineCall()) { - if (p.arity() == 0) { + // Check if we can inline the allocation. + if (IsAllocationInlineable(constructor, original_constructor)) { + // Force completion of inobject slack tracking before + // generating code to finalize the instance size. + original_constructor->CompleteInobjectSlackTrackingIfActive(); + Handle<Map> initial_map(original_constructor->initial_map(), isolate()); + + // Add a dependency on the {initial_map} to make sure that this code is + // deoptimized whenever the {initial_map} changes. + dependencies()->AssumeInitialMapCantChange(initial_map); + + // Tells whether we are protected by either the {site} or a + // protector cell to do certain speculative optimizations. + bool can_inline_call = false; + + // Check if we have a feedback {site} on the {node}. + if (!site.is_null()) { + ElementsKind elements_kind = site->GetElementsKind(); + if (initial_map->elements_kind() != elements_kind) { + initial_map = Map::AsElementsKind(initial_map, elements_kind); + } + can_inline_call = site->CanInlineCall(); + pretenure = site->GetPretenureMode(); + + dependencies()->AssumeTransitionStable(site); + dependencies()->AssumeTenuringDecision(site); + } else { + can_inline_call = isolate()->IsArrayConstructorIntact(); + } + + if (arity == 0) { Node* length = jsgraph()->ZeroConstant(); int capacity = JSArray::kPreallocatedArrayElements; - return ReduceNewArray(node, length, capacity, site); - } else if (p.arity() == 1) { + return ReduceNewArray(node, length, capacity, initial_map, pretenure); + } else if (arity == 1) { Node* length = NodeProperties::GetValueInput(node, 2); Type* length_type = NodeProperties::GetType(length); if (!length_type->Maybe(Type::Number())) { // Handle the single argument case, where we know that the value // cannot be a valid Array length. - return ReduceNewArray(node, {length}, site); + ElementsKind elements_kind = initial_map->elements_kind(); + elements_kind = GetMoreGeneralElementsKind( + elements_kind, IsHoleyElementsKind(elements_kind) + ? HOLEY_ELEMENTS + : PACKED_ELEMENTS); + initial_map = Map::AsElementsKind(initial_map, elements_kind); + return ReduceNewArray(node, std::vector<Node*>{length}, initial_map, + pretenure); } if (length_type->Is(Type::SignedSmall()) && length_type->Min() >= 0 && length_type->Max() <= kElementLoopUnrollLimit && length_type->Min() == length_type->Max()) { int capacity = static_cast<int>(length_type->Max()); - return ReduceNewArray(node, length, capacity, site); + return ReduceNewArray(node, length, capacity, initial_map, pretenure); + } + if (length_type->Maybe(Type::UnsignedSmall()) && can_inline_call) { + return ReduceNewArray(node, length, initial_map, pretenure); } - } else if (p.arity() <= JSArray::kInitialMaxFastElementArray) { + } else if (arity <= JSArray::kInitialMaxFastElementArray) { + // Gather the values to store into the newly created array. + bool values_all_smis = true, values_all_numbers = true, + values_any_nonnumber = false; std::vector<Node*> values; values.reserve(p.arity()); - for (size_t i = 0; i < p.arity(); ++i) { - values.push_back( - NodeProperties::GetValueInput(node, static_cast<int>(2 + i))); + for (int i = 0; i < arity; ++i) { + Node* value = NodeProperties::GetValueInput(node, 2 + i); + Type* value_type = NodeProperties::GetType(value); + if (!value_type->Is(Type::SignedSmall())) { + values_all_smis = false; + } + if (!value_type->Is(Type::Number())) { + values_all_numbers = false; + } + if (!value_type->Maybe(Type::Number())) { + values_any_nonnumber = true; + } + values.push_back(value); + } + + // Try to figure out the ideal elements kind statically. + ElementsKind elements_kind = initial_map->elements_kind(); + if (values_all_smis) { + // Smis can be stored with any elements kind. + } else if (values_all_numbers) { + elements_kind = GetMoreGeneralElementsKind( + elements_kind, IsHoleyElementsKind(elements_kind) + ? HOLEY_DOUBLE_ELEMENTS + : PACKED_DOUBLE_ELEMENTS); + } else if (values_any_nonnumber) { + elements_kind = GetMoreGeneralElementsKind( + elements_kind, IsHoleyElementsKind(elements_kind) + ? HOLEY_ELEMENTS + : PACKED_ELEMENTS); + } else if (!can_inline_call) { + // We have some crazy combination of types for the {values} where + // there's no clear decision on the elements kind statically. And + // we don't have a protection against deoptimization loops for the + // checks that are introduced in the call to ReduceNewArray, so + // we cannot inline this invocation of the Array constructor here. + return NoChange(); } - return ReduceNewArray(node, values, site); + initial_map = Map::AsElementsKind(initial_map, elements_kind); + + return ReduceNewArray(node, values, initial_map, pretenure); } } } + // TODO(bmeurer): Optimize the subclassing case. + if (target != new_target) return NoChange(); + return ReduceNewArrayToStubCall(node, site); } +Reduction JSCreateLowering::ReduceJSCreateClosure(Node* node) { + DCHECK_EQ(IrOpcode::kJSCreateClosure, node->opcode()); + CreateClosureParameters const& p = CreateClosureParametersOf(node->op()); + Handle<SharedFunctionInfo> shared = p.shared_info(); + Node* effect = NodeProperties::GetEffectInput(node); + Node* control = NodeProperties::GetControlInput(node); + Node* context = NodeProperties::GetContextInput(node); + + // Use inline allocation of closures only for instantiation sites that have + // seen more than one instantiation, this simplifies the generated code and + // also serves as a heuristic of which allocation sites benefit from it. + FeedbackSlot slot(FeedbackVector::ToSlot(p.feedback().index())); + Handle<Cell> vector_cell(Cell::cast(p.feedback().vector()->Get(slot))); + if (vector_cell->map() == isolate()->heap()->many_closures_cell_map()) { + Handle<Map> function_map( + Map::cast(native_context()->get(shared->function_map_index()))); + Node* lazy_compile_builtin = jsgraph()->HeapConstant( + handle(isolate()->builtins()->builtin(Builtins::kCompileLazy))); + DCHECK(!function_map->IsInobjectSlackTrackingInProgress()); + DCHECK(!function_map->is_dictionary_map()); + + // Emit code to allocate the JSFunction instance. + AllocationBuilder a(jsgraph(), effect, control); + a.Allocate(function_map->instance_size()); + a.Store(AccessBuilder::ForMap(), function_map); + a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), + jsgraph()->EmptyFixedArrayConstant()); + a.Store(AccessBuilder::ForJSObjectElements(), + jsgraph()->EmptyFixedArrayConstant()); + a.Store(AccessBuilder::ForJSFunctionPrototypeOrInitialMap(), + jsgraph()->TheHoleConstant()); + a.Store(AccessBuilder::ForJSFunctionSharedFunctionInfo(), shared); + a.Store(AccessBuilder::ForJSFunctionContext(), context); + a.Store(AccessBuilder::ForJSFunctionFeedbackVector(), vector_cell); + a.Store(AccessBuilder::ForJSFunctionCode(), lazy_compile_builtin); + STATIC_ASSERT(JSFunction::kSize == 8 * kPointerSize); + for (int i = 0; i < function_map->GetInObjectProperties(); i++) { + a.Store(AccessBuilder::ForJSObjectInObjectProperty(function_map, i), + jsgraph()->UndefinedConstant()); + } + 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); @@ -863,41 +1034,41 @@ Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) { Node* effect = NodeProperties::GetEffectInput(node); Node* control = NodeProperties::GetControlInput(node); - Handle<FeedbackVector> feedback_vector; - if (GetSpecializationFeedbackVector(node).ToHandle(&feedback_vector)) { - FeedbackSlot slot(FeedbackVector::ToSlot(p.index())); - Handle<Object> literal(feedback_vector->Get(slot), isolate()); - if (literal->IsAllocationSite()) { - Handle<AllocationSite> site = Handle<AllocationSite>::cast(literal); - Handle<JSObject> boilerplate(site->boilerplate(), isolate()); - int max_properties = kMaxFastLiteralProperties; - if (IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) { - AllocationSiteUsageContext site_context(isolate(), site, false); - site_context.EnterNewScope(); - Node* value = effect = - AllocateFastLiteral(effect, control, boilerplate, &site_context); - site_context.ExitScope(site, boilerplate); - ReplaceWithValue(node, value, effect, control); - return Replace(value); - } + Handle<Object> feedback(p.feedback().vector()->Get(p.feedback().slot()), + isolate()); + if (feedback->IsAllocationSite()) { + Handle<AllocationSite> site = Handle<AllocationSite>::cast(feedback); + Handle<JSObject> boilerplate(site->boilerplate(), isolate()); + int max_properties = kMaxFastLiteralProperties; + if (IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) { + AllocationSiteUsageContext site_context(isolate(), site, false); + site_context.EnterNewScope(); + Node* value = effect = + AllocateFastLiteral(effect, control, boilerplate, &site_context); + site_context.ExitScope(site, boilerplate); + ReplaceWithValue(node, value, effect, control); + return Replace(value); } } return NoChange(); } Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralArray(Node* node) { - DCHECK_EQ(node->opcode(), IrOpcode::kJSCreateEmptyLiteralArray); - int literal_index = OpParameter<int>(node); - Handle<FeedbackVector> feedback_vector; - if (GetSpecializationFeedbackVector(node).ToHandle(&feedback_vector)) { - FeedbackSlot slot(FeedbackVector::ToSlot(literal_index)); - Handle<Object> raw_site(feedback_vector->Get(slot), isolate()); - if (raw_site->IsAllocationSite()) { - Handle<AllocationSite> site = Handle<AllocationSite>::cast(raw_site); - DCHECK(!site->PointsToLiteral()); - Node* length = jsgraph()->ZeroConstant(); - return ReduceNewArray(node, length, 0, site); - } + DCHECK_EQ(IrOpcode::kJSCreateEmptyLiteralArray, node->opcode()); + FeedbackParameter const& p = FeedbackParameterOf(node->op()); + Handle<Object> feedback(p.feedback().vector()->Get(p.feedback().slot()), + isolate()); + if (feedback->IsAllocationSite()) { + Handle<AllocationSite> site = Handle<AllocationSite>::cast(feedback); + DCHECK(!site->PointsToLiteral()); + Handle<Map> const initial_map( + native_context()->GetInitialJSArrayMap(site->GetElementsKind()), + isolate()); + PretenureFlag const pretenure = site->GetPretenureMode(); + dependencies()->AssumeTransitionStable(site); + dependencies()->AssumeTenuringDecision(site); + Node* length = jsgraph()->ZeroConstant(); + return ReduceNewArray(node, length, 0, initial_map, pretenure); } return NoChange(); } @@ -934,21 +1105,18 @@ Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralObject(Node* node) { } Reduction JSCreateLowering::ReduceJSCreateLiteralRegExp(Node* node) { - DCHECK(node->opcode() == IrOpcode::kJSCreateLiteralRegExp); + DCHECK_EQ(IrOpcode::kJSCreateLiteralRegExp, node->opcode()); CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); Node* effect = NodeProperties::GetEffectInput(node); Node* control = NodeProperties::GetControlInput(node); - Handle<FeedbackVector> feedback_vector; - if (GetSpecializationFeedbackVector(node).ToHandle(&feedback_vector)) { - FeedbackSlot slot(FeedbackVector::ToSlot(p.index())); - Handle<Object> maybe_boilerplate(feedback_vector->Get(slot), isolate()); - if (maybe_boilerplate->IsJSRegExp()) { - Node* value = effect = AllocateLiteralRegExp( - effect, control, Handle<JSRegExp>::cast(maybe_boilerplate)); - ReplaceWithValue(node, value, effect, control); - return Replace(value); - } + Handle<Object> feedback(p.feedback().vector()->Get(p.feedback().slot()), + isolate()); + if (feedback->IsJSRegExp()) { + Handle<JSRegExp> boilerplate = Handle<JSRegExp>::cast(feedback); + Node* value = effect = AllocateLiteralRegExp(effect, control, boilerplate); + ReplaceWithValue(node, value, effect, control); + return Replace(value); } return NoChange(); } @@ -1201,6 +1369,53 @@ Node* JSCreateLowering::AllocateAliasedArguments( return a.Finish(); } +// Helper that allocates a FixedArray serving as a parameter map for values +// unknown at compile-time, the true {arguments_length} and {arguments_frame} +// values can only be determined dynamically at run-time and are provided. +// Serves as backing store for JSCreateArguments nodes. +Node* JSCreateLowering::AllocateAliasedArguments( + Node* effect, Node* control, Node* context, Node* arguments_frame, + Node* arguments_length, Handle<SharedFunctionInfo> shared, + bool* has_aliased_arguments) { + // If there is no aliasing, the arguments object elements are not + // special in any way, we can just return an unmapped backing store. + int parameter_count = shared->internal_formal_parameter_count(); + if (parameter_count == 0) { + return graph()->NewNode(simplified()->NewArgumentsElements(0), + arguments_frame, arguments_length, effect); + } + + // From here on we are going to allocate a mapped (aka. aliased) elements + // backing store. We do not statically know how many arguments exist, but + // dynamically selecting the hole for some of the "mapped" elements allows + // using a static shape for the parameter map. + int mapped_count = parameter_count; + *has_aliased_arguments = true; + + // The unmapped argument values are stored yet another indirection away and + // then linked into the parameter map below, whereas mapped argument values + // (i.e. the first {mapped_count} elements) are replaced with a hole instead. + Node* arguments = + graph()->NewNode(simplified()->NewArgumentsElements(mapped_count), + arguments_frame, arguments_length, effect); + + // Actually allocate the backing store. + AllocationBuilder a(jsgraph(), arguments, control); + a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map()); + a.Store(AccessBuilder::ForFixedArraySlot(0), context); + a.Store(AccessBuilder::ForFixedArraySlot(1), arguments); + for (int i = 0; i < mapped_count; ++i) { + int idx = Context::MIN_CONTEXT_SLOTS + parameter_count - 1 - i; + Node* value = graph()->NewNode( + common()->Select(MachineRepresentation::kTagged), + graph()->NewNode(simplified()->NumberLessThan(), jsgraph()->Constant(i), + arguments_length), + jsgraph()->Constant(idx), jsgraph()->TheHoleConstant()); + a.Store(AccessBuilder::ForFixedArraySlot(i + 2), value); + } + return a.Finish(); +} + Node* JSCreateLowering::AllocateElements(Node* effect, Node* control, ElementsKind elements_kind, int capacity, @@ -1467,30 +1682,6 @@ Node* JSCreateLowering::AllocateLiteralRegExp(Node* effect, Node* control, return builder.Finish(); } -MaybeHandle<FeedbackVector> JSCreateLowering::GetSpecializationFeedbackVector( - Node* node) { - Node* const closure = NodeProperties::GetValueInput(node, 0); - switch (closure->opcode()) { - case IrOpcode::kHeapConstant: { - Handle<HeapObject> object = OpParameter<Handle<HeapObject>>(closure); - return handle(Handle<JSFunction>::cast(object)->feedback_vector()); - } - case IrOpcode::kParameter: { - int const index = ParameterIndexOf(closure->op()); - // The closure is always the last parameter to a JavaScript function, and - // {Parameter} indices start at -1, so value outputs of {Start} look like - // this: closure, receiver, param0, ..., paramN, context. - if (index == -1) { - return feedback_vector_; - } - break; - } - default: - break; - } - return MaybeHandle<FeedbackVector>(); -} - Factory* JSCreateLowering::factory() const { return isolate()->factory(); } Graph* JSCreateLowering::graph() const { return jsgraph()->graph(); } |