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
12namespace dart {
13
14class 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.
24class 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.
76class 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