Unified · Split
| @@ -198,7 +198,7 @@ namespace disvm · 197 unmodified lines | |||
| 198 | 198 | ||
| 199 | public: | 199 | public: |
| 200 | vm_array_t(std::shared_ptr<const type_descriptor_t> td, word_t length); | 200 | vm_array_t(std::shared_ptr<const type_descriptor_t> td, word_t length); |
| 201 | vm_array_t(vm_array_t *original, word_t begin_index, word_t length); | 201 | vm_array_t(vm_array_t &original, word_t begin_index, word_t length); |
| 202 | vm_array_t(const vm_string_t *s); | 202 | vm_array_t(const vm_string_t *s); |
| 203 | ~vm_array_t(); | 203 | ~vm_array_t(); |
| 204 | 204 | ||
| @@ -60,9 +60,12 @@ namespace disvm · 59 unmodified lines | |||
| 60 | // Destroy supplied memory based on the type descriptor | 60 | // Destroy supplied memory based on the type descriptor |
| 61 | void destroy_memory(const type_descriptor_t &type_desc, void *data); | 61 | void destroy_memory(const type_descriptor_t &type_desc, void *data); |
| 62 | 62 | ||
| 63 | // Increment the ref count of all points in the supplied memory allocation | 63 | // Increment the ref count of all pointers in the supplied memory allocation |
| 64 | void inc_ref_count_in_memory(const type_descriptor_t &type_desc, void *data); | 64 | void inc_ref_count_in_memory(const type_descriptor_t &type_desc, void *data); |
| 65 | 65 | ||
| 66 | // Decrement the ref count of all pointers in the supplied memory allocation | ||
| 67 | void dec_ref_count_in_memory(const type_descriptor_t &type_desc, void *data); | ||
| 68 | |||
| 66 | // Decrement the ref count and if 0 free the allocation | 69 | // Decrement the ref count and if 0 free the allocation |
| 67 | void dec_ref_count_and_free(vm_alloc_t *alloc); | 70 | void dec_ref_count_and_free(vm_alloc_t *alloc); |
| 68 | 71 | ||
| @@ -81,20 +84,21 @@ namespace disvm · 12 unmodified lines | |||
| 81 | for (auto i = word_t{ 0 }; i < type_desc.map_in_bytes; ++i, memory += 8, offset_accum += (8 * sizeof(pointer_t))) | 84 | for (auto i = word_t{ 0 }; i < type_desc.map_in_bytes; ++i, memory += 8, offset_accum += (8 * sizeof(pointer_t))) |
| 82 | { | 85 | { |
| 83 | const auto words8 = type_desc.pointer_map[i]; | 86 | const auto words8 = type_desc.pointer_map[i]; |
| 84 | if (words8 != 0) | 87 | assert(sizeof(words8) == 1); |
| 85 | { | 88 | if (words8 == 0) |
| 86 | const auto flags = std::bitset<sizeof(words8) * 8>{ words8 }; | 89 | continue; |
| 87 | 90 | ||
| 88 | // Enumerating the flags in reverse order so memory access is sequential. | 91 | const auto flags = std::bitset<sizeof(words8) * 8>{ words8 }; |
| 89 | if (flags[7] && (memory[0] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[0]), offset_accum); | 92 | |
| 90 | if (flags[6] && (memory[1] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[1]), offset_accum + (1 * sizeof(pointer_t))); | 93 | // Enumerating the flags in reverse order so memory access is sequential. |
| 91 | if (flags[5] && (memory[2] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[2]), offset_accum + (2 * sizeof(pointer_t))); | 94 | if (flags[7] && (memory[0] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[0]), offset_accum); |
| 92 | if (flags[4] && (memory[3] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[3]), offset_accum + (3 * sizeof(pointer_t))); | 95 | if (flags[6] && (memory[1] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[1]), offset_accum + (1 * sizeof(pointer_t))); |
| 93 | if (flags[3] && (memory[4] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[4]), offset_accum + (4 * sizeof(pointer_t))); | 96 | if (flags[5] && (memory[2] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[2]), offset_accum + (2 * sizeof(pointer_t))); |
| 94 | if (flags[2] && (memory[5] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[5]), offset_accum + (5 * sizeof(pointer_t))); | 97 | if (flags[4] && (memory[3] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[3]), offset_accum + (3 * sizeof(pointer_t))); |
| 95 | if (flags[1] && (memory[6] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[6]), offset_accum + (6 * sizeof(pointer_t))); | 98 | if (flags[3] && (memory[4] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[4]), offset_accum + (4 * sizeof(pointer_t))); |
| 96 | if (flags[0] && (memory[7] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[7]), offset_accum + (7 * sizeof(pointer_t))); | 99 | if (flags[2] && (memory[5] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[5]), offset_accum + (5 * sizeof(pointer_t))); |
| 97 | } | 100 | if (flags[1] && (memory[6] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[6]), offset_accum + (6 * sizeof(pointer_t))); |
| 101 | if (flags[0] && (memory[7] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[7]), offset_accum + (7 * sizeof(pointer_t))); | ||
| 98 | } | 102 | } |
| 99 | } | 103 | } |
| 100 | 104 | ||
| @@ -112,6 +116,7 @@ namespace disvm · 11 unmodified lines | |||
| 112 | if (byte_offset < type_desc.map_in_bytes) | 116 | if (byte_offset < type_desc.map_in_bytes) |
| 113 | { | 117 | { |
| 114 | const auto words8 = type_desc.pointer_map[byte_offset]; | 118 | const auto words8 = type_desc.pointer_map[byte_offset]; |
| 119 | assert(sizeof(words8) == 1); | ||
| 115 | if (words8 != 0) | 120 | if (words8 != 0) |
| 116 | { | 121 | { |
| 117 | const auto flags = std::bitset<sizeof(words8) * 8>{ words8 }; | 122 | const auto flags = std::bitset<sizeof(words8) * 8>{ words8 }; |
| @@ -43,16 +43,14 @@ vm_array_t::vm_array_t(std::shared_ptr<const type_descriptor_t> td, word_t lengt · 42 unmodified lines | |||
| 43 | debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "end: init: elements: %d", array_len); | 43 | debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "end: init: elements: %d", array_len); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | vm_array_t::vm_array_t(vm_array_t *original, word_t begin_index, word_t length) | 46 | vm_array_t::vm_array_t(vm_array_t &original, word_t begin_index, word_t length) |
| 47 | : vm_alloc_t(vm_array_t::type_desc()) | 47 | : vm_alloc_t(vm_array_t::type_desc()) |
| 48 | , _arr{ nullptr } | 48 | , _arr{ nullptr } |
| 49 | , _element_type{ original->get_element_type() } | 49 | , _element_type{ original.get_element_type() } |
| 50 | , _length{ length } | 50 | , _length{ length } |
| 51 | , _original{ original } | 51 | , _original{ &original } |
| 52 | { | 52 | { |
| 53 | assert(_original != nullptr); | 53 | assert(0 <= begin_index && (begin_index < _original->get_length() || (begin_index == _original->get_length() && length == 0))); |
| 54 | assert(0 <= begin_index && begin_index < _original->get_length()); | ||
| 55 | assert(_length >= 0 && (_length + begin_index) <= _original->get_length()); | ||
| 56 | 54 | ||
| 57 | if (debug::is_component_tracing_enabled<debug::component_trace_t::memory>()) | 55 | if (debug::is_component_tracing_enabled<debug::component_trace_t::memory>()) |
| 58 | debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "init: vm array: slice: %d %d", begin_index, _length); | 56 | debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "init: vm array: slice: %d %d", begin_index, _length); |
| @@ -164,7 +162,6 @@ void vm_array_t::copy_from(const vm_array_t &source, word_t this_begin_index) · 105 unmodified lines | |||
| 164 | { | 162 | { |
| 165 | // [PERF] There is a chance this copy is within the same array, therefore | 163 | // [PERF] There is a chance this copy is within the same array, therefore |
| 166 | // a check could be made to not ref count memory that is going to be moved. | 164 | // a check could be made to not ref count memory that is going to be moved. |
| 167 | // The Inferno implementation of slicela handles this case (libinterp/xec.c). | ||
| 168 | const auto &type_desc = *_element_type; | 165 | const auto &type_desc = *_element_type; |
| 169 | auto source_array_element = source._arr; | 166 | auto source_array_element = source._arr; |
| 170 | auto dest_array_element = dest_arr; | 167 | auto dest_array_element = dest_arr; |
| @@ -173,7 +170,7 @@ void vm_array_t::copy_from(const vm_array_t &source, word_t this_begin_index) · 2 unmodified lines | |||
| 173 | inc_ref_count_in_memory(type_desc, source_array_element); | 170 | inc_ref_count_in_memory(type_desc, source_array_element); |
| 174 | source_array_element += type_desc.size_in_bytes; | 171 | source_array_element += type_desc.size_in_bytes; |
| 175 | 172 | ||
| 176 | destroy_memory(type_desc, dest_array_element); | 173 | dec_ref_count_in_memory(type_desc, dest_array_element); |
| 177 | dest_array_element += type_desc.size_in_bytes; | 174 | dest_array_element += type_desc.size_in_bytes; |
| 178 | } | 175 | } |
| 179 | } | 176 | } |
| @@ -548,8 +548,6 @@ namespace · 547 unmodified lines | |||
| 548 | auto type = types[type_id]; | 548 | auto type = types[type_id]; |
| 549 | 549 | ||
| 550 | disvm::runtime::inc_ref_count_in_memory(*type, r.src); | 550 | disvm::runtime::inc_ref_count_in_memory(*type, r.src); |
| 551 | |||
| 552 | // Decrement allocated pointers in the destination. | ||
| 553 | destroy_memory(*type, r.dest); | 551 | destroy_memory(*type, r.dest); |
| 554 | 552 | ||
| 555 | assert(r.src != nullptr && r.dest != nullptr); | 553 | assert(r.src != nullptr && r.dest != nullptr); |
| @@ -863,7 +861,7 @@ namespace · 307 unmodified lines | |||
| 863 | throw out_of_range_memory{}; | 861 | throw out_of_range_memory{}; |
| 864 | } | 862 | } |
| 865 | 863 | ||
| 866 | auto new_array = new vm_array_t(arr, begin_index, length); | 864 | auto new_array = new vm_array_t(*arr, begin_index, length); |
| 867 | 865 | ||
| 868 | if (arr->alloc_type->map_in_bytes > 0) | 866 | if (arr->alloc_type->map_in_bytes > 0) |
| 869 | vm.get_garbage_collector().track_allocation(new_array); | 867 | vm.get_garbage_collector().track_allocation(new_array); |
| @@ -301,23 +301,17 @@ vm_string_t::vm_string_t(const vm_string_t &other, word_t begin_index, word_t en · 300 unmodified lines | |||
| 301 | 301 | ||
| 302 | vm_string_t::~vm_string_t() | 302 | vm_string_t::~vm_string_t() |
| 303 | { | 303 | { |
| 304 | // Free memory and string buffer | 304 | // Determine if local or allocated memory |
| 305 | if (_is_alloc) | 305 | auto source = (_is_alloc) ? _mem.alloc : _mem.local; |
| 306 | { | 306 | if (static_cast<void *>(source) != static_cast<void *>(_encoded_str)) |
| 307 | if (static_cast<void *>(_mem.alloc) != static_cast<void *>(_encoded_str)) | 307 | free_memory(_encoded_str); |
| 308 | free_memory(_encoded_str); | ||
| 309 | 308 | ||
| 310 | free_memory(_mem.alloc); | 309 | if (_is_alloc) |
| 311 | } | 310 | free_memory(source); |
| 312 | else | ||
| 313 | { | ||
| 314 | if (static_cast<void *>(_mem.local) != static_cast<void *>(_encoded_str)) | ||
| 315 | free_memory(_encoded_str); | ||
| 316 | } | ||
| 317 | 311 | ||
| 318 | debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "destroy: vm string"); | 312 | debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "destroy: vm string"); |
| 319 | 313 | ||
| 320 | debug::assign_debug_pointer(&_mem.alloc); | 314 | debug::assign_debug_pointer(&source); |
| 321 | debug::assign_debug_pointer(&_encoded_str); | 315 | debug::assign_debug_pointer(&_encoded_str); |
| 322 | } | 316 | } |
| 323 | 317 | ||
| @@ -341,14 +335,10 @@ vm_string_t &vm_string_t::append(const vm_string_t &other) · 17 unmodified lines | |||
| 341 | const auto local_source = (_is_alloc) ? _mem.alloc : _mem.local; | 335 | const auto local_source = (_is_alloc) ? _mem.alloc : _mem.local; |
| 342 | 336 | ||
| 343 | // Release the encoded string for this instance. | 337 | // Release the encoded string for this instance. |
| 344 | { | 338 | if (_encoded_str != reinterpret_cast<char*>(local_source)) |
| 345 | std::lock_guard<std::mutex> lock{ _encoded_str_lock }; | 339 | free_memory(_encoded_str); |
| 346 | if (_encoded_str != reinterpret_cast<char*>(local_source)) | 340 | |
| 347 | { | 341 | _encoded_str = nullptr; |
| 348 | free_memory(_encoded_str); | ||
| 349 | _encoded_str = nullptr; | ||
| 350 | } | ||
| 351 | } | ||
| 352 | 342 | ||
| 353 | // Define the values for the appended string | 343 | // Define the values for the appended string |
| 354 | const auto new_length = local_length + other_length; | 344 | const auto new_length = local_length + other_length; |
| @@ -427,17 +417,12 @@ void vm_string_t::set_rune(word_t index, rune_t value) · 72 unmodified lines | |||
| 427 | throw index_out_of_range_memory{ 0, _length, index }; | 417 | throw index_out_of_range_memory{ 0, _length, index }; |
| 428 | 418 | ||
| 429 | // Determine if local or allocated memory | 419 | // Determine if local or allocated memory |
| 430 | auto source = static_cast<uint8_t *>(_mem.local); | 420 | auto source = (_is_alloc) ? _mem.alloc : _mem.local; |
| 431 | if (_is_alloc) | ||
| 432 | { | ||
| 433 | source = static_cast<uint8_t *>(_mem.alloc); | ||
| 434 | 421 | ||
| 435 | // Since we are setting a rune, the string value should be freed. | 422 | // Release the encoded string for this instance. |
| 436 | if (_encoded_str != nullptr) | 423 | if (_encoded_str != reinterpret_cast<char*>(source)) |
| 437 | free_memory(_encoded_str); | 424 | free_memory(_encoded_str); |
| 438 | } | ||
| 439 | 425 | ||
| 440 | // Reset the string so it can be regenerated. | ||
| 441 | _encoded_str = nullptr; | 426 | _encoded_str = nullptr; |
| 442 | 427 | ||
| 443 | const auto new_character_size = (value > utf8::constants::max_codepoint_ascii) ? sizeof(rune_t) : sizeof(char); | 428 | const auto new_character_size = (value > utf8::constants::max_codepoint_ascii) ? sizeof(rune_t) : sizeof(char); |
| @@ -513,6 +498,7 @@ const char *vm_string_t::str() const · 69 unmodified lines | |||
| 513 | if (_character_size == sizeof(char)) | 498 | if (_character_size == sizeof(char)) |
| 514 | { | 499 | { |
| 515 | _encoded_str = (_is_alloc) ? reinterpret_cast<char *>(_mem.alloc) : reinterpret_cast<char *>(_mem.local); | 500 | _encoded_str = (_is_alloc) ? reinterpret_cast<char *>(_mem.alloc) : reinterpret_cast<char *>(_mem.local); |
| 501 | _encoded_str[_length] = '\0'; | ||
| 516 | return _encoded_str; | 502 | return _encoded_str; |
| 517 | } | 503 | } |
| 518 | 504 | ||
| @@ -158,19 +158,22 @@ namespace · 157 unmodified lines | |||
| 158 | 158 | ||
| 159 | void disvm::runtime::destroy_memory(const type_descriptor_t &type_desc, void *data) | 159 | void disvm::runtime::destroy_memory(const type_descriptor_t &type_desc, void *data) |
| 160 | { | 160 | { |
| 161 | enum_pointer_fields(type_desc, data, dec_ref_and_free_pointer_field); | 161 | dec_ref_count_in_memory(type_desc, data); |
| 162 | |||
| 163 | debug::assign_debug_memory(data, type_desc.size_in_bytes); | 162 | debug::assign_debug_memory(data, type_desc.size_in_bytes); |
| 164 | } | 163 | } |
| 165 | 164 | ||
| 166 | void disvm::runtime::inc_ref_count_in_memory(const type_descriptor_t &type_desc, void *data) | 165 | void disvm::runtime::inc_ref_count_in_memory(const type_descriptor_t &type_desc, void *data) |
| 167 | { | 166 | { |
| 168 | if (data == nullptr) | 167 | assert(data != nullptr); |
| 169 | return; | ||
| 170 | |||
| 171 | enum_pointer_fields(type_desc, data, add_ref_pointer_field); | 168 | enum_pointer_fields(type_desc, data, add_ref_pointer_field); |
| 172 | } | 169 | } |
| 173 | 170 | ||
| 171 | void disvm::runtime::dec_ref_count_in_memory(const type_descriptor_t &type_desc, void *data) | ||
| 172 | { | ||
| 173 | assert(data != nullptr); | ||
| 174 | enum_pointer_fields(type_desc, data, dec_ref_and_free_pointer_field); | ||
| 175 | } | ||
| 176 | |||
| 174 | void disvm::runtime::dec_ref_count_and_free(vm_alloc_t *alloc) | 177 | void disvm::runtime::dec_ref_count_and_free(vm_alloc_t *alloc) |
| 175 | { | 178 | { |
| 176 | if (alloc == nullptr) | 179 | if (alloc == nullptr) |
| @@ -460,7 +463,7 @@ std::shared_ptr<const type_descriptor_t> type_descriptor_t::create( · 283 unmodified lines | |||
| 460 | pointer_map_local[i] = pointer_map[i]; | 463 | pointer_map_local[i] = pointer_map[i]; |
| 461 | } | 464 | } |
| 462 | 465 | ||
| 463 | auto new_type = ::new(new_type_memory) type_descriptor_t{ size_in_bytes, pointer_map_length, pointer_map_local, finalizer, "#" }; | 466 | auto new_type = ::new(new_type_memory) type_descriptor_t{ size_in_bytes, pointer_map_length, pointer_map_local, finalizer, "?" }; |
| 464 | return std::shared_ptr<type_descriptor_t>{ new_type, deleter }; | 467 | return std::shared_ptr<type_descriptor_t>{ new_type, deleter }; |
| 465 | } | 468 | } |
| 466 | 469 | ||