1 | // Copyright (c) 2012, 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_COMPILER_ASSEMBLER_OBJECT_POOL_BUILDER_H_ |
6 | #define RUNTIME_VM_COMPILER_ASSEMBLER_OBJECT_POOL_BUILDER_H_ |
7 | |
8 | #include "platform/globals.h" |
9 | #include "vm/bitfield.h" |
10 | #include "vm/hash_map.h" |
11 | |
12 | namespace dart { |
13 | |
14 | class Object; |
15 | |
16 | namespace compiler { |
17 | |
18 | class ExternalLabel; |
19 | |
20 | bool IsSameObject(const Object& a, const Object& b); |
21 | |
22 | struct ObjectPoolBuilderEntry { |
23 | enum Patchability { |
24 | kPatchable, |
25 | kNotPatchable, |
26 | }; |
27 | |
28 | enum EntryType { |
29 | kTaggedObject, |
30 | kImmediate, |
31 | kNativeFunction, |
32 | kNativeFunctionWrapper, |
33 | kNativeEntryData, |
34 | }; |
35 | |
36 | using TypeBits = BitField<uint8_t, EntryType, 0, 7>; |
37 | using PatchableBit = BitField<uint8_t, Patchability, TypeBits::kNextBit, 1>; |
38 | |
39 | static inline uint8_t EncodeTraits(EntryType type, Patchability patchable) { |
40 | return TypeBits::encode(type) | PatchableBit::encode(patchable); |
41 | } |
42 | |
43 | ObjectPoolBuilderEntry() : raw_value_(), entry_bits_(0), equivalence_() {} |
44 | ObjectPoolBuilderEntry(const Object* obj, Patchability patchable) |
45 | : ObjectPoolBuilderEntry(obj, obj, patchable) {} |
46 | ObjectPoolBuilderEntry(const Object* obj, |
47 | const Object* eqv, |
48 | Patchability patchable) |
49 | : obj_(obj), |
50 | entry_bits_(EncodeTraits(kTaggedObject, patchable)), |
51 | equivalence_(eqv) {} |
52 | ObjectPoolBuilderEntry(uword value, EntryType info, Patchability patchable) |
53 | : raw_value_(value), |
54 | entry_bits_(EncodeTraits(info, patchable)), |
55 | equivalence_() {} |
56 | |
57 | EntryType type() const { return TypeBits::decode(entry_bits_); } |
58 | |
59 | Patchability patchable() const { return PatchableBit::decode(entry_bits_); } |
60 | |
61 | union { |
62 | const Object* obj_; |
63 | uword raw_value_; |
64 | }; |
65 | uint8_t entry_bits_; |
66 | const Object* equivalence_; |
67 | }; |
68 | |
69 | // Pair type parameter for DirectChainedHashMap used for the constant pool. |
70 | class ObjIndexPair { |
71 | public: |
72 | // Typedefs needed for the DirectChainedHashMap template. |
73 | typedef ObjectPoolBuilderEntry Key; |
74 | typedef intptr_t Value; |
75 | typedef ObjIndexPair Pair; |
76 | |
77 | static const intptr_t kNoIndex = -1; |
78 | |
79 | ObjIndexPair() |
80 | : key_(reinterpret_cast<uword>(nullptr), |
81 | ObjectPoolBuilderEntry::kTaggedObject, |
82 | ObjectPoolBuilderEntry::kPatchable), |
83 | value_(kNoIndex) {} |
84 | |
85 | ObjIndexPair(Key key, Value value) : value_(value) { |
86 | key_.entry_bits_ = key.entry_bits_; |
87 | if (key.type() == ObjectPoolBuilderEntry::kTaggedObject) { |
88 | key_.obj_ = key.obj_; |
89 | key_.equivalence_ = key.equivalence_; |
90 | } else { |
91 | key_.raw_value_ = key.raw_value_; |
92 | } |
93 | } |
94 | |
95 | static Key KeyOf(Pair kv) { return kv.key_; } |
96 | |
97 | static Value ValueOf(Pair kv) { return kv.value_; } |
98 | |
99 | static intptr_t Hashcode(Key key); |
100 | |
101 | static inline bool IsKeyEqual(Pair kv, Key key) { |
102 | if (kv.key_.entry_bits_ != key.entry_bits_) return false; |
103 | if (kv.key_.type() == ObjectPoolBuilderEntry::kTaggedObject) { |
104 | return IsSameObject(*kv.key_.obj_, *key.obj_) && |
105 | IsSameObject(*kv.key_.equivalence_, *key.equivalence_); |
106 | } |
107 | return kv.key_.raw_value_ == key.raw_value_; |
108 | } |
109 | |
110 | private: |
111 | Key key_; |
112 | Value value_; |
113 | }; |
114 | |
115 | class ObjectPoolBuilder : public ValueObject { |
116 | public: |
117 | // When generating AOT code in the bare instructions mode we might use a two |
118 | // stage process of forming the pool - first accumulate objects in the |
119 | // intermediary pool and then commit them into the global pool at the |
120 | // end of a successful compilation. Here [parent] is the pool into which |
121 | // we are going to commit objects. |
122 | // See PrecompileParsedFunctionHelper::Compile for more information. |
123 | explicit ObjectPoolBuilder(ObjectPoolBuilder* parent = nullptr) |
124 | : parent_(parent), |
125 | base_index_(parent != nullptr ? parent->CurrentLength() : 0), |
126 | zone_(nullptr) {} |
127 | |
128 | ~ObjectPoolBuilder() { |
129 | if (zone_ != nullptr) { |
130 | Reset(); |
131 | zone_ = nullptr; |
132 | } |
133 | } |
134 | |
135 | // Clears all existing entries in this object pool builder. |
136 | // |
137 | // Note: Any code which has been compiled via this builder might use offsets |
138 | // into the pool which are not correct anymore. |
139 | void Reset(); |
140 | |
141 | // Initialize this object pool builder with a [zone]. |
142 | // |
143 | // Any objects added later on will be referenced using handles from [zone]. |
144 | void InitializeWithZone(Zone* zone) { |
145 | ASSERT(object_pool_.length() == 0); |
146 | ASSERT(zone_ == nullptr && zone != nullptr); |
147 | zone_ = zone; |
148 | } |
149 | |
150 | intptr_t AddObject(const Object& obj, |
151 | ObjectPoolBuilderEntry::Patchability patchable = |
152 | ObjectPoolBuilderEntry::kNotPatchable); |
153 | intptr_t AddImmediate(uword imm); |
154 | |
155 | intptr_t FindObject(const Object& obj, |
156 | ObjectPoolBuilderEntry::Patchability patchable = |
157 | ObjectPoolBuilderEntry::kNotPatchable); |
158 | intptr_t FindObject(const Object& obj, const Object& equivalence); |
159 | intptr_t FindImmediate(uword imm); |
160 | intptr_t FindNativeFunction(const ExternalLabel* label, |
161 | ObjectPoolBuilderEntry::Patchability patchable); |
162 | intptr_t FindNativeFunctionWrapper( |
163 | const ExternalLabel* label, |
164 | ObjectPoolBuilderEntry::Patchability patchable); |
165 | |
166 | intptr_t CurrentLength() const { |
167 | return object_pool_.length() + used_from_parent_.length(); |
168 | } |
169 | ObjectPoolBuilderEntry& EntryAt(intptr_t i) { |
170 | if (i < used_from_parent_.length()) { |
171 | return parent_->EntryAt(used_from_parent_[i]); |
172 | } |
173 | return object_pool_[i - used_from_parent_.length()]; |
174 | } |
175 | const ObjectPoolBuilderEntry& EntryAt(intptr_t i) const { |
176 | if (i < used_from_parent_.length()) { |
177 | return parent_->EntryAt(used_from_parent_[i]); |
178 | } |
179 | return object_pool_[i - used_from_parent_.length()]; |
180 | } |
181 | |
182 | intptr_t AddObject(ObjectPoolBuilderEntry entry); |
183 | |
184 | // Try appending all entries from this pool into the parent pool. |
185 | // This might fail if parent pool was modified invalidating indices which |
186 | // we produced. In this case this function will return false. |
187 | bool TryCommitToParent(); |
188 | |
189 | bool HasParent() const { return parent_ != nullptr; } |
190 | |
191 | private: |
192 | intptr_t FindObject(ObjectPoolBuilderEntry entry); |
193 | |
194 | // Parent pool into which all entries from this pool will be added at |
195 | // the end of the successful compilation. |
196 | ObjectPoolBuilder* const parent_; |
197 | |
198 | // Base index at which entries will be inserted into the parent pool. |
199 | // Should be equal to parent_->CurrentLength() - but is cached here |
200 | // to detect cases when parent pool grows due to nested code generations. |
201 | const intptr_t base_index_; |
202 | |
203 | GrowableArray<intptr_t> used_from_parent_; |
204 | |
205 | // Objects and jump targets. |
206 | GrowableArray<ObjectPoolBuilderEntry> object_pool_; |
207 | |
208 | // Hashmap for fast lookup in object pool. |
209 | DirectChainedHashMap<ObjIndexPair> object_pool_index_table_; |
210 | |
211 | // The zone used for allocating the handles we keep in the map and array (or |
212 | // NULL, in which case allocations happen using the zone active at the point |
213 | // of insertion). |
214 | Zone* zone_; |
215 | }; |
216 | |
217 | } // namespace compiler |
218 | |
219 | } // namespace dart |
220 | |
221 | #endif // RUNTIME_VM_COMPILER_ASSEMBLER_OBJECT_POOL_BUILDER_H_ |
222 | |