LCOV - code coverage report
Current view: top level - src/compiler - compilation-dependencies.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 175 175 100.0 %
Date: 2019-01-20 Functions: 42 42 100.0 %

          Line data    Source code
       1             : // Copyright 2015 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/compilation-dependencies.h"
       6             : 
       7             : #include "src/handles-inl.h"
       8             : #include "src/objects-inl.h"
       9             : 
      10             : namespace v8 {
      11             : namespace internal {
      12             : namespace compiler {
      13             : 
      14      474828 : CompilationDependencies::CompilationDependencies(Isolate* isolate, Zone* zone)
      15      949656 :     : zone_(zone), dependencies_(zone), isolate_(isolate) {}
      16             : 
      17      875155 : class CompilationDependencies::Dependency : public ZoneObject {
      18             :  public:
      19             :   virtual bool IsValid() const = 0;
      20      810960 :   virtual void PrepareInstall() {}
      21             :   virtual void Install(const MaybeObjectHandle& code) = 0;
      22             : 
      23             : #ifdef DEBUG
      24             :   virtual bool IsPretenureModeDependency() const { return false; }
      25             : #endif
      26             : };
      27             : 
      28             : class InitialMapDependency final : public CompilationDependencies::Dependency {
      29             :  public:
      30             :   // TODO(neis): Once the concurrent compiler frontend is always-on, we no
      31             :   // longer need to explicitly store the initial map.
      32             :   InitialMapDependency(const JSFunctionRef& function, const MapRef& initial_map)
      33        5404 :       : function_(function), initial_map_(initial_map) {
      34             :     DCHECK(function_.has_initial_map());
      35             :     DCHECK(function_.initial_map().equals(initial_map_));
      36             :   }
      37             : 
      38       10769 :   bool IsValid() const override {
      39       10769 :     Handle<JSFunction> function = function_.object();
      40       32307 :     return function->has_initial_map() &&
      41       43076 :            function->initial_map() == *initial_map_.object();
      42             :   }
      43             : 
      44        5384 :   void Install(const MaybeObjectHandle& code) override {
      45             :     SLOW_DCHECK(IsValid());
      46             :     DependentCode::InstallDependency(function_.isolate(), code,
      47             :                                      initial_map_.object(),
      48       10768 :                                      DependentCode::kInitialMapChangedGroup);
      49        5384 :   }
      50             : 
      51             :  private:
      52             :   JSFunctionRef function_;
      53             :   MapRef initial_map_;
      54             : };
      55             : 
      56             : class PrototypePropertyDependency final
      57             :     : public CompilationDependencies::Dependency {
      58             :  public:
      59             :   // TODO(neis): Once the concurrent compiler frontend is always-on, we no
      60             :   // longer need to explicitly store the prototype.
      61             :   PrototypePropertyDependency(const JSFunctionRef& function,
      62             :                               const ObjectRef& prototype)
      63       56892 :       : function_(function), prototype_(prototype) {
      64             :     DCHECK(function_.has_prototype());
      65             :     DCHECK(!function_.PrototypeRequiresRuntimeLookup());
      66             :     DCHECK(function_.prototype().equals(prototype_));
      67             :   }
      68             : 
      69      113768 :   bool IsValid() const override {
      70      113768 :     Handle<JSFunction> function = function_.object();
      71      455072 :     return function->has_prototype_slot() && function->has_prototype() &&
      72      455072 :            !function->PrototypeRequiresRuntimeLookup() &&
      73      455072 :            function->prototype() == *prototype_.object();
      74             :   }
      75             : 
      76       56891 :   void PrepareInstall() override {
      77             :     SLOW_DCHECK(IsValid());
      78       56891 :     Handle<JSFunction> function = function_.object();
      79       56891 :     if (!function->has_initial_map()) JSFunction::EnsureHasInitialMap(function);
      80       56891 :   }
      81             : 
      82       56877 :   void Install(const MaybeObjectHandle& code) override {
      83             :     SLOW_DCHECK(IsValid());
      84       56877 :     Handle<JSFunction> function = function_.object();
      85             :     DCHECK(function->has_initial_map());
      86      170631 :     Handle<Map> initial_map(function->initial_map(), function_.isolate());
      87             :     DependentCode::InstallDependency(function_.isolate(), code, initial_map,
      88       56877 :                                      DependentCode::kInitialMapChangedGroup);
      89       56877 :   }
      90             : 
      91             :  private:
      92             :   JSFunctionRef function_;
      93             :   ObjectRef prototype_;
      94             : };
      95             : 
      96             : class StableMapDependency final : public CompilationDependencies::Dependency {
      97             :  public:
      98      158680 :   explicit StableMapDependency(const MapRef& map) : map_(map) {
      99             :     DCHECK(map_.is_stable());
     100             :   }
     101             : 
     102      632886 :   bool IsValid() const override { return map_.object()->is_stable(); }
     103             : 
     104      158195 :   void Install(const MaybeObjectHandle& code) override {
     105             :     SLOW_DCHECK(IsValid());
     106             :     DependentCode::InstallDependency(map_.isolate(), code, map_.object(),
     107      316390 :                                      DependentCode::kPrototypeCheckGroup);
     108      158195 :   }
     109             : 
     110             :  private:
     111             :   MapRef map_;
     112             : };
     113             : 
     114             : class TransitionDependency final : public CompilationDependencies::Dependency {
     115             :  public:
     116       15441 :   explicit TransitionDependency(const MapRef& map) : map_(map) {
     117             :     DCHECK(!map_.is_deprecated());
     118             :   }
     119             : 
     120       61676 :   bool IsValid() const override { return !map_.object()->is_deprecated(); }
     121             : 
     122       15417 :   void Install(const MaybeObjectHandle& code) override {
     123             :     SLOW_DCHECK(IsValid());
     124             :     DependentCode::InstallDependency(map_.isolate(), code, map_.object(),
     125       30834 :                                      DependentCode::kTransitionGroup);
     126       15417 :   }
     127             : 
     128             :  private:
     129             :   MapRef map_;
     130             : };
     131             : 
     132             : class PretenureModeDependency final
     133             :     : public CompilationDependencies::Dependency {
     134             :  public:
     135             :   // TODO(neis): Once the concurrent compiler frontend is always-on, we no
     136             :   // longer need to explicitly store the mode.
     137             :   PretenureModeDependency(const AllocationSiteRef& site, PretenureFlag mode)
     138        7585 :       : site_(site), mode_(mode) {
     139             :     DCHECK_EQ(mode_, site_.GetPretenureMode());
     140             :   }
     141             : 
     142       15030 :   bool IsValid() const override {
     143       30060 :     return mode_ == site_.object()->GetPretenureMode();
     144             :   }
     145             : 
     146        7510 :   void Install(const MaybeObjectHandle& code) override {
     147             :     SLOW_DCHECK(IsValid());
     148             :     DependentCode::InstallDependency(
     149             :         site_.isolate(), code, site_.object(),
     150       15020 :         DependentCode::kAllocationSiteTenuringChangedGroup);
     151        7510 :   }
     152             : 
     153             : #ifdef DEBUG
     154             :   bool IsPretenureModeDependency() const override { return true; }
     155             : #endif
     156             : 
     157             :  private:
     158             :   AllocationSiteRef site_;
     159             :   PretenureFlag mode_;
     160             : };
     161             : 
     162             : class FieldTypeDependency final : public CompilationDependencies::Dependency {
     163             :  public:
     164             :   // TODO(neis): Once the concurrent compiler frontend is always-on, we no
     165             :   // longer need to explicitly store the type.
     166             :   FieldTypeDependency(const MapRef& owner, int descriptor,
     167             :                       const ObjectRef& type, PropertyConstness constness)
     168             :       : owner_(owner),
     169             :         descriptor_(descriptor),
     170             :         type_(type),
     171        1864 :         constness_(constness) {
     172             :     DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
     173             :     DCHECK(type_.equals(owner_.GetFieldType(descriptor_)));
     174             :     DCHECK_EQ(constness_, owner_.GetPropertyDetails(descriptor_).constness());
     175             :   }
     176             : 
     177        3382 :   bool IsValid() const override {
     178             :     DisallowHeapAllocation no_heap_allocation;
     179        3382 :     Handle<Map> owner = owner_.object();
     180        3382 :     Handle<Object> type = type_.object();
     181       16840 :     return *type == owner->instance_descriptors()->GetFieldType(descriptor_) &&
     182       10006 :            constness_ == owner->instance_descriptors()
     183       10006 :                              ->GetDetails(descriptor_)
     184       10076 :                              .constness();
     185             :   }
     186             : 
     187        1541 :   void Install(const MaybeObjectHandle& code) override {
     188             :     SLOW_DCHECK(IsValid());
     189             :     DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
     190        3082 :                                      DependentCode::kFieldOwnerGroup);
     191        1541 :   }
     192             : 
     193             :  private:
     194             :   MapRef owner_;
     195             :   int descriptor_;
     196             :   ObjectRef type_;
     197             :   PropertyConstness constness_;
     198             : };
     199             : 
     200             : class GlobalPropertyDependency final
     201             :     : public CompilationDependencies::Dependency {
     202             :  public:
     203             :   // TODO(neis): Once the concurrent compiler frontend is always-on, we no
     204             :   // longer need to explicitly store the type and the read_only flag.
     205             :   GlobalPropertyDependency(const PropertyCellRef& cell, PropertyCellType type,
     206             :                            bool read_only)
     207      601573 :       : cell_(cell), type_(type), read_only_(read_only) {
     208             :     DCHECK_EQ(type_, cell_.property_details().cell_type());
     209             :     DCHECK_EQ(read_only_, cell_.property_details().IsReadOnly());
     210             :   }
     211             : 
     212     1201380 :   bool IsValid() const override {
     213     1201380 :     Handle<PropertyCell> cell = cell_.object();
     214             :     // The dependency is never valid if the cell is 'invalidated'. This is
     215             :     // marked by setting the value to the hole.
     216     3604140 :     if (cell->value() == *(cell_.isolate()->factory()->the_hole_value())) {
     217             :       DCHECK(cell->property_details().cell_type() ==
     218             :                  PropertyCellType::kInvalidated ||
     219             :              cell->property_details().cell_type() ==
     220             :                  PropertyCellType::kUninitialized);
     221             :       return false;
     222             :     }
     223     6006856 :     return type_ == cell->property_details().cell_type() &&
     224     3604108 :            read_only_ == cell->property_details().IsReadOnly();
     225             :   }
     226             : 
     227      600656 :   void Install(const MaybeObjectHandle& code) override {
     228             :     SLOW_DCHECK(IsValid());
     229             :     DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(),
     230     1201312 :                                      DependentCode::kPropertyCellChangedGroup);
     231      600656 :   }
     232             : 
     233             :  private:
     234             :   PropertyCellRef cell_;
     235             :   PropertyCellType type_;
     236             :   bool read_only_;
     237             : };
     238             : 
     239             : class ProtectorDependency final : public CompilationDependencies::Dependency {
     240             :  public:
     241       19207 :   explicit ProtectorDependency(const PropertyCellRef& cell) : cell_(cell) {
     242             :     DCHECK_EQ(cell_.value().AsSmi(), Isolate::kProtectorValid);
     243             :   }
     244             : 
     245       38188 :   bool IsValid() const override {
     246       38188 :     Handle<PropertyCell> cell = cell_.object();
     247       76376 :     return cell->value() == Smi::FromInt(Isolate::kProtectorValid);
     248             :   }
     249             : 
     250       19092 :   void Install(const MaybeObjectHandle& code) override {
     251             :     SLOW_DCHECK(IsValid());
     252             :     DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(),
     253       38184 :                                      DependentCode::kPropertyCellChangedGroup);
     254       19092 :   }
     255             : 
     256             :  private:
     257             :   PropertyCellRef cell_;
     258             : };
     259             : 
     260             : class ElementsKindDependency final
     261             :     : public CompilationDependencies::Dependency {
     262             :  public:
     263             :   // TODO(neis): Once the concurrent compiler frontend is always-on, we no
     264             :   // longer need to explicitly store the elements kind.
     265             :   ElementsKindDependency(const AllocationSiteRef& site, ElementsKind kind)
     266        3105 :       : site_(site), kind_(kind) {
     267             :     DCHECK(AllocationSite::ShouldTrack(kind_));
     268             :     DCHECK_EQ(kind_, site_.PointsToLiteral()
     269             :                          ? site_.boilerplate().value().GetElementsKind()
     270             :                          : site_.GetElementsKind());
     271             :   }
     272             : 
     273        6143 :   bool IsValid() const override {
     274        6143 :     Handle<AllocationSite> site = site_.object();
     275       12286 :     ElementsKind kind = site->PointsToLiteral()
     276       10143 :                             ? site->boilerplate()->GetElementsKind()
     277       18429 :                             : site->GetElementsKind();
     278        6143 :     return kind_ == kind;
     279             :   }
     280             : 
     281        3065 :   void Install(const MaybeObjectHandle& code) override {
     282             :     SLOW_DCHECK(IsValid());
     283             :     DependentCode::InstallDependency(
     284             :         site_.isolate(), code, site_.object(),
     285        6130 :         DependentCode::kAllocationSiteTransitionChangedGroup);
     286        3065 :   }
     287             : 
     288             :  private:
     289             :   AllocationSiteRef site_;
     290             :   ElementsKind kind_;
     291             : };
     292             : 
     293             : class InitialMapInstanceSizePredictionDependency final
     294             :     : public CompilationDependencies::Dependency {
     295             :  public:
     296             :   InitialMapInstanceSizePredictionDependency(const JSFunctionRef& function,
     297             :                                              int instance_size)
     298        5404 :       : function_(function), instance_size_(instance_size) {}
     299             : 
     300       10771 :   bool IsValid() const override {
     301             :     // The dependency is valid if the prediction is the same as the current
     302             :     // slack tracking result.
     303       21542 :     if (!function_.object()->has_initial_map()) return false;
     304       21538 :     int instance_size = function_.object()->ComputeInstanceSizeWithMinSlack(
     305       21538 :         function_.isolate());
     306       10769 :     return instance_size == instance_size_;
     307             :   }
     308             : 
     309        5385 :   void PrepareInstall() override {
     310             :     SLOW_DCHECK(IsValid());
     311       10770 :     function_.object()->CompleteInobjectSlackTrackingIfActive();
     312        5385 :   }
     313             : 
     314        5384 :   void Install(const MaybeObjectHandle& code) override {
     315             :     SLOW_DCHECK(IsValid());
     316             :     DCHECK(!function_.object()
     317             :                 ->initial_map()
     318             :                 ->IsInobjectSlackTrackingInProgress());
     319        5384 :   }
     320             : 
     321             :  private:
     322             :   JSFunctionRef function_;
     323             :   int instance_size_;
     324             : };
     325             : 
     326        5404 : MapRef CompilationDependencies::DependOnInitialMap(
     327             :     const JSFunctionRef& function) {
     328        5404 :   MapRef map = function.initial_map();
     329       16212 :   dependencies_.push_front(new (zone_) InitialMapDependency(function, map));
     330        5404 :   return map;
     331             : }
     332             : 
     333       56892 : ObjectRef CompilationDependencies::DependOnPrototypeProperty(
     334             :     const JSFunctionRef& function) {
     335       56892 :   ObjectRef prototype = function.prototype();
     336             :   dependencies_.push_front(
     337      170676 :       new (zone_) PrototypePropertyDependency(function, prototype));
     338       56892 :   return prototype;
     339             : }
     340             : 
     341      161346 : void CompilationDependencies::DependOnStableMap(const MapRef& map) {
     342      161346 :   if (map.CanTransition()) {
     343      476041 :     dependencies_.push_front(new (zone_) StableMapDependency(map));
     344             :   } else {
     345             :     DCHECK(map.is_stable());
     346             :   }
     347      161347 : }
     348             : 
     349       17873 : void CompilationDependencies::DependOnTransition(const MapRef& target_map) {
     350       17873 :   if (target_map.CanBeDeprecated()) {
     351       46323 :     dependencies_.push_front(new (zone_) TransitionDependency(target_map));
     352             :   } else {
     353             :     DCHECK(!target_map.is_deprecated());
     354             :   }
     355       17873 : }
     356             : 
     357        7585 : PretenureFlag CompilationDependencies::DependOnPretenureMode(
     358             :     const AllocationSiteRef& site) {
     359        7585 :   PretenureFlag mode = site.GetPretenureMode();
     360       22755 :   dependencies_.push_front(new (zone_) PretenureModeDependency(site, mode));
     361        7585 :   return mode;
     362             : }
     363             : 
     364        1864 : void CompilationDependencies::DependOnFieldType(const MapRef& map,
     365             :                                                 int descriptor) {
     366        1864 :   MapRef owner = map.FindFieldOwner(descriptor);
     367        1864 :   ObjectRef type = owner.GetFieldType(descriptor);
     368             :   PropertyConstness constness =
     369        1864 :       owner.GetPropertyDetails(descriptor).constness();
     370             :   DCHECK(type.equals(map.GetFieldType(descriptor)));
     371             :   dependencies_.push_front(
     372        5592 :       new (zone_) FieldTypeDependency(owner, descriptor, type, constness));
     373        1864 : }
     374             : 
     375      601572 : void CompilationDependencies::DependOnGlobalProperty(
     376             :     const PropertyCellRef& cell) {
     377     1203145 :   PropertyCellType type = cell.property_details().cell_type();
     378     1203147 :   bool read_only = cell.property_details().IsReadOnly();
     379             :   dependencies_.push_front(new (zone_)
     380     1804719 :                                GlobalPropertyDependency(cell, type, read_only));
     381      601572 : }
     382             : 
     383       19207 : void CompilationDependencies::DependOnProtector(const PropertyCellRef& cell) {
     384       57621 :   dependencies_.push_front(new (zone_) ProtectorDependency(cell));
     385       19207 : }
     386             : 
     387        7824 : void CompilationDependencies::DependOnElementsKind(
     388             :     const AllocationSiteRef& site) {
     389             :   // Do nothing if the object doesn't have any useful element transitions left.
     390        7824 :   ElementsKind kind = site.PointsToLiteral()
     391       20242 :                           ? site.boilerplate().value().GetElementsKind()
     392       15648 :                           : site.GetElementsKind();
     393        7824 :   if (AllocationSite::ShouldTrack(kind)) {
     394        9315 :     dependencies_.push_front(new (zone_) ElementsKindDependency(site, kind));
     395             :   }
     396        7824 : }
     397             : 
     398         300 : bool CompilationDependencies::AreValid() const {
     399         830 :   for (auto dep : dependencies_) {
     400         300 :     if (!dep->IsValid()) return false;
     401             :   }
     402             :   return true;
     403             : }
     404             : 
     405      455990 : bool CompilationDependencies::Commit(Handle<Code> code) {
     406     1785216 :   for (auto dep : dependencies_) {
     407      873277 :     if (!dep->IsValid()) {
     408             :       dependencies_.clear();
     409             :       return false;
     410             :     }
     411      873236 :     dep->PrepareInstall();
     412             :   }
     413             : 
     414             :   DisallowCodeDependencyChange no_dependency_change;
     415     1785019 :   for (auto dep : dependencies_) {
     416             :     // Check each dependency's validity again right before installing it,
     417             :     // because the first iteration above might have invalidated some
     418             :     // dependencies. For example, PrototypePropertyDependency::PrepareInstall
     419             :     // can call EnsureHasInitialMap, which can invalidate a StableMapDependency
     420             :     // on the prototype object's map.
     421      873135 :     if (!dep->IsValid()) {
     422             :       dependencies_.clear();
     423             :       return false;
     424             :     }
     425      873121 :     dep->Install(MaybeObjectHandle::Weak(code));
     426             :   }
     427             : 
     428             :   // It is even possible that a GC during the above installations invalidated
     429             :   // one of the dependencies. However, this should only affect pretenure mode
     430             :   // dependencies, which we assert below. It is safe to return successfully in
     431             :   // these cases, because once the code gets executed it will do a stack check
     432             :   // that triggers its deoptimization.
     433      455935 :   if (FLAG_stress_gc_during_compilation) {
     434             :     isolate_->heap()->PreciseCollectAllGarbage(
     435             :         Heap::kNoGCFlags, GarbageCollectionReason::kTesting,
     436           5 :         kGCCallbackFlagForced);
     437             :   }
     438             : #ifdef DEBUG
     439             :   for (auto dep : dependencies_) {
     440             :     CHECK_IMPLIES(!dep->IsValid(), dep->IsPretenureModeDependency());
     441             :   }
     442             : #endif
     443             : 
     444             :   dependencies_.clear();
     445      455935 :   return true;
     446             : }
     447             : 
     448             : namespace {
     449             : // This function expects to never see a JSProxy.
     450       55148 : void DependOnStablePrototypeChain(JSHeapBroker* broker,
     451             :                                   CompilationDependencies* deps, MapRef map,
     452             :                                   const JSObjectRef& last_prototype) {
     453             :   while (true) {
     454       82837 :     map.SerializePrototype();
     455       82838 :     JSObjectRef proto = map.prototype().AsJSObject();
     456       82838 :     map = proto.map();
     457       82837 :     deps->DependOnStableMap(map);
     458       82838 :     if (proto.equals(last_prototype)) break;
     459             :   }
     460       55149 : }
     461             : }  // namespace
     462             : 
     463       52818 : void CompilationDependencies::DependOnStablePrototypeChains(
     464             :     JSHeapBroker* broker, std::vector<Handle<Map>> const& receiver_maps,
     465             :     const JSObjectRef& holder) {
     466             :   // Determine actual holder and perform prototype chain checks.
     467      160785 :   for (auto map : receiver_maps) {
     468             :     MapRef receiver_map(broker, map);
     469       55148 :     if (receiver_map.IsPrimitiveMap()) {
     470             :       // Perform the implicit ToObject for primitives here.
     471             :       // Implemented according to ES6 section 7.3.2 GetV (V, P).
     472             :       base::Optional<JSFunctionRef> constructor =
     473        8546 :           broker->native_context().GetConstructorFunction(receiver_map);
     474        8546 :       if (constructor.has_value()) receiver_map = constructor->initial_map();
     475             :     }
     476       55149 :     DependOnStablePrototypeChain(broker, this, receiver_map, holder);
     477             :   }
     478       52819 : }
     479             : 
     480        5970 : void CompilationDependencies::DependOnElementsKinds(
     481             :     const AllocationSiteRef& site) {
     482        5970 :   AllocationSiteRef current = site;
     483             :   while (true) {
     484        6209 :     DependOnElementsKind(current);
     485        6209 :     if (!current.nested_site().IsAllocationSite()) break;
     486         239 :     current = current.nested_site().AsAllocationSite();
     487             :   }
     488         239 :   CHECK_EQ(current.nested_site().AsSmi(), 0);
     489        5970 : }
     490             : 
     491        1062 : SlackTrackingPrediction::SlackTrackingPrediction(MapRef initial_map,
     492             :                                                  int instance_size)
     493             :     : instance_size_(instance_size),
     494             :       inobject_property_count_(
     495       12932 :           (instance_size >> kTaggedSizeLog2) -
     496        8590 :           initial_map.GetInObjectPropertiesStartInWords()) {}
     497             : 
     498             : SlackTrackingPrediction
     499        5404 : CompilationDependencies::DependOnInitialMapInstanceSizePrediction(
     500             :     const JSFunctionRef& function) {
     501        5404 :   MapRef initial_map = DependOnInitialMap(function);
     502        5404 :   int instance_size = function.InitialMapInstanceSizeWithMinSlack();
     503             :   // Currently, we always install the prediction dependency. If this turns out
     504             :   // to be too expensive, we can only install the dependency if slack
     505             :   // tracking is active.
     506             :   dependencies_.push_front(
     507             :       new (zone_)
     508       16212 :           InitialMapInstanceSizePredictionDependency(function, instance_size));
     509             :   DCHECK_LE(instance_size, function.initial_map().instance_size());
     510        5404 :   return SlackTrackingPrediction(initial_map, instance_size);
     511             : }
     512             : 
     513             : }  // namespace compiler
     514             : }  // namespace internal
     515      183867 : }  // namespace v8

Generated by: LCOV version 1.10