v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
compilation-dependencies.cc
Go to the documentation of this file.
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
6
7#include <optional>
8
9#include "src/base/hashmap.h"
20
21namespace v8 {
22namespace internal {
23namespace compiler {
24
25#define DEPENDENCY_LIST(V) \
26 V(ConsistentJSFunctionView) \
27 V(ConstantInDictionaryPrototypeChain) \
28 V(ElementsKind) \
29 V(EmptyContextExtension) \
30 V(FieldConstness) \
31 V(FieldRepresentation) \
32 V(FieldType) \
33 V(GlobalProperty) \
34 V(InitialMap) \
35 V(InitialMapInstanceSizePrediction) \
36 V(NoSlackTrackingChange) \
37 V(OwnConstantDataProperty) \
38 V(OwnConstantDoubleProperty) \
39 V(OwnConstantDictionaryProperty) \
40 V(OwnConstantElement) \
41 V(PretenureMode) \
42 V(Protector) \
43 V(PrototypeProperty) \
44 V(ScriptContextSlotProperty) \
45 V(StableMap) \
46 V(Transition) \
47 V(ObjectSlotValue)
48
54
55namespace {
56
57enum CompilationDependencyKind {
58#define V(Name) k##Name,
60#undef V
61};
62
63#define V(Name) class Name##Dependency;
65#undef V
66
67const char* CompilationDependencyKindToString(CompilationDependencyKind kind) {
68#define V(Name) #Name "Dependency",
69 static const char* const names[] = {DEPENDENCY_LIST(V)};
70#undef V
71 return names[kind];
72}
73
74class PendingDependencies;
75
76} // namespace
77
79 public:
80 explicit CompilationDependency(CompilationDependencyKind kind) : kind(kind) {}
81
82 virtual bool IsValid(JSHeapBroker* broker) const = 0;
83 virtual void PrepareInstall(JSHeapBroker* broker) const {}
85 PendingDependencies* deps) const = 0;
86
87#define V(Name) \
88 bool Is##Name() const { return kind == k##Name; } \
89 V8_ALLOW_UNUSED const Name##Dependency* As##Name() const;
91#undef V
92
93 const char* ToString() const {
94 return CompilationDependencyKindToString(kind);
95 }
96
97 const CompilationDependencyKind kind;
98
99 private:
100 virtual size_t Hash() const = 0;
101 virtual bool Equals(const CompilationDependency* that) const = 0;
104};
105
110
112 const CompilationDependency* lhs, const CompilationDependency* rhs) const {
113 return lhs->kind == rhs->kind && lhs->Equals(rhs);
114}
115
116namespace {
117
118// Dependencies can only be fully deduplicated immediately prior to
119// installation (because PrepareInstall may create the object on which the dep
120// will be installed). We gather and dedupe deps in this class, and install
121// them from here.
122class PendingDependencies final {
123 public:
124 explicit PendingDependencies(Zone* zone)
125 : deps_(8, {}, ZoneAllocationPolicy(zone)) {}
126
127 void Register(Handle<HeapObject> object,
129 // InstructionStream, which are per-local Isolate, cannot depend on objects
130 // in the shared or RO heaps. Shared and RO heap dependencies are designed
131 // to never invalidate assumptions. E.g., maps for shared structs do not
132 // have transitions or change the shape of their fields. See
133 // DependentCode::DeoptimizeDependencyGroups for corresponding DCHECK.
134 if (HeapLayout::InWritableSharedSpace(*object) ||
135 HeapLayout::InReadOnlySpace(*object))
136 return;
137 deps_.LookupOrInsert(object, HandleValueHash(object))->value |= group;
138 }
139
140 void InstallAll(Isolate* isolate, Handle<Code> code) {
141 if (V8_UNLIKELY(v8_flags.predictable)) {
142 InstallAllPredictable(isolate, code);
143 return;
144 }
145
146 // With deduplication done we no longer rely on the object address for
147 // hashing.
148 AllowGarbageCollection yes_gc;
149 for (auto* entry = deps_.Start(); entry != nullptr;
150 entry = deps_.Next(entry)) {
151 DependentCode::InstallDependency(isolate, code, entry->key, entry->value);
152 }
153 deps_.Invalidate();
154 }
155
156 void InstallAllPredictable(Isolate* isolate, Handle<Code> code) {
157 CHECK(v8_flags.predictable);
158 // First, guarantee predictable iteration order.
159 using DepsMap = decltype(deps_);
160 std::vector<const DepsMap::Entry*> entries;
161 entries.reserve(deps_.occupancy());
162 for (auto* entry = deps_.Start(); entry != nullptr;
163 entry = deps_.Next(entry)) {
164 entries.push_back(entry);
165 }
166
167 std::sort(entries.begin(), entries.end(),
168 [](const DepsMap::Entry* lhs, const DepsMap::Entry* rhs) {
169 return lhs->key->ptr() < rhs->key->ptr();
170 });
171
172 // With deduplication done we no longer rely on the object address for
173 // hashing.
175 for (const auto* entry : entries) {
176 DependentCode::InstallDependency(isolate, code, entry->key, entry->value);
177 }
178 deps_.Invalidate();
179 }
180
181 private:
182 uint32_t HandleValueHash(DirectHandle<HeapObject> handle) {
183 return static_cast<uint32_t>(base::hash_value(handle->ptr()));
184 }
185 struct HandleValueEqual {
186 bool operator()(uint32_t hash1, uint32_t hash2,
187 DirectHandle<HeapObject> lhs,
188 Handle<HeapObject> rhs) const {
189 return hash1 == hash2 && lhs.is_identical_to(rhs);
190 }
191 };
192
193 base::TemplateHashMapImpl<Handle<HeapObject>, DependentCode::DependencyGroups,
194 HandleValueEqual, ZoneAllocationPolicy>
196};
197
198class InitialMapDependency final : public CompilationDependency {
199 public:
200 InitialMapDependency(JSHeapBroker* broker, JSFunctionRef function,
201 MapRef initial_map)
202 : CompilationDependency(kInitialMap),
203 function_(function),
205
206 bool IsValid(JSHeapBroker* broker) const override {
207 DirectHandle<JSFunction> function = function_.object();
208 return function->has_initial_map() &&
209 function->initial_map() == *initial_map_.object();
210 }
211
212 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
213 SLOW_DCHECK(IsValid(broker));
214 deps->Register(initial_map_.object(),
215 DependentCode::kInitialMapChangedGroup);
216 }
217
218 private:
219 size_t Hash() const override {
220 ObjectRef::Hash h;
221 return base::hash_combine(h(function_), h(initial_map_));
222 }
223
224 bool Equals(const CompilationDependency* that) const override {
225 const InitialMapDependency* const zat = that->AsInitialMap();
226 return function_.equals(zat->function_) &&
227 initial_map_.equals(zat->initial_map_);
228 }
229
230 const JSFunctionRef function_;
231 const MapRef initial_map_;
232};
233
234class PrototypePropertyDependency final : public CompilationDependency {
235 public:
236 PrototypePropertyDependency(JSHeapBroker* broker, JSFunctionRef function,
237 ObjectRef prototype)
238 : CompilationDependency(kPrototypeProperty),
239 function_(function),
240 prototype_(prototype) {
241 DCHECK(function_.has_instance_prototype(broker));
242 DCHECK(!function_.PrototypeRequiresRuntimeLookup(broker));
243 DCHECK(function_.instance_prototype(broker).equals(prototype_));
244 }
245
246 bool IsValid(JSHeapBroker* broker) const override {
247 DirectHandle<JSFunction> function = function_.object();
248 return function->has_prototype_slot() &&
249 function->has_instance_prototype() &&
250 !function->PrototypeRequiresRuntimeLookup() &&
251 function->instance_prototype() == *prototype_.object();
252 }
253
254 void PrepareInstall(JSHeapBroker* broker) const override {
255 SLOW_DCHECK(IsValid(broker));
256 DirectHandle<JSFunction> function = function_.object();
257 if (!function->has_initial_map()) JSFunction::EnsureHasInitialMap(function);
258 }
259
260 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
261 SLOW_DCHECK(IsValid(broker));
262 DirectHandle<JSFunction> function = function_.object();
263 CHECK(function->has_initial_map());
264 Handle<Map> initial_map(function->initial_map(), broker->isolate());
265 deps->Register(initial_map, DependentCode::kInitialMapChangedGroup);
266 }
267
268 private:
269 size_t Hash() const override {
270 ObjectRef::Hash h;
271 return base::hash_combine(h(function_), h(prototype_));
272 }
273
274 bool Equals(const CompilationDependency* that) const override {
275 const PrototypePropertyDependency* const zat = that->AsPrototypeProperty();
276 return function_.equals(zat->function_) &&
277 prototype_.equals(zat->prototype_);
278 }
279
280 const JSFunctionRef function_;
281 const ObjectRef prototype_;
282};
283
284class StableMapDependency final : public CompilationDependency {
285 public:
286 explicit StableMapDependency(MapRef map)
287 : CompilationDependency(kStableMap), map_(map) {}
288
289 bool IsValid(JSHeapBroker* broker) const override {
290 // TODO(v8:11670): Consider turn this back into a CHECK inside the
291 // constructor and DependOnStableMap, if possible in light of concurrent
292 // heap state modifications.
293 return !map_.object()->is_dictionary_map() && map_.object()->is_stable();
294 }
295 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
296 SLOW_DCHECK(IsValid(broker));
297 deps->Register(map_.object(), DependentCode::kPrototypeCheckGroup);
298 }
299
300 private:
301 size_t Hash() const override {
302 ObjectRef::Hash h;
303 return base::hash_combine(h(map_));
304 }
305
306 bool Equals(const CompilationDependency* that) const override {
307 const StableMapDependency* const zat = that->AsStableMap();
308 return map_.equals(zat->map_);
309 }
310
311 const MapRef map_;
312};
313
314class ConstantInDictionaryPrototypeChainDependency final
315 : public CompilationDependency {
316 public:
317 explicit ConstantInDictionaryPrototypeChainDependency(
318 const MapRef receiver_map, const NameRef property_name,
319 const ObjectRef constant, PropertyKind kind)
320 : CompilationDependency(kConstantInDictionaryPrototypeChain),
321 receiver_map_(receiver_map),
322 property_name_{property_name},
323 constant_{constant},
324 kind_{kind} {
326 }
327
328 // Checks that |constant_| is still the value of accessing |property_name_|
329 // starting at |receiver_map_|.
330 bool IsValid(JSHeapBroker* broker) const override {
331 return !GetHolderIfValid(broker).is_null();
332 }
333
334 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
335 SLOW_DCHECK(IsValid(broker));
336 Isolate* isolate = broker->isolate();
337 DirectHandle<JSObject> holder = GetHolderIfValid(broker).ToHandleChecked();
338 Handle<Map> map = receiver_map_.object();
339
340 while (map->prototype() != *holder) {
341 map = handle(map->prototype()->map(), isolate);
342 DCHECK(IsJSObjectMap(*map)); // Due to IsValid holding.
343 deps->Register(map, DependentCode::kPrototypeCheckGroup);
344 }
345
346 DCHECK(IsJSObjectMap(map->prototype()->map())); // Due to IsValid holding.
347 deps->Register(handle(map->prototype()->map(), isolate),
348 DependentCode::kPrototypeCheckGroup);
349 }
350
351 private:
352 // If the dependency is still valid, returns holder of the constant. Otherwise
353 // returns null.
354 // TODO(neis) Currently, invoking IsValid and then Install duplicates the call
355 // to GetHolderIfValid. Instead, consider letting IsValid change the state
356 // (and store the holder), or merge IsValid and Install.
357 MaybeHandle<JSObject> GetHolderIfValid(JSHeapBroker* broker) const {
359 Isolate* isolate = broker->isolate();
360
361 Tagged<HeapObject> prototype = receiver_map_.object()->prototype();
362
363 enum class ValidationResult { kFoundCorrect, kFoundIncorrect, kNotFound };
364 auto try_load = [&](auto dictionary) -> ValidationResult {
365 InternalIndex entry =
366 dictionary->FindEntry(isolate, property_name_.object());
367 if (entry.is_not_found()) {
368 return ValidationResult::kNotFound;
369 }
370
371 PropertyDetails details = dictionary->DetailsAt(entry);
372 if (details.constness() != PropertyConstness::kConst) {
373 return ValidationResult::kFoundIncorrect;
374 }
375
376 Tagged<Object> dictionary_value = dictionary->ValueAt(entry);
377 Tagged<Object> value;
378 // We must be able to detect the case that the property |property_name_|
379 // of |holder_| was originally a plain function |constant_| (when creating
380 // this dependency) and has since become an accessor whose getter is
381 // |constant_|. Therefore, we cannot just look at the property kind of
382 // |details|, because that reflects the current situation, not the one
383 // when creating this dependency.
384 if (details.kind() != kind_) {
385 return ValidationResult::kFoundIncorrect;
386 }
387 if (kind_ == PropertyKind::kAccessor) {
388 if (!IsAccessorPair(dictionary_value)) {
389 return ValidationResult::kFoundIncorrect;
390 }
391 // Only supporting loading at the moment, so we only ever want the
392 // getter.
393 value = Cast<AccessorPair>(dictionary_value)
394 ->get(AccessorComponent::ACCESSOR_GETTER);
395 } else {
396 value = dictionary_value;
397 }
398 return value == *constant_.object() ? ValidationResult::kFoundCorrect
399 : ValidationResult::kFoundIncorrect;
400 };
401
402 while (IsJSObject(prototype)) {
403 // We only care about JSObjects because that's the only type of holder
404 // (and types of prototypes on the chain to the holder) that
405 // AccessInfoFactory::ComputePropertyAccessInfo allows.
406 Tagged<JSObject> object = Cast<JSObject>(prototype);
407
408 // We only support dictionary mode prototypes on the chain for this kind
409 // of dependency.
410 CHECK(!object->HasFastProperties());
411
412 ValidationResult result =
414 ? try_load(object->property_dictionary_swiss())
415 : try_load(object->property_dictionary());
416
417 if (result == ValidationResult::kFoundCorrect) {
418 return handle(object, isolate);
419 } else if (result == ValidationResult::kFoundIncorrect) {
420 return MaybeHandle<JSObject>();
421 }
422
423 // In case of kNotFound, continue walking up the chain.
424 prototype = object->map()->prototype();
425 }
426
427 return MaybeHandle<JSObject>();
428 }
429
430 size_t Hash() const override {
431 ObjectRef::Hash h;
432 return base::hash_combine(h(receiver_map_), h(property_name_), h(constant_),
433 static_cast<int>(kind_));
434 }
435
436 bool Equals(const CompilationDependency* that) const override {
437 const ConstantInDictionaryPrototypeChainDependency* const zat =
438 that->AsConstantInDictionaryPrototypeChain();
439 return receiver_map_.equals(zat->receiver_map_) &&
440 property_name_.equals(zat->property_name_) &&
441 constant_.equals(zat->constant_) && kind_ == zat->kind_;
442 }
443
444 const MapRef receiver_map_;
445 const NameRef property_name_;
446 const ObjectRef constant_;
447 const PropertyKind kind_;
448};
449
450class OwnConstantDataPropertyDependency final : public CompilationDependency {
451 public:
452 OwnConstantDataPropertyDependency(JSHeapBroker* broker, JSObjectRef holder,
453 MapRef map, FieldIndex index,
454 ObjectRef value)
455 : CompilationDependency(kOwnConstantDataProperty),
457 holder_(holder),
458 map_(map),
459 index_(index),
460 value_(value) {}
461
462 bool IsValid(JSHeapBroker* broker) const override {
463 if (holder_.object()->map() != *map_.object()) {
465 "Map change detected in " << holder_.object());
466 return false;
467 }
468 DisallowGarbageCollection no_heap_allocation;
469 Tagged<Object> current_value = holder_.object()->RawFastPropertyAt(index_);
470 Tagged<Object> used_value = *value_.object();
471 if (current_value != used_value) {
472 TRACE_BROKER_MISSING(broker_, "Constant property value changed in "
473 << holder_.object() << " at FieldIndex "
474 << index_.property_index());
475 return false;
476 }
477 return true;
478 }
479
480 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
481 }
482
483 private:
484 size_t Hash() const override {
485 ObjectRef::Hash h;
486 return base::hash_combine(h(holder_), h(map_), index_.bit_field(),
487 h(value_));
488 }
489
490 bool Equals(const CompilationDependency* that) const override {
491 const OwnConstantDataPropertyDependency* const zat =
492 that->AsOwnConstantDataProperty();
493 return holder_.equals(zat->holder_) && map_.equals(zat->map_) &&
494 index_ == zat->index_ && value_.equals(zat->value_);
495 }
496
497 JSHeapBroker* const broker_;
498 JSObjectRef const holder_;
499 MapRef const map_;
500 FieldIndex const index_;
501 ObjectRef const value_;
502};
503
504class OwnConstantDoublePropertyDependency final : public CompilationDependency {
505 public:
506 OwnConstantDoublePropertyDependency(JSHeapBroker* broker, JSObjectRef holder,
507 MapRef map, FieldIndex index,
508 Float64 value)
509 : CompilationDependency(kOwnConstantDoubleProperty),
511 holder_(holder),
512 map_(map),
513 index_(index),
514 value_(value) {}
515
516 bool IsValid(JSHeapBroker* broker) const override {
517 if (holder_.object()->map() != *map_.object()) {
519 "Map change detected in " << holder_.object());
520 return false;
521 }
522 DisallowGarbageCollection no_heap_allocation;
523 Tagged<Object> current_value = holder_.object()->RawFastPropertyAt(index_);
524 Float64 used_value = value_;
525
526 // Compare doubles by bit pattern.
527 if (!IsHeapNumber(current_value) ||
528 Cast<HeapNumber>(current_value)->value_as_bits() !=
529 used_value.get_bits()) {
530 TRACE_BROKER_MISSING(broker_, "Constant Double property value changed in "
531 << holder_.object() << " at FieldIndex "
532 << index_.property_index());
533 return false;
534 }
535
536 return true;
537 }
538
539 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
540 }
541
542 private:
543 size_t Hash() const override {
544 ObjectRef::Hash h;
545 return base::hash_combine(h(holder_), h(map_), index_.bit_field(),
546 value_.get_bits());
547 }
548
549 bool Equals(const CompilationDependency* that) const override {
550 const OwnConstantDoublePropertyDependency* const zat =
551 that->AsOwnConstantDoubleProperty();
552 return holder_.equals(zat->holder_) && map_.equals(zat->map_) &&
553 index_ == zat->index_ && value_.get_bits() == zat->value_.get_bits();
554 }
555
556 JSHeapBroker* const broker_;
557 JSObjectRef const holder_;
558 MapRef const map_;
559 FieldIndex const index_;
560 Float64 const value_;
561};
562
563class OwnConstantDictionaryPropertyDependency final
564 : public CompilationDependency {
565 public:
566 OwnConstantDictionaryPropertyDependency(JSHeapBroker* broker,
567 JSObjectRef holder,
568 InternalIndex index, ObjectRef value)
569 : CompilationDependency(kOwnConstantDictionaryProperty),
570 holder_(holder),
571 map_(holder.map(broker)),
572 index_(index),
573 value_(value) {
574 // We depend on map() being cached.
575 static_assert(ref_traits<JSObject>::ref_serialization_kind !=
576 RefSerializationKind::kNeverSerialized);
577 }
578
579 bool IsValid(JSHeapBroker* broker) const override {
580 if (holder_.object()->map() != *map_.object()) {
582 "Map change detected in " << holder_.object());
583 return false;
584 }
585
586 std::optional<Tagged<Object>> maybe_value = JSObject::DictionaryPropertyAt(
587 holder_.object(), index_, broker->isolate()->heap());
588
589 if (!maybe_value) {
591 broker, holder_.object()
592 << "has a value that might not safe to read at index "
593 << index_.as_int());
594 return false;
595 }
596
597 if (*maybe_value != *value_.object()) {
598 TRACE_BROKER_MISSING(broker, "Constant property value changed in "
599 << holder_.object()
600 << " at InternalIndex "
601 << index_.as_int());
602 return false;
603 }
604 return true;
605 }
606
607 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
608 }
609
610 private:
611 size_t Hash() const override {
612 ObjectRef::Hash h;
613 return base::hash_combine(h(holder_), h(map_), index_.raw_value(),
614 h(value_));
615 }
616
617 bool Equals(const CompilationDependency* that) const override {
618 const OwnConstantDictionaryPropertyDependency* const zat =
619 that->AsOwnConstantDictionaryProperty();
620 return holder_.equals(zat->holder_) && map_.equals(zat->map_) &&
621 index_ == zat->index_ && value_.equals(zat->value_);
622 }
623
624 JSObjectRef const holder_;
625 MapRef const map_;
626 InternalIndex const index_;
627 ObjectRef const value_;
628};
629
630class ConsistentJSFunctionViewDependency final : public CompilationDependency {
631 public:
632 explicit ConsistentJSFunctionViewDependency(JSFunctionRef function)
633 : CompilationDependency(kConsistentJSFunctionView), function_(function) {}
634
635 bool IsValid(JSHeapBroker* broker) const override {
636 return function_.IsConsistentWithHeapState(broker);
637 }
638
639 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
640 }
641
642 private:
643 size_t Hash() const override {
644 ObjectRef::Hash h;
645 return base::hash_combine(h(function_));
646 }
647
648 bool Equals(const CompilationDependency* that) const override {
649 const ConsistentJSFunctionViewDependency* const zat =
650 that->AsConsistentJSFunctionView();
651 return function_.equals(zat->function_);
652 }
653
654 const JSFunctionRef function_;
655};
656
657class TransitionDependency final : public CompilationDependency {
658 public:
659 explicit TransitionDependency(MapRef map)
660 : CompilationDependency(kTransition), map_(map) {
661 DCHECK(map_.CanBeDeprecated());
662 }
663
664 bool IsValid(JSHeapBroker* broker) const override {
665 return !map_.object()->is_deprecated();
666 }
667
668 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
669 SLOW_DCHECK(IsValid(broker));
670 deps->Register(map_.object(), DependentCode::kTransitionGroup);
671 }
672
673 private:
674 size_t Hash() const override {
675 ObjectRef::Hash h;
676 return base::hash_combine(h(map_));
677 }
678
679 bool Equals(const CompilationDependency* that) const override {
680 const TransitionDependency* const zat = that->AsTransition();
681 return map_.equals(zat->map_);
682 }
683
684 const MapRef map_;
685};
686
687class PretenureModeDependency final : public CompilationDependency {
688 public:
689 PretenureModeDependency(AllocationSiteRef site, AllocationType allocation)
690 : CompilationDependency(kPretenureMode),
691 site_(site),
692 allocation_(allocation) {}
693
694 bool IsValid(JSHeapBroker* broker) const override {
695 return allocation_ == site_.object()->GetAllocationType();
696 }
697 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
698 SLOW_DCHECK(IsValid(broker));
699 deps->Register(site_.object(),
700 DependentCode::kAllocationSiteTenuringChangedGroup);
701 }
702
703 private:
704 size_t Hash() const override {
705 ObjectRef::Hash h;
706 return base::hash_combine(h(site_), allocation_);
707 }
708
709 bool Equals(const CompilationDependency* that) const override {
710 const PretenureModeDependency* const zat = that->AsPretenureMode();
711 return site_.equals(zat->site_) && allocation_ == zat->allocation_;
712 }
713
714 const AllocationSiteRef site_;
715 const AllocationType allocation_;
716};
717
718class FieldRepresentationDependency final : public CompilationDependency {
719 public:
720 FieldRepresentationDependency(MapRef map, MapRef owner,
721 InternalIndex descriptor,
722 Representation representation)
723 : CompilationDependency(kFieldRepresentation),
724 map_(map),
725 owner_(owner),
726 descriptor_(descriptor),
727 representation_(representation) {}
728
729 bool IsValid(JSHeapBroker* broker) const override {
730 DisallowGarbageCollection no_heap_allocation;
731 if (map_.object()->is_deprecated()) return false;
732 return representation_.Equals(map_.object()
733 ->instance_descriptors(broker->isolate())
734 ->GetDetails(descriptor_)
735 .representation());
736 }
737
738 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
739 SLOW_DCHECK(IsValid(broker));
740 Isolate* isolate = broker->isolate();
741 Handle<Map> owner = owner_.object();
742 CHECK(!owner->is_deprecated());
743 CHECK(representation_.Equals(owner->instance_descriptors(isolate)
744 ->GetDetails(descriptor_)
745 .representation()));
746 deps->Register(owner, DependentCode::kFieldRepresentationGroup);
747 }
748
749 bool DependsOn(const Handle<Map>& receiver_map) const {
750 return map_.object().equals(receiver_map);
751 }
752
753 private:
754 size_t Hash() const override {
755 ObjectRef::Hash h;
756 return base::hash_combine(h(map_), descriptor_.as_int(),
757 representation_.kind());
758 }
759
760 bool Equals(const CompilationDependency* that) const override {
761 const FieldRepresentationDependency* const zat =
762 that->AsFieldRepresentation();
763 return map_.equals(zat->map_) && descriptor_ == zat->descriptor_ &&
764 representation_.Equals(zat->representation_);
765 }
766
767 const MapRef map_;
768 const MapRef owner_;
769 const InternalIndex descriptor_;
770 const Representation representation_;
771};
772
773class FieldTypeDependency final : public CompilationDependency {
774 public:
775 FieldTypeDependency(MapRef map, MapRef owner, InternalIndex descriptor,
776 ObjectRef type)
777 : CompilationDependency(kFieldType),
778 map_(map),
779 owner_(owner),
780 descriptor_(descriptor),
781 type_(type) {}
782
783 bool IsValid(JSHeapBroker* broker) const override {
784 DisallowGarbageCollection no_heap_allocation;
785 if (map_.object()->is_deprecated()) return false;
786 return *type_.object() == map_.object()
787 ->instance_descriptors(broker->isolate())
788 ->GetFieldType(descriptor_);
789 }
790
791 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
792 SLOW_DCHECK(IsValid(broker));
793 Isolate* isolate = broker->isolate();
794 Handle<Map> owner = owner_.object();
795 CHECK(!owner->is_deprecated());
796 CHECK_EQ(*type_.object(),
797 owner->instance_descriptors(isolate)->GetFieldType(descriptor_));
798 deps->Register(owner, DependentCode::kFieldTypeGroup);
799 }
800
801 private:
802 size_t Hash() const override {
803 ObjectRef::Hash h;
804 return base::hash_combine(h(map_), descriptor_.as_int(), h(type_));
805 }
806
807 bool Equals(const CompilationDependency* that) const override {
808 const FieldTypeDependency* const zat = that->AsFieldType();
809 return map_.equals(zat->map_) && descriptor_ == zat->descriptor_ &&
810 type_.equals(zat->type_);
811 }
812
813 const MapRef map_;
814 const MapRef owner_;
815 const InternalIndex descriptor_;
816 const ObjectRef type_;
817};
818
819class FieldConstnessDependency final : public CompilationDependency {
820 public:
821 FieldConstnessDependency(MapRef map, MapRef owner, InternalIndex descriptor)
822 : CompilationDependency(kFieldConstness),
823 map_(map),
824 owner_(owner),
825 descriptor_(descriptor) {}
826
827 bool IsValid(JSHeapBroker* broker) const override {
828 DisallowGarbageCollection no_heap_allocation;
829 if (map_.object()->is_deprecated()) return false;
830 return PropertyConstness::kConst ==
831 map_.object()
832 ->instance_descriptors(broker->isolate())
833 ->GetDetails(descriptor_)
834 .constness();
835 }
836
837 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
838 SLOW_DCHECK(IsValid(broker));
839 Isolate* isolate = broker->isolate();
840 Handle<Map> owner = owner_.object();
841 CHECK(!owner->is_deprecated());
842 CHECK_EQ(PropertyConstness::kConst, owner->instance_descriptors(isolate)
843 ->GetDetails(descriptor_)
844 .constness());
845 deps->Register(owner, DependentCode::kFieldConstGroup);
846 }
847
848 private:
849 size_t Hash() const override {
850 ObjectRef::Hash h;
851 return base::hash_combine(h(map_), descriptor_.as_int());
852 }
853
854 bool Equals(const CompilationDependency* that) const override {
855 const FieldConstnessDependency* const zat = that->AsFieldConstness();
856 return map_.equals(zat->map_) && descriptor_ == zat->descriptor_;
857 }
858
859 const MapRef map_;
860 const MapRef owner_;
861 const InternalIndex descriptor_;
862};
863
864class GlobalPropertyDependency final : public CompilationDependency {
865 public:
866 GlobalPropertyDependency(PropertyCellRef cell, PropertyCellType type,
867 bool read_only)
868 : CompilationDependency(kGlobalProperty),
869 cell_(cell),
870 type_(type),
871 read_only_(read_only) {
872 DCHECK_EQ(type_, cell_.property_details().cell_type());
873 DCHECK_EQ(read_only_, cell_.property_details().IsReadOnly());
874 }
875
876 bool IsValid(JSHeapBroker* broker) const override {
877 DirectHandle<PropertyCell> cell = cell_.object();
878 // The dependency is never valid if the cell is 'invalidated'. This is
879 // marked by setting the value to the hole.
880 if (cell->value() ==
881 *(broker->isolate()->factory()->property_cell_hole_value())) {
882 return false;
883 }
884 return type_ == cell->property_details().cell_type() &&
885 read_only_ == cell->property_details().IsReadOnly();
886 }
887 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
888 SLOW_DCHECK(IsValid(broker));
889 deps->Register(cell_.object(), DependentCode::kPropertyCellChangedGroup);
890 }
891
892 private:
893 size_t Hash() const override {
894 ObjectRef::Hash h;
895 return base::hash_combine(h(cell_), static_cast<int>(type_), read_only_);
896 }
897
898 bool Equals(const CompilationDependency* that) const override {
899 const GlobalPropertyDependency* const zat = that->AsGlobalProperty();
900 return cell_.equals(zat->cell_) && type_ == zat->type_ &&
901 read_only_ == zat->read_only_;
902 }
903
904 const PropertyCellRef cell_;
905 const PropertyCellType type_;
906 const bool read_only_;
907};
908
909class ScriptContextSlotPropertyDependency final : public CompilationDependency {
910 public:
911 ScriptContextSlotPropertyDependency(
912 ContextRef script_context, size_t index,
913 ContextSidePropertyCell::Property property)
914 : CompilationDependency(kScriptContextSlotProperty),
915 script_context_(script_context),
916 index_(index),
917 property_(property) {
918 DCHECK(v8_flags.script_context_mutable_heap_number ||
919 v8_flags.const_tracking_let);
920 }
921
922 bool IsValid(JSHeapBroker* broker) const override {
923 return script_context_.object()->GetScriptContextSideProperty(index_) ==
924 property_;
925 }
926
927 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
928 SLOW_DCHECK(IsValid(broker));
929 Isolate* isolate = broker->isolate();
930 deps->Register(
931 handle(Context::GetOrCreateContextSidePropertyCell(
932 script_context_.object(), index_, property_, isolate),
933 isolate),
934 DependentCode::kScriptContextSlotPropertyChangedGroup);
935 }
936
937 private:
938 size_t Hash() const override {
939 ObjectRef::Hash h;
940 return base::hash_combine(h(script_context_), index_);
941 }
942
943 bool Equals(const CompilationDependency* that) const override {
944 const ScriptContextSlotPropertyDependency* const zat =
945 that->AsScriptContextSlotProperty();
946 return script_context_.equals(zat->script_context_) &&
947 index_ == zat->index_ && property_ == zat->property_;
948 }
949
950 const ContextRef script_context_;
951 size_t index_;
952 ContextSidePropertyCell::Property property_;
953};
954
955class EmptyContextExtensionDependency final : public CompilationDependency {
956 public:
957 explicit EmptyContextExtensionDependency(ScopeInfoRef scope_info)
958 : CompilationDependency(kEmptyContextExtension), scope_info_(scope_info) {
959 DCHECK(v8_flags.empty_context_extension_dep);
960 DCHECK(scope_info.SloppyEvalCanExtendVars());
961 DCHECK(!HeapLayout::InReadOnlySpace(*scope_info.object()));
962 }
963
964 bool IsValid(JSHeapBroker* broker) const override {
965 return !scope_info_.SomeContextHasExtension();
966 }
967
968 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
969 SLOW_DCHECK(IsValid(broker));
970 deps->Register(scope_info_.object(),
971 DependentCode::kEmptyContextExtensionGroup);
972 }
973
974 private:
975 size_t Hash() const override {
976 ObjectRef::Hash h;
977 return base::hash_combine(h(scope_info_));
978 }
979
980 bool Equals(const CompilationDependency* that) const override {
981 const EmptyContextExtensionDependency* const zat =
982 that->AsEmptyContextExtension();
983 return scope_info_.equals(zat->scope_info_);
984 }
985
986 const ScopeInfoRef scope_info_;
987};
988
989class ProtectorDependency final : public CompilationDependency {
990 public:
991 explicit ProtectorDependency(PropertyCellRef cell)
992 : CompilationDependency(kProtector), cell_(cell) {}
993
994 bool IsValid(JSHeapBroker* broker) const override {
995 DirectHandle<PropertyCell> cell = cell_.object();
996 return cell->value() == Smi::FromInt(Protectors::kProtectorValid);
997 }
998 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
999 SLOW_DCHECK(IsValid(broker));
1000 deps->Register(cell_.object(), DependentCode::kPropertyCellChangedGroup);
1001 }
1002
1003 private:
1004 size_t Hash() const override {
1005 ObjectRef::Hash h;
1006 return base::hash_combine(h(cell_));
1007 }
1008
1009 bool Equals(const CompilationDependency* that) const override {
1010 const ProtectorDependency* const zat = that->AsProtector();
1011 return cell_.equals(zat->cell_);
1012 }
1013
1014 const PropertyCellRef cell_;
1015};
1016
1017// Check that an object slot will not change during compilation.
1018class ObjectSlotValueDependency final : public CompilationDependency {
1019 public:
1020 explicit ObjectSlotValueDependency(HeapObjectRef object, int offset,
1021 ObjectRef value)
1022 : CompilationDependency(kObjectSlotValue),
1023 object_(object.object()),
1024 offset_(offset),
1025 value_(value.object()) {}
1026
1027 bool IsValid(JSHeapBroker* broker) const override {
1028 PtrComprCageBase cage_base = GetPtrComprCageBase(*object_);
1029 Tagged<Object> current_value =
1030 offset_ == HeapObject::kMapOffset
1031 ? object_->map()
1032 : TaggedField<Object>::Relaxed_Load(cage_base, *object_, offset_);
1033 return *value_ == current_value;
1034 }
1035 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
1036 }
1037
1038 private:
1039 size_t Hash() const override {
1040 return base::hash_combine(object_.address(), offset_, value_.address());
1041 }
1042
1043 bool Equals(const CompilationDependency* that) const override {
1044 const ObjectSlotValueDependency* const zat = that->AsObjectSlotValue();
1045 return object_->address() == zat->object_->address() &&
1046 offset_ == zat->offset_ && value_.address() == zat->value_.address();
1047 }
1048
1049 Handle<HeapObject> object_;
1051 Handle<Object> value_;
1052};
1053
1054class ElementsKindDependency final : public CompilationDependency {
1055 public:
1056 ElementsKindDependency(AllocationSiteRef site, ElementsKind kind)
1057 : CompilationDependency(kElementsKind), site_(site), kind_(kind) {
1058 DCHECK(AllocationSite::ShouldTrack(kind_));
1059 }
1060
1061 bool IsValid(JSHeapBroker* broker) const override {
1062 DirectHandle<AllocationSite> site = site_.object();
1064 site->PointsToLiteral()
1065 ? site->boilerplate(kAcquireLoad)->map()->elements_kind()
1066 : site->GetElementsKind();
1067 return kind_ == kind;
1068 }
1069 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
1070 SLOW_DCHECK(IsValid(broker));
1071 deps->Register(site_.object(),
1072 DependentCode::kAllocationSiteTransitionChangedGroup);
1073 }
1074
1075 private:
1076 size_t Hash() const override {
1077 ObjectRef::Hash h;
1078 return base::hash_combine(h(site_), static_cast<int>(kind_));
1079 }
1080
1081 bool Equals(const CompilationDependency* that) const override {
1082 const ElementsKindDependency* const zat = that->AsElementsKind();
1083 return site_.equals(zat->site_) && kind_ == zat->kind_;
1084 }
1085
1086 const AllocationSiteRef site_;
1087 const ElementsKind kind_;
1088};
1089
1090// Only valid if the holder can use direct reads, since validation uses
1091// GetOwnConstantElementFromHeap.
1092class OwnConstantElementDependency final : public CompilationDependency {
1093 public:
1094 OwnConstantElementDependency(JSObjectRef holder, uint32_t index,
1095 ObjectRef element)
1096 : CompilationDependency(kOwnConstantElement),
1097 holder_(holder),
1098 index_(index),
1099 element_(element) {}
1100
1101 bool IsValid(JSHeapBroker* broker) const override {
1103 Tagged<JSObject> holder = *holder_.object();
1104 std::optional<Tagged<Object>> maybe_element =
1105 holder_.GetOwnConstantElementFromHeap(
1106 broker, holder->elements(), holder->GetElementsKind(), index_);
1107 if (!maybe_element.has_value()) return false;
1108
1109 return maybe_element.value() == *element_.object();
1110 }
1111 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
1112 }
1113
1114 private:
1115 size_t Hash() const override {
1116 ObjectRef::Hash h;
1117 return base::hash_combine(h(holder_), index_, h(element_));
1118 }
1119
1120 bool Equals(const CompilationDependency* that) const override {
1121 const OwnConstantElementDependency* const zat =
1122 that->AsOwnConstantElement();
1123 return holder_.equals(zat->holder_) && index_ == zat->index_ &&
1124 element_.equals(zat->element_);
1125 }
1126
1127 const JSObjectRef holder_;
1128 const uint32_t index_;
1129 const ObjectRef element_;
1130};
1131
1132class NoSlackTrackingChangeDependency final : public CompilationDependency {
1133 public:
1134 explicit NoSlackTrackingChangeDependency(MapRef map)
1135 : CompilationDependency(kNoSlackTrackingChange), map_(map) {}
1136
1137 bool IsValid(JSHeapBroker* broker) const override {
1138 if (map_.construction_counter() != 0 &&
1139 map_.object()->construction_counter() == 0) {
1140 // Slack tracking finished during compilation.
1141 return false;
1142 }
1143 return map_.UnusedPropertyFields() ==
1144 map_.object()->UnusedPropertyFields() &&
1145 map_.GetInObjectProperties() ==
1146 map_.object()->GetInObjectProperties();
1147 }
1148
1149 void PrepareInstall(JSHeapBroker*) const override {}
1150 void Install(JSHeapBroker*, PendingDependencies*) const override {}
1151
1152 private:
1153 size_t Hash() const override {
1154 ObjectRef::Hash h;
1155 return base::hash_combine(h(map_));
1156 }
1157
1158 bool Equals(const CompilationDependency* that) const override {
1159 const NoSlackTrackingChangeDependency* const zat =
1160 that->AsNoSlackTrackingChange();
1161 return map_.equals(zat->map_);
1162 }
1163
1164 const MapRef map_;
1165};
1166
1167class InitialMapInstanceSizePredictionDependency final
1168 : public CompilationDependency {
1169 public:
1170 InitialMapInstanceSizePredictionDependency(JSFunctionRef function,
1171 int instance_size)
1172 : CompilationDependency(kInitialMapInstanceSizePrediction),
1173 function_(function),
1174 instance_size_(instance_size) {}
1175
1176 bool IsValid(JSHeapBroker* broker) const override {
1177 // The dependency is valid if the prediction is the same as the current
1178 // slack tracking result.
1179 if (!function_.object()->has_initial_map()) return false;
1180 int instance_size =
1181 function_.object()->ComputeInstanceSizeWithMinSlack(broker->isolate());
1182 return instance_size == instance_size_;
1183 }
1184
1185 void PrepareInstall(JSHeapBroker* broker) const override {
1186 SLOW_DCHECK(IsValid(broker));
1187 function_.object()->CompleteInobjectSlackTrackingIfActive();
1188 }
1189
1190 void Install(JSHeapBroker* broker, PendingDependencies* deps) const override {
1191 SLOW_DCHECK(IsValid(broker));
1192 DCHECK(!function_.object()
1193 ->initial_map()
1194 ->IsInobjectSlackTrackingInProgress());
1195 }
1196
1197 private:
1198 size_t Hash() const override {
1199 ObjectRef::Hash h;
1200 return base::hash_combine(h(function_), instance_size_);
1201 }
1202
1203 bool Equals(const CompilationDependency* that) const override {
1204 const InitialMapInstanceSizePredictionDependency* const zat =
1205 that->AsInitialMapInstanceSizePrediction();
1206 return function_.equals(zat->function_) &&
1207 instance_size_ == zat->instance_size_;
1208 }
1209
1210 const JSFunctionRef function_;
1212};
1213
1214} // namespace
1215
1217 CompilationDependency const* dependency) {
1218 if (dependency != nullptr) dependencies_.insert(dependency);
1219}
1220
1222 MapRef map = function.initial_map(broker_);
1223 RecordDependency(zone_->New<InitialMapDependency>(broker_, function, map));
1224 return map;
1225}
1226
1228 JSFunctionRef function) {
1229 HeapObjectRef prototype = function.instance_prototype(broker_);
1231 zone_->New<PrototypePropertyDependency>(broker_, function, prototype));
1232 return prototype;
1233}
1234
1236 if (map.CanTransition()) {
1237 RecordDependency(zone_->New<StableMapDependency>(map));
1238 }
1239}
1240
1242 MapRef receiver_map, NameRef property_name, ObjectRef constant,
1244 RecordDependency(zone_->New<ConstantInDictionaryPrototypeChainDependency>(
1245 receiver_map, property_name, constant, kind));
1246}
1247
1249 AllocationSiteRef site) {
1250 if (!v8_flags.allocation_site_pretenuring) return AllocationType::kYoung;
1251 AllocationType allocation = site.GetAllocationType();
1252 RecordDependency(zone_->New<PretenureModeDependency>(site, allocation));
1253 return allocation;
1254}
1255
1257 MapRef map, MapRef owner, InternalIndex descriptor) {
1258 PropertyConstness constness =
1259 map.GetPropertyDetails(broker_, descriptor).constness();
1260 if (constness == PropertyConstness::kMutable) return constness;
1261
1262 // If the map can have fast elements transitions, then the field can be only
1263 // considered constant if the map does not transition.
1264 if (Map::CanHaveFastTransitionableElementsKind(map.instance_type())) {
1265 // If the map can already transition away, let us report the field as
1266 // mutable.
1267 if (!map.is_stable()) {
1269 }
1270 DependOnStableMap(map);
1271 }
1272
1275 zone_->New<FieldConstnessDependency>(map, owner, descriptor));
1277}
1278
1281 MapRef map, MapRef owner, InternalIndex descriptor) {
1282 DCHECK_EQ(map.GetPropertyDetails(broker_, descriptor).constness(),
1284
1285 // If the map can have fast elements transitions, then the field can be only
1286 // considered constant if the map does not transition.
1287 if (Map::CanHaveFastTransitionableElementsKind(map.instance_type())) {
1288 // If the map can already transition away, let us report the field as
1289 // mutable.
1290 if (!map.is_stable()) {
1291 return {};
1292 }
1293 DependOnStableMap(map);
1294 }
1295
1296 return zone_->New<FieldConstnessDependency>(map, owner, descriptor);
1297}
1298
1300 PropertyCellType type = cell.property_details().cell_type();
1301 bool read_only = cell.property_details().IsReadOnly();
1302 RecordDependency(zone_->New<GlobalPropertyDependency>(cell, type, read_only));
1303}
1304
1306 ContextRef script_context, size_t index,
1308 if ((v8_flags.const_tracking_let ||
1309 v8_flags.script_context_mutable_heap_number) &&
1310 script_context.object()->IsScriptContext() &&
1311 script_context.object()->GetScriptContextSideProperty(index) ==
1312 property) {
1313 RecordDependency(zone_->New<ScriptContextSlotPropertyDependency>(
1314 script_context, index, property));
1315 return true;
1316 }
1317 return false;
1318}
1319
1321 ScopeInfoRef scope_info) {
1322 if (!v8_flags.empty_context_extension_dep) return false;
1323 DCHECK(scope_info.SloppyEvalCanExtendVars());
1324 if (HeapLayout::InReadOnlySpace(*scope_info.object()) ||
1325 scope_info.object()->SomeContextHasExtension()) {
1326 // There are respective contexts with non-empty context extension, so
1327 // dynamic checks are required.
1328 return false;
1329 }
1330 RecordDependency(zone_->New<EmptyContextExtensionDependency>(scope_info));
1331 return true;
1332}
1333
1335 cell.CacheAsProtector(broker_);
1336 if (cell.value(broker_).AsSmi() != Protectors::kProtectorValid) return false;
1337 RecordDependency(zone_->New<ProtectorDependency>(cell));
1338 return true;
1339}
1340
1342 return DependOnProtector(
1343 MakeRef(broker_, broker_->isolate()->factory()->mega_dom_protector()));
1344}
1345
1347 // A shortcut in case profiling was already enabled but the interrupt
1348 // request to invalidate NoProfilingProtector wasn't processed yet.
1349#ifdef V8_RUNTIME_CALL_STATS
1350 if (TracingFlags::is_runtime_stats_enabled()) return false;
1351#endif
1352 if (broker_->isolate()->is_profiling()) return false;
1354 broker_, broker_->isolate()->factory()->no_profiling_protector()));
1355}
1356
1359 broker_,
1360 broker_->isolate()->factory()->no_undetectable_objects_protector()));
1361}
1362
1365 broker_,
1366 broker_->isolate()->factory()->array_buffer_detaching_protector()));
1367}
1368
1371 broker_, broker_->isolate()->factory()->array_iterator_protector()));
1372}
1373
1376 broker_, broker_->isolate()->factory()->array_species_protector()));
1377}
1378
1380 return DependOnProtector(
1381 MakeRef(broker_, broker_->isolate()->factory()->no_elements_protector()));
1382}
1383
1386 broker_, broker_->isolate()->factory()->promise_hook_protector()));
1387}
1388
1391 broker_, broker_->isolate()->factory()->promise_species_protector()));
1392}
1393
1396 broker_, broker_->isolate()->factory()->promise_then_protector()));
1397}
1398
1401 broker_,
1402 broker_->isolate()->factory()->string_wrapper_to_primitive_protector()));
1403}
1404
1407 broker_, broker_->isolate()->factory()->typed_array_length_protector()));
1408}
1409
1412 site.PointsToLiteral()
1413 ? site.boilerplate(broker_).value().map(broker_).elements_kind()
1414 : site.GetElementsKind();
1416 RecordDependency(zone_->New<ElementsKindDependency>(site, kind));
1417 }
1418}
1419
1421 int offset,
1422 ObjectRef value) {
1424 zone_->New<ObjectSlotValueDependency>(object, offset, value));
1425}
1426
1428 uint32_t index,
1429 ObjectRef element) {
1431 zone_->New<OwnConstantElementDependency>(holder, index, element));
1432}
1433
1435 JSObjectRef holder, MapRef map, FieldIndex index, ObjectRef value) {
1436 RecordDependency(zone_->New<OwnConstantDataPropertyDependency>(
1437 broker_, holder, map, index, value));
1438}
1439
1441 JSObjectRef holder, MapRef map, FieldIndex index, Float64 value) {
1442 RecordDependency(zone_->New<OwnConstantDoublePropertyDependency>(
1443 broker_, holder, map, index, value));
1444}
1445
1447 JSObjectRef holder, InternalIndex index, ObjectRef value) {
1448 RecordDependency(zone_->New<OwnConstantDictionaryPropertyDependency>(
1449 broker_, holder, index, value));
1450}
1451
1454 DCHECK(v8_flags.trace_compilation_dependencies);
1455 DCHECK(!d->IsValid(broker));
1456 PrintF("Compilation aborted due to invalid dependency: %s\n", d->ToString());
1457}
1458
1460 if (!PrepareInstall()) return false;
1461
1462 {
1463 PendingDependencies pending_deps(zone_);
1464 DisallowCodeDependencyChange no_dependency_change;
1465 for (const CompilationDependency* dep : dependencies_) {
1466 // Check each dependency's validity again right before installing it,
1467 // because the first iteration above might have invalidated some
1468 // dependencies. For example, PrototypePropertyDependency::PrepareInstall
1469 // can call EnsureHasInitialMap, which can invalidate a
1470 // StableMapDependency on the prototype object's map.
1471 if (!dep->IsValid(broker_)) {
1472 if (v8_flags.trace_compilation_dependencies) {
1474 }
1475 dependencies_.clear();
1476 return false;
1477 }
1478 dep->Install(broker_, &pending_deps);
1479 }
1480 pending_deps.InstallAll(broker_->isolate(), code);
1481 }
1482
1483 // It is even possible that a GC during the above installations invalidated
1484 // one of the dependencies. However, this should only affect
1485 //
1486 // 1. pretenure mode dependencies, or
1487 // 2. function consistency dependencies,
1488 //
1489 // which we assert below. It is safe to return successfully in these cases,
1490 // because
1491 //
1492 // 1. once the code gets executed it will do a stack check that triggers its
1493 // deoptimization.
1494 // 2. since the function state was deemed consistent above, that means the
1495 // compilation saw a self-consistent state of the jsfunction.
1496 if (v8_flags.stress_gc_during_compilation) {
1499 }
1500#ifdef DEBUG
1501 for (auto dep : dependencies_) {
1502 CHECK_IMPLIES(!dep->IsValid(broker_),
1503 dep->IsPretenureMode() || dep->IsConsistentJSFunctionView());
1504 }
1505#endif
1506
1507 dependencies_.clear();
1508 return true;
1509}
1510
1512 if (V8_UNLIKELY(v8_flags.predictable)) {
1514 }
1515
1516 for (auto dep : dependencies_) {
1517 if (!dep->IsValid(broker_)) {
1518 if (v8_flags.trace_compilation_dependencies) {
1520 }
1521 dependencies_.clear();
1522 return false;
1523 }
1524 dep->PrepareInstall(broker_);
1525 }
1526 return true;
1527}
1528
1530 CHECK(v8_flags.predictable);
1531
1532 std::vector<const CompilationDependency*> deps(dependencies_.begin(),
1533 dependencies_.end());
1534 std::sort(deps.begin(), deps.end());
1535
1536 for (auto dep : deps) {
1537 if (!dep->IsValid(broker_)) {
1538 if (v8_flags.trace_compilation_dependencies) {
1540 }
1541 dependencies_.clear();
1542 return false;
1543 }
1544 dep->PrepareInstall(broker_);
1545 }
1546 return true;
1547}
1548
1549#define V(Name) \
1550 const Name##Dependency* CompilationDependency::As##Name() const { \
1551 DCHECK(Is##Name()); \
1552 return static_cast<const Name##Dependency*>(this); \
1553 }
1555#undef V
1556
1558 ZoneVector<MapRef> const& receiver_maps, WhereToStart start,
1559 OptionalJSObjectRef last_prototype) {
1560 for (MapRef receiver_map : receiver_maps) {
1561 DependOnStablePrototypeChain(receiver_map, start, last_prototype);
1562 }
1563}
1564
1566 MapRef receiver_map, WhereToStart start,
1567 OptionalJSObjectRef last_prototype) {
1568 if (receiver_map.IsPrimitiveMap()) {
1569 // Perform the implicit ToObject for primitives here.
1570 // Implemented according to ES6 section 7.3.2 GetV (V, P).
1571 // Note: Keep sync'd with AccessInfoFactory::ComputePropertyAccessInfo.
1572 OptionalJSFunctionRef constructor =
1574 receiver_map);
1575 receiver_map = constructor.value().initial_map(broker_);
1576 }
1577 if (start == kStartAtReceiver) DependOnStableMap(receiver_map);
1578
1579 MapRef map = receiver_map;
1580 while (true) {
1581 HeapObjectRef proto = map.prototype(broker_);
1582 if (!proto.IsJSObject()) {
1584 break;
1585 }
1586 map = proto.map(broker_);
1587 DependOnStableMap(map);
1588 if (last_prototype.has_value() && proto.equals(*last_prototype)) break;
1589 }
1590}
1591
1593 AllocationSiteRef current = site;
1594 while (true) {
1595 DependOnElementsKind(current);
1596 if (!current.nested_site(broker_).IsAllocationSite()) break;
1597 current = current.nested_site(broker_).AsAllocationSite();
1598 }
1599 CHECK_EQ(current.nested_site(broker_).AsSmi(), 0);
1600}
1601
1603 JSFunctionRef function) {
1604 RecordDependency(zone_->New<ConsistentJSFunctionViewDependency>(function));
1605}
1606
1608 if (map.construction_counter() == 0) return;
1609 RecordDependency(zone_->New<NoSlackTrackingChangeDependency>(map));
1610}
1611
1613 int instance_size)
1614 : instance_size_(instance_size),
1615 inobject_property_count_(
1616 (instance_size >> kTaggedSizeLog2) -
1617 initial_map.GetInObjectPropertiesStartInWords()) {}
1618
1621 JSFunctionRef function) {
1623 int instance_size = function.InitialMapInstanceSizeWithMinSlack(broker_);
1624 // Currently, we always install the prediction dependency. If this turns out
1625 // to be too expensive, we can only install the dependency if slack
1626 // tracking is active.
1627 RecordDependency(zone_->New<InitialMapInstanceSizePredictionDependency>(
1628 function, instance_size));
1629 CHECK_LE(instance_size, function.initial_map(broker_).instance_size());
1630 return SlackTrackingPrediction(initial_map, instance_size);
1631}
1632
1635 MapRef target_map) const {
1636 if (target_map.CanBeDeprecated()) {
1637 return zone_->New<TransitionDependency>(target_map);
1638 } else {
1639 DCHECK(!target_map.is_deprecated());
1640 return nullptr;
1641 }
1642}
1643
1646 MapRef map, MapRef owner, InternalIndex descriptor,
1647 Representation representation) const {
1648 return zone_->New<FieldRepresentationDependency>(map, owner, descriptor,
1649 representation);
1650}
1651
1654 MapRef map, MapRef owner, InternalIndex descriptor, ObjectRef type) const {
1655 return zone_->New<FieldTypeDependency>(map, owner, descriptor, type);
1656}
1657
1658#ifdef DEBUG
1659// static
1660bool CompilationDependencies::IsFieldRepresentationDependencyOnMap(
1661 const CompilationDependency* dep, const Handle<Map>& receiver_map) {
1662 return dep->IsFieldRepresentation() &&
1663 dep->AsFieldRepresentation()->DependsOn(receiver_map);
1664}
1665#endif // DEBUG
1666
1667#undef DEPENDENCY_LIST
1668
1669} // namespace compiler
1670} // namespace internal
1671} // namespace v8
Builtins::Kind kind
Definition builtins.cc:40
#define SLOW_DCHECK(condition)
Definition checks.h:21
static bool ShouldTrack(ElementsKind boilerplate_elements_kind)
static V8_INLINE bool InReadOnlySpace(Tagged< HeapObject > object)
V8_EXPORT_PRIVATE void PreciseCollectAllGarbage(GCFlags gc_flags, GarbageCollectionReason gc_reason, const GCCallbackFlags gc_callback_flags=kNoGCCallbackFlags)
Definition heap.cc:1411
bool is_profiling() const
Definition isolate.h:1476
v8::internal::Factory * factory()
Definition isolate.h:1527
bool CanHaveFastTransitionableElementsKind() const
Definition map-inl.h:169
static const int kProtectorValid
Definition protectors.h:15
T * New(Args &&... args)
Definition zone.h:114
PropertyConstness DependOnFieldConstness(MapRef map, MapRef owner, InternalIndex descriptor)
CompilationDependency const * FieldConstnessDependencyOffTheRecord(MapRef map, MapRef owner, InternalIndex descriptor)
void DependOnOwnConstantDataProperty(JSObjectRef holder, MapRef map, FieldIndex index, ObjectRef value)
CompilationDependency const * FieldRepresentationDependencyOffTheRecord(MapRef map, MapRef owner, InternalIndex descriptor, Representation representation) const
void DependOnOwnConstantDictionaryProperty(JSObjectRef holder, InternalIndex index, ObjectRef value)
void DependOnOwnConstantDoubleProperty(JSObjectRef holder, MapRef map, FieldIndex index, Float64 value)
void DependOnConstantInDictionaryPrototypeChain(MapRef receiver_map, NameRef property_name, ObjectRef constant, PropertyKind kind)
HeapObjectRef DependOnPrototypeProperty(JSFunctionRef function)
SlackTrackingPrediction DependOnInitialMapInstanceSizePrediction(JSFunctionRef function)
CompilationDependency const * TransitionDependencyOffTheRecord(MapRef target_map) const
V8_WARN_UNUSED_RESULT bool Commit(Handle< Code > code)
void DependOnOwnConstantElement(JSObjectRef holder, uint32_t index, ObjectRef element)
void DependOnObjectSlotValue(HeapObjectRef object, int offset, ObjectRef value)
void DependOnStablePrototypeChain(MapRef receiver_maps, WhereToStart start, OptionalJSObjectRef last_prototype=OptionalJSObjectRef())
CompilationDependencies(JSHeapBroker *broker, Zone *zone)
void DependOnStablePrototypeChains(ZoneVector< MapRef > const &receiver_maps, WhereToStart start, OptionalJSObjectRef last_prototype=OptionalJSObjectRef())
void RecordDependency(CompilationDependency const *dependency)
bool DependOnScriptContextSlotProperty(ContextRef script_context, size_t index, ContextSidePropertyCell::Property property, JSHeapBroker *broker)
CompilationDependency const * FieldTypeDependencyOffTheRecord(MapRef map, MapRef owner, InternalIndex descriptor, ObjectRef type) const
AllocationType DependOnPretenureMode(AllocationSiteRef site)
virtual void PrepareInstall(JSHeapBroker *broker) const
virtual bool Equals(const CompilationDependency *that) const =0
virtual bool IsValid(JSHeapBroker *broker) const =0
virtual void Install(JSHeapBroker *broker, PendingDependencies *deps) const =0
IndirectHandle< Context > object() const
V8_EXPORT_PRIVATE MapRef map(JSHeapBroker *broker) const
NativeContextRef target_native_context() const
void set_dependencies(CompilationDependencies *dependencies)
OddballType oddball_type(JSHeapBroker *broker) const
OptionalJSFunctionRef GetConstructorFunction(JSHeapBroker *broker, MapRef map) const
IndirectHandle< ScopeInfo > object() const
SlackTrackingPrediction(MapRef initial_map, int instance_size)
Zone * zone_
Register const object_
Operand const offset_
Register const value_
Register const index_
#define V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL
Definition globals.h:242
#define V8_DICT_PROPERTY_CONST_TRACKING_BOOL
Definition globals.h:249
const JSFunctionRef function_
const int instance_size_
const InternalIndex descriptor_
const ObjectRef element_
const MapRef map_
const ScopeInfoRef scope_info_
base::TemplateHashMapImpl< Handle< HeapObject >, DependentCode::DependencyGroups, HandleValueEqual, ZoneAllocationPolicy > deps_
const ContextRef script_context_
const ObjectRef type_
const MapRef initial_map_
const bool read_only_
#define DEPENDENCY_LIST(V)
const MapRef owner_
const MapRef receiver_map_
const NameRef property_name_
const PropertyKind kind_
const PropertyCellRef cell_
JSObjectRef const holder_
ContextSidePropertyCell::Property property_
JSHeapBroker *const broker_
const ObjectRef constant_
const AllocationSiteRef site_
const AllocationType allocation_
const ObjectRef prototype_
const Representation representation_
int start
JSHeapBroker * broker
int32_t offset
std::map< const std::string, const std::string > map
#define TRACE_BROKER_MISSING(broker, x)
ZoneVector< RpoNumber > & result
ZoneVector< Entry > entries
V8_INLINE size_t hash_combine(size_t seed, size_t hash)
Definition hashing.h:77
FloatWithBits< 64 > Float64
Definition index.h:234
V8_INLINE void TraceInvalidCompilationDependency(compiler::JSHeapBroker *broker, const CompilationDependency *d)
ref_traits< T >::ref_type MakeRef(JSHeapBroker *broker, Tagged< T > object)
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
void PrintF(const char *format,...)
Definition utils.cc:39
PerThreadAssertScopeDebugOnly< true, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > AllowGarbageCollection
V8_INLINE PtrComprCageBase GetPtrComprCageBase()
constexpr int kTaggedSizeLog2
Definition globals.h:543
V8_EXPORT_PRIVATE FlagValues v8_flags
kInstanceDescriptorsOffset kTransitionsOrPrototypeInfoOffset prototype
Definition map-inl.h:69
@ kNoGCCallbackFlags
#define CHECK_IMPLIES(lhs, rhs)
#define CHECK(condition)
Definition logging.h:124
#define CHECK_LE(lhs, rhs)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
bool operator()(const CompilationDependency *lhs, const CompilationDependency *rhs) const
#define V8_INLINE
Definition v8config.h:500
#define V8_UNLIKELY(condition)
Definition v8config.h:660
std::unique_ptr< ValueMirror > value
wasm::ValueType type