Skip to content

Commit

Permalink
Object pool with support for untagged entries.
Browse files Browse the repository at this point in the history
This adds meta-information to object pool entries to allow storing
untagged immediates or code addresses (ExternalLabel) directly.

This eliminates the need to generate extra code to preserve the LSB
when storing immediates as smis (x64, arm64).

BUG=

Review URL: https://codereview.chromium.org//1175523002.
  • Loading branch information
fsc8000 committed Jun 10, 2015
1 parent 5cc8fca commit 265a544
Show file tree
Hide file tree
Showing 37 changed files with 530 additions and 259 deletions.
2 changes: 1 addition & 1 deletion runtime/observatory/tests/service/graph_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ var tests = [
bVertex.shallowSize +
rVertex.shallowSize));

const int fixedSizeListCid = 61;
const int fixedSizeListCid = 62;
List<ObjectVertex> lists = new List.from(graph.vertices.where(
(ObjectVertex obj) => obj.vmCid == fixedSizeListCid));
expect(lists.length >= 2, isTrue);
Expand Down
87 changes: 60 additions & 27 deletions runtime/vm/assembler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -242,61 +242,94 @@ const Code::Comments& Assembler::GetCodeComments() const {
}


intptr_t ObjectPool::AddObject(const Object& obj, Patchability patchable) {
intptr_t ObjectPoolWrapper::AddObject(const Object& obj) {
return AddObject(ObjectPool::Entry(&obj), kNotPatchable);
}


intptr_t ObjectPoolWrapper::AddImmediate(uword imm) {
return AddObject(ObjectPool::Entry(imm, ObjectPool::kImmediate),
kNotPatchable);
}

intptr_t ObjectPoolWrapper::AddObject(ObjectPool::Entry entry,
Patchability patchable) {
// The object pool cannot be used in the vm isolate.
ASSERT(Isolate::Current() != Dart::vm_isolate());
if (object_pool_.IsNull()) {
object_pool_ = GrowableObjectArray::New(Heap::kOld);
}
object_pool_.Add(obj, Heap::kOld);
patchable_pool_entries_.Add(patchable);
object_pool_.Add(entry);
if (patchable == kNotPatchable) {
// The object isn't patchable. Record the index for fast lookup.
object_pool_index_table_.Insert(
ObjIndexPair(&obj, object_pool_.Length() - 1));
ObjIndexPair(entry, object_pool_.length() - 1));
}
return object_pool_.Length() - 1;
return object_pool_.length() - 1;
}


intptr_t ObjectPool::AddExternalLabel(const ExternalLabel* label,
Patchability patchable) {
intptr_t ObjectPoolWrapper::AddExternalLabel(const ExternalLabel* label,
Patchability patchable) {
ASSERT(Isolate::Current() != Dart::vm_isolate());
const uword address = label->address();
ASSERT(Utils::IsAligned(address, 4));
// The address is stored in the object array as a RawSmi.
const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(address));
return AddObject(smi, patchable);
return AddObject(ObjectPool::Entry(label->address(),
ObjectPool::kImmediate),
patchable);
}


