diff options
Diffstat (limited to 'deps/v8/src/compiler/serializer-for-background-compilation.cc')
-rw-r--r-- | deps/v8/src/compiler/serializer-for-background-compilation.cc | 850 |
1 files changed, 531 insertions, 319 deletions
diff --git a/deps/v8/src/compiler/serializer-for-background-compilation.cc b/deps/v8/src/compiler/serializer-for-background-compilation.cc index 20d405b775..0391e8742d 100644 --- a/deps/v8/src/compiler/serializer-for-background-compilation.cc +++ b/deps/v8/src/compiler/serializer-for-background-compilation.cc @@ -10,7 +10,9 @@ #include "src/compiler/access-info.h" #include "src/compiler/bytecode-analysis.h" #include "src/compiler/compilation-dependencies.h" +#include "src/compiler/functional-list.h" #include "src/compiler/js-heap-broker.h" +#include "src/compiler/zone-stats.h" #include "src/handles/handles-inl.h" #include "src/ic/call-optimization.h" #include "src/interpreter/bytecode-array-iterator.h" @@ -41,7 +43,6 @@ namespace compiler { V(CallRuntime) \ V(CloneObject) \ V(CreateArrayFromIterable) \ - V(CreateEmptyArrayLiteral) \ V(CreateEmptyObjectLiteral) \ V(CreateMappedArguments) \ V(CreateRestParameter) \ @@ -160,6 +161,7 @@ namespace compiler { V(CreateBlockContext) \ V(CreateCatchContext) \ V(CreateClosure) \ + V(CreateEmptyArrayLiteral) \ V(CreateEvalContext) \ V(CreateFunctionContext) \ V(CreateObjectLiteral) \ @@ -230,13 +232,41 @@ namespace compiler { UNCONDITIONAL_JUMPS_LIST(V) \ UNREACHABLE_BYTECODE_LIST(V) -template <typename T> -struct HandleComparator { - bool operator()(const Handle<T>& lhs, const Handle<T>& rhs) const { - return lhs.address() < rhs.address(); +template <typename T, typename EqualTo> +class FunctionalSet { + public: + void Add(T const& elem, Zone* zone) { + for (auto const& l : data_) { + if (equal_to(l, elem)) return; + } + data_.PushFront(elem, zone); + } + + bool Includes(FunctionalSet<T, EqualTo> const& other) const { + return std::all_of(other.begin(), other.end(), [&](T const& other_elem) { + return std::any_of(this->begin(), this->end(), [&](T const& this_elem) { + return equal_to(this_elem, other_elem); + }); + }); } + + bool IsEmpty() const { return data_.begin() == data_.end(); } + + void Clear() { data_.Clear(); } + + using iterator = typename FunctionalList<T>::iterator; + + iterator begin() const { return data_.begin(); } + iterator end() const { return data_.end(); } + + private: + static EqualTo equal_to; + FunctionalList<T> data_; }; +template <typename T, typename EqualTo> +EqualTo FunctionalSet<T, EqualTo>::equal_to; + struct VirtualContext { unsigned int distance; Handle<Context> context; @@ -245,21 +275,22 @@ struct VirtualContext { : distance(distance_in), context(context_in) { CHECK_GT(distance, 0); } - bool operator<(const VirtualContext& other) const { - return HandleComparator<Context>()(context, other.context) && - distance < other.distance; + bool operator==(const VirtualContext& other) const { + return context.equals(other.context) && distance == other.distance; } }; class FunctionBlueprint; -using ConstantsSet = ZoneSet<Handle<Object>, HandleComparator<Object>>; -using VirtualContextsSet = ZoneSet<VirtualContext>; -using MapsSet = ZoneSet<Handle<Map>, HandleComparator<Map>>; -using BlueprintsSet = ZoneSet<FunctionBlueprint>; +using ConstantsSet = FunctionalSet<Handle<Object>, Handle<Object>::equal_to>; +using VirtualContextsSet = + FunctionalSet<VirtualContext, std::equal_to<VirtualContext>>; +using MapsSet = FunctionalSet<Handle<Map>, Handle<Map>::equal_to>; +using BlueprintsSet = + FunctionalSet<FunctionBlueprint, std::equal_to<FunctionBlueprint>>; class Hints { public: - explicit Hints(Zone* zone); + Hints() = default; static Hints SingleConstant(Handle<Object> constant, Zone* zone); @@ -268,12 +299,13 @@ class Hints { const BlueprintsSet& function_blueprints() const; const VirtualContextsSet& virtual_contexts() const; - void AddConstant(Handle<Object> constant); - void AddMap(Handle<Map> map); - void AddFunctionBlueprint(FunctionBlueprint function_blueprint); - void AddVirtualContext(VirtualContext virtual_context); + void AddConstant(Handle<Object> constant, Zone* zone); + void AddMap(Handle<Map> map, Zone* zone); + void AddFunctionBlueprint(FunctionBlueprint function_blueprint, Zone* zone); + void AddVirtualContext(VirtualContext virtual_context, Zone* zone); - void Add(const Hints& other); + void Add(const Hints& other, Zone* zone); + void AddFromChildSerializer(const Hints& other, Zone* zone); void Clear(); bool IsEmpty() const; @@ -292,6 +324,8 @@ class Hints { using HintsVector = ZoneVector<Hints>; +// A FunctionBlueprint is a SharedFunctionInfo and a FeedbackVector, plus +// Hints about the context in which a closure will be created from them. class FunctionBlueprint { public: FunctionBlueprint(Handle<JSFunction> function, Isolate* isolate, Zone* zone); @@ -304,13 +338,23 @@ class FunctionBlueprint { Handle<FeedbackVector> feedback_vector() const { return feedback_vector_; } const Hints& context_hints() const { return context_hints_; } - bool operator<(const FunctionBlueprint& other) const { - // A feedback vector is never used for more than one SFI, so it can - // be used for strict ordering of blueprints. + bool operator==(const FunctionBlueprint& other) const { + // A feedback vector is never used for more than one SFI. Moreover, we can + // never have two blueprints with identical feedback vector (and SFI) but + // different hints, because: + // (1) A blueprint originates either (i) from the data associated with a + // CreateClosure bytecode, in which case two different CreateClosure + // bytecodes never have the same feedback vector, or (ii) from a + // JSFunction, in which case the hints are determined by the closure. + // (2) We never extend a blueprint's hints after construction. + // + // It is therefore sufficient to look at the feedback vector in order to + // decide equality. DCHECK_IMPLIES(feedback_vector_.equals(other.feedback_vector_), shared_.equals(other.shared_)); - return HandleComparator<FeedbackVector>()(feedback_vector_, - other.feedback_vector_); + SLOW_DCHECK(!feedback_vector_.equals(other.feedback_vector_) || + context_hints_.Equals(other.context_hints_)); + return feedback_vector_.equals(other.feedback_vector_); } private: @@ -319,6 +363,8 @@ class FunctionBlueprint { Hints context_hints_; }; +// A CompilationSubject is a FunctionBlueprint, optionally with a matching +// closure. class CompilationSubject { public: explicit CompilationSubject(FunctionBlueprint blueprint) @@ -336,24 +382,65 @@ class CompilationSubject { MaybeHandle<JSFunction> closure_; }; +// A Callee is either a JSFunction (which may not have a feedback vector), or a +// FunctionBlueprint. Note that this is different from CompilationSubject, which +// always has a FunctionBlueprint. +class Callee { + public: + explicit Callee(Handle<JSFunction> jsfunction) : jsfunction_(jsfunction) {} + explicit Callee(FunctionBlueprint const& blueprint) : blueprint_(blueprint) {} + + Handle<SharedFunctionInfo> shared(Isolate* isolate) const { + return blueprint_.has_value() + ? blueprint_->shared() + : handle(jsfunction_.ToHandleChecked()->shared(), isolate); + } + + bool HasFeedbackVector() const { + Handle<JSFunction> function; + return blueprint_.has_value() || + jsfunction_.ToHandleChecked()->has_feedback_vector(); + } + + CompilationSubject ToCompilationSubject(Isolate* isolate, Zone* zone) const { + CHECK(HasFeedbackVector()); + return blueprint_.has_value() + ? CompilationSubject(*blueprint_) + : CompilationSubject(jsfunction_.ToHandleChecked(), isolate, + zone); + } + + private: + MaybeHandle<JSFunction> const jsfunction_; + base::Optional<FunctionBlueprint> const blueprint_; +}; + +// If a list of arguments (hints) is shorter than the function's parameter +// count, this enum expresses what we know about the missing arguments. +enum MissingArgumentsPolicy { + kMissingArgumentsAreUndefined, // ... as in the JS undefined value + kMissingArgumentsAreUnknown, +}; + // The SerializerForBackgroundCompilation makes sure that the relevant function // data such as bytecode, SharedFunctionInfo and FeedbackVector, used by later // optimizations in the compiler, is copied to the heap broker. class SerializerForBackgroundCompilation { public: SerializerForBackgroundCompilation( - JSHeapBroker* broker, CompilationDependencies* dependencies, Zone* zone, - Handle<JSFunction> closure, SerializerForBackgroundCompilationFlags flags, - BailoutId osr_offset); + ZoneStats* zone_stats, JSHeapBroker* broker, + CompilationDependencies* dependencies, Handle<JSFunction> closure, + SerializerForBackgroundCompilationFlags flags, BailoutId osr_offset); Hints Run(); // NOTE: Returns empty for an already-serialized function. class Environment; private: SerializerForBackgroundCompilation( - JSHeapBroker* broker, CompilationDependencies* dependencies, Zone* zone, - CompilationSubject function, base::Optional<Hints> new_target, - const HintsVector& arguments, + ZoneStats* zone_stats, JSHeapBroker* broker, + CompilationDependencies* dependencies, CompilationSubject function, + base::Optional<Hints> new_target, const HintsVector& arguments, + MissingArgumentsPolicy padding, SerializerForBackgroundCompilationFlags flags); bool BailoutOnUninitialized(ProcessedFeedback const& feedback); @@ -365,36 +452,39 @@ class SerializerForBackgroundCompilation { SUPPORTED_BYTECODE_LIST(DECLARE_VISIT_BYTECODE) #undef DECLARE_VISIT_BYTECODE - // Returns whether the callee with the given SFI should be processed further, - // i.e. whether it's inlineable. - bool ProcessSFIForCallOrConstruct(Handle<SharedFunctionInfo> shared, + void ProcessSFIForCallOrConstruct(Callee const& callee, + base::Optional<Hints> new_target, const HintsVector& arguments, - SpeculationMode speculation_mode); - // Returns whether {function} should be serialized for compilation. - bool ProcessCalleeForCallOrConstruct(Handle<JSFunction> function, + SpeculationMode speculation_mode, + MissingArgumentsPolicy padding); + void ProcessCalleeForCallOrConstruct(Handle<Object> callee, + base::Optional<Hints> new_target, const HintsVector& arguments, - SpeculationMode speculation_mode); + SpeculationMode speculation_mode, + MissingArgumentsPolicy padding); void ProcessCallOrConstruct(Hints callee, base::Optional<Hints> new_target, const HintsVector& arguments, FeedbackSlot slot, - bool with_spread = false); - void ProcessCallVarArgs(ConvertReceiverMode receiver_mode, - Hints const& callee, interpreter::Register first_reg, - int reg_count, FeedbackSlot slot, - bool with_spread = false); + MissingArgumentsPolicy padding); + void ProcessCallVarArgs( + ConvertReceiverMode receiver_mode, Hints const& callee, + interpreter::Register first_reg, int reg_count, FeedbackSlot slot, + MissingArgumentsPolicy padding = kMissingArgumentsAreUndefined); void ProcessApiCall(Handle<SharedFunctionInfo> target, const HintsVector& arguments); void ProcessReceiverMapForApiCall(FunctionTemplateInfoRef target, Handle<Map> receiver); void ProcessBuiltinCall(Handle<SharedFunctionInfo> target, + base::Optional<Hints> new_target, const HintsVector& arguments, - SpeculationMode speculation_mode); + SpeculationMode speculation_mode, + MissingArgumentsPolicy padding); void ProcessJump(interpreter::BytecodeArrayIterator* iterator); void ProcessKeyedPropertyAccess(Hints const& receiver, Hints const& key, FeedbackSlot slot, AccessMode access_mode, bool honor_bailout_on_uninitialized); - void ProcessNamedPropertyAccess(Hints receiver, NameRef const& name, + void ProcessNamedPropertyAccess(Hints const& receiver, NameRef const& name, FeedbackSlot slot, AccessMode access_mode); void ProcessNamedAccess(Hints receiver, NamedAccessFeedback const& feedback, AccessMode access_mode, Hints* new_accumulator_hints); @@ -411,7 +501,6 @@ class SerializerForBackgroundCompilation { void ProcessHintsForHasInPrototypeChain(Hints const& instance_hints); void ProcessHintsForRegExpTest(Hints const& regexp_hints); PropertyAccessInfo ProcessMapForRegExpTest(MapRef map); - void ProcessHintsForFunctionCall(Hints const& target_hints); void ProcessHintsForFunctionBind(Hints const& receiver_hints); void ProcessHintsForObjectGetPrototype(Hints const& object_hints); void ProcessConstantForOrdinaryHasInstance(HeapObjectRef const& constructor, @@ -456,7 +545,8 @@ class SerializerForBackgroundCompilation { Hints RunChildSerializer(CompilationSubject function, base::Optional<Hints> new_target, - const HintsVector& arguments, bool with_spread); + const HintsVector& arguments, + MissingArgumentsPolicy padding); // When (forward-)branching bytecodes are encountered, e.g. a conditional // jump, we call ContributeToJumpTargetEnvironment to "remember" the current @@ -475,14 +565,14 @@ class SerializerForBackgroundCompilation { JSHeapBroker* broker() const { return broker_; } CompilationDependencies* dependencies() const { return dependencies_; } - Zone* zone() const { return zone_; } + Zone* zone() { return zone_scope_.zone(); } Environment* environment() const { return environment_; } SerializerForBackgroundCompilationFlags flags() const { return flags_; } BailoutId osr_offset() const { return osr_offset_; } JSHeapBroker* const broker_; CompilationDependencies* const dependencies_; - Zone* const zone_; + ZoneStats::Scope zone_scope_; Environment* const environment_; ZoneUnorderedMap<int, Environment*> jump_target_environments_; SerializerForBackgroundCompilationFlags const flags_; @@ -490,11 +580,11 @@ class SerializerForBackgroundCompilation { }; void RunSerializerForBackgroundCompilation( - JSHeapBroker* broker, CompilationDependencies* dependencies, Zone* zone, - Handle<JSFunction> closure, SerializerForBackgroundCompilationFlags flags, - BailoutId osr_offset) { - SerializerForBackgroundCompilation serializer(broker, dependencies, zone, - closure, flags, osr_offset); + ZoneStats* zone_stats, JSHeapBroker* broker, + CompilationDependencies* dependencies, Handle<JSFunction> closure, + SerializerForBackgroundCompilationFlags flags, BailoutId osr_offset) { + SerializerForBackgroundCompilation serializer( + zone_stats, broker, dependencies, closure, flags, osr_offset); serializer.Run(); } @@ -505,14 +595,19 @@ FunctionBlueprint::FunctionBlueprint(Handle<SharedFunctionInfo> shared, const Hints& context_hints) : shared_(shared), feedback_vector_(feedback_vector), - context_hints_(context_hints) {} + context_hints_(context_hints) { + // The checked invariant rules out recursion and thus avoids complexity. + CHECK(context_hints_.function_blueprints().IsEmpty()); +} FunctionBlueprint::FunctionBlueprint(Handle<JSFunction> function, Isolate* isolate, Zone* zone) : shared_(handle(function->shared(), isolate)), - feedback_vector_(handle(function->feedback_vector(), isolate)), - context_hints_(zone) { - context_hints_.AddConstant(handle(function->context(), isolate)); + feedback_vector_(function->feedback_vector(), isolate), + context_hints_() { + context_hints_.AddConstant(handle(function->context(), isolate), zone); + // The checked invariant rules out recursion and thus avoids complexity. + CHECK(context_hints_.function_blueprints().IsEmpty()); } CompilationSubject::CompilationSubject(Handle<JSFunction> closure, @@ -521,25 +616,11 @@ CompilationSubject::CompilationSubject(Handle<JSFunction> closure, CHECK(closure->has_feedback_vector()); } -Hints::Hints(Zone* zone) - : virtual_contexts_(zone), - constants_(zone), - maps_(zone), - function_blueprints_(zone) {} - #ifdef ENABLE_SLOW_DCHECKS -namespace { -template <typename K, typename Compare> -bool SetIncludes(ZoneSet<K, Compare> const& lhs, - ZoneSet<K, Compare> const& rhs) { - return std::all_of(rhs.cbegin(), rhs.cend(), - [&](K const& x) { return lhs.find(x) != lhs.cend(); }); -} -} // namespace bool Hints::Includes(Hints const& other) const { - return SetIncludes(constants(), other.constants()) && - SetIncludes(function_blueprints(), other.function_blueprints()) && - SetIncludes(maps(), other.maps()); + return constants().Includes(other.constants()) && + function_blueprints().Includes(other.function_blueprints()) && + maps().Includes(other.maps()); } bool Hints::Equals(Hints const& other) const { return this->Includes(other) && other.Includes(*this); @@ -547,8 +628,8 @@ bool Hints::Equals(Hints const& other) const { #endif Hints Hints::SingleConstant(Handle<Object> constant, Zone* zone) { - Hints result(zone); - result.AddConstant(constant); + Hints result; + result.AddConstant(constant, zone); return result; } @@ -564,30 +645,49 @@ const VirtualContextsSet& Hints::virtual_contexts() const { return virtual_contexts_; } -void Hints::AddVirtualContext(VirtualContext virtual_context) { - virtual_contexts_.insert(virtual_context); +void Hints::AddVirtualContext(VirtualContext virtual_context, Zone* zone) { + virtual_contexts_.Add(virtual_context, zone); } -void Hints::AddConstant(Handle<Object> constant) { - constants_.insert(constant); +void Hints::AddConstant(Handle<Object> constant, Zone* zone) { + constants_.Add(constant, zone); } -void Hints::AddMap(Handle<Map> map) { maps_.insert(map); } +void Hints::AddMap(Handle<Map> map, Zone* zone) { maps_.Add(map, zone); } + +void Hints::AddFunctionBlueprint(FunctionBlueprint function_blueprint, + Zone* zone) { + function_blueprints_.Add(function_blueprint, zone); +} -void Hints::AddFunctionBlueprint(FunctionBlueprint function_blueprint) { - function_blueprints_.insert(function_blueprint); +void Hints::Add(const Hints& other, Zone* zone) { + for (auto x : other.constants()) AddConstant(x, zone); + for (auto x : other.maps()) AddMap(x, zone); + for (auto x : other.function_blueprints()) AddFunctionBlueprint(x, zone); + for (auto x : other.virtual_contexts()) AddVirtualContext(x, zone); } -void Hints::Add(const Hints& other) { - for (auto x : other.constants()) AddConstant(x); - for (auto x : other.maps()) AddMap(x); - for (auto x : other.function_blueprints()) AddFunctionBlueprint(x); - for (auto x : other.virtual_contexts()) AddVirtualContext(x); +void Hints::AddFromChildSerializer(const Hints& other, Zone* zone) { + for (auto x : other.constants()) AddConstant(x, zone); + for (auto x : other.maps()) AddMap(x, zone); + for (auto x : other.virtual_contexts()) AddVirtualContext(x, zone); + + // Adding hints from a child serializer run means copying data out from + // a zone that's being destroyed. FunctionBlueprints have zone allocated + // data, so we've got to make a deep copy to eliminate traces of the + // dying zone. + for (auto x : other.function_blueprints()) { + Hints new_blueprint_hints; + new_blueprint_hints.AddFromChildSerializer(x.context_hints(), zone); + FunctionBlueprint new_blueprint(x.shared(), x.feedback_vector(), + new_blueprint_hints); + AddFunctionBlueprint(new_blueprint, zone); + } } bool Hints::IsEmpty() const { - return constants().empty() && maps().empty() && - function_blueprints().empty() && virtual_contexts().empty(); + return constants().IsEmpty() && maps().IsEmpty() && + function_blueprints().IsEmpty() && virtual_contexts().IsEmpty(); } std::ostream& operator<<(std::ostream& out, @@ -625,10 +725,10 @@ std::ostream& operator<<(std::ostream& out, const Hints& hints) { } void Hints::Clear() { - virtual_contexts_.clear(); - constants_.clear(); - maps_.clear(); - function_blueprints_.clear(); + virtual_contexts_.Clear(); + constants_.Clear(); + maps_.Clear(); + function_blueprints_.Clear(); DCHECK(IsEmpty()); } @@ -636,7 +736,8 @@ class SerializerForBackgroundCompilation::Environment : public ZoneObject { public: Environment(Zone* zone, CompilationSubject function); Environment(Zone* zone, Isolate* isolate, CompilationSubject function, - base::Optional<Hints> new_target, const HintsVector& arguments); + base::Optional<Hints> new_target, const HintsVector& arguments, + MissingArgumentsPolicy padding); bool IsDead() const { return ephemeral_hints_.empty(); } @@ -648,7 +749,7 @@ class SerializerForBackgroundCompilation::Environment : public ZoneObject { void Revive() { DCHECK(IsDead()); - ephemeral_hints_.resize(ephemeral_hints_size(), Hints(zone())); + ephemeral_hints_.resize(ephemeral_hints_size(), Hints()); DCHECK(!IsDead()); } @@ -691,7 +792,6 @@ class SerializerForBackgroundCompilation::Environment : public ZoneObject { int RegisterToLocalIndex(interpreter::Register reg) const; - Zone* zone() const { return zone_; } int parameter_count() const { return parameter_count_; } int register_count() const { return register_count_; } @@ -722,24 +822,25 @@ SerializerForBackgroundCompilation::Environment::Environment( parameter_count_( function_.shared()->GetBytecodeArray().parameter_count()), register_count_(function_.shared()->GetBytecodeArray().register_count()), - closure_hints_(zone), - current_context_hints_(zone), - return_value_hints_(zone), - ephemeral_hints_(ephemeral_hints_size(), Hints(zone), zone) { + closure_hints_(), + current_context_hints_(), + return_value_hints_(), + ephemeral_hints_(ephemeral_hints_size(), Hints(), zone) { Handle<JSFunction> closure; if (function.closure().ToHandle(&closure)) { - closure_hints_.AddConstant(closure); + closure_hints_.AddConstant(closure, zone); } else { - closure_hints_.AddFunctionBlueprint(function.blueprint()); + closure_hints_.AddFunctionBlueprint(function.blueprint(), zone); } // Consume blueprint context hint information. - current_context_hints().Add(function.blueprint().context_hints()); + current_context_hints().Add(function.blueprint().context_hints(), zone); } SerializerForBackgroundCompilation::Environment::Environment( Zone* zone, Isolate* isolate, CompilationSubject function, - base::Optional<Hints> new_target, const HintsVector& arguments) + base::Optional<Hints> new_target, const HintsVector& arguments, + MissingArgumentsPolicy padding) : Environment(zone, function) { // Copy the hints for the actually passed arguments, at most up to // the parameter_count. @@ -748,11 +849,14 @@ SerializerForBackgroundCompilation::Environment::Environment( ephemeral_hints_[i] = arguments[i]; } - // Pad the rest with "undefined". - Hints undefined_hint = - Hints::SingleConstant(isolate->factory()->undefined_value(), zone); - for (size_t i = arguments.size(); i < param_count; ++i) { - ephemeral_hints_[i] = undefined_hint; + if (padding == kMissingArgumentsAreUndefined) { + Hints undefined_hint = + Hints::SingleConstant(isolate->factory()->undefined_value(), zone); + for (size_t i = arguments.size(); i < param_count; ++i) { + ephemeral_hints_[i] = undefined_hint; + } + } else { + DCHECK_EQ(padding, kMissingArgumentsAreUnknown); } interpreter::Register new_target_reg = @@ -762,7 +866,7 @@ SerializerForBackgroundCompilation::Environment::Environment( if (new_target_reg.is_valid()) { DCHECK(register_hints(new_target_reg).IsEmpty()); if (new_target.has_value()) { - register_hints(new_target_reg).Add(*new_target); + register_hints(new_target_reg).Add(*new_target, zone); } } } @@ -785,10 +889,10 @@ void SerializerForBackgroundCompilation::Environment::Merge( CHECK_EQ(ephemeral_hints_.size(), other->ephemeral_hints_.size()); for (size_t i = 0; i < ephemeral_hints_.size(); ++i) { - ephemeral_hints_[i].Add(other->ephemeral_hints_[i]); + ephemeral_hints_[i].Add(other->ephemeral_hints_[i], zone_); } - return_value_hints_.Add(other->return_value_hints_); + return_value_hints_.Add(other->return_value_hints_, zone_); } std::ostream& operator<<( @@ -845,30 +949,33 @@ int SerializerForBackgroundCompilation::Environment::RegisterToLocalIndex( } SerializerForBackgroundCompilation::SerializerForBackgroundCompilation( - JSHeapBroker* broker, CompilationDependencies* dependencies, Zone* zone, - Handle<JSFunction> closure, SerializerForBackgroundCompilationFlags flags, - BailoutId osr_offset) + ZoneStats* zone_stats, JSHeapBroker* broker, + CompilationDependencies* dependencies, Handle<JSFunction> closure, + SerializerForBackgroundCompilationFlags flags, BailoutId osr_offset) : broker_(broker), dependencies_(dependencies), - zone_(zone), - environment_(new (zone) Environment( - zone, CompilationSubject(closure, broker_->isolate(), zone))), - jump_target_environments_(zone), + zone_scope_(zone_stats, ZONE_NAME), + environment_(new (zone()) Environment( + zone(), CompilationSubject(closure, broker_->isolate(), zone()))), + jump_target_environments_(zone()), flags_(flags), osr_offset_(osr_offset) { JSFunctionRef(broker, closure).Serialize(); } SerializerForBackgroundCompilation::SerializerForBackgroundCompilation( - JSHeapBroker* broker, CompilationDependencies* dependencies, Zone* zone, - CompilationSubject function, base::Optional<Hints> new_target, - const HintsVector& arguments, SerializerForBackgroundCompilationFlags flags) + ZoneStats* zone_stats, JSHeapBroker* broker, + CompilationDependencies* dependencies, CompilationSubject function, + base::Optional<Hints> new_target, const HintsVector& arguments, + MissingArgumentsPolicy padding, + SerializerForBackgroundCompilationFlags flags) : broker_(broker), dependencies_(dependencies), - zone_(zone), - environment_(new (zone) Environment(zone, broker_->isolate(), function, - new_target, arguments)), - jump_target_environments_(zone), + zone_scope_(zone_stats, ZONE_NAME), + environment_(new (zone()) + Environment(zone(), broker_->isolate(), function, + new_target, arguments, padding)), + jump_target_environments_(zone()), flags_(flags), osr_offset_(BailoutId::None()) { TraceScope tracer( @@ -902,13 +1009,15 @@ bool SerializerForBackgroundCompilation::BailoutOnUninitialized( Hints SerializerForBackgroundCompilation::Run() { TraceScope tracer(broker(), this, "SerializerForBackgroundCompilation::Run"); + TRACE_BROKER_MEMORY(broker(), "[serializer start] Broker zone usage: " + << broker()->zone()->allocation_size()); SharedFunctionInfoRef shared(broker(), environment()->function().shared()); FeedbackVectorRef feedback_vector_ref(broker(), feedback_vector()); if (shared.IsSerializedForCompilation(feedback_vector_ref)) { TRACE_BROKER(broker(), "Already ran serializer for SharedFunctionInfo " << Brief(*shared.object()) << ", bailing out.\n"); - return Hints(zone()); + return Hints(); } shared.SetSerializedForCompilation(feedback_vector_ref); @@ -923,6 +1032,9 @@ Hints SerializerForBackgroundCompilation::Run() { feedback_vector_ref.Serialize(); TraverseBytecode(); + + TRACE_BROKER_MEMORY(broker(), "[serializer end] Broker zone usage: " + << broker()->zone()->allocation_size()); return environment()->return_value_hints(); } @@ -1036,12 +1148,19 @@ void SerializerForBackgroundCompilation::TraverseBytecode() { void SerializerForBackgroundCompilation::VisitGetIterator( BytecodeArrayIterator* iterator) { - AccessMode mode = AccessMode::kLoad; Hints const& receiver = environment()->register_hints(iterator->GetRegisterOperand(0)); Handle<Name> name = broker()->isolate()->factory()->iterator_symbol(); - FeedbackSlot slot = iterator->GetSlotOperand(1); - ProcessNamedPropertyAccess(receiver, NameRef(broker(), name), slot, mode); + FeedbackSlot load_slot = iterator->GetSlotOperand(1); + ProcessNamedPropertyAccess(receiver, NameRef(broker(), name), load_slot, + AccessMode::kLoad); + if (environment()->IsDead()) return; + + const Hints& callee = Hints(); + FeedbackSlot call_slot = iterator->GetSlotOperand(2); + HintsVector parameters({receiver}, zone()); + ProcessCallOrConstruct(callee, base::nullopt, parameters, call_slot, + kMissingArgumentsAreUndefined); } void SerializerForBackgroundCompilation::VisitGetSuperConstructor( @@ -1057,72 +1176,74 @@ void SerializerForBackgroundCompilation::VisitGetSuperConstructor( map.SerializePrototype(); ObjectRef proto = map.prototype(); if (proto.IsHeapObject() && proto.AsHeapObject().map().is_constructor()) { - environment()->register_hints(dst).AddConstant(proto.object()); + environment()->register_hints(dst).AddConstant(proto.object(), zone()); } } } void SerializerForBackgroundCompilation::VisitGetTemplateObject( BytecodeArrayIterator* iterator) { - ObjectRef description( + TemplateObjectDescriptionRef description( broker(), iterator->GetConstantForIndexOperand(0, broker()->isolate())); FeedbackSlot slot = iterator->GetSlotOperand(1); - FeedbackVectorRef feedback_vector_ref(broker(), feedback_vector()); + FeedbackSource source(feedback_vector(), slot); SharedFunctionInfoRef shared(broker(), environment()->function().shared()); - JSArrayRef template_object = - shared.GetTemplateObject(description, feedback_vector_ref, slot, - SerializationPolicy::kSerializeIfNeeded); + JSArrayRef template_object = shared.GetTemplateObject( + description, source, SerializationPolicy::kSerializeIfNeeded); environment()->accumulator_hints().Clear(); - environment()->accumulator_hints().AddConstant(template_object.object()); + environment()->accumulator_hints().AddConstant(template_object.object(), + zone()); } void SerializerForBackgroundCompilation::VisitLdaTrue( BytecodeArrayIterator* iterator) { environment()->accumulator_hints().Clear(); environment()->accumulator_hints().AddConstant( - broker()->isolate()->factory()->true_value()); + broker()->isolate()->factory()->true_value(), zone()); } void SerializerForBackgroundCompilation::VisitLdaFalse( BytecodeArrayIterator* iterator) { environment()->accumulator_hints().Clear(); environment()->accumulator_hints().AddConstant( - broker()->isolate()->factory()->false_value()); + broker()->isolate()->factory()->false_value(), zone()); } void SerializerForBackgroundCompilation::VisitLdaTheHole( BytecodeArrayIterator* iterator) { environment()->accumulator_hints().Clear(); environment()->accumulator_hints().AddConstant( - broker()->isolate()->factory()->the_hole_value()); + broker()->isolate()->factory()->the_hole_value(), zone()); } void SerializerForBackgroundCompilation::VisitLdaUndefined( BytecodeArrayIterator* iterator) { environment()->accumulator_hints().Clear(); environment()->accumulator_hints().AddConstant( - broker()->isolate()->factory()->undefined_value()); + broker()->isolate()->factory()->undefined_value(), zone()); } void SerializerForBackgroundCompilation::VisitLdaNull( BytecodeArrayIterator* iterator) { environment()->accumulator_hints().Clear(); environment()->accumulator_hints().AddConstant( - broker()->isolate()->factory()->null_value()); + broker()->isolate()->factory()->null_value(), zone()); } void SerializerForBackgroundCompilation::VisitLdaZero( BytecodeArrayIterator* iterator) { environment()->accumulator_hints().Clear(); environment()->accumulator_hints().AddConstant( - handle(Smi::FromInt(0), broker()->isolate())); + handle(Smi::FromInt(0), broker()->isolate()), zone()); } void SerializerForBackgroundCompilation::VisitLdaSmi( BytecodeArrayIterator* iterator) { environment()->accumulator_hints().Clear(); - environment()->accumulator_hints().AddConstant(handle( - Smi::FromInt(iterator->GetImmediateOperand(0)), broker()->isolate())); + environment()->accumulator_hints().AddConstant( + handle(Smi::FromInt(iterator->GetImmediateOperand(0)), + broker()->isolate()), + zone()); } void SerializerForBackgroundCompilation::VisitInvokeIntrinsic( @@ -1215,7 +1336,7 @@ void SerializerForBackgroundCompilation::VisitLdaConstant( ObjectRef object( broker(), iterator->GetConstantForIndexOperand(0, broker()->isolate())); environment()->accumulator_hints().Clear(); - environment()->accumulator_hints().AddConstant(object.object()); + environment()->accumulator_hints().AddConstant(object.object(), zone()); } void SerializerForBackgroundCompilation::VisitPushContext( @@ -1225,12 +1346,12 @@ void SerializerForBackgroundCompilation::VisitPushContext( Hints& saved_context_hints = environment()->register_hints(iterator->GetRegisterOperand(0)); saved_context_hints.Clear(); - saved_context_hints.Add(current_context_hints); + saved_context_hints.Add(current_context_hints, zone()); // New context is in the accumulator. Put those hints into the current context // register hints. current_context_hints.Clear(); - current_context_hints.Add(environment()->accumulator_hints()); + current_context_hints.Add(environment()->accumulator_hints(), zone()); } void SerializerForBackgroundCompilation::VisitPopContext( @@ -1239,7 +1360,7 @@ void SerializerForBackgroundCompilation::VisitPopContext( Hints& new_context_hints = environment()->register_hints(iterator->GetRegisterOperand(0)); environment()->current_context_hints().Clear(); - environment()->current_context_hints().Add(new_context_hints); + environment()->current_context_hints().Add(new_context_hints, zone()); } void SerializerForBackgroundCompilation::ProcessImmutableLoad( @@ -1251,7 +1372,7 @@ void SerializerForBackgroundCompilation::ProcessImmutableLoad( // If requested, record the object as a hint for the result value. if (result_hints != nullptr && slot_value.has_value()) { - result_hints->AddConstant(slot_value.value().object()); + result_hints->AddConstant(slot_value.value().object(), zone()); } } @@ -1294,11 +1415,11 @@ void SerializerForBackgroundCompilation::VisitLdaContextSlot( environment()->register_hints(iterator->GetRegisterOperand(0)); const int slot = iterator->GetIndexOperand(1); const int depth = iterator->GetUnsignedImmediateOperand(2); - Hints new_accumulator_hints(zone()); + Hints new_accumulator_hints; ProcessContextAccess(context_hints, slot, depth, kIgnoreSlot, &new_accumulator_hints); environment()->accumulator_hints().Clear(); - environment()->accumulator_hints().Add(new_accumulator_hints); + environment()->accumulator_hints().Add(new_accumulator_hints, zone()); } void SerializerForBackgroundCompilation::VisitLdaCurrentContextSlot( @@ -1306,11 +1427,11 @@ void SerializerForBackgroundCompilation::VisitLdaCurrentContextSlot( const int slot = iterator->GetIndexOperand(0); const int depth = 0; Hints const& context_hints = environment()->current_context_hints(); - Hints new_accumulator_hints(zone()); + Hints new_accumulator_hints; ProcessContextAccess(context_hints, slot, depth, kIgnoreSlot, &new_accumulator_hints); environment()->accumulator_hints().Clear(); - environment()->accumulator_hints().Add(new_accumulator_hints); + environment()->accumulator_hints().Add(new_accumulator_hints, zone()); } void SerializerForBackgroundCompilation::VisitLdaImmutableContextSlot( @@ -1319,11 +1440,11 @@ void SerializerForBackgroundCompilation::VisitLdaImmutableContextSlot( const int depth = iterator->GetUnsignedImmediateOperand(2); Hints const& context_hints = environment()->register_hints(iterator->GetRegisterOperand(0)); - Hints new_accumulator_hints(zone()); + Hints new_accumulator_hints; ProcessContextAccess(context_hints, slot, depth, kSerializeSlot, &new_accumulator_hints); environment()->accumulator_hints().Clear(); - environment()->accumulator_hints().Add(new_accumulator_hints); + environment()->accumulator_hints().Add(new_accumulator_hints, zone()); } void SerializerForBackgroundCompilation::VisitLdaImmutableCurrentContextSlot( @@ -1331,11 +1452,11 @@ void SerializerForBackgroundCompilation::VisitLdaImmutableCurrentContextSlot( const int slot = iterator->GetIndexOperand(0); const int depth = 0; Hints const& context_hints = environment()->current_context_hints(); - Hints new_accumulator_hints(zone()); + Hints new_accumulator_hints; ProcessContextAccess(context_hints, slot, depth, kSerializeSlot, &new_accumulator_hints); environment()->accumulator_hints().Clear(); - environment()->accumulator_hints().Add(new_accumulator_hints); + environment()->accumulator_hints().Add(new_accumulator_hints, zone()); } void SerializerForBackgroundCompilation::ProcessModuleVariableAccess( @@ -1344,7 +1465,7 @@ void SerializerForBackgroundCompilation::ProcessModuleVariableAccess( const int depth = iterator->GetUnsignedImmediateOperand(1); Hints const& context_hints = environment()->current_context_hints(); - Hints result_hints(zone()); + Hints result_hints; ProcessContextAccess(context_hints, slot, depth, kSerializeSlot, &result_hints); for (Handle<Object> constant : result_hints.constants()) { @@ -1392,14 +1513,15 @@ void SerializerForBackgroundCompilation::VisitLdar( BytecodeArrayIterator* iterator) { environment()->accumulator_hints().Clear(); environment()->accumulator_hints().Add( - environment()->register_hints(iterator->GetRegisterOperand(0))); + environment()->register_hints(iterator->GetRegisterOperand(0)), zone()); } void SerializerForBackgroundCompilation::VisitStar( BytecodeArrayIterator* iterator) { interpreter::Register reg = iterator->GetRegisterOperand(0); environment()->register_hints(reg).Clear(); - environment()->register_hints(reg).Add(environment()->accumulator_hints()); + environment()->register_hints(reg).Add(environment()->accumulator_hints(), + zone()); } void SerializerForBackgroundCompilation::VisitMov( @@ -1407,7 +1529,8 @@ void SerializerForBackgroundCompilation::VisitMov( interpreter::Register src = iterator->GetRegisterOperand(0); interpreter::Register dst = iterator->GetRegisterOperand(1); environment()->register_hints(dst).Clear(); - environment()->register_hints(dst).Add(environment()->register_hints(src)); + environment()->register_hints(dst).Add(environment()->register_hints(src), + zone()); } void SerializerForBackgroundCompilation::VisitCreateRegExpLiteral( @@ -1415,6 +1538,9 @@ void SerializerForBackgroundCompilation::VisitCreateRegExpLiteral( Handle<String> constant_pattern = Handle<String>::cast( iterator->GetConstantForIndexOperand(0, broker()->isolate())); StringRef description(broker(), constant_pattern); + FeedbackSlot slot = iterator->GetSlotOperand(1); + FeedbackSource source(feedback_vector(), slot); + broker()->ProcessFeedbackForRegExpLiteral(source); environment()->accumulator_hints().Clear(); } @@ -1425,6 +1551,17 @@ void SerializerForBackgroundCompilation::VisitCreateArrayLiteral( iterator->GetConstantForIndexOperand(0, broker()->isolate())); ArrayBoilerplateDescriptionRef description(broker(), array_boilerplate_description); + FeedbackSlot slot = iterator->GetSlotOperand(1); + FeedbackSource source(feedback_vector(), slot); + broker()->ProcessFeedbackForArrayOrObjectLiteral(source); + environment()->accumulator_hints().Clear(); +} + +void SerializerForBackgroundCompilation::VisitCreateEmptyArrayLiteral( + BytecodeArrayIterator* iterator) { + FeedbackSlot slot = iterator->GetSlotOperand(0); + FeedbackSource source(feedback_vector(), slot); + broker()->ProcessFeedbackForArrayOrObjectLiteral(source); environment()->accumulator_hints().Clear(); } @@ -1434,6 +1571,9 @@ void SerializerForBackgroundCompilation::VisitCreateObjectLiteral( Handle<ObjectBoilerplateDescription>::cast( iterator->GetConstantForIndexOperand(0, broker()->isolate())); ObjectBoilerplateDescriptionRef description(broker(), constant_properties); + FeedbackSlot slot = iterator->GetSlotOperand(1); + FeedbackSource source(feedback_vector(), slot); + broker()->ProcessFeedbackForArrayOrObjectLiteral(source); environment()->accumulator_hints().Clear(); } @@ -1490,7 +1630,8 @@ void SerializerForBackgroundCompilation::ProcessCreateContext( for (auto x : current_context_hints.constants()) { if (x->IsContext()) { Handle<Context> as_context(Handle<Context>::cast(x)); - accumulator_hints.AddVirtualContext(VirtualContext(1, as_context)); + accumulator_hints.AddVirtualContext(VirtualContext(1, as_context), + zone()); } } @@ -1498,7 +1639,7 @@ void SerializerForBackgroundCompilation::ProcessCreateContext( // it of distance {existing distance} + 1. for (auto x : current_context_hints.virtual_contexts()) { accumulator_hints.AddVirtualContext( - VirtualContext(x.distance + 1, x.context)); + VirtualContext(x.distance + 1, x.context), zone()); } } @@ -1518,7 +1659,7 @@ void SerializerForBackgroundCompilation::VisitCreateClosure( FunctionBlueprint blueprint(shared, Handle<FeedbackVector>::cast(cell_value), environment()->current_context_hints()); - environment()->accumulator_hints().AddFunctionBlueprint(blueprint); + environment()->accumulator_hints().AddFunctionBlueprint(blueprint, zone()); } } @@ -1542,7 +1683,8 @@ void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver0( Hints receiver = Hints::SingleConstant( broker()->isolate()->factory()->undefined_value(), zone()); HintsVector parameters({receiver}, zone()); - ProcessCallOrConstruct(callee, base::nullopt, parameters, slot); + ProcessCallOrConstruct(callee, base::nullopt, parameters, slot, + kMissingArgumentsAreUndefined); } void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver1( @@ -1556,7 +1698,8 @@ void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver1( Hints receiver = Hints::SingleConstant( broker()->isolate()->factory()->undefined_value(), zone()); HintsVector parameters({receiver, arg0}, zone()); - ProcessCallOrConstruct(callee, base::nullopt, parameters, slot); + ProcessCallOrConstruct(callee, base::nullopt, parameters, slot, + kMissingArgumentsAreUndefined); } void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver2( @@ -1572,7 +1715,8 @@ void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver2( Hints receiver = Hints::SingleConstant( broker()->isolate()->factory()->undefined_value(), zone()); HintsVector parameters({receiver, arg0, arg1}, zone()); - ProcessCallOrConstruct(callee, base::nullopt, parameters, slot); + ProcessCallOrConstruct(callee, base::nullopt, parameters, slot, + kMissingArgumentsAreUndefined); } void SerializerForBackgroundCompilation::VisitCallAnyReceiver( @@ -1616,7 +1760,8 @@ void SerializerForBackgroundCompilation::VisitCallProperty0( FeedbackSlot slot = iterator->GetSlotOperand(2); HintsVector parameters({receiver}, zone()); - ProcessCallOrConstruct(callee, base::nullopt, parameters, slot); + ProcessCallOrConstruct(callee, base::nullopt, parameters, slot, + kMissingArgumentsAreUndefined); } void SerializerForBackgroundCompilation::VisitCallProperty1( @@ -1630,7 +1775,8 @@ void SerializerForBackgroundCompilation::VisitCallProperty1( FeedbackSlot slot = iterator->GetSlotOperand(3); HintsVector parameters({receiver, arg0}, zone()); - ProcessCallOrConstruct(callee, base::nullopt, parameters, slot); + ProcessCallOrConstruct(callee, base::nullopt, parameters, slot, + kMissingArgumentsAreUndefined); } void SerializerForBackgroundCompilation::VisitCallProperty2( @@ -1646,7 +1792,8 @@ void SerializerForBackgroundCompilation::VisitCallProperty2( FeedbackSlot slot = iterator->GetSlotOperand(4); HintsVector parameters({receiver, arg0, arg1}, zone()); - ProcessCallOrConstruct(callee, base::nullopt, parameters, slot); + ProcessCallOrConstruct(callee, base::nullopt, parameters, slot, + kMissingArgumentsAreUndefined); } void SerializerForBackgroundCompilation::VisitCallWithSpread( @@ -1657,7 +1804,7 @@ void SerializerForBackgroundCompilation::VisitCallWithSpread( int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2)); FeedbackSlot slot = iterator->GetSlotOperand(3); ProcessCallVarArgs(ConvertReceiverMode::kAny, callee, first_reg, reg_count, - slot, true); + slot, kMissingArgumentsAreUnknown); } void SerializerForBackgroundCompilation::VisitCallJSRuntime( @@ -1677,61 +1824,45 @@ void SerializerForBackgroundCompilation::VisitCallJSRuntime( Hints SerializerForBackgroundCompilation::RunChildSerializer( CompilationSubject function, base::Optional<Hints> new_target, - const HintsVector& arguments, bool with_spread) { - if (with_spread) { - DCHECK_LT(0, arguments.size()); - // Pad the missing arguments in case we were called with spread operator. - // Drop the last actually passed argument, which contains the spread. - // We don't know what the spread element produces. Therefore we pretend - // that the function is called with the maximal number of parameters and - // that we have no information about the parameters that were not - // explicitly provided. - HintsVector padded = arguments; - padded.pop_back(); // Remove the spread element. - // Fill the rest with empty hints. - padded.resize( - function.blueprint().shared()->GetBytecodeArray().parameter_count(), - Hints(zone())); - return RunChildSerializer(function, new_target, padded, false); - } - + const HintsVector& arguments, MissingArgumentsPolicy padding) { SerializerForBackgroundCompilation child_serializer( - broker(), dependencies(), zone(), function, new_target, arguments, - flags()); - return child_serializer.Run(); -} - -bool SerializerForBackgroundCompilation::ProcessSFIForCallOrConstruct( - Handle<SharedFunctionInfo> shared, const HintsVector& arguments, - SpeculationMode speculation_mode) { + zone_scope_.zone_stats(), broker(), dependencies(), function, new_target, + arguments, padding, flags()); + // The Hints returned by the call to Run are allocated in the zone + // created by the child serializer. Adding those hints to a hints + // object created in our zone will preserve the information. + Hints hints; + hints.AddFromChildSerializer(child_serializer.Run(), zone()); + return hints; +} + +void SerializerForBackgroundCompilation::ProcessSFIForCallOrConstruct( + Callee const& callee, base::Optional<Hints> new_target, + const HintsVector& arguments, SpeculationMode speculation_mode, + MissingArgumentsPolicy padding) { + Handle<SharedFunctionInfo> shared = callee.shared(broker()->isolate()); if (shared->IsApiFunction()) { ProcessApiCall(shared, arguments); DCHECK(!shared->IsInlineable()); } else if (shared->HasBuiltinId()) { - ProcessBuiltinCall(shared, arguments, speculation_mode); + ProcessBuiltinCall(shared, new_target, arguments, speculation_mode, + padding); DCHECK(!shared->IsInlineable()); + } else if (shared->IsInlineable() && callee.HasFeedbackVector()) { + CompilationSubject subject = + callee.ToCompilationSubject(broker()->isolate(), zone()); + environment()->accumulator_hints().Add( + RunChildSerializer(subject, new_target, arguments, padding), zone()); } - return shared->IsInlineable(); -} - -bool SerializerForBackgroundCompilation::ProcessCalleeForCallOrConstruct( - Handle<JSFunction> function, const HintsVector& arguments, - SpeculationMode speculation_mode) { - JSFunctionRef(broker(), function).Serialize(); - - Handle<SharedFunctionInfo> shared(function->shared(), broker()->isolate()); - - return ProcessSFIForCallOrConstruct(shared, arguments, speculation_mode) && - function->has_feedback_vector(); } namespace { -// Returns the innermost bound target, if it's a JSFunction and inserts -// all bound arguments and {original_arguments} into {expanded_arguments} -// in the appropriate order. -MaybeHandle<JSFunction> UnrollBoundFunction( - JSBoundFunctionRef const& bound_function, JSHeapBroker* broker, - const HintsVector& original_arguments, HintsVector* expanded_arguments) { +// Returns the innermost bound target and inserts all bound arguments and +// {original_arguments} into {expanded_arguments} in the appropriate order. +JSReceiverRef UnrollBoundFunction(JSBoundFunctionRef const& bound_function, + JSHeapBroker* broker, + const HintsVector& original_arguments, + HintsVector* expanded_arguments) { DCHECK(expanded_arguments->empty()); JSReceiverRef target = bound_function.AsJSReceiver(); @@ -1750,8 +1881,6 @@ MaybeHandle<JSFunction> UnrollBoundFunction( reversed_bound_arguments.push_back(arg); } - if (!target.IsJSFunction()) return MaybeHandle<JSFunction>(); - expanded_arguments->insert(expanded_arguments->end(), reversed_bound_arguments.rbegin(), reversed_bound_arguments.rend()); @@ -1759,13 +1888,38 @@ MaybeHandle<JSFunction> UnrollBoundFunction( original_arguments.begin(), original_arguments.end()); - return target.AsJSFunction().object(); + return target; } } // namespace +void SerializerForBackgroundCompilation::ProcessCalleeForCallOrConstruct( + Handle<Object> callee, base::Optional<Hints> new_target, + const HintsVector& arguments, SpeculationMode speculation_mode, + MissingArgumentsPolicy padding) { + const HintsVector* actual_arguments = &arguments; + HintsVector expanded_arguments(zone()); + if (callee->IsJSBoundFunction()) { + JSBoundFunctionRef bound_function(broker(), + Handle<JSBoundFunction>::cast(callee)); + bound_function.Serialize(); + callee = UnrollBoundFunction(bound_function, broker(), arguments, + &expanded_arguments) + .object(); + actual_arguments = &expanded_arguments; + } + if (!callee->IsJSFunction()) return; + + JSFunctionRef function(broker(), Handle<JSFunction>::cast(callee)); + function.Serialize(); + Callee new_callee(function.object()); + ProcessSFIForCallOrConstruct(new_callee, new_target, *actual_arguments, + speculation_mode, padding); +} + void SerializerForBackgroundCompilation::ProcessCallOrConstruct( Hints callee, base::Optional<Hints> new_target, - const HintsVector& arguments, FeedbackSlot slot, bool with_spread) { + const HintsVector& arguments, FeedbackSlot slot, + MissingArgumentsPolicy padding) { SpeculationMode speculation_mode = SpeculationMode::kDisallowSpeculation; if (!slot.IsInvalid()) { FeedbackSource source(feedback_vector(), slot); @@ -1782,11 +1936,11 @@ void SerializerForBackgroundCompilation::ProcessCallOrConstruct( // site, and it may make sense to add the Array JSFunction constant. if (new_target.has_value()) { // Construct; feedback is new_target, which often is also the callee. - new_target->AddConstant(target->object()); - callee.AddConstant(target->object()); + new_target->AddConstant(target->object(), zone()); + callee.AddConstant(target->object(), zone()); } else { // Call; target is callee. - callee.AddConstant(target->object()); + callee.AddConstant(target->object(), zone()); } } } @@ -1795,50 +1949,22 @@ void SerializerForBackgroundCompilation::ProcessCallOrConstruct( environment()->accumulator_hints().Clear(); // For JSCallReducer::ReduceJSCall and JSCallReducer::ReduceJSConstruct. - for (auto hint : callee.constants()) { - const HintsVector* actual_arguments = &arguments; - Handle<JSFunction> function; - HintsVector expanded_arguments(zone()); - if (hint->IsJSBoundFunction()) { - JSBoundFunctionRef bound_function(broker(), - Handle<JSBoundFunction>::cast(hint)); - bound_function.Serialize(); - - MaybeHandle<JSFunction> maybe_function = UnrollBoundFunction( - bound_function, broker(), arguments, &expanded_arguments); - if (maybe_function.is_null()) continue; - function = maybe_function.ToHandleChecked(); - actual_arguments = &expanded_arguments; - } else if (hint->IsJSFunction()) { - function = Handle<JSFunction>::cast(hint); - } else { - continue; - } - - if (ProcessCalleeForCallOrConstruct(function, *actual_arguments, - speculation_mode)) { - environment()->accumulator_hints().Add(RunChildSerializer( - CompilationSubject(function, broker()->isolate(), zone()), new_target, - *actual_arguments, with_spread)); - } + for (auto constant : callee.constants()) { + ProcessCalleeForCallOrConstruct(constant, new_target, arguments, + speculation_mode, padding); } // For JSCallReducer::ReduceJSCall and JSCallReducer::ReduceJSConstruct. for (auto hint : callee.function_blueprints()) { - Handle<SharedFunctionInfo> shared = hint.shared(); - if (!ProcessSFIForCallOrConstruct(shared, arguments, speculation_mode)) { - continue; - } - - environment()->accumulator_hints().Add(RunChildSerializer( - CompilationSubject(hint), new_target, arguments, with_spread)); + ProcessSFIForCallOrConstruct(Callee(hint), new_target, arguments, + speculation_mode, padding); } } void SerializerForBackgroundCompilation::ProcessCallVarArgs( ConvertReceiverMode receiver_mode, Hints const& callee, interpreter::Register first_reg, int reg_count, FeedbackSlot slot, - bool with_spread) { + MissingArgumentsPolicy padding) { HintsVector arguments(zone()); // The receiver is either given in the first register or it is implicitly // the {undefined} value. @@ -1848,7 +1974,7 @@ void SerializerForBackgroundCompilation::ProcessCallVarArgs( } environment()->ExportRegisterHints(first_reg, reg_count, &arguments); - ProcessCallOrConstruct(callee, base::nullopt, arguments, slot); + ProcessCallOrConstruct(callee, base::nullopt, arguments, slot, padding); } void SerializerForBackgroundCompilation::ProcessApiCall( @@ -1866,17 +1992,17 @@ void SerializerForBackgroundCompilation::ProcessApiCall( FunctionTemplateInfoRef target_template_info( broker(), handle(target->function_data(), broker()->isolate())); if (!target_template_info.has_call_code()) return; - target_template_info.SerializeCallCode(); SharedFunctionInfoRef target_ref(broker(), target); target_ref.SerializeFunctionTemplateInfo(); if (target_template_info.accept_any_receiver() && - target_template_info.is_signature_undefined()) + target_template_info.is_signature_undefined()) { return; + } - CHECK_GE(arguments.size(), 1); + if (arguments.empty()) return; Hints const& receiver_hints = arguments[0]; for (auto hint : receiver_hints.constants()) { if (hint->IsUndefined()) { @@ -1920,8 +2046,9 @@ void SerializerForBackgroundCompilation::ProcessHintsForObjectCreate( } void SerializerForBackgroundCompilation::ProcessBuiltinCall( - Handle<SharedFunctionInfo> target, const HintsVector& arguments, - SpeculationMode speculation_mode) { + Handle<SharedFunctionInfo> target, base::Optional<Hints> new_target, + const HintsVector& arguments, SpeculationMode speculation_mode, + MissingArgumentsPolicy padding) { DCHECK(target->HasBuiltinId()); const int builtin_id = target->builtin_id(); const char* name = Builtins::name(builtin_id); @@ -1963,20 +2090,31 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall( case Builtins::kPromiseResolveTrampoline: // For JSCallReducer::ReducePromiseInternalResolve and // JSNativeContextSpecialization::ReduceJSResolvePromise. - if (arguments.size() >= 2) { - Hints const& resolution_hints = arguments[1]; + if (arguments.size() >= 1) { + Hints const& resolution_hints = + arguments.size() >= 2 + ? arguments[1] + : Hints::SingleConstant( + broker()->isolate()->factory()->undefined_value(), + zone()); ProcessHintsForPromiseResolve(resolution_hints); } break; case Builtins::kPromiseInternalResolve: // For JSCallReducer::ReducePromiseInternalResolve and // JSNativeContextSpecialization::ReduceJSResolvePromise. - if (arguments.size() >= 3) { - Hints const& resolution_hints = arguments[2]; + if (arguments.size() >= 2) { + Hints const& resolution_hints = + arguments.size() >= 3 + ? arguments[2] + : Hints::SingleConstant( + broker()->isolate()->factory()->undefined_value(), + zone()); ProcessHintsForPromiseResolve(resolution_hints); } break; case Builtins::kRegExpPrototypeTest: + case Builtins::kRegExpPrototypeTestFast: // For JSCallReducer::ReduceRegExpPrototypeTest. if (arguments.size() >= 1 && speculation_mode != SpeculationMode::kDisallowSpeculation) { @@ -1990,35 +2128,105 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall( case Builtins::kArrayPrototypeFind: case Builtins::kArrayPrototypeFindIndex: case Builtins::kArrayMap: + case Builtins::kArraySome: + if (arguments.size() >= 2 && + speculation_mode != SpeculationMode::kDisallowSpeculation) { + Hints const& callback = arguments[1]; + // "Call(callbackfn, T, « kValue, k, O »)" + HintsVector new_arguments(zone()); + new_arguments.push_back( + arguments.size() < 3 + ? Hints::SingleConstant( + broker()->isolate()->factory()->undefined_value(), zone()) + : arguments[2]); // T + new_arguments.push_back(Hints()); // kValue + new_arguments.push_back(Hints()); // k + new_arguments.push_back(arguments[0]); // O + for (auto constant : callback.constants()) { + ProcessCalleeForCallOrConstruct(constant, base::nullopt, + new_arguments, + SpeculationMode::kDisallowSpeculation, + kMissingArgumentsAreUndefined); + } + } + break; case Builtins::kArrayReduce: case Builtins::kArrayReduceRight: - case Builtins::kArraySome: if (arguments.size() >= 2 && speculation_mode != SpeculationMode::kDisallowSpeculation) { - Hints const& callback_hints = arguments[1]; - ProcessHintsForFunctionCall(callback_hints); + Hints const& callback = arguments[1]; + // "Call(callbackfn, undefined, « accumulator, kValue, k, O »)" + HintsVector new_arguments(zone()); + new_arguments.push_back(Hints::SingleConstant( + broker()->isolate()->factory()->undefined_value(), zone())); + new_arguments.push_back(Hints()); // accumulator + new_arguments.push_back(Hints()); // kValue + new_arguments.push_back(Hints()); // k + new_arguments.push_back(arguments[0]); // O + for (auto constant : callback.constants()) { + ProcessCalleeForCallOrConstruct(constant, base::nullopt, + new_arguments, + SpeculationMode::kDisallowSpeculation, + kMissingArgumentsAreUndefined); + } } break; + // TODO(neis): At least for Array* we should look at blueprints too. + // TODO(neis): Might need something like a FunctionBlueprint but for + // creating bound functions rather than creating closures. case Builtins::kFunctionPrototypeApply: - case Builtins::kFunctionPrototypeCall: + if (arguments.size() >= 1) { + // Drop hints for all arguments except the user-given receiver. + Hints new_receiver = + arguments.size() >= 2 + ? arguments[1] + : Hints::SingleConstant( + broker()->isolate()->factory()->undefined_value(), + zone()); + HintsVector new_arguments({new_receiver}, zone()); + for (auto constant : arguments[0].constants()) { + ProcessCalleeForCallOrConstruct(constant, base::nullopt, + new_arguments, + SpeculationMode::kDisallowSpeculation, + kMissingArgumentsAreUnknown); + } + } + break; case Builtins::kPromiseConstructor: - // TODO(mslekova): Since the reducer for all these introduce a - // JSCall/JSConstruct that will again get optimized by the JSCallReducer, - // we basically might have to do all the serialization that we do for that - // here as well. The only difference is that the new JSCall/JSConstruct - // has speculation disabled, causing the JSCallReducer to do much less - // work. To account for that, ProcessCallOrConstruct should have a way of - // taking the speculation mode as an argument rather than getting that - // from the feedback. (Also applies to Reflect.apply and - // Reflect.construct.) if (arguments.size() >= 1) { - ProcessHintsForFunctionCall(arguments[0]); + // "Call(executor, undefined, « resolvingFunctions.[[Resolve]], + // resolvingFunctions.[[Reject]] »)" + HintsVector new_arguments( + {Hints::SingleConstant( + broker()->isolate()->factory()->undefined_value(), zone())}, + zone()); + for (auto constant : arguments[0].constants()) { + ProcessCalleeForCallOrConstruct(constant, base::nullopt, + new_arguments, + SpeculationMode::kDisallowSpeculation, + kMissingArgumentsAreUnknown); + } + } + break; + case Builtins::kFunctionPrototypeCall: + if (arguments.size() >= 1) { + HintsVector new_arguments(arguments.begin() + 1, arguments.end(), + zone()); + for (auto constant : arguments[0].constants()) { + ProcessCalleeForCallOrConstruct( + constant, base::nullopt, new_arguments, + SpeculationMode::kDisallowSpeculation, padding); + } } break; case Builtins::kReflectApply: case Builtins::kReflectConstruct: if (arguments.size() >= 2) { - ProcessHintsForFunctionCall(arguments[1]); + for (auto constant : arguments[1].constants()) { + if (constant->IsJSFunction()) { + JSFunctionRef(broker(), constant).Serialize(); + } + } } break; case Builtins::kObjectPrototypeIsPrototypeOf: @@ -2181,13 +2389,6 @@ void SerializerForBackgroundCompilation::ProcessHintsForRegExpTest( } } -void SerializerForBackgroundCompilation::ProcessHintsForFunctionCall( - Hints const& target_hints) { - for (auto constant : target_hints.constants()) { - if (constant->IsJSFunction()) JSFunctionRef(broker(), constant).Serialize(); - } -} - namespace { void ProcessMapForFunctionBind(MapRef map) { map.SerializePrototype(); @@ -2195,8 +2396,9 @@ void ProcessMapForFunctionBind(MapRef map) { JSFunction::kNameDescriptorIndex) + 1; if (map.NumberOfOwnDescriptors() >= min_nof_descriptors) { - map.SerializeOwnDescriptor(JSFunction::kLengthDescriptorIndex); - map.SerializeOwnDescriptor(JSFunction::kNameDescriptorIndex); + map.SerializeOwnDescriptor( + InternalIndex(JSFunction::kLengthDescriptorIndex)); + map.SerializeOwnDescriptor(InternalIndex(JSFunction::kNameDescriptorIndex)); } } } // namespace @@ -2261,7 +2463,8 @@ void SerializerForBackgroundCompilation::ProcessJump( void SerializerForBackgroundCompilation::VisitReturn( BytecodeArrayIterator* iterator) { - environment()->return_value_hints().Add(environment()->accumulator_hints()); + environment()->return_value_hints().Add(environment()->accumulator_hints(), + zone()); environment()->ClearEphemeralHints(); } @@ -2301,7 +2504,8 @@ void SerializerForBackgroundCompilation::VisitConstruct( HintsVector arguments(zone()); environment()->ExportRegisterHints(first_reg, reg_count, &arguments); - ProcessCallOrConstruct(callee, new_target, arguments, slot); + ProcessCallOrConstruct(callee, new_target, arguments, slot, + kMissingArgumentsAreUndefined); } void SerializerForBackgroundCompilation::VisitConstructWithSpread( @@ -2315,8 +2519,10 @@ void SerializerForBackgroundCompilation::VisitConstructWithSpread( HintsVector arguments(zone()); environment()->ExportRegisterHints(first_reg, reg_count, &arguments); - - ProcessCallOrConstruct(callee, new_target, arguments, slot, true); + DCHECK(!arguments.empty()); + arguments.pop_back(); // Remove the spread element. + ProcessCallOrConstruct(callee, new_target, arguments, slot, + kMissingArgumentsAreUnknown); } void SerializerForBackgroundCompilation::ProcessGlobalAccess(FeedbackSlot slot, @@ -2333,7 +2539,7 @@ void SerializerForBackgroundCompilation::ProcessGlobalAccess(FeedbackSlot slot, base::Optional<ObjectRef> value = feedback.AsGlobalAccess().GetConstantHint(); if (value.has_value()) { - environment()->accumulator_hints().AddConstant(value->object()); + environment()->accumulator_hints().AddConstant(value->object(), zone()); } } else { DCHECK(feedback.IsInsufficient()); @@ -2480,9 +2686,16 @@ SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess( receiver_map.SerializeRootMap(); // For JSNativeContextSpecialization::ReduceNamedAccess. - if (receiver_map.IsMapOfTargetGlobalProxy()) { - broker()->target_native_context().global_proxy_object().GetPropertyCell( + JSGlobalProxyRef global_proxy = + broker()->target_native_context().global_proxy_object(); + JSGlobalObjectRef global_object = + broker()->target_native_context().global_object(); + if (receiver_map.equals(global_proxy.map())) { + base::Optional<PropertyCellRef> cell = global_object.GetPropertyCell( name, SerializationPolicy::kSerializeIfNeeded); + if (access_mode == AccessMode::kLoad && cell.has_value()) { + new_accumulator_hints->AddConstant(cell->value().object(), zone()); + } } PropertyAccessInfo access_info = broker()->GetPropertyAccessInfo( @@ -2515,6 +2728,10 @@ SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess( FunctionTemplateInfoRef fti(broker(), access_info.constant()); if (fti.has_call_code()) fti.SerializeCallCode(); } + } else if (access_info.IsModuleExport()) { + // For JSNativeContextSpecialization::BuildPropertyLoad + DCHECK(!access_info.constant().is_null()); + CellRef(broker(), access_info.constant()); } // For PropertyAccessBuilder::TryBuildLoadConstantDataField @@ -2535,7 +2752,7 @@ SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess( access_info.field_representation(), access_info.field_index(), SerializationPolicy::kSerializeIfNeeded)); if (constant.has_value()) { - new_accumulator_hints->AddConstant(constant->object()); + new_accumulator_hints->AddConstant(constant->object(), zone()); } } } @@ -2565,7 +2782,7 @@ void SerializerForBackgroundCompilation::ProcessKeyedPropertyAccess( return; } - Hints new_accumulator_hints(zone()); + Hints new_accumulator_hints; switch (feedback.kind()) { case ProcessedFeedback::kElementAccess: ProcessElementAccess(receiver, key, feedback.AsElementAccess(), @@ -2583,14 +2800,14 @@ void SerializerForBackgroundCompilation::ProcessKeyedPropertyAccess( if (access_mode == AccessMode::kLoad) { environment()->accumulator_hints().Clear(); - environment()->accumulator_hints().Add(new_accumulator_hints); + environment()->accumulator_hints().Add(new_accumulator_hints, zone()); } else { DCHECK(new_accumulator_hints.IsEmpty()); } } void SerializerForBackgroundCompilation::ProcessNamedPropertyAccess( - Hints receiver, NameRef const& name, FeedbackSlot slot, + Hints const& receiver, NameRef const& name, FeedbackSlot slot, AccessMode access_mode) { if (slot.IsInvalid() || feedback_vector().is_null()) return; FeedbackSource source(feedback_vector(), slot); @@ -2598,12 +2815,13 @@ void SerializerForBackgroundCompilation::ProcessNamedPropertyAccess( broker()->ProcessFeedbackForPropertyAccess(source, access_mode, name); if (BailoutOnUninitialized(feedback)) return; - Hints new_accumulator_hints(zone()); + Hints new_accumulator_hints; switch (feedback.kind()) { case ProcessedFeedback::kNamedAccess: DCHECK(name.equals(feedback.AsNamedAccess().name())); ProcessNamedAccess(receiver, feedback.AsNamedAccess(), access_mode, &new_accumulator_hints); + // TODO(neis): Propagate feedback maps to receiver hints. break; case ProcessedFeedback::kInsufficient: break; @@ -2613,7 +2831,7 @@ void SerializerForBackgroundCompilation::ProcessNamedPropertyAccess( if (access_mode == AccessMode::kLoad) { environment()->accumulator_hints().Clear(); - environment()->accumulator_hints().Add(new_accumulator_hints); + environment()->accumulator_hints().Add(new_accumulator_hints, zone()); } else { DCHECK(new_accumulator_hints.IsEmpty()); } @@ -2622,7 +2840,7 @@ void SerializerForBackgroundCompilation::ProcessNamedPropertyAccess( void SerializerForBackgroundCompilation::ProcessNamedAccess( Hints receiver, NamedAccessFeedback const& feedback, AccessMode access_mode, Hints* new_accumulator_hints) { - for (Handle<Map> map : feedback.AsNamedAccess().maps()) { + for (Handle<Map> map : feedback.maps()) { MapRef map_ref(broker(), map); ProcessMapForNamedPropertyAccess(map_ref, feedback.name(), access_mode, base::nullopt, new_accumulator_hints); @@ -2635,8 +2853,6 @@ void SerializerForBackgroundCompilation::ProcessNamedAccess( base::nullopt, new_accumulator_hints); } - JSGlobalProxyRef global_proxy = - broker()->target_native_context().global_proxy_object(); for (Handle<Object> hint : receiver.constants()) { ObjectRef object(broker(), hint); if (access_mode == AccessMode::kLoad && object.IsJSObject()) { @@ -2645,13 +2861,6 @@ void SerializerForBackgroundCompilation::ProcessNamedAccess( object.AsJSObject(), new_accumulator_hints); } - // For JSNativeContextSpecialization::ReduceNamedAccessFromNexus. - if (object.equals(global_proxy)) { - // TODO(neis): Record accumulator hint? Also for string.length and maybe - // more. - global_proxy.GetPropertyCell(feedback.name(), - SerializationPolicy::kSerializeIfNeeded); - } // For JSNativeContextSpecialization::ReduceJSLoadNamed. if (access_mode == AccessMode::kLoad && object.IsJSFunction() && feedback.name().equals(ObjectRef( @@ -2659,9 +2868,12 @@ void SerializerForBackgroundCompilation::ProcessNamedAccess( JSFunctionRef function = object.AsJSFunction(); function.Serialize(); if (new_accumulator_hints != nullptr && function.has_prototype()) { - new_accumulator_hints->AddConstant(function.prototype().object()); + new_accumulator_hints->AddConstant(function.prototype().object(), + zone()); } } + // TODO(neis): Also record accumulator hint for string.length and maybe + // more? } } @@ -2841,7 +3053,7 @@ void SerializerForBackgroundCompilation::VisitTestInstanceOf( environment()->register_hints(iterator->GetRegisterOperand(0)); Hints rhs = environment()->accumulator_hints(); FeedbackSlot slot = iterator->GetSlotOperand(1); - Hints new_accumulator_hints(zone()); + Hints new_accumulator_hints; if (slot.IsInvalid() || feedback_vector().is_null()) return; FeedbackSource source(feedback_vector(), slot); @@ -2853,7 +3065,7 @@ void SerializerForBackgroundCompilation::VisitTestInstanceOf( InstanceOfFeedback const& rhs_feedback = feedback.AsInstanceOf(); if (rhs_feedback.value().has_value()) { Handle<JSObject> constructor = rhs_feedback.value()->object(); - rhs.AddConstant(constructor); + rhs.AddConstant(constructor, zone()); } } @@ -2865,7 +3077,7 @@ void SerializerForBackgroundCompilation::VisitTestInstanceOf( if (walk_prototypes) ProcessHintsForHasInPrototypeChain(lhs); environment()->accumulator_hints().Clear(); - environment()->accumulator_hints().Add(new_accumulator_hints); + environment()->accumulator_hints().Add(new_accumulator_hints, zone()); } void SerializerForBackgroundCompilation::VisitToNumeric( |