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