Flutter Engine
The Flutter Engine
become.cc
Go to the documentation of this file.
1// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/heap/become.h"
6
7#include "platform/assert.h"
8#include "platform/utils.h"
9
10#include "vm/dart_api_state.h"
11#include "vm/heap/safepoint.h"
12#include "vm/isolate_reload.h"
13#include "vm/object.h"
14#include "vm/raw_object.h"
15#include "vm/timeline.h"
16#include "vm/visitor.h"
17
18namespace dart {
19
23
24 ForwardingCorpse* result = reinterpret_cast<ForwardingCorpse*>(addr);
25
26 uword tags = result->tags_; // Carry-over any identity hash.
30 tags = UntaggedObject::NotMarkedBit::update(true, tags);
33
34 result->tags_ = tags;
36 *result->SizeAddress() = size;
37 }
38 result->set_target(Object::null());
39 return result;
40}
41
45}
46
47// Free list elements are used as a marker for forwarding objects. This is
48// safe because we cannot reach free list elements from live objects. Ideally
49// forwarding objects would have their own class id. See TODO below.
50static bool IsForwardingObject(ObjectPtr object) {
51 return object->IsHeapObject() && object->IsForwardingCorpse();
52}
53
56 uword addr = static_cast<uword>(object) - kHeapObjectTag;
57 ForwardingCorpse* forwarder = reinterpret_cast<ForwardingCorpse*>(addr);
58 return forwarder->target();
59}
60
61static void ForwardObjectTo(ObjectPtr before_obj, ObjectPtr after_obj) {
62 const intptr_t size_before = before_obj->untag()->HeapSize();
63
64 uword corpse_addr = static_cast<uword>(before_obj) - kHeapObjectTag;
65 ForwardingCorpse* forwarder =
66 ForwardingCorpse::AsForwarder(corpse_addr, size_before);
67 forwarder->set_target(after_obj);
68 if (!IsForwardingObject(before_obj)) {
69 FATAL("become: ForwardObjectTo failure.");
70 }
71 // Still need to be able to iterate over the forwarding corpse.
72 const intptr_t size_after = before_obj->untag()->HeapSize();
73 if (size_before != size_after) {
74 FATAL("become: Before and after sizes do not match.");
75 }
76}
77
79 public:
82 thread_(thread),
83 visiting_object_(nullptr) {}
84
85 void VisitPointers(ObjectPtr* first, ObjectPtr* last) override {
86 for (ObjectPtr* p = first; p <= last; p++) {
87 ObjectPtr old_target = *p;
88 ObjectPtr new_target;
89 if (IsForwardingObject(old_target)) {
90 new_target = GetForwardedObject(old_target);
91 } else {
92 // Though we do not need to update the slot's value when it is not
93 // forwarded, we do need to recheck the generational barrier. In
94 // particular, the remembered bit may be incorrectly false if this
95 // become was the result of aborting a scavenge while visiting the
96 // remembered set.
97 new_target = old_target;
98 }
99 if (visiting_object_ == nullptr) {
100 *p = new_target;
101 } else if (visiting_object_->untag()->IsCardRemembered()) {
102 visiting_object_->untag()->StoreArrayPointer(p, new_target, thread_);
103 } else {
104 visiting_object_->untag()->StorePointer(p, new_target, thread_);
105 }
106 }
107 }
108
109#if defined(DART_COMPRESSED_POINTERS)
110 void VisitCompressedPointers(uword heap_base,
111 CompressedObjectPtr* first,
112 CompressedObjectPtr* last) override {
113 for (CompressedObjectPtr* p = first; p <= last; p++) {
114 ObjectPtr old_target = p->Decompress(heap_base);
115 ObjectPtr new_target;
116 if (IsForwardingObject(old_target)) {
117 new_target = GetForwardedObject(old_target);
118 } else {
119 // Though we do not need to update the slot's value when it is not
120 // forwarded, we do need to recheck the generational barrier. In
121 // particular, the remembered bit may be incorrectly false if this
122 // become was the result of aborting a scavenge while visiting the
123 // remembered set.
124 new_target = old_target;
125 }
126 if (visiting_object_ == nullptr) {
127 *p = new_target;
128 } else if (visiting_object_->untag()->IsCardRemembered()) {
129 visiting_object_->untag()->StoreCompressedArrayPointer(p, new_target,
130 thread_);
131 } else {
132 visiting_object_->untag()->StoreCompressedPointer(p, new_target,
133 thread_);
134 }
135 }
136 }
137#endif
138
140 visiting_object_ = obj;
141 // The incoming remembered bit may be unreliable. Clear it so we can
142 // consistently reapply the barrier to all slots.
143 if ((obj != nullptr) && obj->IsOldObject() &&
144 obj->untag()->IsRemembered()) {
145 ASSERT(!obj->IsForwardingCorpse());
146 ASSERT(!obj->IsFreeListElement());
147 obj->untag()->ClearRememberedBit();
148 }
149 }
150
151 private:
152 Thread* thread_;
153 ObjectPtr visiting_object_;
154
155 DISALLOW_COPY_AND_ASSIGN(ForwardPointersVisitor);
156};
157
159 public:
161 : pointer_visitor_(pointer_visitor) {}
162
163 void VisitObject(ObjectPtr obj) override {
164 pointer_visitor_->VisitingObject(obj);
165 obj->untag()->VisitPointers(pointer_visitor_);
166 }
167
168 private:
169 ForwardPointersVisitor* pointer_visitor_;
170
171 DISALLOW_COPY_AND_ASSIGN(ForwardHeapPointersVisitor);
172};
173
175 public:
178
179 void VisitHandle(uword addr) override {
181 reinterpret_cast<FinalizablePersistentHandle*>(addr);
182 if (IsForwardingObject(handle->ptr())) {
183 *handle->ptr_addr() = GetForwardedObject(handle->ptr());
184 }
185 }
186
187 private:
188 DISALLOW_COPY_AND_ASSIGN(ForwardHeapPointersHandleVisitor);
189};
190
191// On IA32, object pointers are embedded directly in the instruction stream,
192// which is normally write-protected, so we need to make it temporarily writable
193// to forward the pointers. On all other architectures, object pointers are
194// accessed through ObjectPools.
195#if defined(TARGET_ARCH_IA32)
196class WritableCodeLiteralsScope : public ValueObject {
197 public:
198 explicit WritableCodeLiteralsScope(Heap* heap) : heap_(heap) {
199 if (FLAG_write_protect_code) {
200 heap_->WriteProtectCode(false);
201 }
202 }
203
205 if (FLAG_write_protect_code) {
206 heap_->WriteProtectCode(true);
207 }
208 }
209
210 private:
211 Heap* heap_;
212};
213#else
215 public:
218};
219#endif
220
223 ASSERT(group->become() == nullptr); // Only one outstanding become at a time.
224 group->set_become(this);
225}
226
229}
230
231void Become::Add(const Object& before, const Object& after) {
232 pointers_.Add(before.ptr());
233 pointers_.Add(after.ptr());
234}
235
237 if (pointers_.length() != 0) {
238 visitor->VisitPointers(&pointers_[0], pointers_.length());
239 }
240}
241
243 // Make the forward pointer point to itself.
244 // This is needed to distinguish it from a real forward object.
245 ForwardObjectTo(instance.ptr(), instance.ptr());
246}
247
248static bool IsDummyObject(ObjectPtr object) {
249 if (!object->IsForwardingCorpse()) return false;
250 return GetForwardedObject(object) == object;
251}
252
253DART_NOINLINE
254DART_NORETURN
255static void InvalidForwarding(ObjectPtr before,
256 ObjectPtr after,
257 const char* message) {
258 // Separate prints so we can at least get partial information if header
259 // dereference or ToCString crashes.
260 OS::PrintErr("become: %s\n", message);
261 OS::PrintErr("before: %" Px "\n", static_cast<uword>(before));
262 OS::PrintErr("after: %" Px "\n", static_cast<uword>(after));
263 OS::PrintErr("before header: %" Px "\n",
264 before->IsHeapObject() ? before->untag()->tags() : 0);
265 OS::PrintErr("after header: %" Px "\n",
266 after->IsHeapObject() ? after->untag()->tags() : 0);
267 // Create both handles before either ToCString.
268 Object& before_handle = Object::Handle(before);
269 Object& after_handle = Object::Handle(after);
270 OS::PrintErr("before: %s\n", before_handle.ToCString());
271 OS::PrintErr("after: %s\n", after_handle.ToCString());
272 FATAL("become: %s", message);
273}
274
276 if (pointers_.length() == 0) {
277 return;
278 }
279
280 Thread* thread = Thread::Current();
281 auto heap = thread->isolate_group()->heap();
282
283 TIMELINE_FUNCTION_GC_DURATION(thread, "Become::ElementsForwardIdentity");
284 HeapIterationScope his(thread);
285
286 // Setup forwarding pointers.
287 for (intptr_t i = 0; i < pointers_.length(); i += 2) {
288 ObjectPtr before = pointers_[i];
289 ObjectPtr after = pointers_[i + 1];
290
291 if (before == after) {
292 InvalidForwarding(before, after, "Cannot self-forward");
293 }
294 if (before->IsImmediateObject()) {
295 InvalidForwarding(before, after, "Cannot forward immediates");
296 }
297 if (after->IsImmediateObject()) {
298 InvalidForwarding(before, after, "Cannot target immediates");
299 }
300 if (before->untag()->InVMIsolateHeap()) {
301 InvalidForwarding(before, after, "Cannot forward VM heap objects");
302 }
303 if (before->IsForwardingCorpse() && !IsDummyObject(before)) {
304 InvalidForwarding(before, after, "Cannot forward to multiple targets");
305 }
306 if (after->IsForwardingCorpse()) {
307 // The Smalltalk become does allow this, and for very special cases
308 // it is important (shape changes to Class or Mixin), but as these
309 // cases do not arise in Dart, better to prohibit it.
310 InvalidForwarding(before, after, "No indirect chains of forwarding");
311 }
312
313 ForwardObjectTo(before, after);
314 heap->ForwardWeakEntries(before, after);
315#if defined(HASH_IN_OBJECT_HEADER)
316 Object::SetCachedHashIfNotSet(after, Object::GetCachedHash(before));
317#endif
318 }
319
321
322#if defined(DEBUG)
323 for (intptr_t i = 0; i < pointers_.length(); i += 2) {
324 ASSERT(pointers_[i] == pointers_[i + 1]);
325 }
326#endif
327 pointers_.Clear();
328}
329
331 // N.B.: We forward the heap before forwarding the stack. This limits the
332 // amount of following of forwarding pointers needed to get at stack maps.
333 auto isolate_group = thread->isolate_group();
334 Heap* heap = isolate_group->heap();
335
336 // Clear the store buffer; will be rebuilt as we forward the heap.
337 isolate_group->ReleaseStoreBuffers();
338 isolate_group->store_buffer()->Reset();
339
340 ForwardPointersVisitor pointer_visitor(thread);
341
342 {
343 // Heap pointers.
344 WritableCodeLiteralsScope writable_code(heap);
345 ForwardHeapPointersVisitor object_visitor(&pointer_visitor);
346 heap->VisitObjects(&object_visitor);
347 pointer_visitor.VisitingObject(nullptr);
348 }
349
350 // C++ pointers.
351 isolate_group->VisitObjectPointers(&pointer_visitor,
353#ifndef PRODUCT
354 isolate_group->ForEachIsolate(
355 [&](Isolate* isolate) {
356 ObjectIdRing* ring = isolate->object_id_ring();
357 if (ring != nullptr) {
358 ring->VisitPointers(&pointer_visitor);
359 }
360 },
361 /*at_safepoint=*/true);
362#endif // !PRODUCT
363
364 // Weak persistent handles.
365 ForwardHeapPointersHandleVisitor handle_visitor(thread);
366 isolate_group->VisitWeakPersistentHandles(&handle_visitor);
367}
368
369} // namespace dart
static void FollowForwardingPointers(Thread *thread)
Definition: become.cc:330
static void MakeDummyObject(const Instance &instance)
Definition: become.cc:242
void VisitObjectPointers(ObjectPointerVisitor *visitor)
Definition: become.cc:236
void Add(const Object &before, const Object &after)
Definition: become.cc:231
void Forward()
Definition: become.cc:275
static constexpr uword update(ClassIdTagType value, uword original)
Definition: bitfield.h:188
ForwardHeapPointersHandleVisitor(Thread *thread)
Definition: become.cc:176
void VisitHandle(uword addr) override
Definition: become.cc:179
void VisitObject(ObjectPtr obj) override
Definition: become.cc:163
ForwardHeapPointersVisitor(ForwardPointersVisitor *pointer_visitor)
Definition: become.cc:160
void VisitPointers(ObjectPtr *first, ObjectPtr *last) override
Definition: become.cc:85
ForwardPointersVisitor(Thread *thread)
Definition: become.cc:80
void VisitingObject(ObjectPtr obj)
Definition: become.cc:139
static ForwardingCorpse * AsForwarder(uword addr, intptr_t size)
Definition: become.cc:20
void set_target(ObjectPtr target)
Definition: become.h:28
static void Init()
Definition: become.cc:42
ObjectPtr target() const
Definition: become.h:27
Thread * thread() const
Heap * heap() const
Definition: isolate.h:296
void set_become(Become *become)
Definition: isolate.h:678
ObjectIdRing * object_id_ring() const
Definition: isolate.h:1250
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
void VisitPointers(ObjectPointerVisitor *visitor)
virtual void VisitPointers(ObjectPtr *first, ObjectPtr *last)=0
IsolateGroup * isolate_group() const
Definition: visitor.h:25
void VisitCompressedPointers(uword heap_base, CompressedObjectPtr *first, CompressedObjectPtr *last)
Definition: visitor.h:43
bool IsFreeListElement() const
UntaggedObject * untag() const
bool IsForwardingCorpse() const
static ObjectPtr null()
Definition: object.h:433
ObjectPtr ptr() const
Definition: object.h:332
virtual const char * ToCString() const
Definition: object.h:366
static Object & Handle()
Definition: object.h:407
static intptr_t tags_offset()
Definition: object.h:346
static Thread * Current()
Definition: thread.h:362
IsolateGroup * isolate_group() const
Definition: thread.h:541
static constexpr uword update(intptr_t size, uword tag)
Definition: raw_object.h:212
static constexpr intptr_t kMaxSizeTag
Definition: raw_object.h:201
void StorePointer(type const *addr, type value)
Definition: raw_object.h:595
uword tags() const
Definition: raw_object.h:298
void StoreCompressedArrayPointer(compressed_type const *addr, type value)
Definition: raw_object.h:662
void StoreArrayPointer(type const *addr, value_type value)
Definition: raw_object.h:645
bool IsCardRemembered() const
Definition: raw_object.h:385
intptr_t HeapSize() const
Definition: raw_object.h:401
bool InVMIsolateHeap() const
Definition: raw_object.cc:20
intptr_t VisitPointers(ObjectPointerVisitor *visitor)
Definition: raw_object.h:447
bool IsRemembered() const
Definition: raw_object.h:361
void StoreCompressedPointer(compressed_type const *addr, type value)
Definition: raw_object.h:606
static constexpr bool IsAligned(T x, uintptr_t alignment, uintptr_t offset=0)
Definition: utils.h:92
WritableCodeLiteralsScope(Heap *heap)
Definition: become.cc:216
#define ASSERT(E)
VkInstance instance
Definition: main.cc:48
#define FATAL(error)
GAsyncResult * result
Win32Message message
Definition: dart_vm.cc:33
DART_NOINLINE static DART_NORETURN void InvalidForwarding(ObjectPtr before, ObjectPtr after, const char *message)
Definition: become.cc:255
static ObjectPtr GetForwardedObject(ObjectPtr object)
Definition: become.cc:54
static constexpr intptr_t kOldObjectAlignmentOffset
static constexpr intptr_t kNewObjectAlignmentOffset
static void ForwardObjectTo(ObjectPtr before_obj, ObjectPtr after_obj)
Definition: become.cc:61
@ kForwardingCorpse
Definition: class_id.h:225
static bool IsDummyObject(ObjectPtr object)
Definition: become.cc:248
uintptr_t uword
Definition: globals.h:501
static bool IsForwardingObject(ObjectPtr object)
Definition: become.cc:50
static constexpr intptr_t kObjectAlignment
@ kHeapObjectTag
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
#define Px
Definition: globals.h:410
#define TIMELINE_FUNCTION_GC_DURATION(thread, name)
Definition: timeline.h:41
#define OFFSET_OF(type, field)
Definition: globals.h:138