Unified · Split
| @@ -198,7 +198,7 @@ namespace disvm · 197 unmodified lines | ||
| 198 | 198 | |
| 199 | 199 | public: |
| 200 | 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 | 202 | vm_array_t(const vm_string_t *s); |
| 203 | 203 | ~vm_array_t(); |
| 204 | 204 | |
| @@ -60,9 +60,12 @@ namespace disvm · 59 unmodified lines | ||
| 60 | 60 | // Destroy supplied memory based on the type descriptor |
| 61 | 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 | 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 | 69 | // Decrement the ref count and if 0 free the allocation |
| 67 | 70 | void dec_ref_count_and_free(vm_alloc_t *alloc); |
| 68 | 71 | |
| @@ -81,20 +84,21 @@ namespace disvm · 12 unmodified lines | ||
| 81 | 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 | 86 | const auto words8 = type_desc.pointer_map[i]; |
| 84 | − if (words8 != 0) | |
| 85 | − { | |
| 86 | − const auto flags = std::bitset<sizeof(words8) * 8>{ words8 }; | |
| 87 | − | |
| 88 | − // Enumerating the flags in reverse order so memory access is sequential. | |
| 89 | − if (flags[7] && (memory[0] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[0]), offset_accum); | |
| 90 | − if (flags[6] && (memory[1] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[1]), offset_accum + (1 * sizeof(pointer_t))); | |
| 91 | − if (flags[5] && (memory[2] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[2]), offset_accum + (2 * sizeof(pointer_t))); | |
| 92 | − if (flags[4] && (memory[3] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[3]), offset_accum + (3 * 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))); | |
| 94 | − if (flags[2] && (memory[5] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[5]), offset_accum + (5 * 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))); | |
| 96 | − if (flags[0] && (memory[7] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[7]), offset_accum + (7 * sizeof(pointer_t))); | |
| 97 | − } | |
| 87 | + assert(sizeof(words8) == 1); | |
| 88 | + if (words8 == 0) | |
| 89 | + continue; | |
| 90 | + | |
| 91 | + const auto flags = std::bitset<sizeof(words8) * 8>{ words8 }; | |
| 92 | + | |
| 93 | + // Enumerating the flags in reverse order so memory access is sequential. | |
| 94 | + if (flags[7] && (memory[0] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[0]), offset_accum); | |
| 95 | + if (flags[6] && (memory[1] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[1]), offset_accum + (1 * 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))); | |
| 97 | + if (flags[4] && (memory[3] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[3]), offset_accum + (3 * 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))); | |
| 99 | + if (flags[2] && (memory[5] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[5]), offset_accum + (5 * sizeof(pointer_t))); | |
| 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 | 116 | if (byte_offset < type_desc.map_in_bytes) |
| 113 | 117 | { |
| 114 | 118 | const auto words8 = type_desc.pointer_map[byte_offset]; |
| 119 | + assert(sizeof(words8) == 1); | |
| 115 | 120 | if (words8 != 0) |
| 116 | 121 | { |
| 117 | 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 | 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 | 47 | : vm_alloc_t(vm_array_t::type_desc()) |
| 48 | 48 | , _arr{ nullptr } |
| 49 | − , _element_type{ original->get_element_type() } | |
| 49 | + , _element_type{ original.get_element_type() } | |
| 50 | 50 | , _length{ length } |
| 51 | − , _original{ original } | |
| 51 | + , _original{ &original } | |
| 52 | 52 | { |
| 53 | − assert(_original != nullptr); | |
| 54 | − assert(0 <= begin_index && begin_index < _original->get_length()); | |
| 55 | − assert(_length >= 0 && (_length + begin_index) <= _original->get_length()); | |
| 53 | + assert(0 <= begin_index && (begin_index < _original->get_length() || (begin_index == _original->get_length() && length == 0))); | |
| 56 | 54 | |
| 57 | 55 | if (debug::is_component_tracing_enabled<debug::component_trace_t::memory>()) |
| 58 | 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 | 163 | // [PERF] There is a chance this copy is within the same array, therefore |
| 166 | 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 | 165 | const auto &type_desc = *_element_type; |
| 169 | 166 | auto source_array_element = source._arr; |
| 170 | 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 | 170 | inc_ref_count_in_memory(type_desc, source_array_element); |
| 174 | 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 | 174 | dest_array_element += type_desc.size_in_bytes; |
| 178 | 175 | } |
| 179 | 176 | } |
| @@ -548,8 +548,6 @@ namespace · 547 unmodified lines | ||
| 548 | 548 | auto type = types[type_id]; |
| 549 | 549 | |
| 550 | 550 | disvm::runtime::inc_ref_count_in_memory(*type, r.src); |
| 551 | − | |
| 552 | − // Decrement allocated pointers in the destination. | |
| 553 | 551 | destroy_memory(*type, r.dest); |
| 554 | 552 | |
| 555 | 553 | assert(r.src != nullptr && r.dest != nullptr); |
| @@ -863,7 +861,7 @@ namespace · 307 unmodified lines | ||
| 863 | 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 | 866 | if (arr->alloc_type->map_in_bytes > 0) |
| 869 | 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 | 302 | vm_string_t::~vm_string_t() |
| 303 | 303 | { |
| 304 | − // Free memory and string buffer | |
| 305 | − if (_is_alloc) | |
| 306 | − { | |
| 307 | − if (static_cast<void *>(_mem.alloc) != static_cast<void *>(_encoded_str)) | |
| 308 | − free_memory(_encoded_str); | |
| 304 | + // Determine if local or allocated memory | |
| 305 | + auto source = (_is_alloc) ? _mem.alloc : _mem.local; | |
| 306 | + if (static_cast<void *>(source) != static_cast<void *>(_encoded_str)) | |
| 307 | + free_memory(_encoded_str); | |
| 309 | 308 | |
| 310 | − free_memory(_mem.alloc); | |
| 311 | − } | |
| 312 | − else | |
| 313 | − { | |
| 314 | − if (static_cast<void *>(_mem.local) != static_cast<void *>(_encoded_str)) | |
| 315 | − free_memory(_encoded_str); | |
| 316 | − } | |
| 309 | + if (_is_alloc) | |
| 310 | + free_memory(source); | |
| 317 | 311 | |
| 318 | 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 | 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 | 335 | const auto local_source = (_is_alloc) ? _mem.alloc : _mem.local; |
| 342 | 336 | |
| 343 | 337 | // Release the encoded string for this instance. |
| 344 | − { | |
| 345 | − std::lock_guard<std::mutex> lock{ _encoded_str_lock }; | |
| 346 | − if (_encoded_str != reinterpret_cast<char*>(local_source)) | |
| 347 | − { | |
| 348 | − free_memory(_encoded_str); | |
| 349 | − _encoded_str = nullptr; | |
| 350 | − } | |
| 351 | − } | |
| 338 | + if (_encoded_str != reinterpret_cast<char*>(local_source)) | |
| 339 | + free_memory(_encoded_str); | |
| 340 | + | |
| 341 | + _encoded_str = nullptr; | |
| 352 | 342 | |
| 353 | 343 | // Define the values for the appended string |
| 354 | 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 | 417 | throw index_out_of_range_memory{ 0, _length, index }; |
| 428 | 418 | |
| 429 | 419 | // Determine if local or allocated memory |
| 430 | − auto source = static_cast<uint8_t *>(_mem.local); | |
| 431 | − if (_is_alloc) | |
| 432 | − { | |
| 433 | − source = static_cast<uint8_t *>(_mem.alloc); | |
| 420 | + auto source = (_is_alloc) ? _mem.alloc : _mem.local; | |
| 434 | 421 | |
| 435 | − // Since we are setting a rune, the string value should be freed. | |
| 436 | − if (_encoded_str != nullptr) | |
| 437 | − free_memory(_encoded_str); | |
| 438 | − } | |
| 422 | + // Release the encoded string for this instance. | |
| 423 | + if (_encoded_str != reinterpret_cast<char*>(source)) | |
| 424 | + free_memory(_encoded_str); | |
| 439 | 425 | |
| 440 | − // Reset the string so it can be regenerated. | |
| 441 | 426 | _encoded_str = nullptr; |
| 442 | 427 | |
| 443 | 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 | 498 | if (_character_size == sizeof(char)) |
| 514 | 499 | { |
| 515 | 500 | _encoded_str = (_is_alloc) ? reinterpret_cast<char *>(_mem.alloc) : reinterpret_cast<char *>(_mem.local); |
| 501 | + _encoded_str[_length] = '\0'; | |
| 516 | 502 | return _encoded_str; |
| 517 | 503 | } |
| 518 | 504 | |
| @@ -158,19 +158,22 @@ namespace · 157 unmodified lines | ||
| 158 | 158 | |
| 159 | 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); | |
| 162 | − | |
| 161 | + dec_ref_count_in_memory(type_desc, data); | |
| 163 | 162 | debug::assign_debug_memory(data, type_desc.size_in_bytes); |
| 164 | 163 | } |
| 165 | 164 | |
| 166 | 165 | void disvm::runtime::inc_ref_count_in_memory(const type_descriptor_t &type_desc, void *data) |
| 167 | 166 | { |
| 168 | − if (data == nullptr) | |
| 169 | − return; | |
| 170 | − | |
| 167 | + assert(data != nullptr); | |
| 171 | 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 | 177 | void disvm::runtime::dec_ref_count_and_free(vm_alloc_t *alloc) |
| 175 | 178 | { |
| 176 | 179 | if (alloc == nullptr) |
| @@ -460,7 +463,7 @@ std::shared_ptr<const type_descriptor_t> type_descriptor_t::create( · 283 unmodified lines | ||
| 460 | 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 | 467 | return std::shared_ptr<type_descriptor_t>{ new_type, deleter }; |
| 465 | 468 | } |
| 466 | 469 | |