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/compiler/compilation-dependency.h"
8 #include "src/execution/protectors.h"
9 #include "src/handles/handles-inl.h"
10 #include "src/objects/allocation-site-inl.h"
11 #include "src/objects/js-function-inl.h"
12 #include "src/objects/objects-inl.h"
13 #include "src/zone/zone-handle-set.h"
14
15 namespace v8 {
16 namespace internal {
17 namespace compiler {
18
CompilationDependencies(JSHeapBroker * broker,Zone * zone)19 CompilationDependencies::CompilationDependencies(JSHeapBroker* broker,
20 Zone* zone)
21 : zone_(zone), broker_(broker), dependencies_(zone) {}
22
23 class InitialMapDependency final : public CompilationDependency {
24 public:
25 // TODO(neis): Once the concurrent compiler frontend is always-on, we no
26 // longer need to explicitly store the initial map.
InitialMapDependency(const JSFunctionRef & function,const MapRef & initial_map)27 InitialMapDependency(const JSFunctionRef& function, const MapRef& initial_map)
28 : function_(function), initial_map_(initial_map) {
29 DCHECK(function_.has_initial_map());
30 DCHECK(function_.initial_map().equals(initial_map_));
31 }
32
IsValid() const33 bool IsValid() const override {
34 Handle<JSFunction> function = function_.object();
35 return function->has_initial_map() &&
36 function->initial_map() == *initial_map_.object();
37 }
38
Install(const MaybeObjectHandle & code) const39 void Install(const MaybeObjectHandle& code) const override {
40 SLOW_DCHECK(IsValid());
41 DependentCode::InstallDependency(function_.isolate(), code,
42 initial_map_.object(),
43 DependentCode::kInitialMapChangedGroup);
44 }
45
46 private:
47 JSFunctionRef function_;
48 MapRef initial_map_;
49 };
50
51 class PrototypePropertyDependency final : public CompilationDependency {
52 public:
53 // TODO(neis): Once the concurrent compiler frontend is always-on, we no
54 // longer need to explicitly store the prototype.
PrototypePropertyDependency(const JSFunctionRef & function,const ObjectRef & prototype)55 PrototypePropertyDependency(const JSFunctionRef& function,
56 const ObjectRef& prototype)
57 : function_(function), prototype_(prototype) {
58 DCHECK(function_.has_prototype());
59 DCHECK(!function_.PrototypeRequiresRuntimeLookup());
60 DCHECK(function_.prototype().equals(prototype_));
61 }
62
IsValid() const63 bool IsValid() const override {
64 Handle<JSFunction> function = function_.object();
65 return function->has_prototype_slot() && function->has_prototype() &&
66 !function->PrototypeRequiresRuntimeLookup() &&
67 function->prototype() == *prototype_.object();
68 }
69
PrepareInstall() const70 void PrepareInstall() const override {
71 SLOW_DCHECK(IsValid());
72 Handle<JSFunction> function = function_.object();
73 if (!function->has_initial_map()) JSFunction::EnsureHasInitialMap(function);
74 }
75
Install(const MaybeObjectHandle & code) const76 void Install(const MaybeObjectHandle& code) const override {
77 SLOW_DCHECK(IsValid());
78 Handle<JSFunction> function = function_.object();
79 DCHECK(function->has_initial_map());
80 Handle<Map> initial_map(function->initial_map(), function_.isolate());
81 DependentCode::InstallDependency(function_.isolate(), code, initial_map,
82 DependentCode::kInitialMapChangedGroup);
83 }
84
85 private:
86 JSFunctionRef function_;
87 ObjectRef prototype_;
88 };
89
90 class StableMapDependency final : public CompilationDependency {
91 public:
StableMapDependency(const MapRef & map)92 explicit StableMapDependency(const MapRef& map) : map_(map) {
93 DCHECK(map_.is_stable());
94 }
95
IsValid() const96 bool IsValid() const override { return map_.object()->is_stable(); }
97
Install(const MaybeObjectHandle & code) const98 void Install(const MaybeObjectHandle& code) const override {
99 SLOW_DCHECK(IsValid());
100 DependentCode::InstallDependency(map_.isolate(), code, map_.object(),
101 DependentCode::kPrototypeCheckGroup);
102 }
103
104 private:
105 MapRef map_;
106 };
107
108 class TransitionDependency final : public CompilationDependency {
109 public:
TransitionDependency(const MapRef & map)110 explicit TransitionDependency(const MapRef& map) : map_(map) {
111 DCHECK(!map_.is_deprecated());
112 }
113
IsValid() const114 bool IsValid() const override { return !map_.object()->is_deprecated(); }
115
Install(const MaybeObjectHandle & code) const116 void Install(const MaybeObjectHandle& code) const override {
117 SLOW_DCHECK(IsValid());
118 DependentCode::InstallDependency(map_.isolate(), code, map_.object(),
119 DependentCode::kTransitionGroup);
120 }
121
122 private:
123 MapRef map_;
124 };
125
126 class PretenureModeDependency final : public CompilationDependency {
127 public:
128 // TODO(neis): Once the concurrent compiler frontend is always-on, we no
129 // longer need to explicitly store the mode.
PretenureModeDependency(const AllocationSiteRef & site,AllocationType allocation)130 PretenureModeDependency(const AllocationSiteRef& site,
131 AllocationType allocation)
132 : site_(site), allocation_(allocation) {
133 DCHECK_EQ(allocation, site_.GetAllocationType());
134 }
135
IsValid() const136 bool IsValid() const override {
137 return allocation_ == site_.object()->GetAllocationType();
138 }
139
Install(const MaybeObjectHandle & code) const140 void Install(const MaybeObjectHandle& code) const override {
141 SLOW_DCHECK(IsValid());
142 DependentCode::InstallDependency(
143 site_.isolate(), code, site_.object(),
144 DependentCode::kAllocationSiteTenuringChangedGroup);
145 }
146
147 #ifdef DEBUG
IsPretenureModeDependency() const148 bool IsPretenureModeDependency() const override { return true; }
149 #endif
150
151 private:
152 AllocationSiteRef site_;
153 AllocationType allocation_;
154 };
155
156 class FieldRepresentationDependency final : public CompilationDependency {
157 public:
158 // TODO(neis): Once the concurrent compiler frontend is always-on, we no
159 // longer need to explicitly store the representation.
FieldRepresentationDependency(const MapRef & owner,InternalIndex descriptor,Representation representation)160 FieldRepresentationDependency(const MapRef& owner, InternalIndex descriptor,
161 Representation representation)
162 : owner_(owner),
163 descriptor_(descriptor),
164 representation_(representation) {
165 DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
166 DCHECK(representation_.Equals(
167 owner_.GetPropertyDetails(descriptor_).representation()));
168 }
169
IsValid() const170 bool IsValid() const override {
171 DisallowHeapAllocation no_heap_allocation;
172 Handle<Map> owner = owner_.object();
173 return representation_.Equals(owner->instance_descriptors(kRelaxedLoad)
174 .GetDetails(descriptor_)
175 .representation());
176 }
177
Install(const MaybeObjectHandle & code) const178 void Install(const MaybeObjectHandle& code) const override {
179 SLOW_DCHECK(IsValid());
180 DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
181 DependentCode::kFieldRepresentationGroup);
182 }
183
184 #ifdef DEBUG
IsFieldRepresentationDependencyOnMap(Handle<Map> const & receiver_map) const185 bool IsFieldRepresentationDependencyOnMap(
186 Handle<Map> const& receiver_map) const override {
187 return owner_.object().equals(receiver_map);
188 }
189 #endif
190
191 private:
192 MapRef owner_;
193 InternalIndex descriptor_;
194 Representation representation_;
195 };
196
197 class FieldTypeDependency final : public CompilationDependency {
198 public:
199 // TODO(neis): Once the concurrent compiler frontend is always-on, we no
200 // longer need to explicitly store the type.
FieldTypeDependency(const MapRef & owner,InternalIndex descriptor,const ObjectRef & type)201 FieldTypeDependency(const MapRef& owner, InternalIndex descriptor,
202 const ObjectRef& type)
203 : owner_(owner), descriptor_(descriptor), type_(type) {
204 DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
205 DCHECK(type_.equals(owner_.GetFieldType(descriptor_)));
206 }
207
IsValid() const208 bool IsValid() const override {
209 DisallowHeapAllocation no_heap_allocation;
210 Handle<Map> owner = owner_.object();
211 Handle<Object> type = type_.object();
212 return *type ==
213 owner->instance_descriptors(kRelaxedLoad).GetFieldType(descriptor_);
214 }
215
Install(const MaybeObjectHandle & code) const216 void Install(const MaybeObjectHandle& code) const override {
217 SLOW_DCHECK(IsValid());
218 DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
219 DependentCode::kFieldTypeGroup);
220 }
221
222 private:
223 MapRef owner_;
224 InternalIndex descriptor_;
225 ObjectRef type_;
226 };
227
228 class FieldConstnessDependency final : public CompilationDependency {
229 public:
FieldConstnessDependency(const MapRef & owner,InternalIndex descriptor)230 FieldConstnessDependency(const MapRef& owner, InternalIndex descriptor)
231 : owner_(owner), descriptor_(descriptor) {
232 DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
233 DCHECK_EQ(PropertyConstness::kConst,
234 owner_.GetPropertyDetails(descriptor_).constness());
235 }
236
IsValid() const237 bool IsValid() const override {
238 DisallowHeapAllocation no_heap_allocation;
239 Handle<Map> owner = owner_.object();
240 return PropertyConstness::kConst ==
241 owner->instance_descriptors(kRelaxedLoad)
242 .GetDetails(descriptor_)
243 .constness();
244 }
245
Install(const MaybeObjectHandle & code) const246 void Install(const MaybeObjectHandle& code) const override {
247 SLOW_DCHECK(IsValid());
248 DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
249 DependentCode::kFieldConstGroup);
250 }
251
252 private:
253 MapRef owner_;
254 InternalIndex descriptor_;
255 };
256
257 class GlobalPropertyDependency final : public CompilationDependency {
258 public:
259 // TODO(neis): Once the concurrent compiler frontend is always-on, we no
260 // longer need to explicitly store the type and the read_only flag.
GlobalPropertyDependency(const PropertyCellRef & cell,PropertyCellType type,bool read_only)261 GlobalPropertyDependency(const PropertyCellRef& cell, PropertyCellType type,
262 bool read_only)
263 : cell_(cell), type_(type), read_only_(read_only) {
264 DCHECK_EQ(type_, cell_.property_details().cell_type());
265 DCHECK_EQ(read_only_, cell_.property_details().IsReadOnly());
266 }
267
IsValid() const268 bool IsValid() const override {
269 Handle<PropertyCell> cell = cell_.object();
270 // The dependency is never valid if the cell is 'invalidated'. This is
271 // marked by setting the value to the hole.
272 if (cell->value() == *(cell_.isolate()->factory()->the_hole_value())) {
273 DCHECK(cell->property_details().cell_type() ==
274 PropertyCellType::kInvalidated ||
275 cell->property_details().cell_type() ==
276 PropertyCellType::kUninitialized);
277 return false;
278 }
279 return type_ == cell->property_details().cell_type() &&
280 read_only_ == cell->property_details().IsReadOnly();
281 }
282
Install(const MaybeObjectHandle & code) const283 void Install(const MaybeObjectHandle& code) const override {
284 SLOW_DCHECK(IsValid());
285 DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(),
286 DependentCode::kPropertyCellChangedGroup);
287 }
288
289 private:
290 PropertyCellRef cell_;
291 PropertyCellType type_;
292 bool read_only_;
293 };
294
295 class ProtectorDependency final : public CompilationDependency {
296 public:
ProtectorDependency(const PropertyCellRef & cell)297 explicit ProtectorDependency(const PropertyCellRef& cell) : cell_(cell) {
298 DCHECK_EQ(cell_.value().AsSmi(), Protectors::kProtectorValid);
299 }
300
IsValid() const301 bool IsValid() const override {
302 Handle<PropertyCell> cell = cell_.object();
303 return cell->value() == Smi::FromInt(Protectors::kProtectorValid);
304 }
305
Install(const MaybeObjectHandle & code) const306 void Install(const MaybeObjectHandle& code) const override {
307 SLOW_DCHECK(IsValid());
308 DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(),
309 DependentCode::kPropertyCellChangedGroup);
310 }
311
312 private:
313 PropertyCellRef cell_;
314 };
315
316 class ElementsKindDependency final : public CompilationDependency {
317 public:
318 // TODO(neis): Once the concurrent compiler frontend is always-on, we no
319 // longer need to explicitly store the elements kind.
ElementsKindDependency(const AllocationSiteRef & site,ElementsKind kind)320 ElementsKindDependency(const AllocationSiteRef& site, ElementsKind kind)
321 : site_(site), kind_(kind) {
322 DCHECK(AllocationSite::ShouldTrack(kind_));
323 DCHECK_EQ(kind_, site_.PointsToLiteral()
324 ? site_.boilerplate().value().GetElementsKind()
325 : site_.GetElementsKind());
326 }
327
IsValid() const328 bool IsValid() const override {
329 Handle<AllocationSite> site = site_.object();
330 ElementsKind kind = site->PointsToLiteral()
331 ? site->boilerplate().GetElementsKind()
332 : site->GetElementsKind();
333 return kind_ == kind;
334 }
335
Install(const MaybeObjectHandle & code) const336 void Install(const MaybeObjectHandle& code) const override {
337 SLOW_DCHECK(IsValid());
338 DependentCode::InstallDependency(
339 site_.isolate(), code, site_.object(),
340 DependentCode::kAllocationSiteTransitionChangedGroup);
341 }
342
343 private:
344 AllocationSiteRef site_;
345 ElementsKind kind_;
346 };
347
348 class InitialMapInstanceSizePredictionDependency final
349 : public CompilationDependency {
350 public:
InitialMapInstanceSizePredictionDependency(const JSFunctionRef & function,int instance_size)351 InitialMapInstanceSizePredictionDependency(const JSFunctionRef& function,
352 int instance_size)
353 : function_(function), instance_size_(instance_size) {}
354
IsValid() const355 bool IsValid() const override {
356 // The dependency is valid if the prediction is the same as the current
357 // slack tracking result.
358 if (!function_.object()->has_initial_map()) return false;
359 int instance_size = function_.object()->ComputeInstanceSizeWithMinSlack(
360 function_.isolate());
361 return instance_size == instance_size_;
362 }
363
PrepareInstall() const364 void PrepareInstall() const override {
365 SLOW_DCHECK(IsValid());
366 function_.object()->CompleteInobjectSlackTrackingIfActive();
367 }
368
Install(const MaybeObjectHandle & code) const369 void Install(const MaybeObjectHandle& code) const override {
370 SLOW_DCHECK(IsValid());
371 DCHECK(
372 !function_.object()->initial_map().IsInobjectSlackTrackingInProgress());
373 }
374
375 private:
376 JSFunctionRef function_;
377 int instance_size_;
378 };
379
RecordDependency(CompilationDependency const * dependency)380 void CompilationDependencies::RecordDependency(
381 CompilationDependency const* dependency) {
382 if (dependency != nullptr) dependencies_.push_front(dependency);
383 }
384
DependOnInitialMap(const JSFunctionRef & function)385 MapRef CompilationDependencies::DependOnInitialMap(
386 const JSFunctionRef& function) {
387 MapRef map = function.initial_map();
388 RecordDependency(zone_->New<InitialMapDependency>(function, map));
389 return map;
390 }
391
DependOnPrototypeProperty(const JSFunctionRef & function)392 ObjectRef CompilationDependencies::DependOnPrototypeProperty(
393 const JSFunctionRef& function) {
394 ObjectRef prototype = function.prototype();
395 RecordDependency(
396 zone_->New<PrototypePropertyDependency>(function, prototype));
397 return prototype;
398 }
399
DependOnStableMap(const MapRef & map)400 void CompilationDependencies::DependOnStableMap(const MapRef& map) {
401 if (map.CanTransition()) {
402 RecordDependency(zone_->New<StableMapDependency>(map));
403 } else {
404 DCHECK(map.is_stable());
405 }
406 }
407
DependOnTransition(const MapRef & target_map)408 void CompilationDependencies::DependOnTransition(const MapRef& target_map) {
409 RecordDependency(TransitionDependencyOffTheRecord(target_map));
410 }
411
DependOnPretenureMode(const AllocationSiteRef & site)412 AllocationType CompilationDependencies::DependOnPretenureMode(
413 const AllocationSiteRef& site) {
414 AllocationType allocation = site.GetAllocationType();
415 RecordDependency(zone_->New<PretenureModeDependency>(site, allocation));
416 return allocation;
417 }
418
DependOnFieldConstness(const MapRef & map,InternalIndex descriptor)419 PropertyConstness CompilationDependencies::DependOnFieldConstness(
420 const MapRef& map, InternalIndex descriptor) {
421 MapRef owner = map.FindFieldOwner(descriptor);
422 PropertyConstness constness =
423 owner.GetPropertyDetails(descriptor).constness();
424 if (constness == PropertyConstness::kMutable) return constness;
425
426 // If the map can have fast elements transitions, then the field can be only
427 // considered constant if the map does not transition.
428 if (Map::CanHaveFastTransitionableElementsKind(map.instance_type())) {
429 // If the map can already transition away, let us report the field as
430 // mutable.
431 if (!map.is_stable()) {
432 return PropertyConstness::kMutable;
433 }
434 DependOnStableMap(map);
435 }
436
437 DCHECK_EQ(constness, PropertyConstness::kConst);
438 RecordDependency(zone_->New<FieldConstnessDependency>(owner, descriptor));
439 return PropertyConstness::kConst;
440 }
441
DependOnFieldRepresentation(const MapRef & map,InternalIndex descriptor)442 void CompilationDependencies::DependOnFieldRepresentation(
443 const MapRef& map, InternalIndex descriptor) {
444 RecordDependency(FieldRepresentationDependencyOffTheRecord(map, descriptor));
445 }
446
DependOnFieldType(const MapRef & map,InternalIndex descriptor)447 void CompilationDependencies::DependOnFieldType(const MapRef& map,
448 InternalIndex descriptor) {
449 RecordDependency(FieldTypeDependencyOffTheRecord(map, descriptor));
450 }
451
DependOnGlobalProperty(const PropertyCellRef & cell)452 void CompilationDependencies::DependOnGlobalProperty(
453 const PropertyCellRef& cell) {
454 PropertyCellType type = cell.property_details().cell_type();
455 bool read_only = cell.property_details().IsReadOnly();
456 RecordDependency(zone_->New<GlobalPropertyDependency>(cell, type, read_only));
457 }
458
DependOnProtector(const PropertyCellRef & cell)459 bool CompilationDependencies::DependOnProtector(const PropertyCellRef& cell) {
460 if (cell.value().AsSmi() != Protectors::kProtectorValid) return false;
461 RecordDependency(zone_->New<ProtectorDependency>(cell));
462 return true;
463 }
464
DependOnArrayBufferDetachingProtector()465 bool CompilationDependencies::DependOnArrayBufferDetachingProtector() {
466 return DependOnProtector(PropertyCellRef(
467 broker_,
468 broker_->isolate()->factory()->array_buffer_detaching_protector()));
469 }
470
DependOnArrayIteratorProtector()471 bool CompilationDependencies::DependOnArrayIteratorProtector() {
472 return DependOnProtector(PropertyCellRef(
473 broker_, broker_->isolate()->factory()->array_iterator_protector()));
474 }
475
DependOnArraySpeciesProtector()476 bool CompilationDependencies::DependOnArraySpeciesProtector() {
477 return DependOnProtector(PropertyCellRef(
478 broker_, broker_->isolate()->factory()->array_species_protector()));
479 }
480
DependOnNoElementsProtector()481 bool CompilationDependencies::DependOnNoElementsProtector() {
482 return DependOnProtector(PropertyCellRef(
483 broker_, broker_->isolate()->factory()->no_elements_protector()));
484 }
485
DependOnPromiseHookProtector()486 bool CompilationDependencies::DependOnPromiseHookProtector() {
487 return DependOnProtector(PropertyCellRef(
488 broker_, broker_->isolate()->factory()->promise_hook_protector()));
489 }
490
DependOnPromiseSpeciesProtector()491 bool CompilationDependencies::DependOnPromiseSpeciesProtector() {
492 return DependOnProtector(PropertyCellRef(
493 broker_, broker_->isolate()->factory()->promise_species_protector()));
494 }
495
DependOnPromiseThenProtector()496 bool CompilationDependencies::DependOnPromiseThenProtector() {
497 return DependOnProtector(PropertyCellRef(
498 broker_, broker_->isolate()->factory()->promise_then_protector()));
499 }
500
DependOnElementsKind(const AllocationSiteRef & site)501 void CompilationDependencies::DependOnElementsKind(
502 const AllocationSiteRef& site) {
503 // Do nothing if the object doesn't have any useful element transitions left.
504 ElementsKind kind = site.PointsToLiteral()
505 ? site.boilerplate().value().GetElementsKind()
506 : site.GetElementsKind();
507 if (AllocationSite::ShouldTrack(kind)) {
508 RecordDependency(zone_->New<ElementsKindDependency>(site, kind));
509 }
510 }
511
AreValid() const512 bool CompilationDependencies::AreValid() const {
513 for (auto dep : dependencies_) {
514 if (!dep->IsValid()) return false;
515 }
516 return true;
517 }
518
Commit(Handle<Code> code)519 bool CompilationDependencies::Commit(Handle<Code> code) {
520 // Dependencies are context-dependent. In the future it may be possible to
521 // restore them in the consumer native context, but for now they are
522 // disabled.
523 CHECK_IMPLIES(broker_->is_native_context_independent(),
524 dependencies_.empty());
525
526 for (auto dep : dependencies_) {
527 if (!dep->IsValid()) {
528 dependencies_.clear();
529 return false;
530 }
531 dep->PrepareInstall();
532 }
533
534 DisallowCodeDependencyChange no_dependency_change;
535 for (auto dep : dependencies_) {
536 // Check each dependency's validity again right before installing it,
537 // because the first iteration above might have invalidated some
538 // dependencies. For example, PrototypePropertyDependency::PrepareInstall
539 // can call EnsureHasInitialMap, which can invalidate a StableMapDependency
540 // on the prototype object's map.
541 if (!dep->IsValid()) {
542 dependencies_.clear();
543 return false;
544 }
545 dep->Install(MaybeObjectHandle::Weak(code));
546 }
547
548 // It is even possible that a GC during the above installations invalidated
549 // one of the dependencies. However, this should only affect pretenure mode
550 // dependencies, which we assert below. It is safe to return successfully in
551 // these cases, because once the code gets executed it will do a stack check
552 // that triggers its deoptimization.
553 if (FLAG_stress_gc_during_compilation) {
554 broker_->isolate()->heap()->PreciseCollectAllGarbage(
555 Heap::kForcedGC, GarbageCollectionReason::kTesting, kNoGCCallbackFlags);
556 }
557 #ifdef DEBUG
558 for (auto dep : dependencies_) {
559 CHECK_IMPLIES(!dep->IsValid(), dep->IsPretenureModeDependency());
560 }
561 #endif
562
563 dependencies_.clear();
564 return true;
565 }
566
567 namespace {
568 // This function expects to never see a JSProxy.
DependOnStablePrototypeChain(CompilationDependencies * deps,MapRef map,base::Optional<JSObjectRef> last_prototype)569 void DependOnStablePrototypeChain(CompilationDependencies* deps, MapRef map,
570 base::Optional<JSObjectRef> last_prototype) {
571 while (true) {
572 HeapObjectRef proto = map.prototype();
573 if (!proto.IsJSObject()) {
574 CHECK_EQ(proto.map().oddball_type(), OddballType::kNull);
575 break;
576 }
577 map = proto.map();
578 deps->DependOnStableMap(map);
579 if (last_prototype.has_value() && proto.equals(*last_prototype)) break;
580 }
581 }
582 } // namespace
583
584 template <class MapContainer>
DependOnStablePrototypeChains(MapContainer const & receiver_maps,WhereToStart start,base::Optional<JSObjectRef> last_prototype)585 void CompilationDependencies::DependOnStablePrototypeChains(
586 MapContainer const& receiver_maps, WhereToStart start,
587 base::Optional<JSObjectRef> last_prototype) {
588 for (auto map : receiver_maps) {
589 MapRef receiver_map(broker_, map);
590 if (start == kStartAtReceiver) DependOnStableMap(receiver_map);
591 if (receiver_map.IsPrimitiveMap()) {
592 // Perform the implicit ToObject for primitives here.
593 // Implemented according to ES6 section 7.3.2 GetV (V, P).
594 base::Optional<JSFunctionRef> constructor =
595 broker_->target_native_context().GetConstructorFunction(receiver_map);
596 if (constructor.has_value()) receiver_map = constructor->initial_map();
597 }
598 DependOnStablePrototypeChain(this, receiver_map, last_prototype);
599 }
600 }
601 template void CompilationDependencies::DependOnStablePrototypeChains(
602 ZoneVector<Handle<Map>> const& receiver_maps, WhereToStart start,
603 base::Optional<JSObjectRef> last_prototype);
604 template void CompilationDependencies::DependOnStablePrototypeChains(
605 ZoneHandleSet<Map> const& receiver_maps, WhereToStart start,
606 base::Optional<JSObjectRef> last_prototype);
607
DependOnElementsKinds(const AllocationSiteRef & site)608 void CompilationDependencies::DependOnElementsKinds(
609 const AllocationSiteRef& site) {
610 AllocationSiteRef current = site;
611 while (true) {
612 DependOnElementsKind(current);
613 if (!current.nested_site().IsAllocationSite()) break;
614 current = current.nested_site().AsAllocationSite();
615 }
616 CHECK_EQ(current.nested_site().AsSmi(), 0);
617 }
618
SlackTrackingPrediction(MapRef initial_map,int instance_size)619 SlackTrackingPrediction::SlackTrackingPrediction(MapRef initial_map,
620 int instance_size)
621 : instance_size_(instance_size),
622 inobject_property_count_(
623 (instance_size >> kTaggedSizeLog2) -
624 initial_map.GetInObjectPropertiesStartInWords()) {}
625
626 SlackTrackingPrediction
DependOnInitialMapInstanceSizePrediction(const JSFunctionRef & function)627 CompilationDependencies::DependOnInitialMapInstanceSizePrediction(
628 const JSFunctionRef& function) {
629 MapRef initial_map = DependOnInitialMap(function);
630 int instance_size = function.InitialMapInstanceSizeWithMinSlack();
631 // Currently, we always install the prediction dependency. If this turns out
632 // to be too expensive, we can only install the dependency if slack
633 // tracking is active.
634 RecordDependency(zone_->New<InitialMapInstanceSizePredictionDependency>(
635 function, instance_size));
636 DCHECK_LE(instance_size, function.initial_map().instance_size());
637 return SlackTrackingPrediction(initial_map, instance_size);
638 }
639
640 CompilationDependency const*
TransitionDependencyOffTheRecord(const MapRef & target_map) const641 CompilationDependencies::TransitionDependencyOffTheRecord(
642 const MapRef& target_map) const {
643 if (target_map.CanBeDeprecated()) {
644 return zone_->New<TransitionDependency>(target_map);
645 } else {
646 DCHECK(!target_map.is_deprecated());
647 return nullptr;
648 }
649 }
650
651 CompilationDependency const*
FieldRepresentationDependencyOffTheRecord(const MapRef & map,InternalIndex descriptor) const652 CompilationDependencies::FieldRepresentationDependencyOffTheRecord(
653 const MapRef& map, InternalIndex descriptor) const {
654 MapRef owner = map.FindFieldOwner(descriptor);
655 PropertyDetails details = owner.GetPropertyDetails(descriptor);
656 DCHECK(details.representation().Equals(
657 map.GetPropertyDetails(descriptor).representation()));
658 return zone_->New<FieldRepresentationDependency>(owner, descriptor,
659 details.representation());
660 }
661
662 CompilationDependency const*
FieldTypeDependencyOffTheRecord(const MapRef & map,InternalIndex descriptor) const663 CompilationDependencies::FieldTypeDependencyOffTheRecord(
664 const MapRef& map, InternalIndex descriptor) const {
665 MapRef owner = map.FindFieldOwner(descriptor);
666 ObjectRef type = owner.GetFieldType(descriptor);
667 DCHECK(type.equals(map.GetFieldType(descriptor)));
668 return zone_->New<FieldTypeDependency>(owner, descriptor, type);
669 }
670
671 } // namespace compiler
672 } // namespace internal
673 } // namespace v8
674