Modify placer to allow single object containers, use offset in container.
This commit is contained in:
+112
-64
@@ -11,53 +11,120 @@
|
|||||||
class Container;
|
class Container;
|
||||||
class TypeInfo;
|
class TypeInfo;
|
||||||
|
|
||||||
// Header of every object. Now contains direct references, will contain
|
// Could be made 64-bit for large memory configs.
|
||||||
// offsets in real translated code.
|
typedef uint32_t container_offset_t;
|
||||||
|
|
||||||
|
// Header of every object.
|
||||||
struct ObjHeader {
|
struct ObjHeader {
|
||||||
Container* container_;
|
|
||||||
const TypeInfo* type_info_;
|
const TypeInfo* type_info_;
|
||||||
|
container_offset_t container_offset_negative_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Header of value type array objects.
|
// Header of value type array objects.
|
||||||
struct ArrayHeader : public ObjHeader {
|
struct ArrayHeader : public ObjHeader {
|
||||||
int count_;
|
uint32_t count_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ContainerHeader {
|
||||||
|
// Reference counter of container.
|
||||||
|
int ref_count_;
|
||||||
|
|
||||||
// Class representing placement container. Container is used for reference counting,
|
void AddRef() {
|
||||||
// and it is assumed that objects with related placement will share container. Only
|
ref_count_++;
|
||||||
// whole container can be freed, individual objects are not taken into account.
|
}
|
||||||
class Container {
|
|
||||||
private:
|
void Release() {
|
||||||
// Data where everything is being stored.
|
if (--ref_count_ == 0) {
|
||||||
uint8_t* data_;
|
free(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ArenaContainerHeader : public ContainerHeader {
|
||||||
// Current allocation limit. As objects never freed, we can have rather simple
|
// Current allocation limit. As objects never freed, we can have rather simple
|
||||||
// allocation algorithm.
|
// allocation algorithm.
|
||||||
uint8_t* current_;
|
uint8_t* current_;
|
||||||
// Total size of the container.
|
// Total size of the container.
|
||||||
int size_;
|
uint8_t* end_;
|
||||||
// Reference counter of container.
|
};
|
||||||
int ref_count_;
|
|
||||||
|
// Class representing placement container for single object.
|
||||||
|
class Container {
|
||||||
|
protected:
|
||||||
|
// Data where everything is being stored.
|
||||||
|
ContainerHeader* header_;
|
||||||
|
|
||||||
|
void SetMeta(ObjHeader* obj, const TypeInfo* type_info) {
|
||||||
|
obj->container_offset_negative_ =
|
||||||
|
reinterpret_cast<uintptr_t>(obj) - reinterpret_cast<uintptr_t>(header_);
|
||||||
|
obj->type_info_ = type_info;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Container(int size)
|
// Increment reference counter associated with container.
|
||||||
: size_(size), ref_count_(1) {
|
void AddRef() {
|
||||||
data_ = reinterpret_cast<uint8_t*>(calloc(size_, 1));
|
if (header_) header_->AddRef();
|
||||||
current_ = data_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~Container() {
|
// Decrement reference counter associated with container.
|
||||||
assert(ref_count_ == 0);
|
// For objects whith tricky lifetime (such as ones shared between threads objects)
|
||||||
free(data_);
|
// individual container per object (ObjectContainer) shall be created.
|
||||||
|
// As an alternative, such objects could be evacuated from short-lived containers.
|
||||||
|
void Release() {
|
||||||
|
if (header_) header_->Release();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Container for a single object.
|
||||||
|
class ObjectContainer : public Container {
|
||||||
|
public:
|
||||||
|
explicit ObjectContainer(int size) {
|
||||||
|
header_ = reinterpret_cast<ContainerHeader*>(
|
||||||
|
calloc(size + sizeof(ContainerHeader), 1));
|
||||||
|
header_->ref_count_ = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ObjectContainer() {
|
||||||
|
assert(header_->ref_count_ == 0);
|
||||||
|
free(header_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* GetPlace() const {
|
||||||
|
return reinterpret_cast<uint8_t*>(header_) + sizeof(ContainerHeader);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Class representing arena-style placement container.
|
||||||
|
// Container is used for reference counting,
|
||||||
|
// and it is assumed that objects with related placement will share container. Only
|
||||||
|
// whole container can be freed, individual objects are not taken into account.
|
||||||
|
class ArenaContainer : public Container {
|
||||||
|
public:
|
||||||
|
explicit ArenaContainer(int size) {
|
||||||
|
header_ = reinterpret_cast<ArenaContainerHeader*>(
|
||||||
|
calloc(size + sizeof(ArenaContainerHeader), 1));
|
||||||
|
header_->ref_count_ = 1;
|
||||||
|
ArenaContainerHeader* header = static_cast<ArenaContainerHeader*>(header_);
|
||||||
|
header->current_ = reinterpret_cast<uint8_t*>(header_) + sizeof(ArenaContainerHeader);
|
||||||
|
header->end_ = header->current_ + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ArenaContainer() {
|
||||||
|
if (header_) {
|
||||||
|
assert(header_->ref_count_ == 0);
|
||||||
|
free(header_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Allocation function.
|
// Allocation function.
|
||||||
void* Place(int size) {
|
void* Place(int size) {
|
||||||
if (current_ + size > data_ + size_) {
|
ArenaContainerHeader* header = reinterpret_cast<ArenaContainerHeader*>(header_);
|
||||||
|
if (header->current_ + size > header->end_) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
void* result = current_;
|
void* result = header->current_;
|
||||||
current_ += size;
|
header->current_ += size;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,31 +135,13 @@ class Container {
|
|||||||
// is type infor for an array, not for an individual element.
|
// is type infor for an array, not for an individual element.
|
||||||
ArrayHeader* PlaceArray(const TypeInfo* array_type_info, int count);
|
ArrayHeader* PlaceArray(const TypeInfo* array_type_info, int count);
|
||||||
|
|
||||||
// Increment reference counter associated with container.
|
|
||||||
void AddRef() {
|
|
||||||
if (data_) {
|
|
||||||
// printf("addref %d\n", ref_count_);
|
|
||||||
ref_count_++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrement reference counter associated with container.
|
|
||||||
// For objects whith tricky lifetime (such as ones shared between threads objects)
|
|
||||||
// individual container per object shall be created. As an alternative, such objects
|
|
||||||
// could be evacuated from short-lived containers.
|
|
||||||
void Release() {
|
|
||||||
if (data_) {
|
|
||||||
// printf("release %d\n", ref_count_);
|
|
||||||
ref_count_--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dispose whole container ignoring non-zero refcount. Use with care.
|
// Dispose whole container ignoring non-zero refcount. Use with care.
|
||||||
void Dispose() {
|
void Dispose() {
|
||||||
ref_count_ = 0;
|
if (header_) {
|
||||||
free(data_);
|
header_->ref_count_ = 0;
|
||||||
data_ = nullptr;
|
free(header_);
|
||||||
current_ = nullptr;
|
header_ = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -114,19 +163,20 @@ class AnyObjRef {
|
|||||||
|
|
||||||
explicit AnyObjRef(ObjHeader* ptr) : ptr_(ptr) {
|
explicit AnyObjRef(ObjHeader* ptr) : ptr_(ptr) {
|
||||||
if (ptr_) {
|
if (ptr_) {
|
||||||
container()->AddRef();
|
container_header()->AddRef();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~AnyObjRef() {
|
~AnyObjRef() {
|
||||||
if (ptr_) {
|
if (ptr_) {
|
||||||
container()->Release();
|
container_header()->Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Container* container() const {
|
ContainerHeader* container_header() const {
|
||||||
return ptr_->container_;
|
return reinterpret_cast<ContainerHeader*>(
|
||||||
|
reinterpret_cast<uint8_t*>(ptr_) - ptr_->container_offset_negative_);
|
||||||
}
|
}
|
||||||
|
|
||||||
const TypeInfo* type_info() const {
|
const TypeInfo* type_info() const {
|
||||||
@@ -146,11 +196,11 @@ class AnyObjRef {
|
|||||||
void Assign(const AnyObjRef& other) {
|
void Assign(const AnyObjRef& other) {
|
||||||
// TODO: optimize for an important case where containers match?
|
// TODO: optimize for an important case where containers match?
|
||||||
if (ptr_) {
|
if (ptr_) {
|
||||||
container()->Release();
|
container_header()->Release();
|
||||||
}
|
}
|
||||||
ptr_ = other.ptr_;
|
ptr_ = other.ptr_;
|
||||||
if (ptr_) {
|
if (ptr_) {
|
||||||
container()->AddRef();
|
container_header()->AddRef();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +260,7 @@ class ObjRef : public AnyObjRef {
|
|||||||
void CopyTo(ObjRef<T> other) const;
|
void CopyTo(ObjRef<T> other) const;
|
||||||
|
|
||||||
// Clones object to given container.
|
// Clones object to given container.
|
||||||
ObjRef<T> Clone(Container* container) {
|
ObjRef<T> Clone(ArenaContainer* container) {
|
||||||
ObjRef<T> result = Alloc(container);
|
ObjRef<T> result = Alloc(container);
|
||||||
CopyTo(result);
|
CopyTo(result);
|
||||||
return result;
|
return result;
|
||||||
@@ -223,7 +273,7 @@ class ObjRef : public AnyObjRef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocates properly typed object in container.
|
// Allocates properly typed object in container.
|
||||||
static ObjRef<T> Alloc(Container* container) {
|
static ObjRef<T> Alloc(ArenaContainer* container) {
|
||||||
return ObjRef<T>(container->PlaceObject(T::GetTypeInfo()));
|
return ObjRef<T>(container->PlaceObject(T::GetTypeInfo()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -236,7 +286,7 @@ class ArrayRef : public AnyObjRef {
|
|||||||
ArrayHeader* header() { return reinterpret_cast<ArrayHeader*>(ptr_); }
|
ArrayHeader* header() { return reinterpret_cast<ArrayHeader*>(ptr_); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ArrayRef<T> Alloc(Container* container, int count) {
|
static ArrayRef<T> Alloc(ArenaContainer* container, int count) {
|
||||||
auto result = ArrayRef<T>(container->PlaceArray(GetArrayTypeInfo<T>(), count));
|
auto result = ArrayRef<T>(container->PlaceArray(GetArrayTypeInfo<T>(), count));
|
||||||
result.header()->count_ = count;
|
result.header()->count_ = count;
|
||||||
return result;
|
return result;
|
||||||
@@ -301,25 +351,23 @@ class TypeInfo {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline ObjHeader* Container::PlaceObject(const TypeInfo* type_info) {
|
inline ObjHeader* ArenaContainer::PlaceObject(const TypeInfo* type_info) {
|
||||||
int size = type_info->size() + sizeof(ObjHeader);
|
int size = type_info->size() + sizeof(ObjHeader);
|
||||||
ObjHeader* result = reinterpret_cast<ObjHeader*>(Place(size));
|
ObjHeader* result = reinterpret_cast<ObjHeader*>(Place(size));
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
result->container_ = this;
|
SetMeta(result, type_info);
|
||||||
result->type_info_ = type_info;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ArrayHeader* Container::PlaceArray(const TypeInfo* type_info, int count) {
|
inline ArrayHeader* ArenaContainer::PlaceArray(const TypeInfo* type_info, int count) {
|
||||||
int size = sizeof(ArrayHeader) + type_info->size() * count;
|
int size = sizeof(ArrayHeader) + type_info->size() * count;
|
||||||
ArrayHeader* result = reinterpret_cast<ArrayHeader*>(Place(size));
|
ArrayHeader* result = reinterpret_cast<ArrayHeader*>(Place(size));
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
result->container_ = this;
|
SetMeta(result, type_info);
|
||||||
result->type_info_ = type_info;
|
|
||||||
result->count_ = count;
|
result->count_ = count;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -335,7 +383,7 @@ inline void ObjRef<T>::CopyTo(ObjRef<T> other) const {
|
|||||||
for (int i = 0; i < obj_offsets_count; ++i) {
|
for (int i = 0; i < obj_offsets_count; ++i) {
|
||||||
AnyObjRef any = other.any_obj_at(obj_offsets[i]);
|
AnyObjRef any = other.any_obj_at(obj_offsets[i]);
|
||||||
if (!any.null()) {
|
if (!any.null()) {
|
||||||
any.container()->AddRef();
|
any.container_header()->AddRef();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -41,14 +41,14 @@ void ReturnByValue(ObjRef<List> value) {
|
|||||||
value.at<int, data_offset>().set(239);
|
value.at<int, data_offset>().set(239);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjRef<List> ReturnByRef(Container* container) {
|
ObjRef<List> ReturnByRef(ArenaContainer* container) {
|
||||||
auto result = ObjRef<List>::Alloc(container);
|
auto result = ObjRef<List>::Alloc(container);
|
||||||
result.at<int, data_offset>().set(30);
|
result.at<int, data_offset>().set(30);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_placer() {
|
void test_placer() {
|
||||||
Container heap(1024);
|
ArenaContainer heap(1024);
|
||||||
{
|
{
|
||||||
ObjRef<List> head = ObjRef<List>::Alloc(&heap);
|
ObjRef<List> head = ObjRef<List>::Alloc(&heap);
|
||||||
head.at<int, data_offset>().set(1);
|
head.at<int, data_offset>().set(1);
|
||||||
|
|||||||
Reference in New Issue
Block a user