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
339 {339 {
340 ss << alloc->alloc_type << " - alloc" << dbg_alloc;340 ss << alloc->alloc_type << " - alloc" << dbg_alloc;
341 341
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)
343 {344 {
344 ss << "\n";345 ss << "\n";
345 std::fill_n(std::ostream_iterator<std::ostream::char_type>{ ss }, 4 * recurse_depth, ' ');346 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 } << "] ";
347 349
348 if (recurse_depth < 2)350 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);
350 else352 else
351 ss << "...";353 ss << "...";
352 });354 });
src/include/runtime.h+15−3
@@ -98,7 +98,14 @@ namespace disvm · 97 unmodified lines
98 98
99 static vm_alloc_t *allocate(std::shared_ptr<const type_descriptor_t> td);99 static vm_alloc_t *allocate(std::shared_ptr<const type_descriptor_t> td);
100 static vm_alloc_t *copy(const vm_alloc_t &other);100 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 }
102 109
103 template <typename T>110 template <typename T>
104 static T *from_allocation(pointer_t allocation)111 static T *from_allocation(pointer_t allocation)
@@ -125,7 +132,12 @@ namespace disvm · 20 unmodified lines
125 pointer_t gc_reserved;132 pointer_t gc_reserved;
126 133
127 public:134 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 }
129 141
130 template <typename T>142 template <typename T>
131 T *get_allocation() const143 T *get_allocation() const
@@ -638,7 +650,7 @@ namespace disvm · 506 unmodified lines
638 class vm_frame_t final650 class vm_frame_t final
639 {651 {
640 public:652 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);
642 ~vm_frame_t();654 ~vm_frame_t();
643 655
644 std::shared_ptr<const type_descriptor_t> frame_type;656 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
49 // Decrement the ref count and if 0 free the allocation49 // Decrement the ref count and if 0 free the allocation
50 void dec_ref_count_and_free(vm_alloc_t *alloc);50 void dec_ref_count_and_free(vm_alloc_t *alloc);
51 51
52 // Callback for a pointer field supplying the pointer52 // Function to enumerate pointer fields in an object. The function is defined
53 using pointer_field_callback_t = void(*)(pointer_t);53 // as a template to permit raw function pointers or lambdas. The signature
54 54 // of the callback must be 'void(pointer_t *)' and is supplied a pointer to the
55 // The callback will be called on all non-null pointer fields.55 // non-null pointer field. The offset of the field is relative to the supplied
56 void enum_pointer_fields(const type_descriptor_t &type_desc, void *data, pointer_field_callback_t callback);56 // 'data' pointer.
57 57 template<typename CB>
58 // Callback for a pointer field supplying the pointer and a calling context58 void enum_pointer_fields(const type_descriptor_t &type_desc, void *data, CB callback)
59 using pointer_field_callback_ext_t = void(*)(pointer_t, void *cxt);59 {
60 60 assert(data != nullptr && callback != nullptr);
61 // The callback will be called on all non-null pointer fields.61
62 void enum_pointer_fields(const type_descriptor_t &type_desc, void *data, pointer_field_callback_ext_t callback, void *cxt);62 auto memory = reinterpret_cast<word_t *>(data);
63 63 for (auto i = word_t{ 0 }; i < type_desc.map_in_bytes; ++i, memory += 8)
64 // Callback for a pointer field supplying the pointer and byte offset64 {
65 using pointer_field_offset_callback_t = std::function<void(pointer_t, std::size_t)>;65 const auto words8 = type_desc.pointer_map[i];
66 66 assert(sizeof(words8) == 1);
67 // The callback will be called on all non-null pointer fields.67 if (words8 == 0)
68 void enum_pointer_fields_with_offset(const type_descriptor_t &type_desc, void *data, pointer_field_offset_callback_t callback);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 }
69 83
70 // Check if a specific pointer-sized offset in a type represents a pointer84 // Check if a specific pointer-sized offset in a type represents a pointer
71 bool is_offset_pointer(const type_descriptor_t &type_desc, std::size_t offset);85 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
28vm_array_t::vm_array_t(std::shared_ptr<const type_descriptor_t> td, word_t length)28vm_array_t::vm_array_t(std::shared_ptr<const type_descriptor_t> td, word_t length)
29 : vm_alloc_t(vm_array_t::type_desc())29 : vm_alloc_t(vm_array_t::type_desc())
30 , _arr{ nullptr }30 , _arr{ nullptr }
31 , _element_type{ td }31 , _element_type{ std::move(td) }
32 , _length{ length }32 , _length{ length }
33 , _original{ nullptr }33 , _original{ nullptr }
34{34{
src/vm/channel.cpp+2−2
@@ -45,13 +45,13 @@ vm_channel_t::vm_channel_t( · 44 unmodified lines
45 , _data_buffer_head{ 0 }45 , _data_buffer_head{ 0 }
46 , _data_buffer_count{ 0 }46 , _data_buffer_count{ 0 }
47 , _data_transfer{ transfer }47 , _data_transfer{ transfer }
48 , _data_type{ td }48 , _data_type{ std::move(td) }
49{49{
50 if (buffer_len < 0)50 if (buffer_len < 0)
51 throw out_of_range_memory{};51 throw out_of_range_memory{};
52 52
53 if (buffer_len > 0)53 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 };
55 55
56 disvm::debug::log_msg(component_trace_t::memory, log_level_t::debug, "init: vm channel");56 disvm::debug::log_msg(component_trace_t::memory, log_level_t::debug, "init: vm channel");
57}57}
src/vm/execution_table.cpp+12−12
@@ -509,16 +509,14 @@ namespace · 508 unmodified lines
509 {509 {
510 auto alloc_prev = at_val<vm_alloc_t>(dest);510 auto alloc_prev = at_val<vm_alloc_t>(dest);
511 auto alloc = at_val<vm_alloc_t>(src);511 auto alloc = at_val<vm_alloc_t>(src);
512 pointer_t to_move = nullptr;
512 if (alloc != nullptr)513 if (alloc != nullptr)
513 {514 {
514 alloc->add_ref();515 alloc->add_ref();
515 pt_ref(dest) = alloc->get_allocation();516 to_move = alloc->get_allocation();
516 }
517 else
518 {
519 pt_ref(dest) = nullptr;
520 }517 }
521 518
519 pt_ref(dest) = to_move;
522 dec_ref_count_and_free(alloc_prev);520 dec_ref_count_and_free(alloc_prev);
523 }521 }
524 522
@@ -531,7 +529,6 @@ namespace · 6 unmodified lines
531 EXEC_DECL(movm)529 EXEC_DECL(movm)
532 {530 {
533 assert(r.src != nullptr && r.dest != nullptr);531 assert(r.src != nullptr && r.dest != nullptr);
534
535 std::memmove(r.dest, r.src, vt_ref<word_t>(r.mid));532 std::memmove(r.dest, r.src, vt_ref<word_t>(r.mid));
536 }533 }
537 534
@@ -1087,9 +1084,11 @@ namespace · 549 unmodified lines
1087 }1084 }
1088 1085
1089 dec_ref_count_and_free(at_val<vm_alloc_t>(r.dest));1086 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 };
1091 1087
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)
1093 vm.get_garbage_collector().track_allocation(new_channel);1092 vm.get_garbage_collector().track_allocation(new_channel);
1094 1093
1095 pt_ref(r.dest) = new_channel->get_allocation();1094 pt_ref(r.dest) = new_channel->get_allocation();
@@ -1107,7 +1106,7 @@ namespace · 11 unmodified lines
1107 auto memory_size = vt_ref<word_t>(r.src); 1106 auto memory_size = vt_ref<word_t>(r.src);
1108 auto channel_data_type = type_descriptor_t::create(memory_size); 1107 auto channel_data_type = type_descriptor_t::create(memory_size);
1109 1108
1110 _newc_(r, vm, channel_data_type, _channel_movm);1109 _newc_(r, vm, std::move(channel_data_type), _channel_movm);
1111 }1110 }
1112 1111
1113 EXEC_DECL(newcmp)1112 EXEC_DECL(newcmp)
@@ -1117,7 +1116,7 @@ namespace · 3 unmodified lines
1117 assert(0 <= type_id && type_id < static_cast<word_t>(types.size()));1116 assert(0 <= type_id && type_id < static_cast<word_t>(types.size()));
1118 auto type = types[type_id];1117 auto type = types[type_id];
1119 1118
1120 _newc_(r, vm, type, _channel_movmp);1119 _newc_(r, vm, std::move(type), _channel_movmp);
1121 }1120 }
1122 1121
1123 EXEC_DECL(send)1122 EXEC_DECL(send)
@@ -1440,7 +1439,7 @@ namespace · 316 unmodified lines
1440 assert(0 <= frame_type_id && frame_type_id < static_cast<word_t>(types.size()));1439 assert(0 <= frame_type_id && frame_type_id < static_cast<word_t>(types.size()));
1441 const auto frame_type = types[frame_type_id];1440 const auto frame_type = types[frame_type_id];
1442 1441
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();
1444 }1443 }
1445 1444
1446 EXEC_DECL(mframe)1445 EXEC_DECL(mframe)
@@ -1500,7 +1499,8 @@ namespace · 53 unmodified lines
1500 1499
1501 r.next_pc = vt_ref<vm_pc_t>(r.dest);1500 r.next_pc = vt_ref<vm_pc_t>(r.dest);
1502 1501
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");
1504 }1504 }
1505 1505
1506 EXEC_DECL(mcall)1506 EXEC_DECL(mcall)
src/vm/garbage_collector.cpp+33−11
@@ -28,6 +28,7 @@ using disvm::runtime::vm_memory_allocator_t; · 27 unmodified lines
28using disvm::runtime::vm_string_t;28using disvm::runtime::vm_string_t;
29using disvm::runtime::vm_thread_t;29using disvm::runtime::vm_thread_t;
30using disvm::runtime::vm_tool_controller_t;30using disvm::runtime::vm_tool_controller_t;
31using disvm::runtime::word_t;
31 32
32// Empty destructors for vm garbage collector 'interfaces'33// Empty destructors for vm garbage collector 'interfaces'
33vm_garbage_collector_t::~vm_garbage_collector_t()34vm_garbage_collector_t::~vm_garbage_collector_t()
@@ -97,11 +98,9 @@ namespace · 63 unmodified lines
97 {98 {
98 public:99 public:
99 mark_cxt_t()100 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 lifetime101 : curr_colour{ gc_colour_t::white }
101 , curr_colour{ gc_colour_t::white }
102 { }102 { }
103 103
104 const type_descriptor_t *string_type;
105 gc_colour_t curr_colour;104 gc_colour_t curr_colour;
106 105
107 vm_alloc_t *pop()106 vm_alloc_t *pop()
@@ -161,16 +160,39 @@ void default_garbage_collector_t::enum_tracked_allocations(vm_alloc_callback_t c · 53 unmodified lines
161 160
162namespace161namespace
163{162{
164 void mark_pointers(pointer_t p, void *cxt)163 void mark_pointer_maybe(pointer_t p, mark_cxt_t &c)
165 {164 {
166 auto a = vm_alloc_t::from_allocation(p);165 auto a = vm_alloc_t::from_allocation(p);
167 166
168 assert(cxt != nullptr);167 // Don't examine allocations with the current colour
169 auto c = static_cast<mark_cxt_t *>(cxt);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);
170 175
171 // Don't examine vm strings or allocations with the current colour176 auto memory = reinterpret_cast<pointer_t *>(data);
172 if (c->curr_colour != get_gc_colour(a) && a->alloc_type.get() != c->string_type)177 for (auto i = word_t{ 0 }; i < type_desc.map_in_bytes; ++i, memory += 8)
173 c->push(a);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 }
174 }196 }
175 197
176 void mark(std::vector<std::shared_ptr<const vm_thread_t>> threads, mark_cxt_t &mark_cxt)198 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
194 }216 }
195 217
196 if (frame->frame_type->map_in_bytes > 0)218 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);
198 }220 }
199 }221 }
200 222
@@ -208,7 +230,7 @@ namespace · 7 unmodified lines
208 set_gc_colour(curr, mark_cxt.curr_colour);230 set_gc_colour(curr, mark_cxt.curr_colour);
209 231
210 if (curr->alloc_type->map_in_bytes > 0)232 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);
212 }234 }
213 }235 }
214 236
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
26 26
27vm_list_t::vm_list_t(std::shared_ptr<const type_descriptor_t> td, vm_list_t *tail)27vm_list_t::vm_list_t(std::shared_ptr<const type_descriptor_t> td, vm_list_t *tail)
28 : vm_alloc_t(vm_list_t::type_desc())28 : vm_alloc_t(vm_list_t::type_desc())
29 , _element_type{ td }
30 , _is_alloc{ sizeof(_mem) < td->size_in_bytes }29 , _is_alloc{ sizeof(_mem) < td->size_in_bytes }
31 , _mem{}30 , _mem{}
32 , _tail{ nullptr }31 , _tail{ nullptr }
33{32{
33 _element_type = std::move(td);
34 assert(_element_type != nullptr);34 assert(_element_type != nullptr);
35 set_tail(tail);35 set_tail(tail);
36 36
src/vm/stack.cpp+3−3
@@ -106,7 +106,7 @@ namespace · 105 unmodified lines
106 };106 };
107}107}
108 108
109vm_frame_t::vm_frame_t(std::shared_ptr<const type_descriptor_t> &td)109vm_frame_t::vm_frame_t(std::shared_ptr<const type_descriptor_t> td)
110 : frame_type{ std::move(td) }110 : frame_type{ std::move(td) }
111{111{
112 assert(frame_type != nullptr);112 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
222 if (page_top_frame == nullptr)222 if (page_top_frame == nullptr)
223 {223 {
224 auto new_frame_addr = layout->top_page->stack_data();224 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) };
226 }226 }
227 else227 else
228 {228 {
@@ -233,7 +233,7 @@ vm_frame_t *vm_stack_t::alloc_frame(std::shared_ptr<const type_descriptor_t> fra · 4 unmodified lines
233 if ((new_frame_addr_maybe + new_frame_size) >= layout->top_page->page_limit_addr)233 if ((new_frame_addr_maybe + new_frame_size) >= layout->top_page->page_limit_addr)
234 new_frame_addr_maybe = reinterpret_cast<std::uintptr_t>(layout->new_page());234 new_frame_addr_maybe = reinterpret_cast<std::uintptr_t>(layout->new_page());
235 235
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) };
237 }237 }
238 238
239 // Record the top frame on the page239 // 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
83 83
84namespace84namespace
85{85{
86 void dec_ref_and_free_pointer_field(pointer_t pointer_field)86 void dec_ref_and_free_pointer_field(pointer_t *pointer_field)
87 {87 {
88 assert(pointer_field != nullptr);88 assert(pointer_field != nullptr && *pointer_field != nullptr);
89 dec_ref_count_and_free(vm_alloc_t::from_allocation(pointer_field));89 dec_ref_count_and_free(vm_alloc_t::from_allocation(*pointer_field));
90 }90 }
91 91
92 void add_ref_pointer_field(pointer_t pointer_field)92 void add_ref_pointer_field(pointer_t *pointer_field)
93 {93 {
94 assert(pointer_field != nullptr);94 assert(pointer_field != nullptr && *pointer_field != nullptr);
95 vm_alloc_t::from_allocation(pointer_field)->add_ref();95 vm_alloc_t::from_allocation(*pointer_field)->add_ref();
96 }96 }
97}97}
98 98
@@ -128,87 +128,6 @@ void disvm::runtime::dec_ref_count_and_free(vm_alloc_t *alloc) · 29 unmodified lines
128 delete alloc;128 delete alloc;
129}129}
130 130
131void 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
157void 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
183void 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
212bool disvm::runtime::is_offset_pointer(const type_descriptor_t &type_desc, std::size_t offset)131bool disvm::runtime::is_offset_pointer(const type_descriptor_t &type_desc, std::size_t offset)
213{132{
214 if (type_desc.size_in_bytes == 0)133 if (type_desc.size_in_bytes == 0)
@@ -247,14 +166,15 @@ void vm_alloc_t::operator delete(void *ptr) · 32 unmodified lines
247vm_alloc_t *vm_alloc_t::allocate(std::shared_ptr<const type_descriptor_t> td)166vm_alloc_t *vm_alloc_t::allocate(std::shared_ptr<const type_descriptor_t> td)
248{167{
249 assert(td != nullptr);168 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)
251 throw vm_system_exception{ "Invalid dynamic memory allocation size" };171 throw vm_system_exception{ "Invalid dynamic memory allocation size" };
252 172
253 auto mem = alloc_memory(sizeof(vm_alloc_t) + td->size_in_bytes);173 auto mem = alloc_memory(sizeof(vm_alloc_t) + type_size_in_bytes);
254 auto alloc = ::new(mem)vm_alloc_t{ td };174 auto alloc = ::new(mem)vm_alloc_t{ std::move(td) };
255 175
256 if (disvm::debug::is_component_tracing_enabled<component_trace_t::memory>())176 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);
258 178
259 return alloc;179 return alloc;
260}180}
@@ -273,16 +193,8 @@ vm_alloc_t *vm_alloc_t::copy(const vm_alloc_t &other) · 12 unmodified lines
273 return alloc_copy;193 return alloc_copy;
274}194}
275 195
276vm_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
284vm_alloc_t::vm_alloc_t(std::shared_ptr<const type_descriptor_t> td)196vm_alloc_t::vm_alloc_t(std::shared_ptr<const type_descriptor_t> td)
285 : alloc_type{ td }197 : alloc_type{ std::move(td) }
286 , gc_reserved{ nullptr }198 , gc_reserved{ nullptr }
287 , _ref_count{ 1 }199 , _ref_count{ 1 }
288{200{
@@ -330,13 +242,6 @@ std::size_t vm_alloc_t::get_ref_count() const · 41 unmodified lines
330 return _ref_count;242 return _ref_count;
331}243}
332 244
333pointer_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
340namespace245namespace
341{246{
342 namespace hidden_type_desc247 namespace hidden_type_desc