diff --git a/experiments/placer/placer.cc b/experiments/placer/placer.cc index a7139eebfc2..e0cbc264342 100644 --- a/experiments/placer/placer.cc +++ b/experiments/placer/placer.cc @@ -70,34 +70,18 @@ class RawRef { void set(const T& value) { *ptr_ = value; } }; -// Object reference, adds reference counting in container. -template -class ObjRef { - private: +class AnyObjRef { + protected: void* ptr_; - explicit ObjRef(void* ptr) : ptr_(ptr) { + explicit AnyObjRef(void* ptr) : ptr_(ptr) { if (ptr_) { container()->AddRef(); } } - T* ref() const { - if (!ptr_) return nullptr; - return reinterpret_cast(reinterpret_cast(ptr_) + sizeof(Container*)); - } - public: - ObjRef() : ptr_(nullptr) {} - ObjRef(const ObjRef& other) : ptr_(nullptr) { - Assign(other); - } - ObjRef& operator=(const ObjRef& other) { - Assign(other); - return *this; - } - - ~ObjRef() { + ~AnyObjRef() { if (ptr_) { container()->Release(); } @@ -110,11 +94,11 @@ class ObjRef { template RawRef at() const { return RawRef( - reinterpret_cast(reinterpret_cast(ref()) + offset)); + reinterpret_cast(reinterpret_cast(any_ref()) + offset)); } - void Assign(const ObjRef& other) { - // TODO: optimize for an important case where containers match. + void Assign(const AnyObjRef& other) { + // TODO: optimize for an important case where containers match? if (ptr_) { container()->Release(); } @@ -124,14 +108,69 @@ class ObjRef { } } - ObjRef Clone(Container* container) { - ObjRef result = Alloc(container); - // TODO: take into account object references in T! - memcpy(result.ref(), ref(), sizeof(T)); - return result; + uint8_t* any_ref() const { + if (!ptr_) return nullptr; + return reinterpret_cast(ptr_) + sizeof(Container*); + } + + AnyObjRef any_obj_at(int offset) const { + assert(ptr_); + return AnyObjRef(*reinterpret_cast(any_ref() + offset)); } bool null() const { return ptr_ == nullptr; } +}; + +// Object reference, adds reference counting in container. +template +class ObjRef : public AnyObjRef { + private: + explicit ObjRef(void* ptr) : AnyObjRef(ptr) {} + + T* ref() const { + if (!ptr_) return nullptr; + return reinterpret_cast(any_ref()); + } + + public: + ObjRef(const ObjRef& other) : AnyObjRef(nullptr) { + Assign(other); + } + ObjRef& operator=(const ObjRef& other) { + Assign(other); + return *this; + } + + void Assign(const ObjRef& other) { + AnyObjRef::Assign(other); + } + + void CopyTo(ObjRef other) const { + assert(!other.null()); + if (ref()) { + memcpy(other.ref(), ref(), sizeof(T)); + for (int i = 0; i < sizeof(T::obj_offsets) / sizeof(T::obj_offsets[0]); ++i) { + AnyObjRef any = other.any_obj_at(T::obj_offsets[i]); + if (!any.null()) { + any.container()->AddRef(); + } + } + } else { + // TODO: shall we do anything if copy from/to null? + } + } + + ObjRef Clone(Container* container) { + ObjRef result = Alloc(container); + CopyTo(result); + return result; + } + + template + ObjRef obj_at() const { + return ObjRef( + reinterpret_cast(any_ref() + offset)); + } static ObjRef Alloc(Container* container) { return ObjRef(container->Place(sizeof(T))); @@ -140,9 +179,14 @@ class ObjRef { struct List { ObjRef next_; + ObjRef prev_; int data_; + // Object offsets in the class, needed for CopyTo() operation to update refs and for GC. + static constexpr int obj_offsets[] = { 0 /* =offsetof(struct List, next_) */, 8 /* =offsetof(struct List, prev_) */ }; }; +constexpr int List::obj_offsets[]; + void UpdateElement(ObjRef element) { element.at().set (element.at().get() + 10); @@ -153,10 +197,21 @@ void DoNotUpdateElement(ObjRef element) { (element.at().get() + 100); } +constexpr int next_offset = offsetof(struct List, next_); +constexpr int data_offset = offsetof(struct List, data_); + +void ReturnByValue(ObjRef value) { + value.at().set(239); +} + +ObjRef ReturnByRef(Container* container) { + auto result = ObjRef::Alloc(container); + result.at().set(30); + return result; +} + void test_placer() { Container heap(1024); - constexpr int next_offset = offsetof(struct List, next_); - constexpr int data_offset = offsetof(struct List, data_); { ObjRef head = ObjRef::Alloc(&heap); head.at().set(1); @@ -166,6 +221,32 @@ void test_placer() { cur = cur.at, next_offset>().get(); cur.at().set(i + 2); } + + // Pass by reference. + cur = head; + while (!cur.null()) { + UpdateElement(cur); + cur = cur.at, next_offset>().get(); + } + + // Pass by value. + cur = head; + while (!cur.null()) { + // We could place clone on stack as well. + DoNotUpdateElement(cur.Clone(&heap)); + cur = cur.at, next_offset>().get(); + } + + // Return by value is trivial in this system. CopyTo() into provided container. + auto value = ObjRef::Alloc(&heap); + ReturnByValue(value); + printf("By value is %d\n", value.at().get()); + + // Return by references assumes passing of container where results to be allocated. + value = ReturnByRef(&heap /* or stack container */); + printf("By ref is %d\n", value.at().get()); + + // Dump results. cur = head; // Pass by reference. while (!cur.null()) {