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 483560 : CompilationDependencies::CompilationDependencies(JSHeapBroker* broker,
17 : Zone* zone)
18 967120 : : zone_(zone), broker_(broker), dependencies_(zone) {}
19 :
20 595240 : class CompilationDependencies::Dependency : public ZoneObject {
21 : public:
22 : virtual bool IsValid() const = 0;
23 585689 : 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 5446 : : function_(function), initial_map_(initial_map) {
37 : DCHECK(function_.has_initial_map());
38 : DCHECK(function_.initial_map().equals(initial_map_));
39 : }
40 :
41 10841 : bool IsValid() const override {
42 10841 : Handle<JSFunction> function = function_.object();
43 21682 : return function->has_initial_map() &&
44 21682 : function->initial_map() == *initial_map_.object();
45 : }
46 :
47 5420 : void Install(const MaybeObjectHandle& code) override {
48 : SLOW_DCHECK(IsValid());
49 16260 : DependentCode::InstallDependency(function_.isolate(), code,
50 : initial_map_.object(),
51 5420 : DependentCode::kInitialMapChangedGroup);
52 5420 : }
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 1348 : : function_(function), prototype_(prototype) {
67 : DCHECK(function_.has_prototype());
68 : DCHECK(!function_.PrototypeRequiresRuntimeLookup());
69 : DCHECK(function_.prototype().equals(prototype_));
70 : }
71 :
72 2672 : bool IsValid() const override {
73 2672 : Handle<JSFunction> function = function_.object();
74 10688 : return function->has_prototype_slot() && function->has_prototype() &&
75 8016 : !function->PrototypeRequiresRuntimeLookup() &&
76 8016 : function->prototype() == *prototype_.object();
77 : }
78 :
79 1343 : void PrepareInstall() override {
80 : SLOW_DCHECK(IsValid());
81 1343 : Handle<JSFunction> function = function_.object();
82 1343 : if (!function->has_initial_map()) JSFunction::EnsureHasInitialMap(function);
83 1343 : }
84 :
85 1329 : void Install(const MaybeObjectHandle& code) override {
86 : SLOW_DCHECK(IsValid());
87 1329 : Handle<JSFunction> function = function_.object();
88 : DCHECK(function->has_initial_map());
89 1329 : Handle<Map> initial_map(function->initial_map(), function_.isolate());
90 2658 : DependentCode::InstallDependency(function_.isolate(), code, initial_map,
91 1329 : DependentCode::kInitialMapChangedGroup);
92 1329 : }
93 :
94 : private:
95 : JSFunctionRef function_;
96 : ObjectRef prototype_;
97 : };
98 :
99 : class StableMapDependency final : public CompilationDependencies::Dependency {
100 : public:
101 162640 : explicit StableMapDependency(const MapRef& map) : map_(map) {
102 : DCHECK(map_.is_stable());
103 : }
104 :
105 647944 : bool IsValid() const override { return map_.object()->is_stable(); }
106 :
107 161961 : void Install(const MaybeObjectHandle& code) override {
108 : SLOW_DCHECK(IsValid());
109 485883 : DependentCode::InstallDependency(map_.isolate(), code, map_.object(),
110 161961 : DependentCode::kPrototypeCheckGroup);
111 161961 : }
112 :
113 : private:
114 : MapRef map_;
115 : };
116 :
117 : class TransitionDependency final : public CompilationDependencies::Dependency {
118 : public:
119 19644 : explicit TransitionDependency(const MapRef& map) : map_(map) {
120 : DCHECK(!map_.is_deprecated());
121 : }
122 :
123 78444 : bool IsValid() const override { return !map_.object()->is_deprecated(); }
124 :
125 19609 : void Install(const MaybeObjectHandle& code) override {
126 : SLOW_DCHECK(IsValid());
127 58827 : DependentCode::InstallDependency(map_.isolate(), code, map_.object(),
128 19609 : DependentCode::kTransitionGroup);
129 19609 : }
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 7521 : : site_(site), allocation_(allocation) {
143 : DCHECK_EQ(allocation, site_.GetAllocationType());
144 : }
145 :
146 14818 : bool IsValid() const override {
147 29636 : return allocation_ == site_.object()->GetAllocationType();
148 : }
149 :
150 7403 : void Install(const MaybeObjectHandle& code) override {
151 : SLOW_DCHECK(IsValid());
152 22209 : DependentCode::InstallDependency(
153 : site_.isolate(), code, site_.object(),
154 7403 : DependentCode::kAllocationSiteTenuringChangedGroup);
155 7403 : }
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 111007 : representation_(representation) {
176 : DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
177 : DCHECK(representation_.Equals(
178 : owner_.GetPropertyDetails(descriptor_).representation()));
179 : }
180 :
181 220745 : bool IsValid() const override {
182 : DisallowHeapAllocation no_heap_allocation;
183 220745 : Handle<Map> owner = owner_.object();
184 441490 : return representation_.Equals(owner->instance_descriptors()
185 662235 : ->GetDetails(descriptor_)
186 220745 : .representation());
187 : }
188 :
189 110367 : void Install(const MaybeObjectHandle& code) override {
190 : SLOW_DCHECK(IsValid());
191 331101 : DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
192 110367 : DependentCode::kFieldOwnerGroup);
193 110367 : }
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 3843 : : owner_(owner), descriptor_(descriptor), type_(type) {
208 : DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
209 : DCHECK(type_.equals(owner_.GetFieldType(descriptor_)));
210 : }
211 :
212 7568 : bool IsValid() const override {
213 : DisallowHeapAllocation no_heap_allocation;
214 7568 : Handle<Map> owner = owner_.object();
215 7568 : Handle<Object> type = type_.object();
216 22704 : return *type == owner->instance_descriptors()->GetFieldType(descriptor_);
217 : }
218 :
219 3784 : void Install(const MaybeObjectHandle& code) override {
220 : SLOW_DCHECK(IsValid());
221 11352 : DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
222 3784 : DependentCode::kFieldOwnerGroup);
223 3784 : }
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 70924 : : owner_(owner), descriptor_(descriptor) {
236 : DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
237 : DCHECK_EQ(PropertyConstness::kConst,
238 : owner_.GetPropertyDetails(descriptor_).constness());
239 : }
240 :
241 141350 : bool IsValid() const override {
242 : DisallowHeapAllocation no_heap_allocation;
243 141350 : Handle<Map> owner = owner_.object();
244 : return PropertyConstness::kConst ==
245 424050 : owner->instance_descriptors()->GetDetails(descriptor_).constness();
246 : }
247 :
248 70670 : void Install(const MaybeObjectHandle& code) override {
249 : SLOW_DCHECK(IsValid());
250 212010 : DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
251 70670 : DependentCode::kFieldOwnerGroup);
252 70670 : }
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 184646 : : 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 367502 : bool IsValid() const override {
272 367502 : 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 735004 : 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 1102479 : return type_ == cell->property_details().cell_type() &&
283 367491 : read_only_ == cell->property_details().IsReadOnly();
284 : }
285 :
286 183702 : void Install(const MaybeObjectHandle& code) override {
287 : SLOW_DCHECK(IsValid());
288 551106 : DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(),
289 183702 : DependentCode::kPropertyCellChangedGroup);
290 183702 : }
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 19824 : explicit ProtectorDependency(const PropertyCellRef& cell) : cell_(cell) {
301 : DCHECK_EQ(cell_.value().AsSmi(), Isolate::kProtectorValid);
302 : }
303 :
304 39436 : bool IsValid() const override {
305 39436 : Handle<PropertyCell> cell = cell_.object();
306 39436 : return cell->value() == Smi::FromInt(Isolate::kProtectorValid);
307 : }
308 :
309 19716 : void Install(const MaybeObjectHandle& code) override {
310 : SLOW_DCHECK(IsValid());
311 59148 : DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(),
312 19716 : DependentCode::kPropertyCellChangedGroup);
313 19716 : }
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 2951 : : 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 5822 : bool IsValid() const override {
333 5822 : Handle<AllocationSite> site = site_.object();
334 : ElementsKind kind = site->PointsToLiteral()
335 : ? site->boilerplate()->GetElementsKind()
336 5822 : : site->GetElementsKind();
337 5822 : return kind_ == kind;
338 : }
339 :
340 2903 : void Install(const MaybeObjectHandle& code) override {
341 : SLOW_DCHECK(IsValid());
342 8709 : DependentCode::InstallDependency(
343 : site_.isolate(), code, site_.object(),
344 2903 : DependentCode::kAllocationSiteTransitionChangedGroup);
345 2903 : }
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 5446 : : function_(function), instance_size_(instance_size) {}
358 :
359 10847 : bool IsValid() const override {
360 : // The dependency is valid if the prediction is the same as the current
361 : // slack tracking result.
362 21694 : if (!function_.object()->has_initial_map()) return false;
363 32523 : int instance_size = function_.object()->ComputeInstanceSizeWithMinSlack(
364 10841 : function_.isolate());
365 10841 : return instance_size == instance_size_;
366 : }
367 :
368 5421 : void PrepareInstall() override {
369 : SLOW_DCHECK(IsValid());
370 10842 : function_.object()->CompleteInobjectSlackTrackingIfActive();
371 5421 : }
372 :
373 5420 : void Install(const MaybeObjectHandle& code) override {
374 : SLOW_DCHECK(IsValid());
375 : DCHECK(!function_.object()
376 : ->initial_map()
377 : ->IsInobjectSlackTrackingInProgress());
378 5420 : }
379 :
380 : private:
381 : JSFunctionRef function_;
382 : int instance_size_;
383 : };
384 :
385 5446 : MapRef CompilationDependencies::DependOnInitialMap(
386 : const JSFunctionRef& function) {
387 5446 : MapRef map = function.initial_map();
388 16338 : dependencies_.push_front(new (zone_) InitialMapDependency(function, map));
389 5446 : return map;
390 : }
391 :
392 1348 : ObjectRef CompilationDependencies::DependOnPrototypeProperty(
393 : const JSFunctionRef& function) {
394 1348 : ObjectRef prototype = function.prototype();
395 2696 : dependencies_.push_front(
396 1348 : new (zone_) PrototypePropertyDependency(function, prototype));
397 1348 : return prototype;
398 : }
399 :
400 164497 : void CompilationDependencies::DependOnStableMap(const MapRef& map) {
401 164497 : if (map.CanTransition()) {
402 487920 : dependencies_.push_front(new (zone_) StableMapDependency(map));
403 : } else {
404 : DCHECK(map.is_stable());
405 : }
406 164497 : }
407 :
408 22026 : void CompilationDependencies::DependOnTransition(const MapRef& target_map) {
409 22026 : if (target_map.CanBeDeprecated()) {
410 58932 : dependencies_.push_front(new (zone_) TransitionDependency(target_map));
411 : } else {
412 : DCHECK(!target_map.is_deprecated());
413 : }
414 22026 : }
415 :
416 7521 : AllocationType CompilationDependencies::DependOnPretenureMode(
417 : const AllocationSiteRef& site) {
418 7521 : AllocationType allocation = site.GetAllocationType();
419 22563 : dependencies_.push_front(new (zone_)
420 : PretenureModeDependency(site, allocation));
421 7521 : return allocation;
422 : }
423 :
424 70924 : PropertyConstness CompilationDependencies::DependOnFieldConstness(
425 : const MapRef& map, int descriptor) {
426 70924 : MapRef owner = map.FindFieldOwner(descriptor);
427 : PropertyConstness constness =
428 141848 : owner.GetPropertyDetails(descriptor).constness();
429 70924 : 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 141848 : if (Map::CanHaveFastTransitionableElementsKind(map.instance_type())) {
434 : // If the map can already transition away, let us report the field as
435 : // mutable.
436 13650 : if (!map.is_stable()) {
437 : return PropertyConstness::kMutable;
438 : }
439 13650 : DependOnStableMap(map);
440 : }
441 :
442 : DCHECK_EQ(constness, PropertyConstness::kConst);
443 212772 : dependencies_.push_front(new (zone_)
444 : FieldConstnessDependency(owner, descriptor));
445 70924 : return PropertyConstness::kConst;
446 : }
447 :
448 111007 : void CompilationDependencies::DependOnFieldRepresentation(const MapRef& map,
449 : int descriptor) {
450 111007 : MapRef owner = map.FindFieldOwner(descriptor);
451 111007 : PropertyDetails details = owner.GetPropertyDetails(descriptor);
452 : DCHECK(details.representation().Equals(
453 : map.GetPropertyDetails(descriptor).representation()));
454 333021 : dependencies_.push_front(new (zone_) FieldRepresentationDependency(
455 : owner, descriptor, details.representation()));
456 111007 : }
457 :
458 3843 : void CompilationDependencies::DependOnFieldType(const MapRef& map,
459 : int descriptor) {
460 3843 : MapRef owner = map.FindFieldOwner(descriptor);
461 3843 : ObjectRef type = owner.GetFieldType(descriptor);
462 : DCHECK(type.equals(map.GetFieldType(descriptor)));
463 11529 : dependencies_.push_front(new (zone_)
464 : FieldTypeDependency(owner, descriptor, type));
465 3843 : }
466 :
467 184646 : void CompilationDependencies::DependOnGlobalProperty(
468 : const PropertyCellRef& cell) {
469 369292 : PropertyCellType type = cell.property_details().cell_type();
470 369292 : bool read_only = cell.property_details().IsReadOnly();
471 553938 : dependencies_.push_front(new (zone_)
472 : GlobalPropertyDependency(cell, type, read_only));
473 184646 : }
474 :
475 20744 : bool CompilationDependencies::DependOnProtector(const PropertyCellRef& cell) {
476 20744 : if (cell.value().AsSmi() != Isolate::kProtectorValid) return false;
477 59472 : dependencies_.push_front(new (zone_) ProtectorDependency(cell));
478 19824 : return true;
479 : }
480 :
481 8008 : bool CompilationDependencies::DependOnArrayBufferDetachingProtector() {
482 8008 : return DependOnProtector(PropertyCellRef(
483 : broker_,
484 24024 : broker_->isolate()->factory()->array_buffer_detaching_protector()));
485 : }
486 :
487 991 : bool CompilationDependencies::DependOnArrayIteratorProtector() {
488 991 : return DependOnProtector(PropertyCellRef(
489 2973 : broker_, broker_->isolate()->factory()->array_iterator_protector()));
490 : }
491 :
492 806 : bool CompilationDependencies::DependOnArraySpeciesProtector() {
493 806 : return DependOnProtector(PropertyCellRef(
494 2418 : broker_, broker_->isolate()->factory()->array_species_protector()));
495 : }
496 :
497 6549 : bool CompilationDependencies::DependOnNoElementsProtector() {
498 6549 : return DependOnProtector(PropertyCellRef(
499 19647 : broker_, broker_->isolate()->factory()->no_elements_protector()));
500 : }
501 :
502 4019 : bool CompilationDependencies::DependOnPromiseHookProtector() {
503 4019 : return DependOnProtector(PropertyCellRef(
504 12057 : broker_, broker_->isolate()->factory()->promise_hook_protector()));
505 : }
506 :
507 228 : bool CompilationDependencies::DependOnPromiseSpeciesProtector() {
508 228 : return DependOnProtector(PropertyCellRef(
509 684 : broker_, broker_->isolate()->factory()->promise_species_protector()));
510 : }
511 :
512 109 : bool CompilationDependencies::DependOnPromiseThenProtector() {
513 109 : return DependOnProtector(PropertyCellRef(
514 327 : broker_, broker_->isolate()->factory()->promise_then_protector()));
515 : }
516 :
517 7740 : void CompilationDependencies::DependOnElementsKind(
518 : const AllocationSiteRef& site) {
519 : // Do nothing if the object doesn't have any useful element transitions left.
520 7740 : ElementsKind kind = site.PointsToLiteral()
521 20246 : ? site.boilerplate().value().GetElementsKind()
522 15480 : : site.GetElementsKind();
523 7740 : if (AllocationSite::ShouldTrack(kind)) {
524 8853 : dependencies_.push_front(new (zone_) ElementsKindDependency(site, kind));
525 : }
526 7740 : }
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 464251 : bool CompilationDependencies::Commit(Handle<Code> code) {
536 1056704 : for (auto dep : dependencies_) {
537 592497 : if (!dep->IsValid()) {
538 : dependencies_.clear();
539 : return false;
540 : }
541 592453 : dep->PrepareInstall();
542 : }
543 :
544 : DisallowCodeDependencyChange no_dependency_change;
545 1056491 : 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 592298 : if (!dep->IsValid()) {
552 : dependencies_.clear();
553 : return false;
554 : }
555 592284 : 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 464193 : 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 464193 : return true;
576 : }
577 :
578 : namespace {
579 : // This function expects to never see a JSProxy.
580 54710 : void DependOnStablePrototypeChain(CompilationDependencies* deps, MapRef map,
581 : base::Optional<JSObjectRef> last_prototype) {
582 30185 : while (true) {
583 84895 : map.SerializePrototype();
584 84895 : HeapObjectRef proto = map.prototype();
585 84895 : if (!proto.IsJSObject()) {
586 50 : CHECK_EQ(proto.map().oddball_type(), OddballType::kNull);
587 54710 : break;
588 : }
589 84845 : map = proto.map();
590 84845 : deps->DependOnStableMap(map);
591 84845 : if (last_prototype.has_value() && proto.equals(*last_prototype)) break;
592 : }
593 54710 : }
594 : } // namespace
595 :
596 : template <class MapContainer>
597 52465 : 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 107175 : for (auto map : receiver_maps) {
602 54710 : MapRef receiver_map(broker_, map);
603 54710 : 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 8124 : broker_->native_context().GetConstructorFunction(receiver_map);
608 8124 : if (constructor.has_value()) receiver_map = constructor->initial_map();
609 : }
610 54710 : if (start == kStartAtReceiver) DependOnStableMap(receiver_map);
611 54710 : DependOnStablePrototypeChain(this, receiver_map, last_prototype);
612 : }
613 52465 : }
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 6034 : void CompilationDependencies::DependOnElementsKinds(
622 : const AllocationSiteRef& site) {
623 6034 : AllocationSiteRef current = site;
624 219 : while (true) {
625 6253 : DependOnElementsKind(current);
626 6253 : if (!current.nested_site().IsAllocationSite()) break;
627 219 : current = current.nested_site().AsAllocationSite();
628 : }
629 6034 : CHECK_EQ(current.nested_site().AsSmi(), 0);
630 6034 : }
631 :
632 951 : SlackTrackingPrediction::SlackTrackingPrediction(MapRef initial_map,
633 : int instance_size)
634 : : instance_size_(instance_size),
635 : inobject_property_count_(
636 12794 : (instance_size >> kTaggedSizeLog2) -
637 8299 : initial_map.GetInObjectPropertiesStartInWords()) {}
638 :
639 : SlackTrackingPrediction
640 5446 : CompilationDependencies::DependOnInitialMapInstanceSizePrediction(
641 : const JSFunctionRef& function) {
642 5446 : MapRef initial_map = DependOnInitialMap(function);
643 5446 : 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 10892 : dependencies_.push_front(
648 5446 : new (zone_)
649 : InitialMapInstanceSizePredictionDependency(function, instance_size));
650 : DCHECK_LE(instance_size, function.initial_map().instance_size());
651 5446 : return SlackTrackingPrediction(initial_map, instance_size);
652 : }
653 :
654 : } // namespace compiler
655 : } // namespace internal
656 122036 : } // namespace v8
|