| // Copyright 2015 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/compiler/compilation-dependencies.h" |
| |
| #include "src/compiler/compilation-dependency.h" |
| #include "src/execution/protectors.h" |
| #include "src/handles/handles-inl.h" |
| #include "src/objects/allocation-site-inl.h" |
| #include "src/objects/js-function-inl.h" |
| #include "src/objects/objects-inl.h" |
| #include "src/zone/zone-handle-set.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace compiler { |
| |
| CompilationDependencies::CompilationDependencies(JSHeapBroker* broker, |
| Zone* zone) |
| : zone_(zone), broker_(broker), dependencies_(zone) {} |
| |
| class InitialMapDependency final : public CompilationDependency { |
| public: |
| // TODO(neis): Once the concurrent compiler frontend is always-on, we no |
| // longer need to explicitly store the initial map. |
| InitialMapDependency(const JSFunctionRef& function, const MapRef& initial_map) |
| : function_(function), initial_map_(initial_map) { |
| DCHECK(function_.has_initial_map()); |
| DCHECK(function_.initial_map().equals(initial_map_)); |
| } |
| |
| bool IsValid() const override { |
| Handle<JSFunction> function = function_.object(); |
| return function->has_initial_map() && |
| function->initial_map() == *initial_map_.object(); |
| } |
| |
| void Install(const MaybeObjectHandle& code) const override { |
| SLOW_DCHECK(IsValid()); |
| DependentCode::InstallDependency(function_.isolate(), code, |
| initial_map_.object(), |
| DependentCode::kInitialMapChangedGroup); |
| } |
| |
| private: |
| JSFunctionRef function_; |
| MapRef initial_map_; |
| }; |
| |
| class PrototypePropertyDependency final : public CompilationDependency { |
| public: |
| // TODO(neis): Once the concurrent compiler frontend is always-on, we no |
| // longer need to explicitly store the prototype. |
| PrototypePropertyDependency(const JSFunctionRef& function, |
| const ObjectRef& prototype) |
| : function_(function), prototype_(prototype) { |
| DCHECK(function_.has_prototype()); |
| DCHECK(!function_.PrototypeRequiresRuntimeLookup()); |
| DCHECK(function_.prototype().equals(prototype_)); |
| } |
| |
| bool IsValid() const override { |
| Handle<JSFunction> function = function_.object(); |
| return function->has_prototype_slot() && function->has_prototype() && |
| !function->PrototypeRequiresRuntimeLookup() && |
| function->prototype() == *prototype_.object(); |
| } |
| |
| void PrepareInstall() const override { |
| SLOW_DCHECK(IsValid()); |
| Handle<JSFunction> function = function_.object(); |
| if (!function->has_initial_map()) JSFunction::EnsureHasInitialMap(function); |
| } |
| |
| void Install(const MaybeObjectHandle& code) const override { |
| SLOW_DCHECK(IsValid()); |
| Handle<JSFunction> function = function_.object(); |
| DCHECK(function->has_initial_map()); |
| Handle<Map> initial_map(function->initial_map(), function_.isolate()); |
| DependentCode::InstallDependency(function_.isolate(), code, initial_map, |
| DependentCode::kInitialMapChangedGroup); |
| } |
| |
| private: |
| JSFunctionRef function_; |
| ObjectRef prototype_; |
| }; |
| |
| class StableMapDependency final : public CompilationDependency { |
| public: |
| explicit StableMapDependency(const MapRef& map) : map_(map) { |
| DCHECK(map_.is_stable()); |
| } |
| |
| bool IsValid() const override { return map_.object()->is_stable(); } |
| |
| void Install(const MaybeObjectHandle& code) const override { |
| SLOW_DCHECK(IsValid()); |
| DependentCode::InstallDependency(map_.isolate(), code, map_.object(), |
| DependentCode::kPrototypeCheckGroup); |
| } |
| |
| private: |
| MapRef map_; |
| }; |
| |
| class TransitionDependency final : public CompilationDependency { |
| public: |
| explicit TransitionDependency(const MapRef& map) : map_(map) { |
| DCHECK(!map_.is_deprecated()); |
| } |
| |
| bool IsValid() const override { return !map_.object()->is_deprecated(); } |
| |
| void Install(const MaybeObjectHandle& code) const override { |
| SLOW_DCHECK(IsValid()); |
| DependentCode::InstallDependency(map_.isolate(), code, map_.object(), |
| DependentCode::kTransitionGroup); |
| } |
| |
| private: |
| MapRef map_; |
| }; |
| |
| class PretenureModeDependency final : public CompilationDependency { |
| public: |
| // TODO(neis): Once the concurrent compiler frontend is always-on, we no |
| // longer need to explicitly store the mode. |
| PretenureModeDependency(const AllocationSiteRef& site, |
| AllocationType allocation) |
| : site_(site), allocation_(allocation) { |
| DCHECK_EQ(allocation, site_.GetAllocationType()); |
| } |
| |
| bool IsValid() const override { |
| return allocation_ == site_.object()->GetAllocationType(); |
| } |
| |
| void Install(const MaybeObjectHandle& code) const override { |
| SLOW_DCHECK(IsValid()); |
| DependentCode::InstallDependency( |
| site_.isolate(), code, site_.object(), |
| DependentCode::kAllocationSiteTenuringChangedGroup); |
| } |
| |
| #ifdef DEBUG |
| bool IsPretenureModeDependency() const override { return true; } |
| #endif |
| |
| private: |
| AllocationSiteRef site_; |
| AllocationType allocation_; |
| }; |
| |
| class FieldRepresentationDependency final : public CompilationDependency { |
| public: |
| // TODO(neis): Once the concurrent compiler frontend is always-on, we no |
| // longer need to explicitly store the representation. |
| FieldRepresentationDependency(const MapRef& owner, InternalIndex descriptor, |
| Representation representation) |
| : owner_(owner), |
| descriptor_(descriptor), |
| representation_(representation) { |
| DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_))); |
| DCHECK(representation_.Equals( |
| owner_.GetPropertyDetails(descriptor_).representation())); |
| } |
| |
| bool IsValid() const override { |
| DisallowHeapAllocation no_heap_allocation; |
| Handle<Map> owner = owner_.object(); |
| return representation_.Equals(owner->instance_descriptors(kRelaxedLoad) |
| .GetDetails(descriptor_) |
| .representation()); |
| } |
| |
| void Install(const MaybeObjectHandle& code) const override { |
| SLOW_DCHECK(IsValid()); |
| DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(), |
| DependentCode::kFieldRepresentationGroup); |
| } |
| |
| #ifdef DEBUG |
| bool IsFieldRepresentationDependencyOnMap( |
| Handle<Map> const& receiver_map) const override { |
| return owner_.object().equals(receiver_map); |
| } |
| #endif |
| |
| private: |
| MapRef owner_; |
| InternalIndex descriptor_; |
| Representation representation_; |
| }; |
| |
| class FieldTypeDependency final : public CompilationDependency { |
| public: |
| // TODO(neis): Once the concurrent compiler frontend is always-on, we no |
| // longer need to explicitly store the type. |
| FieldTypeDependency(const MapRef& owner, InternalIndex descriptor, |
| const ObjectRef& type) |
| : owner_(owner), descriptor_(descriptor), type_(type) { |
| DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_))); |
| DCHECK(type_.equals(owner_.GetFieldType(descriptor_))); |
| } |
| |
| bool IsValid() const override { |
| DisallowHeapAllocation no_heap_allocation; |
| Handle<Map> owner = owner_.object(); |
| Handle<Object> type = type_.object(); |
| return *type == |
| owner->instance_descriptors(kRelaxedLoad).GetFieldType(descriptor_); |
| } |
| |
| void Install(const MaybeObjectHandle& code) const override { |
| SLOW_DCHECK(IsValid()); |
| DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(), |
| DependentCode::kFieldTypeGroup); |
| } |
| |
| private: |
| MapRef owner_; |
| InternalIndex descriptor_; |
| ObjectRef type_; |
| }; |
| |
| class FieldConstnessDependency final : public CompilationDependency { |
| public: |
| FieldConstnessDependency(const MapRef& owner, InternalIndex descriptor) |
| : owner_(owner), descriptor_(descriptor) { |
| DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_))); |
| DCHECK_EQ(PropertyConstness::kConst, |
| owner_.GetPropertyDetails(descriptor_).constness()); |
| } |
| |
| bool IsValid() const override { |
| DisallowHeapAllocation no_heap_allocation; |
| Handle<Map> owner = owner_.object(); |
| return PropertyConstness::kConst == |
| owner->instance_descriptors(kRelaxedLoad) |
| .GetDetails(descriptor_) |
| .constness(); |
| } |
| |
| void Install(const MaybeObjectHandle& code) const override { |
| SLOW_DCHECK(IsValid()); |
| DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(), |
| DependentCode::kFieldConstGroup); |
| } |
| |
| private: |
| MapRef owner_; |
| InternalIndex descriptor_; |
| }; |
| |
| class GlobalPropertyDependency final : public CompilationDependency { |
| public: |
| // TODO(neis): Once the concurrent compiler frontend is always-on, we no |
| // longer need to explicitly store the type and the read_only flag. |
| GlobalPropertyDependency(const PropertyCellRef& cell, PropertyCellType type, |
| bool read_only) |
| : cell_(cell), type_(type), read_only_(read_only) { |
| DCHECK_EQ(type_, cell_.property_details().cell_type()); |
| DCHECK_EQ(read_only_, cell_.property_details().IsReadOnly()); |
| } |
| |
| bool IsValid() const override { |
| Handle<PropertyCell> cell = cell_.object(); |
| // The dependency is never valid if the cell is 'invalidated'. This is |
| // marked by setting the value to the hole. |
| if (cell->value() == *(cell_.isolate()->factory()->the_hole_value())) { |
| DCHECK(cell->property_details().cell_type() == |
| PropertyCellType::kInvalidated || |
| cell->property_details().cell_type() == |
| PropertyCellType::kUninitialized); |
| return false; |
| } |
| return type_ == cell->property_details().cell_type() && |
| read_only_ == cell->property_details().IsReadOnly(); |
| } |
| |
| void Install(const MaybeObjectHandle& code) const override { |
| SLOW_DCHECK(IsValid()); |
| DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(), |
| DependentCode::kPropertyCellChangedGroup); |
| } |
| |
| private: |
| PropertyCellRef cell_; |
| PropertyCellType type_; |
| bool read_only_; |
| }; |
| |
| class ProtectorDependency final : public CompilationDependency { |
| public: |
| explicit ProtectorDependency(const PropertyCellRef& cell) : cell_(cell) { |
| DCHECK_EQ(cell_.value().AsSmi(), Protectors::kProtectorValid); |
| } |
| |
| bool IsValid() const override { |
| Handle<PropertyCell> cell = cell_.object(); |
| return cell->value() == Smi::FromInt(Protectors::kProtectorValid); |
| } |
| |
| void Install(const MaybeObjectHandle& code) const override { |
| SLOW_DCHECK(IsValid()); |
| DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(), |
| DependentCode::kPropertyCellChangedGroup); |
| } |
| |
| private: |
| PropertyCellRef cell_; |
| }; |
| |
| class ElementsKindDependency final : public CompilationDependency { |
| public: |
| // TODO(neis): Once the concurrent compiler frontend is always-on, we no |
| // longer need to explicitly store the elements kind. |
| ElementsKindDependency(const AllocationSiteRef& site, ElementsKind kind) |
| : site_(site), kind_(kind) { |
| DCHECK(AllocationSite::ShouldTrack(kind_)); |
| DCHECK_EQ(kind_, site_.PointsToLiteral() |
| ? site_.boilerplate().value().GetElementsKind() |
| : site_.GetElementsKind()); |
| } |
| |
| bool IsValid() const override { |
| Handle<AllocationSite> site = site_.object(); |
| ElementsKind kind = site->PointsToLiteral() |
| ? site->boilerplate().GetElementsKind() |
| : site->GetElementsKind(); |
| return kind_ == kind; |
| } |
| |
| void Install(const MaybeObjectHandle& code) const override { |
| SLOW_DCHECK(IsValid()); |
| DependentCode::InstallDependency( |
| site_.isolate(), code, site_.object(), |
| DependentCode::kAllocationSiteTransitionChangedGroup); |
| } |
| |
| private: |
| AllocationSiteRef site_; |
| ElementsKind kind_; |
| }; |
| |
| class InitialMapInstanceSizePredictionDependency final |
| : public CompilationDependency { |
| public: |
| InitialMapInstanceSizePredictionDependency(const JSFunctionRef& function, |
| int instance_size) |
| : function_(function), instance_size_(instance_size) {} |
| |
| bool IsValid() const override { |
| // The dependency is valid if the prediction is the same as the current |
| // slack tracking result. |
| if (!function_.object()->has_initial_map()) return false; |
| int instance_size = function_.object()->ComputeInstanceSizeWithMinSlack( |
| function_.isolate()); |
| return instance_size == instance_size_; |
| } |
| |
| void PrepareInstall() const override { |
| SLOW_DCHECK(IsValid()); |
| function_.object()->CompleteInobjectSlackTrackingIfActive(); |
| } |
| |
| void Install(const MaybeObjectHandle& code) const override { |
| SLOW_DCHECK(IsValid()); |
| DCHECK( |
| !function_.object()->initial_map().IsInobjectSlackTrackingInProgress()); |
| } |
| |
| private: |
| JSFunctionRef function_; |
| int instance_size_; |
| }; |
| |
| void CompilationDependencies::RecordDependency( |
| CompilationDependency const* dependency) { |
| if (dependency != nullptr) dependencies_.push_front(dependency); |
| } |
| |
| MapRef CompilationDependencies::DependOnInitialMap( |
| const JSFunctionRef& function) { |
| MapRef map = function.initial_map(); |
| RecordDependency(zone_->New<InitialMapDependency>(function, map)); |
| return map; |
| } |
| |
| ObjectRef CompilationDependencies::DependOnPrototypeProperty( |
| const JSFunctionRef& function) { |
| ObjectRef prototype = function.prototype(); |
| RecordDependency( |
| zone_->New<PrototypePropertyDependency>(function, prototype)); |
| return prototype; |
| } |
| |
| void CompilationDependencies::DependOnStableMap(const MapRef& map) { |
| if (map.CanTransition()) { |
| RecordDependency(zone_->New<StableMapDependency>(map)); |
| } else { |
| DCHECK(map.is_stable()); |
| } |
| } |
| |
| void CompilationDependencies::DependOnTransition(const MapRef& target_map) { |
| RecordDependency(TransitionDependencyOffTheRecord(target_map)); |
| } |
| |
| AllocationType CompilationDependencies::DependOnPretenureMode( |
| const AllocationSiteRef& site) { |
| AllocationType allocation = site.GetAllocationType(); |
| RecordDependency(zone_->New<PretenureModeDependency>(site, allocation)); |
| return allocation; |
| } |
| |
| PropertyConstness CompilationDependencies::DependOnFieldConstness( |
| const MapRef& map, InternalIndex descriptor) { |
| MapRef owner = map.FindFieldOwner(descriptor); |
| PropertyConstness constness = |
| owner.GetPropertyDetails(descriptor).constness(); |
| if (constness == PropertyConstness::kMutable) return constness; |
| |
| // If the map can have fast elements transitions, then the field can be only |
| // considered constant if the map does not transition. |
| if (Map::CanHaveFastTransitionableElementsKind(map.instance_type())) { |
| // If the map can already transition away, let us report the field as |
| // mutable. |
| if (!map.is_stable()) { |
| return PropertyConstness::kMutable; |
| } |
| DependOnStableMap(map); |
| } |
| |
| DCHECK_EQ(constness, PropertyConstness::kConst); |
| RecordDependency(zone_->New<FieldConstnessDependency>(owner, descriptor)); |
| return PropertyConstness::kConst; |
| } |
| |
| void CompilationDependencies::DependOnFieldRepresentation( |
| const MapRef& map, InternalIndex descriptor) { |
| RecordDependency(FieldRepresentationDependencyOffTheRecord(map, descriptor)); |
| } |
| |
| void CompilationDependencies::DependOnFieldType(const MapRef& map, |
| InternalIndex descriptor) { |
| RecordDependency(FieldTypeDependencyOffTheRecord(map, descriptor)); |
| } |
| |
| void CompilationDependencies::DependOnGlobalProperty( |
| const PropertyCellRef& cell) { |
| PropertyCellType type = cell.property_details().cell_type(); |
| bool read_only = cell.property_details().IsReadOnly(); |
| RecordDependency(zone_->New<GlobalPropertyDependency>(cell, type, read_only)); |
| } |
| |
| bool CompilationDependencies::DependOnProtector(const PropertyCellRef& cell) { |
| if (cell.value().AsSmi() != Protectors::kProtectorValid) return false; |
| RecordDependency(zone_->New<ProtectorDependency>(cell)); |
| return true; |
| } |
| |
| bool CompilationDependencies::DependOnArrayBufferDetachingProtector() { |
| return DependOnProtector(PropertyCellRef( |
| broker_, |
| broker_->isolate()->factory()->array_buffer_detaching_protector())); |
| } |
| |
| bool CompilationDependencies::DependOnArrayIteratorProtector() { |
| return DependOnProtector(PropertyCellRef( |
| broker_, broker_->isolate()->factory()->array_iterator_protector())); |
| } |
| |
| bool CompilationDependencies::DependOnArraySpeciesProtector() { |
| return DependOnProtector(PropertyCellRef( |
| broker_, broker_->isolate()->factory()->array_species_protector())); |
| } |
| |
| bool CompilationDependencies::DependOnNoElementsProtector() { |
| return DependOnProtector(PropertyCellRef( |
| broker_, broker_->isolate()->factory()->no_elements_protector())); |
| } |
| |
| bool CompilationDependencies::DependOnPromiseHookProtector() { |
| return DependOnProtector(PropertyCellRef( |
| broker_, broker_->isolate()->factory()->promise_hook_protector())); |
| } |
| |
| bool CompilationDependencies::DependOnPromiseSpeciesProtector() { |
| return DependOnProtector(PropertyCellRef( |
| broker_, broker_->isolate()->factory()->promise_species_protector())); |
| } |
| |
| bool CompilationDependencies::DependOnPromiseThenProtector() { |
| return DependOnProtector(PropertyCellRef( |
| broker_, broker_->isolate()->factory()->promise_then_protector())); |
| } |
| |
| void CompilationDependencies::DependOnElementsKind( |
| const AllocationSiteRef& site) { |
| // Do nothing if the object doesn't have any useful element transitions left. |
| ElementsKind kind = site.PointsToLiteral() |
| ? site.boilerplate().value().GetElementsKind() |
| : site.GetElementsKind(); |
| if (AllocationSite::ShouldTrack(kind)) { |
| RecordDependency(zone_->New<ElementsKindDependency>(site, kind)); |
| } |
| } |
| |
| bool CompilationDependencies::AreValid() const { |
| for (auto dep : dependencies_) { |
| if (!dep->IsValid()) return false; |
| } |
| return true; |
| } |
| |
| bool CompilationDependencies::Commit(Handle<Code> code) { |
| // Dependencies are context-dependent. In the future it may be possible to |
| // restore them in the consumer native context, but for now they are |
| // disabled. |
| CHECK_IMPLIES(broker_->is_native_context_independent(), |
| dependencies_.empty()); |
| |
| for (auto dep : dependencies_) { |
| if (!dep->IsValid()) { |
| dependencies_.clear(); |
| return false; |
| } |
| dep->PrepareInstall(); |
| } |
| |
| DisallowCodeDependencyChange no_dependency_change; |
| for (auto dep : dependencies_) { |
| // Check each dependency's validity again right before installing it, |
| // because the first iteration above might have invalidated some |
| // dependencies. For example, PrototypePropertyDependency::PrepareInstall |
| // can call EnsureHasInitialMap, which can invalidate a StableMapDependency |
| // on the prototype object's map. |
| if (!dep->IsValid()) { |
| dependencies_.clear(); |
| return false; |
| } |
| dep->Install(MaybeObjectHandle::Weak(code)); |
| } |
| |
| // It is even possible that a GC during the above installations invalidated |
| // one of the dependencies. However, this should only affect pretenure mode |
| // dependencies, which we assert below. It is safe to return successfully in |
| // these cases, because once the code gets executed it will do a stack check |
| // that triggers its deoptimization. |
| if (FLAG_stress_gc_during_compilation) { |
| broker_->isolate()->heap()->PreciseCollectAllGarbage( |
| Heap::kForcedGC, GarbageCollectionReason::kTesting, kNoGCCallbackFlags); |
| } |
| #ifdef DEBUG |
| for (auto dep : dependencies_) { |
| CHECK_IMPLIES(!dep->IsValid(), dep->IsPretenureModeDependency()); |
| } |
| #endif |
| |
| dependencies_.clear(); |
| return true; |
| } |
| |
| namespace { |
| // This function expects to never see a JSProxy. |
| void DependOnStablePrototypeChain(CompilationDependencies* deps, MapRef map, |
| base::Optional<JSObjectRef> last_prototype) { |
| while (true) { |
| HeapObjectRef proto = map.prototype(); |
| if (!proto.IsJSObject()) { |
| CHECK_EQ(proto.map().oddball_type(), OddballType::kNull); |
| break; |
| } |
| map = proto.map(); |
| deps->DependOnStableMap(map); |
| if (last_prototype.has_value() && proto.equals(*last_prototype)) break; |
| } |
| } |
| } // namespace |
| |
| template <class MapContainer> |
| void CompilationDependencies::DependOnStablePrototypeChains( |
| MapContainer const& receiver_maps, WhereToStart start, |
| base::Optional<JSObjectRef> last_prototype) { |
| for (auto map : receiver_maps) { |
| MapRef receiver_map(broker_, map); |
| if (start == kStartAtReceiver) DependOnStableMap(receiver_map); |
| if (receiver_map.IsPrimitiveMap()) { |
| // Perform the implicit ToObject for primitives here. |
| // Implemented according to ES6 section 7.3.2 GetV (V, P). |
| base::Optional<JSFunctionRef> constructor = |
| broker_->target_native_context().GetConstructorFunction(receiver_map); |
| if (constructor.has_value()) receiver_map = constructor->initial_map(); |
| } |
| DependOnStablePrototypeChain(this, receiver_map, last_prototype); |
| } |
| } |
| template void CompilationDependencies::DependOnStablePrototypeChains( |
| ZoneVector<Handle<Map>> const& receiver_maps, WhereToStart start, |
| base::Optional<JSObjectRef> last_prototype); |
| template void CompilationDependencies::DependOnStablePrototypeChains( |
| ZoneHandleSet<Map> const& receiver_maps, WhereToStart start, |
| base::Optional<JSObjectRef> last_prototype); |
| |
| void CompilationDependencies::DependOnElementsKinds( |
| const AllocationSiteRef& site) { |
| AllocationSiteRef current = site; |
| while (true) { |
| DependOnElementsKind(current); |
| if (!current.nested_site().IsAllocationSite()) break; |
| current = current.nested_site().AsAllocationSite(); |
| } |
| CHECK_EQ(current.nested_site().AsSmi(), 0); |
| } |
| |
| SlackTrackingPrediction::SlackTrackingPrediction(MapRef initial_map, |
| int instance_size) |
| : instance_size_(instance_size), |
| inobject_property_count_( |
| (instance_size >> kTaggedSizeLog2) - |
| initial_map.GetInObjectPropertiesStartInWords()) {} |
| |
| SlackTrackingPrediction |
| CompilationDependencies::DependOnInitialMapInstanceSizePrediction( |
| const JSFunctionRef& function) { |
| MapRef initial_map = DependOnInitialMap(function); |
| int instance_size = function.InitialMapInstanceSizeWithMinSlack(); |
| // Currently, we always install the prediction dependency. If this turns out |
| // to be too expensive, we can only install the dependency if slack |
| // tracking is active. |
| RecordDependency(zone_->New<InitialMapInstanceSizePredictionDependency>( |
| function, instance_size)); |
| DCHECK_LE(instance_size, function.initial_map().instance_size()); |
| return SlackTrackingPrediction(initial_map, instance_size); |
| } |
| |
| CompilationDependency const* |
| CompilationDependencies::TransitionDependencyOffTheRecord( |
| const MapRef& target_map) const { |
| if (target_map.CanBeDeprecated()) { |
| return zone_->New<TransitionDependency>(target_map); |
| } else { |
| DCHECK(!target_map.is_deprecated()); |
| return nullptr; |
| } |
| } |
| |
| CompilationDependency const* |
| CompilationDependencies::FieldRepresentationDependencyOffTheRecord( |
| const MapRef& map, InternalIndex descriptor) const { |
| MapRef owner = map.FindFieldOwner(descriptor); |
| PropertyDetails details = owner.GetPropertyDetails(descriptor); |
| DCHECK(details.representation().Equals( |
| map.GetPropertyDetails(descriptor).representation())); |
| return zone_->New<FieldRepresentationDependency>(owner, descriptor, |
| details.representation()); |
| } |
| |
| CompilationDependency const* |
| CompilationDependencies::FieldTypeDependencyOffTheRecord( |
| const MapRef& map, InternalIndex descriptor) const { |
| MapRef owner = map.FindFieldOwner(descriptor); |
| ObjectRef type = owner.GetFieldType(descriptor); |
| DCHECK(type.equals(map.GetFieldType(descriptor))); |
| return zone_->New<FieldTypeDependency>(owner, descriptor, type); |
| } |
| |
| } // namespace compiler |
| } // namespace internal |
| } // namespace v8 |