• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/compiler/compilation-dependency.h"
8 #include "src/execution/protectors.h"
9 #include "src/handles/handles-inl.h"
10 #include "src/objects/allocation-site-inl.h"
11 #include "src/objects/js-function-inl.h"
12 #include "src/objects/objects-inl.h"
13 #include "src/zone/zone-handle-set.h"
14 
15 namespace v8 {
16 namespace internal {
17 namespace compiler {
18 
CompilationDependencies(JSHeapBroker * broker,Zone * zone)19 CompilationDependencies::CompilationDependencies(JSHeapBroker* broker,
20                                                  Zone* zone)
21     : zone_(zone), broker_(broker), dependencies_(zone) {}
22 
23 class InitialMapDependency final : public CompilationDependency {
24  public:
25   // TODO(neis): Once the concurrent compiler frontend is always-on, we no
26   // longer need to explicitly store the initial map.
InitialMapDependency(const JSFunctionRef & function,const MapRef & initial_map)27   InitialMapDependency(const JSFunctionRef& function, const MapRef& initial_map)
28       : function_(function), initial_map_(initial_map) {
29     DCHECK(function_.has_initial_map());
30     DCHECK(function_.initial_map().equals(initial_map_));
31   }
32 
IsValid() const33   bool IsValid() const override {
34     Handle<JSFunction> function = function_.object();
35     return function->has_initial_map() &&
36            function->initial_map() == *initial_map_.object();
37   }
38 
Install(const MaybeObjectHandle & code) const39   void Install(const MaybeObjectHandle& code) const override {
40     SLOW_DCHECK(IsValid());
41     DependentCode::InstallDependency(function_.isolate(), code,
42                                      initial_map_.object(),
43                                      DependentCode::kInitialMapChangedGroup);
44   }
45 
46  private:
47   JSFunctionRef function_;
48   MapRef initial_map_;
49 };
50 
51 class PrototypePropertyDependency final : public CompilationDependency {
52  public:
53   // TODO(neis): Once the concurrent compiler frontend is always-on, we no
54   // longer need to explicitly store the prototype.
PrototypePropertyDependency(const JSFunctionRef & function,const ObjectRef & prototype)55   PrototypePropertyDependency(const JSFunctionRef& function,
56                               const ObjectRef& prototype)
57       : function_(function), prototype_(prototype) {
58     DCHECK(function_.has_prototype());
59     DCHECK(!function_.PrototypeRequiresRuntimeLookup());
60     DCHECK(function_.prototype().equals(prototype_));
61   }
62 
IsValid() const63   bool IsValid() const override {
64     Handle<JSFunction> function = function_.object();
65     return function->has_prototype_slot() && function->has_prototype() &&
66            !function->PrototypeRequiresRuntimeLookup() &&
67            function->prototype() == *prototype_.object();
68   }
69 
PrepareInstall() const70   void PrepareInstall() const override {
71     SLOW_DCHECK(IsValid());
72     Handle<JSFunction> function = function_.object();
73     if (!function->has_initial_map()) JSFunction::EnsureHasInitialMap(function);
74   }
75 
Install(const MaybeObjectHandle & code) const76   void Install(const MaybeObjectHandle& code) const override {
77     SLOW_DCHECK(IsValid());
78     Handle<JSFunction> function = function_.object();
79     DCHECK(function->has_initial_map());
80     Handle<Map> initial_map(function->initial_map(), function_.isolate());
81     DependentCode::InstallDependency(function_.isolate(), code, initial_map,
82                                      DependentCode::kInitialMapChangedGroup);
83   }
84 
85  private:
86   JSFunctionRef function_;
87   ObjectRef prototype_;
88 };
89 
90 class StableMapDependency final : public CompilationDependency {
91  public:
StableMapDependency(const MapRef & map)92   explicit StableMapDependency(const MapRef& map) : map_(map) {
93     DCHECK(map_.is_stable());
94   }
95 
IsValid() const96   bool IsValid() const override { return map_.object()->is_stable(); }
97 
Install(const MaybeObjectHandle & code) const98   void Install(const MaybeObjectHandle& code) const override {
99     SLOW_DCHECK(IsValid());
100     DependentCode::InstallDependency(map_.isolate(), code, map_.object(),
101                                      DependentCode::kPrototypeCheckGroup);
102   }
103 
104  private:
105   MapRef map_;
106 };
107 
108 class TransitionDependency final : public CompilationDependency {
109  public:
TransitionDependency(const MapRef & map)110   explicit TransitionDependency(const MapRef& map) : map_(map) {
111     DCHECK(!map_.is_deprecated());
112   }
113 
IsValid() const114   bool IsValid() const override { return !map_.object()->is_deprecated(); }
115 
Install(const MaybeObjectHandle & code) const116   void Install(const MaybeObjectHandle& code) const override {
117     SLOW_DCHECK(IsValid());
118     DependentCode::InstallDependency(map_.isolate(), code, map_.object(),
119                                      DependentCode::kTransitionGroup);
120   }
121 
122  private:
123   MapRef map_;
124 };
125 
126 class PretenureModeDependency final : public CompilationDependency {
127  public:
128   // TODO(neis): Once the concurrent compiler frontend is always-on, we no
129   // longer need to explicitly store the mode.
PretenureModeDependency(const AllocationSiteRef & site,AllocationType allocation)130   PretenureModeDependency(const AllocationSiteRef& site,
131                           AllocationType allocation)
132       : site_(site), allocation_(allocation) {
133     DCHECK_EQ(allocation, site_.GetAllocationType());
134   }
135 
IsValid() const136   bool IsValid() const override {
137     return allocation_ == site_.object()->GetAllocationType();
138   }
139 
Install(const MaybeObjectHandle & code) const140   void Install(const MaybeObjectHandle& code) const override {
141     SLOW_DCHECK(IsValid());
142     DependentCode::InstallDependency(
143         site_.isolate(), code, site_.object(),
144         DependentCode::kAllocationSiteTenuringChangedGroup);
145   }
146 
147 #ifdef DEBUG
IsPretenureModeDependency() const148   bool IsPretenureModeDependency() const override { return true; }
149 #endif
150 
151  private:
152   AllocationSiteRef site_;
153   AllocationType allocation_;
154 };
155 
156 class FieldRepresentationDependency final : public CompilationDependency {
157  public:
158   // TODO(neis): Once the concurrent compiler frontend is always-on, we no
159   // longer need to explicitly store the representation.
FieldRepresentationDependency(const MapRef & owner,InternalIndex descriptor,Representation representation)160   FieldRepresentationDependency(const MapRef& owner, InternalIndex descriptor,
161                                 Representation representation)
162       : owner_(owner),
163         descriptor_(descriptor),
164         representation_(representation) {
165     DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
166     DCHECK(representation_.Equals(
167         owner_.GetPropertyDetails(descriptor_).representation()));
168   }
169 
IsValid() const170   bool IsValid() const override {
171     DisallowHeapAllocation no_heap_allocation;
172     Handle<Map> owner = owner_.object();
173     return representation_.Equals(owner->instance_descriptors(kRelaxedLoad)
174                                       .GetDetails(descriptor_)
175                                       .representation());
176   }
177 
Install(const MaybeObjectHandle & code) const178   void Install(const MaybeObjectHandle& code) const override {
179     SLOW_DCHECK(IsValid());
180     DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
181                                      DependentCode::kFieldRepresentationGroup);
182   }
183 
184 #ifdef DEBUG
IsFieldRepresentationDependencyOnMap(Handle<Map> const & receiver_map) const185   bool IsFieldRepresentationDependencyOnMap(
186       Handle<Map> const& receiver_map) const override {
187     return owner_.object().equals(receiver_map);
188   }
189 #endif
190 
191  private:
192   MapRef owner_;
193   InternalIndex descriptor_;
194   Representation representation_;
195 };
196 
197 class FieldTypeDependency final : public CompilationDependency {
198  public:
199   // TODO(neis): Once the concurrent compiler frontend is always-on, we no
200   // longer need to explicitly store the type.
FieldTypeDependency(const MapRef & owner,InternalIndex descriptor,const ObjectRef & type)201   FieldTypeDependency(const MapRef& owner, InternalIndex descriptor,
202                       const ObjectRef& type)
203       : owner_(owner), descriptor_(descriptor), type_(type) {
204     DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
205     DCHECK(type_.equals(owner_.GetFieldType(descriptor_)));
206   }
207 
IsValid() const208   bool IsValid() const override {
209     DisallowHeapAllocation no_heap_allocation;
210     Handle<Map> owner = owner_.object();
211     Handle<Object> type = type_.object();
212     return *type ==
213            owner->instance_descriptors(kRelaxedLoad).GetFieldType(descriptor_);
214   }
215 
Install(const MaybeObjectHandle & code) const216   void Install(const MaybeObjectHandle& code) const override {
217     SLOW_DCHECK(IsValid());
218     DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
219                                      DependentCode::kFieldTypeGroup);
220   }
221 
222  private:
223   MapRef owner_;
224   InternalIndex descriptor_;
225   ObjectRef type_;
226 };
227 
228 class FieldConstnessDependency final : public CompilationDependency {
229  public:
FieldConstnessDependency(const MapRef & owner,InternalIndex descriptor)230   FieldConstnessDependency(const MapRef& owner, InternalIndex descriptor)
231       : owner_(owner), descriptor_(descriptor) {
232     DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
233     DCHECK_EQ(PropertyConstness::kConst,
234               owner_.GetPropertyDetails(descriptor_).constness());
235   }
236 
IsValid() const237   bool IsValid() const override {
238     DisallowHeapAllocation no_heap_allocation;
239     Handle<Map> owner = owner_.object();
240     return PropertyConstness::kConst ==
241            owner->instance_descriptors(kRelaxedLoad)
242                .GetDetails(descriptor_)
243                .constness();
244   }
245 
Install(const MaybeObjectHandle & code) const246   void Install(const MaybeObjectHandle& code) const override {
247     SLOW_DCHECK(IsValid());
248     DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
249                                      DependentCode::kFieldConstGroup);
250   }
251 
252  private:
253   MapRef owner_;
254   InternalIndex descriptor_;
255 };
256 
257 class GlobalPropertyDependency final : public CompilationDependency {
258  public:
259   // TODO(neis): Once the concurrent compiler frontend is always-on, we no
260   // longer need to explicitly store the type and the read_only flag.
GlobalPropertyDependency(const PropertyCellRef & cell,PropertyCellType type,bool read_only)261   GlobalPropertyDependency(const PropertyCellRef& cell, PropertyCellType type,
262                            bool read_only)
263       : cell_(cell), type_(type), read_only_(read_only) {
264     DCHECK_EQ(type_, cell_.property_details().cell_type());
265     DCHECK_EQ(read_only_, cell_.property_details().IsReadOnly());
266   }
267 
IsValid() const268   bool IsValid() const override {
269     Handle<PropertyCell> cell = cell_.object();
270     // The dependency is never valid if the cell is 'invalidated'. This is
271     // marked by setting the value to the hole.
272     if (cell->value() == *(cell_.isolate()->factory()->the_hole_value())) {
273       DCHECK(cell->property_details().cell_type() ==
274                  PropertyCellType::kInvalidated ||
275              cell->property_details().cell_type() ==
276                  PropertyCellType::kUninitialized);
277       return false;
278     }
279     return type_ == cell->property_details().cell_type() &&
280            read_only_ == cell->property_details().IsReadOnly();
281   }
282 
Install(const MaybeObjectHandle & code) const283   void Install(const MaybeObjectHandle& code) const override {
284     SLOW_DCHECK(IsValid());
285     DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(),
286                                      DependentCode::kPropertyCellChangedGroup);
287   }
288 
289  private:
290   PropertyCellRef cell_;
291   PropertyCellType type_;
292   bool read_only_;
293 };
294 
295 class ProtectorDependency final : public CompilationDependency {
296  public:
ProtectorDependency(const PropertyCellRef & cell)297   explicit ProtectorDependency(const PropertyCellRef& cell) : cell_(cell) {
298     DCHECK_EQ(cell_.value().AsSmi(), Protectors::kProtectorValid);
299   }
300 
IsValid() const301   bool IsValid() const override {
302     Handle<PropertyCell> cell = cell_.object();
303     return cell->value() == Smi::FromInt(Protectors::kProtectorValid);
304   }
305 
Install(const MaybeObjectHandle & code) const306   void Install(const MaybeObjectHandle& code) const override {
307     SLOW_DCHECK(IsValid());
308     DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(),
309                                      DependentCode::kPropertyCellChangedGroup);
310   }
311 
312  private:
313   PropertyCellRef cell_;
314 };
315 
316 class ElementsKindDependency final : public CompilationDependency {
317  public:
318   // TODO(neis): Once the concurrent compiler frontend is always-on, we no
319   // longer need to explicitly store the elements kind.
ElementsKindDependency(const AllocationSiteRef & site,ElementsKind kind)320   ElementsKindDependency(const AllocationSiteRef& site, ElementsKind kind)
321       : site_(site), kind_(kind) {
322     DCHECK(AllocationSite::ShouldTrack(kind_));
323     DCHECK_EQ(kind_, site_.PointsToLiteral()
324                          ? site_.boilerplate().value().GetElementsKind()
325                          : site_.GetElementsKind());
326   }
327 
IsValid() const328   bool IsValid() const override {
329     Handle<AllocationSite> site = site_.object();
330     ElementsKind kind = site->PointsToLiteral()
331                             ? site->boilerplate().GetElementsKind()
332                             : site->GetElementsKind();
333     return kind_ == kind;
334   }
335 
Install(const MaybeObjectHandle & code) const336   void Install(const MaybeObjectHandle& code) const override {
337     SLOW_DCHECK(IsValid());
338     DependentCode::InstallDependency(
339         site_.isolate(), code, site_.object(),
340         DependentCode::kAllocationSiteTransitionChangedGroup);
341   }
342 
343  private:
344   AllocationSiteRef site_;
345   ElementsKind kind_;
346 };
347 
348 class InitialMapInstanceSizePredictionDependency final
349     : public CompilationDependency {
350  public:
InitialMapInstanceSizePredictionDependency(const JSFunctionRef & function,int instance_size)351   InitialMapInstanceSizePredictionDependency(const JSFunctionRef& function,
352                                              int instance_size)
353       : function_(function), instance_size_(instance_size) {}
354 
IsValid() const355   bool IsValid() const override {
356     // The dependency is valid if the prediction is the same as the current
357     // slack tracking result.
358     if (!function_.object()->has_initial_map()) return false;
359     int instance_size = function_.object()->ComputeInstanceSizeWithMinSlack(
360         function_.isolate());
361     return instance_size == instance_size_;
362   }
363 
PrepareInstall() const364   void PrepareInstall() const override {
365     SLOW_DCHECK(IsValid());
366     function_.object()->CompleteInobjectSlackTrackingIfActive();
367   }
368 
Install(const MaybeObjectHandle & code) const369   void Install(const MaybeObjectHandle& code) const override {
370     SLOW_DCHECK(IsValid());
371     DCHECK(
372         !function_.object()->initial_map().IsInobjectSlackTrackingInProgress());
373   }
374 
375  private:
376   JSFunctionRef function_;
377   int instance_size_;
378 };
379 
RecordDependency(CompilationDependency const * dependency)380 void CompilationDependencies::RecordDependency(
381     CompilationDependency const* dependency) {
382   if (dependency != nullptr) dependencies_.push_front(dependency);
383 }
384 
DependOnInitialMap(const JSFunctionRef & function)385 MapRef CompilationDependencies::DependOnInitialMap(
386     const JSFunctionRef& function) {
387   MapRef map = function.initial_map();
388   RecordDependency(zone_->New<InitialMapDependency>(function, map));
389   return map;
390 }
391 
DependOnPrototypeProperty(const JSFunctionRef & function)392 ObjectRef CompilationDependencies::DependOnPrototypeProperty(
393     const JSFunctionRef& function) {
394   ObjectRef prototype = function.prototype();
395   RecordDependency(
396       zone_->New<PrototypePropertyDependency>(function, prototype));
397   return prototype;
398 }
399 
DependOnStableMap(const MapRef & map)400 void CompilationDependencies::DependOnStableMap(const MapRef& map) {
401   if (map.CanTransition()) {
402     RecordDependency(zone_->New<StableMapDependency>(map));
403   } else {
404     DCHECK(map.is_stable());
405   }
406 }
407 
DependOnTransition(const MapRef & target_map)408 void CompilationDependencies::DependOnTransition(const MapRef& target_map) {
409   RecordDependency(TransitionDependencyOffTheRecord(target_map));
410 }
411 
DependOnPretenureMode(const AllocationSiteRef & site)412 AllocationType CompilationDependencies::DependOnPretenureMode(
413     const AllocationSiteRef& site) {
414   AllocationType allocation = site.GetAllocationType();
415   RecordDependency(zone_->New<PretenureModeDependency>(site, allocation));
416   return allocation;
417 }
418 
DependOnFieldConstness(const MapRef & map,InternalIndex descriptor)419 PropertyConstness CompilationDependencies::DependOnFieldConstness(
420     const MapRef& map, InternalIndex descriptor) {
421   MapRef owner = map.FindFieldOwner(descriptor);
422   PropertyConstness constness =
423       owner.GetPropertyDetails(descriptor).constness();
424   if (constness == PropertyConstness::kMutable) return constness;
425 
426   // If the map can have fast elements transitions, then the field can be only
427   // considered constant if the map does not transition.
428   if (Map::CanHaveFastTransitionableElementsKind(map.instance_type())) {
429     // If the map can already transition away, let us report the field as
430     // mutable.
431     if (!map.is_stable()) {
432       return PropertyConstness::kMutable;
433     }
434     DependOnStableMap(map);
435   }
436 
437   DCHECK_EQ(constness, PropertyConstness::kConst);
438   RecordDependency(zone_->New<FieldConstnessDependency>(owner, descriptor));
439   return PropertyConstness::kConst;
440 }
441 
DependOnFieldRepresentation(const MapRef & map,InternalIndex descriptor)442 void CompilationDependencies::DependOnFieldRepresentation(
443     const MapRef& map, InternalIndex descriptor) {
444   RecordDependency(FieldRepresentationDependencyOffTheRecord(map, descriptor));
445 }
446 
DependOnFieldType(const MapRef & map,InternalIndex descriptor)447 void CompilationDependencies::DependOnFieldType(const MapRef& map,
448                                                 InternalIndex descriptor) {
449   RecordDependency(FieldTypeDependencyOffTheRecord(map, descriptor));
450 }
451 
DependOnGlobalProperty(const PropertyCellRef & cell)452 void CompilationDependencies::DependOnGlobalProperty(
453     const PropertyCellRef& cell) {
454   PropertyCellType type = cell.property_details().cell_type();
455   bool read_only = cell.property_details().IsReadOnly();
456   RecordDependency(zone_->New<GlobalPropertyDependency>(cell, type, read_only));
457 }
458 
DependOnProtector(const PropertyCellRef & cell)459 bool CompilationDependencies::DependOnProtector(const PropertyCellRef& cell) {
460   if (cell.value().AsSmi() != Protectors::kProtectorValid) return false;
461   RecordDependency(zone_->New<ProtectorDependency>(cell));
462   return true;
463 }
464 
DependOnArrayBufferDetachingProtector()465 bool CompilationDependencies::DependOnArrayBufferDetachingProtector() {
466   return DependOnProtector(PropertyCellRef(
467       broker_,
468       broker_->isolate()->factory()->array_buffer_detaching_protector()));
469 }
470 
DependOnArrayIteratorProtector()471 bool CompilationDependencies::DependOnArrayIteratorProtector() {
472   return DependOnProtector(PropertyCellRef(
473       broker_, broker_->isolate()->factory()->array_iterator_protector()));
474 }
475 
DependOnArraySpeciesProtector()476 bool CompilationDependencies::DependOnArraySpeciesProtector() {
477   return DependOnProtector(PropertyCellRef(
478       broker_, broker_->isolate()->factory()->array_species_protector()));
479 }
480 
DependOnNoElementsProtector()481 bool CompilationDependencies::DependOnNoElementsProtector() {
482   return DependOnProtector(PropertyCellRef(
483       broker_, broker_->isolate()->factory()->no_elements_protector()));
484 }
485 
DependOnPromiseHookProtector()486 bool CompilationDependencies::DependOnPromiseHookProtector() {
487   return DependOnProtector(PropertyCellRef(
488       broker_, broker_->isolate()->factory()->promise_hook_protector()));
489 }
490 
DependOnPromiseSpeciesProtector()491 bool CompilationDependencies::DependOnPromiseSpeciesProtector() {
492   return DependOnProtector(PropertyCellRef(
493       broker_, broker_->isolate()->factory()->promise_species_protector()));
494 }
495 
DependOnPromiseThenProtector()496 bool CompilationDependencies::DependOnPromiseThenProtector() {
497   return DependOnProtector(PropertyCellRef(
498       broker_, broker_->isolate()->factory()->promise_then_protector()));
499 }
500 
DependOnElementsKind(const AllocationSiteRef & site)501 void CompilationDependencies::DependOnElementsKind(
502     const AllocationSiteRef& site) {
503   // Do nothing if the object doesn't have any useful element transitions left.
504   ElementsKind kind = site.PointsToLiteral()
505                           ? site.boilerplate().value().GetElementsKind()
506                           : site.GetElementsKind();
507   if (AllocationSite::ShouldTrack(kind)) {
508     RecordDependency(zone_->New<ElementsKindDependency>(site, kind));
509   }
510 }
511 
AreValid() const512 bool CompilationDependencies::AreValid() const {
513   for (auto dep : dependencies_) {
514     if (!dep->IsValid()) return false;
515   }
516   return true;
517 }
518 
Commit(Handle<Code> code)519 bool CompilationDependencies::Commit(Handle<Code> code) {
520   // Dependencies are context-dependent. In the future it may be possible to
521   // restore them in the consumer native context, but for now they are
522   // disabled.
523   CHECK_IMPLIES(broker_->is_native_context_independent(),
524                 dependencies_.empty());
525 
526   for (auto dep : dependencies_) {
527     if (!dep->IsValid()) {
528       dependencies_.clear();
529       return false;
530     }
531     dep->PrepareInstall();
532   }
533 
534   DisallowCodeDependencyChange no_dependency_change;
535   for (auto dep : dependencies_) {
536     // Check each dependency's validity again right before installing it,
537     // because the first iteration above might have invalidated some
538     // dependencies. For example, PrototypePropertyDependency::PrepareInstall
539     // can call EnsureHasInitialMap, which can invalidate a StableMapDependency
540     // on the prototype object's map.
541     if (!dep->IsValid()) {
542       dependencies_.clear();
543       return false;
544     }
545     dep->Install(MaybeObjectHandle::Weak(code));
546   }
547 
548   // It is even possible that a GC during the above installations invalidated
549   // one of the dependencies. However, this should only affect pretenure mode
550   // dependencies, which we assert below. It is safe to return successfully in
551   // these cases, because once the code gets executed it will do a stack check
552   // that triggers its deoptimization.
553   if (FLAG_stress_gc_during_compilation) {
554     broker_->isolate()->heap()->PreciseCollectAllGarbage(
555         Heap::kForcedGC, GarbageCollectionReason::kTesting, kNoGCCallbackFlags);
556   }
557 #ifdef DEBUG
558   for (auto dep : dependencies_) {
559     CHECK_IMPLIES(!dep->IsValid(), dep->IsPretenureModeDependency());
560   }
561 #endif
562 
563   dependencies_.clear();
564   return true;
565 }
566 
567 namespace {
568 // This function expects to never see a JSProxy.
DependOnStablePrototypeChain(CompilationDependencies * deps,MapRef map,base::Optional<JSObjectRef> last_prototype)569 void DependOnStablePrototypeChain(CompilationDependencies* deps, MapRef map,
570                                   base::Optional<JSObjectRef> last_prototype) {
571   while (true) {
572     HeapObjectRef proto = map.prototype();
573     if (!proto.IsJSObject()) {
574       CHECK_EQ(proto.map().oddball_type(), OddballType::kNull);
575       break;
576     }
577     map = proto.map();
578     deps->DependOnStableMap(map);
579     if (last_prototype.has_value() && proto.equals(*last_prototype)) break;
580   }
581 }
582 }  // namespace
583 
584 template <class MapContainer>
DependOnStablePrototypeChains(MapContainer const & receiver_maps,WhereToStart start,base::Optional<JSObjectRef> last_prototype)585 void CompilationDependencies::DependOnStablePrototypeChains(
586     MapContainer const& receiver_maps, WhereToStart start,
587     base::Optional<JSObjectRef> last_prototype) {
588   for (auto map : receiver_maps) {
589     MapRef receiver_map(broker_, map);
590     if (start == kStartAtReceiver) DependOnStableMap(receiver_map);
591     if (receiver_map.IsPrimitiveMap()) {
592       // Perform the implicit ToObject for primitives here.
593       // Implemented according to ES6 section 7.3.2 GetV (V, P).
594       base::Optional<JSFunctionRef> constructor =
595           broker_->target_native_context().GetConstructorFunction(receiver_map);
596       if (constructor.has_value()) receiver_map = constructor->initial_map();
597     }
598     DependOnStablePrototypeChain(this, receiver_map, last_prototype);
599   }
600 }
601 template void CompilationDependencies::DependOnStablePrototypeChains(
602     ZoneVector<Handle<Map>> const& receiver_maps, WhereToStart start,
603     base::Optional<JSObjectRef> last_prototype);
604 template void CompilationDependencies::DependOnStablePrototypeChains(
605     ZoneHandleSet<Map> const& receiver_maps, WhereToStart start,
606     base::Optional<JSObjectRef> last_prototype);
607 
DependOnElementsKinds(const AllocationSiteRef & site)608 void CompilationDependencies::DependOnElementsKinds(
609     const AllocationSiteRef& site) {
610   AllocationSiteRef current = site;
611   while (true) {
612     DependOnElementsKind(current);
613     if (!current.nested_site().IsAllocationSite()) break;
614     current = current.nested_site().AsAllocationSite();
615   }
616   CHECK_EQ(current.nested_site().AsSmi(), 0);
617 }
618 
SlackTrackingPrediction(MapRef initial_map,int instance_size)619 SlackTrackingPrediction::SlackTrackingPrediction(MapRef initial_map,
620                                                  int instance_size)
621     : instance_size_(instance_size),
622       inobject_property_count_(
623           (instance_size >> kTaggedSizeLog2) -
624           initial_map.GetInObjectPropertiesStartInWords()) {}
625 
626 SlackTrackingPrediction
DependOnInitialMapInstanceSizePrediction(const JSFunctionRef & function)627 CompilationDependencies::DependOnInitialMapInstanceSizePrediction(
628     const JSFunctionRef& function) {
629   MapRef initial_map = DependOnInitialMap(function);
630   int instance_size = function.InitialMapInstanceSizeWithMinSlack();
631   // Currently, we always install the prediction dependency. If this turns out
632   // to be too expensive, we can only install the dependency if slack
633   // tracking is active.
634   RecordDependency(zone_->New<InitialMapInstanceSizePredictionDependency>(
635       function, instance_size));
636   DCHECK_LE(instance_size, function.initial_map().instance_size());
637   return SlackTrackingPrediction(initial_map, instance_size);
638 }
639 
640 CompilationDependency const*
TransitionDependencyOffTheRecord(const MapRef & target_map) const641 CompilationDependencies::TransitionDependencyOffTheRecord(
642     const MapRef& target_map) const {
643   if (target_map.CanBeDeprecated()) {
644     return zone_->New<TransitionDependency>(target_map);
645   } else {
646     DCHECK(!target_map.is_deprecated());
647     return nullptr;
648   }
649 }
650 
651 CompilationDependency const*
FieldRepresentationDependencyOffTheRecord(const MapRef & map,InternalIndex descriptor) const652 CompilationDependencies::FieldRepresentationDependencyOffTheRecord(
653     const MapRef& map, InternalIndex descriptor) const {
654   MapRef owner = map.FindFieldOwner(descriptor);
655   PropertyDetails details = owner.GetPropertyDetails(descriptor);
656   DCHECK(details.representation().Equals(
657       map.GetPropertyDetails(descriptor).representation()));
658   return zone_->New<FieldRepresentationDependency>(owner, descriptor,
659                                                    details.representation());
660 }
661 
662 CompilationDependency const*
FieldTypeDependencyOffTheRecord(const MapRef & map,InternalIndex descriptor) const663 CompilationDependencies::FieldTypeDependencyOffTheRecord(
664     const MapRef& map, InternalIndex descriptor) const {
665   MapRef owner = map.FindFieldOwner(descriptor);
666   ObjectRef type = owner.GetFieldType(descriptor);
667   DCHECK(type.equals(map.GetFieldType(descriptor)));
668   return zone_->New<FieldTypeDependency>(owner, descriptor, type);
669 }
670 
671 }  // namespace compiler
672 }  // namespace internal
673 }  // namespace v8
674