Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Classes | Namespaces | Macros | Functions
gc_shared.h File Reference
#include "vm/compiler/runtime_api.h"
#include "vm/dart_api_state.h"
#include "vm/heap/heap.h"
#include "vm/log.h"
#include "vm/message_handler.h"
#include "vm/object.h"

Go to the source code of this file.

Classes

class  dart::GCLinkedList< Type, PtrType >
 
struct  dart::GCLinkedLists
 

Namespaces

namespace  dart
 

Macros

#define GC_LINKED_LIST(V)
 
#define FOREACH(type, var)   GCLinkedList<type, type##Ptr> var;
 
#define TRACE_FINALIZER(format, ...)
 

Functions

Heap::Space dart::SpaceForExternal (FinalizerEntryPtr raw_entry)
 
template<typename GCVisitorType >
void dart::RunNativeFinalizerCallback (NativeFinalizerPtr raw_finalizer, FinalizerEntryPtr raw_entry, Heap::Space before_gc_space, GCVisitorType *visitor)
 
template<typename GCVisitorType >
void dart::MournFinalizerEntry (GCVisitorType *visitor, FinalizerEntryPtr current_entry)
 

Macro Definition Documentation

◆ FOREACH

#define FOREACH (   type,
  var 
)    GCLinkedList<type, type##Ptr> var;

Definition at line 84 of file gc_shared.h.

◆ GC_LINKED_LIST

#define GC_LINKED_LIST (   V)
Value:
V(WeakProperty, weak_properties) \
V(WeakArray, weak_arrays) \
V(WeakReference, weak_references) \
V(FinalizerEntry, finalizer_entries)
#define V(name)
Definition raw_object.h:124

Definition at line 31 of file gc_shared.h.

