1 // Copyright 2020 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 #include "src/heap/weak-object-worklists.h"
6
7 #include "src/heap/heap-inl.h"
8 #include "src/heap/heap.h"
9 #include "src/objects/hash-table.h"
10 #include "src/objects/heap-object.h"
11 #include "src/objects/js-function.h"
12 #include "src/objects/js-weak-refs-inl.h"
13 #include "src/objects/js-weak-refs.h"
14 #include "src/objects/shared-function-info.h"
15 #include "src/objects/transitions.h"
16
17 namespace v8 {
18
19 namespace internal {
20
Local(WeakObjects * weak_objects)21 WeakObjects::Local::Local(WeakObjects* weak_objects)
22 : WeakObjects::UnusedBase()
23 #define INIT_LOCAL_WORKLIST(_, name, __) , name##_local(&weak_objects->name)
24 WEAK_OBJECT_WORKLISTS(INIT_LOCAL_WORKLIST)
25 #undef INIT_LOCAL_WORKLIST
26 {
27 }
28
Publish()29 void WeakObjects::Local::Publish() {
30 #define INVOKE_PUBLISH(_, name, __) name##_local.Publish();
31 WEAK_OBJECT_WORKLISTS(INVOKE_PUBLISH)
32 #undef INVOKE_PUBLISH
33 }
34
UpdateAfterScavenge()35 void WeakObjects::UpdateAfterScavenge() {
36 #define INVOKE_UPDATE(_, name, Name) Update##Name(name);
37 WEAK_OBJECT_WORKLISTS(INVOKE_UPDATE)
38 #undef INVOKE_UPDATE
39 }
40
Clear()41 void WeakObjects::Clear() {
42 #define INVOKE_CLEAR(_, name, __) name.Clear();
43 WEAK_OBJECT_WORKLISTS(INVOKE_CLEAR)
44 #undef INVOKE_CLEAR
45 }
46
47 // static
UpdateTransitionArrays(WeakObjectWorklist<TransitionArray> & transition_arrays)48 void WeakObjects::UpdateTransitionArrays(
49 WeakObjectWorklist<TransitionArray>& transition_arrays) {
50 DCHECK(!ContainsYoungObjects(transition_arrays));
51 }
52
53 // static
UpdateEphemeronHashTables(WeakObjectWorklist<EphemeronHashTable> & ephemeron_hash_tables)54 void WeakObjects::UpdateEphemeronHashTables(
55 WeakObjectWorklist<EphemeronHashTable>& ephemeron_hash_tables) {
56 ephemeron_hash_tables.Update(
57 [](EphemeronHashTable slot_in, EphemeronHashTable* slot_out) -> bool {
58 EphemeronHashTable forwarded = ForwardingAddress(slot_in);
59
60 if (!forwarded.is_null()) {
61 *slot_out = forwarded;
62 return true;
63 }
64
65 return false;
66 });
67 }
68
69 namespace {
EphemeronUpdater(Ephemeron slot_in,Ephemeron * slot_out)70 bool EphemeronUpdater(Ephemeron slot_in, Ephemeron* slot_out) {
71 HeapObject key = slot_in.key;
72 HeapObject value = slot_in.value;
73 HeapObject forwarded_key = ForwardingAddress(key);
74 HeapObject forwarded_value = ForwardingAddress(value);
75
76 if (!forwarded_key.is_null() && !forwarded_value.is_null()) {
77 *slot_out = Ephemeron{forwarded_key, forwarded_value};
78 return true;
79 }
80
81 return false;
82 }
83 } // anonymous namespace
84
85 // static
UpdateCurrentEphemerons(WeakObjectWorklist<Ephemeron> & current_ephemerons)86 void WeakObjects::UpdateCurrentEphemerons(
87 WeakObjectWorklist<Ephemeron>& current_ephemerons) {
88 current_ephemerons.Update(EphemeronUpdater);
89 }
90
91 // static
UpdateNextEphemerons(WeakObjectWorklist<Ephemeron> & next_ephemerons)92 void WeakObjects::UpdateNextEphemerons(
93 WeakObjectWorklist<Ephemeron>& next_ephemerons) {
94 next_ephemerons.Update(EphemeronUpdater);
95 }
96
97 // static
UpdateDiscoveredEphemerons(WeakObjectWorklist<Ephemeron> & discovered_ephemerons)98 void WeakObjects::UpdateDiscoveredEphemerons(
99 WeakObjectWorklist<Ephemeron>& discovered_ephemerons) {
100 discovered_ephemerons.Update(EphemeronUpdater);
101 }
102
103 // static
UpdateWeakReferences(WeakObjectWorklist<HeapObjectAndSlot> & weak_references)104 void WeakObjects::UpdateWeakReferences(
105 WeakObjectWorklist<HeapObjectAndSlot>& weak_references) {
106 weak_references.Update(
107 [](HeapObjectAndSlot slot_in, HeapObjectAndSlot* slot_out) -> bool {
108 HeapObject heap_obj = slot_in.first;
109 HeapObject forwarded = ForwardingAddress(heap_obj);
110
111 if (!forwarded.is_null()) {
112 ptrdiff_t distance_to_slot =
113 slot_in.second.address() - slot_in.first.ptr();
114 Address new_slot = forwarded.ptr() + distance_to_slot;
115 slot_out->first = forwarded;
116 slot_out->second = HeapObjectSlot(new_slot);
117 return true;
118 }
119
120 return false;
121 });
122 }
123
124 // static
UpdateWeakObjectsInCode(WeakObjectWorklist<HeapObjectAndCode> & weak_objects_in_code)125 void WeakObjects::UpdateWeakObjectsInCode(
126 WeakObjectWorklist<HeapObjectAndCode>& weak_objects_in_code) {
127 weak_objects_in_code.Update(
128 [](HeapObjectAndCode slot_in, HeapObjectAndCode* slot_out) -> bool {
129 HeapObject heap_obj = slot_in.first;
130 HeapObject forwarded = ForwardingAddress(heap_obj);
131
132 if (!forwarded.is_null()) {
133 slot_out->first = forwarded;
134 slot_out->second = slot_in.second;
135 return true;
136 }
137
138 return false;
139 });
140 }
141
142 // static
UpdateJSWeakRefs(WeakObjectWorklist<JSWeakRef> & js_weak_refs)143 void WeakObjects::UpdateJSWeakRefs(
144 WeakObjectWorklist<JSWeakRef>& js_weak_refs) {
145 js_weak_refs.Update(
146 [](JSWeakRef js_weak_ref_in, JSWeakRef* js_weak_ref_out) -> bool {
147 JSWeakRef forwarded = ForwardingAddress(js_weak_ref_in);
148
149 if (!forwarded.is_null()) {
150 *js_weak_ref_out = forwarded;
151 return true;
152 }
153
154 return false;
155 });
156 }
157
158 // static
UpdateWeakCells(WeakObjectWorklist<WeakCell> & weak_cells)159 void WeakObjects::UpdateWeakCells(WeakObjectWorklist<WeakCell>& weak_cells) {
160 // TODO(syg, marja): Support WeakCells in the young generation.
161 DCHECK(!ContainsYoungObjects(weak_cells));
162 }
163
164 // static
UpdateCodeFlushingCandidates(WeakObjectWorklist<SharedFunctionInfo> & code_flushing_candidates)165 void WeakObjects::UpdateCodeFlushingCandidates(
166 WeakObjectWorklist<SharedFunctionInfo>& code_flushing_candidates) {
167 DCHECK(!ContainsYoungObjects(code_flushing_candidates));
168 }
169
170 // static
UpdateFlushedJSFunctions(WeakObjectWorklist<JSFunction> & flushed_js_functions)171 void WeakObjects::UpdateFlushedJSFunctions(
172 WeakObjectWorklist<JSFunction>& flushed_js_functions) {
173 flushed_js_functions.Update(
174 [](JSFunction slot_in, JSFunction* slot_out) -> bool {
175 JSFunction forwarded = ForwardingAddress(slot_in);
176
177 if (!forwarded.is_null()) {
178 *slot_out = forwarded;
179 return true;
180 }
181
182 return false;
183 });
184 }
185
186 // static
UpdateBaselineFlushingCandidates(WeakObjectWorklist<JSFunction> & baseline_flush_candidates)187 void WeakObjects::UpdateBaselineFlushingCandidates(
188 WeakObjectWorklist<JSFunction>& baseline_flush_candidates) {
189 baseline_flush_candidates.Update(
190 [](JSFunction slot_in, JSFunction* slot_out) -> bool {
191 JSFunction forwarded = ForwardingAddress(slot_in);
192
193 if (!forwarded.is_null()) {
194 *slot_out = forwarded;
195 return true;
196 }
197
198 return false;
199 });
200 }
201
202 #ifdef DEBUG
203 // static
204 template <typename Type>
ContainsYoungObjects(WeakObjectWorklist<Type> & worklist)205 bool WeakObjects::ContainsYoungObjects(WeakObjectWorklist<Type>& worklist) {
206 bool result = false;
207 worklist.Iterate([&result](Type candidate) {
208 if (Heap::InYoungGeneration(candidate)) {
209 result = true;
210 }
211 });
212 return result;
213 }
214 #endif
215
216 } // namespace internal
217 } // namespace v8
218