Unified · Split
| @@ -339,14 +339,16 @@ namespace · 338 unmodified lines | ||
| 339 | 339 | { |
| 340 | 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 | 345 | ss << "\n"; |
| 345 | 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 | 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 | 352 | else |
| 351 | 353 | ss << "..."; |
| 352 | 354 | }); |
| @@ -98,7 +98,14 @@ namespace disvm · 97 unmodified lines | ||
| 98 | 98 | |
| 99 | 99 | static vm_alloc_t *allocate(std::shared_ptr<const type_descriptor_t> td); |
| 100 | 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 | 110 | template <typename T> |
| 104 | 111 | static T *from_allocation(pointer_t allocation) |
| @@ -125,7 +132,12 @@ namespace disvm · 20 unmodified lines | ||
| 125 | 132 | pointer_t gc_reserved; |
| 126 | 133 | |
| 127 | 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 | 142 | template <typename T> |
| 131 | 143 | T *get_allocation() const |
| @@ -638,7 +650,7 @@ namespace disvm · 506 unmodified lines | ||
| 638 | 650 | class vm_frame_t final |
| 639 | 651 | { |
| 640 | 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 | 654 | ~vm_frame_t(); |
| 643 | 655 | |
| 644 | 656 | std::shared_ptr<const type_descriptor_t> frame_type; |
| @@ -49,23 +49,37 @@ namespace disvm · 48 unmodified lines | ||
| 49 | 49 | // Decrement the ref count and if 0 free the allocation |
| 50 | 50 | void dec_ref_count_and_free(vm_alloc_t *alloc); |
| 51 | 51 | |
| 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 | + } | |
| 69 | 83 | |
| 70 | 84 | // Check if a specific pointer-sized offset in a type represents a pointer |
| 71 | 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 | 28 | vm_array_t::vm_array_t(std::shared_ptr<const type_descriptor_t> td, word_t length) |
| 29 | 29 | : vm_alloc_t(vm_array_t::type_desc()) |
| 30 | 30 | , _arr{ nullptr } |
| 31 | − , _element_type{ td } | |
| 31 | + , _element_type{ std::move(td) } | |
| 32 | 32 | , _length{ length } |
| 33 | 33 | , _original{ nullptr } |
| 34 | 34 | { |
| @@ -45,13 +45,13 @@ vm_channel_t::vm_channel_t( · 44 unmodified lines | ||
| 45 | 45 | , _data_buffer_head{ 0 } |
| 46 | 46 | , _data_buffer_count{ 0 } |
| 47 | 47 | , _data_transfer{ transfer } |
| 48 | − , _data_type{ td } | |
| 48 | + , _data_type{ std::move(td) } | |
| 49 | 49 | { |
| 50 | 50 | if (buffer_len < 0) |
| 51 | 51 | throw out_of_range_memory{}; |
| 52 | 52 | |
| 53 | 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 | 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 | 510 | auto alloc_prev = at_val<vm_alloc_t>(dest); |
| 511 | 511 | auto alloc = at_val<vm_alloc_t>(src); |
| 512 | + pointer_t to_move = nullptr; | |
| 512 | 513 | if (alloc != nullptr) |
| 513 | 514 | { |
| 514 | 515 | 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(); | |
| 520 | 517 | } |
| 521 | 518 | |
| 519 | + pt_ref(dest) = to_move; | |
| 522 | 520 | dec_ref_count_and_free(alloc_prev); |
| 523 | 521 | } |
| 524 | 522 | |
| @@ -531,7 +529,6 @@ namespace · 6 unmodified lines | ||
| 531 | 529 | EXEC_DECL(movm) |
| 532 | 530 | { |
| 533 | 531 | assert(r.src != nullptr && r.dest != nullptr); |
| 534 | − | |
| 535 | 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 | 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 | 1092 | vm.get_garbage_collector().track_allocation(new_channel); |
| 1094 | 1093 | |
| 1095 | 1094 | pt_ref(r.dest) = new_channel->get_allocation(); |
| @@ -1107,7 +1106,7 @@ namespace · 11 unmodified lines | ||
| 1107 | 1106 | auto memory_size = vt_ref<word_t>(r.src); |
| 1108 | 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 | 1112 | EXEC_DECL(newcmp) |
| @@ -1117,7 +1116,7 @@ namespace · 3 unmodified lines | ||
| 1117 | 1116 | assert(0 <= type_id && type_id < static_cast<word_t>(types.size())); |
| 1118 | 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 | 1122 | EXEC_DECL(send) |
| @@ -1440,7 +1439,7 @@ namespace · 316 unmodified lines | ||
| 1440 | 1439 | assert(0 <= frame_type_id && frame_type_id < static_cast<word_t>(types.size())); |
| 1441 | 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 | 1445 | EXEC_DECL(mframe) |
| @@ -1500,7 +1499,8 @@ namespace · 53 unmodified lines | ||
| 1500 | 1499 | |
| 1501 | 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 | 1506 | EXEC_DECL(mcall) |
| @@ -28,6 +28,7 @@ using disvm::runtime::vm_memory_allocator_t; · 27 unmodified lines | ||
| 28 | 28 | using disvm::runtime::vm_string_t; |
| 29 | 29 | using disvm::runtime::vm_thread_t; |
| 30 | 30 | using disvm::runtime::vm_tool_controller_t; |
| 31 | +using disvm::runtime::word_t; | |
| 31 | 32 | |
| 32 | 33 | // Empty destructors for vm garbage collector 'interfaces' |
| 33 | 34 | vm_garbage_collector_t::~vm_garbage_collector_t() |
| @@ -97,11 +98,9 @@ namespace · 63 unmodified lines | ||
| 97 | 98 | { |
| 98 | 99 | public: |
| 99 | 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 | 104 | gc_colour_t curr_colour; |
| 106 | 105 | |
| 107 | 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 | 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 | 165 | auto a = vm_alloc_t::from_allocation(p); |
| 167 | 166 | |
| 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); | |
| 170 | 175 | |
| 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 | + } | |
| 174 | 196 | } |
| 175 | 197 | |
| 176 | 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 | 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 | 230 | set_gc_colour(curr, mark_cxt.curr_colour); |
| 209 | 231 | |
| 210 | 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 | 27 | vm_list_t::vm_list_t(std::shared_ptr<const type_descriptor_t> td, vm_list_t *tail) |
| 28 | 28 | : vm_alloc_t(vm_list_t::type_desc()) |
| 29 | − , _element_type{ td } | |
| 30 | 29 | , _is_alloc{ sizeof(_mem) < td->size_in_bytes } |
| 31 | 30 | , _mem{} |
| 32 | 31 | , _tail{ nullptr } |
| 33 | 32 | { |
| 33 | + _element_type = std::move(td); | |
| 34 | 34 | assert(_element_type != nullptr); |
| 35 | 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 | 110 | : frame_type{ std::move(td) } |
| 111 | 111 | { |
| 112 | 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 | 222 | if (page_top_frame == nullptr) |
| 223 | 223 | { |
| 224 | 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 | 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 | 233 | if ((new_frame_addr_maybe + new_frame_size) >= layout->top_page->page_limit_addr) |
| 234 | 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 | 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 | 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); | |
| 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)); | |
| 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); | |
| 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(); | |
| 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 | 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 | 131 | bool disvm::runtime::is_offset_pointer(const type_descriptor_t &type_desc, std::size_t offset) |
| 213 | 132 | { |
| 214 | 133 | if (type_desc.size_in_bytes == 0) |
| @@ -247,14 +166,15 @@ void vm_alloc_t::operator delete(void *ptr) · 32 unmodified lines | ||
| 247 | 166 | vm_alloc_t *vm_alloc_t::allocate(std::shared_ptr<const type_descriptor_t> td) |
| 248 | 167 | { |
| 249 | 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 | 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); | |
| 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) }; | |
| 255 | 175 | |
| 256 | 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 | 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 | 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 | 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 | 198 | , gc_reserved{ nullptr } |
| 287 | 199 | , _ref_count{ 1 } |
| 288 | 200 | { |
| @@ -330,13 +242,6 @@ std::size_t vm_alloc_t::get_ref_count() const · 41 unmodified lines | ||
| 330 | 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 | 245 | namespace |
| 341 | 246 | { |
| 342 | 247 | namespace hidden_type_desc |