// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #ifndef RUNTIME_VM_COMPILER_ASSEMBLER_OBJECT_POOL_BUILDER_H_ #define RUNTIME_VM_COMPILER_ASSEMBLER_OBJECT_POOL_BUILDER_H_ #include "platform/globals.h" #include "vm/bitfield.h" #include "vm/hash_map.h" namespace dart { class Object; namespace compiler { class ExternalLabel; bool IsSameObject(const Object& a, const Object& b); struct ObjectPoolBuilderEntry { enum Patchability { kPatchable, kNotPatchable, }; enum EntryType { kTaggedObject, kImmediate, kNativeFunction, kNativeFunctionWrapper, }; using TypeBits = BitField; using PatchableBit = BitField; static inline uint8_t EncodeTraits(EntryType type, Patchability patchable) { return TypeBits::encode(type) | PatchableBit::encode(patchable); } ObjectPoolBuilderEntry() : raw_value_(), entry_bits_(0), equivalence_() {} ObjectPoolBuilderEntry(const Object* obj, Patchability patchable) : ObjectPoolBuilderEntry(obj, obj, patchable) {} ObjectPoolBuilderEntry(const Object* obj, const Object* eqv, Patchability patchable) : obj_(obj), entry_bits_(EncodeTraits(kTaggedObject, patchable)), equivalence_(eqv) {} ObjectPoolBuilderEntry(uword value, EntryType info, Patchability patchable) : raw_value_(value), entry_bits_(EncodeTraits(info, patchable)), equivalence_() {} EntryType type() const { return TypeBits::decode(entry_bits_); } Patchability patchable() const { return PatchableBit::decode(entry_bits_); } union { const Object* obj_; uword raw_value_; }; uint8_t entry_bits_; const Object* equivalence_; }; // Pair type parameter for DirectChainedHashMap used for the constant pool. class ObjIndexPair { public: // Typedefs needed for the DirectChainedHashMap template. typedef ObjectPoolBuilderEntry Key; typedef intptr_t Value; typedef ObjIndexPair Pair; static const intptr_t kNoIndex = -1; ObjIndexPair() : key_(reinterpret_cast(nullptr), ObjectPoolBuilderEntry::kTaggedObject, ObjectPoolBuilderEntry::kPatchable), value_(kNoIndex) {} ObjIndexPair(Key key, Value value) : value_(value) { key_.entry_bits_ = key.entry_bits_; if (key.type() == ObjectPoolBuilderEntry::kTaggedObject) { key_.obj_ = key.obj_; key_.equivalence_ = key.equivalence_; } else { key_.raw_value_ = key.raw_value_; } } static Key KeyOf(Pair kv) { return kv.key_; } static Value ValueOf(Pair kv) { return kv.value_; } static uword Hash(Key key); static inline bool IsKeyEqual(Pair kv, Key key) { if (kv.key_.entry_bits_ != key.entry_bits_) return false; if (kv.key_.type() == ObjectPoolBuilderEntry::kTaggedObject) { return IsSameObject(*kv.key_.obj_, *key.obj_) && IsSameObject(*kv.key_.equivalence_, *key.equivalence_); } return kv.key_.raw_value_ == key.raw_value_; } private: Key key_; Value value_; }; class ObjectPoolBuilder : public ValueObject { public: // When generating AOT code in the bare instructions mode we might use a two // stage process of forming the pool - first accumulate objects in the // intermediary pool and then commit them into the global pool at the // end of a successful compilation. Here [parent] is the pool into which // we are going to commit objects. // See PrecompileParsedFunctionHelper::Compile for more information. explicit ObjectPoolBuilder(ObjectPoolBuilder* parent = nullptr) : parent_(parent), base_index_(parent != nullptr ? parent->CurrentLength() : 0), zone_(nullptr) {} ~ObjectPoolBuilder() { if (zone_ != nullptr) { Reset(); zone_ = nullptr; } } // Clears all existing entries in this object pool builder. // // Note: Any code which has been compiled via this builder might use offsets // into the pool which are not correct anymore. void Reset(); // Initialize this object pool builder with a [zone]. // // Any objects added later on will be referenced using handles from [zone]. void InitializeWithZone(Zone* zone) { ASSERT(object_pool_.length() == 0); ASSERT(zone_ == nullptr && zone != nullptr); zone_ = zone; } intptr_t AddObject(const Object& obj, ObjectPoolBuilderEntry::Patchability patchable = ObjectPoolBuilderEntry::kNotPatchable); intptr_t AddImmediate(uword imm); intptr_t FindObject(const Object& obj, ObjectPoolBuilderEntry::Patchability patchable = ObjectPoolBuilderEntry::kNotPatchable); intptr_t FindObject(const Object& obj, const Object& equivalence); intptr_t FindImmediate(uword imm); intptr_t FindNativeFunction(const ExternalLabel* label, ObjectPoolBuilderEntry::Patchability patchable); intptr_t FindNativeFunctionWrapper( const ExternalLabel* label, ObjectPoolBuilderEntry::Patchability patchable); intptr_t CurrentLength() const { return object_pool_.length() + used_from_parent_.length(); } ObjectPoolBuilderEntry& EntryAt(intptr_t i) { if (i < used_from_parent_.length()) { return parent_->EntryAt(used_from_parent_[i]); } return object_pool_[i - used_from_parent_.length()]; } const ObjectPoolBuilderEntry& EntryAt(intptr_t i) const { if (i < used_from_parent_.length()) { return parent_->EntryAt(used_from_parent_[i]); } return object_pool_[i - used_from_parent_.length()]; } intptr_t AddObject(ObjectPoolBuilderEntry entry); // Try appending all entries from this pool into the parent pool. // This might fail if parent pool was modified invalidating indices which // we produced. In this case this function will return false. bool TryCommitToParent(); bool HasParent() const { return parent_ != nullptr; } private: intptr_t FindObject(ObjectPoolBuilderEntry entry); // Parent pool into which all entries from this pool will be added at // the end of the successful compilation. ObjectPoolBuilder* const parent_; // Base index at which entries will be inserted into the parent pool. // Should be equal to parent_->CurrentLength() - but is cached here // to detect cases when parent pool grows due to nested code generations. const intptr_t base_index_; GrowableArray used_from_parent_; // Objects and jump targets. GrowableArray object_pool_; // Hashmap for fast lookup in object pool. DirectChainedHashMap object_pool_index_table_; // The zone used for allocating the handles we keep in the map and array (or // NULL, in which case allocations happen using the zone active at the point // of insertion). Zone* zone_; }; } // namespace compiler } // namespace dart #endif // RUNTIME_VM_COMPILER_ASSEMBLER_OBJECT_POOL_BUILDER_H_