intptr_t ObjectPool::FindObject(const Object& obj, Patchability patchable) {
intptr_t ObjectPoolWrapper::FindObject(ObjectPool::Entry entry,
Patchability patchable) {
// The object pool cannot be used in the vm isolate.
ASSERT(Isolate::Current() != Dart::vm_isolate());

// If the object is not patchable, check if we've already got it in the
// object pool.
if (patchable == kNotPatchable && !object_pool_.IsNull()) {
intptr_t idx = object_pool_index_table_.Lookup(&obj);
if (patchable == kNotPatchable) {
intptr_t idx = object_pool_index_table_.Lookup(entry);
if (idx != ObjIndexPair::kNoIndex) {
ASSERT(patchable_pool_entries_[idx] == kNotPatchable);
return idx;
}
}

return AddObject(obj, patchable);
return AddObject(entry, patchable);
}


intptr_t ObjectPool::FindExternalLabel(const ExternalLabel* label,
Patchability patchable) {
intptr_t ObjectPoolWrapper::FindObject(const Object& obj) {
return FindObject(ObjectPool::Entry(&obj), kNotPatchable);
}


intptr_t ObjectPoolWrapper::FindImmediate(uword imm) {
return FindObject(ObjectPool::Entry(imm, ObjectPool::kImmediate),
kNotPatchable);
}


intptr_t ObjectPoolWrapper::FindExternalLabel(const ExternalLabel* label,
Patchability patchable) {
// The object pool cannot be used in the vm isolate.
ASSERT(Isolate::Current() != Dart::vm_isolate());
const uword address = label->address();
ASSERT(Utils::IsAligned(address, 4));
// The address is stored in the object array as a RawSmi.
const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(address));
return FindObject(smi, patchable);
return FindObject(ObjectPool::Entry(label->address(),
ObjectPool::kImmediate),
patchable);
}


RawObjectPool* ObjectPoolWrapper::MakeObjectPool() {
intptr_t len = object_pool_.length();
if (len == 0) {
return Object::empty_object_pool().raw();
}
const ObjectPool& result = ObjectPool::Handle(ObjectPool::New(len));
for (intptr_t i = 0; i < len; ++i) {
ObjectPool::EntryType info = object_pool_[i].type_;
result.SetInfoAt(i, info);
if (info == ObjectPool::kTaggedObject) {
result.SetObjectAt(i, *object_pool_[i].obj_);
} else {
result.SetRawValueAt(i, object_pool_[i].raw_value_);
}
}
return result.raw();
}


Expand Down
71 changes: 44 additions & 27 deletions runtime/vm/assembler.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,45 +216,61 @@ class AssemblerBuffer : public ValueObject {
class ObjIndexPair {
public:
// Typedefs needed for the DirectChainedHashMap template.
typedef const Object* Key;
typedef ObjectPool::Entry Key;
typedef intptr_t Value;
typedef ObjIndexPair Pair;

static const intptr_t kNoIndex = -1;

ObjIndexPair() : key_(NULL), value_(kNoIndex) { }

ObjIndexPair(Key key, Value value)
: key_(key->IsNotTemporaryScopedHandle()
? key : &Object::ZoneHandle(key->raw())),
value_(value) { }
ObjIndexPair() : key_(static_cast<uword>(NULL), ObjectPool::kTaggedObject),
value_(kNoIndex) { }

ObjIndexPair(Key key, Value value) : value_(value) {
key_.type_ = key.type_;
if (key.type_ == ObjectPool::kTaggedObject) {
if (key.obj_->IsNotTemporaryScopedHandle()) {
key_.obj_ = key.obj_;
} else {
key_.obj_ = &Object::ZoneHandle(key.obj_->raw());
}
} else {
key_.raw_value_ = key.raw_value_;
}
}

static Key KeyOf(Pair kv) { return kv.key_; }

static Value ValueOf(Pair kv) { return kv.value_; }

static intptr_t Hashcode(Key key) {
if (key->IsSmi()) {
return Smi::Cast(*key).Value();
if (key.type_ != ObjectPool::kTaggedObject) {
return key.raw_value_;
}
if (key->IsDouble()) {
if (key.obj_->IsSmi()) {
return Smi::Cast(*key.obj_).Value();
}
if (key.obj_->IsDouble()) {
return static_cast<intptr_t>(
bit_cast<int32_t, float>(
static_cast<float>(Double::Cast(*key).value())));
static_cast<float>(Double::Cast(*key.obj_).value())));
}
if (key->IsMint()) {
return static_cast<intptr_t>(Mint::Cast(*key).value());
if (key.obj_->IsMint()) {
return static_cast<intptr_t>(Mint::Cast(*key.obj_).value());
}
if (key->IsString()) {
return String::Cast(*key).Hash();
if (key.obj_->IsString()) {
return String::Cast(*key.obj_).Hash();
}
// TODO(fschneider): Add hash function for other classes commonly used as
// compile-time constants.
return key->GetClassId();
return key.obj_->GetClassId();
}

static inline bool IsKeyEqual(Pair kv, Key key) {
return kv.key_->raw() == key->raw();
if (kv.key_.type_ != key.type_) return false;
if (kv.key_.type_ == ObjectPool::kTaggedObject) {
return kv.key_.obj_->raw() == key.obj_->raw();
}
return kv.key_.raw_value_ == key.raw_value_;
}

private:
Expand All @@ -269,25 +285,26 @@ enum Patchability {
};


class ObjectPool : public ValueObject {
class ObjectPoolWrapper : public ValueObject {
public:
ObjectPool() : object_pool_(GrowableObjectArray::Handle()) { }

intptr_t AddObject(const Object& obj, Patchability patchable);
intptr_t AddObject(const Object& obj);
intptr_t AddImmediate(uword imm);
intptr_t AddExternalLabel(const ExternalLabel* label,
Patchability patchable);

intptr_t FindObject(const Object& obj, Patchability patchable);
intptr_t FindObject(const Object& obj);
intptr_t FindImmediate(uword imm);
intptr_t FindExternalLabel(const ExternalLabel* label,
Patchability patchable);
const GrowableObjectArray& data() const { return object_pool_; }

RawObjectPool* MakeObjectPool();

private:
// Objects and jump targets.
GrowableObjectArray& object_pool_;
intptr_t AddObject(ObjectPool::Entry entry, Patchability patchable);
intptr_t FindObject(ObjectPool::Entry entry, Patchability patchable);

// Patchability of pool entries.
GrowableArray<Patchability> patchable_pool_entries_;
// Objects and jump targets.
GrowableArray<ObjectPool::Entry> object_pool_;

// Hashmap for fast lookup in object pool.
DirectChainedHashMap<ObjIndexPair> object_pool_index_table_;
Expand Down
6 changes: 3 additions & 3 deletions runtime/vm/assembler_arm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1575,7 +1575,7 @@ void Assembler::LoadObject(Register rd, const Object& object, Condition cond) {
// Make sure that class CallPattern is able to decode this load from the
// object pool.
const int32_t offset =
Array::element_offset(object_pool_.FindObject(object, kNotPatchable));
ObjectPool::element_offset(object_pool_wrapper_.FindObject(object));
LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, cond);
}
}
Expand Down Expand Up @@ -2660,8 +2660,8 @@ void Assembler::BranchLinkPatchable(const ExternalLabel* label) {
// to by this code sequence.
// For added code robustness, use 'blx lr' in a patchable sequence and
// use 'blx ip' in a non-patchable sequence (see other BranchLink flavors).
const int32_t offset =
Array::element_offset(object_pool_.FindExternalLabel(label, kPatchable));
const int32_t offset = ObjectPool::element_offset(
object_pool_wrapper_.FindExternalLabel(label, kPatchable));
LoadWordFromPoolOffset(LR, offset - kHeapObjectTag);
blx(LR); // Use blx instruction so that the return branch prediction works.
}
Expand Down
10 changes: 5 additions & 5 deletions runtime/vm/assembler_arm.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,11 +341,11 @@ class Assembler : public ValueObject {
return buffer_.pointer_offsets();
}

const GrowableObjectArray& object_pool_data() const {
return object_pool_.data();
}
ObjectPoolWrapper& object_pool_wrapper() { return object_pool_wrapper_; }

ObjectPool& object_pool() { return object_pool_; }
RawObjectPool* MakeObjectPool() {
return object_pool_wrapper_.MakeObjectPool();
}

bool use_far_branches() const {
return FLAG_use_far_branches || use_far_branches_;
Expand Down Expand Up @@ -961,7 +961,7 @@ class Assembler : public ValueObject {

private:
AssemblerBuffer buffer_; // Contains position independent code.
ObjectPool object_pool_; // Objects and patchable jump targets.
ObjectPoolWrapper object_pool_wrapper_;

int32_t prologue_offset_;

Expand Down
31 changes: 15 additions & 16 deletions runtime/vm/assembler_arm64.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,29 +35,29 @@ Assembler::Assembler(bool use_far_branches)
// These objects and labels need to be accessible through every pool-pointer
// at the same index.
intptr_t index =
object_pool_.AddObject(Object::null_object(), kNotPatchable);
object_pool_wrapper_.AddObject(Object::null_object());
ASSERT(index == 0);

index = object_pool_.AddObject(Bool::True(), kNotPatchable);
index = object_pool_wrapper_.AddObject(Bool::True());
ASSERT(index == 1);

index = object_pool_.AddObject(Bool::False(), kNotPatchable);
index = object_pool_wrapper_.AddObject(Bool::False());
ASSERT(index == 2);

const Smi& vacant = Smi::Handle(Smi::New(0xfa >> kSmiTagShift));
StubCode* stub_code = Isolate::Current()->stub_code();
if (stub_code->UpdateStoreBuffer_entry() != NULL) {
object_pool_.AddExternalLabel(
object_pool_wrapper_.AddExternalLabel(
&stub_code->UpdateStoreBufferLabel(), kNotPatchable);
} else {
object_pool_.AddObject(vacant, kNotPatchable);
object_pool_wrapper_.AddObject(vacant);
}

if (stub_code->CallToRuntime_entry() != NULL) {
object_pool_.AddExternalLabel(
object_pool_wrapper_.AddExternalLabel(
&stub_code->CallToRuntimeLabel(), kNotPatchable);
} else {
object_pool_.AddObject(vacant, kNotPatchable);
object_pool_wrapper_.AddObject(vacant);
}
}
}
Expand Down Expand Up @@ -390,8 +390,7 @@ void Assembler::LoadWordFromPoolOffsetFixed(Register dst, Register pp,

intptr_t Assembler::FindImmediate(int64_t imm) {
ASSERT(Isolate::Current() != Dart::vm_isolate());
const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(imm));
return object_pool_.FindObject(smi, kNotPatchable);
return object_pool_wrapper_.FindImmediate(imm);
}


Expand Down Expand Up @@ -441,8 +440,8 @@ void Assembler::LoadExternalLabel(Register dst,
Register pp) {
const int64_t target = static_cast<int64_t>(label->address());
if (CanLoadImmediateFromPool(target, pp)) {
const int32_t offset =
Array::element_offset(object_pool_.FindExternalLabel(label, patchable));
const int32_t offset = ObjectPool::element_offset(
object_pool_wrapper_.FindExternalLabel(label, patchable));
LoadWordFromPoolOffset(dst, pp, offset);
} else {
LoadImmediate(dst, target, kNoPP);
Expand All @@ -454,8 +453,8 @@ void Assembler::LoadExternalLabelFixed(Register dst,
const ExternalLabel* label,
Patchability patchable,
Register pp) {
const int32_t offset =
Array::element_offset(object_pool_.FindExternalLabel(label, patchable));
const int32_t offset = ObjectPool::element_offset(
object_pool_wrapper_.FindExternalLabel(label, patchable));
LoadWordFromPoolOffsetFixed(dst, pp, offset);
}

Expand All @@ -468,7 +467,7 @@ void Assembler::LoadIsolate(Register dst, Register pp) {
void Assembler::LoadObject(Register dst, const Object& object, Register pp) {
if (CanLoadObjectFromPool(object)) {
const int32_t offset =
Array::element_offset(object_pool_.FindObject(object, kNotPatchable));
ObjectPool::element_offset(object_pool_wrapper_.FindObject(object));
LoadWordFromPoolOffset(dst, pp, offset);
} else {
ASSERT((Isolate::Current() == Dart::vm_isolate()) ||
Expand All @@ -495,7 +494,7 @@ void Assembler::LoadDecodableImmediate(Register reg, int64_t imm, Register pp) {
allow_constant_pool()) {
int64_t val_smi_tag = imm & kSmiTagMask;
imm &= ~kSmiTagMask; // Mask off the tag bits.
const int32_t offset = Array::element_offset(FindImmediate(imm));
const int32_t offset = ObjectPool::element_offset(FindImmediate(imm));
LoadWordFromPoolOffset(reg, pp, offset);
if (val_smi_tag != 0) {
// Add back the tag bits.
Expand Down Expand Up @@ -531,7 +530,7 @@ void Assembler::LoadImmediate(Register reg, int64_t imm, Register pp) {
// Save the bits that must be masked-off for the SmiTag
int64_t val_smi_tag = imm & kSmiTagMask;
imm &= ~kSmiTagMask; // Mask off the tag bits.
const int32_t offset = Array::element_offset(FindImmediate(imm));
const int32_t offset = ObjectPool::element_offset(FindImmediate(imm));
LoadWordFromPoolOffset(reg, pp, offset);
if (val_smi_tag != 0) {
// Add back the tag bits.
Expand Down

0 comments on commit 265a544

Please sign in to comment.