History

Alter debugger API to accept vector value not reference.

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

arr committed 9 years ago

Commit cc8f2b61 parent 41616d412 files · +167 −250Browse files

Showing the changes to src/vm/vm_memory.cpp (1 of 12 files). Show all

Unified · Split

src/vm/vm_memory.cpp+88−87
@@ -20,92 +20,8 @@ · 19 unmodified lines
2020 using namespace disvm;
2121 using namespace disvm::runtime;
2222
23−namespace
24−{
25− std::mutex global_lock;
26− std::condition_variable release_lock;
27−
28− enum class lock_state_t
29− {
30− none,
31− pending,
32− active
33− };
34−
35− std::atomic<uint32_t> allocating_thread_count;
36− std::atomic<lock_state_t> lock_state;
37−
38− struct safe_alloc final
39− {
40− safe_alloc()
41− {
42− allocating_thread_count++;
43− if (lock_state != lock_state_t::none)
44− {
45− allocating_thread_count--;
46−
47− std::unique_lock<std::mutex> lock{ global_lock };
48− release_lock.wait(lock, [&]{ return lock_state == lock_state_t::none; });
49−
50− allocating_thread_count++;
51− }
52− }
53−
54− ~safe_alloc()
55− {
56− assert(allocating_thread_count > 0);
57− allocating_thread_count--;
58− }
59− };
60−}
61−
62−global_alloc_lock_t::global_alloc_lock_t(bool owner)
63− : _owner{ owner }
64−{ }
65−
66−global_alloc_lock_t::global_alloc_lock_t(global_alloc_lock_t &&other)
67− : _owner{ other._owner }
68−{
69− other._owner = false;
70−}
71−
72−global_alloc_lock_t::~global_alloc_lock_t()
73−{
74− if (_owner)
75− {
76− lock_state = lock_state_t::none;
77− release_lock.notify_all();
78− }
79−}
80−
81−// Lock all allocations on the VM heap.
82−global_alloc_lock_t disvm::runtime::get_global_alloc_lock()
83−{
84− auto expected = lock_state_t::none;
85−
86− // Block while trying to get lock
87− while (!lock_state.compare_exchange_strong(expected, lock_state_t::pending))
88− {
89− expected = lock_state_t::none;
90− std::unique_lock<std::mutex> lock{ global_lock };
91− release_lock.wait(lock);
92− }
93−
94− while (allocating_thread_count != 0)
95− {
96− // Spin-wait for all allocating threads to stop
97− }
98−
99− // Transition to active lock state
100− lock_state = lock_state_t::active;
101−
102− return{ true };
103−}
104−
10523 void *disvm::runtime::alloc_memory(std::size_t amount_in_bytes)
10624 {
107− safe_alloc s;
108−
10925 auto memory = std::calloc(amount_in_bytes, sizeof(byte_t));
11026 if (memory == nullptr)
11127 throw vm_system_exception{ "Out of memory" };
@@ -143,13 +59,13 @@ void disvm::runtime::init_memory(const type_descriptor_t &type_desc, void *data) · 31 unmodified lines
14359
14460 namespace
14561 {
146− void dec_ref_and_free_pointer_field(pointer_t pointer_field, std::size_t)
62+ void dec_ref_and_free_pointer_field(pointer_t pointer_field)
14763 {
14864 assert(pointer_field != nullptr);
14965 dec_ref_count_and_free(vm_alloc_t::from_allocation(pointer_field));
15066 }
15167
152− void add_ref_pointer_field(pointer_t pointer_field, std::size_t)
68+ void add_ref_pointer_field(pointer_t pointer_field)
15369 {
15470 assert(pointer_field != nullptr);
15571 vm_alloc_t::from_allocation(pointer_field)->add_ref();
@@ -184,6 +100,89 @@ void disvm::runtime::dec_ref_count_and_free(vm_alloc_t *alloc) · 28 unmodified lines
184100 delete alloc;
185101 }
186102
103+void disvm::runtime::enum_pointer_fields(const type_descriptor_t &type_desc, void *data, pointer_field_callback_t callback)
104+{
105+ assert(data != nullptr && callback != nullptr);
106+ if (type_desc.size_in_bytes == 0)
107+ return;
108+
109+ auto offset_accum = std::size_t{ 0 };
110+ auto memory = reinterpret_cast<word_t *>(data);
111+ for (auto i = word_t{ 0 }; i < type_desc.map_in_bytes; ++i, memory += 8, offset_accum += (8 * sizeof(pointer_t)))
112+ {
113+ const auto words8 = type_desc.pointer_map[i];
114+ assert(sizeof(words8) == 1);
115+ if (words8 == 0)
116+ continue;
117+
118+ const auto flags = std::bitset<sizeof(words8) * 8>{ words8 };
119+
120+ // Enumerating the flags in reverse order so memory access is sequential.
121+ if (flags[7] && (memory[0] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[0]));
122+ if (flags[6] && (memory[1] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[1]));
123+ if (flags[5] && (memory[2] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[2]));
124+ if (flags[4] && (memory[3] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[3]));
125+ if (flags[3] && (memory[4] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[4]));
126+ if (flags[2] && (memory[5] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[5]));
127+ if (flags[1] && (memory[6] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[6]));
128+ if (flags[0] && (memory[7] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[7]));
129+ }
130+}
131+
132+void disvm::runtime::enum_pointer_fields_with_offset(const type_descriptor_t &type_desc, void *data, pointer_field_offset_callback_t callback)
133+{
134+ assert(data != nullptr && callback != nullptr);
135+ if (type_desc.size_in_bytes == 0)
136+ return;
137+
138+ auto offset_accum = std::size_t{ 0 };
139+ auto memory = reinterpret_cast<word_t *>(data);
140+ for (auto i = word_t{ 0 }; i < type_desc.map_in_bytes; ++i, memory += 8, offset_accum += (8 * sizeof(pointer_t)))
141+ {
142+ const auto words8 = type_desc.pointer_map[i];
143+ assert(sizeof(words8) == 1);
144+ if (words8 == 0)
145+ continue;
146+
147+ const auto flags = std::bitset<sizeof(words8) * 8>{ words8 };
148+
149+ // Enumerating the flags in reverse order so memory access is sequential.
150+ if (flags[7] && (memory[0] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[0]), offset_accum);
151+ if (flags[6] && (memory[1] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[1]), offset_accum + (1 * sizeof(pointer_t)));
152+ if (flags[5] && (memory[2] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[2]), offset_accum + (2 * sizeof(pointer_t)));
153+ if (flags[4] && (memory[3] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[3]), offset_accum + (3 * sizeof(pointer_t)));
154+ if (flags[3] && (memory[4] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[4]), offset_accum + (4 * sizeof(pointer_t)));
155+ if (flags[2] && (memory[5] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[5]), offset_accum + (5 * sizeof(pointer_t)));
156+ if (flags[1] && (memory[6] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[6]), offset_accum + (6 * sizeof(pointer_t)));
157+ if (flags[0] && (memory[7] != runtime_constants::nil)) callback(reinterpret_cast<pointer_t>(memory[7]), offset_accum + (7 * sizeof(pointer_t)));
158+ }
159+}
160+
161+bool disvm::runtime::is_offset_pointer(const type_descriptor_t &type_desc, std::size_t offset)
162+{
163+ if (type_desc.size_in_bytes == 0)
164+ return false;
165+
166+ assert(offset < static_cast<std::size_t>(std::numeric_limits<word_t>::max()));
167+ const auto byte_offset = static_cast<word_t>(offset / 8);
168+
169+ if (byte_offset < type_desc.map_in_bytes)
170+ {
171+ const auto words8 = type_desc.pointer_map[byte_offset];
172+ assert(sizeof(words8) == 1);
173+ if (words8 != 0)
174+ {
175+ const auto flags = std::bitset<sizeof(words8) * 8>{ words8 };
176+
177+ // Highest order bit is the first field
178+ const auto bit_offset = 7 - (offset % 8);
179+ return flags[bit_offset];
180+ }
181+ }
182+
183+ return false;
184+}
185+
187186 void *vm_alloc_t::operator new(std::size_t sz)
188187 {
189188 return alloc_memory(sz);
@@ -203,7 +202,9 @@ vm_alloc_t *vm_alloc_t::allocate(std::shared_ptr<const type_descriptor_t> td) · 13 unmodified lines
203202 auto mem = alloc_memory(sizeof(vm_alloc_t) + td->size_in_bytes);
204203 auto alloc = ::new(mem)vm_alloc_t{ td };
205204
206− debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "init: vm alloc: %d", td->size_in_bytes);
205+ if (debug::is_component_tracing_enabled<debug::component_trace_t::memory>())
206+ debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "init: vm alloc: %d", td->size_in_bytes);
207+
207208 return alloc;
208209 }
209210