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 483050 : CompilationDependencies::CompilationDependencies(JSHeapBroker* broker,
17 : Zone* zone)
18 966100 : : zone_(zone), broker_(broker), dependencies_(zone) {}
19 :
20 595237 : class CompilationDependencies::Dependency : public ZoneObject {
21 : public:
22 : virtual bool IsValid() const = 0;
23 585681 : 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 5398 : : function_(function), initial_map_(initial_map) {
37 : DCHECK(function_.has_initial_map());
38 : DCHECK(function_.initial_map().equals(initial_map_));
39 : }
40 :
41 10747 : bool IsValid() const override {
42 10747 : Handle<JSFunction> function = function_.object();
43 21494 : return function->has_initial_map() &&
44 21494 : function->initial_map() == *initial_map_.object();
45 : }
46 :
47 5372 : void Install(const MaybeObjectHandle& code) override {
48 : SLOW_DCHECK(IsValid());
49 16116 : DependentCode::InstallDependency(function_.isolate(), code,
50 : initial_map_.object(),
51 5372 : DependentCode::kInitialMapChangedGroup);
52 5372 : }
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 1343 : : function_(function), prototype_(prototype) {
67 : DCHECK(function_.has_prototype());
68 : DCHECK(!function_.PrototypeRequiresRuntimeLookup());
69 : DCHECK(function_.prototype().equals(prototype_));
70 : }
71 :
72 2666 : bool IsValid() const override {
73 2666 : Handle<JSFunction> function = function_.object();
74 10664 : return function->has_prototype_slot() && function->has_prototype() &&
75 7998 : !function->PrototypeRequiresRuntimeLookup() &&
76 7998 : function->prototype() == *prototype_.object();
77 : }
78 :
79 1340 : void PrepareInstall() override {
80 : SLOW_DCHECK(IsValid());
81 1340 : Handle<JSFunction> function = function_.object();
82 1340 : if (!function->has_initial_map()) JSFunction::EnsureHasInitialMap(function);
83 1340 : }
84 :
85 1326 : void Install(const MaybeObjectHandle& code) override {
86 : SLOW_DCHECK(IsValid());
87 1326 : Handle<JSFunction> function = function_.object();
88 : DCHECK(function->has_initial_map());
89 1326 : Handle<Map> initial_map(function->initial_map(), function_.isolate());
90 2652 : DependentCode::InstallDependency(function_.isolate(), code, initial_map,
91 1326 : DependentCode::kInitialMapChangedGroup);
92 1326 : }
93 :
94 : private:
95 : JSFunctionRef function_;
96 : ObjectRef prototype_;
97 : };
98 :
99 : class StableMapDependency final : public CompilationDependencies::Dependency {
100 : public:
101 162189 : explicit StableMapDependency(const MapRef& map) : map_(map) {
102 : DCHECK(map_.is_stable());
103 : }
104 :
105 646138 : bool IsValid() const override { return map_.object()->is_stable(); }
106 :
107 161501 : void Install(const MaybeObjectHandle& code) override {
108 : SLOW_DCHECK(IsValid());
109 484503 : DependentCode::InstallDependency(map_.isolate(), code, map_.object(),
110 161501 : DependentCode::kPrototypeCheckGroup);
111 161501 : }
112 :
113 : private:
114 : MapRef map_;
115 : };
116 :
117 : class TransitionDependency final : public CompilationDependencies::Dependency {
118 : public:
119 19488 : explicit TransitionDependency(const MapRef& map) : map_(map) {
120 : DCHECK(!map_.is_deprecated());
121 : }
122 :
123 77864 : bool IsValid() const override { return !map_.object()->is_deprecated(); }
124 :
125 19464 : void Install(const MaybeObjectHandle& code) override {
126 : SLOW_DCHECK(IsValid());
127 58392 : DependentCode::InstallDependency(map_.isolate(), code, map_.object(),
128 19464 : DependentCode::kTransitionGroup);
129 19464 : }
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 7588 : : site_(site), allocation_(allocation) {
143 : DCHECK_EQ(allocation, site_.GetAllocationType());
144 : }
145 :
146 14911 : bool IsValid() const override {
147 29822 : return allocation_ == site_.object()->GetAllocationType();
148 : }
149 :
150 7448 : void Install(const MaybeObjectHandle& code) override {
151 : SLOW_DCHECK(IsValid());
152 22344 : DependentCode::InstallDependency(
153 : site_.isolate(), code, site_.object(),
154 7448 : DependentCode::kAllocationSiteTenuringChangedGroup);
155 7448 : }
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 110830 : representation_(representation) {
176 : DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
177 : DCHECK(representation_.Equals(
178 : owner_.GetPropertyDetails(descriptor_).representation()));
179 : }
180 :
181 220321 : bool IsValid() const override {
182 : DisallowHeapAllocation no_heap_allocation;
183 220321 : Handle<Map> owner = owner_.object();
184 440642 : return representation_.Equals(owner->instance_descriptors()
185 660963 : ->GetDetails(descriptor_)
186 220321 : .representation());
187 : }
188 :
189 110152 : void Install(const MaybeObjectHandle& code) override {
190 : SLOW_DCHECK(IsValid());
191 330456 : DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
192 110152 : DependentCode::kFieldOwnerGroup);
193 110152 : }
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 3792 : : owner_(owner), descriptor_(descriptor), type_(type) {
208 : DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
209 : DCHECK(type_.equals(owner_.GetFieldType(descriptor_)));
210 : }
211 :
212 7522 : bool IsValid() const override {
213 : DisallowHeapAllocation no_heap_allocation;
214 7522 : Handle<Map> owner = owner_.object();
215 7522 : Handle<Object> type = type_.object();
216 22566 : return *type == owner->instance_descriptors()->GetFieldType(descriptor_);
217 : }
218 :
219 3761 : void Install(const MaybeObjectHandle& code) override {
220 : SLOW_DCHECK(IsValid());
221 11283 : DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
222 3761 : DependentCode::kFieldOwnerGroup);
223 3761 : }
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 70918 : : owner_(owner), descriptor_(descriptor) {
236 : DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
237 : DCHECK_EQ(PropertyConstness::kConst,
238 : owner_.GetPropertyDetails(descriptor_).constness());
239 : }
240 :
241 141253 : bool IsValid() const override {
242 : DisallowHeapAllocation no_heap_allocation;
243 141253 : Handle<Map> owner = owner_.object();
244 : return PropertyConstness::kConst ==
245 423759 : owner->instance_descriptors()->GetDetails(descriptor_).constness();
246 : }
247 :
248 70616 : void Install(const MaybeObjectHandle& code) override {
249 : SLOW_DCHECK(IsValid());
250 211848 : DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
251 70616 : DependentCode::kFieldOwnerGroup);
252 70616 : }
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 185371 : : 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 368803 : bool IsValid() const override {
272 368803 : 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 737606 : 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 1106380 : return type_ == cell->property_details().cell_type() &&
283 368790 : read_only_ == cell->property_details().IsReadOnly();
284 : }
285 :
286 184339 : void Install(const MaybeObjectHandle& code) override {
287 : SLOW_DCHECK(IsValid());
288 553017 : DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(),
289 184339 : DependentCode::kPropertyCellChangedGroup);
290 184339 : }
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 19937 : explicit ProtectorDependency(const PropertyCellRef& cell) : cell_(cell) {
301 : DCHECK_EQ(cell_.value().AsSmi(), Isolate::kProtectorValid);
302 : }
303 :
304 39782 : bool IsValid() const override {
305 39782 : Handle<PropertyCell> cell = cell_.object();
306 39782 : return cell->value() == Smi::FromInt(Isolate::kProtectorValid);
307 : }
308 :
309 19889 : void Install(const MaybeObjectHandle& code) override {
310 : SLOW_DCHECK(IsValid());
311 59667 : DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(),
312 19889 : DependentCode::kPropertyCellChangedGroup);
313 19889 : }
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 2985 : : 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 5879 : bool IsValid() const override {
333 5879 : Handle<AllocationSite> site = site_.object();
334 : ElementsKind kind = site->PointsToLiteral()
335 : ? site->boilerplate()->GetElementsKind()
336 5879 : : site->GetElementsKind();
337 5879 : return kind_ == kind;
338 : }
339 :
340 2930 : void Install(const MaybeObjectHandle& code) override {
341 : SLOW_DCHECK(IsValid());
342 8790 : DependentCode::InstallDependency(
343 : site_.isolate(), code, site_.object(),
344 2930 : DependentCode::kAllocationSiteTransitionChangedGroup);
345 2930 : }
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 5398 : : function_(function), instance_size_(instance_size) {}
358 :
359 10750 : bool IsValid() const override {
360 : // The dependency is valid if the prediction is the same as the current
361 : // slack tracking result.
362 21500 : if (!function_.object()->has_initial_map()) return false;
363 32241 : int instance_size = function_.object()->ComputeInstanceSizeWithMinSlack(
364 10747 : function_.isolate());
365 10747 : return instance_size == instance_size_;
366 : }
367 :
368 5375 : void PrepareInstall() override {
369 : SLOW_DCHECK(IsValid());
370 10750 : function_.object()->CompleteInobjectSlackTrackingIfActive();
371 5375 : }
372 :
373 5372 : void Install(const MaybeObjectHandle& code) override {
374 : SLOW_DCHECK(IsValid());
375 : DCHECK(!function_.object()
376 : ->initial_map()
377 : ->IsInobjectSlackTrackingInProgress());
378 5372 : }
379 :
380 : private:
381 : JSFunctionRef function_;
382 : int instance_size_;
383 : };
384 :
385 5398 : MapRef CompilationDependencies::DependOnInitialMap(
386 : const JSFunctionRef& function) {
387 5398 : MapRef map = function.initial_map();
388 16194 : dependencies_.push_front(new (zone_) InitialMapDependency(function, map));
389 5398 : return map;
390 : }
391 :
392 1343 : ObjectRef CompilationDependencies::DependOnPrototypeProperty(
393 : const JSFunctionRef& function) {
394 1343 : ObjectRef prototype = function.prototype();
395 2686 : dependencies_.push_front(
396 1343 : new (zone_) PrototypePropertyDependency(function, prototype));
397 1343 : return prototype;
398 : }
399 :
400 164063 : void CompilationDependencies::DependOnStableMap(const MapRef& map) {
401 164063 : if (map.CanTransition()) {
402 486567 : dependencies_.push_front(new (zone_) StableMapDependency(map));
403 : } else {
404 : DCHECK(map.is_stable());
405 : }
406 164063 : }
407 :
408 21867 : void CompilationDependencies::DependOnTransition(const MapRef& target_map) {
409 21867 : if (target_map.CanBeDeprecated()) {
410 58464 : dependencies_.push_front(new (zone_) TransitionDependency(target_map));
411 : } else {
412 : DCHECK(!target_map.is_deprecated());
413 : }
414 21867 : }
415 :
416 7588 : AllocationType CompilationDependencies::DependOnPretenureMode(
417 : const AllocationSiteRef& site) {
418 7588 : AllocationType allocation = site.GetAllocationType();
419 22764 : dependencies_.push_front(new (zone_)
420 : PretenureModeDependency(site, allocation));
421 7588 : return allocation;
422 : }
423 :
424 70918 : PropertyConstness CompilationDependencies::DependOnFieldConstness(
425 : const MapRef& map, int descriptor) {
426 70918 : MapRef owner = map.FindFieldOwner(descriptor);
427 : PropertyConstness constness =
428 141836 : owner.GetPropertyDetails(descriptor).constness();
429 70918 : 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 141836 : if (Map::CanHaveFastTransitionableElementsKind(map.instance_type())) {
434 : // If the map can already transition away, let us report the field as
435 : // mutable.
436 13697 : if (!map.is_stable()) {
437 : return PropertyConstness::kMutable;
438 : }
439 13697 : DependOnStableMap(map);
440 : }
441 :
442 : DCHECK_EQ(constness, PropertyConstness::kConst);
443 212754 : dependencies_.push_front(new (zone_)
444 : FieldConstnessDependency(owner, descriptor));
445 70918 : return PropertyConstness::kConst;
446 : }
447 :
448 110830 : void CompilationDependencies::DependOnFieldRepresentation(const MapRef& map,
449 : int descriptor) {
450 110830 : MapRef owner = map.FindFieldOwner(descriptor);
451 110830 : PropertyDetails details = owner.GetPropertyDetails(descriptor);
452 : DCHECK(details.representation().Equals(
453 : map.GetPropertyDetails(descriptor).representation()));
454 332490 : dependencies_.push_front(new (zone_) FieldRepresentationDependency(
455 : owner, descriptor, details.representation()));
456 110830 : }
457 :
458 3792 : void CompilationDependencies::DependOnFieldType(const MapRef& map,
459 : int descriptor) {
460 3792 : MapRef owner = map.FindFieldOwner(descriptor);
461 3792 : ObjectRef type = owner.GetFieldType(descriptor);
462 : DCHECK(type.equals(map.GetFieldType(descriptor)));
463 11376 : dependencies_.push_front(new (zone_)
464 : FieldTypeDependency(owner, descriptor, type));
465 3792 : }
466 :
467 185371 : void CompilationDependencies::DependOnGlobalProperty(
468 : const PropertyCellRef& cell) {
469 370742 : PropertyCellType type = cell.property_details().cell_type();
470 370742 : bool read_only = cell.property_details().IsReadOnly();
471 556113 : dependencies_.push_front(new (zone_)
472 : GlobalPropertyDependency(cell, type, read_only));
473 185371 : }
474 :
475 20836 : bool CompilationDependencies::DependOnProtector(const PropertyCellRef& cell) {
476 20836 : if (cell.value().AsSmi() != Isolate::kProtectorValid) return false;
477 59811 : dependencies_.push_front(new (zone_) ProtectorDependency(cell));
478 19937 : return true;
479 : }
480 :
481 8043 : bool CompilationDependencies::DependOnArrayBufferDetachingProtector() {
482 8043 : return DependOnProtector(PropertyCellRef(
483 : broker_,
484 24129 : broker_->isolate()->factory()->array_buffer_detaching_protector()));
485 : }
486 :
487 1018 : bool CompilationDependencies::DependOnArrayIteratorProtector() {
488 1018 : return DependOnProtector(PropertyCellRef(
489 3054 : broker_, broker_->isolate()->factory()->array_iterator_protector()));
490 : }
491 :
492 815 : bool CompilationDependencies::DependOnArraySpeciesProtector() {
493 815 : return DependOnProtector(PropertyCellRef(
494 2445 : broker_, broker_->isolate()->factory()->array_species_protector()));
495 : }
496 :
497 6571 : bool CompilationDependencies::DependOnNoElementsProtector() {
498 6571 : return DependOnProtector(PropertyCellRef(
499 19713 : broker_, broker_->isolate()->factory()->no_elements_protector()));
500 : }
501 :
502 4018 : bool CompilationDependencies::DependOnPromiseHookProtector() {
503 4018 : return DependOnProtector(PropertyCellRef(
504 12054 : 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 7814 : void CompilationDependencies::DependOnElementsKind(
518 : const AllocationSiteRef& site) {
519 : // Do nothing if the object doesn't have any useful element transitions left.
520 7814 : ElementsKind kind = site.PointsToLiteral()
521 20434 : ? site.boilerplate().value().GetElementsKind()
522 15628 : : site.GetElementsKind();
523 7814 : if (AllocationSite::ShouldTrack(kind)) {
524 8955 : dependencies_.push_front(new (zone_) ElementsKindDependency(site, kind));
525 : }
526 7814 : }
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 463748 : bool CompilationDependencies::Commit(Handle<Code> code) {
536 1056144 : for (auto dep : dependencies_) {
537 592451 : if (!dep->IsValid()) {
538 : dependencies_.clear();
539 : return false;
540 : }
541 592396 : dep->PrepareInstall();
542 : }
543 :
544 : DisallowCodeDependencyChange no_dependency_change;
545 1055863 : 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 592184 : if (!dep->IsValid()) {
552 : dependencies_.clear();
553 : return false;
554 : }
555 592170 : 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 463679 : 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 463679 : return true;
576 : }
577 :
578 : namespace {
579 : // This function expects to never see a JSProxy.
580 54589 : void DependOnStablePrototypeChain(CompilationDependencies* deps, MapRef map,
581 : base::Optional<JSObjectRef> last_prototype) {
582 29726 : while (true) {
583 84315 : map.SerializePrototype();
584 84315 : HeapObjectRef proto = map.prototype();
585 84315 : if (!proto.IsJSObject()) {
586 50 : CHECK_EQ(proto.map().oddball_type(), OddballType::kNull);
587 54589 : break;
588 : }
589 84265 : map = proto.map();
590 84265 : deps->DependOnStableMap(map);
591 84265 : if (last_prototype.has_value() && proto.equals(*last_prototype)) break;
592 : }
593 54589 : }
594 : } // namespace
595 :
596 : template <class MapContainer>
597 52310 : 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 106899 : for (auto map : receiver_maps) {
602 54589 : MapRef receiver_map(broker_, map);
603 54589 : 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 8156 : broker_->native_context().GetConstructorFunction(receiver_map);
608 8156 : if (constructor.has_value()) receiver_map = constructor->initial_map();
609 : }
610 54589 : if (start == kStartAtReceiver) DependOnStableMap(receiver_map);
611 54589 : DependOnStablePrototypeChain(this, receiver_map, last_prototype);
612 : }
613 52310 : }
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 6084 : void CompilationDependencies::DependOnElementsKinds(
622 : const AllocationSiteRef& site) {
623 6084 : AllocationSiteRef current = site;
624 226 : while (true) {
625 6310 : DependOnElementsKind(current);
626 6310 : if (!current.nested_site().IsAllocationSite()) break;
627 226 : current = current.nested_site().AsAllocationSite();
628 : }
629 6084 : CHECK_EQ(current.nested_site().AsSmi(), 0);
630 6084 : }
631 :
632 961 : SlackTrackingPrediction::SlackTrackingPrediction(MapRef initial_map,
633 : int instance_size)
634 : : instance_size_(instance_size),
635 : inobject_property_count_(
636 12718 : (instance_size >> kTaggedSizeLog2) -
637 8281 : initial_map.GetInObjectPropertiesStartInWords()) {}
638 :
639 : SlackTrackingPrediction
640 5398 : CompilationDependencies::DependOnInitialMapInstanceSizePrediction(
641 : const JSFunctionRef& function) {
642 5398 : MapRef initial_map = DependOnInitialMap(function);
643 5398 : 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 10796 : dependencies_.push_front(
648 5398 : new (zone_)
649 : InitialMapInstanceSizePredictionDependency(function, instance_size));
650 : DCHECK_LE(instance_size, function.initial_map().instance_size());
651 5398 : return SlackTrackingPrediction(initial_map, instance_size);
652 : }
653 :
654 : } // namespace compiler
655 : } // namespace internal
656 122036 : } // namespace v8
|