• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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 #ifndef V8_OBJECTS_ALLOCATION_SITE_INL_H_
6 #define V8_OBJECTS_ALLOCATION_SITE_INL_H_
7 
8 #include "src/objects/allocation-site.h"
9 
10 #include "src/heap/heap-write-barrier-inl.h"
11 #include "src/objects/js-objects-inl.h"
12 
13 // Has to be the last include (doesn't have include guards):
14 #include "src/objects/object-macros.h"
15 
16 namespace v8 {
17 namespace internal {
18 
19 #include "torque-generated/src/objects/allocation-site-tq-inl.inc"
20 
21 TQ_OBJECT_CONSTRUCTORS_IMPL(AllocationMemento)
OBJECT_CONSTRUCTORS_IMPL(AllocationSite,Struct)22 OBJECT_CONSTRUCTORS_IMPL(AllocationSite, Struct)
23 
24 NEVER_READ_ONLY_SPACE_IMPL(AllocationSite)
25 
26 CAST_ACCESSOR(AllocationSite)
27 
28 ACCESSORS(AllocationSite, transition_info_or_boilerplate, Object,
29           kTransitionInfoOrBoilerplateOffset)
30 ACCESSORS(AllocationSite, nested_site, Object, kNestedSiteOffset)
31 INT32_ACCESSORS(AllocationSite, pretenure_data, kPretenureDataOffset)
32 INT32_ACCESSORS(AllocationSite, pretenure_create_count,
33                 kPretenureCreateCountOffset)
34 ACCESSORS(AllocationSite, dependent_code, DependentCode, kDependentCodeOffset)
35 ACCESSORS_CHECKED(AllocationSite, weak_next, Object, kWeakNextOffset,
36                   HasWeakNext())
37 ACCESSORS(AllocationMemento, allocation_site, Object, kAllocationSiteOffset)
38 
39 JSObject AllocationSite::boilerplate() const {
40   DCHECK(PointsToLiteral());
41   return JSObject::cast(transition_info_or_boilerplate());
42 }
43 
set_boilerplate(JSObject object,WriteBarrierMode mode)44 void AllocationSite::set_boilerplate(JSObject object, WriteBarrierMode mode) {
45   set_transition_info_or_boilerplate(object, mode);
46 }
47 
transition_info()48 int AllocationSite::transition_info() const {
49   DCHECK(!PointsToLiteral());
50   return Smi::cast(transition_info_or_boilerplate()).value();
51 }
52 
set_transition_info(int value)53 void AllocationSite::set_transition_info(int value) {
54   DCHECK(!PointsToLiteral());
55   set_transition_info_or_boilerplate(Smi::FromInt(value), SKIP_WRITE_BARRIER);
56 }
57 
HasWeakNext()58 bool AllocationSite::HasWeakNext() const {
59   return map() == GetReadOnlyRoots().allocation_site_map();
60 }
61 
Initialize()62 void AllocationSite::Initialize() {
63   set_transition_info_or_boilerplate(Smi::zero());
64   SetElementsKind(GetInitialFastElementsKind());
65   set_nested_site(Smi::zero());
66   set_pretenure_data(0);
67   set_pretenure_create_count(0);
68   set_dependent_code(
69       DependentCode::cast(GetReadOnlyRoots().empty_weak_fixed_array()),
70       SKIP_WRITE_BARRIER);
71 }
72 
IsZombie()73 bool AllocationSite::IsZombie() const {
74   return pretenure_decision() == kZombie;
75 }
76 
IsMaybeTenure()77 bool AllocationSite::IsMaybeTenure() const {
78   return pretenure_decision() == kMaybeTenure;
79 }
80 
PretenuringDecisionMade()81 bool AllocationSite::PretenuringDecisionMade() const {
82   return pretenure_decision() != kUndecided;
83 }
84 
MarkZombie()85 void AllocationSite::MarkZombie() {
86   DCHECK(!IsZombie());
87   Initialize();
88   set_pretenure_decision(kZombie);
89 }
90 
GetElementsKind()91 ElementsKind AllocationSite::GetElementsKind() const {
92   return ElementsKindBits::decode(transition_info());
93 }
94 
SetElementsKind(ElementsKind kind)95 void AllocationSite::SetElementsKind(ElementsKind kind) {
96   set_transition_info(ElementsKindBits::update(transition_info(), kind));
97 }
98 
CanInlineCall()99 bool AllocationSite::CanInlineCall() const {
100   return DoNotInlineBit::decode(transition_info()) == 0;
101 }
102 
SetDoNotInlineCall()103 void AllocationSite::SetDoNotInlineCall() {
104   set_transition_info(DoNotInlineBit::update(transition_info(), true));
105 }
106 
PointsToLiteral()107 bool AllocationSite::PointsToLiteral() const {
108   Object raw_value = transition_info_or_boilerplate();
109   DCHECK_EQ(!raw_value.IsSmi(),
110             raw_value.IsJSArray() || raw_value.IsJSObject());
111   return !raw_value.IsSmi();
112 }
113 
114 // Heuristic: We only need to create allocation site info if the boilerplate
115 // elements kind is the initial elements kind.
ShouldTrack(ElementsKind boilerplate_elements_kind)116 bool AllocationSite::ShouldTrack(ElementsKind boilerplate_elements_kind) {
117   return IsSmiElementsKind(boilerplate_elements_kind);
118 }
119 
CanTrack(InstanceType type)120 inline bool AllocationSite::CanTrack(InstanceType type) {
121   if (FLAG_allocation_site_pretenuring) {
122     // TurboFan doesn't care at all about String pretenuring feedback,
123     // so don't bother even trying to track that.
124     return type == JS_ARRAY_TYPE || type == JS_OBJECT_TYPE;
125   }
126   return type == JS_ARRAY_TYPE;
127 }
128 
pretenure_decision()129 AllocationSite::PretenureDecision AllocationSite::pretenure_decision() const {
130   return PretenureDecisionBits::decode(pretenure_data());
131 }
132 
set_pretenure_decision(PretenureDecision decision)133 void AllocationSite::set_pretenure_decision(PretenureDecision decision) {
134   int32_t value = pretenure_data();
135   set_pretenure_data(PretenureDecisionBits::update(value, decision));
136 }
137 
deopt_dependent_code()138 bool AllocationSite::deopt_dependent_code() const {
139   return DeoptDependentCodeBit::decode(pretenure_data());
140 }
141 
set_deopt_dependent_code(bool deopt)142 void AllocationSite::set_deopt_dependent_code(bool deopt) {
143   int32_t value = pretenure_data();
144   set_pretenure_data(DeoptDependentCodeBit::update(value, deopt));
145 }
146 
memento_found_count()147 int AllocationSite::memento_found_count() const {
148   return MementoFoundCountBits::decode(pretenure_data());
149 }
150 
set_memento_found_count(int count)151 inline void AllocationSite::set_memento_found_count(int count) {
152   int32_t value = pretenure_data();
153   // Verify that we can count more mementos than we can possibly find in one
154   // new space collection.
155   DCHECK((GetHeap()->MaxSemiSpaceSize() /
156           (Heap::kMinObjectSizeInTaggedWords * kTaggedSize +
157            AllocationMemento::kSize)) < MementoFoundCountBits::kMax);
158   DCHECK_LT(count, MementoFoundCountBits::kMax);
159   set_pretenure_data(MementoFoundCountBits::update(value, count));
160 }
161 
memento_create_count()162 int AllocationSite::memento_create_count() const {
163   return pretenure_create_count();
164 }
165 
set_memento_create_count(int count)166 void AllocationSite::set_memento_create_count(int count) {
167   set_pretenure_create_count(count);
168 }
169 
IncrementMementoFoundCount(int increment)170 bool AllocationSite::IncrementMementoFoundCount(int increment) {
171   if (IsZombie()) return false;
172 
173   int value = memento_found_count();
174   set_memento_found_count(value + increment);
175   return memento_found_count() >= kPretenureMinimumCreated;
176 }
177 
IncrementMementoCreateCount()178 inline void AllocationSite::IncrementMementoCreateCount() {
179   DCHECK(FLAG_allocation_site_pretenuring);
180   int value = memento_create_count();
181   set_memento_create_count(value + 1);
182 }
183 
IsValid()184 bool AllocationMemento::IsValid() const {
185   return allocation_site().IsAllocationSite() &&
186          !AllocationSite::cast(allocation_site()).IsZombie();
187 }
188 
GetAllocationSite()189 AllocationSite AllocationMemento::GetAllocationSite() const {
190   DCHECK(IsValid());
191   return AllocationSite::cast(allocation_site());
192 }
193 
GetAllocationSiteUnchecked()194 Address AllocationMemento::GetAllocationSiteUnchecked() const {
195   return allocation_site().ptr();
196 }
197 
198 template <AllocationSiteUpdateMode update_or_check>
DigestTransitionFeedback(Handle<AllocationSite> site,ElementsKind to_kind)199 bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
200                                               ElementsKind to_kind) {
201   Isolate* isolate = site->GetIsolate();
202   bool result = false;
203 
204   if (site->PointsToLiteral() && site->boilerplate().IsJSArray()) {
205     Handle<JSArray> boilerplate(JSArray::cast(site->boilerplate()), isolate);
206     ElementsKind kind = boilerplate->GetElementsKind();
207     // if kind is holey ensure that to_kind is as well.
208     if (IsHoleyElementsKind(kind)) {
209       to_kind = GetHoleyElementsKind(to_kind);
210     }
211     if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
212       // If the array is huge, it's not likely to be defined in a local
213       // function, so we shouldn't make new instances of it very often.
214       uint32_t length = 0;
215       CHECK(boilerplate->length().ToArrayLength(&length));
216       if (length <= kMaximumArrayBytesToPretransition) {
217         if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) {
218           return true;
219         }
220         if (FLAG_trace_track_allocation_sites) {
221           bool is_nested = site->IsNested();
222           PrintF("AllocationSite: JSArray %p boilerplate %supdated %s->%s\n",
223                  reinterpret_cast<void*>(site->ptr()),
224                  is_nested ? "(nested)" : " ", ElementsKindToString(kind),
225                  ElementsKindToString(to_kind));
226         }
227         JSObject::TransitionElementsKind(boilerplate, to_kind);
228         site->dependent_code().DeoptimizeDependentCodeGroup(
229             DependentCode::kAllocationSiteTransitionChangedGroup);
230         result = true;
231       }
232     }
233   } else {
234     // The AllocationSite is for a constructed Array.
235     ElementsKind kind = site->GetElementsKind();
236     // if kind is holey ensure that to_kind is as well.
237     if (IsHoleyElementsKind(kind)) {
238       to_kind = GetHoleyElementsKind(to_kind);
239     }
240     if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
241       if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true;
242       if (FLAG_trace_track_allocation_sites) {
243         PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
244                reinterpret_cast<void*>(site->ptr()), ElementsKindToString(kind),
245                ElementsKindToString(to_kind));
246       }
247       site->SetElementsKind(to_kind);
248       site->dependent_code().DeoptimizeDependentCodeGroup(
249           DependentCode::kAllocationSiteTransitionChangedGroup);
250       result = true;
251     }
252   }
253   return result;
254 }
255 
256 }  // namespace internal
257 }  // namespace v8
258 
259 #include "src/objects/object-macros-undef.h"
260 
261 #endif  // V8_OBJECTS_ALLOCATION_SITE_INL_H_
262