diff options
Diffstat (limited to 'src/compiler/js-create-lowering.cc')
-rw-r--r-- | src/compiler/js-create-lowering.cc | 284 |
1 files changed, 174 insertions, 110 deletions
diff --git a/src/compiler/js-create-lowering.cc b/src/compiler/js-create-lowering.cc index c54b76b6..f3ceb2b0 100644 --- a/src/compiler/js-create-lowering.cc +++ b/src/compiler/js-create-lowering.cc @@ -12,11 +12,12 @@ #include "src/compiler/js-graph.h" #include "src/compiler/js-operator.h" #include "src/compiler/linkage.h" -#include "src/compiler/node.h" #include "src/compiler/node-properties.h" +#include "src/compiler/node.h" #include "src/compiler/operator-properties.h" #include "src/compiler/simplified-operator.h" #include "src/compiler/state-values-utils.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { @@ -38,6 +39,7 @@ class AllocationBuilder final { // Primitive allocation of static size. void Allocate(int size, PretenureFlag pretenure = NOT_TENURED, Type* type = Type::Any()) { + DCHECK_LE(size, kMaxRegularHeapObjectSize); effect_ = graph()->NewNode( common()->BeginRegion(RegionObservability::kNotObservable), effect_); allocation_ = @@ -161,7 +163,9 @@ bool IsFastLiteral(Handle<JSObject> boilerplate, int max_depth, } } } - } else if (!boilerplate->HasFastDoubleElements()) { + } else if (boilerplate->HasFastDoubleElements()) { + if (elements->Size() > kMaxRegularHeapObjectSize) return false; + } else { return false; } } @@ -176,7 +180,8 @@ bool IsFastLiteral(Handle<JSObject> boilerplate, int max_depth, int limit = boilerplate->map()->NumberOfOwnDescriptors(); for (int i = 0; i < limit; i++) { PropertyDetails details = descriptors->GetDetails(i); - if (details.type() != DATA) continue; + if (details.location() != kField) continue; + DCHECK_EQ(kData, details.kind()); if ((*max_properties)-- == 0) return false; FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i); if (boilerplate->IsUnboxedDoubleField(field_index)) continue; @@ -206,8 +211,6 @@ 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: @@ -236,6 +239,7 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) { Node* const new_target = NodeProperties::GetValueInput(node, 1); Type* const new_target_type = NodeProperties::GetType(new_target); Node* const effect = NodeProperties::GetEffectInput(node); + Node* const control = NodeProperties::GetControlInput(node); // Extract constructor and original constructor function. if (target_type->IsHeapConstant() && new_target_type->IsHeapConstant() && new_target_type->AsHeapConstant()->Value()->IsJSFunction()) { @@ -263,7 +267,7 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) { // Emit code to allocate the JSObject instance for the // {original_constructor}. - AllocationBuilder a(jsgraph(), effect, graph()->start()); + AllocationBuilder a(jsgraph(), effect, control); a.Allocate(instance_size); a.Store(AccessBuilder::ForMap(), initial_map); a.Store(AccessBuilder::ForJSObjectProperties(), @@ -274,6 +278,7 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) { a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i), jsgraph()->UndefinedConstant()); } + RelaxControls(node); a.FinishAndChange(node); return Changed(node); } @@ -294,46 +299,130 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) { if (outer_state->opcode() != IrOpcode::kFrameState) { switch (type) { case CreateArgumentsType::kMappedArguments: { - // TODO(mstarzinger): Duplicate parameters are not handled yet. + // TODO(bmeurer): Make deoptimization mandatory for the various + // arguments objects, so that we always have a shared_info here. Handle<SharedFunctionInfo> shared_info; - if (!state_info.shared_info().ToHandle(&shared_info) || - shared_info->has_duplicate_parameters()) { - return NoChange(); + if (state_info.shared_info().ToHandle(&shared_info)) { + // TODO(mstarzinger): Duplicate parameters are not handled yet. + if (shared_info->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_info->internal_formal_parameter_count() == 0) { + Node* const callee = NodeProperties::GetValueInput(node, 0); + Node* effect = NodeProperties::GetEffectInput(node); + // Allocate the elements backing store. + Node* const elements = effect = graph()->NewNode( + simplified()->NewUnmappedArgumentsElements(0), effect); + Node* const length = effect = graph()->NewNode( + simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), + elements, effect, control); + // 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::ForJSObjectProperties(), properties); + a.Store(AccessBuilder::ForJSObjectElements(), elements); + a.Store(AccessBuilder::ForArgumentsLength(), length); + a.Store(AccessBuilder::ForArgumentsCallee(), callee); + RelaxControls(node); + a.FinishAndChange(node); + } else { + Callable callable = CodeFactory::FastNewSloppyArguments(isolate()); + 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); + } + return Changed(node); } - Callable callable = CodeFactory::FastNewSloppyArguments(isolate()); - 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); - return Changed(node); + return NoChange(); } case CreateArgumentsType::kUnmappedArguments: { - Callable callable = CodeFactory::FastNewStrictArguments(isolate()); - Operator::Properties properties = node->op()->properties(); - CallDescriptor* desc = Linkage::GetStubCallDescriptor( - isolate(), graph()->zone(), callable.descriptor(), 0, - CallDescriptor::kNeedsFrameState, properties); - const Operator* new_op = common()->Call(desc); - Node* stub_code = jsgraph()->HeapConstant(callable.code()); - node->InsertInput(graph()->zone(), 0, stub_code); - NodeProperties::ChangeOp(node, new_op); + Handle<SharedFunctionInfo> shared_info; + if (state_info.shared_info().ToHandle(&shared_info)) { + Node* effect = NodeProperties::GetEffectInput(node); + // Allocate the elements backing store. + Node* const elements = effect = graph()->NewNode( + simplified()->NewUnmappedArgumentsElements( + shared_info->internal_formal_parameter_count()), + effect); + Node* const length = effect = graph()->NewNode( + simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), + elements, effect, control); + // Load the arguments object map. + Node* const arguments_map = jsgraph()->HeapConstant( + handle(native_context()->strict_arguments_map(), isolate())); + // Actually allocate and initialize the arguments object. + AllocationBuilder a(jsgraph(), effect, control); + Node* properties = jsgraph()->EmptyFixedArrayConstant(); + STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize); + a.Allocate(JSStrictArgumentsObject::kSize); + a.Store(AccessBuilder::ForMap(), arguments_map); + a.Store(AccessBuilder::ForJSObjectProperties(), properties); + a.Store(AccessBuilder::ForJSObjectElements(), elements); + a.Store(AccessBuilder::ForArgumentsLength(), length); + RelaxControls(node); + a.FinishAndChange(node); + } else { + Callable callable = CodeFactory::FastNewStrictArguments(isolate()); + Operator::Properties properties = node->op()->properties(); + CallDescriptor* desc = Linkage::GetStubCallDescriptor( + isolate(), graph()->zone(), callable.descriptor(), 0, + CallDescriptor::kNeedsFrameState, properties); + const Operator* new_op = common()->Call(desc); + Node* stub_code = jsgraph()->HeapConstant(callable.code()); + node->InsertInput(graph()->zone(), 0, stub_code); + NodeProperties::ChangeOp(node, new_op); + } return Changed(node); } case CreateArgumentsType::kRestParameter: { - Callable callable = CodeFactory::FastNewRestParameter(isolate()); - Operator::Properties properties = node->op()->properties(); - CallDescriptor* desc = Linkage::GetStubCallDescriptor( - isolate(), graph()->zone(), callable.descriptor(), 0, - CallDescriptor::kNeedsFrameState, properties); - const Operator* new_op = common()->Call(desc); - Node* stub_code = jsgraph()->HeapConstant(callable.code()); - node->InsertInput(graph()->zone(), 0, stub_code); - NodeProperties::ChangeOp(node, new_op); + Handle<SharedFunctionInfo> shared_info; + if (state_info.shared_info().ToHandle(&shared_info)) { + Node* effect = NodeProperties::GetEffectInput(node); + // Allocate the elements backing store. + Node* const elements = effect = graph()->NewNode( + simplified()->NewRestParameterElements( + shared_info->internal_formal_parameter_count()), + effect); + Node* const length = effect = graph()->NewNode( + simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), + elements, effect, control); + // Load the JSArray object map. + Node* const jsarray_map = jsgraph()->HeapConstant(handle( + native_context()->js_array_fast_elements_map_index(), isolate())); + // Actually allocate and initialize the jsarray. + AllocationBuilder a(jsgraph(), effect, control); + Node* properties = jsgraph()->EmptyFixedArrayConstant(); + STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); + a.Allocate(JSArray::kSize); + a.Store(AccessBuilder::ForMap(), jsarray_map); + a.Store(AccessBuilder::ForJSObjectProperties(), properties); + a.Store(AccessBuilder::ForJSObjectElements(), elements); + a.Store(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS), length); + RelaxControls(node); + a.FinishAndChange(node); + } else { + Callable callable = CodeFactory::FastNewRestParameter(isolate()); + Operator::Properties properties = node->op()->properties(); + CallDescriptor* desc = Linkage::GetStubCallDescriptor( + isolate(), graph()->zone(), callable.descriptor(), 0, + CallDescriptor::kNeedsFrameState, properties); + const Operator* new_op = common()->Call(desc); + Node* stub_code = jsgraph()->HeapConstant(callable.code()); + node->InsertInput(graph()->zone(), 0, stub_code); + NodeProperties::ChangeOp(node, new_op); + } return Changed(node); } } @@ -662,43 +751,6 @@ Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) { 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); - int const function_map_index = - Context::FunctionMapIndex(shared->language_mode(), shared->kind()); - Node* function_map = jsgraph()->HeapConstant( - handle(Map::cast(native_context()->get(function_map_index)), isolate())); - // 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()->PointerConstant( - jsgraph()->isolate()->builtins()->CompileLazy()->entry()); - Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant(); - Node* empty_literals_array = jsgraph()->EmptyLiteralsArrayConstant(); - 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_literals_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); -} - Reduction JSCreateLowering::ReduceJSCreateIterResultObject(Node* node) { DCHECK_EQ(IrOpcode::kJSCreateIterResultObject, node->opcode()); Node* value = NodeProperties::GetValueInput(node, 0); @@ -760,9 +812,10 @@ Reduction JSCreateLowering::ReduceJSCreateLiteral(Node* node) { Node* effect = NodeProperties::GetEffectInput(node); Node* control = NodeProperties::GetControlInput(node); - Handle<LiteralsArray> literals_array; - if (GetSpecializationLiterals(node).ToHandle(&literals_array)) { - Handle<Object> literal(literals_array->literal(p.index()), isolate()); + 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(JSObject::cast(site->transition_info()), @@ -785,7 +838,10 @@ Reduction JSCreateLowering::ReduceJSCreateLiteral(Node* node) { Reduction JSCreateLowering::ReduceJSCreateFunctionContext(Node* node) { DCHECK_EQ(IrOpcode::kJSCreateFunctionContext, node->opcode()); - int slot_count = OpParameter<int>(node->op()); + const CreateFunctionContextParameters& parameters = + CreateFunctionContextParametersOf(node->op()); + int slot_count = parameters.slot_count(); + ScopeType scope_type = parameters.scope_type(); Node* const closure = NodeProperties::GetValueInput(node, 0); // Use inline allocation for function contexts up to a size limit. @@ -798,7 +854,18 @@ Reduction JSCreateLowering::ReduceJSCreateFunctionContext(Node* node) { AllocationBuilder a(jsgraph(), effect, control); STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. int context_length = slot_count + Context::MIN_CONTEXT_SLOTS; - a.AllocateArray(context_length, factory()->function_context_map()); + Handle<Map> map; + switch (scope_type) { + case EVAL_SCOPE: + map = factory()->eval_context_map(); + break; + case FUNCTION_SCOPE: + map = factory()->function_context_map(); + break; + default: + UNREACHABLE(); + } + a.AllocateArray(context_length, map); a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure); a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context); a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension); @@ -929,6 +996,7 @@ Node* JSCreateLowering::AllocateArguments(Node* effect, Node* control, AllocationBuilder a(jsgraph(), effect, control); a.AllocateArray(argument_count, factory()->fixed_array_map()); for (int i = 0; i < argument_count; ++i, ++parameters_it) { + DCHECK_NOT_NULL((*parameters_it).node); a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node); } return a.Finish(); @@ -958,6 +1026,7 @@ Node* JSCreateLowering::AllocateRestArguments(Node* effect, Node* control, AllocationBuilder a(jsgraph(), effect, control); a.AllocateArray(num_elements, factory()->fixed_array_map()); for (int i = 0; i < num_elements; ++i, ++parameters_it) { + DCHECK_NOT_NULL((*parameters_it).node); a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node); } return a.Finish(); @@ -987,18 +1056,19 @@ Node* JSCreateLowering::AllocateAliasedArguments( // Prepare an iterator over argument values recorded in the frame state. Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); StateValuesAccess parameters_access(parameters); - auto paratemers_it = ++parameters_access.begin(); + auto parameters_it = ++parameters_access.begin(); // The unmapped argument values recorded in the frame state are stored yet // another indirection away and then linked into the parameter map below, // whereas mapped argument values are replaced with a hole instead. AllocationBuilder aa(jsgraph(), effect, control); aa.AllocateArray(argument_count, factory()->fixed_array_map()); - for (int i = 0; i < mapped_count; ++i, ++paratemers_it) { + for (int i = 0; i < mapped_count; ++i, ++parameters_it) { aa.Store(AccessBuilder::ForFixedArraySlot(i), jsgraph()->TheHoleConstant()); } - for (int i = mapped_count; i < argument_count; ++i, ++paratemers_it) { - aa.Store(AccessBuilder::ForFixedArraySlot(i), (*paratemers_it).node); + for (int i = mapped_count; i < argument_count; ++i, ++parameters_it) { + DCHECK_NOT_NULL((*parameters_it).node); + aa.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node); } Node* arguments = aa.Finish(); @@ -1081,13 +1151,15 @@ Node* JSCreateLowering::AllocateFastLiteral( for (int i = 0; i < boilerplate_nof; ++i) { PropertyDetails const property_details = boilerplate_map->instance_descriptors()->GetDetails(i); - if (property_details.type() != DATA) continue; + if (property_details.location() != kField) continue; + DCHECK_EQ(kData, property_details.kind()); Handle<Name> property_name( boilerplate_map->instance_descriptors()->GetKey(i), isolate()); FieldIndex index = FieldIndex::ForDescriptor(*boilerplate_map, i); - FieldAccess access = { - kTaggedBase, index.offset(), property_name, - Type::Any(), MachineType::AnyTagged(), kFullWriteBarrier}; + FieldAccess access = {kTaggedBase, index.offset(), + property_name, MaybeHandle<Map>(), + Type::Any(), MachineType::AnyTagged(), + kFullWriteBarrier}; Node* value; if (boilerplate->IsUnboxedDoubleField(index)) { access.machine_type = MachineType::Float64(); @@ -1104,23 +1176,15 @@ Node* JSCreateLowering::AllocateFastLiteral( boilerplate_object, site_context); site_context->ExitScope(current_site, boilerplate_object); } else if (property_details.representation().IsDouble()) { + double number = Handle<HeapNumber>::cast(boilerplate_value)->value(); // Allocate a mutable HeapNumber box and store the value into it. - effect = graph()->NewNode( - common()->BeginRegion(RegionObservability::kNotObservable), effect); - value = effect = graph()->NewNode( - simplified()->Allocate(pretenure), - jsgraph()->Constant(HeapNumber::kSize), effect, control); - effect = graph()->NewNode( - simplified()->StoreField(AccessBuilder::ForMap()), value, - jsgraph()->HeapConstant(factory()->mutable_heap_number_map()), - effect, control); - effect = graph()->NewNode( - simplified()->StoreField(AccessBuilder::ForHeapNumberValue()), - value, jsgraph()->Constant( - Handle<HeapNumber>::cast(boilerplate_value)->value()), - effect, control); - value = effect = - graph()->NewNode(common()->FinishRegion(), value, effect); + AllocationBuilder builder(jsgraph(), effect, control); + builder.Allocate(HeapNumber::kSize, pretenure); + builder.Store(AccessBuilder::ForMap(), + factory()->mutable_heap_number_map()); + builder.Store(AccessBuilder::ForHeapNumberValue(), + jsgraph()->Constant(number)); + value = effect = builder.Finish(); } else if (property_details.representation().IsSmi()) { // Ensure that value is stored as smi. value = boilerplate_value->IsUninitialized(isolate()) @@ -1156,7 +1220,7 @@ Node* JSCreateLowering::AllocateFastLiteral( AccessBuilder::ForJSArrayLength(boilerplate_array->GetElementsKind()), handle(boilerplate_array->length(), isolate())); } - for (auto const inobject_field : inobject_fields) { + for (auto const& inobject_field : inobject_fields) { builder.Store(inobject_field.first, inobject_field.second); } return builder.Finish(); @@ -1242,13 +1306,13 @@ Node* JSCreateLowering::AllocateFastLiteralElements( return builder.Finish(); } -MaybeHandle<LiteralsArray> JSCreateLowering::GetSpecializationLiterals( +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)->literals()); + return handle(Handle<JSFunction>::cast(object)->feedback_vector()); } case IrOpcode::kParameter: { int const index = ParameterIndexOf(closure->op()); @@ -1256,14 +1320,14 @@ MaybeHandle<LiteralsArray> JSCreateLowering::GetSpecializationLiterals( // {Parameter} indices start at -1, so value outputs of {Start} look like // this: closure, receiver, param0, ..., paramN, context. if (index == -1) { - return literals_array_; + return feedback_vector_; } break; } default: break; } - return MaybeHandle<LiteralsArray>(); + return MaybeHandle<FeedbackVector>(); } Factory* JSCreateLowering::factory() const { return isolate()->factory(); } |