History

Merged perf_investigation into master

Aaron R Robinson committed 9 years ago

Commit cae8cd32 parents 3dd1c82 cd2748b10 files · +115 −160Browse files

Unified · Split

10 files
  1. src/exec/debugger.cpp +5 −3
  2. src/include/runtime.h +15 −3
  3. src/include/vm_memory.h +31 −17
  4. src/vm/array.cpp +1 −1
  5. src/vm/channel.cpp +2 −2
  6. src/vm/execution_table.cpp +12 −12
  7. src/vm/garbage_collector.cpp +33 −11
  8. src/vm/list.cpp +1 −1
  9. src/vm/stack.cpp +3 −3
  10. src/vm/vm_memory.cpp +12 −107
src/exec/debugger.cpp+5−3
@@ -339,14 +339,16 @@ namespace · 338 unmodified lines
339339 {
340340 ss << alloc->alloc_type << " - alloc" << dbg_alloc;
341341
342− enum_pointer_fields_with_offset(*alloc->alloc_type, alloc->get_allocation(), [&ss, recurse_depth](pointer_t p, std::size_t o)
342+ const auto base_address = reinterpret_cast<std::uintptr_t>(alloc->get_allocation());
343+ enum_pointer_fields(*alloc->alloc_type, alloc->get_allocation(), [&ss, recurse_depth, base_address](pointer_t *p)
343344 {
344345 ss << "\n";
345346 std::fill_n(std::ostream_iterator<std::ostream::char_type>{ ss }, 4 * recurse_depth, ' ');
346− ss << "[" << o << "] ";
347+ const auto p_address = reinterpret_cast<std::uintptr_t>(p);
348+ ss << "[" << std::size_t{ p_address - base_address } << "] ";
347349
348350 if (recurse_depth < 2)
349− safe_alloc_print(ss, vm_alloc_t::from_allocation(p), recurse_depth + 1);
351+ safe_alloc_print(ss, vm_alloc_t::from_allocation(*p), recurse_depth + 1);
350352 else
351353 ss << "...";
352354 });
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);
src/vm/array.cpp+1−1
@@ -28,7 +28,7 @@ std::shared_ptr<const type_descriptor_t> vm_array_t::type_desc() · 27 unmodified lines
2828 vm_array_t::vm_array_t(std::shared_ptr<const type_descriptor_t> td, word_t length)
2929 : vm_alloc_t(vm_array_t::type_desc())
3030 , _arr{ nullptr }
31− , _element_type{ td }
31+ , _element_type{ std::move(td) }
3232 , _length{ length }
3333 , _original{ nullptr }
3434 {
src/vm/channel.cpp+2−2
@@ -45,13 +45,13 @@ vm_channel_t::vm_channel_t( · 44 unmodified lines
4545 , _data_buffer_head{ 0 }
4646 , _data_buffer_count{ 0 }
4747 , _data_transfer{ transfer }
48− , _data_type{ td }
48+ , _data_type{ std::move(td) }
4949 {
5050 if (buffer_len < 0)
5151 throw out_of_range_memory{};
5252
5353 if (buffer_len > 0)
54− _data_buffer = new vm_array_t{ td, buffer_len };
54+ _data_buffer = new vm_array_t{ _data_type, buffer_len };
5555
5656 disvm::debug::log_msg(component_trace_t::memory, log_level_t::debug, "init: vm channel");
5757 }
src/vm/execution_table.cpp+12−12
@@ -509,16 +509,14 @@ namespace · 508 unmodified lines
509509 {
510510 auto alloc_prev = at_val<vm_alloc_t>(dest);
511511 auto alloc = at_val<vm_alloc_t>(src);
512+ pointer_t to_move = nullptr;
512513 if (alloc != nullptr)
513514 {
514515 alloc->add_ref();
515− pt_ref(dest) = alloc->get_allocation();
516− }
517− else
518− {
519− pt_ref(dest) = nullptr;
516+ to_move = alloc->get_allocation();
520517 }
521518
519+ pt_ref(dest) = to_move;
522520 dec_ref_count_and_free(alloc_prev);
523521 }
524522
@@ -531,7 +529,6 @@ namespace · 6 unmodified lines
531529 EXEC_DECL(movm)
532530 {
533531 assert(r.src != nullptr && r.dest != nullptr);
534−
535532 std::memmove(r.dest, r.src, vt_ref<word_t>(r.mid));
536533 }
537534
@@ -1087,9 +1084,11 @@ namespace · 549 unmodified lines
10871084 }
10881085
10891086 dec_ref_count_and_free(at_val<vm_alloc_t>(r.dest));
1090− auto new_channel = new vm_channel_t{ type_desc, transfer, buffer_len };
10911087
1092− if (type_desc->map_in_bytes > 0)
1088+ const auto track_object = type_desc->map_in_bytes > 0;
1089+ auto new_channel = new vm_channel_t{ std::move(type_desc), transfer, buffer_len };
1090+
1091+ if (track_object)
10931092 vm.get_garbage_collector().track_allocation(new_channel);
10941093
10951094 pt_ref(r.dest) = new_channel->get_allocation();
@@ -1107,7 +1106,7 @@ namespace · 11 unmodified lines
11071106 auto memory_size = vt_ref<word_t>(r.src);
11081107 auto channel_data_type = type_descriptor_t::create(memory_size);
11091108
1110− _newc_(r, vm, channel_data_type, _channel_movm);
1109+ _newc_(r, vm, std::move(channel_data_type), _channel_movm);
11111110 }
11121111
11131112 EXEC_DECL(newcmp)
@@ -1117,7 +1116,7 @@ namespace · 3 unmodified lines
11171116 assert(0 <= type_id && type_id < static_cast<word_t>(types.size()));
11181117 auto type = types[type_id];
11191118
1120− _newc_(r, vm, type, _channel_movmp);
1119+ _newc_(r, vm, std::move(type), _channel_movmp);
11211120 }
11221121
11231122 EXEC_DECL(send)
@@ -1440,7 +1439,7 @@ namespace · 316 unmodified lines
14401439 assert(0 <= frame_type_id && frame_type_id < static_cast<word_t>(types.size()));
14411440 const auto frame_type = types[frame_type_id];
14421441
1443− pt_ref(r.dest) = r.stack.alloc_frame(frame_type)->base();
1442+ pt_ref(r.dest) = r.stack.alloc_frame(std::move(frame_type))->base();
14441443 }
14451444
14461445 EXEC_DECL(mframe)
@@ -1500,7 +1499,8 @@ namespace · 53 unmodified lines
15001499
15011500 r.next_pc = vt_ref<vm_pc_t>(r.dest);
15021501
1503− disvm::debug::log_msg(debug::component_trace_t::stack, debug::log_level_t::debug, "enter: function");
1502+ if (disvm::debug::is_component_tracing_enabled<debug::component_trace_t::stack>())
1503+ disvm::debug::log_msg(debug::component_trace_t::stack, debug::log_level_t::debug, "enter: function");
15041504 }
15051505
15061506 EXEC_DECL(mcall)
src/vm/garbage_collector.cpp+33−11
@@ -28,6 +28,7 @@ using disvm::runtime::vm_memory_allocator_t; · 27 unmodified lines
2828 using disvm::runtime::vm_string_t;
2929 using disvm::runtime::vm_thread_t;
3030 using disvm::runtime::vm_tool_controller_t;
31+using disvm::runtime::word_t;
3132
3233 // Empty destructors for vm garbage collector 'interfaces'
3334 vm_garbage_collector_t::~vm_garbage_collector_t()
@@ -97,11 +98,9 @@ namespace · 63 unmodified lines
9798 {
9899 public:
99100 mark_cxt_t()
100− : string_type{ intrinsic_type_desc::type<vm_string_t>().get() } // Using raw pointer since it is a built-in type and has unlimited lifetime
101− , curr_colour{ gc_colour_t::white }
101+ : curr_colour{ gc_colour_t::white }
102102 { }
103103
104− const type_descriptor_t *string_type;
105104 gc_colour_t curr_colour;
106105
107106 vm_alloc_t *pop()
@@ -161,16 +160,39 @@ void default_garbage_collector_t::enum_tracked_allocations(vm_alloc_callback_t c · 53 unmodified lines
161160
162161 namespace
163162 {
164− void mark_pointers(pointer_t p, void *cxt)
163+ void mark_pointer_maybe(pointer_t p, mark_cxt_t &c)
165164 {
166165 auto a = vm_alloc_t::from_allocation(p);
167166
168− assert(cxt != nullptr);
169− auto c = static_cast<mark_cxt_t *>(cxt);
167+ // Don't examine allocations with the current colour
168+ if (a != nullptr && c.curr_colour != get_gc_colour(a))
169+ c.push(a);
170+ }
171+
172+ void mark_pointer_fields(const type_descriptor_t &type_desc, void *data, mark_cxt_t &cxt)
173+ {
174+ assert(data != nullptr);
170175
171− // Don't examine vm strings or allocations with the current colour
172− if (c->curr_colour != get_gc_colour(a) && a->alloc_type.get() != c->string_type)
173− c->push(a);
176+ auto memory = reinterpret_cast<pointer_t *>(data);
177+ for (auto i = word_t{ 0 }; i < type_desc.map_in_bytes; ++i, memory += 8)
178+ {
179+ const auto words8 = type_desc.pointer_map[i];
180+ assert(sizeof(words8) == 1);
181+ if (words8 == 0)
182+ continue;
183+
184+ const auto flags = std::bitset<sizeof(words8) * 8>{ words8 };
185+
186+ // Enumerating the flags in reverse order so memory access is sequential.
187+ if (flags[7]) mark_pointer_maybe(memory[0], cxt);
188+ if (flags[6]) mark_pointer_maybe(memory[1], cxt);
189+ if (flags[5]) mark_pointer_maybe(memory[2], cxt);
190+ if (flags[4]) mark_pointer_maybe(memory[3], cxt);
191+ if (flags[3]) mark_pointer_maybe(memory[4], cxt);
192+ if (flags[2]) mark_pointer_maybe(memory[5], cxt);
193+ if (flags[1]) mark_pointer_maybe(memory[6], cxt);
194+ if (flags[0]) mark_pointer_maybe(memory[7], cxt);
195+ }
174196 }
175197
176198 void mark(std::vector<std::shared_ptr<const vm_thread_t>> threads, mark_cxt_t &mark_cxt)
@@ -194,7 +216,7 @@ namespace · 17 unmodified lines
194216 }
195217
196218 if (frame->frame_type->map_in_bytes > 0)
197− enum_pointer_fields(*frame->frame_type, frame->base(), mark_pointers, &mark_cxt);
219+ mark_pointer_fields(*frame->frame_type, frame->base(), mark_cxt);
198220 }
199221 }
200222
@@ -208,7 +230,7 @@ namespace · 7 unmodified lines
208230 set_gc_colour(curr, mark_cxt.curr_colour);
209231
210232 if (curr->alloc_type->map_in_bytes > 0)
211− enum_pointer_fields(*curr->alloc_type, curr->get_allocation(), mark_pointers, &mark_cxt);
233+ mark_pointer_fields(*curr->alloc_type, curr->get_allocation(), mark_cxt);
212234 }
213235 }
214236
src/vm/list.cpp+1−1
@@ -26,11 +26,11 @@ std::shared_ptr<const type_descriptor_t> vm_list_t::type_desc() · 25 unmodified lines
2626
2727 vm_list_t::vm_list_t(std::shared_ptr<const type_descriptor_t> td, vm_list_t *tail)
2828 : vm_alloc_t(vm_list_t::type_desc())
29− , _element_type{ td }
3029 , _is_alloc{ sizeof(_mem) < td->size_in_bytes }
3130 , _mem{}
3231 , _tail{ nullptr }
3332 {
33+ _element_type = std::move(td);
3434 assert(_element_type != nullptr);
3535 set_tail(tail);
3636
src/vm/stack.cpp+3−3
@@ -106,7 +106,7 @@ namespace · 105 unmodified lines
106106 };
107107 }
108108
109−vm_frame_t::vm_frame_t(std::shared_ptr<const type_descriptor_t> &td)
109+vm_frame_t::vm_frame_t(std::shared_ptr<const type_descriptor_t> td)
110110 : frame_type{ std::move(td) }
111111 {
112112 assert(frame_type != nullptr);
@@ -222,7 +222,7 @@ vm_frame_t *vm_stack_t::alloc_frame(std::shared_ptr<const type_descriptor_t> fra · 109 unmodified lines
222222 if (page_top_frame == nullptr)
223223 {
224224 auto new_frame_addr = layout->top_page->stack_data();
225− new_frame = ::new(new_frame_addr)vm_frame_t{ frame_type };
225+ new_frame = ::new(new_frame_addr)vm_frame_t{ std::move(frame_type) };
226226 }
227227 else
228228 {
@@ -233,7 +233,7 @@ vm_frame_t *vm_stack_t::alloc_frame(std::shared_ptr<const type_descriptor_t> fra · 4 unmodified lines
233233 if ((new_frame_addr_maybe + new_frame_size) >= layout->top_page->page_limit_addr)
234234 new_frame_addr_maybe = reinterpret_cast<std::uintptr_t>(layout->new_page());
235235
236− new_frame = ::new(reinterpret_cast<void *>(new_frame_addr_maybe))vm_frame_t{ frame_type };
236+ new_frame = ::new(reinterpret_cast<void *>(new_frame_addr_maybe))vm_frame_t{ std::move(frame_type) };
237237 }
238238
239239 // Record the top frame on the page
src/vm/vm_memory.cpp+12−107
@@ -83,16 +83,16 @@ void disvm::runtime::init_memory(const type_descriptor_t &type_desc, void *data) · 82 unmodified lines
8383
8484 namespace
8585 {
86− void dec_ref_and_free_pointer_field(pointer_t pointer_field)
86+ void dec_ref_and_free_pointer_field(pointer_t *pointer_field)
8787 {
88− assert(pointer_field != nullptr);
89− dec_ref_count_and_free(vm_alloc_t::from_allocation(pointer_field));
88+ assert(pointer_field != nullptr && *pointer_field != nullptr);
89+ dec_ref_count_and_free(vm_alloc_t::from_allocation(*pointer_field));
9090 }
9191
92− void add_ref_pointer_field(pointer_t pointer_field)
92+ void add_ref_pointer_field(pointer_t *pointer_field)
9393 {
94− assert(pointer_field != nullptr);
95− vm_alloc_t::from_allocation(pointer_field)->add_ref();
94+ assert(pointer_field != nullptr && *pointer_field != nullptr);
95+ vm_alloc_t::from_allocation(*pointer_field)->add_ref();
9696 }
9797 }
9898
@@ -128,87 +128,6 @@ void disvm::runtime::dec_ref_count_and_free(vm_alloc_t *alloc) · 29 unmodified lines
128128 delete alloc;
129129 }
130130
131−void disvm::runtime::enum_pointer_fields(const type_descriptor_t &type_desc, void *data, pointer_field_callback_t callback)
132−{
133− assert(data != nullptr && callback != nullptr);
134−
135− auto memory = reinterpret_cast<word_t *>(data);
136− for (auto i = word_t{ 0 }; i < type_desc.map_in_bytes; ++i, memory += 8)
137− {
138− const auto words8 = type_desc.pointer_map[i];
139− assert(sizeof(words8) == 1);
140− if (words8 == 0)
141− continue;
142−
143− const auto flags = std::bitset<sizeof(words8) * 8>{ words8 };
144−
145− // Enumerating the flags in reverse order so memory access is sequential.
146− if (flags[7] && (memory[0] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[0]));
147− if (flags[6] && (memory[1] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[1]));
148− if (flags[5] && (memory[2] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[2]));
149− if (flags[4] && (memory[3] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[3]));
150− if (flags[3] && (memory[4] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[4]));
151− if (flags[2] && (memory[5] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[5]));
152− if (flags[1] && (memory[6] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[6]));
153− if (flags[0] && (memory[7] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[7]));
154− }
155−}
156−
157−void disvm::runtime::enum_pointer_fields(const type_descriptor_t &type_desc, void *data, pointer_field_callback_ext_t callback, void *cxt)
158−{
159− assert(data != nullptr && callback != nullptr);
160−
161− auto memory = reinterpret_cast<word_t *>(data);
162− for (auto i = word_t{ 0 }; i < type_desc.map_in_bytes; ++i, memory += 8)
163− {
164− const auto words8 = type_desc.pointer_map[i];
165− assert(sizeof(words8) == 1);
166− if (words8 == 0)
167− continue;
168−
169− const auto flags = std::bitset<sizeof(words8) * 8>{ words8 };
170−
171− // Enumerating the flags in reverse order so memory access is sequential.
172− if (flags[7] && (memory[0] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[0]), cxt);
173− if (flags[6] && (memory[1] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[1]), cxt);
174− if (flags[5] && (memory[2] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[2]), cxt);
175− if (flags[4] && (memory[3] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[3]), cxt);
176− if (flags[3] && (memory[4] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[4]), cxt);
177− if (flags[2] && (memory[5] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[5]), cxt);
178− if (flags[1] && (memory[6] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[6]), cxt);
179− if (flags[0] && (memory[7] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[7]), cxt);
180− }
181−}
182−
183−void disvm::runtime::enum_pointer_fields_with_offset(const type_descriptor_t &type_desc, void *data, pointer_field_offset_callback_t callback)
184−{
185− assert(data != nullptr && callback != nullptr);
186− if (type_desc.size_in_bytes == 0)
187− return;
188−
189− auto offset_accum = std::size_t{ 0 };
190− auto memory = reinterpret_cast<word_t *>(data);
191− for (auto i = word_t{ 0 }; i < type_desc.map_in_bytes; ++i, memory += 8, offset_accum += (8 * sizeof(pointer_t)))
192− {
193− const auto words8 = type_desc.pointer_map[i];
194− assert(sizeof(words8) == 1);
195− if (words8 == 0)
196− continue;
197−
198− const auto flags = std::bitset<sizeof(words8) * 8>{ words8 };
199−
200− // Enumerating the flags in reverse order so memory access is sequential.
201− if (flags[7] && (memory[0] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[0]), offset_accum);
202− if (flags[6] && (memory[1] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[1]), offset_accum + (1 * sizeof(pointer_t)));
203− if (flags[5] && (memory[2] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[2]), offset_accum + (2 * sizeof(pointer_t)));
204− if (flags[4] && (memory[3] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[3]), offset_accum + (3 * sizeof(pointer_t)));
205− if (flags[3] && (memory[4] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[4]), offset_accum + (4 * sizeof(pointer_t)));
206− if (flags[2] && (memory[5] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[5]), offset_accum + (5 * sizeof(pointer_t)));
207− if (flags[1] && (memory[6] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[6]), offset_accum + (6 * sizeof(pointer_t)));
208− if (flags[0] && (memory[7] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[7]), offset_accum + (7 * sizeof(pointer_t)));
209− }
210−}
211−
212131 bool disvm::runtime::is_offset_pointer(const type_descriptor_t &type_desc, std::size_t offset)
213132 {
214133 if (type_desc.size_in_bytes == 0)
@@ -247,14 +166,15 @@ void vm_alloc_t::operator delete(void *ptr) · 32 unmodified lines
247166 vm_alloc_t *vm_alloc_t::allocate(std::shared_ptr<const type_descriptor_t> td)
248167 {
249168 assert(td != nullptr);
250− if (td->size_in_bytes <= 0)
169+ const auto type_size_in_bytes = td->size_in_bytes;
170+ if (type_size_in_bytes <= 0)
251171 throw vm_system_exception{ "Invalid dynamic memory allocation size" };
252172
253− auto mem = alloc_memory(sizeof(vm_alloc_t) + td->size_in_bytes);
254− auto alloc = ::new(mem)vm_alloc_t{ td };
173+ auto mem = alloc_memory(sizeof(vm_alloc_t) + type_size_in_bytes);
174+ auto alloc = ::new(mem)vm_alloc_t{ std::move(td) };
255175
256176 if (disvm::debug::is_component_tracing_enabled<component_trace_t::memory>())
257− disvm::debug::log_msg(component_trace_t::memory, log_level_t::debug, "init: vm alloc: %d", td->size_in_bytes);
177+ disvm::debug::log_msg(component_trace_t::memory, log_level_t::debug, "init: vm alloc: %d", type_size_in_bytes);
258178
259179 return alloc;
260180 }
@@ -273,16 +193,8 @@ vm_alloc_t *vm_alloc_t::copy(const vm_alloc_t &other) · 12 unmodified lines
273193 return alloc_copy;
274194 }
275195
276−vm_alloc_t *vm_alloc_t::from_allocation(pointer_t allocation)
277−{
278− if (allocation == nullptr)
279− return nullptr;
280−
281− return reinterpret_cast<vm_alloc_t *>(reinterpret_cast<uint8_t *>(allocation) - sizeof(vm_alloc_t));
282−}
283−
284196 vm_alloc_t::vm_alloc_t(std::shared_ptr<const type_descriptor_t> td)
285− : alloc_type{ td }
197+ : alloc_type{ std::move(td) }
286198 , gc_reserved{ nullptr }
287199 , _ref_count{ 1 }
288200 {
@@ -330,13 +242,6 @@ std::size_t vm_alloc_t::get_ref_count() const · 41 unmodified lines
330242 return _ref_count;
331243 }
332244
333−pointer_t vm_alloc_t::get_allocation() const
334−{
335− // Remove const on the this pointer so the offset can be computed.
336− auto non_const_this = const_cast<vm_alloc_t *>(this);
337− return reinterpret_cast<pointer_t>(reinterpret_cast<uint8_t *>(non_const_this)+sizeof(vm_alloc_t));
338−}
339−
340245 namespace
341246 {
342247 namespace hidden_type_desc