LCOV - code coverage report
Current view: top level - src/compiler - serializer-for-background-compilation.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 282 395 71.4 %
Date: 2019-03-21 Functions: 45 132 34.1 %

          Line data    Source code
       1             : // Copyright 2018 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/compiler/serializer-for-background-compilation.h"
       6             : 
       7             : #include <sstream>
       8             : 
       9             : #include "src/compiler/js-heap-broker.h"
      10             : #include "src/handles-inl.h"
      11             : #include "src/interpreter/bytecode-array-iterator.h"
      12             : #include "src/objects/code.h"
      13             : #include "src/objects/shared-function-info-inl.h"
      14             : #include "src/vector-slot-pair.h"
      15             : #include "src/zone/zone.h"
      16             : 
      17             : namespace v8 {
      18             : namespace internal {
      19             : namespace compiler {
      20             : 
      21             : using BytecodeArrayIterator = interpreter::BytecodeArrayIterator;
      22             : 
      23         133 : CompilationSubject::CompilationSubject(Handle<JSFunction> closure,
      24             :                                        Isolate* isolate)
      25             :     : blueprint_{handle(closure->shared(), isolate),
      26         266 :                  handle(closure->feedback_vector(), isolate)},
      27         266 :       closure_(closure) {
      28         133 :   CHECK(closure->has_feedback_vector());
      29         133 : }
      30             : 
      31           0 : Hints::Hints(Zone* zone)
      32           0 :     : constants_(zone), maps_(zone), function_blueprints_(zone) {}
      33             : 
      34           0 : const ConstantsSet& Hints::constants() const { return constants_; }
      35             : 
      36           0 : const MapsSet& Hints::maps() const { return maps_; }
      37             : 
      38           0 : const BlueprintsSet& Hints::function_blueprints() const {
      39           0 :   return function_blueprints_;
      40             : }
      41             : 
      42           0 : void Hints::AddConstant(Handle<Object> constant) {
      43             :   constants_.insert(constant);
      44           0 : }
      45             : 
      46           0 : void Hints::AddMap(Handle<Map> map) { maps_.insert(map); }
      47             : 
      48           0 : void Hints::AddFunctionBlueprint(FunctionBlueprint function_blueprint) {
      49             :   function_blueprints_.insert(function_blueprint);
      50           0 : }
      51             : 
      52         585 : void Hints::Add(const Hints& other) {
      53         819 :   for (auto x : other.constants()) AddConstant(x);
      54         585 :   for (auto x : other.maps()) AddMap(x);
      55         646 :   for (auto x : other.function_blueprints()) AddFunctionBlueprint(x);
      56         585 : }
      57             : 
      58           0 : bool Hints::IsEmpty() const {
      59           0 :   return constants().empty() && maps().empty() && function_blueprints().empty();
      60             : }
      61             : 
      62           0 : std::ostream& operator<<(std::ostream& out,
      63             :                          const FunctionBlueprint& blueprint) {
      64           0 :   out << Brief(*blueprint.shared) << std::endl;
      65           0 :   out << Brief(*blueprint.feedback_vector) << std::endl;
      66           0 :   return out;
      67             : }
      68             : 
      69           0 : std::ostream& operator<<(std::ostream& out, const Hints& hints) {
      70             :   !hints.constants().empty() &&
      71           0 :       out << "\t\tConstants (" << hints.constants().size() << "):" << std::endl;
      72           0 :   for (auto x : hints.constants()) out << Brief(*x) << std::endl;
      73             :   !hints.maps().empty() && out << "\t\tMaps (" << hints.maps().size()
      74           0 :                                << "):" << std::endl;
      75           0 :   for (auto x : hints.maps()) out << Brief(*x) << std::endl;
      76             :   !hints.function_blueprints().empty() &&
      77             :       out << "\t\tBlueprints (" << hints.function_blueprints().size()
      78           0 :           << "):" << std::endl;
      79           0 :   for (auto x : hints.function_blueprints()) out << x;
      80           0 :   return out;
      81             : }
      82             : 
      83        1937 : void Hints::Clear() {
      84             :   constants_.clear();
      85             :   maps_.clear();
      86             :   function_blueprints_.clear();
      87             :   DCHECK(IsEmpty());
      88        1937 : }
      89             : 
      90          32 : class SerializerForBackgroundCompilation::Environment : public ZoneObject {
      91             :  public:
      92             :   Environment(Zone* zone, CompilationSubject function);
      93             :   Environment(Zone* zone, Isolate* isolate, CompilationSubject function,
      94             :               base::Optional<Hints> new_target, const HintsVector& arguments);
      95             : 
      96             :   // When control flow bytecodes are encountered, e.g. a conditional jump,
      97             :   // the current environment needs to be stashed together with the target jump
      98             :   // address. Later, when this target bytecode is handled, the stashed
      99             :   // environment will be merged into the current one.
     100             :   void Merge(Environment* other);
     101             : 
     102             :   friend std::ostream& operator<<(std::ostream& out, const Environment& env);
     103             : 
     104             :   FunctionBlueprint function() const { return function_; }
     105             : 
     106        1149 :   Hints& accumulator_hints() { return environment_hints_[accumulator_index()]; }
     107             :   Hints& register_hints(interpreter::Register reg) {
     108         634 :     int local_index = RegisterToLocalIndex(reg);
     109             :     DCHECK_LT(local_index, environment_hints_.size());
     110         634 :     return environment_hints_[local_index];
     111             :   }
     112         294 :   Hints& return_value_hints() { return return_value_hints_; }
     113             : 
     114             :   // Clears all hints except those for the return value and the closure.
     115         214 :   void ClearEphemeralHints() {
     116             :     DCHECK_EQ(environment_hints_.size(), function_closure_index() + 1);
     117        2618 :     for (int i = 0; i < function_closure_index(); ++i) {
     118        2404 :       environment_hints_[i].Clear();
     119             :     }
     120         214 :   }
     121             : 
     122             :   // Appends the hints for the given register range to {dst} (in order).
     123             :   void ExportRegisterHints(interpreter::Register first, size_t count,
     124             :                            HintsVector& dst);
     125             : 
     126             :  private:
     127             :   int RegisterToLocalIndex(interpreter::Register reg) const;
     128             : 
     129             :   Zone* zone() const { return zone_; }
     130             :   int parameter_count() const { return parameter_count_; }
     131             :   int register_count() const { return register_count_; }
     132             : 
     133             :   Zone* const zone_;
     134             :   // Instead of storing the blueprint here, we could extract it from the
     135             :   // (closure) hints but that would be cumbersome.
     136             :   FunctionBlueprint const function_;
     137             :   int const parameter_count_;
     138             :   int const register_count_;
     139             : 
     140             :   // environment_hints_ contains hints for the contents of the registers,
     141             :   // the accumulator and the parameters. The layout is as follows:
     142             :   // [ parameters | registers | accumulator | context | closure ]
     143             :   // The first parameter is the receiver.
     144             :   HintsVector environment_hints_;
     145        2906 :   int accumulator_index() const { return parameter_count() + register_count(); }
     146           1 :   int current_context_index() const { return accumulator_index() + 1; }
     147        1573 :   int function_closure_index() const { return current_context_index() + 1; }
     148         183 :   int environment_hints_size() const { return function_closure_index() + 1; }
     149             : 
     150             :   Hints return_value_hints_;
     151             : };
     152             : 
     153         151 : SerializerForBackgroundCompilation::Environment::Environment(
     154             :     Zone* zone, CompilationSubject function)
     155             :     : zone_(zone),
     156             :       function_(function.blueprint()),
     157         302 :       parameter_count_(function_.shared->GetBytecodeArray()->parameter_count()),
     158         302 :       register_count_(function_.shared->GetBytecodeArray()->register_count()),
     159             :       environment_hints_(environment_hints_size(), Hints(zone), zone),
     160         755 :       return_value_hints_(zone) {
     161             :   Handle<JSFunction> closure;
     162         151 :   if (function.closure().ToHandle(&closure)) {
     163         133 :     environment_hints_[function_closure_index()].AddConstant(closure);
     164             :   } else {
     165          18 :     environment_hints_[function_closure_index()].AddFunctionBlueprint(
     166             :         function.blueprint());
     167             :   }
     168         151 : }
     169             : 
     170          72 : SerializerForBackgroundCompilation::Environment::Environment(
     171             :     Zone* zone, Isolate* isolate, CompilationSubject function,
     172             :     base::Optional<Hints> new_target, const HintsVector& arguments)
     173          72 :     : Environment(zone, function) {
     174             :   // Copy the hints for the actually passed arguments, at most up to
     175             :   // the parameter_count.
     176          72 :   size_t param_count = static_cast<size_t>(parameter_count());
     177         558 :   for (size_t i = 0; i < std::min(arguments.size(), param_count); ++i) {
     178         138 :     environment_hints_[i] = arguments[i];
     179             :   }
     180             : 
     181             :   // Pad the rest with "undefined".
     182          72 :   Hints undefined_hint(zone);
     183             :   undefined_hint.AddConstant(isolate->factory()->undefined_value());
     184          80 :   for (size_t i = arguments.size(); i < param_count; ++i) {
     185           4 :     environment_hints_[i] = undefined_hint;
     186             :   }
     187             : 
     188             :   interpreter::Register new_target_reg =
     189         144 :       function_.shared->GetBytecodeArray()
     190             :           ->incoming_new_target_or_generator_register();
     191          72 :   if (new_target_reg.is_valid()) {
     192             :     DCHECK(register_hints(new_target_reg).IsEmpty());
     193           0 :     if (new_target.has_value()) {
     194           0 :       register_hints(new_target_reg).Add(*new_target);
     195             :     }
     196             :   }
     197          72 : }
     198             : 
     199          16 : void SerializerForBackgroundCompilation::Environment::Merge(
     200             :     Environment* other) {
     201             :   // Presumably the source and the target would have the same layout
     202             :   // so this is enforced here.
     203          16 :   CHECK_EQ(parameter_count(), other->parameter_count());
     204          16 :   CHECK_EQ(register_count(), other->register_count());
     205          16 :   CHECK_EQ(environment_hints_size(), other->environment_hints_size());
     206             : 
     207         232 :   for (size_t i = 0; i < environment_hints_.size(); ++i) {
     208         108 :     environment_hints_[i].Add(other->environment_hints_[i]);
     209             :   }
     210          16 :   return_value_hints_.Add(other->return_value_hints_);
     211          16 : }
     212             : 
     213           0 : std::ostream& operator<<(
     214             :     std::ostream& out,
     215             :     const SerializerForBackgroundCompilation::Environment& env) {
     216           0 :   std::ostringstream output_stream;
     217           0 :   output_stream << "Function ";
     218           0 :   env.function_.shared->Name()->Print(output_stream);
     219           0 :   output_stream << "Parameter count: " << env.parameter_count() << std::endl;
     220           0 :   output_stream << "Register count: " << env.register_count() << std::endl;
     221             : 
     222           0 :   output_stream << "Hints (" << env.environment_hints_.size() << "):\n";
     223           0 :   for (size_t i = 0; i < env.environment_hints_.size(); ++i) {
     224           0 :     if (env.environment_hints_[i].IsEmpty()) continue;
     225             : 
     226             :     output_stream << "\tSlot " << i << std::endl;
     227           0 :     output_stream << env.environment_hints_[i];
     228             :   }
     229           0 :   output_stream << "Return value:\n";
     230           0 :   output_stream << env.return_value_hints_
     231           0 :                 << "===========================================\n";
     232             : 
     233           0 :   out << output_stream.str();
     234           0 :   return out;
     235             : }
     236             : 
     237         634 : int SerializerForBackgroundCompilation::Environment::RegisterToLocalIndex(
     238             :     interpreter::Register reg) const {
     239             :   // TODO(mslekova): We also want to gather hints for the context.
     240         635 :   if (reg.is_current_context()) return current_context_index();
     241         639 :   if (reg.is_function_closure()) return function_closure_index();
     242         627 :   if (reg.is_parameter()) {
     243          15 :     return reg.ToParameterIndex(parameter_count());
     244             :   } else {
     245         612 :     return parameter_count() + reg.index();
     246             :   }
     247             : }
     248             : 
     249          79 : SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
     250             :     JSHeapBroker* broker, Zone* zone, Handle<JSFunction> closure)
     251             :     : broker_(broker),
     252             :       zone_(zone),
     253          79 :       environment_(new (zone) Environment(zone, {closure, broker_->isolate()})),
     254         158 :       stashed_environments_(zone) {
     255          79 :   JSFunctionRef(broker, closure).Serialize();
     256          79 : }
     257             : 
     258          72 : SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
     259             :     JSHeapBroker* broker, Zone* zone, CompilationSubject function,
     260             :     base::Optional<Hints> new_target, const HintsVector& arguments)
     261             :     : broker_(broker),
     262             :       zone_(zone),
     263             :       environment_(new (zone) Environment(zone, broker_->isolate(), function,
     264          72 :                                           new_target, arguments)),
     265         216 :       stashed_environments_(zone) {
     266             :   Handle<JSFunction> closure;
     267          72 :   if (function.closure().ToHandle(&closure)) {
     268          54 :     JSFunctionRef(broker, closure).Serialize();
     269             :   }
     270          72 : }
     271             : 
     272         151 : Hints SerializerForBackgroundCompilation::Run() {
     273             :   SharedFunctionInfoRef shared(broker(), environment()->function().shared);
     274             :   FeedbackVectorRef feedback_vector(broker(),
     275             :                                     environment()->function().feedback_vector);
     276         151 :   if (shared.IsSerializedForCompilation(feedback_vector)) {
     277             :     return Hints(zone());
     278             :   }
     279         147 :   shared.SetSerializedForCompilation(feedback_vector);
     280         147 :   feedback_vector.SerializeSlots();
     281         147 :   TraverseBytecode();
     282         147 :   return environment()->return_value_hints();
     283             : }
     284             : 
     285         147 : void SerializerForBackgroundCompilation::TraverseBytecode() {
     286             :   BytecodeArrayRef bytecode_array(
     287             :       broker(), handle(environment()->function().shared->GetBytecodeArray(),
     288         294 :                        broker()->isolate()));
     289         147 :   BytecodeArrayIterator iterator(bytecode_array.object());
     290             : 
     291        2505 :   for (; !iterator.done(); iterator.Advance()) {
     292        1179 :     MergeAfterJump(&iterator);
     293        1179 :     switch (iterator.current_bytecode()) {
     294             : #define DEFINE_BYTECODE_CASE(name)     \
     295             :   case interpreter::Bytecode::k##name: \
     296             :     Visit##name(&iterator);            \
     297             :     break;
     298          20 :       SUPPORTED_BYTECODE_LIST(DEFINE_BYTECODE_CASE)
     299             : #undef DEFINE_BYTECODE_CASE
     300             :       default: {
     301          18 :         environment()->ClearEphemeralHints();
     302          18 :         break;
     303             :       }
     304             :     }
     305             :   }
     306         147 : }
     307             : 
     308           0 : void SerializerForBackgroundCompilation::VisitIllegal(
     309             :     BytecodeArrayIterator* iterator) {
     310           0 :   UNREACHABLE();
     311             : }
     312             : 
     313           0 : void SerializerForBackgroundCompilation::VisitWide(
     314             :     BytecodeArrayIterator* iterator) {
     315           0 :   UNREACHABLE();
     316             : }
     317             : 
     318           0 : void SerializerForBackgroundCompilation::VisitExtraWide(
     319             :     BytecodeArrayIterator* iterator) {
     320           0 :   UNREACHABLE();
     321             : }
     322             : 
     323           0 : void SerializerForBackgroundCompilation::VisitStackCheck(
     324           0 :     BytecodeArrayIterator* iterator) {}
     325             : 
     326          79 : void SerializerForBackgroundCompilation::VisitLdaUndefined(
     327             :     BytecodeArrayIterator* iterator) {
     328          79 :   environment()->accumulator_hints().Clear();
     329             :   environment()->accumulator_hints().AddConstant(
     330             :       broker()->isolate()->factory()->undefined_value());
     331          79 : }
     332             : 
     333           0 : void SerializerForBackgroundCompilation::VisitLdaNull(
     334             :     BytecodeArrayIterator* iterator) {
     335           0 :   environment()->accumulator_hints().Clear();
     336             :   environment()->accumulator_hints().AddConstant(
     337             :       broker()->isolate()->factory()->null_value());
     338           0 : }
     339             : 
     340          23 : void SerializerForBackgroundCompilation::VisitLdaZero(
     341             :     BytecodeArrayIterator* iterator) {
     342          23 :   environment()->accumulator_hints().Clear();
     343             :   environment()->accumulator_hints().AddConstant(
     344             :       handle(Smi::FromInt(0), broker()->isolate()));
     345          23 : }
     346             : 
     347          42 : void SerializerForBackgroundCompilation::VisitLdaSmi(
     348             :     BytecodeArrayIterator* iterator) {
     349          42 :   environment()->accumulator_hints().Clear();
     350          42 :   environment()->accumulator_hints().AddConstant(handle(
     351             :       Smi::FromInt(iterator->GetImmediateOperand(0)), broker()->isolate()));
     352          42 : }
     353             : 
     354           7 : void SerializerForBackgroundCompilation::VisitLdaConstant(
     355             :     BytecodeArrayIterator* iterator) {
     356           7 :   environment()->accumulator_hints().Clear();
     357           7 :   environment()->accumulator_hints().AddConstant(
     358             :       handle(iterator->GetConstantForIndexOperand(0), broker()->isolate()));
     359           7 : }
     360             : 
     361          25 : void SerializerForBackgroundCompilation::VisitLdar(
     362             :     BytecodeArrayIterator* iterator) {
     363          25 :   environment()->accumulator_hints().Clear();
     364             :   environment()->accumulator_hints().Add(
     365          50 :       environment()->register_hints(iterator->GetRegisterOperand(0)));
     366          25 : }
     367             : 
     368         210 : void SerializerForBackgroundCompilation::VisitStar(
     369             :     BytecodeArrayIterator* iterator) {
     370         210 :   interpreter::Register reg = iterator->GetRegisterOperand(0);
     371         210 :   environment()->register_hints(reg).Clear();
     372         210 :   environment()->register_hints(reg).Add(environment()->accumulator_hints());
     373         210 : }
     374             : 
     375           7 : void SerializerForBackgroundCompilation::VisitMov(
     376             :     BytecodeArrayIterator* iterator) {
     377           7 :   interpreter::Register src = iterator->GetRegisterOperand(0);
     378           7 :   interpreter::Register dst = iterator->GetRegisterOperand(1);
     379           7 :   environment()->register_hints(dst).Clear();
     380           7 :   environment()->register_hints(dst).Add(environment()->register_hints(src));
     381           7 : }
     382             : 
     383          69 : void SerializerForBackgroundCompilation::VisitCreateClosure(
     384             :     BytecodeArrayIterator* iterator) {
     385             :   Handle<SharedFunctionInfo> shared(
     386             :       SharedFunctionInfo::cast(iterator->GetConstantForIndexOperand(0)),
     387          69 :       broker()->isolate());
     388             : 
     389             :   Handle<FeedbackCell> feedback_cell =
     390             :       environment()->function().feedback_vector->GetClosureFeedbackCell(
     391         138 :           iterator->GetIndexOperand(1));
     392             :   Handle<Object> cell_value(feedback_cell->value(), broker()->isolate());
     393             : 
     394          69 :   environment()->accumulator_hints().Clear();
     395          69 :   if (cell_value->IsFeedbackVector()) {
     396             :     environment()->accumulator_hints().AddFunctionBlueprint(
     397             :         {shared, Handle<FeedbackVector>::cast(cell_value)});
     398             :   }
     399          69 : }
     400             : 
     401           4 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver(
     402             :     BytecodeArrayIterator* iterator) {
     403           4 :   ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
     404           4 : }
     405             : 
     406          24 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver0(
     407             :     BytecodeArrayIterator* iterator) {
     408             :   const Hints& callee =
     409          24 :       environment()->register_hints(iterator->GetRegisterOperand(0));
     410          24 :   FeedbackSlot slot = iterator->GetSlotOperand(1);
     411             : 
     412          24 :   Hints receiver(zone());
     413             :   receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
     414             : 
     415          72 :   HintsVector parameters({receiver}, zone());
     416          48 :   ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
     417          24 : }
     418             : 
     419          19 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver1(
     420             :     BytecodeArrayIterator* iterator) {
     421             :   const Hints& callee =
     422          19 :       environment()->register_hints(iterator->GetRegisterOperand(0));
     423             :   const Hints& arg0 =
     424          19 :       environment()->register_hints(iterator->GetRegisterOperand(1));
     425          19 :   FeedbackSlot slot = iterator->GetSlotOperand(2);
     426             : 
     427          19 :   Hints receiver(zone());
     428             :   receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
     429             : 
     430          76 :   HintsVector parameters({receiver, arg0}, zone());
     431          38 :   ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
     432          19 : }
     433             : 
     434           4 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver2(
     435             :     BytecodeArrayIterator* iterator) {
     436             :   const Hints& callee =
     437           4 :       environment()->register_hints(iterator->GetRegisterOperand(0));
     438             :   const Hints& arg0 =
     439           4 :       environment()->register_hints(iterator->GetRegisterOperand(1));
     440             :   const Hints& arg1 =
     441           4 :       environment()->register_hints(iterator->GetRegisterOperand(2));
     442           4 :   FeedbackSlot slot = iterator->GetSlotOperand(3);
     443             : 
     444           4 :   Hints receiver(zone());
     445             :   receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
     446             : 
     447          20 :   HintsVector parameters({receiver, arg0, arg1}, zone());
     448           8 :   ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
     449           4 : }
     450             : 
     451           4 : void SerializerForBackgroundCompilation::VisitCallAnyReceiver(
     452             :     BytecodeArrayIterator* iterator) {
     453           4 :   ProcessCallVarArgs(iterator, ConvertReceiverMode::kAny);
     454           4 : }
     455             : 
     456           3 : void SerializerForBackgroundCompilation::VisitCallNoFeedback(
     457             :     BytecodeArrayIterator* iterator) {
     458           3 :   ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
     459           3 : }
     460             : 
     461           4 : void SerializerForBackgroundCompilation::VisitCallProperty(
     462             :     BytecodeArrayIterator* iterator) {
     463           4 :   ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
     464           4 : }
     465             : 
     466           0 : void SerializerForBackgroundCompilation::VisitCallProperty0(
     467             :     BytecodeArrayIterator* iterator) {
     468             :   const Hints& callee =
     469           0 :       environment()->register_hints(iterator->GetRegisterOperand(0));
     470             :   const Hints& receiver =
     471           0 :       environment()->register_hints(iterator->GetRegisterOperand(1));
     472           0 :   FeedbackSlot slot = iterator->GetSlotOperand(2);
     473             : 
     474           0 :   HintsVector parameters({receiver}, zone());
     475           0 :   ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
     476           0 : }
     477             : 
     478           0 : void SerializerForBackgroundCompilation::VisitCallProperty1(
     479             :     BytecodeArrayIterator* iterator) {
     480             :   const Hints& callee =
     481           0 :       environment()->register_hints(iterator->GetRegisterOperand(0));
     482             :   const Hints& receiver =
     483           0 :       environment()->register_hints(iterator->GetRegisterOperand(1));
     484             :   const Hints& arg0 =
     485           0 :       environment()->register_hints(iterator->GetRegisterOperand(2));
     486           0 :   FeedbackSlot slot = iterator->GetSlotOperand(3);
     487             : 
     488           0 :   HintsVector parameters({receiver, arg0}, zone());
     489           0 :   ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
     490           0 : }
     491             : 
     492           4 : void SerializerForBackgroundCompilation::VisitCallProperty2(
     493             :     BytecodeArrayIterator* iterator) {
     494             :   const Hints& callee =
     495           4 :       environment()->register_hints(iterator->GetRegisterOperand(0));
     496             :   const Hints& receiver =
     497           4 :       environment()->register_hints(iterator->GetRegisterOperand(1));
     498             :   const Hints& arg0 =
     499           4 :       environment()->register_hints(iterator->GetRegisterOperand(2));
     500             :   const Hints& arg1 =
     501           4 :       environment()->register_hints(iterator->GetRegisterOperand(3));
     502           4 :   FeedbackSlot slot = iterator->GetSlotOperand(4);
     503             : 
     504          20 :   HintsVector parameters({receiver, arg0, arg1}, zone());
     505           8 :   ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
     506           4 : }
     507             : 
     508           4 : void SerializerForBackgroundCompilation::VisitCallWithSpread(
     509             :     BytecodeArrayIterator* iterator) {
     510           4 :   ProcessCallVarArgs(iterator, ConvertReceiverMode::kAny, true);
     511           4 : }
     512             : 
     513          76 : Hints SerializerForBackgroundCompilation::RunChildSerializer(
     514             :     CompilationSubject function, base::Optional<Hints> new_target,
     515             :     const HintsVector& arguments, bool with_spread) {
     516          76 :   if (with_spread) {
     517             :     DCHECK_LT(0, arguments.size());
     518             :     // Pad the missing arguments in case we were called with spread operator.
     519             :     // Drop the last actually passed argument, which contains the spread.
     520             :     // We don't know what the spread element produces. Therefore we pretend
     521             :     // that the function is called with the maximal number of parameters and
     522             :     // that we have no information about the parameters that were not
     523             :     // explicitly provided.
     524             :     HintsVector padded = arguments;
     525             :     padded.pop_back();  // Remove the spread element.
     526             :     // Fill the rest with empty hints.
     527           8 :     padded.resize(
     528           8 :         function.blueprint().shared->GetBytecodeArray()->parameter_count(),
     529           4 :         Hints(zone()));
     530           8 :     return RunChildSerializer(function, new_target, padded, false);
     531             :   }
     532             : 
     533          72 :   if (FLAG_trace_heap_broker) {
     534           0 :     std::ostream& out = broker()->Trace();
     535             :     out << "\nWill run child serializer with environment:\n"
     536             :         << "===========================================\n"
     537           0 :         << *environment();
     538             :   }
     539             : 
     540             :   SerializerForBackgroundCompilation child_serializer(
     541         144 :       broker(), zone(), function, new_target, arguments);
     542          72 :   return child_serializer.Run();
     543             : }
     544             : 
     545             : namespace {
     546          78 : base::Optional<HeapObjectRef> GetHeapObjectFeedback(
     547             :     JSHeapBroker* broker, Handle<FeedbackVector> feedback_vector,
     548             :     FeedbackSlot slot) {
     549          78 :   if (slot.IsInvalid()) return base::nullopt;
     550             :   FeedbackNexus nexus(feedback_vector, slot);
     551          75 :   VectorSlotPair feedback(feedback_vector, slot, nexus.ic_state());
     552             :   DCHECK(feedback.IsValid());
     553          75 :   if (nexus.IsUninitialized()) return base::nullopt;
     554             :   HeapObject object;
     555         136 :   if (!nexus.GetFeedback()->GetHeapObject(&object)) return base::nullopt;
     556          68 :   return HeapObjectRef(broker, handle(object, broker->isolate()));
     557             : }
     558             : }  // namespace
     559             : 
     560          78 : void SerializerForBackgroundCompilation::ProcessCallOrConstruct(
     561             :     Hints callee, base::Optional<Hints> new_target,
     562             :     const HintsVector& arguments, FeedbackSlot slot, bool with_spread) {
     563             :   // Incorporate feedback into hints.
     564             :   base::Optional<HeapObjectRef> feedback = GetHeapObjectFeedback(
     565          78 :       broker(), environment()->function().feedback_vector, slot);
     566          78 :   if (feedback.has_value() && feedback->map().is_callable()) {
     567          54 :     if (new_target.has_value()) {
     568             :       // Construct; feedback is new_target, which often is also the callee.
     569           8 :       new_target->AddConstant(feedback->object());
     570           8 :       callee.AddConstant(feedback->object());
     571             :     } else {
     572             :       // Call; feedback is callee.
     573          46 :       callee.AddConstant(feedback->object());
     574             :     }
     575             :   }
     576             : 
     577          78 :   environment()->accumulator_hints().Clear();
     578             : 
     579         132 :   for (auto hint : callee.constants()) {
     580          54 :     if (!hint->IsJSFunction()) continue;
     581             : 
     582             :     Handle<JSFunction> function = Handle<JSFunction>::cast(hint);
     583         108 :     if (!function->shared()->IsInlineable() || !function->has_feedback_vector())
     584             :       continue;
     585             : 
     586         216 :     environment()->accumulator_hints().Add(RunChildSerializer(
     587          54 :         {function, broker()->isolate()}, new_target, arguments, with_spread));
     588             :   }
     589             : 
     590          96 :   for (auto hint : callee.function_blueprints()) {
     591          18 :     if (!hint.shared->IsInlineable()) continue;
     592          72 :     environment()->accumulator_hints().Add(RunChildSerializer(
     593          18 :         CompilationSubject(hint), new_target, arguments, with_spread));
     594             :   }
     595          78 : }
     596             : 
     597          19 : void SerializerForBackgroundCompilation::ProcessCallVarArgs(
     598             :     BytecodeArrayIterator* iterator, ConvertReceiverMode receiver_mode,
     599             :     bool with_spread) {
     600             :   const Hints& callee =
     601          19 :       environment()->register_hints(iterator->GetRegisterOperand(0));
     602          19 :   interpreter::Register first_reg = iterator->GetRegisterOperand(1);
     603          19 :   int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
     604             :   FeedbackSlot slot;
     605          19 :   if (iterator->current_bytecode() != interpreter::Bytecode::kCallNoFeedback) {
     606          16 :     slot = iterator->GetSlotOperand(3);
     607             :   }
     608             : 
     609             :   HintsVector arguments(zone());
     610             :   // The receiver is either given in the first register or it is implicitly
     611             :   // the {undefined} value.
     612          19 :   if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
     613          11 :     Hints receiver(zone());
     614             :     receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
     615          11 :     arguments.push_back(receiver);
     616             :   }
     617          19 :   environment()->ExportRegisterHints(first_reg, reg_count, arguments);
     618             : 
     619          38 :   ProcessCallOrConstruct(callee, base::nullopt, arguments, slot);
     620          19 : }
     621             : 
     622          16 : void SerializerForBackgroundCompilation::ProcessJump(
     623             :     interpreter::BytecodeArrayIterator* iterator) {
     624          16 :   int jump_target = iterator->GetJumpTargetOffset();
     625             :   int current_offset = iterator->current_offset();
     626          16 :   if (current_offset >= jump_target) return;
     627             : 
     628          32 :   stashed_environments_[jump_target] = new (zone()) Environment(*environment());
     629             : }
     630             : 
     631        1179 : void SerializerForBackgroundCompilation::MergeAfterJump(
     632             :     interpreter::BytecodeArrayIterator* iterator) {
     633        1179 :   int current_offset = iterator->current_offset();
     634             :   auto stash = stashed_environments_.find(current_offset);
     635        1179 :   if (stash != stashed_environments_.end()) {
     636          16 :     environment()->Merge(stash->second);
     637             :     stashed_environments_.erase(stash);
     638             :   }
     639        1179 : }
     640             : 
     641         147 : void SerializerForBackgroundCompilation::VisitReturn(
     642             :     BytecodeArrayIterator* iterator) {
     643         147 :   environment()->return_value_hints().Add(environment()->accumulator_hints());
     644         147 :   environment()->ClearEphemeralHints();
     645         147 : }
     646             : 
     647          27 : void SerializerForBackgroundCompilation::Environment::ExportRegisterHints(
     648             :     interpreter::Register first, size_t count, HintsVector& dst) {
     649          27 :   dst.resize(dst.size() + count, Hints(zone()));
     650             :   int reg_base = first.index();
     651         129 :   for (int i = 0; i < static_cast<int>(count); ++i) {
     652         102 :     dst.push_back(register_hints(interpreter::Register(reg_base + i)));
     653             :   }
     654          27 : }
     655             : 
     656           4 : void SerializerForBackgroundCompilation::VisitConstruct(
     657             :     BytecodeArrayIterator* iterator) {
     658             :   const Hints& callee =
     659           4 :       environment()->register_hints(iterator->GetRegisterOperand(0));
     660           4 :   interpreter::Register first_reg = iterator->GetRegisterOperand(1);
     661           4 :   size_t reg_count = iterator->GetRegisterCountOperand(2);
     662           4 :   FeedbackSlot slot = iterator->GetSlotOperand(3);
     663             :   const Hints& new_target = environment()->accumulator_hints();
     664             : 
     665             :   HintsVector arguments(zone());
     666           4 :   environment()->ExportRegisterHints(first_reg, reg_count, arguments);
     667             : 
     668           8 :   ProcessCallOrConstruct(callee, new_target, arguments, slot);
     669           4 : }
     670             : 
     671           4 : void SerializerForBackgroundCompilation::VisitConstructWithSpread(
     672             :     BytecodeArrayIterator* iterator) {
     673             :   const Hints& callee =
     674           4 :       environment()->register_hints(iterator->GetRegisterOperand(0));
     675           4 :   interpreter::Register first_reg = iterator->GetRegisterOperand(1);
     676           4 :   size_t reg_count = iterator->GetRegisterCountOperand(2);
     677           4 :   FeedbackSlot slot = iterator->GetSlotOperand(3);
     678             :   const Hints& new_target = environment()->accumulator_hints();
     679             : 
     680             :   HintsVector arguments(zone());
     681           4 :   environment()->ExportRegisterHints(first_reg, reg_count, arguments);
     682             : 
     683           8 :   ProcessCallOrConstruct(callee, new_target, arguments, slot, true);
     684           4 : }
     685             : 
     686             : GlobalAccessFeedback const*
     687          51 : SerializerForBackgroundCompilation::ProcessFeedbackForGlobalAccess(
     688             :     FeedbackSlot slot) {
     689          51 :   if (slot.IsInvalid()) return nullptr;
     690          51 :   if (environment()->function().feedback_vector.is_null()) return nullptr;
     691             :   FeedbackSource source(environment()->function().feedback_vector, slot);
     692          51 :   if (!broker()->HasFeedback(source)) {
     693             :     const GlobalAccessFeedback* feedback =
     694          47 :         broker()->ProcessFeedbackForGlobalAccess(source);
     695          47 :     broker()->SetFeedback(source, feedback);
     696          47 :     return feedback;
     697             :   }
     698             :   return nullptr;
     699             : }
     700             : 
     701          16 : void SerializerForBackgroundCompilation::VisitLdaGlobal(
     702             :     BytecodeArrayIterator* iterator) {
     703          16 :   FeedbackSlot slot = iterator->GetSlotOperand(1);
     704          16 :   environment()->accumulator_hints().Clear();
     705          16 :   GlobalAccessFeedback const* feedback = ProcessFeedbackForGlobalAccess(slot);
     706          16 :   if (feedback != nullptr) {
     707             :     // We may be able to contribute to accumulator constant hints.
     708           0 :     base::Optional<ObjectRef> value = feedback->GetConstantValue();
     709           0 :     if (value.has_value()) {
     710           0 :       environment()->accumulator_hints().AddConstant(value->object());
     711             :     }
     712             :   }
     713          16 : }
     714             : 
     715           0 : void SerializerForBackgroundCompilation::VisitLdaGlobalInsideTypeof(
     716             :     BytecodeArrayIterator* iterator) {
     717           0 :   VisitLdaGlobal(iterator);
     718           0 : }
     719             : 
     720           0 : void SerializerForBackgroundCompilation::VisitLdaLookupGlobalSlot(
     721             :     BytecodeArrayIterator* iterator) {
     722           0 :   VisitLdaGlobal(iterator);
     723           0 : }
     724             : 
     725           0 : void SerializerForBackgroundCompilation::VisitLdaLookupGlobalSlotInsideTypeof(
     726             :     BytecodeArrayIterator* iterator) {
     727           0 :   VisitLdaGlobal(iterator);
     728           0 : }
     729             : 
     730           0 : void SerializerForBackgroundCompilation::VisitStaGlobal(
     731             :     BytecodeArrayIterator* iterator) {
     732          35 :   FeedbackSlot slot = iterator->GetSlotOperand(1);
     733          35 :   ProcessFeedbackForGlobalAccess(slot);
     734           0 : }
     735             : 
     736             : // Note: We never use the same feeedback slot for multiple access modes.
     737          16 : void SerializerForBackgroundCompilation::ProcessFeedbackForKeyedPropertyAccess(
     738             :     FeedbackSlot slot, AccessMode mode) {
     739          32 :   if (slot.IsInvalid()) return;
     740          16 :   if (environment()->function().feedback_vector.is_null()) return;
     741             : 
     742             :   FeedbackNexus nexus(environment()->function().feedback_vector, slot);
     743          16 :   FeedbackSource source(nexus);
     744          16 :   if (broker()->HasFeedback(source)) return;
     745             : 
     746          16 :   if (nexus.ic_state() == MEGAMORPHIC) return;
     747             : 
     748          16 :   if (nexus.GetKeyType() == PROPERTY) {
     749           0 :     CHECK_NE(mode, AccessMode::kStoreInLiteral);
     750             :     return;  // TODO(neis): Support named access.
     751             :   }
     752             :   DCHECK_EQ(nexus.GetKeyType(), ELEMENT);
     753          32 :   CHECK(nexus.GetName().is_null());
     754             : 
     755             :   MapHandles maps;
     756          16 :   nexus.ExtractMaps(&maps);
     757             :   ElementAccessFeedback const* processed =
     758          16 :       broker()->ProcessFeedbackMapsForElementAccess(maps);
     759          16 :   broker()->SetFeedback(source, processed);
     760          16 :   if (processed == nullptr) return;
     761             : 
     762           0 :   for (ElementAccessFeedback::MapIterator it = processed->all_maps(broker());
     763           0 :        !it.done(); it.advance()) {
     764           0 :     switch (mode) {
     765             :       case AccessMode::kHas:
     766             :       case AccessMode::kLoad:
     767           0 :         it.current().SerializeForElementLoad();
     768           0 :         break;
     769             :       case AccessMode::kStore:
     770           0 :         it.current().SerializeForElementStore();
     771           0 :         break;
     772             :       case AccessMode::kStoreInLiteral:
     773             :         // This operation is fairly local and simple, nothing to serialize.
     774             :         break;
     775             :     }
     776             :   }
     777             : }
     778             : 
     779          16 : void SerializerForBackgroundCompilation::VisitLdaKeyedProperty(
     780             :     BytecodeArrayIterator* iterator) {
     781          16 :   FeedbackSlot slot = iterator->GetSlotOperand(1);
     782          16 :   ProcessFeedbackForKeyedPropertyAccess(slot, AccessMode::kLoad);
     783          16 :   environment()->accumulator_hints().Clear();
     784          16 : }
     785             : 
     786           0 : void SerializerForBackgroundCompilation::VisitTestIn(
     787             :     BytecodeArrayIterator* iterator) {
     788           0 :   FeedbackSlot slot = iterator->GetSlotOperand(1);
     789           0 :   ProcessFeedbackForKeyedPropertyAccess(slot, AccessMode::kHas);
     790           0 :   environment()->accumulator_hints().Clear();
     791           0 : }
     792             : 
     793           0 : void SerializerForBackgroundCompilation::VisitStaKeyedProperty(
     794             :     BytecodeArrayIterator* iterator) {
     795             :   const Hints& receiver =
     796           0 :       environment()->register_hints(iterator->GetRegisterOperand(0));
     797           0 :   FeedbackSlot slot = iterator->GetSlotOperand(2);
     798             : 
     799           0 :   ProcessFeedbackForKeyedPropertyAccess(slot, AccessMode::kStore);
     800             : 
     801             :   // Process hints about constants.
     802           0 :   for (Handle<Object> object : receiver.constants()) {
     803           0 :     if (object->IsJSTypedArray()) JSTypedArrayRef(broker(), object).Serialize();
     804             :   }
     805             : 
     806           0 :   environment()->accumulator_hints().Clear();
     807           0 : }
     808             : 
     809           0 : void SerializerForBackgroundCompilation::VisitStaInArrayLiteral(
     810             :     BytecodeArrayIterator* iterator) {
     811           0 :   FeedbackSlot slot = iterator->GetSlotOperand(2);
     812           0 :   ProcessFeedbackForKeyedPropertyAccess(slot, AccessMode::kStoreInLiteral);
     813           0 :   environment()->accumulator_hints().Clear();
     814           0 : }
     815             : 
     816             : #define DEFINE_CLEAR_ENVIRONMENT(name, ...)             \
     817             :   void SerializerForBackgroundCompilation::Visit##name( \
     818             :       BytecodeArrayIterator* iterator) {                \
     819             :     environment()->ClearEphemeralHints();               \
     820             :   }
     821           0 : CLEAR_ENVIRONMENT_LIST(DEFINE_CLEAR_ENVIRONMENT)
     822             : #undef DEFINE_CLEAR_ENVIRONMENT
     823             : 
     824             : #define DEFINE_CLEAR_ACCUMULATOR(name, ...)             \
     825             :   void SerializerForBackgroundCompilation::Visit##name( \
     826             :       BytecodeArrayIterator* iterator) {                \
     827             :     environment()->accumulator_hints().Clear();         \
     828             :   }
     829         163 : CLEAR_ACCUMULATOR_LIST(DEFINE_CLEAR_ACCUMULATOR)
     830             : #undef DEFINE_CLEAR_ACCUMULATOR
     831             : 
     832             : #define DEFINE_CONDITIONAL_JUMP(name, ...)              \
     833             :   void SerializerForBackgroundCompilation::Visit##name( \
     834             :       BytecodeArrayIterator* iterator) {                \
     835             :     ProcessJump(iterator);                              \
     836             :   }
     837           0 : CONDITIONAL_JUMPS_LIST(DEFINE_CONDITIONAL_JUMP)
     838             : #undef DEFINE_CONDITIONAL_JUMP
     839             : 
     840             : #define DEFINE_UNCONDITIONAL_JUMP(name, ...)            \
     841             :   void SerializerForBackgroundCompilation::Visit##name( \
     842             :       BytecodeArrayIterator* iterator) {                \
     843             :     ProcessJump(iterator);                              \
     844             :     environment()->ClearEphemeralHints();               \
     845             :   }
     846           6 : UNCONDITIONAL_JUMPS_LIST(DEFINE_UNCONDITIONAL_JUMP)
     847             : #undef DEFINE_UNCONDITIONAL_JUMP
     848             : 
     849             : #define DEFINE_IGNORE(name, ...)                        \
     850             :   void SerializerForBackgroundCompilation::Visit##name( \
     851             :       BytecodeArrayIterator* iterator) {}
     852           0 : INGORED_BYTECODE_LIST(DEFINE_IGNORE)
     853             : #undef DEFINE_IGNORE
     854             : 
     855             : }  // namespace compiler
     856             : }  // namespace internal
     857      120216 : }  // namespace v8

Generated by: LCOV version 1.10