Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
21 ASSERT(size >= kObjectAlignment);
23
24 ForwardingCorpse* result = reinterpret_cast<ForwardingCorpse*>(addr);
25
26 uword tags = result->tags_; // Carry-over any identity hash.
27 tags = UntaggedObject::SizeTag::update(size, tags);
30 tags = UntaggedObject::NotMarkedBit::update(true, tags);
32 tags = UntaggedObject::NewBit::update(!is_old, tags);
33
34 result->tags_ = tags;
36 *result->SizeAddress() = size;
37 }
38 result->set_target(Object::null());
39 return result;
40}
41
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
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
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:
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
219#endif
220
223 ASSERT(group->become() == nullptr); // Only one outstanding become at a time.
224 group->set_become(this);
225}
226
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:190
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:295
void set_become(Become *become)
Definition isolate.h:671
ObjectIdRing * object_id_ring() const
Definition isolate.h:1203
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:361
IsolateGroup * isolate_group() const
Definition thread.h:540
static constexpr uword update(intptr_t size, uword tag)
Definition raw_object.h:209
static constexpr intptr_t kMaxSizeTag
Definition raw_object.h:198
void StorePointer(type const *addr, type value)
Definition raw_object.h:574
uword tags() const
Definition raw_object.h:294
void StoreCompressedArrayPointer(compressed_type const *addr, type value)
Definition raw_object.h:641
void StoreArrayPointer(type const *addr, value_type value)
Definition raw_object.h:624
bool IsCardRemembered() const
Definition raw_object.h:364
intptr_t HeapSize() const
Definition raw_object.h:380
bool InVMIsolateHeap() const
Definition raw_object.cc:20
intptr_t VisitPointers(ObjectPointerVisitor *visitor)
Definition raw_object.h:426
bool IsRemembered() const
Definition raw_object.h:340
void StoreCompressedPointer(compressed_type const *addr, type value)
Definition raw_object.h:585
static constexpr bool IsAligned(T x, uintptr_t alignment, uintptr_t offset=0)
Definition utils.h:77
WritableCodeLiteralsScope(Heap *heap)
Definition become.cc:216
#define ASSERT(E)
VkInstance instance
Definition main.cc:48
#define FATAL(error)
GAsyncResult * result
Win32Message message
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
@ kHeapObjectTag
uintptr_t uword
Definition globals.h:501
static bool IsForwardingObject(ObjectPtr object)
Definition become.cc:50
static constexpr intptr_t kObjectAlignment
#define Px
Definition globals.h:410
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition globals.h:581
#define TIMELINE_FUNCTION_GC_DURATION(thread, name)
Definition timeline.h:41
#define OFFSET_OF(type, field)
Definition globals.h:138