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