37 {
38 public:
39 void Enqueue(PtrType ptr) {
40 ASSERT(ptr->untag()->next_seen_by_gc().IsRawNull());
41 ptr->untag()->next_seen_by_gc_ = head_;
42 if (head_ == Type::null()) {
43 tail_ = ptr;
44 }
45 head_ = ptr;
46 }
47
48 void FlushInto(GCLinkedList<Type, PtrType>* to) {
49 if (to->head_ == Type::null()) {
50 ASSERT(to->tail_ == Type::null());
51 to->head_ = head_;
52 to->tail_ = tail_;
53 } else {
54 ASSERT(to->tail_ != Type::null());
55 ASSERT(to->tail_->untag()->next_seen_by_gc() == Type::null());
56 if (head_ != Type::null()) {
57 to->tail_->untag()->next_seen_by_gc_ = head_;
58 to->tail_ = tail_;
59 }
60 }
61 Release();
62 }
63
64 PtrType Release() {
65 PtrType return_value = head_;
66 head_ = Type::null();
67 tail_ = Type::null();
68 return return_value;
69 }
70
71 bool IsEmpty() { return head_ == Type::null() && tail_ == Type::null(); }
72
73 private:
74 PtrType head_ = Type::null();
75 PtrType tail_ = Type::null();
76};
77
78struct GCLinkedLists {
79 void Release();
80 bool IsEmpty();
81 void FlushInto(GCLinkedLists* to);
82
83#define FOREACH(type, var) GCLinkedList<type, type##Ptr> var;
85#undef FOREACH
86};
87
88#ifdef DEBUG
89#define TRACE_FINALIZER(format, ...) \
90 if (FLAG_trace_finalizers) { \
91 THR_Print("%s %p " format "\n", GCVisitorType::kName, visitor, \
92 __VA_ARGS__); \
93 }
94#else
95#define TRACE_FINALIZER(format, ...)
96#endif
97
98// The space in which `raw_entry`'s `value` is.
99Heap::Space SpaceForExternal(FinalizerEntryPtr raw_entry);
100
101// Runs the finalizer if not detached, detaches the value and set external size
102// to 0.
103// TODO(http://dartbug.com/47777): Can this be merged with
104// NativeFinalizer::RunCallback?
105template <typename GCVisitorType>
106void RunNativeFinalizerCallback(NativeFinalizerPtr raw_finalizer,
107 FinalizerEntryPtr raw_entry,
108 Heap::Space before_gc_space,
109 GCVisitorType* visitor) {
110 PointerPtr callback_pointer = raw_finalizer->untag()->callback();
111 const auto callback = reinterpret_cast<NativeFinalizer::Callback>(
112 callback_pointer->untag()->data());
113 ObjectPtr token_object = raw_entry->untag()->token();
114 const bool is_detached = token_object == raw_entry;
115 const intptr_t external_size = raw_entry->untag()->external_size();
116 if (is_detached) {
117 // Detached from Dart code.
118 ASSERT(token_object == raw_entry);
119 ASSERT(external_size == 0);
120 if (FLAG_trace_finalizers) {
121 TRACE_FINALIZER("Not running native finalizer %p callback %p, detached",
122 raw_finalizer->untag(), callback);
123 }
124 } else {
125 // TODO(http://dartbug.com/48615): Unbox pointer address in entry.
126 ASSERT(token_object.IsPointer());
127 PointerPtr token = static_cast<PointerPtr>(token_object);
128 void* peer = reinterpret_cast<void*>(token->untag()->data());
129 if (FLAG_trace_finalizers) {
130 TRACE_FINALIZER("Running native finalizer %p callback %p with token %p",
131 raw_finalizer->untag(), callback, peer);
132 }
133 raw_entry.untag()->set_token(raw_entry);
134 (*callback)(peer);
135 if (external_size > 0) {
136 if (FLAG_trace_finalizers) {
137 TRACE_FINALIZER("Clearing external size %" Pd " bytes in %s space",
138 external_size, before_gc_space == 0 ? "new" : "old");
139 }
140 visitor->isolate_group()->heap()->FreedExternal(external_size,
141 before_gc_space);
142 raw_entry->untag()->set_external_size(0);
143 }
144 }
145}
146
147// This function processes all finalizer entries discovered by a scavenger or
148// marker. If an entry is referencing an object that is going to die, such entry
149// is cleared and enqueued in the respective finalizer.
150//
151// Finalizer entries belonging to unreachable finalizer entries do not get
152// processed, so the callback will not be called for these finalizers.
153//
154// For more documentation see runtime/docs/gc.md.
155//
156// |GCVisitorType| is a concrete type implementing either marker or scavenger.
157// It is expected to provide |ForwardOrSetNullIfCollected| method for clearing
158// fields referring to dead objects and |kName| field which contains visitor
159// name for tracing output.
160template <typename GCVisitorType>
161void MournFinalizerEntry(GCVisitorType* visitor,
162 FinalizerEntryPtr current_entry) {
163 TRACE_FINALIZER("Processing Entry %p", current_entry->untag());
164
165 const Heap::Space before_gc_space = SpaceForExternal(current_entry);
166 const bool value_collected_this_gc =
167 GCVisitorType::ForwardOrSetNullIfCollected(
168 current_entry, &current_entry->untag()->value_);
169 if (!value_collected_this_gc && before_gc_space == Heap::kNew) {
170 const Heap::Space after_gc_space = SpaceForExternal(current_entry);
171 if (after_gc_space == Heap::kOld) {
172 const intptr_t external_size = current_entry->untag()->external_size_;
173 TRACE_FINALIZER("Promoting external size %" Pd
174 " bytes from new to old space",
175 external_size);
176 visitor->isolate_group()->heap()->PromotedExternal(external_size);
177 }
178 }
179 GCVisitorType::ForwardOrSetNullIfCollected(current_entry,
180 &current_entry->untag()->detach_);
181 GCVisitorType::ForwardOrSetNullIfCollected(
182 current_entry, &current_entry->untag()->finalizer_);
183
184 ObjectPtr token_object = current_entry->untag()->token();
185 // See sdk/lib/_internal/vm/lib/internal_patch.dart FinalizerBase.detach.
186 const bool is_detached = token_object == current_entry;
187
188 if (!value_collected_this_gc) return;
189 if (is_detached) return;
190
191 FinalizerBasePtr finalizer = current_entry->untag()->finalizer();
192
193 if (finalizer.IsRawNull()) {
194 TRACE_FINALIZER("Value collected entry %p finalizer null",
195 current_entry->untag());
196
197 // Do nothing, the finalizer has been GCed.
198 return;
199 }
200
201 TRACE_FINALIZER("Value collected entry %p finalizer %p",
202 current_entry->untag(), finalizer->untag());
203
204 FinalizerPtr finalizer_dart = static_cast<FinalizerPtr>(finalizer);
205 // Move entry to entries collected and current head of that list as
206 // the next element. Using a atomic exchange satisfies concurrency
207 // between the parallel GC tasks.
208 // We rely on the fact that the mutator thread is not running to avoid
209 // races between GC and mutator modifying Finalizer.entries_collected.
210 //
211 // We only run in serial marker or in the finalize step in the marker,
212 // both are in safepoint.
213 // The main scavenger worker is at safepoint, the other scavenger
214 // workers are not, but they bypass safepoint because the main
215 // worker is at a safepoint already.
216 ASSERT(Thread::Current()->OwnsGCSafepoint() ||
217 Thread::Current()->BypassSafepoints());
218
219 if (finalizer.IsNativeFinalizer()) {
220 NativeFinalizerPtr native_finalizer =
221 static_cast<NativeFinalizerPtr>(finalizer);
222
223 // Immediately call native callback.
224 RunNativeFinalizerCallback(native_finalizer, current_entry, before_gc_space,
225 visitor);
226
227 // Fall-through sending a message to clear the entries and remove
228 // from detachments.
229 }
230
231 FinalizerEntryPtr previous_head =
232 finalizer_dart->untag()->exchange_entries_collected(current_entry);
233 current_entry->untag()->set_next(previous_head);
234 const bool first_entry = previous_head.IsRawNull();
235
236 // If we're in the marker, we need to ensure that we release the store
237 // buffer afterwards.
238 // If we're in the scavenger and have the finalizer in old space and
239 // a new space entry, we don't need to release the store buffer.
240 if (!first_entry && previous_head->IsNewObject() &&
241 current_entry->IsOldObject()) {
242 TRACE_FINALIZER("Entry %p (old) next is %p (new)", current_entry->untag(),
243 previous_head->untag());
244 // We must release the thread's store buffer block.
245 }
246
247 // Schedule calling Dart finalizer.
248 if (first_entry) {
249 Isolate* isolate = finalizer->untag()->isolate_;
250 if (isolate == nullptr) {
251 TRACE_FINALIZER("Not scheduling finalizer %p callback on isolate null",
252 finalizer->untag());
253 } else {
254 TRACE_FINALIZER("Scheduling finalizer %p callback on isolate %p",
255 finalizer->untag(), isolate);
256
257 PersistentHandle* handle =
258 isolate->group()->api_state()->AllocatePersistentHandle();
259 handle->set_ptr(finalizer);
260 MessageHandler* message_handler = isolate->message_handler();
261 message_handler->PostMessage(
262 Message::New(handle, Message::kNormalPriority),
263 /*before_events*/ false);
264 }
265 }
266}
267
268#undef TRACE_FINALIZER
269
270} // namespace dart
271
272#endif // RUNTIME_VM_HEAP_GC_SHARED_H_
#define ASSERT(E)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
#define FOREACH(type, var)
#define TRACE_FINALIZER(format,...)
Definition gc_shared.h:96
#define GC_LINKED_LIST(V)
Definition gc_shared.h:31
void MournFinalizerEntry(GCVisitorType *visitor, FinalizerEntryPtr current_entry)
Definition gc_shared.h:162
Heap::Space SpaceForExternal(FinalizerEntryPtr raw_entry)
Definition gc_shared.cc:42
void RunNativeFinalizerCallback(NativeFinalizerPtr raw_finalizer, FinalizerEntryPtr raw_entry, Heap::Space before_gc_space, GCVisitorType *visitor)
Definition gc_shared.h:107
std::function< void(const T &message, const MessageReply< T > &reply)> MessageHandler
#define Pd
Definition globals.h:408

◆ TRACE_FINALIZER

#define TRACE_FINALIZER (   format,
  ... 
)

Definition at line 96 of file gc_shared.h.