| // Copyright 2018 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. | 
 |  | 
 | #ifndef V8_OBJECTS_ALLOCATION_SITE_INL_H_ | 
 | #define V8_OBJECTS_ALLOCATION_SITE_INL_H_ | 
 |  | 
 | #include "src/objects/allocation-site.h" | 
 |  | 
 | #include "src/heap/heap-write-barrier-inl.h" | 
 | #include "src/objects/js-objects-inl.h" | 
 |  | 
 | // Has to be the last include (doesn't have include guards): | 
 | #include "src/objects/object-macros.h" | 
 |  | 
 | namespace v8 { | 
 | namespace internal { | 
 |  | 
 | #include "torque-generated/src/objects/allocation-site-tq-inl.inc" | 
 |  | 
 | TQ_OBJECT_CONSTRUCTORS_IMPL(AllocationMemento) | 
 | OBJECT_CONSTRUCTORS_IMPL(AllocationSite, Struct) | 
 |  | 
 | NEVER_READ_ONLY_SPACE_IMPL(AllocationSite) | 
 |  | 
 | CAST_ACCESSOR(AllocationSite) | 
 |  | 
 | ACCESSORS(AllocationSite, transition_info_or_boilerplate, Object, | 
 |           kTransitionInfoOrBoilerplateOffset) | 
 | ACCESSORS(AllocationSite, nested_site, Object, kNestedSiteOffset) | 
 | INT32_ACCESSORS(AllocationSite, pretenure_data, kPretenureDataOffset) | 
 | INT32_ACCESSORS(AllocationSite, pretenure_create_count, | 
 |                 kPretenureCreateCountOffset) | 
 | ACCESSORS(AllocationSite, dependent_code, DependentCode, kDependentCodeOffset) | 
 | ACCESSORS_CHECKED(AllocationSite, weak_next, Object, kWeakNextOffset, | 
 |                   HasWeakNext()) | 
 | ACCESSORS(AllocationMemento, allocation_site, Object, kAllocationSiteOffset) | 
 |  | 
 | JSObject AllocationSite::boilerplate() const { | 
 |   DCHECK(PointsToLiteral()); | 
 |   return JSObject::cast(transition_info_or_boilerplate()); | 
 | } | 
 |  | 
 | void AllocationSite::set_boilerplate(JSObject object, WriteBarrierMode mode) { | 
 |   set_transition_info_or_boilerplate(object, mode); | 
 | } | 
 |  | 
 | int AllocationSite::transition_info() const { | 
 |   DCHECK(!PointsToLiteral()); | 
 |   return Smi::cast(transition_info_or_boilerplate()).value(); | 
 | } | 
 |  | 
 | void AllocationSite::set_transition_info(int value) { | 
 |   DCHECK(!PointsToLiteral()); | 
 |   set_transition_info_or_boilerplate(Smi::FromInt(value), SKIP_WRITE_BARRIER); | 
 | } | 
 |  | 
 | bool AllocationSite::HasWeakNext() const { | 
 |   return map() == GetReadOnlyRoots().allocation_site_map(); | 
 | } | 
 |  | 
 | void AllocationSite::Initialize() { | 
 |   set_transition_info_or_boilerplate(Smi::zero()); | 
 |   SetElementsKind(GetInitialFastElementsKind()); | 
 |   set_nested_site(Smi::zero()); | 
 |   set_pretenure_data(0); | 
 |   set_pretenure_create_count(0); | 
 |   set_dependent_code( | 
 |       DependentCode::cast(GetReadOnlyRoots().empty_weak_fixed_array()), | 
 |       SKIP_WRITE_BARRIER); | 
 | } | 
 |  | 
 | bool AllocationSite::IsZombie() const { | 
 |   return pretenure_decision() == kZombie; | 
 | } | 
 |  | 
 | bool AllocationSite::IsMaybeTenure() const { | 
 |   return pretenure_decision() == kMaybeTenure; | 
 | } | 
 |  | 
 | bool AllocationSite::PretenuringDecisionMade() const { | 
 |   return pretenure_decision() != kUndecided; | 
 | } | 
 |  | 
 | void AllocationSite::MarkZombie() { | 
 |   DCHECK(!IsZombie()); | 
 |   Initialize(); | 
 |   set_pretenure_decision(kZombie); | 
 | } | 
 |  | 
 | ElementsKind AllocationSite::GetElementsKind() const { | 
 |   return ElementsKindBits::decode(transition_info()); | 
 | } | 
 |  | 
 | void AllocationSite::SetElementsKind(ElementsKind kind) { | 
 |   set_transition_info(ElementsKindBits::update(transition_info(), kind)); | 
 | } | 
 |  | 
 | bool AllocationSite::CanInlineCall() const { | 
 |   return DoNotInlineBit::decode(transition_info()) == 0; | 
 | } | 
 |  | 
 | void AllocationSite::SetDoNotInlineCall() { | 
 |   set_transition_info(DoNotInlineBit::update(transition_info(), true)); | 
 | } | 
 |  | 
 | bool AllocationSite::PointsToLiteral() const { | 
 |   Object raw_value = transition_info_or_boilerplate(); | 
 |   DCHECK_EQ(!raw_value.IsSmi(), | 
 |             raw_value.IsJSArray() || raw_value.IsJSObject()); | 
 |   return !raw_value.IsSmi(); | 
 | } | 
 |  | 
 | // Heuristic: We only need to create allocation site info if the boilerplate | 
 | // elements kind is the initial elements kind. | 
 | bool AllocationSite::ShouldTrack(ElementsKind boilerplate_elements_kind) { | 
 |   return IsSmiElementsKind(boilerplate_elements_kind); | 
 | } | 
 |  | 
 | inline bool AllocationSite::CanTrack(InstanceType type) { | 
 |   if (FLAG_allocation_site_pretenuring) { | 
 |     // TurboFan doesn't care at all about String pretenuring feedback, | 
 |     // so don't bother even trying to track that. | 
 |     return type == JS_ARRAY_TYPE || type == JS_OBJECT_TYPE; | 
 |   } | 
 |   return type == JS_ARRAY_TYPE; | 
 | } | 
 |  | 
 | AllocationSite::PretenureDecision AllocationSite::pretenure_decision() const { | 
 |   return PretenureDecisionBits::decode(pretenure_data()); | 
 | } | 
 |  | 
 | void AllocationSite::set_pretenure_decision(PretenureDecision decision) { | 
 |   int32_t value = pretenure_data(); | 
 |   set_pretenure_data(PretenureDecisionBits::update(value, decision)); | 
 | } | 
 |  | 
 | bool AllocationSite::deopt_dependent_code() const { | 
 |   return DeoptDependentCodeBit::decode(pretenure_data()); | 
 | } | 
 |  | 
 | void AllocationSite::set_deopt_dependent_code(bool deopt) { | 
 |   int32_t value = pretenure_data(); | 
 |   set_pretenure_data(DeoptDependentCodeBit::update(value, deopt)); | 
 | } | 
 |  | 
 | int AllocationSite::memento_found_count() const { | 
 |   return MementoFoundCountBits::decode(pretenure_data()); | 
 | } | 
 |  | 
 | inline void AllocationSite::set_memento_found_count(int count) { | 
 |   int32_t value = pretenure_data(); | 
 |   // Verify that we can count more mementos than we can possibly find in one | 
 |   // new space collection. | 
 |   DCHECK((GetHeap()->MaxSemiSpaceSize() / | 
 |           (Heap::kMinObjectSizeInTaggedWords * kTaggedSize + | 
 |            AllocationMemento::kSize)) < MementoFoundCountBits::kMax); | 
 |   DCHECK_LT(count, MementoFoundCountBits::kMax); | 
 |   set_pretenure_data(MementoFoundCountBits::update(value, count)); | 
 | } | 
 |  | 
 | int AllocationSite::memento_create_count() const { | 
 |   return pretenure_create_count(); | 
 | } | 
 |  | 
 | void AllocationSite::set_memento_create_count(int count) { | 
 |   set_pretenure_create_count(count); | 
 | } | 
 |  | 
 | bool AllocationSite::IncrementMementoFoundCount(int increment) { | 
 |   if (IsZombie()) return false; | 
 |  | 
 |   int value = memento_found_count(); | 
 |   set_memento_found_count(value + increment); | 
 |   return memento_found_count() >= kPretenureMinimumCreated; | 
 | } | 
 |  | 
 | inline void AllocationSite::IncrementMementoCreateCount() { | 
 |   DCHECK(FLAG_allocation_site_pretenuring); | 
 |   int value = memento_create_count(); | 
 |   set_memento_create_count(value + 1); | 
 | } | 
 |  | 
 | bool AllocationMemento::IsValid() const { | 
 |   return allocation_site().IsAllocationSite() && | 
 |          !AllocationSite::cast(allocation_site()).IsZombie(); | 
 | } | 
 |  | 
 | AllocationSite AllocationMemento::GetAllocationSite() const { | 
 |   DCHECK(IsValid()); | 
 |   return AllocationSite::cast(allocation_site()); | 
 | } | 
 |  | 
 | Address AllocationMemento::GetAllocationSiteUnchecked() const { | 
 |   return allocation_site().ptr(); | 
 | } | 
 |  | 
 | template <AllocationSiteUpdateMode update_or_check> | 
 | bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site, | 
 |                                               ElementsKind to_kind) { | 
 |   Isolate* isolate = site->GetIsolate(); | 
 |   bool result = false; | 
 |  | 
 |   if (site->PointsToLiteral() && site->boilerplate().IsJSArray()) { | 
 |     Handle<JSArray> boilerplate(JSArray::cast(site->boilerplate()), isolate); | 
 |     ElementsKind kind = boilerplate->GetElementsKind(); | 
 |     // if kind is holey ensure that to_kind is as well. | 
 |     if (IsHoleyElementsKind(kind)) { | 
 |       to_kind = GetHoleyElementsKind(to_kind); | 
 |     } | 
 |     if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { | 
 |       // If the array is huge, it's not likely to be defined in a local | 
 |       // function, so we shouldn't make new instances of it very often. | 
 |       uint32_t length = 0; | 
 |       CHECK(boilerplate->length().ToArrayLength(&length)); | 
 |       if (length <= kMaximumArrayBytesToPretransition) { | 
 |         if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) { | 
 |           return true; | 
 |         } | 
 |         if (FLAG_trace_track_allocation_sites) { | 
 |           bool is_nested = site->IsNested(); | 
 |           PrintF("AllocationSite: JSArray %p boilerplate %supdated %s->%s\n", | 
 |                  reinterpret_cast<void*>(site->ptr()), | 
 |                  is_nested ? "(nested)" : " ", ElementsKindToString(kind), | 
 |                  ElementsKindToString(to_kind)); | 
 |         } | 
 |         JSObject::TransitionElementsKind(boilerplate, to_kind); | 
 |         site->dependent_code().DeoptimizeDependentCodeGroup( | 
 |             DependentCode::kAllocationSiteTransitionChangedGroup); | 
 |         result = true; | 
 |       } | 
 |     } | 
 |   } else { | 
 |     // The AllocationSite is for a constructed Array. | 
 |     ElementsKind kind = site->GetElementsKind(); | 
 |     // if kind is holey ensure that to_kind is as well. | 
 |     if (IsHoleyElementsKind(kind)) { | 
 |       to_kind = GetHoleyElementsKind(to_kind); | 
 |     } | 
 |     if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { | 
 |       if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true; | 
 |       if (FLAG_trace_track_allocation_sites) { | 
 |         PrintF("AllocationSite: JSArray %p site updated %s->%s\n", | 
 |                reinterpret_cast<void*>(site->ptr()), ElementsKindToString(kind), | 
 |                ElementsKindToString(to_kind)); | 
 |       } | 
 |       site->SetElementsKind(to_kind); | 
 |       site->dependent_code().DeoptimizeDependentCodeGroup( | 
 |           DependentCode::kAllocationSiteTransitionChangedGroup); | 
 |       result = true; | 
 |     } | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 | }  // namespace internal | 
 | }  // namespace v8 | 
 |  | 
 | #include "src/objects/object-macros-undef.h" | 
 |  | 
 | #endif  // V8_OBJECTS_ALLOCATION_SITE_INL_H_ |