Unified · Split
| @@ -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 | else | 352 | else |
| 351 | ss << "..."; | 353 | ss << "..."; |
| 352 | }); | 354 | }); |
| @@ -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() const | 143 | T *get_allocation() const |
| @@ -638,7 +650,7 @@ namespace disvm · 506 unmodified lines | |||
| 638 | class vm_frame_t final | 650 | 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; |
| @@ -49,23 +49,37 @@ namespace disvm · 48 unmodified lines | |||
| 49 | // Decrement the ref count and if 0 free the allocation | 49 | // 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 pointer | 52 | // 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 context | 58 | 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 offset | 64 | { |
| 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 pointer | 84 | // 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); |
| @@ -28,7 +28,7 @@ std::shared_ptr<const type_descriptor_t> vm_array_t::type_desc() · 27 unmodified lines | |||
| 28 | vm_array_t::vm_array_t(std::shared_ptr<const type_descriptor_t> td, word_t length) | 28 | vm_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 | { |
| @@ -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 | } |
| @@ -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) |
| @@ -28,6 +28,7 @@ using disvm::runtime::vm_memory_allocator_t; · 27 unmodified lines | |||
| 28 | using disvm::runtime::vm_string_t; | 28 | using disvm::runtime::vm_string_t; |
| 29 | using disvm::runtime::vm_thread_t; | 29 | using disvm::runtime::vm_thread_t; |
| 30 | using disvm::runtime::vm_tool_controller_t; | 30 | using disvm::runtime::vm_tool_controller_t; |
| 31 | using disvm::runtime::word_t; | ||
| 31 | 32 | ||
| 32 | // Empty destructors for vm garbage collector 'interfaces' | 33 | // Empty destructors for vm garbage collector 'interfaces' |
| 33 | vm_garbage_collector_t::~vm_garbage_collector_t() | 34 | vm_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 lifetime | 101 | : 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 | ||
| 162 | namespace | 161 | namespace |
| 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 colour | 176 | 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 | ||
| @@ -26,11 +26,11 @@ std::shared_ptr<const type_descriptor_t> vm_list_t::type_desc() · 25 unmodified lines | |||
| 26 | 26 | ||
| 27 | vm_list_t::vm_list_t(std::shared_ptr<const type_descriptor_t> td, vm_list_t *tail) | 27 | vm_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 | ||
| @@ -106,7 +106,7 @@ namespace · 105 unmodified lines | |||
| 106 | }; | 106 | }; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 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) |
| 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 | else | 227 | 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 page | 239 | // Record the top frame on the page |
| @@ -83,16 +83,16 @@ void disvm::runtime::init_memory(const type_descriptor_t &type_desc, void *data) · 82 unmodified lines | |||
| 83 | 83 | ||
| 84 | namespace | 84 | namespace |
| 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 | ||
| 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 | |||
| 212 | bool disvm::runtime::is_offset_pointer(const type_descriptor_t &type_desc, std::size_t offset) | 131 | bool 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 | |||
| 247 | vm_alloc_t *vm_alloc_t::allocate(std::shared_ptr<const type_descriptor_t> td) | 166 | vm_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 | ||
| 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 | |||
| 284 | vm_alloc_t::vm_alloc_t(std::shared_ptr<const type_descriptor_t> td) | 196 | vm_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 | ||
| 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 | |||
| 340 | namespace | 245 | namespace |
| 341 | { | 246 | { |
| 342 | namespace hidden_type_desc | 247 | namespace hidden_type_desc |