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 | #ifndef RUNTIME_VM_HEAP_BECOME_H_ |
6 | #define RUNTIME_VM_HEAP_BECOME_H_ |
7 | |
8 | #include "platform/atomic.h" |
9 | #include "vm/allocation.h" |
10 | #include "vm/raw_object.h" |
11 | |
12 | namespace dart { |
13 | |
14 | class Array; |
15 | |
16 | // Objects that are a source in a become are tranformed into forwarding |
17 | // corpses pointing to the corresponding target. Forwarding corpses have the |
18 | // same heap sizes as the source object to ensure the heap remains walkable. |
19 | // If the heap sizes is small enough to be encoded in the size field of the |
20 | // header, a forwarding corpse consists only of a header and the target pointer. |
21 | // If the heap size is too big to be encoded in the header's size field, the |
22 | // word after the target pointer contains the size. This is the same |
23 | // representation as a FreeListElement. |
24 | class ForwardingCorpse { |
25 | public: |
26 | ObjectPtr target() const { return target_; } |
27 | void set_target(ObjectPtr target) { target_ = target; } |
28 | |
29 | intptr_t HeapSize() { |
30 | intptr_t size = ObjectLayout::SizeTag::decode(tags_); |
31 | if (size != 0) return size; |
32 | return *SizeAddress(); |
33 | } |
34 | |
35 | static ForwardingCorpse* AsForwarder(uword addr, intptr_t size); |
36 | |
37 | static void Init(); |
38 | |
39 | // Used to allocate class for forwarding corpses in Object::InitOnce. |
40 | class FakeInstance { |
41 | public: |
42 | FakeInstance() {} |
43 | static cpp_vtable vtable() { return 0; } |
44 | static intptr_t InstanceSize() { return 0; } |
45 | static intptr_t NextFieldOffset() { return -kWordSize; } |
46 | static const ClassId kClassId = kForwardingCorpse; |
47 | static bool IsInstance() { return true; } |
48 | |
49 | private: |
50 | DISALLOW_ALLOCATION(); |
51 | DISALLOW_COPY_AND_ASSIGN(FakeInstance); |
52 | }; |
53 | |
54 | private: |
55 | // This layout mirrors the layout of RawObject. |
56 | RelaxedAtomic<uint32_t> tags_; |
57 | #if defined(HASH_IN_OBJECT_HEADER) |
58 | uint32_t hash_; |
59 | #endif |
60 | ObjectPtr target_; |
61 | |
62 | // Returns the address of the embedded size. |
63 | intptr_t* SizeAddress() const { |
64 | uword addr = reinterpret_cast<uword>(&target_) + kWordSize; |
65 | return reinterpret_cast<intptr_t*>(addr); |
66 | } |
67 | |
68 | // ForwardingCorpses cannot be allocated. Instead references to them are |
69 | // created using the AsForwarder factory method. |
70 | DISALLOW_ALLOCATION(); |
71 | DISALLOW_IMPLICIT_CONSTRUCTORS(ForwardingCorpse); |
72 | }; |
73 | |
74 | // TODO(johnmccutchan): Refactor this class so that it is not all static and |
75 | // provides utility methods for building the mapping of before and after. |
76 | class Become : public AllStatic { |
77 | public: |
78 | // Smalltalk's one-way bulk become (Array>>#elementsForwardIdentityTo:). |
79 | // Redirects all pointers to elements of 'before' to the corresponding element |
80 | // in 'after'. Every element in 'before' is guaranteed to be not reachable. |
81 | // Useful for atomically applying behavior and schema changes. |
82 | static void ElementsForwardIdentity(const Array& before, const Array& after); |
83 | |
84 | // Convert and instance object into a dummy object, |
85 | // making the instance independent of its class. |
86 | // (used for morphic instances during reload). |
87 | static void MakeDummyObject(const Instance& instance); |
88 | |
89 | // Update any references pointing to forwarding objects to point the |
90 | // forwarding objects' targets. |
91 | static void FollowForwardingPointers(Thread* thread); |
92 | |
93 | private: |
94 | static void CrashDump(ObjectPtr before_obj, ObjectPtr after_obj); |
95 | }; |
96 | |
97 | } // namespace dart |
98 | |
99 | #endif // RUNTIME_VM_HEAP_BECOME_H_ |
100 | |