Remove global memory lock mechanism - Wasn't being used but showed up on profile report :( Move enum_pointer_fields and is_offset_pointer impls into cpp file Create enum_pointer_fields_with_offset function since the VM never needs the offset values and the generated code was about 5% bigger. Now the VM can use the callback without the offset. Removed pointless init_memory() usage since alloc_memory() now is required to return zeroed out memory. Fixed bugs in GC Added support - Ranged absolute disassembly in debugger - New duration log component
Showing the changes to src/include (3 of 12 files). Show all
Unified · Split
| @@ -31,9 +31,10 @@ namespace disvm · 30 unmodified lines | |||
| 31 | // Potentially logged from a VM extension. | 31 | // Potentially logged from a VM extension. |
| 32 | scheduler, | 32 | scheduler, |
| 33 | garbage_collector, | 33 | garbage_collector, |
| 34 | duration, | ||
| 34 | 35 | ||
| 35 | // Tracking purposes | 36 | // Tracking purposes |
| 36 | last = garbage_collector | 37 | last = duration |
| 37 | }; | 38 | }; |
| 38 | 39 | ||
| 39 | // Trace component enable state. | 40 | // Trace component enable state. |
| @@ -104,7 +104,7 @@ namespace disvm · 103 unmodified lines | |||
| 104 | static T *from_allocation(pointer_t allocation) | 104 | static T *from_allocation(pointer_t allocation) |
| 105 | { | 105 | { |
| 106 | auto alloc_inst = vm_alloc_t::from_allocation(allocation); | 106 | auto alloc_inst = vm_alloc_t::from_allocation(allocation); |
| 107 | assert(alloc_inst == nullptr || alloc_inst->alloc_type == intrinsic_type_desc::type<T>()); | 107 | assert(alloc_inst == nullptr || alloc_inst->alloc_type->is_equal(intrinsic_type_desc::type<T>().get())); |
| 108 | return static_cast<T *>(alloc_inst); | 108 | return static_cast<T *>(alloc_inst); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| @@ -875,7 +875,7 @@ namespace disvm · 764 unmodified lines | |||
| 875 | // Called by the scheduler to inform the collector it should attempt to free resources. | 875 | // Called by the scheduler to inform the collector it should attempt to free resources. |
| 876 | // All VM threads are guaranteed to be idle when called. | 876 | // All VM threads are guaranteed to be idle when called. |
| 877 | // Returns true if the collection algorithm was run, otherwise false. | 877 | // Returns true if the collection algorithm was run, otherwise false. |
| 878 | virtual bool collect(std::vector<std::shared_ptr<const vm_thread_t>> &threads) = 0; | 878 | virtual bool collect(std::vector<std::shared_ptr<const vm_thread_t>> threads) = 0; |
| 879 | }; | 879 | }; |
| 880 | 880 | ||
| 881 | // Create a garbage collector that does nothing. | 881 | // Create a garbage collector that does nothing. |
| @@ -20,26 +20,6 @@ namespace disvm · 19 unmodified lines | |||
| 20 | { | 20 | { |
| 21 | namespace runtime | 21 | namespace runtime |
| 22 | { | 22 | { |
| 23 | class global_alloc_lock_t final | ||
| 24 | { | ||
| 25 | public: | ||
| 26 | global_alloc_lock_t(const global_alloc_lock_t &) = delete; | ||
| 27 | global_alloc_lock_t& operator=(const global_alloc_lock_t &) = delete; | ||
| 28 | |||
| 29 | global_alloc_lock_t(global_alloc_lock_t &&); | ||
| 30 | |||
| 31 | ~global_alloc_lock_t(); | ||
| 32 | |||
| 33 | private: | ||
| 34 | bool _owner; | ||
| 35 | global_alloc_lock_t(bool owner); | ||
| 36 | friend global_alloc_lock_t get_global_alloc_lock(); | ||
| 37 | }; | ||
| 38 | |||
| 39 | // Take the global allocation lock for the VM heap. | ||
| 40 | // While this lock is taken all further allocations will block. | ||
| 41 | global_alloc_lock_t get_global_alloc_lock(); | ||
| 42 | |||
| 43 | // Allocate memory from the VM heap that is initialize to 0. | 23 | // Allocate memory from the VM heap that is initialize to 0. |
| 44 | // [SPEC] All memory in this implementation of the Dis VM spec | 24 | // [SPEC] All memory in this implementation of the Dis VM spec |
| 45 | // will be 0 initialized. | 25 | // will be 0 initialized. |
| @@ -69,63 +49,20 @@ namespace disvm · 23 unmodified lines | |||
| 69 | // Decrement the ref count and if 0 free the allocation | 49 | // Decrement the ref count and if 0 free the allocation |
| 70 | void dec_ref_count_and_free(vm_alloc_t *alloc); | 50 | void dec_ref_count_and_free(vm_alloc_t *alloc); |
| 71 | 51 | ||
| 52 | // Callback for a pointer field supplying the pointer | ||
| 53 | using pointer_field_callback_t = std::function<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 | |||
| 72 | // Callback for a pointer field supplying the pointer and byte offset | 58 | // Callback for a pointer field supplying the pointer and byte offset |
| 73 | using pointer_field_callback_t = std::function<void(pointer_t, std::size_t)>; | 59 | using pointer_field_offset_callback_t = std::function<void(pointer_t, std::size_t)>; |
| 74 | 60 | ||
| 75 | // The callback will be called on all non-null pointer fields. | 61 | // The callback will be called on all non-null pointer fields. |
| 76 | inline void enum_pointer_fields(const type_descriptor_t &type_desc, void *data, pointer_field_callback_t callback) | 62 | void enum_pointer_fields_with_offset(const type_descriptor_t &type_desc, void *data, pointer_field_offset_callback_t callback); |
| 77 | { | ||
| 78 | assert(data != nullptr && callback != nullptr); | ||
| 79 | if (type_desc.size_in_bytes == 0) | ||
| 80 | return; | ||
| 81 | |||
| 82 | auto offset_accum = std::size_t{ 0 }; | ||
| 83 | auto memory = reinterpret_cast<word_t *>(data); | ||
| 84 | for (auto i = word_t{ 0 }; i < type_desc.map_in_bytes; ++i, memory += 8, offset_accum += (8 * sizeof(pointer_t))) | ||
| 85 | { | ||
| 86 | const auto words8 = type_desc.pointer_map[i]; | ||
| 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))); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | 63 | ||
| 105 | // Check if a specific pointer-sized offset in a type represents a pointer | 64 | // Check if a specific pointer-sized offset in a type represents a pointer |
| 106 | inline bool is_offset_pointer(const type_descriptor_t &type_desc, std::size_t offset) | 65 | bool is_offset_pointer(const type_descriptor_t &type_desc, std::size_t offset); |
| 107 | { | ||
| 108 | if (type_desc.size_in_bytes == 0) | ||
| 109 | return false; | ||
| 110 | |||
| 111 | assert(offset < static_cast<std::size_t>(std::numeric_limits<word_t>::max())); | ||
| 112 | const auto byte_offset = static_cast<word_t>(offset / 8); | ||
| 113 | |||
| 114 | // Highest order bit is the first field | ||
| 115 | const auto bit_offset = 7 - (offset % 8); | ||
| 116 | if (byte_offset < type_desc.map_in_bytes) | ||
| 117 | { | ||
| 118 | const auto words8 = type_desc.pointer_map[byte_offset]; | ||
| 119 | assert(sizeof(words8) == 1); | ||
| 120 | if (words8 != 0) | ||
| 121 | { | ||
| 122 | const auto flags = std::bitset<sizeof(words8) * 8>{ words8 }; | ||
| 123 | return flags[bit_offset]; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | return false; | ||
| 128 | } | ||
| 129 | } | 66 | } |
| 130 | } | 67 | } |
| 131 | 68 | ||