History

Move some basic offset functions to header files for inlining ease Replace enum_pointer_field functions with custom implementations - GC now has custom implementation - other implementations use template<> version Fix misuse of shared_ptr<type_descriptor_t> in various built-in types Observed 5 - 8 % improvement in GC for compiler scenario.

arr committed 9 years ago

Commit cd2748b1 parent 3dd1c8210 files · +115 −160Browse files

Showing the changes to src/include (2 of 10 files). Show all

Unified · Split

2 files
  1. src/include/runtime.h +15 −3
  2. src/include/vm_memory.h +31 −17
src/include/runtime.h+15−3
@@ -98,7 +98,14 @@ namespace disvm · 97 unmodified lines
9898
9999 static vm_alloc_t *allocate(std::shared_ptr<const type_descriptor_t> td);
100100 static vm_alloc_t *copy(const vm_alloc_t &other);
101− static vm_alloc_t *from_allocation(pointer_t allocation);
101+
102+ static vm_alloc_t *from_allocation(pointer_t allocation)
103+ {
104+ if (allocation == nullptr)
105+ return nullptr;
106+
107+ return reinterpret_cast<vm_alloc_t *>(reinterpret_cast<uint8_t *>(allocation) - sizeof(vm_alloc_t));
108+ }
102109
103110 template <typename T>
104111 static T *from_allocation(pointer_t allocation)
@@ -125,7 +132,12 @@ namespace disvm · 20 unmodified lines
125132 pointer_t gc_reserved;
126133
127134 public:
128− pointer_t get_allocation() const;
135+ pointer_t get_allocation() const
136+ {
137+ // Remove const on the this pointer so the offset can be computed.
138+ auto non_const_this = const_cast<vm_alloc_t *>(this);
139+ return reinterpret_cast<pointer_t>(reinterpret_cast<uint8_t *>(non_const_this) + sizeof(vm_alloc_t));
140+ }
129141
130142 template <typename T>
131143 T *get_allocation() const
@@ -638,7 +650,7 @@ namespace disvm · 506 unmodified lines
638650 class vm_frame_t final
639651 {
640652 public:
641− vm_frame_t(std::shared_ptr<const type_descriptor_t> &frame_type);
653+ vm_frame_t(std::shared_ptr<const type_descriptor_t> frame_type);
642654 ~vm_frame_t();
643655
644656 std::shared_ptr<const type_descriptor_t> frame_type;
src/include/vm_memory.h+31−17
@@ -49,23 +49,37 @@ namespace disvm · 48 unmodified lines
4949 // Decrement the ref count and if 0 free the allocation
5050 void dec_ref_count_and_free(vm_alloc_t *alloc);
5151
52− // Callback for a pointer field supplying the pointer
53− using pointer_field_callback_t = void(*)(pointer_t);
54−
55− // The callback will be called on all non-null pointer fields.
56− void enum_pointer_fields(const type_descriptor_t &type_desc, void *data, pointer_field_callback_t callback);
57−
58− // Callback for a pointer field supplying the pointer and a calling context
59− using pointer_field_callback_ext_t = void(*)(pointer_t, void *cxt);
60−
61− // The callback will be called on all non-null pointer fields.
62− void enum_pointer_fields(const type_descriptor_t &type_desc, void *data, pointer_field_callback_ext_t callback, void *cxt);
63−
64− // Callback for a pointer field supplying the pointer and byte offset
65− using pointer_field_offset_callback_t = std::function<void(pointer_t, std::size_t)>;
66−
67− // The callback will be called on all non-null pointer fields.
68− void enum_pointer_fields_with_offset(const type_descriptor_t &type_desc, void *data, pointer_field_offset_callback_t callback);
52+ // Function to enumerate pointer fields in an object. The function is defined
53+ // as a template to permit raw function pointers or lambdas. The signature
54+ // of the callback must be 'void(pointer_t *)' and is supplied a pointer to the
55+ // non-null pointer field. The offset of the field is relative to the supplied
56+ // 'data' pointer.
57+ template<typename CB>
58+ void enum_pointer_fields(const type_descriptor_t &type_desc, void *data, CB callback)
59+ {
60+ assert(data != nullptr && callback != nullptr);
61+
62+ auto memory = reinterpret_cast<word_t *>(data);
63+ for (auto i = word_t{ 0 }; i < type_desc.map_in_bytes; ++i, memory += 8)
64+ {
65+ const auto words8 = type_desc.pointer_map[i];
66+ assert(sizeof(words8) == 1);
67+ if (words8 == 0)
68+ continue;
69+
70+ const auto flags = std::bitset<sizeof(words8) * 8>{ words8 };
71+
72+ // Enumerating the flags in reverse order so memory access is sequential.
73+ if (flags[7] && (memory[0] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t *>(memory));
74+ if (flags[6] && (memory[1] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t *>(memory) + 1);
75+ if (flags[5] && (memory[2] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t *>(memory) + 2);
76+ if (flags[4] && (memory[3] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t *>(memory) + 3);
77+ if (flags[3] && (memory[4] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t *>(memory) + 4);
78+ if (flags[2] && (memory[5] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t *>(memory) + 5);
79+ if (flags[1] && (memory[6] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t *>(memory) + 6);
80+ if (flags[0] && (memory[7] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t *>(memory) + 7);
81+ }
82+ }
6983
7084 // Check if a specific pointer-sized offset in a type represents a pointer
7185 bool is_offset_pointer(const type_descriptor_t &type_desc, std::size_t offset);