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
12namespace dart {
13
14class Object;
15
16namespace compiler {
17
18class ExternalLabel;
19
20bool IsSameObject(const Object& a, const Object& b);
21
22struct 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.
70class 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
115class 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