LCOV - code coverage report
Current view: top level - src/compiler - serializer-for-background-compilation.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 279 366 76.2 %
Date: 2019-02-19 Functions: 43 126 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         113 : CompilationSubject::CompilationSubject(Handle<JSFunction> closure,
      24             :                                        Isolate* isolate)
      25         226 :     : blueprint_{handle(closure->shared(), isolate),
      26         226 :                  handle(closure->feedback_vector(), isolate)},
      27         226 :       closure_(closure) {
      28         113 :   CHECK(closure->has_feedback_vector());
      29         113 : }
      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         490 : void Hints::Add(const Hints& other) {
      53        1200 :   for (auto x : other.constants()) AddConstant(x);
      54         980 :   for (auto x : other.maps()) AddMap(x);
      55        1041 :   for (auto x : other.function_blueprints()) AddFunctionBlueprint(x);
      56         490 : }
      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           0 :   !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           0 :       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        1336 : void Hints::Clear() {
      84             :   constants_.clear();
      85             :   maps_.clear();
      86             :   function_blueprints_.clear();
      87             :   DCHECK(IsEmpty());
      88        1336 : }
      89             : 
      90          30 : 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         878 :   Hints& accumulator_hints() { return environment_hints_[accumulator_index()]; }
     107             :   Hints& register_hints(interpreter::Register reg) {
     108         494 :     int local_index = RegisterToLocalIndex(reg);
     109             :     DCHECK_LT(local_index, environment_hints_.size());
     110         494 :     return environment_hints_[local_index];
     111             :   }
     112             :   Hints& return_value_hints() { return return_value_hints_; }
     113             : 
     114             :   // Clears all hints except those for the return value and the closure.
     115         152 :   void ClearEphemeralHints() {
     116             :     DCHECK_EQ(environment_hints_.size(), function_closure_index() + 1);
     117        1948 :     for (int i = 0; i < function_closure_index(); ++i) {
     118        1644 :       environment_hints_[i].Clear();
     119             :     }
     120         152 :   }
     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        2148 :   int accumulator_index() const { return parameter_count() + register_count(); }
     146           0 :   int current_context_index() const { return accumulator_index() + 1; }
     147        1109 :   int function_closure_index() const { return current_context_index() + 1; }
     148         161 :   int environment_hints_size() const { return function_closure_index() + 1; }
     149             : 
     150             :   Hints return_value_hints_;
     151             : };
     152             : 
     153         131 : SerializerForBackgroundCompilation::Environment::Environment(
     154             :     Zone* zone, CompilationSubject function)
     155             :     : zone_(zone),
     156             :       function_(function.blueprint()),
     157         262 :       parameter_count_(function_.shared->GetBytecodeArray()->parameter_count()),
     158         262 :       register_count_(function_.shared->GetBytecodeArray()->register_count()),
     159             :       environment_hints_(environment_hints_size(), Hints(zone), zone),
     160         655 :       return_value_hints_(zone) {
     161             :   Handle<JSFunction> closure;
     162         131 :   if (function.closure().ToHandle(&closure)) {
     163         131 :     environment_hints_[function_closure_index()].AddConstant(closure);
     164             :   } else {
     165          18 :     environment_hints_[function_closure_index()].AddFunctionBlueprint(
     166             :         function.blueprint());
     167             :   }
     168         131 : }
     169             : 
     170          72 : SerializerForBackgroundCompilation::Environment::Environment(
     171             :     Zone* zone, Isolate* isolate, CompilationSubject function,
     172          72 :     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         630 :   for (size_t i = 0; i < std::min(arguments.size(), param_count); ++i) {
     178         700 :     environment_hints_[i] = arguments[i];
     179             :   }
     180             : 
     181             :   // Pad the rest with "undefined".
     182             :   Hints undefined_hint(zone);
     183             :   undefined_hint.AddConstant(isolate->factory()->undefined_value());
     184          76 :   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         144 :           ->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          72 :   }
     197          72 : }
     198             : 
     199          15 : void SerializerForBackgroundCompilation::Environment::Merge(
     200          30 :     Environment* other) {
     201             :   // Presumably the source and the target would have the same layout
     202             :   // so this is enforced here.
     203          15 :   CHECK_EQ(parameter_count(), other->parameter_count());
     204          15 :   CHECK_EQ(register_count(), other->register_count());
     205          15 :   CHECK_EQ(environment_hints_size(), other->environment_hints_size());
     206             : 
     207         215 :   for (size_t i = 0; i < environment_hints_.size(); ++i) {
     208         315 :     environment_hints_[i].Add(other->environment_hints_[i]);
     209             :   }
     210          15 :   return_value_hints_.Add(other->return_value_hints_);
     211          15 : }
     212             : 
     213           0 : std::ostream& operator<<(
     214             :     std::ostream& out,
     215           0 :     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           0 :     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         494 : int SerializerForBackgroundCompilation::Environment::RegisterToLocalIndex(
     238         490 :     interpreter::Register reg) const {
     239             :   // TODO(mslekova): We also want to gather hints for the context.
     240         494 :   if (reg.is_current_context()) return current_context_index();
     241         498 :   if (reg.is_function_closure()) return function_closure_index();
     242         490 :   if (reg.is_parameter()) {
     243          14 :     return reg.ToParameterIndex(parameter_count());
     244             :   } else {
     245         476 :     return parameter_count() + reg.index();
     246             :   }
     247             : }
     248             : 
     249          59 : SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
     250             :     JSHeapBroker* broker, Zone* zone, Handle<JSFunction> closure)
     251             :     : broker_(broker),
     252             :       zone_(zone),
     253          59 :       environment_(new (zone) Environment(zone, {closure, broker_->isolate()})),
     254         118 :       stashed_environments_(zone) {
     255          59 :   JSFunctionRef(broker, closure).Serialize();
     256          59 : }
     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          72 :       environment_(new (zone) Environment(zone, broker_->isolate(), function,
     264          72 :                                           new_target, arguments)),
     265         288 :       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         393 : Hints SerializerForBackgroundCompilation::Run() {
     273             :   SharedFunctionInfoRef shared(broker(), environment()->function().shared);
     274             :   FeedbackVectorRef feedback_vector(broker(),
     275             :                                     environment()->function().feedback_vector);
     276         131 :   if (shared.IsSerializedForCompilation(feedback_vector)) {
     277             :     return Hints(zone());
     278             :   }
     279         127 :   shared.SetSerializedForCompilation(feedback_vector);
     280         127 :   feedback_vector.SerializeSlots();
     281         127 :   TraverseBytecode();
     282         127 :   return environment()->return_value_hints();
     283             : }
     284             : 
     285         393 : void SerializerForBackgroundCompilation::TraverseBytecode() {
     286             :   BytecodeArrayRef bytecode_array(
     287             :       broker(), handle(environment()->function().shared->GetBytecodeArray(),
     288         381 :                        broker()->isolate()));
     289         127 :   BytecodeArrayIterator iterator(bytecode_array.object());
     290             : 
     291         968 :   for (; !iterator.done(); iterator.Advance()) {
     292         841 :     MergeAfterJump(&iterator);
     293         841 :     switch (iterator.current_bytecode()) {
     294             : #define DEFINE_BYTECODE_CASE(name)     \
     295             :   case interpreter::Bytecode::k##name: \
     296             :     Visit##name(&iterator);            \
     297             :     break;
     298           4 :       SUPPORTED_BYTECODE_LIST(DEFINE_BYTECODE_CASE)
     299             : #undef DEFINE_BYTECODE_CASE
     300             :       default: {
     301          12 :         environment()->ClearEphemeralHints();
     302          12 :         break;
     303             :       }
     304             :     }
     305             :   }
     306         127 : }
     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          73 : void SerializerForBackgroundCompilation::VisitLdaUndefined(
     327         219 :     BytecodeArrayIterator* iterator) {
     328          73 :   environment()->accumulator_hints().Clear();
     329             :   environment()->accumulator_hints().AddConstant(
     330          73 :       broker()->isolate()->factory()->undefined_value());
     331          73 : }
     332             : 
     333           0 : void SerializerForBackgroundCompilation::VisitLdaNull(
     334           0 :     BytecodeArrayIterator* iterator) {
     335           0 :   environment()->accumulator_hints().Clear();
     336             :   environment()->accumulator_hints().AddConstant(
     337           0 :       broker()->isolate()->factory()->null_value());
     338           0 : }
     339             : 
     340           4 : void SerializerForBackgroundCompilation::VisitLdaZero(
     341          12 :     BytecodeArrayIterator* iterator) {
     342           4 :   environment()->accumulator_hints().Clear();
     343             :   environment()->accumulator_hints().AddConstant(
     344           4 :       handle(Smi::FromInt(0), broker()->isolate()));
     345           4 : }
     346             : 
     347          40 : void SerializerForBackgroundCompilation::VisitLdaSmi(
     348         120 :     BytecodeArrayIterator* iterator) {
     349          40 :   environment()->accumulator_hints().Clear();
     350             :   environment()->accumulator_hints().AddConstant(handle(
     351          40 :       Smi::FromInt(iterator->GetImmediateOperand(0)), broker()->isolate()));
     352          40 : }
     353             : 
     354           4 : void SerializerForBackgroundCompilation::VisitLdaConstant(
     355          12 :     BytecodeArrayIterator* iterator) {
     356           4 :   environment()->accumulator_hints().Clear();
     357             :   environment()->accumulator_hints().AddConstant(
     358           4 :       handle(iterator->GetConstantForIndexOperand(0), broker()->isolate()));
     359           4 : }
     360             : 
     361          22 : void SerializerForBackgroundCompilation::VisitLdar(
     362          66 :     BytecodeArrayIterator* iterator) {
     363          22 :   environment()->accumulator_hints().Clear();
     364             :   environment()->accumulator_hints().Add(
     365          44 :       environment()->register_hints(iterator->GetRegisterOperand(0)));
     366          22 : }
     367             : 
     368         150 : void SerializerForBackgroundCompilation::VisitStar(
     369         300 :     BytecodeArrayIterator* iterator) {
     370         150 :   interpreter::Register reg = iterator->GetRegisterOperand(0);
     371         150 :   environment()->register_hints(reg).Clear();
     372         150 :   environment()->register_hints(reg).Add(environment()->accumulator_hints());
     373         150 : }
     374             : 
     375           4 : void SerializerForBackgroundCompilation::VisitMov(
     376          12 :     BytecodeArrayIterator* iterator) {
     377           4 :   interpreter::Register src = iterator->GetRegisterOperand(0);
     378           4 :   interpreter::Register dst = iterator->GetRegisterOperand(1);
     379           4 :   environment()->register_hints(dst).Clear();
     380           4 :   environment()->register_hints(dst).Add(environment()->register_hints(src));
     381           4 : }
     382             : 
     383          23 : void SerializerForBackgroundCompilation::VisitCreateClosure(
     384         110 :     BytecodeArrayIterator* iterator) {
     385             :   Handle<SharedFunctionInfo> shared(
     386             :       SharedFunctionInfo::cast(iterator->GetConstantForIndexOperand(0)),
     387          23 :       broker()->isolate());
     388             : 
     389             :   FeedbackNexus nexus(environment()->function().feedback_vector,
     390          46 :                       iterator->GetSlotOperand(1));
     391          69 :   Handle<Object> cell_value(nexus.GetFeedbackCell()->value(),
     392          69 :                             broker()->isolate());
     393             : 
     394          23 :   environment()->accumulator_hints().Clear();
     395          46 :   if (cell_value->IsFeedbackVector()) {
     396             :     environment()->accumulator_hints().AddFunctionBlueprint(
     397          18 :         {shared, Handle<FeedbackVector>::cast(cell_value)});
     398             :   }
     399          23 : }
     400             : 
     401           4 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver(
     402             :     BytecodeArrayIterator* iterator) {
     403           4 :   ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
     404           4 : }
     405             : 
     406          22 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver0(
     407          88 :     BytecodeArrayIterator* iterator) {
     408             :   const Hints& callee =
     409          22 :       environment()->register_hints(iterator->GetRegisterOperand(0));
     410          22 :   FeedbackSlot slot = iterator->GetSlotOperand(1);
     411             : 
     412             :   Hints receiver(zone());
     413          22 :   receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
     414             : 
     415          66 :   HintsVector parameters({receiver}, zone());
     416          66 :   ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
     417          22 : }
     418             : 
     419          19 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver1(
     420          95 :     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             :   Hints receiver(zone());
     428          19 :   receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
     429             : 
     430          76 :   HintsVector parameters({receiver, arg0}, zone());
     431          57 :   ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
     432          19 : }
     433             : 
     434           4 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver2(
     435          24 :     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             :   Hints receiver(zone());
     445           4 :   receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
     446             : 
     447          20 :   HintsVector parameters({receiver, arg0, arg1}, zone());
     448          12 :   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           0 : void SerializerForBackgroundCompilation::VisitCallNoFeedback(
     457             :     BytecodeArrayIterator* iterator) {
     458           0 :   ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
     459           0 : }
     460             : 
     461           4 : void SerializerForBackgroundCompilation::VisitCallProperty(
     462             :     BytecodeArrayIterator* iterator) {
     463           4 :   ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
     464           4 : }
     465             : 
     466           0 : void SerializerForBackgroundCompilation::VisitCallProperty0(
     467           0 :     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           0 :     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          20 :     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          76 :     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             :     padded.resize(
     528           8 :         function.blueprint().shared->GetBytecodeArray()->parameter_count(),
     529           8 :         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           0 :     out << "\nWill run child serializer with environment:\n"
     536           0 :         << "===========================================\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          73 : base::Optional<HeapObjectRef> GetHeapObjectFeedback(
     547          68 :     JSHeapBroker* broker, Handle<FeedbackVector> feedback_vector,
     548             :     FeedbackSlot slot) {
     549          73 :   if (slot.IsInvalid()) return base::nullopt;
     550          73 :   FeedbackNexus nexus(feedback_vector, slot);
     551          73 :   VectorSlotPair feedback(feedback_vector, slot, nexus.ic_state());
     552             :   DCHECK(feedback.IsValid());
     553          73 :   if (nexus.IsUninitialized()) return base::nullopt;
     554          68 :   HeapObject object;
     555          68 :   if (!nexus.GetFeedback()->GetHeapObject(&object)) return base::nullopt;
     556          68 :   return HeapObjectRef(broker, handle(object, broker->isolate()));
     557             : }
     558             : }  // namespace
     559             : 
     560          73 : void SerializerForBackgroundCompilation::ProcessCallOrConstruct(
     561          54 :     Hints callee, base::Optional<Hints> new_target,
     562         345 :     const HintsVector& arguments, FeedbackSlot slot, bool with_spread) {
     563             :   // Incorporate feedback into hints.
     564             :   base::Optional<HeapObjectRef> feedback = GetHeapObjectFeedback(
     565         146 :       broker(), environment()->function().feedback_vector, slot);
     566          73 :   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          73 :   environment()->accumulator_hints().Clear();
     578             : 
     579         200 :   for (auto hint : callee.constants()) {
     580         108 :     if (!hint->IsJSFunction()) continue;
     581             : 
     582          54 :     Handle<JSFunction> function = Handle<JSFunction>::cast(hint);
     583         108 :     if (!function->shared()->IsInlineable() || !function->has_feedback_vector())
     584             :       continue;
     585             : 
     586             :     environment()->accumulator_hints().Add(RunChildSerializer(
     587         216 :         {function, broker()->isolate()}, new_target, arguments, with_spread));
     588             :   }
     589             : 
     590         164 :   for (auto hint : callee.function_blueprints()) {
     591          18 :     if (!hint.shared->IsInlineable()) continue;
     592             :     environment()->accumulator_hints().Add(RunChildSerializer(
     593          72 :         CompilationSubject(hint), new_target, arguments, with_spread));
     594             :   }
     595          73 : }
     596             : 
     597          16 : void SerializerForBackgroundCompilation::ProcessCallVarArgs(
     598             :     BytecodeArrayIterator* iterator, ConvertReceiverMode receiver_mode,
     599          56 :     bool with_spread) {
     600             :   const Hints& callee =
     601          16 :       environment()->register_hints(iterator->GetRegisterOperand(0));
     602          16 :   interpreter::Register first_reg = iterator->GetRegisterOperand(1);
     603          16 :   int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
     604             :   FeedbackSlot slot;
     605          16 :   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          16 :   if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
     613             :     Hints receiver(zone());
     614           8 :     receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
     615           8 :     arguments.push_back(receiver);
     616             :   }
     617          32 :   environment()->ExportRegisterHints(first_reg, reg_count, arguments);
     618             : 
     619          32 :   ProcessCallOrConstruct(callee, base::nullopt, arguments, slot);
     620          16 : }
     621             : 
     622          15 : void SerializerForBackgroundCompilation::ProcessJump(
     623          15 :     interpreter::BytecodeArrayIterator* iterator) {
     624          15 :   int jump_target = iterator->GetJumpTargetOffset();
     625             :   int current_offset = iterator->current_offset();
     626          15 :   if (current_offset >= jump_target) return;
     627             : 
     628          30 :   stashed_environments_[jump_target] = new (zone()) Environment(*environment());
     629             : }
     630             : 
     631         841 : void SerializerForBackgroundCompilation::MergeAfterJump(
     632          15 :     interpreter::BytecodeArrayIterator* iterator) {
     633         841 :   int current_offset = iterator->current_offset();
     634             :   auto stash = stashed_environments_.find(current_offset);
     635         841 :   if (stash != stashed_environments_.end()) {
     636          30 :     environment()->Merge(stash->second);
     637             :     stashed_environments_.erase(stash);
     638             :   }
     639         841 : }
     640             : 
     641         127 : void SerializerForBackgroundCompilation::VisitReturn(
     642         254 :     BytecodeArrayIterator* iterator) {
     643         127 :   environment()->return_value_hints().Add(environment()->accumulator_hints());
     644         127 :   environment()->ClearEphemeralHints();
     645         127 : }
     646             : 
     647          24 : void SerializerForBackgroundCompilation::Environment::ExportRegisterHints(
     648          24 :     interpreter::Register first, size_t count, HintsVector& dst) {
     649          48 :   dst.resize(dst.size() + count, Hints(zone()));
     650             :   int reg_base = first.index();
     651          72 :   for (int i = 0; i < static_cast<int>(count); ++i) {
     652          96 :     dst.push_back(register_hints(interpreter::Register(reg_base + i)));
     653             :   }
     654          24 : }
     655             : 
     656           4 : void SerializerForBackgroundCompilation::VisitConstruct(
     657          12 :     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          12 :     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             : #define DEFINE_CLEAR_ENVIRONMENT(name, ...)             \
     687             :   void SerializerForBackgroundCompilation::Visit##name( \
     688             :       BytecodeArrayIterator* iterator) {                \
     689             :     environment()->ClearEphemeralHints();               \
     690             :   }
     691           0 : CLEAR_ENVIRONMENT_LIST(DEFINE_CLEAR_ENVIRONMENT)
     692             : #undef DEFINE_CLEAR_ENVIRONMENT
     693             : 
     694             : #define DEFINE_CLEAR_ACCUMULATOR(name, ...)             \
     695             :   void SerializerForBackgroundCompilation::Visit##name( \
     696             :       BytecodeArrayIterator* iterator) {                \
     697             :     environment()->accumulator_hints().Clear();         \
     698             :   }
     699         242 : CLEAR_ACCUMULATOR_LIST(DEFINE_CLEAR_ACCUMULATOR)
     700             : #undef DEFINE_CLEAR_ACCUMULATOR
     701             : 
     702             : #define DEFINE_CONDITIONAL_JUMP(name, ...)              \
     703             :   void SerializerForBackgroundCompilation::Visit##name( \
     704             :       BytecodeArrayIterator* iterator) {                \
     705             :     ProcessJump(iterator);                              \
     706             :   }
     707           0 : CONDITIONAL_JUMPS_LIST(DEFINE_CONDITIONAL_JUMP)
     708             : #undef DEFINE_CONDITIONAL_JUMP
     709             : 
     710             : #define DEFINE_UNCONDITIONAL_JUMP(name, ...)            \
     711             :   void SerializerForBackgroundCompilation::Visit##name( \
     712             :       BytecodeArrayIterator* iterator) {                \
     713             :     ProcessJump(iterator);                              \
     714             :     environment()->ClearEphemeralHints();               \
     715             :   }
     716           5 : UNCONDITIONAL_JUMPS_LIST(DEFINE_UNCONDITIONAL_JUMP)
     717             : #undef DEFINE_UNCONDITIONAL_JUMP
     718             : 
     719             : #define DEFINE_IGNORE(name, ...)                        \
     720             :   void SerializerForBackgroundCompilation::Visit##name( \
     721             :       BytecodeArrayIterator* iterator) {}
     722           0 : INGORED_BYTECODE_LIST(DEFINE_IGNORE)
     723             : #undef DEFINE_IGNORE
     724             : 
     725             : }  // namespace compiler
     726             : }  // namespace internal
     727      178779 : }  // namespace v8

Generated by: LCOV version 1.10