Skip to content

Commit 00e0a6d

Browse files
authored
Remove global ROOT_NODES/EDGES (merge after #86) (#89)
This PR is based on #86. * Move stack scanning code to Rust, and implement `Scanning::scan_roots_in_mutator_thread`. * Implement necessary types/functions in Rust. * It is not necessary to implement this in Rust. However, it needs to use `scan_gcstack()`, which is implemented in Rust, and used for object scanning. It would be better to remove our implementation for it in C. * Create `scan_vm_specific_roots`, and call it in `Scanning::scan_vm_specific_roots`. * Allow using `RootsWorkFactory` in C * Remove global `ROOT_NODES/EDGES` as they are no longer used. * Add assertions to check type size for our Rust and C types.
1 parent 85617c4 commit 00e0a6d

File tree

12 files changed

+5955
-1602
lines changed

12 files changed

+5955
-1602
lines changed

julia/mmtk_julia.c

Lines changed: 93 additions & 223 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "mmtk_julia.h"
22
#include "mmtk.h"
3+
#include "mmtk_julia_types.h"
34
#include <stdbool.h>
45
#include <stddef.h>
56
#include "gc.h"
@@ -233,239 +234,51 @@ int* get_jl_gc_have_pending_finalizers(void) {
233234
return (int*)&jl_gc_have_pending_finalizers;
234235
}
235236

236-
// add the initial root set to mmtk roots
237-
static void queue_roots(void)
238-
{
239-
// modules
240-
mmtk_add_object_to_mmtk_roots(jl_main_module);
241-
242-
// invisible builtin values
243-
if (jl_an_empty_vec_any != NULL)
244-
mmtk_add_object_to_mmtk_roots(jl_an_empty_vec_any);
245-
if (jl_module_init_order != NULL)
246-
mmtk_add_object_to_mmtk_roots(jl_module_init_order);
247-
for (size_t i = 0; i < jl_current_modules.size; i += 2) {
248-
if (jl_current_modules.table[i + 1] != HT_NOTFOUND) {
249-
mmtk_add_object_to_mmtk_roots(jl_current_modules.table[i]);
250-
}
251-
}
252-
mmtk_add_object_to_mmtk_roots(jl_anytuple_type_type);
253-
for (size_t i = 0; i < N_CALL_CACHE; i++) {
254-
jl_typemap_entry_t *v = jl_atomic_load_relaxed(&call_cache[i]);
255-
if (v != NULL)
256-
mmtk_add_object_to_mmtk_roots(v);
257-
}
258-
if (jl_all_methods != NULL)
259-
mmtk_add_object_to_mmtk_roots(jl_all_methods);
260-
261-
if (_jl_debug_method_invalidation != NULL)
262-
mmtk_add_object_to_mmtk_roots(_jl_debug_method_invalidation);
263-
// if (jl_build_ids != NULL)
264-
// add_object_to_mmtk_roots(jl_build_ids);
265-
266-
// constants
267-
mmtk_add_object_to_mmtk_roots(jl_emptytuple_type);
268-
if (cmpswap_names != NULL)
269-
mmtk_add_object_to_mmtk_roots(cmpswap_names);
270-
mmtk_add_object_to_mmtk_roots(jl_global_roots_table);
271-
272-
}
273-
274-
// Handle the case where the stack is only partially copied.
275-
static inline uintptr_t mmtk_gc_get_stack_addr(void *_addr, uintptr_t offset,
276-
uintptr_t lb, uintptr_t ub)
277-
{
278-
uintptr_t addr = (uintptr_t)_addr;
279-
if (addr >= lb && addr < ub)
280-
return addr + offset;
281-
return addr;
282-
}
283-
284-
static inline uintptr_t mmtk_gc_read_stack(void *_addr, uintptr_t offset,
285-
uintptr_t lb, uintptr_t ub)
286-
{
287-
uintptr_t real_addr = mmtk_gc_get_stack_addr(_addr, offset, lb, ub);
288-
return *(uintptr_t*)real_addr;
289-
}
290-
291-
void scan_gcstack(jl_task_t *ta, void* closure, ProcessEdgeFn process_edge)
292-
{
293-
void *stkbuf = ta->stkbuf;
294-
#ifdef COPY_STACKS
295-
if (stkbuf && ta->copy_stack && mmtk_object_is_managed_by_mmtk(ta->stkbuf)) {
296-
// printf("-copystack: %p\n", &ta->stkbuf);fflush(stdout);
297-
process_edge(closure, &ta->stkbuf);
298-
}
299-
#endif
300-
jl_gcframe_t *s = ta->gcstack;
301-
size_t nroots;
302-
uintptr_t offset = 0;
303-
uintptr_t lb = 0;
304-
uintptr_t ub = (uintptr_t)-1;
305-
#ifdef COPY_STACKS
306-
if (stkbuf && ta->copy_stack && ta->ptls == NULL) {
307-
assert(ta->tid >= 0);
308-
jl_ptls_t ptls2 = jl_all_tls_states[ta->tid];
309-
ub = (uintptr_t)ptls2->stackbase;
310-
lb = ub - ta->copy_stack;
311-
offset = (uintptr_t)stkbuf - lb;
312-
}
313-
#endif
314-
if (s) { // gc_mark_stack()
315-
nroots = mmtk_gc_read_stack(&s->nroots, offset, lb, ub);
316-
assert(nroots <= UINT32_MAX);
317-
318-
uint32_t nr = nroots >> 2;
319-
320-
while (1) {
321-
jl_value_t ***rts = (jl_value_t***)(((void**)s) + 2);
322-
for (uint32_t i = 0; i < nr; i++) {
323-
if (nroots & 1) {
324-
void **slot = (void**)mmtk_gc_read_stack(&rts[i], offset, lb, ub);
325-
uintptr_t real_addr = mmtk_gc_get_stack_addr(slot, offset, lb, ub);
326-
// printf("-nroots&1 i = %d/%d: %p\n", i, nr, real_addr);fflush(stdout);
327-
process_edge(closure, (void*)real_addr);
328-
}
329-
else {
330-
uintptr_t real_addr = mmtk_gc_get_stack_addr(&rts[i], offset, lb, ub);
331-
// printf("-nroots i = %d/%d: %p\n", i, nr, real_addr);fflush(stdout);
332-
process_edge(closure, (void*)real_addr);
333-
}
334-
}
335-
336-
jl_gcframe_t *sprev = (jl_gcframe_t*)mmtk_gc_read_stack(&s->prev, offset, lb, ub);
337-
if (sprev == NULL)
338-
break;
339-
340-
s = sprev;
341-
uintptr_t new_nroots = mmtk_gc_read_stack(&s->nroots, offset, lb, ub);
342-
assert(new_nroots <= UINT32_MAX);
343-
nroots = (uint32_t)new_nroots;
344-
nr = nroots >> 2;
345-
continue;
346-
}
347-
}
348-
if (ta->excstack) { // inlining label `excstack` from mark_loop
349-
// if it is not managed by MMTk, nothing needs to be done because the object does not need to be scanned
350-
if (mmtk_object_is_managed_by_mmtk(ta->excstack)) {
351-
// printf("-excstack: %p\n", &ta->excstack);fflush(stdout);
352-
process_edge(closure, &ta->excstack);
353-
}
354-
jl_excstack_t *excstack = ta->excstack;
355-
size_t itr = ta->excstack->top;
356-
size_t bt_index = 0;
357-
size_t jlval_index = 0;
358-
while (itr > 0) {
359-
size_t bt_size = jl_excstack_bt_size(excstack, itr);
360-
jl_bt_element_t *bt_data = jl_excstack_bt_data(excstack, itr);
361-
for (; bt_index < bt_size; bt_index += jl_bt_entry_size(bt_data + bt_index)) {
362-
jl_bt_element_t *bt_entry = bt_data + bt_index;
363-
if (jl_bt_is_native(bt_entry))
364-
continue;
365-
// Found an extended backtrace entry: iterate over any
366-
// GC-managed values inside.
367-
size_t njlvals = jl_bt_num_jlvals(bt_entry);
368-
while (jlval_index < njlvals) {
369-
jl_value_t** new_obj_edge = &bt_entry[2 + jlval_index].jlvalue;
370-
jlval_index += 1;
371-
process_edge(closure, new_obj_edge);
372-
}
373-
jlval_index = 0;
374-
}
375-
376-
jl_bt_element_t *stack_raw = (jl_bt_element_t *)(excstack+1);
377-
jl_value_t** stack_obj_edge = &stack_raw[itr-1].jlvalue;
237+
static void add_node_to_roots_buffer(RootsWorkClosure* closure, RootsWorkBuffer* buf, size_t* buf_len, void* root) {
238+
if (root == NULL)
239+
return;
378240

379-
itr = jl_excstack_next(excstack, itr);
380-
bt_index = 0;
381-
jlval_index = 0;
382-
process_edge(closure, stack_obj_edge);
383-
}
241+
buf->ptr[*buf_len] = root;
242+
*buf_len += 1;
243+
if (*buf_len >= buf->cap) {
244+
RootsWorkBuffer new_buf = (closure->report_nodes_func)(buf->ptr, *buf_len, buf->cap, closure->data, true);
245+
*buf = new_buf;
246+
*buf_len = 0;
384247
}
385248
}
386249

387-
void root_scan_task(jl_ptls_t ptls, jl_task_t* task)
250+
void scan_vm_specific_roots(RootsWorkClosure* closure)
388251
{
389-
// This is never accessed so just leave it NULL.
390-
void* c = NULL;
252+
// Create a new buf
253+
RootsWorkBuffer buf = (closure->report_nodes_func)((void**)0, 0, 0, closure->data, true);
254+
size_t len = 0;
391255

392-
// Scan the stack
393-
scan_gcstack(task, c, mmtk_process_root_edges);
394-
// And add the task itself
395-
mmtk_add_object_to_mmtk_roots(task);
396-
}
256+
// add module
257+
add_node_to_roots_buffer(closure, &buf, &len, jl_main_module);
397258

398-
static void jl_gc_queue_bt_buf_mmtk(jl_ptls_t ptls2)
399-
{
400-
jl_bt_element_t *bt_data = ptls2->bt_data;
401-
jl_value_t* bt_entry_value;
402-
size_t bt_size = ptls2->bt_size;
403-
for (size_t i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) {
404-
jl_bt_element_t *bt_entry = bt_data + i;
405-
if (jl_bt_is_native(bt_entry))
406-
continue;
407-
size_t njlvals = jl_bt_num_jlvals(bt_entry);
408-
for (size_t j = 0; j < njlvals; j++) {
409-
bt_entry_value = jl_bt_entry_jlvalue(bt_entry, j);
410-
mmtk_add_object_to_mmtk_roots(bt_entry_value);
259+
// buildin values
260+
add_node_to_roots_buffer(closure, &buf, &len, jl_an_empty_vec_any);
261+
add_node_to_roots_buffer(closure, &buf, &len, jl_module_init_order);
262+
for (size_t i = 0; i < jl_current_modules.size; i += 2) {
263+
if (jl_current_modules.table[i + 1] != HT_NOTFOUND) {
264+
add_node_to_roots_buffer(closure, &buf, &len, jl_current_modules.table[i]);
411265
}
412266
}
413-
}
414-
415-
static void jl_gc_queue_thread_local_mmtk(jl_ptls_t ptls2)
416-
{
417-
jl_task_t * task;
418-
task = ptls2->root_task;
419-
if (task != NULL) {
420-
root_scan_task(ptls2, task);
421-
}
422-
423-
task = jl_atomic_load_relaxed(&ptls2->current_task);
424-
if (task != NULL) {
425-
root_scan_task(ptls2, task);
426-
}
427-
428-
task = ptls2->next_task;
429-
if (task != NULL) {
430-
root_scan_task(ptls2, task);
431-
}
432-
433-
task = ptls2->previous_task;
434-
if (task != NULL) {
435-
root_scan_task(ptls2, task);
436-
}
437-
438-
if (ptls2->previous_exception) {
439-
mmtk_add_object_to_mmtk_roots(ptls2->previous_exception);
440-
}
441-
}
442-
443-
static void jl_gc_queue_remset_mmtk(jl_ptls_t ptls2)
444-
{
445-
size_t len = ptls2->heap.last_remset->len;
446-
void **items = ptls2->heap.last_remset->items;
447-
for (size_t i = 0; i < len; i++) {
448-
mmtk_add_object_to_mmtk_roots(items[i]);
267+
add_node_to_roots_buffer(closure, &buf, &len, jl_anytuple_type_type);
268+
for (size_t i = 0; i < N_CALL_CACHE; i++) {
269+
jl_typemap_entry_t *v = jl_atomic_load_relaxed(&call_cache[i]);
270+
add_node_to_roots_buffer(closure, &buf, &len, v);
449271
}
450-
}
272+
add_node_to_roots_buffer(closure, &buf, &len, jl_all_methods);
273+
add_node_to_roots_buffer(closure, &buf, &len, _jl_debug_method_invalidation);
451274

452-
void calculate_roots(void* ptls_raw)
453-
{
454-
for (int t_i = 0; t_i < gc_n_threads; t_i++)
455-
gc_premark(gc_all_tls_states[t_i]);
456-
457-
for (int t_i = 0; t_i < gc_n_threads; t_i++) {
458-
jl_ptls_t ptls2 = gc_all_tls_states[t_i];
459-
// 2.1. mark every thread local root
460-
jl_gc_queue_thread_local_mmtk(ptls2);
461-
// 2.2. mark any managed objects in the backtrace buffer
462-
jl_gc_queue_bt_buf_mmtk(ptls2);
463-
// 2.3. mark any managed objects in the backtrace buffer
464-
// TODO: treat these as roots for gc_heap_snapshot_record
465-
jl_gc_queue_remset_mmtk(ptls2);
466-
}
275+
// constants
276+
add_node_to_roots_buffer(closure, &buf, &len, jl_emptytuple_type);
277+
add_node_to_roots_buffer(closure, &buf, &len, cmpswap_names);
278+
add_node_to_roots_buffer(closure, &buf, &len, jl_global_roots_table);
467279

468-
queue_roots();
280+
// Push the result of the work.
281+
(closure->report_nodes_func)(buf.ptr, len, buf.cap, closure->data, false);
469282
}
470283

471284
JL_DLLEXPORT void scan_julia_exc_obj(void* obj_raw, void* closure, ProcessEdgeFn process_edge) {
@@ -523,14 +336,70 @@ void update_gc_time(uint64_t inc) {
523336
gc_num.total_time += inc;
524337
}
525338

339+
#define assert_size(ty_a, ty_b) \
340+
if(sizeof(ty_a) != sizeof(ty_b)) {\
341+
printf("%s size = %ld, %s size = %ld. Need to update our type definition.\n", #ty_a, sizeof(ty_a), #ty_b, sizeof(ty_b));\
342+
exit(1); \
343+
}
344+
345+
#define PRINT_STRUCT_SIZE false
346+
#define print_sizeof(type) (PRINT_STRUCT_SIZE ? (printf("C " #type " = %zu bytes\n", sizeof(type)), sizeof(type)) : sizeof(type))
347+
526348
uintptr_t get_abi_structs_checksum_c(void) {
527-
return sizeof(MMTkMutatorContext);
349+
assert_size(struct mmtk__jl_taggedvalue_bits, struct _jl_taggedvalue_bits);
350+
assert_size(mmtk_jl_taggedvalue_t, jl_taggedvalue_t);
351+
assert_size(mmtk_jl_array_flags_t, jl_array_flags_t);
352+
assert_size(mmtk_jl_datatype_layout_t, jl_datatype_layout_t);
353+
assert_size(mmtk_jl_typename_t, jl_typename_t);
354+
assert_size(mmtk_jl_svec_t, jl_svec_t);
355+
assert_size(mmtk_jl_datatype_t, jl_datatype_t);
356+
assert_size(mmtk_jl_array_t, jl_array_t);
357+
assert_size(mmtk_jl_sym_t, jl_sym_t);
358+
assert_size(mmtk_jl_binding_t, jl_binding_t);
359+
assert_size(mmtk_htable_t, htable_t);
360+
assert_size(mmtk_arraylist_t, arraylist_t);
361+
assert_size(mmtk_jl_uuid_t, jl_uuid_t);
362+
assert_size(mmtk_jl_mutex_t, jl_mutex_t);
363+
assert_size(mmtk_jl_module_t, jl_module_t);
364+
assert_size(mmtk_jl_excstack_t, jl_excstack_t);
365+
assert_size(mmtk_jl_bt_element_t, jl_bt_element_t);
366+
assert_size(mmtk_jl_stack_context_t, jl_stack_context_t);
367+
assert_size(mmtk_jl_ucontext_t, jl_ucontext_t);
368+
assert_size(struct mmtk__jl_gcframe_t, struct _jl_gcframe_t);
369+
assert_size(mmtk_jl_task_t, jl_task_t);
370+
assert_size(mmtk_jl_weakref_t, jl_weakref_t);
371+
372+
return print_sizeof(MMTkMutatorContext)
373+
^ print_sizeof(struct mmtk__jl_taggedvalue_bits)
374+
^ print_sizeof(mmtk_jl_taggedvalue_t)
375+
^ print_sizeof(mmtk_jl_array_flags_t)
376+
^ print_sizeof(mmtk_jl_datatype_layout_t)
377+
^ print_sizeof(mmtk_jl_typename_t)
378+
^ print_sizeof(mmtk_jl_svec_t)
379+
^ print_sizeof(mmtk_jl_datatype_t)
380+
^ print_sizeof(mmtk_jl_array_t)
381+
^ print_sizeof(mmtk_jl_sym_t)
382+
^ print_sizeof(mmtk_jl_binding_t)
383+
^ print_sizeof(mmtk_htable_t)
384+
^ print_sizeof(mmtk_arraylist_t)
385+
^ print_sizeof(mmtk_jl_uuid_t)
386+
^ print_sizeof(mmtk_jl_mutex_t)
387+
^ print_sizeof(mmtk_jl_module_t)
388+
^ print_sizeof(mmtk_jl_excstack_t)
389+
^ print_sizeof(mmtk_jl_bt_element_t)
390+
^ print_sizeof(mmtk_jl_stack_context_t)
391+
^ print_sizeof(mmtk_jl_ucontext_t)
392+
^ print_sizeof(struct mmtk__jl_gcframe_t)
393+
^ print_sizeof(mmtk_jl_task_t)
394+
^ print_sizeof(mmtk_jl_weakref_t)
395+
^ print_sizeof(mmtk_jl_tls_states_t)
396+
^ print_sizeof(mmtk_jl_thread_heap_t)
397+
^ print_sizeof(mmtk_jl_thread_gc_num_t);
528398
}
529399

530400
Julia_Upcalls mmtk_upcalls = (Julia_Upcalls) {
531401
.scan_julia_exc_obj = scan_julia_exc_obj,
532402
.get_stackbase = get_stackbase,
533-
.calculate_roots = calculate_roots,
534403
// .run_finalizer_function = run_finalizer_function,
535404
.get_jl_last_err = get_jl_last_err,
536405
.set_jl_last_err = set_jl_last_err,
@@ -551,4 +420,5 @@ Julia_Upcalls mmtk_upcalls = (Julia_Upcalls) {
551420
.get_marked_finalizers_list = get_marked_finalizers_list,
552421
.arraylist_grow = (void (*)(void*, long unsigned int))arraylist_grow,
553422
.get_jl_gc_have_pending_finalizers = get_jl_gc_have_pending_finalizers,
423+
.scan_vm_specific_roots = scan_vm_specific_roots,
554424
};

0 commit comments

Comments
 (0)