Line data Source code
1 : // Copyright 2015 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/compiler/compilation-dependencies.h"
6 :
7 : #include "src/handles-inl.h"
8 : #include "src/objects-inl.h"
9 : #include "src/objects/allocation-site-inl.h"
10 : #include "src/zone/zone-handle-set.h"
11 :
12 : namespace v8 {
13 : namespace internal {
14 : namespace compiler {
15 :
16 483336 : CompilationDependencies::CompilationDependencies(JSHeapBroker* broker,
17 : Zone* zone)
18 966672 : : zone_(zone), broker_(broker), dependencies_(zone) {}
19 :
20 599195 : class CompilationDependencies::Dependency : public ZoneObject {
21 : public:
22 : virtual bool IsValid() const = 0;
23 588669 : virtual void PrepareInstall() {}
24 : virtual void Install(const MaybeObjectHandle& code) = 0;
25 :
26 : #ifdef DEBUG
27 : virtual bool IsPretenureModeDependency() const { return false; }
28 : #endif
29 : };
30 :
31 : class InitialMapDependency final : public CompilationDependencies::Dependency {
32 : public:
33 : // TODO(neis): Once the concurrent compiler frontend is always-on, we no
34 : // longer need to explicitly store the initial map.
35 : InitialMapDependency(const JSFunctionRef& function, const MapRef& initial_map)
36 5415 : : function_(function), initial_map_(initial_map) {
37 : DCHECK(function_.has_initial_map());
38 : DCHECK(function_.initial_map().equals(initial_map_));
39 : }
40 :
41 10770 : bool IsValid() const override {
42 10770 : Handle<JSFunction> function = function_.object();
43 21540 : return function->has_initial_map() &&
44 21540 : function->initial_map() == *initial_map_.object();
45 : }
46 :
47 5384 : void Install(const MaybeObjectHandle& code) override {
48 : SLOW_DCHECK(IsValid());
49 16152 : DependentCode::InstallDependency(function_.isolate(), code,
50 : initial_map_.object(),
51 5384 : DependentCode::kInitialMapChangedGroup);
52 5384 : }
53 :
54 : private:
55 : JSFunctionRef function_;
56 : MapRef initial_map_;
57 : };
58 :
59 : class PrototypePropertyDependency final
60 : : public CompilationDependencies::Dependency {
61 : public:
62 : // TODO(neis): Once the concurrent compiler frontend is always-on, we no
63 : // longer need to explicitly store the prototype.
64 : PrototypePropertyDependency(const JSFunctionRef& function,
65 : const ObjectRef& prototype)
66 1364 : : function_(function), prototype_(prototype) {
67 : DCHECK(function_.has_prototype());
68 : DCHECK(!function_.PrototypeRequiresRuntimeLookup());
69 : DCHECK(function_.prototype().equals(prototype_));
70 : }
71 :
72 2704 : bool IsValid() const override {
73 2704 : Handle<JSFunction> function = function_.object();
74 10816 : return function->has_prototype_slot() && function->has_prototype() &&
75 8112 : !function->PrototypeRequiresRuntimeLookup() &&
76 8112 : function->prototype() == *prototype_.object();
77 : }
78 :
79 1359 : void PrepareInstall() override {
80 : SLOW_DCHECK(IsValid());
81 1359 : Handle<JSFunction> function = function_.object();
82 1359 : if (!function->has_initial_map()) JSFunction::EnsureHasInitialMap(function);
83 1359 : }
84 :
85 1345 : void Install(const MaybeObjectHandle& code) override {
86 : SLOW_DCHECK(IsValid());
87 1345 : Handle<JSFunction> function = function_.object();
88 : DCHECK(function->has_initial_map());
89 1345 : Handle<Map> initial_map(function->initial_map(), function_.isolate());
90 2690 : DependentCode::InstallDependency(function_.isolate(), code, initial_map,
91 1345 : DependentCode::kInitialMapChangedGroup);
92 1345 : }
93 :
94 : private:
95 : JSFunctionRef function_;
96 : ObjectRef prototype_;
97 : };
98 :
99 : class StableMapDependency final : public CompilationDependencies::Dependency {
100 : public:
101 163601 : explicit StableMapDependency(const MapRef& map) : map_(map) {
102 : DCHECK(map_.is_stable());
103 : }
104 :
105 650754 : bool IsValid() const override { return map_.object()->is_stable(); }
106 :
107 162653 : void Install(const MaybeObjectHandle& code) override {
108 : SLOW_DCHECK(IsValid());
109 487959 : DependentCode::InstallDependency(map_.isolate(), code, map_.object(),
110 162653 : DependentCode::kPrototypeCheckGroup);
111 162653 : }
112 :
113 : private:
114 : MapRef map_;
115 : };
116 :
117 : class TransitionDependency final : public CompilationDependencies::Dependency {
118 : public:
119 19648 : explicit TransitionDependency(const MapRef& map) : map_(map) {
120 : DCHECK(!map_.is_deprecated());
121 : }
122 :
123 78488 : bool IsValid() const override { return !map_.object()->is_deprecated(); }
124 :
125 19620 : void Install(const MaybeObjectHandle& code) override {
126 : SLOW_DCHECK(IsValid());
127 58860 : DependentCode::InstallDependency(map_.isolate(), code, map_.object(),
128 19620 : DependentCode::kTransitionGroup);
129 19620 : }
130 :
131 : private:
132 : MapRef map_;
133 : };
134 :
135 : class PretenureModeDependency final
136 : : public CompilationDependencies::Dependency {
137 : public:
138 : // TODO(neis): Once the concurrent compiler frontend is always-on, we no
139 : // longer need to explicitly store the mode.
140 : PretenureModeDependency(const AllocationSiteRef& site,
141 : AllocationType allocation)
142 7575 : : site_(site), allocation_(allocation) {
143 : DCHECK_EQ(allocation, site_.GetAllocationType());
144 : }
145 :
146 14886 : bool IsValid() const override {
147 29772 : return allocation_ == site_.object()->GetAllocationType();
148 : }
149 :
150 7434 : void Install(const MaybeObjectHandle& code) override {
151 : SLOW_DCHECK(IsValid());
152 22302 : DependentCode::InstallDependency(
153 : site_.isolate(), code, site_.object(),
154 7434 : DependentCode::kAllocationSiteTenuringChangedGroup);
155 7434 : }
156 :
157 : #ifdef DEBUG
158 : bool IsPretenureModeDependency() const override { return true; }
159 : #endif
160 :
161 : private:
162 : AllocationSiteRef site_;
163 : AllocationType allocation_;
164 : };
165 :
166 : class FieldRepresentationDependency final
167 : : public CompilationDependencies::Dependency {
168 : public:
169 : // TODO(neis): Once the concurrent compiler frontend is always-on, we no
170 : // longer need to explicitly store the representation.
171 : FieldRepresentationDependency(const MapRef& owner, int descriptor,
172 : Representation representation)
173 : : owner_(owner),
174 : descriptor_(descriptor),
175 112037 : representation_(representation) {
176 : DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
177 : DCHECK(representation_.Equals(
178 : owner_.GetPropertyDetails(descriptor_).representation()));
179 : }
180 :
181 222306 : bool IsValid() const override {
182 : DisallowHeapAllocation no_heap_allocation;
183 222306 : Handle<Map> owner = owner_.object();
184 444612 : return representation_.Equals(owner->instance_descriptors()
185 666918 : ->GetDetails(descriptor_)
186 222306 : .representation());
187 : }
188 :
189 111140 : void Install(const MaybeObjectHandle& code) override {
190 : SLOW_DCHECK(IsValid());
191 333420 : DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
192 111140 : DependentCode::kFieldOwnerGroup);
193 111140 : }
194 :
195 : private:
196 : MapRef owner_;
197 : int descriptor_;
198 : Representation representation_;
199 : };
200 :
201 : class FieldTypeDependency final : public CompilationDependencies::Dependency {
202 : public:
203 : // TODO(neis): Once the concurrent compiler frontend is always-on, we no
204 : // longer need to explicitly store the type.
205 : FieldTypeDependency(const MapRef& owner, int descriptor,
206 : const ObjectRef& type)
207 4094 : : owner_(owner), descriptor_(descriptor), type_(type) {
208 : DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
209 : DCHECK(type_.equals(owner_.GetFieldType(descriptor_)));
210 : }
211 :
212 7998 : bool IsValid() const override {
213 : DisallowHeapAllocation no_heap_allocation;
214 7998 : Handle<Map> owner = owner_.object();
215 7998 : Handle<Object> type = type_.object();
216 23994 : return *type == owner->instance_descriptors()->GetFieldType(descriptor_);
217 : }
218 :
219 3999 : void Install(const MaybeObjectHandle& code) override {
220 : SLOW_DCHECK(IsValid());
221 11997 : DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
222 3999 : DependentCode::kFieldOwnerGroup);
223 3999 : }
224 :
225 : private:
226 : MapRef owner_;
227 : int descriptor_;
228 : ObjectRef type_;
229 : };
230 :
231 : class FieldConstnessDependency final
232 : : public CompilationDependencies::Dependency {
233 : public:
234 : FieldConstnessDependency(const MapRef& owner, int descriptor)
235 71285 : : owner_(owner), descriptor_(descriptor) {
236 : DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
237 : DCHECK_EQ(PropertyConstness::kConst,
238 : owner_.GetPropertyDetails(descriptor_).constness());
239 : }
240 :
241 141920 : bool IsValid() const override {
242 : DisallowHeapAllocation no_heap_allocation;
243 141920 : Handle<Map> owner = owner_.object();
244 : return PropertyConstness::kConst ==
245 425760 : owner->instance_descriptors()->GetDetails(descriptor_).constness();
246 : }
247 :
248 70951 : void Install(const MaybeObjectHandle& code) override {
249 : SLOW_DCHECK(IsValid());
250 212853 : DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
251 70951 : DependentCode::kFieldOwnerGroup);
252 70951 : }
253 :
254 : private:
255 : MapRef owner_;
256 : int descriptor_;
257 : };
258 :
259 : class GlobalPropertyDependency final
260 : : public CompilationDependencies::Dependency {
261 : public:
262 : // TODO(neis): Once the concurrent compiler frontend is always-on, we no
263 : // longer need to explicitly store the type and the read_only flag.
264 : GlobalPropertyDependency(const PropertyCellRef& cell, PropertyCellType type,
265 : bool read_only)
266 185718 : : cell_(cell), type_(type), read_only_(read_only) {
267 : DCHECK_EQ(type_, cell_.property_details().cell_type());
268 : DCHECK_EQ(read_only_, cell_.property_details().IsReadOnly());
269 : }
270 :
271 369020 : bool IsValid() const override {
272 369020 : Handle<PropertyCell> cell = cell_.object();
273 : // The dependency is never valid if the cell is 'invalidated'. This is
274 : // marked by setting the value to the hole.
275 738040 : if (cell->value() == *(cell_.isolate()->factory()->the_hole_value())) {
276 : DCHECK(cell->property_details().cell_type() ==
277 : PropertyCellType::kInvalidated ||
278 : cell->property_details().cell_type() ==
279 : PropertyCellType::kUninitialized);
280 : return false;
281 : }
282 1107028 : return type_ == cell->property_details().cell_type() &&
283 369004 : read_only_ == cell->property_details().IsReadOnly();
284 : }
285 :
286 184386 : void Install(const MaybeObjectHandle& code) override {
287 : SLOW_DCHECK(IsValid());
288 553158 : DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(),
289 184386 : DependentCode::kPropertyCellChangedGroup);
290 184386 : }
291 :
292 : private:
293 : PropertyCellRef cell_;
294 : PropertyCellType type_;
295 : bool read_only_;
296 : };
297 :
298 : class ProtectorDependency final : public CompilationDependencies::Dependency {
299 : public:
300 20066 : explicit ProtectorDependency(const PropertyCellRef& cell) : cell_(cell) {
301 : DCHECK_EQ(cell_.value().AsSmi(), Isolate::kProtectorValid);
302 : }
303 :
304 39668 : bool IsValid() const override {
305 39668 : Handle<PropertyCell> cell = cell_.object();
306 39668 : return cell->value() == Smi::FromInt(Isolate::kProtectorValid);
307 : }
308 :
309 19832 : void Install(const MaybeObjectHandle& code) override {
310 : SLOW_DCHECK(IsValid());
311 59496 : DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(),
312 19832 : DependentCode::kPropertyCellChangedGroup);
313 19832 : }
314 :
315 : private:
316 : PropertyCellRef cell_;
317 : };
318 :
319 : class ElementsKindDependency final
320 : : public CompilationDependencies::Dependency {
321 : public:
322 : // TODO(neis): Once the concurrent compiler frontend is always-on, we no
323 : // longer need to explicitly store the elements kind.
324 : ElementsKindDependency(const AllocationSiteRef& site, ElementsKind kind)
325 2977 : : site_(site), kind_(kind) {
326 : DCHECK(AllocationSite::ShouldTrack(kind_));
327 : DCHECK_EQ(kind_, site_.PointsToLiteral()
328 : ? site_.boilerplate().value().GetElementsKind()
329 : : site_.GetElementsKind());
330 : }
331 :
332 5861 : bool IsValid() const override {
333 5861 : Handle<AllocationSite> site = site_.object();
334 : ElementsKind kind = site->PointsToLiteral()
335 : ? site->boilerplate()->GetElementsKind()
336 5861 : : site->GetElementsKind();
337 5861 : return kind_ == kind;
338 : }
339 :
340 2921 : void Install(const MaybeObjectHandle& code) override {
341 : SLOW_DCHECK(IsValid());
342 8763 : DependentCode::InstallDependency(
343 : site_.isolate(), code, site_.object(),
344 2921 : DependentCode::kAllocationSiteTransitionChangedGroup);
345 2921 : }
346 :
347 : private:
348 : AllocationSiteRef site_;
349 : ElementsKind kind_;
350 : };
351 :
352 : class InitialMapInstanceSizePredictionDependency final
353 : : public CompilationDependencies::Dependency {
354 : public:
355 : InitialMapInstanceSizePredictionDependency(const JSFunctionRef& function,
356 : int instance_size)
357 5415 : : function_(function), instance_size_(instance_size) {}
358 :
359 10775 : bool IsValid() const override {
360 : // The dependency is valid if the prediction is the same as the current
361 : // slack tracking result.
362 21550 : if (!function_.object()->has_initial_map()) return false;
363 32310 : int instance_size = function_.object()->ComputeInstanceSizeWithMinSlack(
364 10770 : function_.isolate());
365 10770 : return instance_size == instance_size_;
366 : }
367 :
368 5386 : void PrepareInstall() override {
369 : SLOW_DCHECK(IsValid());
370 10772 : function_.object()->CompleteInobjectSlackTrackingIfActive();
371 5386 : }
372 :
373 5384 : void Install(const MaybeObjectHandle& code) override {
374 : SLOW_DCHECK(IsValid());
375 : DCHECK(!function_.object()
376 : ->initial_map()
377 : ->IsInobjectSlackTrackingInProgress());
378 5384 : }
379 :
380 : private:
381 : JSFunctionRef function_;
382 : int instance_size_;
383 : };
384 :
385 5415 : MapRef CompilationDependencies::DependOnInitialMap(
386 : const JSFunctionRef& function) {
387 5415 : MapRef map = function.initial_map();
388 16245 : dependencies_.push_front(new (zone_) InitialMapDependency(function, map));
389 5415 : return map;
390 : }
391 :
392 1364 : ObjectRef CompilationDependencies::DependOnPrototypeProperty(
393 : const JSFunctionRef& function) {
394 1364 : ObjectRef prototype = function.prototype();
395 2728 : dependencies_.push_front(
396 1364 : new (zone_) PrototypePropertyDependency(function, prototype));
397 1364 : return prototype;
398 : }
399 :
400 165422 : void CompilationDependencies::DependOnStableMap(const MapRef& map) {
401 165422 : if (map.CanTransition()) {
402 490803 : dependencies_.push_front(new (zone_) StableMapDependency(map));
403 : } else {
404 : DCHECK(map.is_stable());
405 : }
406 165422 : }
407 :
408 22031 : void CompilationDependencies::DependOnTransition(const MapRef& target_map) {
409 22031 : if (target_map.CanBeDeprecated()) {
410 58944 : dependencies_.push_front(new (zone_) TransitionDependency(target_map));
411 : } else {
412 : DCHECK(!target_map.is_deprecated());
413 : }
414 22031 : }
415 :
416 7575 : AllocationType CompilationDependencies::DependOnPretenureMode(
417 : const AllocationSiteRef& site) {
418 7575 : AllocationType allocation = site.GetAllocationType();
419 22725 : dependencies_.push_front(new (zone_)
420 : PretenureModeDependency(site, allocation));
421 7575 : return allocation;
422 : }
423 :
424 71285 : PropertyConstness CompilationDependencies::DependOnFieldConstness(
425 : const MapRef& map, int descriptor) {
426 71285 : MapRef owner = map.FindFieldOwner(descriptor);
427 : PropertyConstness constness =
428 142570 : owner.GetPropertyDetails(descriptor).constness();
429 71285 : if (constness == PropertyConstness::kMutable) return constness;
430 :
431 : // If the map can have fast elements transitions, then the field can be only
432 : // considered constant if the map does not transition.
433 142570 : if (Map::CanHaveFastTransitionableElementsKind(map.instance_type())) {
434 : // If the map can already transition away, let us report the field as
435 : // mutable.
436 13726 : if (!map.is_stable()) {
437 : return PropertyConstness::kMutable;
438 : }
439 13726 : DependOnStableMap(map);
440 : }
441 :
442 : DCHECK_EQ(constness, PropertyConstness::kConst);
443 213855 : dependencies_.push_front(new (zone_)
444 : FieldConstnessDependency(owner, descriptor));
445 71285 : return PropertyConstness::kConst;
446 : }
447 :
448 112037 : void CompilationDependencies::DependOnFieldRepresentation(const MapRef& map,
449 : int descriptor) {
450 112037 : MapRef owner = map.FindFieldOwner(descriptor);
451 112037 : PropertyDetails details = owner.GetPropertyDetails(descriptor);
452 : DCHECK(details.representation().Equals(
453 : map.GetPropertyDetails(descriptor).representation()));
454 336111 : dependencies_.push_front(new (zone_) FieldRepresentationDependency(
455 : owner, descriptor, details.representation()));
456 112037 : }
457 :
458 4094 : void CompilationDependencies::DependOnFieldType(const MapRef& map,
459 : int descriptor) {
460 4094 : MapRef owner = map.FindFieldOwner(descriptor);
461 4094 : ObjectRef type = owner.GetFieldType(descriptor);
462 : DCHECK(type.equals(map.GetFieldType(descriptor)));
463 12282 : dependencies_.push_front(new (zone_)
464 : FieldTypeDependency(owner, descriptor, type));
465 4094 : }
466 :
467 185718 : void CompilationDependencies::DependOnGlobalProperty(
468 : const PropertyCellRef& cell) {
469 371436 : PropertyCellType type = cell.property_details().cell_type();
470 371436 : bool read_only = cell.property_details().IsReadOnly();
471 557154 : dependencies_.push_front(new (zone_)
472 : GlobalPropertyDependency(cell, type, read_only));
473 185718 : }
474 :
475 20947 : bool CompilationDependencies::DependOnProtector(const PropertyCellRef& cell) {
476 20947 : if (cell.value().AsSmi() != Isolate::kProtectorValid) return false;
477 60198 : dependencies_.push_front(new (zone_) ProtectorDependency(cell));
478 20066 : return true;
479 : }
480 :
481 8212 : bool CompilationDependencies::DependOnArrayBufferDetachingProtector() {
482 8212 : return DependOnProtector(PropertyCellRef(
483 : broker_,
484 24636 : broker_->isolate()->factory()->array_buffer_detaching_protector()));
485 : }
486 :
487 966 : bool CompilationDependencies::DependOnArrayIteratorProtector() {
488 966 : return DependOnProtector(PropertyCellRef(
489 2898 : broker_, broker_->isolate()->factory()->array_iterator_protector()));
490 : }
491 :
492 807 : bool CompilationDependencies::DependOnArraySpeciesProtector() {
493 807 : return DependOnProtector(PropertyCellRef(
494 2421 : broker_, broker_->isolate()->factory()->array_species_protector()));
495 : }
496 :
497 6567 : bool CompilationDependencies::DependOnNoElementsProtector() {
498 6567 : return DependOnProtector(PropertyCellRef(
499 19701 : broker_, broker_->isolate()->factory()->no_elements_protector()));
500 : }
501 :
502 4021 : bool CompilationDependencies::DependOnPromiseHookProtector() {
503 4021 : return DependOnProtector(PropertyCellRef(
504 12063 : broker_, broker_->isolate()->factory()->promise_hook_protector()));
505 : }
506 :
507 230 : bool CompilationDependencies::DependOnPromiseSpeciesProtector() {
508 230 : return DependOnProtector(PropertyCellRef(
509 690 : broker_, broker_->isolate()->factory()->promise_species_protector()));
510 : }
511 :
512 110 : bool CompilationDependencies::DependOnPromiseThenProtector() {
513 110 : return DependOnProtector(PropertyCellRef(
514 330 : broker_, broker_->isolate()->factory()->promise_then_protector()));
515 : }
516 :
517 7807 : void CompilationDependencies::DependOnElementsKind(
518 : const AllocationSiteRef& site) {
519 : // Do nothing if the object doesn't have any useful element transitions left.
520 7807 : ElementsKind kind = site.PointsToLiteral()
521 20399 : ? site.boilerplate().value().GetElementsKind()
522 15614 : : site.GetElementsKind();
523 7807 : if (AllocationSite::ShouldTrack(kind)) {
524 8931 : dependencies_.push_front(new (zone_) ElementsKindDependency(site, kind));
525 : }
526 7807 : }
527 :
528 0 : bool CompilationDependencies::AreValid() const {
529 0 : for (auto dep : dependencies_) {
530 0 : if (!dep->IsValid()) return false;
531 : }
532 : return true;
533 : }
534 :
535 463997 : bool CompilationDependencies::Commit(Handle<Code> code) {
536 1059411 : for (auto dep : dependencies_) {
537 595466 : if (!dep->IsValid()) {
538 : dependencies_.clear();
539 : return false;
540 : }
541 595414 : dep->PrepareInstall();
542 : }
543 :
544 : DisallowCodeDependencyChange no_dependency_change;
545 1058994 : for (auto dep : dependencies_) {
546 : // Check each dependency's validity again right before installing it,
547 : // because the first iteration above might have invalidated some
548 : // dependencies. For example, PrototypePropertyDependency::PrepareInstall
549 : // can call EnsureHasInitialMap, which can invalidate a StableMapDependency
550 : // on the prototype object's map.
551 595063 : if (!dep->IsValid()) {
552 : dependencies_.clear();
553 : return false;
554 : }
555 595049 : dep->Install(MaybeObjectHandle::Weak(code));
556 : }
557 :
558 : // It is even possible that a GC during the above installations invalidated
559 : // one of the dependencies. However, this should only affect pretenure mode
560 : // dependencies, which we assert below. It is safe to return successfully in
561 : // these cases, because once the code gets executed it will do a stack check
562 : // that triggers its deoptimization.
563 463931 : if (FLAG_stress_gc_during_compilation) {
564 4 : broker_->isolate()->heap()->PreciseCollectAllGarbage(
565 : Heap::kNoGCFlags, GarbageCollectionReason::kTesting,
566 4 : kGCCallbackFlagForced);
567 : }
568 : #ifdef DEBUG
569 : for (auto dep : dependencies_) {
570 : CHECK_IMPLIES(!dep->IsValid(), dep->IsPretenureModeDependency());
571 : }
572 : #endif
573 :
574 : dependencies_.clear();
575 463931 : return true;
576 : }
577 :
578 : namespace {
579 : // This function expects to never see a JSProxy.
580 55357 : void DependOnStablePrototypeChain(CompilationDependencies* deps, MapRef map,
581 : base::Optional<JSObjectRef> last_prototype) {
582 30249 : while (true) {
583 85606 : map.SerializePrototype();
584 85606 : HeapObjectRef proto = map.prototype();
585 85606 : if (!proto.IsJSObject()) {
586 50 : CHECK_EQ(proto.map().oddball_type(), OddballType::kNull);
587 55357 : break;
588 : }
589 85556 : map = proto.map();
590 85556 : deps->DependOnStableMap(map);
591 85556 : if (last_prototype.has_value() && proto.equals(*last_prototype)) break;
592 : }
593 55357 : }
594 : } // namespace
595 :
596 : template <class MapContainer>
597 53087 : void CompilationDependencies::DependOnStablePrototypeChains(
598 : MapContainer const& receiver_maps, WhereToStart start,
599 : base::Optional<JSObjectRef> last_prototype) {
600 : // Determine actual holder and perform prototype chain checks.
601 108444 : for (auto map : receiver_maps) {
602 55357 : MapRef receiver_map(broker_, map);
603 55357 : if (receiver_map.IsPrimitiveMap()) {
604 : // Perform the implicit ToObject for primitives here.
605 : // Implemented according to ES6 section 7.3.2 GetV (V, P).
606 : base::Optional<JSFunctionRef> constructor =
607 8130 : broker_->native_context().GetConstructorFunction(receiver_map);
608 8130 : if (constructor.has_value()) receiver_map = constructor->initial_map();
609 : }
610 55357 : if (start == kStartAtReceiver) DependOnStableMap(receiver_map);
611 55357 : DependOnStablePrototypeChain(this, receiver_map, last_prototype);
612 : }
613 53087 : }
614 : template void CompilationDependencies::DependOnStablePrototypeChains(
615 : MapHandles const& receiver_maps, WhereToStart start,
616 : base::Optional<JSObjectRef> last_prototype);
617 : template void CompilationDependencies::DependOnStablePrototypeChains(
618 : ZoneHandleSet<Map> const& receiver_maps, WhereToStart start,
619 : base::Optional<JSObjectRef> last_prototype);
620 :
621 6064 : void CompilationDependencies::DependOnElementsKinds(
622 : const AllocationSiteRef& site) {
623 6064 : AllocationSiteRef current = site;
624 232 : while (true) {
625 6296 : DependOnElementsKind(current);
626 6296 : if (!current.nested_site().IsAllocationSite()) break;
627 232 : current = current.nested_site().AsAllocationSite();
628 : }
629 6064 : CHECK_EQ(current.nested_site().AsSmi(), 0);
630 6064 : }
631 :
632 980 : SlackTrackingPrediction::SlackTrackingPrediction(MapRef initial_map,
633 : int instance_size)
634 : : instance_size_(instance_size),
635 : inobject_property_count_(
636 12790 : (instance_size >> kTaggedSizeLog2) -
637 8355 : initial_map.GetInObjectPropertiesStartInWords()) {}
638 :
639 : SlackTrackingPrediction
640 5415 : CompilationDependencies::DependOnInitialMapInstanceSizePrediction(
641 : const JSFunctionRef& function) {
642 5415 : MapRef initial_map = DependOnInitialMap(function);
643 5415 : int instance_size = function.InitialMapInstanceSizeWithMinSlack();
644 : // Currently, we always install the prediction dependency. If this turns out
645 : // to be too expensive, we can only install the dependency if slack
646 : // tracking is active.
647 10830 : dependencies_.push_front(
648 5415 : new (zone_)
649 : InitialMapInstanceSizePredictionDependency(function, instance_size));
650 : DCHECK_LE(instance_size, function.initial_map().instance_size());
651 5415 : return SlackTrackingPrediction(initial_map, instance_size);
652 : }
653 :
654 : } // namespace compiler
655 : } // namespace internal
656 122004 : } // namespace v8
|