diff --git a/src/array.c b/src/array.c index b10c6d723c7b3..7a44322fbcb3f 100644 --- a/src/array.c +++ b/src/array.c @@ -239,6 +239,11 @@ JL_DLLEXPORT jl_array_t *jl_reshape_array(jl_value_t *atype, jl_array_t *data, jl_array_t *owner = (jl_array_t*)jl_array_owner(data); jl_array_data_owner(a) = (jl_value_t*)owner; + // For array objects with an owner point (a->flags.how == 3), we would need to + // introspect the object to update the a->data field. To avoid doing that and + // making scan_object much more complex we simply enforce that both owner and + // buffers are always pinned + mmtk_pin_object(owner); a->flags.how = 3; a->data = data->data; a->flags.isshared = 1; @@ -287,6 +292,11 @@ JL_DLLEXPORT jl_array_t *jl_string_to_array(jl_value_t *str) a->flags.ptrarray = 0; a->flags.hasptr = 0; jl_array_data_owner(a) = str; + // For array objects with an owner point (a->flags.how == 3), we would need to + // introspect the object to update the a->data field. To avoid doing that and + // making scan_object much more complex we simply enforce that both owner and + // buffers are always pinned + mmtk_pin_object(str); a->flags.how = 3; a->flags.isshared = 1; size_t l = jl_string_len(str); @@ -683,6 +693,11 @@ static int NOINLINE array_resize_buffer(jl_array_t *a, size_t newlen) else { s = jl_gc_realloc_string(jl_array_data_owner(a), nbytes - (elsz == 1)); } + // For array objects with an owner point (a->flags.how == 3), we would need to + // introspect the object to update the a->data field. To avoid doing that and + // making scan_object much more complex we simply enforce that both owner and + // buffers are always pinned + mmtk_pin_object(s); jl_array_data_owner(a) = s; jl_gc_wb(a, s); a->data = jl_string_data(s); diff --git a/src/builtins.c b/src/builtins.c index 90cc544b47986..2ab4b7b8a18ad 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -312,6 +312,9 @@ static uintptr_t type_object_id_(jl_value_t *v, jl_varidx_t *env) JL_NOTSAFEPOIN i++; pe = pe->prev; } + // FIXME: Pinning objects that get hashed + // until we implement address space hashing. + mmtk_pin_object(v); return inthash((uintptr_t)v); } if (tv == jl_uniontype_type) { @@ -358,6 +361,10 @@ static uintptr_t immut_id_(jl_datatype_t *dt, jl_value_t *v, uintptr_t h) JL_NOT return ~h; size_t f, nf = jl_datatype_nfields(dt); if (nf == 0 || (!dt->layout->haspadding && dt->layout->npointers == 0)) { + + // FIXME: Pinning objects that get hashed + // until we implement address space hashing. + mmtk_pin_object(v); // operate element-wise if there are unused bits inside, // otherwise just take the whole data block at once // a few select pointers (notably symbol) also have special hash values @@ -414,8 +421,12 @@ static uintptr_t NOINLINE jl_object_id__cold(jl_datatype_t *dt, jl_value_t *v) J return memhash32_seed(jl_string_data(v), jl_string_len(v), 0xedc3b677); #endif } - if (dt->name->mutabl) + if (dt->name->mutabl) { + // FIXME: Pinning objects that get hashed + // until we implement address space hashing. + mmtk_pin_object(v); return inthash((uintptr_t)v); + } return immut_id_(dt, v, dt->hash); } diff --git a/src/datatype.c b/src/datatype.c index 74dc95e59bd61..9f966effbc513 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -65,6 +65,9 @@ JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *modu jl_typename_t *tn = (jl_typename_t*)jl_gc_alloc(ct->ptls, sizeof(jl_typename_t), jl_typename_type); + // Typenames should be pinned since they are used as metadata, and are + // read during scan_object + mmtk_pin_object(tn); tn->name = name; tn->module = module; tn->wrapper = NULL; @@ -96,6 +99,9 @@ jl_datatype_t *jl_new_uninitialized_datatype(void) { jl_task_t *ct = jl_current_task; jl_datatype_t *t = (jl_datatype_t*)jl_gc_alloc(ct->ptls, sizeof(jl_datatype_t), jl_datatype_type); + // Types should be pinned since they are used as metadata, and are + // read during scan_object + mmtk_pin_object(t); t->hash = 0; t->hasfreetypevars = 0; t->isdispatchtuple = 0; diff --git a/src/interpreter.c b/src/interpreter.c index 6f546db9bbbb1..a7bea95a7e762 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -751,6 +751,7 @@ jl_value_t *NOINLINE jl_interpret_toplevel_thunk(jl_module_t *m, jl_code_info_t unsigned nroots = jl_source_nslots(src) + jl_source_nssavalues(src); JL_GC_PUSHFRAME(s, s->locals, nroots); jl_array_t *stmts = src->code; + JL_GC_PUSH1(&stmts); assert(jl_typeis(stmts, jl_array_any_type)); s->src = src; s->module = m; @@ -763,6 +764,7 @@ jl_value_t *NOINLINE jl_interpret_toplevel_thunk(jl_module_t *m, jl_code_info_t jl_value_t *r = eval_body(stmts, s, 0, 1); ct->world_age = last_age; JL_GC_POP(); + JL_GC_POP(); return r; } diff --git a/src/ircode.c b/src/ircode.c index 648b954449aa2..3e72e8399a107 100644 --- a/src/ircode.c +++ b/src/ircode.c @@ -1145,12 +1145,15 @@ void jl_init_serializer(void) assert(LAST_TAG+1+i < 256); for (i = 2; i < 256; i++) { - if (deser_tag[i]) + if (deser_tag[i]) { + PTRHASH_PIN(deser_tag[i]) ptrhash_put(&ser_tag, deser_tag[i], (void*)i); + } } i = 2; while (common_symbols[i-2] != NULL) { + PTRHASH_PIN(common_symbols[i-2]) ptrhash_put(&common_symbol_tag, common_symbols[i-2], (void*)i); deser_symbols[i] = (jl_value_t*)common_symbols[i-2]; i += 1; diff --git a/src/julia.h b/src/julia.h index a93ad4877f3da..4641eff3d9839 100644 --- a/src/julia.h +++ b/src/julia.h @@ -4,6 +4,22 @@ #define JULIA_H #ifdef LIBRARY_EXPORTS + +#ifdef __cplusplus +extern "C" { +#endif + +extern int mmtk_object_is_managed_by_mmtk(void* addr); +extern unsigned char mmtk_pin_object(void* obj); +// FIXME: Pinning objects that get hashed in the ptrhash table +// until we implement address space hashing. +#define PTRHASH_PIN(key) \ + mmtk_pin_object(key); \ + +#ifdef __cplusplus +} +#endif + // Generated file, needs to be searched in include paths so that the builddir // retains priority #include diff --git a/src/julia_internal.h b/src/julia_internal.h index 81867f244408e..af438c239c5fb 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -529,7 +529,13 @@ JL_DLLEXPORT uintptr_t jl_get_buff_tag(void); typedef void jl_gc_tracked_buffer_t; // For the benefit of the static analyzer STATIC_INLINE jl_gc_tracked_buffer_t *jl_gc_alloc_buf(jl_ptls_t ptls, size_t sz) { - return jl_gc_alloc(ptls, sz, (void*)jl_buff_tag); + jl_gc_tracked_buffer_t *buf = jl_gc_alloc(ptls, sz, (void*)jl_buff_tag); + // For array objects with an owner point (a->flags.how == 3), we would need to + // introspect the object to update the a->data field. To avoid doing that and + // making scan_object much more complex we simply enforce that both owner and + // buffers are always pinned + mmtk_pin_object(buf); + return buf; } STATIC_INLINE jl_value_t *jl_gc_permobj(size_t sz, void *ty) JL_NOTSAFEPOINT diff --git a/src/mmtk-gc.c b/src/mmtk-gc.c index 87da49cc2fa4d..93edad4e6eb19 100644 --- a/src/mmtk-gc.c +++ b/src/mmtk-gc.c @@ -478,6 +478,10 @@ jl_value_t *jl_gc_realloc_string(jl_value_t *s, size_t sz) size_t len = jl_string_len(s); jl_value_t *snew = jl_alloc_string(sz); memcpy(jl_string_data(snew), jl_string_data(s), sz <= len ? sz : len); + if(mmtk_is_pinned(s)) { + // if the source string was pinned, we also pin the new one + mmtk_pin_object(snew); + } return snew; } diff --git a/src/runtime_ccall.cpp b/src/runtime_ccall.cpp index e3543c9f62656..bc81cf0e73b86 100644 --- a/src/runtime_ccall.cpp +++ b/src/runtime_ccall.cpp @@ -354,6 +354,8 @@ jl_value_t *jl_get_cfunction_trampoline( tramp = trampoline_alloc(); ((void**)result)[0] = tramp; tramp = init_trampoline(tramp, nval); + PTRHASH_PIN((void*)fobj) + PTRHASH_PIN(result) ptrhash_put(cache, (void*)fobj, result); uv_mutex_unlock(&trampoline_lock); return result; diff --git a/src/staticdata.c b/src/staticdata.c index 7934b9b404d49..38b487f1c35c8 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -699,6 +699,8 @@ static int needs_uniquing(jl_value_t *v) JL_NOTSAFEPOINT static void record_field_change(jl_value_t **addr, jl_value_t *newval) JL_NOTSAFEPOINT { + PTRHASH_PIN((void*)addr) + PTRHASH_PIN((void*)newval) ptrhash_put(&field_replace, (void*)addr, newval); } @@ -2197,6 +2199,8 @@ static jl_svec_t *jl_prune_type_cache_hash(jl_svec_t *cache) JL_GC_DISABLED assert(serialization_queue.items[(char*)idx - 1 - (char*)HT_NOTFOUND] == cache); cache = cache_rehash_set(cache, l); // redirect all references to the old cache to relocate to the new cache object + PTRHASH_PIN((void*)cache) + PTRHASH_PIN((void*)idx) ptrhash_put(&serialization_order, cache, idx); serialization_queue.items[(char*)idx - 1 - (char*)HT_NOTFOUND] = cache; return cache; @@ -2442,6 +2446,7 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, htable_new(&fptr_to_id, sizeof(id_to_fptrs) / sizeof(*id_to_fptrs)); uintptr_t i; for (i = 0; id_to_fptrs[i] != NULL; i++) { + PTRHASH_PIN((void*)(uintptr_t)id_to_fptrs[i]) ptrhash_put(&fptr_to_id, (void*)(uintptr_t)id_to_fptrs[i], (void*)(i + 2)); } htable_new(&serialization_order, 25000); @@ -2529,6 +2534,7 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, htable_new(&external_objects, NUM_TAGS); for (size_t i = 0; tags[i] != NULL; i++) { jl_value_t *tag = *tags[i]; + PTRHASH_PIN(tag) ptrhash_put(&external_objects, tag, tag); } // Queue the worklist itself as the first item we serialize @@ -3083,6 +3089,7 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl assert(tag == 0); arraylist_push(&delay_list, pfld); arraylist_push(&delay_list, obj); + PTRHASH_PIN(obj) ptrhash_put(&new_dt_objs, (void*)obj, obj); // mark obj as invalid *pfld = (uintptr_t)NULL; continue; @@ -3116,6 +3123,8 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl } static_assert(offsetof(jl_datatype_t, name) == 0, ""); newdt->name = dt->name; + PTRHASH_PIN(newdt) + PTRHASH_PIN(dt) ptrhash_put(&new_dt_objs, (void*)newdt, dt); } else { diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index 2532546702545..0333074b57571 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -272,6 +272,7 @@ static void jl_collect_new_roots(jl_array_t *roots, jl_array_t *new_specializati assert(jl_is_code_instance(ci)); jl_method_t *m = ci->def->def.method; assert(jl_is_method(m)); + PTRHASH_PIN(m) ptrhash_put(&mset, (void*)m, (void*)m); } int nwithkey; @@ -428,6 +429,7 @@ static void jl_collect_edges(jl_array_t *edges, jl_array_t *ext_targets, jl_arra for (size_t i = 0; i < jl_array_len(external_cis); i++) { jl_code_instance_t *ci = (jl_code_instance_t*)jl_array_ptr_ref(external_cis, i); jl_method_instance_t *mi = ci->def; + PTRHASH_PIN(mi) ptrhash_put(&external_mis, (void*)mi, (void*)mi); } } @@ -463,6 +465,8 @@ static void jl_collect_edges(jl_array_t *edges, jl_array_t *ext_targets, jl_arra for (size_t i = 0; i < l / 2; i++) { jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(edges, i * 2); void *target = (void*)((char*)HT_NOTFOUND + i + 1); + PTRHASH_PIN(caller) + PTRHASH_PIN(target) ptrhash_put(&edges_ids, (void*)caller, target); } // process target list to turn it into a memoized validity table @@ -534,6 +538,8 @@ static void jl_collect_edges(jl_array_t *edges, jl_array_t *ext_targets, jl_arra jl_array_ptr_1d_push(ext_targets, callee); jl_array_ptr_1d_push(ext_targets, matches); target = (void*)((char*)HT_NOTFOUND + jl_array_len(ext_targets) / 3); + PTRHASH_PIN(callee) + PTRHASH_PIN(target) ptrhash_put(&edges_map2, (void*)callee, target); } idxs[++nt] = (char*)target - (char*)HT_NOTFOUND - 1; @@ -1070,6 +1076,8 @@ static void jl_insert_backedges(jl_array_t *edges, jl_array_t *ext_targets, jl_a jl_code_instance_t *ci = (jl_code_instance_t*)jl_array_ptr_ref(ci_list, i); assert(ci->min_world == minworld); if (ci->max_world == 1) { // sentinel value: has edges to external callables + PTRHASH_PIN((void*)ci->def) + PTRHASH_PIN((void*)ci) ptrhash_put(&visited, (void*)ci->def, (void*)ci); } else { @@ -1135,6 +1143,7 @@ static void classify_callers(htable_t *callers_with_edges, jl_array_t *edges) size_t l = edges ? jl_array_len(edges) / 2 : 0; for (size_t i = 0; i < l; i++) { jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(edges, 2 * i); + PTRHASH_PIN((void*)caller) ptrhash_put(callers_with_edges, (void*)caller, (void*)caller); } } diff --git a/src/task.c b/src/task.c index 0006687b1a8d5..7093b8625b5c4 100644 --- a/src/task.c +++ b/src/task.c @@ -1062,6 +1062,7 @@ CFI_NORETURN jl_task_t *ct = jl_get_current_task(); #else jl_task_t *ct = jl_current_task; + JL_GC_PUSH1(&ct); #endif jl_ptls_t ptls = ct->ptls; jl_value_t *res; @@ -1101,6 +1102,7 @@ skip_pop_exception:; ct->result = res; jl_gc_wb(ct, ct->result); jl_finish_task(ct); + JL_GC_POP(); jl_gc_debug_critical_error(); abort(); } diff --git a/src/toplevel.c b/src/toplevel.c index 84c3b77ade7f5..da7ae85942168 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -138,6 +138,8 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex jl_value_t *form = (jl_value_t*)newm; JL_GC_PUSH1(&form); JL_LOCK(&jl_modules_mutex); + PTRHASH_PIN(newm) + PTRHASH_PIN((void*)((uintptr_t)HT_NOTFOUND + 1)) ptrhash_put(&jl_current_modules, (void*)newm, (void*)((uintptr_t)HT_NOTFOUND + 1)); JL_UNLOCK(&jl_modules_mutex); diff --git a/test/threads.jl b/test/threads.jl index 1a0dbeb2d4dbf..7e1406f20acdd 100644 --- a/test/threads.jl +++ b/test/threads.jl @@ -288,7 +288,7 @@ close(proc.in) proc = run(cmd; wait = false) done = Threads.Atomic{Bool}(false) timeout = false - timer = Timer(100) do _ + timer = Timer(150) do _ timeout = true for sig in [Base.SIGTERM, Base.SIGHUP, Base.SIGKILL] for _ in 1:1000