• 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/base/optional.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/internal-index.h"
12 #include "src/objects/js-array-inl.h"
13 #include "src/objects/js-function-inl.h"
14 #include "src/objects/objects-inl.h"
15 #include "src/zone/zone-handle-set.h"
16 
17 namespace v8 {
18 namespace internal {
19 namespace compiler {
20 
21 #define DEPENDENCY_LIST(V)              \
22   V(ConsistentJSFunctionView)           \
23   V(ConstantInDictionaryPrototypeChain) \
24   V(ElementsKind)                       \
25   V(FieldConstness)                     \
26   V(FieldRepresentation)                \
27   V(FieldType)                          \
28   V(GlobalProperty)                     \
29   V(InitialMap)                         \
30   V(InitialMapInstanceSizePrediction)   \
31   V(OwnConstantDataProperty)            \
32   V(OwnConstantDictionaryProperty)      \
33   V(OwnConstantElement)                 \
34   V(PretenureMode)                      \
35   V(Protector)                          \
36   V(PrototypeProperty)                  \
37   V(StableMap)                          \
38   V(Transition)                         \
39   V(ObjectSlotValue)
40 
CompilationDependencies(JSHeapBroker * broker,Zone * zone)41 CompilationDependencies::CompilationDependencies(JSHeapBroker* broker,
42                                                  Zone* zone)
43     : zone_(zone), broker_(broker), dependencies_(zone) {
44   broker->set_dependencies(this);
45 }
46 
47 namespace {
48 
49 enum CompilationDependencyKind {
50 #define V(Name) k##Name,
51   DEPENDENCY_LIST(V)
52 #undef V
53 };
54 
55 #define V(Name) class Name##Dependency;
DEPENDENCY_LIST(V) const56 DEPENDENCY_LIST(V)
57 #undef V
58 
59 const char* CompilationDependencyKindToString(CompilationDependencyKind kind) {
60 #define V(Name) #Name "Dependency",
61   static const char* const names[] = {DEPENDENCY_LIST(V)};
62 #undef V
63   return names[kind];
64 }
65 
66 class PendingDependencies;
67 
68 }  // namespace
69 
70 class CompilationDependency : public ZoneObject {
71  public:
CompilationDependency(CompilationDependencyKind kind)72   explicit CompilationDependency(CompilationDependencyKind kind) : kind(kind) {}
73 
74   virtual bool IsValid() const = 0;
PrepareInstall() const75   virtual void PrepareInstall() const {}
76   virtual void Install(PendingDependencies* deps) const = 0;
77 
78 #define V(Name)                                     \
79   bool Is##Name() const { return kind == k##Name; } \
80   V8_ALLOW_UNUSED const Name##Dependency* As##Name() const;
DEPENDENCY_LIST(V) const81   DEPENDENCY_LIST(V)
82 #undef V
83 
84   const char* ToString() const {
85     return CompilationDependencyKindToString(kind);
86   }
87 
88   const CompilationDependencyKind kind;
89 
90  private:
91   virtual size_t Hash() const = 0;
92   virtual bool Equals(const CompilationDependency* that) const = 0;
93   friend struct CompilationDependencies::CompilationDependencyHash;
94   friend struct CompilationDependencies::CompilationDependencyEqual;
95 };
96 
operator ()(const CompilationDependency * dep) const97 size_t CompilationDependencies::CompilationDependencyHash::operator()(
98     const CompilationDependency* dep) const {
99   return base::hash_combine(dep->kind, dep->Hash());
100 }
101 
operator ()(const CompilationDependency * lhs,const CompilationDependency * rhs) const102 bool CompilationDependencies::CompilationDependencyEqual::operator()(
103     const CompilationDependency* lhs, const CompilationDependency* rhs) const {
104   return lhs->kind == rhs->kind && lhs->Equals(rhs);
105 }
106 
107 namespace {
108 
109 // Dependencies can only be fully deduplicated immediately prior to
110 // installation (because PrepareInstall may create the object on which the dep
111 // will be installed). We gather and dedupe deps in this class, and install
112 // them from here.
113 class PendingDependencies final {
114  public:
PendingDependencies(Zone * zone)115   explicit PendingDependencies(Zone* zone) : deps_(zone) {}
116 
Register(Handle<HeapObject> object,DependentCode::DependencyGroup group)117   void Register(Handle<HeapObject> object,
118                 DependentCode::DependencyGroup group) {
119     deps_[object] |= group;
120   }
121 
InstallAll(Isolate * isolate,Handle<Code> code)122   void InstallAll(Isolate* isolate, Handle<Code> code) {
123     if (V8_UNLIKELY(FLAG_predictable)) {
124       InstallAllPredictable(isolate, code);
125       return;
126     }
127 
128     // With deduplication done we no longer rely on the object address for
129     // hashing.
130     AllowGarbageCollection yes_gc;
131     for (const auto& o_and_g : deps_) {
132       DependentCode::InstallDependency(isolate, code, o_and_g.first,
133                                        o_and_g.second);
134     }
135   }
136 
InstallAllPredictable(Isolate * isolate,Handle<Code> code)137   void InstallAllPredictable(Isolate* isolate, Handle<Code> code) {
138     CHECK(FLAG_predictable);
139     // First, guarantee predictable iteration order.
140     using HandleAndGroup =
141         std::pair<Handle<HeapObject>, DependentCode::DependencyGroups>;
142     std::vector<HandleAndGroup> entries(deps_.begin(), deps_.end());
143 
144     std::sort(entries.begin(), entries.end(),
145               [](const HandleAndGroup& lhs, const HandleAndGroup& rhs) {
146                 return lhs.first->ptr() < rhs.first->ptr();
147               });
148 
149     // With deduplication done we no longer rely on the object address for
150     // hashing.
151     AllowGarbageCollection yes_gc;
152     for (const auto& o_and_g : entries) {
153       DependentCode::InstallDependency(isolate, code, o_and_g.first,
154                                        o_and_g.second);
155     }
156   }
157 
158  private:
159   struct HandleHash {
operator ()v8::internal::compiler::__anon82456ba40211::PendingDependencies::HandleHash160     size_t operator()(const Handle<HeapObject>& x) const {
161       return static_cast<size_t>(x->ptr());
162     }
163   };
164   struct HandleEqual {
operator ()v8::internal::compiler::__anon82456ba40211::PendingDependencies::HandleEqual165     bool operator()(const Handle<HeapObject>& lhs,
166                     const Handle<HeapObject>& rhs) const {
167       return lhs.is_identical_to(rhs);
168     }
169   };
170   ZoneUnorderedMap<Handle<HeapObject>, DependentCode::DependencyGroups,
171                    HandleHash, HandleEqual>
172       deps_;
173   const DisallowGarbageCollection no_gc_;
174 };
175 
176 class InitialMapDependency final : public CompilationDependency {
177  public:
InitialMapDependency(JSHeapBroker * broker,const JSFunctionRef & function,const MapRef & initial_map)178   InitialMapDependency(JSHeapBroker* broker, const JSFunctionRef& function,
179                        const MapRef& initial_map)
180       : CompilationDependency(kInitialMap),
181         function_(function),
182         initial_map_(initial_map) {}
183 
IsValid() const184   bool IsValid() const override {
185     Handle<JSFunction> function = function_.object();
186     return function->has_initial_map() &&
187            function->initial_map() == *initial_map_.object();
188   }
189 
Install(PendingDependencies * deps) const190   void Install(PendingDependencies* deps) const override {
191     SLOW_DCHECK(IsValid());
192     deps->Register(initial_map_.object(),
193                    DependentCode::kInitialMapChangedGroup);
194   }
195 
196  private:
Hash() const197   size_t Hash() const override {
198     ObjectRef::Hash h;
199     return base::hash_combine(h(function_), h(initial_map_));
200   }
201 
Equals(const CompilationDependency * that) const202   bool Equals(const CompilationDependency* that) const override {
203     const InitialMapDependency* const zat = that->AsInitialMap();
204     return function_.equals(zat->function_) &&
205            initial_map_.equals(zat->initial_map_);
206   }
207 
208   const JSFunctionRef function_;
209   const MapRef initial_map_;
210 };
211 
212 class PrototypePropertyDependency final : public CompilationDependency {
213  public:
PrototypePropertyDependency(JSHeapBroker * broker,const JSFunctionRef & function,const ObjectRef & prototype)214   PrototypePropertyDependency(JSHeapBroker* broker,
215                               const JSFunctionRef& function,
216                               const ObjectRef& prototype)
217       : CompilationDependency(kPrototypeProperty),
218         function_(function),
219         prototype_(prototype) {
220     DCHECK(function_.has_instance_prototype(broker->dependencies()));
221     DCHECK(!function_.PrototypeRequiresRuntimeLookup(broker->dependencies()));
222     DCHECK(function_.instance_prototype(broker->dependencies())
223                .equals(prototype_));
224   }
225 
IsValid() const226   bool IsValid() const override {
227     Handle<JSFunction> function = function_.object();
228     return function->has_prototype_slot() &&
229            function->has_instance_prototype() &&
230            !function->PrototypeRequiresRuntimeLookup() &&
231            function->instance_prototype() == *prototype_.object();
232   }
233 
PrepareInstall() const234   void PrepareInstall() const override {
235     SLOW_DCHECK(IsValid());
236     Handle<JSFunction> function = function_.object();
237     if (!function->has_initial_map()) JSFunction::EnsureHasInitialMap(function);
238   }
239 
Install(PendingDependencies * deps) const240   void Install(PendingDependencies* deps) const override {
241     SLOW_DCHECK(IsValid());
242     Handle<JSFunction> function = function_.object();
243     CHECK(function->has_initial_map());
244     Handle<Map> initial_map(function->initial_map(), function_.isolate());
245     deps->Register(initial_map, DependentCode::kInitialMapChangedGroup);
246   }
247 
248  private:
Hash() const249   size_t Hash() const override {
250     ObjectRef::Hash h;
251     return base::hash_combine(h(function_), h(prototype_));
252   }
253 
Equals(const CompilationDependency * that) const254   bool Equals(const CompilationDependency* that) const override {
255     const PrototypePropertyDependency* const zat = that->AsPrototypeProperty();
256     return function_.equals(zat->function_) &&
257            prototype_.equals(zat->prototype_);
258   }
259 
260   const JSFunctionRef function_;
261   const ObjectRef prototype_;
262 };
263 
264 class StableMapDependency final : public CompilationDependency {
265  public:
StableMapDependency(const MapRef & map)266   explicit StableMapDependency(const MapRef& map)
267       : CompilationDependency(kStableMap), map_(map) {}
268 
IsValid() const269   bool IsValid() const override {
270     // TODO(v8:11670): Consider turn this back into a CHECK inside the
271     // constructor and DependOnStableMap, if possible in light of concurrent
272     // heap state modifications.
273     return !map_.object()->is_dictionary_map() && map_.object()->is_stable();
274   }
Install(PendingDependencies * deps) const275   void Install(PendingDependencies* deps) const override {
276     SLOW_DCHECK(IsValid());
277     deps->Register(map_.object(), DependentCode::kPrototypeCheckGroup);
278   }
279 
280  private:
Hash() const281   size_t Hash() const override {
282     ObjectRef::Hash h;
283     return base::hash_combine(h(map_));
284   }
285 
Equals(const CompilationDependency * that) const286   bool Equals(const CompilationDependency* that) const override {
287     const StableMapDependency* const zat = that->AsStableMap();
288     return map_.equals(zat->map_);
289   }
290 
291   const MapRef map_;
292 };
293 
294 class ConstantInDictionaryPrototypeChainDependency final
295     : public CompilationDependency {
296  public:
ConstantInDictionaryPrototypeChainDependency(const MapRef receiver_map,const NameRef property_name,const ObjectRef constant,PropertyKind kind)297   explicit ConstantInDictionaryPrototypeChainDependency(
298       const MapRef receiver_map, const NameRef property_name,
299       const ObjectRef constant, PropertyKind kind)
300       : CompilationDependency(kConstantInDictionaryPrototypeChain),
301         receiver_map_(receiver_map),
302         property_name_{property_name},
303         constant_{constant},
304         kind_{kind} {
305     DCHECK(V8_DICT_PROPERTY_CONST_TRACKING_BOOL);
306   }
307 
308   // Checks that |constant_| is still the value of accessing |property_name_|
309   // starting at |receiver_map_|.
IsValid() const310   bool IsValid() const override { return !GetHolderIfValid().is_null(); }
311 
Install(PendingDependencies * deps) const312   void Install(PendingDependencies* deps) const override {
313     SLOW_DCHECK(IsValid());
314     Isolate* isolate = receiver_map_.isolate();
315     Handle<JSObject> holder = GetHolderIfValid().ToHandleChecked();
316     Handle<Map> map = receiver_map_.object();
317 
318     while (map->prototype() != *holder) {
319       map = handle(map->prototype().map(), isolate);
320       DCHECK(map->IsJSObjectMap());  // Due to IsValid holding.
321       deps->Register(map, DependentCode::kPrototypeCheckGroup);
322     }
323 
324     DCHECK(map->prototype().map().IsJSObjectMap());  // Due to IsValid holding.
325     deps->Register(handle(map->prototype().map(), isolate),
326                    DependentCode::kPrototypeCheckGroup);
327   }
328 
329  private:
330   // If the dependency is still valid, returns holder of the constant. Otherwise
331   // returns null.
332   // TODO(neis) Currently, invoking IsValid and then Install duplicates the call
333   // to GetHolderIfValid. Instead, consider letting IsValid change the state
334   // (and store the holder), or merge IsValid and Install.
GetHolderIfValid() const335   MaybeHandle<JSObject> GetHolderIfValid() const {
336     DisallowGarbageCollection no_gc;
337     Isolate* isolate = receiver_map_.isolate();
338 
339     Handle<Object> holder;
340     HeapObject prototype = receiver_map_.object()->prototype();
341 
342     enum class ValidationResult { kFoundCorrect, kFoundIncorrect, kNotFound };
343     auto try_load = [&](auto dictionary) -> ValidationResult {
344       InternalIndex entry =
345           dictionary.FindEntry(isolate, property_name_.object());
346       if (entry.is_not_found()) {
347         return ValidationResult::kNotFound;
348       }
349 
350       PropertyDetails details = dictionary.DetailsAt(entry);
351       if (details.constness() != PropertyConstness::kConst) {
352         return ValidationResult::kFoundIncorrect;
353       }
354 
355       Object dictionary_value = dictionary.ValueAt(entry);
356       Object value;
357       // We must be able to detect the case that the property |property_name_|
358       // of |holder_| was originally a plain function |constant_| (when creating
359       // this dependency) and has since become an accessor whose getter is
360       // |constant_|. Therefore, we cannot just look at the property kind of
361       // |details|, because that reflects the current situation, not the one
362       // when creating this dependency.
363       if (details.kind() != kind_) {
364         return ValidationResult::kFoundIncorrect;
365       }
366       if (kind_ == PropertyKind::kAccessor) {
367         if (!dictionary_value.IsAccessorPair()) {
368           return ValidationResult::kFoundIncorrect;
369         }
370         // Only supporting loading at the moment, so we only ever want the
371         // getter.
372         value = AccessorPair::cast(dictionary_value)
373                     .get(AccessorComponent::ACCESSOR_GETTER);
374       } else {
375         value = dictionary_value;
376       }
377       return value == *constant_.object() ? ValidationResult::kFoundCorrect
378                                           : ValidationResult::kFoundIncorrect;
379     };
380 
381     while (prototype.IsJSObject()) {
382       // We only care about JSObjects because that's the only type of holder
383       // (and types of prototypes on the chain to the holder) that
384       // AccessInfoFactory::ComputePropertyAccessInfo allows.
385       JSObject object = JSObject::cast(prototype);
386 
387       // We only support dictionary mode prototypes on the chain for this kind
388       // of dependency.
389       CHECK(!object.HasFastProperties());
390 
391       ValidationResult result =
392           V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL
393               ? try_load(object.property_dictionary_swiss())
394               : try_load(object.property_dictionary());
395 
396       if (result == ValidationResult::kFoundCorrect) {
397         return handle(object, isolate);
398       } else if (result == ValidationResult::kFoundIncorrect) {
399         return MaybeHandle<JSObject>();
400       }
401 
402       // In case of kNotFound, continue walking up the chain.
403       prototype = object.map().prototype();
404     }
405 
406     return MaybeHandle<JSObject>();
407   }
408 
Hash() const409   size_t Hash() const override {
410     ObjectRef::Hash h;
411     return base::hash_combine(h(receiver_map_), h(property_name_), h(constant_),
412                               static_cast<int>(kind_));
413   }
414 
Equals(const CompilationDependency * that) const415   bool Equals(const CompilationDependency* that) const override {
416     const ConstantInDictionaryPrototypeChainDependency* const zat =
417         that->AsConstantInDictionaryPrototypeChain();
418     return receiver_map_.equals(zat->receiver_map_) &&
419            property_name_.equals(zat->property_name_) &&
420            constant_.equals(zat->constant_) && kind_ == zat->kind_;
421   }
422 
423   const MapRef receiver_map_;
424   const NameRef property_name_;
425   const ObjectRef constant_;
426   const PropertyKind kind_;
427 };
428 
429 class OwnConstantDataPropertyDependency final : public CompilationDependency {
430  public:
OwnConstantDataPropertyDependency(JSHeapBroker * broker,const JSObjectRef & holder,const MapRef & map,Representation representation,FieldIndex index,const ObjectRef & value)431   OwnConstantDataPropertyDependency(JSHeapBroker* broker,
432                                     const JSObjectRef& holder,
433                                     const MapRef& map,
434                                     Representation representation,
435                                     FieldIndex index, const ObjectRef& value)
436       : CompilationDependency(kOwnConstantDataProperty),
437         broker_(broker),
438         holder_(holder),
439         map_(map),
440         representation_(representation),
441         index_(index),
442         value_(value) {}
443 
IsValid() const444   bool IsValid() const override {
445     if (holder_.object()->map() != *map_.object()) {
446       TRACE_BROKER_MISSING(broker_,
447                            "Map change detected in " << holder_.object());
448       return false;
449     }
450     DisallowGarbageCollection no_heap_allocation;
451     Object current_value = holder_.object()->RawFastPropertyAt(index_);
452     Object used_value = *value_.object();
453     if (representation_.IsDouble()) {
454       // Compare doubles by bit pattern.
455       if (!current_value.IsHeapNumber() || !used_value.IsHeapNumber() ||
456           HeapNumber::cast(current_value).value_as_bits(kRelaxedLoad) !=
457               HeapNumber::cast(used_value).value_as_bits(kRelaxedLoad)) {
458         TRACE_BROKER_MISSING(broker_,
459                              "Constant Double property value changed in "
460                                  << holder_.object() << " at FieldIndex "
461                                  << index_.property_index());
462         return false;
463       }
464     } else if (current_value != used_value) {
465       TRACE_BROKER_MISSING(broker_, "Constant property value changed in "
466                                         << holder_.object() << " at FieldIndex "
467                                         << index_.property_index());
468       return false;
469     }
470     return true;
471   }
472 
Install(PendingDependencies * deps) const473   void Install(PendingDependencies* deps) const override {}
474 
475  private:
Hash() const476   size_t Hash() const override {
477     ObjectRef::Hash h;
478     return base::hash_combine(h(holder_), h(map_), representation_.kind(),
479                               index_.bit_field(), h(value_));
480   }
481 
Equals(const CompilationDependency * that) const482   bool Equals(const CompilationDependency* that) const override {
483     const OwnConstantDataPropertyDependency* const zat =
484         that->AsOwnConstantDataProperty();
485     return holder_.equals(zat->holder_) && map_.equals(zat->map_) &&
486            representation_.Equals(zat->representation_) &&
487            index_ == zat->index_ && value_.equals(zat->value_);
488   }
489 
490   JSHeapBroker* const broker_;
491   JSObjectRef const holder_;
492   MapRef const map_;
493   Representation const representation_;
494   FieldIndex const index_;
495   ObjectRef const value_;
496 };
497 
498 class OwnConstantDictionaryPropertyDependency final
499     : public CompilationDependency {
500  public:
OwnConstantDictionaryPropertyDependency(JSHeapBroker * broker,const JSObjectRef & holder,InternalIndex index,const ObjectRef & value)501   OwnConstantDictionaryPropertyDependency(JSHeapBroker* broker,
502                                           const JSObjectRef& holder,
503                                           InternalIndex index,
504                                           const ObjectRef& value)
505       : CompilationDependency(kOwnConstantDictionaryProperty),
506         broker_(broker),
507         holder_(holder),
508         map_(holder.map()),
509         index_(index),
510         value_(value) {
511     // We depend on map() being cached.
512     STATIC_ASSERT(ref_traits<JSObject>::ref_serialization_kind !=
513                   RefSerializationKind::kNeverSerialized);
514   }
515 
IsValid() const516   bool IsValid() const override {
517     if (holder_.object()->map() != *map_.object()) {
518       TRACE_BROKER_MISSING(broker_,
519                            "Map change detected in " << holder_.object());
520       return false;
521     }
522 
523     base::Optional<Object> maybe_value = JSObject::DictionaryPropertyAt(
524         holder_.object(), index_, broker_->isolate()->heap());
525 
526     if (!maybe_value) {
527       TRACE_BROKER_MISSING(
528           broker_, holder_.object()
529                        << "has a value that might not safe to read at index "
530                        << index_.as_int());
531       return false;
532     }
533 
534     if (*maybe_value != *value_.object()) {
535       TRACE_BROKER_MISSING(broker_, "Constant property value changed in "
536                                         << holder_.object()
537                                         << " at InternalIndex "
538                                         << index_.as_int());
539       return false;
540     }
541     return true;
542   }
543 
Install(PendingDependencies * deps) const544   void Install(PendingDependencies* deps) const override {}
545 
546  private:
Hash() const547   size_t Hash() const override {
548     ObjectRef::Hash h;
549     return base::hash_combine(h(holder_), h(map_), index_.raw_value(),
550                               h(value_));
551   }
552 
Equals(const CompilationDependency * that) const553   bool Equals(const CompilationDependency* that) const override {
554     const OwnConstantDictionaryPropertyDependency* const zat =
555         that->AsOwnConstantDictionaryProperty();
556     return holder_.equals(zat->holder_) && map_.equals(zat->map_) &&
557            index_ == zat->index_ && value_.equals(zat->value_);
558   }
559 
560   JSHeapBroker* const broker_;
561   JSObjectRef const holder_;
562   MapRef const map_;
563   InternalIndex const index_;
564   ObjectRef const value_;
565 };
566 
567 class ConsistentJSFunctionViewDependency final : public CompilationDependency {
568  public:
ConsistentJSFunctionViewDependency(const JSFunctionRef & function)569   explicit ConsistentJSFunctionViewDependency(const JSFunctionRef& function)
570       : CompilationDependency(kConsistentJSFunctionView), function_(function) {}
571 
IsValid() const572   bool IsValid() const override {
573     return function_.IsConsistentWithHeapState();
574   }
575 
Install(PendingDependencies * deps) const576   void Install(PendingDependencies* deps) const override {}
577 
578  private:
Hash() const579   size_t Hash() const override {
580     ObjectRef::Hash h;
581     return base::hash_combine(h(function_));
582   }
583 
Equals(const CompilationDependency * that) const584   bool Equals(const CompilationDependency* that) const override {
585     const ConsistentJSFunctionViewDependency* const zat =
586         that->AsConsistentJSFunctionView();
587     return function_.equals(zat->function_);
588   }
589 
590   const JSFunctionRef function_;
591 };
592 
593 class TransitionDependency final : public CompilationDependency {
594  public:
TransitionDependency(const MapRef & map)595   explicit TransitionDependency(const MapRef& map)
596       : CompilationDependency(kTransition), map_(map) {
597     DCHECK(map_.CanBeDeprecated());
598   }
599 
IsValid() const600   bool IsValid() const override { return !map_.object()->is_deprecated(); }
601 
Install(PendingDependencies * deps) const602   void Install(PendingDependencies* deps) const override {
603     SLOW_DCHECK(IsValid());
604     deps->Register(map_.object(), DependentCode::kTransitionGroup);
605   }
606 
607  private:
Hash() const608   size_t Hash() const override {
609     ObjectRef::Hash h;
610     return base::hash_combine(h(map_));
611   }
612 
Equals(const CompilationDependency * that) const613   bool Equals(const CompilationDependency* that) const override {
614     const TransitionDependency* const zat = that->AsTransition();
615     return map_.equals(zat->map_);
616   }
617 
618   const MapRef map_;
619 };
620 
621 class PretenureModeDependency final : public CompilationDependency {
622  public:
PretenureModeDependency(const AllocationSiteRef & site,AllocationType allocation)623   PretenureModeDependency(const AllocationSiteRef& site,
624                           AllocationType allocation)
625       : CompilationDependency(kPretenureMode),
626         site_(site),
627         allocation_(allocation) {}
628 
IsValid() const629   bool IsValid() const override {
630     return allocation_ == site_.object()->GetAllocationType();
631   }
Install(PendingDependencies * deps) const632   void Install(PendingDependencies* deps) const override {
633     SLOW_DCHECK(IsValid());
634     deps->Register(site_.object(),
635                    DependentCode::kAllocationSiteTenuringChangedGroup);
636   }
637 
638  private:
Hash() const639   size_t Hash() const override {
640     ObjectRef::Hash h;
641     return base::hash_combine(h(site_), allocation_);
642   }
643 
Equals(const CompilationDependency * that) const644   bool Equals(const CompilationDependency* that) const override {
645     const PretenureModeDependency* const zat = that->AsPretenureMode();
646     return site_.equals(zat->site_) && allocation_ == zat->allocation_;
647   }
648 
649   const AllocationSiteRef site_;
650   const AllocationType allocation_;
651 };
652 
653 class FieldRepresentationDependency final : public CompilationDependency {
654  public:
FieldRepresentationDependency(const MapRef & map,InternalIndex descriptor,Representation representation)655   FieldRepresentationDependency(const MapRef& map, InternalIndex descriptor,
656                                 Representation representation)
657       : CompilationDependency(kFieldRepresentation),
658         map_(map),
659         descriptor_(descriptor),
660         representation_(representation) {}
661 
IsValid() const662   bool IsValid() const override {
663     DisallowGarbageCollection no_heap_allocation;
664     if (map_.object()->is_deprecated()) return false;
665     return representation_.Equals(map_.object()
666                                       ->instance_descriptors(map_.isolate())
667                                       .GetDetails(descriptor_)
668                                       .representation());
669   }
670 
Install(PendingDependencies * deps) const671   void Install(PendingDependencies* deps) const override {
672     SLOW_DCHECK(IsValid());
673     Isolate* isolate = map_.isolate();
674     Handle<Map> owner(map_.object()->FindFieldOwner(isolate, descriptor_),
675                       isolate);
676     CHECK(!owner->is_deprecated());
677     CHECK(representation_.Equals(owner->instance_descriptors(isolate)
678                                      .GetDetails(descriptor_)
679                                      .representation()));
680     deps->Register(owner, DependentCode::kFieldRepresentationGroup);
681   }
682 
DependsOn(const Handle<Map> & receiver_map) const683   bool DependsOn(const Handle<Map>& receiver_map) const {
684     return map_.object().equals(receiver_map);
685   }
686 
687  private:
Hash() const688   size_t Hash() const override {
689     ObjectRef::Hash h;
690     return base::hash_combine(h(map_), descriptor_.as_int(),
691                               representation_.kind());
692   }
693 
Equals(const CompilationDependency * that) const694   bool Equals(const CompilationDependency* that) const override {
695     const FieldRepresentationDependency* const zat =
696         that->AsFieldRepresentation();
697     return map_.equals(zat->map_) && descriptor_ == zat->descriptor_ &&
698            representation_.Equals(zat->representation_);
699   }
700 
701   const MapRef map_;
702   const InternalIndex descriptor_;
703   const Representation representation_;
704 };
705 
706 class FieldTypeDependency final : public CompilationDependency {
707  public:
FieldTypeDependency(const MapRef & map,InternalIndex descriptor,const ObjectRef & type)708   FieldTypeDependency(const MapRef& map, InternalIndex descriptor,
709                       const ObjectRef& type)
710       : CompilationDependency(kFieldType),
711         map_(map),
712         descriptor_(descriptor),
713         type_(type) {}
714 
IsValid() const715   bool IsValid() const override {
716     DisallowGarbageCollection no_heap_allocation;
717     if (map_.object()->is_deprecated()) return false;
718     return *type_.object() == map_.object()
719                                   ->instance_descriptors(map_.isolate())
720                                   .GetFieldType(descriptor_);
721   }
722 
Install(PendingDependencies * deps) const723   void Install(PendingDependencies* deps) const override {
724     SLOW_DCHECK(IsValid());
725     Isolate* isolate = map_.isolate();
726     Handle<Map> owner(map_.object()->FindFieldOwner(isolate, descriptor_),
727                       isolate);
728     CHECK(!owner->is_deprecated());
729     CHECK_EQ(*type_.object(),
730              owner->instance_descriptors(isolate).GetFieldType(descriptor_));
731     deps->Register(owner, DependentCode::kFieldTypeGroup);
732   }
733 
734  private:
Hash() const735   size_t Hash() const override {
736     ObjectRef::Hash h;
737     return base::hash_combine(h(map_), descriptor_.as_int(), h(type_));
738   }
739 
Equals(const CompilationDependency * that) const740   bool Equals(const CompilationDependency* that) const override {
741     const FieldTypeDependency* const zat = that->AsFieldType();
742     return map_.equals(zat->map_) && descriptor_ == zat->descriptor_ &&
743            type_.equals(zat->type_);
744   }
745 
746   const MapRef map_;
747   const InternalIndex descriptor_;
748   const ObjectRef type_;
749 };
750 
751 class FieldConstnessDependency final : public CompilationDependency {
752  public:
FieldConstnessDependency(const MapRef & map,InternalIndex descriptor)753   FieldConstnessDependency(const MapRef& map, InternalIndex descriptor)
754       : CompilationDependency(kFieldConstness),
755         map_(map),
756         descriptor_(descriptor) {}
757 
IsValid() const758   bool IsValid() const override {
759     DisallowGarbageCollection no_heap_allocation;
760     if (map_.object()->is_deprecated()) return false;
761     return PropertyConstness::kConst ==
762            map_.object()
763                ->instance_descriptors(map_.isolate())
764                .GetDetails(descriptor_)
765                .constness();
766   }
767 
Install(PendingDependencies * deps) const768   void Install(PendingDependencies* deps) const override {
769     SLOW_DCHECK(IsValid());
770     Isolate* isolate = map_.isolate();
771     Handle<Map> owner(map_.object()->FindFieldOwner(isolate, descriptor_),
772                       isolate);
773     CHECK(!owner->is_deprecated());
774     CHECK_EQ(PropertyConstness::kConst, owner->instance_descriptors(isolate)
775                                             .GetDetails(descriptor_)
776                                             .constness());
777     deps->Register(owner, DependentCode::kFieldConstGroup);
778   }
779 
780  private:
Hash() const781   size_t Hash() const override {
782     ObjectRef::Hash h;
783     return base::hash_combine(h(map_), descriptor_.as_int());
784   }
785 
Equals(const CompilationDependency * that) const786   bool Equals(const CompilationDependency* that) const override {
787     const FieldConstnessDependency* const zat = that->AsFieldConstness();
788     return map_.equals(zat->map_) && descriptor_ == zat->descriptor_;
789   }
790 
791   const MapRef map_;
792   const InternalIndex descriptor_;
793 };
794 
795 class GlobalPropertyDependency final : public CompilationDependency {
796  public:
GlobalPropertyDependency(const PropertyCellRef & cell,PropertyCellType type,bool read_only)797   GlobalPropertyDependency(const PropertyCellRef& cell, PropertyCellType type,
798                            bool read_only)
799       : CompilationDependency(kGlobalProperty),
800         cell_(cell),
801         type_(type),
802         read_only_(read_only) {
803     DCHECK_EQ(type_, cell_.property_details().cell_type());
804     DCHECK_EQ(read_only_, cell_.property_details().IsReadOnly());
805   }
806 
IsValid() const807   bool IsValid() const override {
808     Handle<PropertyCell> cell = cell_.object();
809     // The dependency is never valid if the cell is 'invalidated'. This is
810     // marked by setting the value to the hole.
811     if (cell->value() == *(cell_.isolate()->factory()->the_hole_value())) {
812       return false;
813     }
814     return type_ == cell->property_details().cell_type() &&
815            read_only_ == cell->property_details().IsReadOnly();
816   }
Install(PendingDependencies * deps) const817   void Install(PendingDependencies* deps) const override {
818     SLOW_DCHECK(IsValid());
819     deps->Register(cell_.object(), DependentCode::kPropertyCellChangedGroup);
820   }
821 
822  private:
Hash() const823   size_t Hash() const override {
824     ObjectRef::Hash h;
825     return base::hash_combine(h(cell_), static_cast<int>(type_), read_only_);
826   }
827 
Equals(const CompilationDependency * that) const828   bool Equals(const CompilationDependency* that) const override {
829     const GlobalPropertyDependency* const zat = that->AsGlobalProperty();
830     return cell_.equals(zat->cell_) && type_ == zat->type_ &&
831            read_only_ == zat->read_only_;
832   }
833 
834   const PropertyCellRef cell_;
835   const PropertyCellType type_;
836   const bool read_only_;
837 };
838 
839 class ProtectorDependency final : public CompilationDependency {
840  public:
ProtectorDependency(const PropertyCellRef & cell)841   explicit ProtectorDependency(const PropertyCellRef& cell)
842       : CompilationDependency(kProtector), cell_(cell) {}
843 
IsValid() const844   bool IsValid() const override {
845     Handle<PropertyCell> cell = cell_.object();
846     return cell->value() == Smi::FromInt(Protectors::kProtectorValid);
847   }
Install(PendingDependencies * deps) const848   void Install(PendingDependencies* deps) const override {
849     SLOW_DCHECK(IsValid());
850     deps->Register(cell_.object(), DependentCode::kPropertyCellChangedGroup);
851   }
852 
853  private:
Hash() const854   size_t Hash() const override {
855     ObjectRef::Hash h;
856     return base::hash_combine(h(cell_));
857   }
858 
Equals(const CompilationDependency * that) const859   bool Equals(const CompilationDependency* that) const override {
860     const ProtectorDependency* const zat = that->AsProtector();
861     return cell_.equals(zat->cell_);
862   }
863 
864   const PropertyCellRef cell_;
865 };
866 
867 // Check that an object slot will not change during compilation.
868 class ObjectSlotValueDependency final : public CompilationDependency {
869  public:
ObjectSlotValueDependency(const HeapObjectRef & object,int offset,const ObjectRef & value)870   explicit ObjectSlotValueDependency(const HeapObjectRef& object, int offset,
871                                      const ObjectRef& value)
872       : CompilationDependency(kObjectSlotValue),
873         object_(object.object()),
874         offset_(offset),
875         value_(value.object()) {}
876 
IsValid() const877   bool IsValid() const override {
878     PtrComprCageBase cage_base = GetPtrComprCageBase(*object_);
879     Object current_value =
880         offset_ == HeapObject::kMapOffset
881             ? object_->map()
882             : TaggedField<Object>::Relaxed_Load(cage_base, *object_, offset_);
883     return *value_ == current_value;
884   }
Install(PendingDependencies * deps) const885   void Install(PendingDependencies* deps) const override {}
886 
887  private:
Hash() const888   size_t Hash() const override {
889     return base::hash_combine(object_.address(), offset_, value_.address());
890   }
891 
Equals(const CompilationDependency * that) const892   bool Equals(const CompilationDependency* that) const override {
893     const ObjectSlotValueDependency* const zat = that->AsObjectSlotValue();
894     return object_->address() == zat->object_->address() &&
895            offset_ == zat->offset_ && value_.address() == zat->value_.address();
896   }
897 
898   Handle<HeapObject> object_;
899   int offset_;
900   Handle<Object> value_;
901 };
902 
903 class ElementsKindDependency final : public CompilationDependency {
904  public:
ElementsKindDependency(const AllocationSiteRef & site,ElementsKind kind)905   ElementsKindDependency(const AllocationSiteRef& site, ElementsKind kind)
906       : CompilationDependency(kElementsKind), site_(site), kind_(kind) {
907     DCHECK(AllocationSite::ShouldTrack(kind_));
908   }
909 
IsValid() const910   bool IsValid() const override {
911     Handle<AllocationSite> site = site_.object();
912     ElementsKind kind =
913         site->PointsToLiteral()
914             ? site->boilerplate(kAcquireLoad).map().elements_kind()
915             : site->GetElementsKind();
916     return kind_ == kind;
917   }
Install(PendingDependencies * deps) const918   void Install(PendingDependencies* deps) const override {
919     SLOW_DCHECK(IsValid());
920     deps->Register(site_.object(),
921                    DependentCode::kAllocationSiteTransitionChangedGroup);
922   }
923 
924  private:
Hash() const925   size_t Hash() const override {
926     ObjectRef::Hash h;
927     return base::hash_combine(h(site_), static_cast<int>(kind_));
928   }
929 
Equals(const CompilationDependency * that) const930   bool Equals(const CompilationDependency* that) const override {
931     const ElementsKindDependency* const zat = that->AsElementsKind();
932     return site_.equals(zat->site_) && kind_ == zat->kind_;
933   }
934 
935   const AllocationSiteRef site_;
936   const ElementsKind kind_;
937 };
938 
939 // Only valid if the holder can use direct reads, since validation uses
940 // GetOwnConstantElementFromHeap.
941 class OwnConstantElementDependency final : public CompilationDependency {
942  public:
OwnConstantElementDependency(const JSObjectRef & holder,uint32_t index,const ObjectRef & element)943   OwnConstantElementDependency(const JSObjectRef& holder, uint32_t index,
944                                const ObjectRef& element)
945       : CompilationDependency(kOwnConstantElement),
946         holder_(holder),
947         index_(index),
948         element_(element) {}
949 
IsValid() const950   bool IsValid() const override {
951     DisallowGarbageCollection no_gc;
952     JSObject holder = *holder_.object();
953     base::Optional<Object> maybe_element =
954         holder_.GetOwnConstantElementFromHeap(holder.elements(),
955                                               holder.GetElementsKind(), index_);
956     if (!maybe_element.has_value()) return false;
957 
958     return maybe_element.value() == *element_.object();
959   }
Install(PendingDependencies * deps) const960   void Install(PendingDependencies* deps) const override {}
961 
962  private:
Hash() const963   size_t Hash() const override {
964     ObjectRef::Hash h;
965     return base::hash_combine(h(holder_), index_, h(element_));
966   }
967 
Equals(const CompilationDependency * that) const968   bool Equals(const CompilationDependency* that) const override {
969     const OwnConstantElementDependency* const zat =
970         that->AsOwnConstantElement();
971     return holder_.equals(zat->holder_) && index_ == zat->index_ &&
972            element_.equals(zat->element_);
973   }
974 
975   const JSObjectRef holder_;
976   const uint32_t index_;
977   const ObjectRef element_;
978 };
979 
980 class InitialMapInstanceSizePredictionDependency final
981     : public CompilationDependency {
982  public:
InitialMapInstanceSizePredictionDependency(const JSFunctionRef & function,int instance_size)983   InitialMapInstanceSizePredictionDependency(const JSFunctionRef& function,
984                                              int instance_size)
985       : CompilationDependency(kInitialMapInstanceSizePrediction),
986         function_(function),
987         instance_size_(instance_size) {}
988 
IsValid() const989   bool IsValid() const override {
990     // The dependency is valid if the prediction is the same as the current
991     // slack tracking result.
992     if (!function_.object()->has_initial_map()) return false;
993     int instance_size = function_.object()->ComputeInstanceSizeWithMinSlack(
994         function_.isolate());
995     return instance_size == instance_size_;
996   }
997 
PrepareInstall() const998   void PrepareInstall() const override {
999     SLOW_DCHECK(IsValid());
1000     function_.object()->CompleteInobjectSlackTrackingIfActive();
1001   }
1002 
Install(PendingDependencies * deps) const1003   void Install(PendingDependencies* deps) const override {
1004     SLOW_DCHECK(IsValid());
1005     DCHECK(
1006         !function_.object()->initial_map().IsInobjectSlackTrackingInProgress());
1007   }
1008 
1009  private:
Hash() const1010   size_t Hash() const override {
1011     ObjectRef::Hash h;
1012     return base::hash_combine(h(function_), instance_size_);
1013   }
1014 
Equals(const CompilationDependency * that) const1015   bool Equals(const CompilationDependency* that) const override {
1016     const InitialMapInstanceSizePredictionDependency* const zat =
1017         that->AsInitialMapInstanceSizePrediction();
1018     return function_.equals(zat->function_) &&
1019            instance_size_ == zat->instance_size_;
1020   }
1021 
1022   const JSFunctionRef function_;
1023   const int instance_size_;
1024 };
1025 
1026 }  // namespace
1027 
RecordDependency(CompilationDependency const * dependency)1028 void CompilationDependencies::RecordDependency(
1029     CompilationDependency const* dependency) {
1030   if (dependency != nullptr) dependencies_.insert(dependency);
1031 }
1032 
DependOnInitialMap(const JSFunctionRef & function)1033 MapRef CompilationDependencies::DependOnInitialMap(
1034     const JSFunctionRef& function) {
1035   MapRef map = function.initial_map(this);
1036   RecordDependency(zone_->New<InitialMapDependency>(broker_, function, map));
1037   return map;
1038 }
1039 
DependOnPrototypeProperty(const JSFunctionRef & function)1040 ObjectRef CompilationDependencies::DependOnPrototypeProperty(
1041     const JSFunctionRef& function) {
1042   ObjectRef prototype = function.instance_prototype(this);
1043   RecordDependency(
1044       zone_->New<PrototypePropertyDependency>(broker_, function, prototype));
1045   return prototype;
1046 }
1047 
DependOnStableMap(const MapRef & map)1048 void CompilationDependencies::DependOnStableMap(const MapRef& map) {
1049   if (map.CanTransition()) {
1050     RecordDependency(zone_->New<StableMapDependency>(map));
1051   }
1052 }
1053 
DependOnConstantInDictionaryPrototypeChain(const MapRef & receiver_map,const NameRef & property_name,const ObjectRef & constant,PropertyKind kind)1054 void CompilationDependencies::DependOnConstantInDictionaryPrototypeChain(
1055     const MapRef& receiver_map, const NameRef& property_name,
1056     const ObjectRef& constant, PropertyKind kind) {
1057   RecordDependency(zone_->New<ConstantInDictionaryPrototypeChainDependency>(
1058       receiver_map, property_name, constant, kind));
1059 }
1060 
DependOnPretenureMode(const AllocationSiteRef & site)1061 AllocationType CompilationDependencies::DependOnPretenureMode(
1062     const AllocationSiteRef& site) {
1063   if (!FLAG_allocation_site_pretenuring) return AllocationType::kYoung;
1064   AllocationType allocation = site.GetAllocationType();
1065   RecordDependency(zone_->New<PretenureModeDependency>(site, allocation));
1066   return allocation;
1067 }
1068 
DependOnFieldConstness(const MapRef & map,InternalIndex descriptor)1069 PropertyConstness CompilationDependencies::DependOnFieldConstness(
1070     const MapRef& map, InternalIndex descriptor) {
1071   PropertyConstness constness = map.GetPropertyDetails(descriptor).constness();
1072   if (constness == PropertyConstness::kMutable) return constness;
1073 
1074   // If the map can have fast elements transitions, then the field can be only
1075   // considered constant if the map does not transition.
1076   if (Map::CanHaveFastTransitionableElementsKind(map.instance_type())) {
1077     // If the map can already transition away, let us report the field as
1078     // mutable.
1079     if (!map.is_stable()) {
1080       return PropertyConstness::kMutable;
1081     }
1082     DependOnStableMap(map);
1083   }
1084 
1085   DCHECK_EQ(constness, PropertyConstness::kConst);
1086   RecordDependency(zone_->New<FieldConstnessDependency>(map, descriptor));
1087   return PropertyConstness::kConst;
1088 }
1089 
DependOnGlobalProperty(const PropertyCellRef & cell)1090 void CompilationDependencies::DependOnGlobalProperty(
1091     const PropertyCellRef& cell) {
1092   PropertyCellType type = cell.property_details().cell_type();
1093   bool read_only = cell.property_details().IsReadOnly();
1094   RecordDependency(zone_->New<GlobalPropertyDependency>(cell, type, read_only));
1095 }
1096 
DependOnProtector(const PropertyCellRef & cell)1097 bool CompilationDependencies::DependOnProtector(const PropertyCellRef& cell) {
1098   cell.CacheAsProtector();
1099   if (cell.value().AsSmi() != Protectors::kProtectorValid) return false;
1100   RecordDependency(zone_->New<ProtectorDependency>(cell));
1101   return true;
1102 }
1103 
DependOnArrayBufferDetachingProtector()1104 bool CompilationDependencies::DependOnArrayBufferDetachingProtector() {
1105   return DependOnProtector(MakeRef(
1106       broker_,
1107       broker_->isolate()->factory()->array_buffer_detaching_protector()));
1108 }
1109 
DependOnArrayIteratorProtector()1110 bool CompilationDependencies::DependOnArrayIteratorProtector() {
1111   return DependOnProtector(MakeRef(
1112       broker_, broker_->isolate()->factory()->array_iterator_protector()));
1113 }
1114 
DependOnArraySpeciesProtector()1115 bool CompilationDependencies::DependOnArraySpeciesProtector() {
1116   return DependOnProtector(MakeRef(
1117       broker_, broker_->isolate()->factory()->array_species_protector()));
1118 }
1119 
DependOnNoElementsProtector()1120 bool CompilationDependencies::DependOnNoElementsProtector() {
1121   return DependOnProtector(
1122       MakeRef(broker_, broker_->isolate()->factory()->no_elements_protector()));
1123 }
1124 
DependOnPromiseHookProtector()1125 bool CompilationDependencies::DependOnPromiseHookProtector() {
1126   return DependOnProtector(MakeRef(
1127       broker_, broker_->isolate()->factory()->promise_hook_protector()));
1128 }
1129 
DependOnPromiseSpeciesProtector()1130 bool CompilationDependencies::DependOnPromiseSpeciesProtector() {
1131   return DependOnProtector(MakeRef(
1132       broker_, broker_->isolate()->factory()->promise_species_protector()));
1133 }
1134 
DependOnPromiseThenProtector()1135 bool CompilationDependencies::DependOnPromiseThenProtector() {
1136   return DependOnProtector(MakeRef(
1137       broker_, broker_->isolate()->factory()->promise_then_protector()));
1138 }
1139 
DependOnElementsKind(const AllocationSiteRef & site)1140 void CompilationDependencies::DependOnElementsKind(
1141     const AllocationSiteRef& site) {
1142   ElementsKind kind = site.PointsToLiteral()
1143                           ? site.boilerplate().value().map().elements_kind()
1144                           : site.GetElementsKind();
1145   if (AllocationSite::ShouldTrack(kind)) {
1146     RecordDependency(zone_->New<ElementsKindDependency>(site, kind));
1147   }
1148 }
1149 
DependOnObjectSlotValue(const HeapObjectRef & object,int offset,const ObjectRef & value)1150 void CompilationDependencies::DependOnObjectSlotValue(
1151     const HeapObjectRef& object, int offset, const ObjectRef& value) {
1152   RecordDependency(
1153       zone_->New<ObjectSlotValueDependency>(object, offset, value));
1154 }
1155 
DependOnOwnConstantElement(const JSObjectRef & holder,uint32_t index,const ObjectRef & element)1156 void CompilationDependencies::DependOnOwnConstantElement(
1157     const JSObjectRef& holder, uint32_t index, const ObjectRef& element) {
1158   RecordDependency(
1159       zone_->New<OwnConstantElementDependency>(holder, index, element));
1160 }
1161 
DependOnOwnConstantDataProperty(const JSObjectRef & holder,const MapRef & map,Representation representation,FieldIndex index,const ObjectRef & value)1162 void CompilationDependencies::DependOnOwnConstantDataProperty(
1163     const JSObjectRef& holder, const MapRef& map, Representation representation,
1164     FieldIndex index, const ObjectRef& value) {
1165   RecordDependency(zone_->New<OwnConstantDataPropertyDependency>(
1166       broker_, holder, map, representation, index, value));
1167 }
1168 
DependOnOwnConstantDictionaryProperty(const JSObjectRef & holder,InternalIndex index,const ObjectRef & value)1169 void CompilationDependencies::DependOnOwnConstantDictionaryProperty(
1170     const JSObjectRef& holder, InternalIndex index, const ObjectRef& value) {
1171   RecordDependency(zone_->New<OwnConstantDictionaryPropertyDependency>(
1172       broker_, holder, index, value));
1173 }
1174 
TraceInvalidCompilationDependency(const CompilationDependency * d)1175 V8_INLINE void TraceInvalidCompilationDependency(
1176     const CompilationDependency* d) {
1177   DCHECK(FLAG_trace_compilation_dependencies);
1178   DCHECK(!d->IsValid());
1179   PrintF("Compilation aborted due to invalid dependency: %s\n", d->ToString());
1180 }
1181 
Commit(Handle<Code> code)1182 bool CompilationDependencies::Commit(Handle<Code> code) {
1183   if (!PrepareInstall()) return false;
1184 
1185   {
1186     PendingDependencies pending_deps(zone_);
1187     DisallowCodeDependencyChange no_dependency_change;
1188     for (const CompilationDependency* dep : dependencies_) {
1189       // Check each dependency's validity again right before installing it,
1190       // because the first iteration above might have invalidated some
1191       // dependencies. For example, PrototypePropertyDependency::PrepareInstall
1192       // can call EnsureHasInitialMap, which can invalidate a
1193       // StableMapDependency on the prototype object's map.
1194       if (!dep->IsValid()) {
1195         if (FLAG_trace_compilation_dependencies) {
1196           TraceInvalidCompilationDependency(dep);
1197         }
1198         dependencies_.clear();
1199         return false;
1200       }
1201       dep->Install(&pending_deps);
1202     }
1203     pending_deps.InstallAll(broker_->isolate(), code);
1204   }
1205 
1206   // It is even possible that a GC during the above installations invalidated
1207   // one of the dependencies. However, this should only affect
1208   //
1209   // 1. pretenure mode dependencies, or
1210   // 2. function consistency dependencies,
1211   //
1212   // which we assert below. It is safe to return successfully in these cases,
1213   // because
1214   //
1215   // 1. once the code gets executed it will do a stack check that triggers its
1216   //    deoptimization.
1217   // 2. since the function state was deemed consistent above, that means the
1218   //    compilation saw a self-consistent state of the jsfunction.
1219   if (FLAG_stress_gc_during_compilation) {
1220     broker_->isolate()->heap()->PreciseCollectAllGarbage(
1221         Heap::kForcedGC, GarbageCollectionReason::kTesting, kNoGCCallbackFlags);
1222   }
1223 #ifdef DEBUG
1224   for (auto dep : dependencies_) {
1225     CHECK_IMPLIES(!dep->IsValid(),
1226                   dep->IsPretenureMode() || dep->IsConsistentJSFunctionView());
1227   }
1228 #endif
1229 
1230   dependencies_.clear();
1231   return true;
1232 }
1233 
PrepareInstall()1234 bool CompilationDependencies::PrepareInstall() {
1235   if (V8_UNLIKELY(FLAG_predictable)) {
1236     return PrepareInstallPredictable();
1237   }
1238 
1239   for (auto dep : dependencies_) {
1240     if (!dep->IsValid()) {
1241       if (FLAG_trace_compilation_dependencies) {
1242         TraceInvalidCompilationDependency(dep);
1243       }
1244       dependencies_.clear();
1245       return false;
1246     }
1247     dep->PrepareInstall();
1248   }
1249   return true;
1250 }
1251 
PrepareInstallPredictable()1252 bool CompilationDependencies::PrepareInstallPredictable() {
1253   CHECK(FLAG_predictable);
1254 
1255   std::vector<const CompilationDependency*> deps(dependencies_.begin(),
1256                                                  dependencies_.end());
1257   std::sort(deps.begin(), deps.end());
1258 
1259   for (auto dep : deps) {
1260     if (!dep->IsValid()) {
1261       if (FLAG_trace_compilation_dependencies) {
1262         TraceInvalidCompilationDependency(dep);
1263       }
1264       dependencies_.clear();
1265       return false;
1266     }
1267     dep->PrepareInstall();
1268   }
1269   return true;
1270 }
1271 
1272 namespace {
1273 
1274 // This function expects to never see a JSProxy.
DependOnStablePrototypeChain(CompilationDependencies * deps,MapRef map,base::Optional<JSObjectRef> last_prototype)1275 void DependOnStablePrototypeChain(CompilationDependencies* deps, MapRef map,
1276                                   base::Optional<JSObjectRef> last_prototype) {
1277   while (true) {
1278     HeapObjectRef proto = map.prototype();
1279     if (!proto.IsJSObject()) {
1280       CHECK_EQ(proto.map().oddball_type(), OddballType::kNull);
1281       break;
1282     }
1283     map = proto.map();
1284     deps->DependOnStableMap(map);
1285     if (last_prototype.has_value() && proto.equals(*last_prototype)) break;
1286   }
1287 }
1288 
1289 }  // namespace
1290 
1291 #define V(Name)                                                     \
1292   const Name##Dependency* CompilationDependency::As##Name() const { \
1293     DCHECK(Is##Name());                                             \
1294     return static_cast<const Name##Dependency*>(this);              \
1295   }
DEPENDENCY_LIST(V)1296 DEPENDENCY_LIST(V)
1297 #undef V
1298 
1299 void CompilationDependencies::DependOnStablePrototypeChains(
1300     ZoneVector<MapRef> const& receiver_maps, WhereToStart start,
1301     base::Optional<JSObjectRef> last_prototype) {
1302   for (MapRef receiver_map : receiver_maps) {
1303     if (receiver_map.IsPrimitiveMap()) {
1304       // Perform the implicit ToObject for primitives here.
1305       // Implemented according to ES6 section 7.3.2 GetV (V, P).
1306       // Note: Keep sync'd with AccessInfoFactory::ComputePropertyAccessInfo.
1307       base::Optional<JSFunctionRef> constructor =
1308           broker_->target_native_context().GetConstructorFunction(receiver_map);
1309       receiver_map = constructor.value().initial_map(this);
1310     }
1311     if (start == kStartAtReceiver) DependOnStableMap(receiver_map);
1312     DependOnStablePrototypeChain(this, receiver_map, last_prototype);
1313   }
1314 }
1315 
DependOnElementsKinds(const AllocationSiteRef & site)1316 void CompilationDependencies::DependOnElementsKinds(
1317     const AllocationSiteRef& site) {
1318   AllocationSiteRef current = site;
1319   while (true) {
1320     DependOnElementsKind(current);
1321     if (!current.nested_site().IsAllocationSite()) break;
1322     current = current.nested_site().AsAllocationSite();
1323   }
1324   CHECK_EQ(current.nested_site().AsSmi(), 0);
1325 }
1326 
DependOnConsistentJSFunctionView(const JSFunctionRef & function)1327 void CompilationDependencies::DependOnConsistentJSFunctionView(
1328     const JSFunctionRef& function) {
1329   RecordDependency(zone_->New<ConsistentJSFunctionViewDependency>(function));
1330 }
1331 
SlackTrackingPrediction(MapRef initial_map,int instance_size)1332 SlackTrackingPrediction::SlackTrackingPrediction(MapRef initial_map,
1333                                                  int instance_size)
1334     : instance_size_(instance_size),
1335       inobject_property_count_(
1336           (instance_size >> kTaggedSizeLog2) -
1337           initial_map.GetInObjectPropertiesStartInWords()) {}
1338 
1339 SlackTrackingPrediction
DependOnInitialMapInstanceSizePrediction(const JSFunctionRef & function)1340 CompilationDependencies::DependOnInitialMapInstanceSizePrediction(
1341     const JSFunctionRef& function) {
1342   MapRef initial_map = DependOnInitialMap(function);
1343   int instance_size = function.InitialMapInstanceSizeWithMinSlack(this);
1344   // Currently, we always install the prediction dependency. If this turns out
1345   // to be too expensive, we can only install the dependency if slack
1346   // tracking is active.
1347   RecordDependency(zone_->New<InitialMapInstanceSizePredictionDependency>(
1348       function, instance_size));
1349   CHECK_LE(instance_size, function.initial_map(this).instance_size());
1350   return SlackTrackingPrediction(initial_map, instance_size);
1351 }
1352 
1353 CompilationDependency const*
TransitionDependencyOffTheRecord(const MapRef & target_map) const1354 CompilationDependencies::TransitionDependencyOffTheRecord(
1355     const MapRef& target_map) const {
1356   if (target_map.CanBeDeprecated()) {
1357     return zone_->New<TransitionDependency>(target_map);
1358   } else {
1359     DCHECK(!target_map.is_deprecated());
1360     return nullptr;
1361   }
1362 }
1363 
1364 CompilationDependency const*
FieldRepresentationDependencyOffTheRecord(const MapRef & map,InternalIndex descriptor,Representation representation) const1365 CompilationDependencies::FieldRepresentationDependencyOffTheRecord(
1366     const MapRef& map, InternalIndex descriptor,
1367     Representation representation) const {
1368   return zone_->New<FieldRepresentationDependency>(map, descriptor,
1369                                                    representation);
1370 }
1371 
1372 CompilationDependency const*
FieldTypeDependencyOffTheRecord(const MapRef & map,InternalIndex descriptor,const ObjectRef & type) const1373 CompilationDependencies::FieldTypeDependencyOffTheRecord(
1374     const MapRef& map, InternalIndex descriptor, const ObjectRef& type) const {
1375   return zone_->New<FieldTypeDependency>(map, descriptor, type);
1376 }
1377 
1378 #ifdef DEBUG
1379 // static
IsFieldRepresentationDependencyOnMap(const CompilationDependency * dep,const Handle<Map> & receiver_map)1380 bool CompilationDependencies::IsFieldRepresentationDependencyOnMap(
1381     const CompilationDependency* dep, const Handle<Map>& receiver_map) {
1382   return dep->IsFieldRepresentation() &&
1383          dep->AsFieldRepresentation()->DependsOn(receiver_map);
1384 }
1385 #endif  // DEBUG
1386 
1387 #undef DEPENDENCY_LIST
1388 
1389 }  // namespace compiler
1390 }  // namespace internal
1391 }  // namespace v8
1392