v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
dependent-code.cc
Go to the documentation of this file.
1// Copyright 2023 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
6
7#include "src/base/bits.h"
11#include "src/objects/map.h"
12
13namespace v8 {
14namespace internal {
15
17 Tagged<HeapObject> object) {
18 if (IsMap(object)) {
19 return Cast<Map>(object)->dependent_code();
20 } else if (IsPropertyCell(object)) {
21 return Cast<PropertyCell>(object)->dependent_code();
22 } else if (IsAllocationSite(object)) {
23 return Cast<AllocationSite>(object)->dependent_code();
24 } else if (IsContextSidePropertyCell(object)) {
25 return Cast<ContextSidePropertyCell>(object)->dependent_code();
26 } else if (IsScopeInfo(object)) {
27 return Cast<ScopeInfo>(object)->dependent_code();
28 }
30}
31
34 if (IsMap(*object)) {
35 Cast<Map>(object)->set_dependent_code(*dep);
36 } else if (IsPropertyCell(*object)) {
37 Cast<PropertyCell>(object)->set_dependent_code(*dep);
38 } else if (IsAllocationSite(*object)) {
39 Cast<AllocationSite>(object)->set_dependent_code(*dep);
40 } else if (IsContextSidePropertyCell(*object)) {
41 Cast<ContextSidePropertyCell>(object)->set_dependent_code(*dep);
42 } else if (IsScopeInfo(*object)) {
43 Cast<ScopeInfo>(object)->set_dependent_code(*dep);
44 } else {
46 }
47}
48
49namespace {
50
51void PrintDependencyGroups(DependentCode::DependencyGroups groups) {
52 while (groups != 0) {
53 auto group = static_cast<DependentCode::DependencyGroup>(
54 1 << base::bits::CountTrailingZeros(static_cast<uint32_t>(groups)));
56 groups &= ~group;
57 if (groups != 0) StdoutStream{} << ",";
58 }
59}
60
61} // namespace
62
64 Handle<HeapObject> object,
65 DependencyGroups groups) {
66 if (V8_UNLIKELY(v8_flags.trace_compilation_dependencies)) {
67 StdoutStream{} << "Installing dependency of [" << code << "] on [" << object
68 << "] in groups [";
69 PrintDependencyGroups(groups);
70 StdoutStream{} << "]\n";
71 }
73 isolate);
75 InsertWeakCode(isolate, old_deps, groups, code);
76
77 // Update the list head if necessary.
78 if (!new_deps.is_identical_to(old_deps)) {
79 DependentCode::SetDependentCode(object, new_deps);
80 }
81}
82
85 DirectHandle<Code> code) {
86 if (entries->length() == entries->capacity()) {
87 // We'd have to grow - try to compact first.
88 entries->IterateAndCompact(
89 isolate, [](Tagged<Code>, DependencyGroups) { return false; });
90 }
91
92 // As the Code object lives outside of the sandbox in trusted space, we need
93 // to use its in-sandbox wrapper object here.
94 MaybeObjectDirectHandle code_slot(MakeWeak(code->wrapper()), isolate);
96 isolate, entries, code_slot, Smi::FromInt(groups)));
97 return entries;
98}
99
100template <typename Function>
102 const Function& fn) {
104
105 int len = length();
106 if (len == 0) return;
107
108 // We compact during traversal, thus use a somewhat custom loop construct:
109 //
110 // - Loop back-to-front s.t. trailing cleared entries can simply drop off
111 // the back of the list.
112 // - Any cleared slots are filled from the back of the list.
113 int i = len - kSlotsPerEntry;
114 while (i >= 0) {
116 if (obj.IsCleared()) {
117 len = FillEntryFromBack(i, len);
118 i -= kSlotsPerEntry;
119 continue;
120 }
121
122 if (fn(Cast<CodeWrapper>(obj.GetHeapObjectAssumeWeak())->code(isolate),
123 static_cast<DependencyGroups>(
124 Get(i + kGroupsSlotOffset).ToSmi().value()))) {
125 len = FillEntryFromBack(i, len);
126 }
127
128 i -= kSlotsPerEntry;
129 }
130
131 set_length(len);
132}
133
135 Isolate* isolate, DependentCode::DependencyGroups deopt_groups) {
137
138 bool marked_something = false;
139 IterateAndCompact(isolate, [&](Tagged<Code> code, DependencyGroups groups) {
140 if ((groups & deopt_groups) == 0) return false;
141
142 if (!code->marked_for_deoptimization()) {
143 // Pick a single group out of the applicable deopt groups, to use as the
144 // deopt reason. Only one group is reported to avoid string concatenation.
145 DependencyGroup first_group = static_cast<DependencyGroup>(
146 1 << base::bits::CountTrailingZeros32(groups & deopt_groups));
147 code->SetMarkedForDeoptimization(
148 isolate,
150 marked_something = true;
151 }
152
153 return true;
154 });
155
156 return marked_something;
157}
158
159int DependentCode::FillEntryFromBack(int index, int length) {
160 DCHECK_EQ(index % 2, 0);
161 DCHECK_EQ(length % 2, 0);
162 for (int i = length - kSlotsPerEntry; i > index; i -= kSlotsPerEntry) {
164 if (obj.IsCleared()) continue;
165
166 Set(index + kCodeSlotOffset, obj);
169 return i;
170 }
171 return index; // No non-cleared entry found.
172}
173
175 Isolate* isolate, DependentCode::DependencyGroups groups) {
176 DisallowGarbageCollection no_gc_scope;
177 bool marked_something = MarkCodeForDeoptimization(isolate, groups);
178 if (marked_something) {
179 DCHECK(AllowCodeDependencyChange::IsAllowed());
181 }
182}
183
184// static
186 const ReadOnlyRoots& roots) {
187 return Cast<DependentCode>(roots.empty_weak_array_list());
188}
189
191 switch (group) {
192 case kTransitionGroup:
193 return "transition";
195 return "prototype-check";
197 return "property-cell-changed";
198 case kFieldConstGroup:
199 return "field-const";
200 case kFieldTypeGroup:
201 return "field-type";
203 return "field-representation";
205 return "initial-map-changed";
207 return "allocation-site-tenuring-changed";
209 return "allocation-site-transition-changed";
211 return "script-context-slot-property-changed";
213 return "empty-context-extension";
214 }
215 UNREACHABLE();
216}
217
219 DependencyGroup group) {
220 switch (group) {
221 case kTransitionGroup:
222 return LazyDeoptimizeReason::kMapDeprecated;
224 return LazyDeoptimizeReason::kPrototypeChange;
226 return LazyDeoptimizeReason::kPropertyCellChange;
227 case kFieldConstGroup:
228 return LazyDeoptimizeReason::kFieldTypeConstChange;
229 case kFieldTypeGroup:
230 return LazyDeoptimizeReason::kFieldTypeChange;
232 return LazyDeoptimizeReason::kFieldRepresentationChange;
234 return LazyDeoptimizeReason::kInitialMapChange;
236 return LazyDeoptimizeReason::kAllocationSiteTenuringChange;
238 return LazyDeoptimizeReason::kAllocationSiteTransitionChange;
240 return LazyDeoptimizeReason::kScriptContextSlotPropertyChange;
242 return LazyDeoptimizeReason::kEmptyContextExtensionChange;
243 }
244 UNREACHABLE();
245}
246
247} // namespace internal
248} // namespace v8
static void DeoptimizeMarkedCode(Isolate *isolate)
static LazyDeoptimizeReason DependencyGroupToLazyDeoptReason(DependencyGroup group)
static constexpr int kCodeSlotOffset
static void SetDependentCode(DirectHandle< HeapObject > object, DirectHandle< DependentCode > dep)
int FillEntryFromBack(int index, int length)
static V8_EXPORT_PRIVATE Tagged< DependentCode > empty_dependent_code(const ReadOnlyRoots &roots)
static DirectHandle< DependentCode > InsertWeakCode(Isolate *isolate, Handle< DependentCode > entries, DependencyGroups groups, DirectHandle< Code > code)
static constexpr int kSlotsPerEntry
static const char * DependencyGroupName(DependencyGroup group)
static V8_EXPORT_PRIVATE void InstallDependency(Isolate *isolate, Handle< Code > code, Handle< HeapObject > object, DependencyGroups groups)
static constexpr int kGroupsSlotOffset
static void DeoptimizeDependencyGroups(Isolate *isolate, ObjectT object, DependencyGroups groups)
void IterateAndCompact(IsolateForSandbox isolate, const Function &fn)
static bool MarkCodeForDeoptimization(Isolate *isolate, Tagged< ObjectT > object, DependencyGroups groups)
static Tagged< DependentCode > GetDependentCode(Tagged< HeapObject > object)
V8_INLINE bool is_identical_to(Handle< S > other) const
Definition handles.h:716
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
constexpr bool IsCleared() const
Tagged< HeapObject > GetHeapObjectAssumeWeak() const
void Set(int index, Tagged< MaybeObject > value, WriteBarrierMode mode=UPDATE_WRITE_BARRIER)
NEVER_READ_ONLY_SPACE static V8_EXPORT_PRIVATE Handle< WeakArrayList > AddToEnd(Isolate *isolate, Handle< WeakArrayList > array, MaybeObjectDirectHandle value)
Tagged< MaybeObject > Get(int index) const
ZoneVector< Entry > entries
EmitFn fn
constexpr unsigned CountTrailingZeros32(uint32_t value)
Definition bits.h:161
constexpr unsigned CountTrailingZeros(T value)
Definition bits.h:144
@ SKIP_WRITE_BARRIER
Definition objects.h:52
Tagged< MaybeWeak< T > > MakeWeak(Tagged< T > value)
Definition tagged.h:893
V8_EXPORT_PRIVATE FlagValues v8_flags
return value
Definition map-inl.h:893
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define V8_UNLIKELY(condition)
Definition v8config.h:660