| 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 | |