38920c9585
This became obsolete when we added separate exit stubs for each wrapper. TEST=ci Change-Id: Icf73452aebd20e00e16d0a75ffec877715c9e5c4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/215646 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
225 lines
7.2 KiB
C++
225 lines
7.2 KiB
C++
// 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,
|
|
|
|
// Used only during AOT snapshot serialization/deserialization.
|
|
// Denotes kImmediate entry with
|
|
// - StubCode::SwitchableCallMiss().MonomorphicEntryPoint()
|
|
// - StubCode::MegamorphicCall().MonomorphicEntryPoint()
|
|
// values which become known only at run time.
|
|
kSwitchableCallMissEntryPoint,
|
|
kMegamorphicCallEntryPoint,
|
|
};
|
|
|
|
using TypeBits = BitField<uint8_t, EntryType, 0, 7>;
|
|
using PatchableBit = BitField<uint8_t, Patchability, TypeBits::kNextBit, 1>;
|
|
|
|
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<uword>(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 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<intptr_t> used_from_parent_;
|
|
|
|
// Objects and jump targets.
|
|
GrowableArray<ObjectPoolBuilderEntry> object_pool_;
|
|
|
|
// Hashmap for fast lookup in object pool.
|
|
DirectChainedHashMap<ObjIndexPair> 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_
|