From c81fe48f9820bb3a6a67e155fd08b6b7fa4f2734 Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Wed, 8 Jan 2025 02:31:39 +0000 Subject: [PATCH 1/4] PTR_PIN vs OBJ_PIN. Trace all global symbols. Pin more pointers in the runtime. --- src/aotcompile.cpp | 1 + src/ast.c | 2 +- src/builtins.c | 6 +- src/cgutils.cpp | 3 +- src/codegen.cpp | 10 ++ src/datatype.c | 4 +- src/gc-interface.h | 2 + src/gc-mmtk.c | 295 ++++++++++++++++++++++++++++++++++++++--- src/gc-stock.c | 4 + src/genericmemory.c | 4 +- src/gf.c | 2 + src/jitlayers.h | 3 +- src/jl_uv.c | 2 + src/julia.h | 7 +- src/method.c | 2 + src/module.c | 1 + src/staticdata_utils.c | 2 +- src/task.c | 12 +- src/toplevel.c | 2 +- 19 files changed, 332 insertions(+), 32 deletions(-) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 1d1e48efc8c6c..ee43a8d103e05 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -77,6 +77,7 @@ typedef struct { SmallVector jl_sysimg_fvars; SmallVector jl_sysimg_gvars; std::map> jl_fvar_map; + // This holds references to the heap. Need to be pinned. SmallVector jl_value_to_llvm; SmallVector jl_external_to_llvm; } jl_native_code_desc_t; diff --git a/src/ast.c b/src/ast.c index 3d8a56c85600a..a01b5bb9c2007 100644 --- a/src/ast.c +++ b/src/ast.c @@ -815,7 +815,7 @@ static value_t julia_to_list2_noalloc(fl_context_t *fl_ctx, jl_value_t *a, jl_va static value_t julia_to_scm_(fl_context_t *fl_ctx, jl_value_t *v, int check_valid) { - PTR_PIN(v); + OBJ_PIN(v); value_t retval; if (julia_to_scm_noalloc1(fl_ctx, v, &retval)) return retval; diff --git a/src/builtins.c b/src/builtins.c index b7572ef3753d3..73cefd0be2544 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -347,7 +347,7 @@ static uintptr_t type_object_id_(jl_value_t *v, jl_varidx_t *env) JL_NOTSAFEPOIN } // FIXME: Pinning objects that get hashed // until we implement address space hashing. - PTR_PIN(v); + OBJ_PIN(v); uintptr_t bits = jl_astaggedvalue(v)->header; if (bits & GC_IN_IMAGE) return ((uintptr_t*)v)[-2]; @@ -407,7 +407,7 @@ static uintptr_t immut_id_(jl_datatype_t *dt, jl_value_t *v, uintptr_t h) JL_NOT // FIXME: Pinning objects that get hashed // until we implement address space hashing. - PTR_PIN(v); + PTR_PIN(v); // This has to be a pointer pin -- v could be an internal pointer return bits_hash(v, sz) ^ h; } if (dt == jl_unionall_type) @@ -471,7 +471,7 @@ static uintptr_t NOINLINE jl_object_id__cold(uintptr_t tv, jl_value_t *v) JL_NOT // FIXME: Pinning objects that get hashed // until we implement address space hashing. - PTR_PIN(v); + OBJ_PIN(v); return inthash((uintptr_t)v); } return immut_id_(dt, v, dt->hash); diff --git a/src/cgutils.cpp b/src/cgutils.cpp index c81886d936e64..2230511b3dced 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -406,6 +406,7 @@ static Constant *julia_pgv(jl_codectx_t &ctx, const char *cname, void *addr) // emit a GlobalVariable for a jl_value_t named "cname" // store the name given so we can reuse it (facilitating merging later) // so first see if there already is a GlobalVariable for this address + OBJ_PIN(addr); // This will be stored in the native heap. We need to pin it. GlobalVariable* &gv = ctx.emission_context.global_targets[addr]; Module *M = jl_Module; StringRef localname; @@ -578,7 +579,7 @@ static Value *literal_pointer_val(jl_codectx_t &ctx, jl_value_t *p) { if (p == NULL) return Constant::getNullValue(ctx.types().T_pjlvalue); - PTR_PIN(p); + OBJ_PIN(p); Value *pgv = literal_pointer_val_slot(ctx, p); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); auto load = ai.decorateInst(maybe_mark_load_dereferenceable( diff --git a/src/codegen.cpp b/src/codegen.cpp index b8bed0793730b..6e7b02f1418c1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1835,6 +1835,7 @@ struct jl_cgval_t { promotion_point(nullptr), promotion_ssa(-1) { + OBJ_PIN(typ); // jl_cgval_t could be in the native heap. We have to pin the object references in it. assert(TIndex == nullptr || TIndex->getType() == getInt8Ty(TIndex->getContext())); } jl_cgval_t(Value *Vptr, bool isboxed, jl_value_t *typ, Value *tindex, MDNode *tbaa, Value* inline_roots) = delete; @@ -1851,6 +1852,7 @@ struct jl_cgval_t { promotion_point(nullptr), promotion_ssa(-1) { + OBJ_PIN(typ); // jl_cgval_t could be in the native heap. We have to pin the object references in it. if (Vboxed) assert(Vboxed->getType() == JuliaType::get_prjlvalue_ty(Vboxed->getContext())); assert(tbaa != nullptr); @@ -1871,6 +1873,8 @@ struct jl_cgval_t { promotion_point(nullptr), promotion_ssa(-1) { + OBJ_PIN(typ); // jl_cgval_t could be in the native heap. We have to pin the object references in it. + OBJ_PIN(constant); // jl_cgval_t could be in the native heap. We have to pin the object references in it. assert(jl_is_datatype(typ)); assert(constant); } @@ -1887,6 +1891,8 @@ struct jl_cgval_t { promotion_point(v.promotion_point), promotion_ssa(v.promotion_ssa) { + OBJ_PIN(typ); // jl_cgval_t could be in the native heap. We have to pin the object references in it. + OBJ_PIN(constant); // jl_cgval_t could be in the native heap. We have to pin the object references in it. if (Vboxed) assert(Vboxed->getType() == JuliaType::get_prjlvalue_ty(Vboxed->getContext())); // this constructor expects we had a badly or equivalently typed version @@ -1959,6 +1965,7 @@ class jl_codectx_t { std::map phic_slots; std::map > scope_restore; SmallVector SAvalues; + // The vector holds reference to Julia obj ref. We need to pin jl_value_t*. SmallVector, jl_value_t *>, 0> PhiNodes; SmallVector ssavalue_assigned; SmallVector ssavalue_usecount; @@ -6241,6 +6248,7 @@ static void emit_phinode_assign(jl_codectx_t &ctx, ssize_t idx, jl_value_t *r) decay_derived(ctx, phi)); jl_cgval_t val = mark_julia_slot(ptr, phiType, Tindex_phi, best_tbaa(ctx.tbaa(), phiType)); val.Vboxed = ptr_phi; + OBJ_PIN(r); ctx.PhiNodes.push_back(std::make_tuple(val, BB, dest, ptr_phi, roots, r)); ctx.SAvalues[idx] = val; ctx.ssavalue_assigned[idx] = true; @@ -6250,6 +6258,7 @@ static void emit_phinode_assign(jl_codectx_t &ctx, ssize_t idx, jl_value_t *r) PHINode *Tindex_phi = PHINode::Create(getInt8Ty(ctx.builder.getContext()), jl_array_nrows(edges), "tindex_phi"); Tindex_phi->insertInto(BB, InsertPt); jl_cgval_t val = mark_julia_slot(NULL, phiType, Tindex_phi, ctx.tbaa().tbaa_stack); + OBJ_PIN(r); ctx.PhiNodes.push_back(std::make_tuple(val, BB, dest, (PHINode*)nullptr, roots, r)); ctx.SAvalues[idx] = val; ctx.ssavalue_assigned[idx] = true; @@ -6300,6 +6309,7 @@ static void emit_phinode_assign(jl_codectx_t &ctx, ssize_t idx, jl_value_t *r) value_phi->insertInto(BB, InsertPt); slot = mark_julia_type(ctx, value_phi, isboxed, phiType); } + OBJ_PIN(r); ctx.PhiNodes.push_back(std::make_tuple(slot, BB, dest, value_phi, roots, r)); ctx.SAvalues[idx] = slot; ctx.ssavalue_assigned[idx] = true; diff --git a/src/datatype.c b/src/datatype.c index 3a2ebf2bb303a..f585c6952cdd5 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -66,7 +66,7 @@ JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *modu jl_typename_type); // Typenames should be pinned since they are used as metadata, and are // read during scan_object - PTR_PIN(tn); + OBJ_PIN(tn); tn->name = name; tn->module = module; tn->wrapper = NULL; @@ -101,7 +101,7 @@ jl_datatype_t *jl_new_uninitialized_datatype(void) 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 - PTR_PIN(t); + OBJ_PIN(t); jl_set_typetagof(t, jl_datatype_tag, 0); t->hash = 0; t->hasfreetypevars = 0; diff --git a/src/gc-interface.h b/src/gc-interface.h index bc5462b9b6470..328b14493ec14 100644 --- a/src/gc-interface.h +++ b/src/gc-interface.h @@ -100,6 +100,8 @@ JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection); JL_DLLEXPORT int gc_is_collector_thread(int tid) JL_NOTSAFEPOINT; // Pinning objects; Returns whether the object has been pinned by this call. JL_DLLEXPORT unsigned char jl_gc_pin_object(void* obj); +// Pinning objects through a potential internal pointer; Returns whether the object has been pinned by this call. +JL_DLLEXPORT unsigned char jl_gc_pin_pointer(void* ptr); // Returns the version of which GC implementation is being used according to the list of supported GCs JL_DLLEXPORT const char* jl_active_gc_impl(void); // Notifies the GC that the given thread is about to yield for a GC. ctx is the ucontext for the thread diff --git a/src/gc-mmtk.c b/src/gc-mmtk.c index f82f0479476da..6cd90ce7d9123 100644 --- a/src/gc-mmtk.c +++ b/src/gc-mmtk.c @@ -305,6 +305,10 @@ JL_DLLEXPORT unsigned char jl_gc_pin_object(void* obj) { return mmtk_pin_object(obj); } +JL_DLLEXPORT unsigned char jl_gc_pin_pointer(void* ptr) { + return mmtk_pin_pointer(ptr); +} + JL_DLLEXPORT void jl_gc_notify_thread_yield(jl_ptls_t ptls, void* ctx) { if (ctx == NULL) { // Save the context for the thread as it was running at the time of the call @@ -494,40 +498,295 @@ static void add_node_to_tpinned_roots_buffer(RootsWorkClosure* closure, RootsWor } } -JL_DLLEXPORT void jl_mmtk_scan_vm_specific_roots(RootsWorkClosure* closure) +// staticdata_utils.c +extern jl_array_t *internal_methods; +extern jl_array_t *newly_inferred; +// task.c +extern jl_function_t* task_done_hook_func; + +#define TRACE_GLOBALLY_ROOTED(r) add_node_to_roots_buffer(closure, buf, buf_len, r) + +// This is a list of global variables that are marked with JL_GLOBALLY_ROOTED. We need to make sure that they +// won't be moved. Otherwise, when we access those objects from the C global variables, we may see moved references. +void trace_full_globally_rooted(RootsWorkClosure* closure, RootsWorkBuffer* buf, size_t* buf_len) { - // Create a new buf - RootsWorkBuffer buf = (closure->report_nodes_func)((void**)0, 0, 0, closure->data, true); - size_t len = 0; + TRACE_GLOBALLY_ROOTED(cmpswap_names); + TRACE_GLOBALLY_ROOTED(jl_typeinf_func); + TRACE_GLOBALLY_ROOTED(_jl_debug_method_invalidation); + // Max 4096 + for (size_t i = 0; i < N_CALL_CACHE; i++) { + TRACE_GLOBALLY_ROOTED(call_cache[i]); + } + // julia_internal.h + TRACE_GLOBALLY_ROOTED(jl_type_type_mt); + TRACE_GLOBALLY_ROOTED(jl_nonfunction_mt); + TRACE_GLOBALLY_ROOTED(jl_kwcall_mt); + TRACE_GLOBALLY_ROOTED(jl_opaque_closure_method); + TRACE_GLOBALLY_ROOTED(jl_nulldebuginfo); + TRACE_GLOBALLY_ROOTED(_jl_debug_method_invalidation); + TRACE_GLOBALLY_ROOTED(jl_module_init_order); + // TRACE_GLOBALLY_ROOTED(jl_current_modules); -- we cannot trace a htable_t. So we trace each module. + for (size_t i = 0; i < jl_current_modules.size; i += 2) { + if (jl_current_modules.table[i + 1] != HT_NOTFOUND) { + TRACE_GLOBALLY_ROOTED(jl_current_modules.table[i]); + } + } + for (size_t i = 0; i < N_CALL_CACHE; i++) { + jl_typemap_entry_t *v = jl_atomic_load_relaxed(&call_cache[i]); + TRACE_GLOBALLY_ROOTED(v); + } + TRACE_GLOBALLY_ROOTED(jl_precompile_toplevel_module); + TRACE_GLOBALLY_ROOTED(jl_global_roots_list); + TRACE_GLOBALLY_ROOTED(jl_global_roots_keyset); + TRACE_GLOBALLY_ROOTED(precompile_field_replace); + // julia.h + TRACE_GLOBALLY_ROOTED(jl_typeofbottom_type); + TRACE_GLOBALLY_ROOTED(jl_datatype_type); + TRACE_GLOBALLY_ROOTED(jl_uniontype_type); + TRACE_GLOBALLY_ROOTED(jl_unionall_type); + TRACE_GLOBALLY_ROOTED(jl_tvar_type); + + TRACE_GLOBALLY_ROOTED(jl_any_type); + TRACE_GLOBALLY_ROOTED(jl_type_type); + TRACE_GLOBALLY_ROOTED(jl_typename_type); + TRACE_GLOBALLY_ROOTED(jl_type_typename); + TRACE_GLOBALLY_ROOTED(jl_symbol_type); + TRACE_GLOBALLY_ROOTED(jl_ssavalue_type); + TRACE_GLOBALLY_ROOTED(jl_slotnumber_type); + TRACE_GLOBALLY_ROOTED(jl_argument_type); + TRACE_GLOBALLY_ROOTED(jl_const_type); + TRACE_GLOBALLY_ROOTED(jl_partial_struct_type); + TRACE_GLOBALLY_ROOTED(jl_partial_opaque_type); + TRACE_GLOBALLY_ROOTED(jl_interconditional_type); + TRACE_GLOBALLY_ROOTED(jl_method_match_type); + TRACE_GLOBALLY_ROOTED(jl_simplevector_type); + TRACE_GLOBALLY_ROOTED(jl_tuple_typename); + TRACE_GLOBALLY_ROOTED(jl_vecelement_typename); + TRACE_GLOBALLY_ROOTED(jl_anytuple_type); + TRACE_GLOBALLY_ROOTED(jl_emptytuple_type); + TRACE_GLOBALLY_ROOTED(jl_anytuple_type_type); + TRACE_GLOBALLY_ROOTED(jl_vararg_type); + TRACE_GLOBALLY_ROOTED(jl_function_type); + TRACE_GLOBALLY_ROOTED(jl_builtin_type); + TRACE_GLOBALLY_ROOTED(jl_opaque_closure_type); + TRACE_GLOBALLY_ROOTED(jl_opaque_closure_typename); + + TRACE_GLOBALLY_ROOTED(jl_bottom_type); + TRACE_GLOBALLY_ROOTED(jl_method_instance_type); + TRACE_GLOBALLY_ROOTED(jl_code_instance_type); + TRACE_GLOBALLY_ROOTED(jl_code_info_type); + TRACE_GLOBALLY_ROOTED(jl_debuginfo_type); + TRACE_GLOBALLY_ROOTED(jl_method_type); + TRACE_GLOBALLY_ROOTED(jl_module_type); + TRACE_GLOBALLY_ROOTED(jl_addrspace_type); + TRACE_GLOBALLY_ROOTED(jl_addrspacecore_type); + TRACE_GLOBALLY_ROOTED(jl_abstractarray_type); + TRACE_GLOBALLY_ROOTED(jl_densearray_type); + TRACE_GLOBALLY_ROOTED(jl_array_type); + TRACE_GLOBALLY_ROOTED(jl_array_typename); + TRACE_GLOBALLY_ROOTED(jl_genericmemory_type); + TRACE_GLOBALLY_ROOTED(jl_genericmemory_typename); + TRACE_GLOBALLY_ROOTED(jl_genericmemoryref_type); + TRACE_GLOBALLY_ROOTED(jl_genericmemoryref_typename); + TRACE_GLOBALLY_ROOTED(jl_weakref_type); + TRACE_GLOBALLY_ROOTED(jl_abstractstring_type); + TRACE_GLOBALLY_ROOTED(jl_string_type); + TRACE_GLOBALLY_ROOTED(jl_errorexception_type); + TRACE_GLOBALLY_ROOTED(jl_argumenterror_type); + TRACE_GLOBALLY_ROOTED(jl_loaderror_type); + TRACE_GLOBALLY_ROOTED(jl_initerror_type); + TRACE_GLOBALLY_ROOTED(jl_typeerror_type); + TRACE_GLOBALLY_ROOTED(jl_methoderror_type); + TRACE_GLOBALLY_ROOTED(jl_undefvarerror_type); + TRACE_GLOBALLY_ROOTED(jl_fielderror_type); + TRACE_GLOBALLY_ROOTED(jl_atomicerror_type); + TRACE_GLOBALLY_ROOTED(jl_missingcodeerror_type); + TRACE_GLOBALLY_ROOTED(jl_lineinfonode_type); + TRACE_GLOBALLY_ROOTED(jl_stackovf_exception); + TRACE_GLOBALLY_ROOTED(jl_memory_exception); + TRACE_GLOBALLY_ROOTED(jl_readonlymemory_exception); + TRACE_GLOBALLY_ROOTED(jl_diverror_exception); + TRACE_GLOBALLY_ROOTED(jl_undefref_exception); + TRACE_GLOBALLY_ROOTED(jl_interrupt_exception); + TRACE_GLOBALLY_ROOTED(jl_precompilable_error); + TRACE_GLOBALLY_ROOTED(jl_boundserror_type); + TRACE_GLOBALLY_ROOTED(jl_an_empty_vec_any); + TRACE_GLOBALLY_ROOTED(jl_an_empty_memory_any); + TRACE_GLOBALLY_ROOTED(jl_an_empty_string); + + TRACE_GLOBALLY_ROOTED(jl_bool_type); + TRACE_GLOBALLY_ROOTED(jl_char_type); + TRACE_GLOBALLY_ROOTED(jl_int8_type); + TRACE_GLOBALLY_ROOTED(jl_uint8_type); + TRACE_GLOBALLY_ROOTED(jl_int16_type); + TRACE_GLOBALLY_ROOTED(jl_uint16_type); + TRACE_GLOBALLY_ROOTED(jl_int32_type); + TRACE_GLOBALLY_ROOTED(jl_uint32_type); + TRACE_GLOBALLY_ROOTED(jl_int64_type); + TRACE_GLOBALLY_ROOTED(jl_uint64_type); + TRACE_GLOBALLY_ROOTED(jl_float16_type); + TRACE_GLOBALLY_ROOTED(jl_float32_type); + TRACE_GLOBALLY_ROOTED(jl_float64_type); + TRACE_GLOBALLY_ROOTED(jl_floatingpoint_type); + TRACE_GLOBALLY_ROOTED(jl_number_type); + TRACE_GLOBALLY_ROOTED(jl_void_type); // deprecated + TRACE_GLOBALLY_ROOTED(jl_nothing_type); + TRACE_GLOBALLY_ROOTED(jl_signed_type); + TRACE_GLOBALLY_ROOTED(jl_voidpointer_type); + TRACE_GLOBALLY_ROOTED(jl_uint8pointer_type); + TRACE_GLOBALLY_ROOTED(jl_pointer_type); + TRACE_GLOBALLY_ROOTED(jl_llvmpointer_type); + TRACE_GLOBALLY_ROOTED(jl_ref_type); + TRACE_GLOBALLY_ROOTED(jl_pointer_typename); + TRACE_GLOBALLY_ROOTED(jl_llvmpointer_typename); + TRACE_GLOBALLY_ROOTED(jl_namedtuple_typename); + TRACE_GLOBALLY_ROOTED(jl_namedtuple_type); + TRACE_GLOBALLY_ROOTED(jl_task_type); + TRACE_GLOBALLY_ROOTED(jl_pair_type); + + TRACE_GLOBALLY_ROOTED(jl_array_uint8_type); + TRACE_GLOBALLY_ROOTED(jl_array_any_type); + TRACE_GLOBALLY_ROOTED(jl_array_symbol_type); + TRACE_GLOBALLY_ROOTED(jl_array_int32_type); + TRACE_GLOBALLY_ROOTED(jl_array_uint32_type); + TRACE_GLOBALLY_ROOTED(jl_array_uint64_type); + TRACE_GLOBALLY_ROOTED(jl_memory_uint8_type); + TRACE_GLOBALLY_ROOTED(jl_memory_uint16_type); + TRACE_GLOBALLY_ROOTED(jl_memory_uint32_type); + TRACE_GLOBALLY_ROOTED(jl_memory_uint64_type); + TRACE_GLOBALLY_ROOTED(jl_memory_any_type); + TRACE_GLOBALLY_ROOTED(jl_memoryref_uint8_type); + TRACE_GLOBALLY_ROOTED(jl_memoryref_any_type); + TRACE_GLOBALLY_ROOTED(jl_expr_type); + TRACE_GLOBALLY_ROOTED(jl_binding_type); + TRACE_GLOBALLY_ROOTED(jl_binding_partition_type); + TRACE_GLOBALLY_ROOTED(jl_globalref_type); + TRACE_GLOBALLY_ROOTED(jl_linenumbernode_type); + TRACE_GLOBALLY_ROOTED(jl_gotonode_type); + TRACE_GLOBALLY_ROOTED(jl_gotoifnot_type); + TRACE_GLOBALLY_ROOTED(jl_enternode_type); + TRACE_GLOBALLY_ROOTED(jl_returnnode_type); + TRACE_GLOBALLY_ROOTED(jl_phinode_type); + TRACE_GLOBALLY_ROOTED(jl_pinode_type); + TRACE_GLOBALLY_ROOTED(jl_phicnode_type); + TRACE_GLOBALLY_ROOTED(jl_upsilonnode_type); + TRACE_GLOBALLY_ROOTED(jl_quotenode_type); + TRACE_GLOBALLY_ROOTED(jl_newvarnode_type); + TRACE_GLOBALLY_ROOTED(jl_intrinsic_type); + TRACE_GLOBALLY_ROOTED(jl_methtable_type); + TRACE_GLOBALLY_ROOTED(jl_typemap_level_type); + TRACE_GLOBALLY_ROOTED(jl_typemap_entry_type); + + TRACE_GLOBALLY_ROOTED(jl_emptysvec); + TRACE_GLOBALLY_ROOTED(jl_emptytuple); + TRACE_GLOBALLY_ROOTED(jl_true); + TRACE_GLOBALLY_ROOTED(jl_false); + TRACE_GLOBALLY_ROOTED(jl_nothing); + TRACE_GLOBALLY_ROOTED(jl_kwcall_func); + + TRACE_GLOBALLY_ROOTED(jl_libdl_dlopen_func); + + TRACE_GLOBALLY_ROOTED(jl_main_module); + TRACE_GLOBALLY_ROOTED(jl_core_module); + TRACE_GLOBALLY_ROOTED(jl_base_module); + TRACE_GLOBALLY_ROOTED(jl_top_module); + TRACE_GLOBALLY_ROOTED(jl_libdl_module); + + // staticdata_utils.c + TRACE_GLOBALLY_ROOTED(internal_methods); + TRACE_GLOBALLY_ROOTED(newly_inferred); + // task.c + TRACE_GLOBALLY_ROOTED(task_done_hook_func); + // threading.c + // TRACE_GLOBALLY_ROOTED(jl_all_tls_states); -- we don't need to pin these. Julia TLS are allocated with calloc. +} + +// These are from gc_mark_roots -- this is not enough for a moving GC. We need to make sure +// all the globally rooted symbols are traced and will not move. This function is unused. +// We use trace_full_globally_rooted() instead. +void trace_partial_globally_rooted(RootsWorkClosure* closure, RootsWorkBuffer* buf, size_t* buf_len) +{ // add module - add_node_to_roots_buffer(closure, &buf, &len, jl_main_module); + TRACE_GLOBALLY_ROOTED(jl_main_module); // buildin values - add_node_to_roots_buffer(closure, &buf, &len, jl_an_empty_vec_any); - add_node_to_roots_buffer(closure, &buf, &len, jl_module_init_order); + TRACE_GLOBALLY_ROOTED(jl_an_empty_vec_any); + TRACE_GLOBALLY_ROOTED(jl_module_init_order); for (size_t i = 0; i < jl_current_modules.size; i += 2) { if (jl_current_modules.table[i + 1] != HT_NOTFOUND) { - add_node_to_roots_buffer(closure, &buf, &len, jl_current_modules.table[i]); + TRACE_GLOBALLY_ROOTED(jl_current_modules.table[i]); } } - add_node_to_roots_buffer(closure, &buf, &len, jl_anytuple_type_type); + TRACE_GLOBALLY_ROOTED(jl_anytuple_type_type); for (size_t i = 0; i < N_CALL_CACHE; i++) { - jl_typemap_entry_t *v = jl_atomic_load_relaxed(&call_cache[i]); - add_node_to_roots_buffer(closure, &buf, &len, v); + jl_typemap_entry_t *v = jl_atomic_load_relaxed(&call_cache[i]); + TRACE_GLOBALLY_ROOTED(v); } - add_node_to_roots_buffer(closure, &buf, &len, _jl_debug_method_invalidation); + TRACE_GLOBALLY_ROOTED(_jl_debug_method_invalidation); // constants - add_node_to_roots_buffer(closure, &buf, &len, jl_emptytuple_type); - add_node_to_roots_buffer(closure, &buf, &len, cmpswap_names); - add_node_to_roots_buffer(closure, &buf, &len, precompile_field_replace); + TRACE_GLOBALLY_ROOTED(jl_emptytuple_type); + TRACE_GLOBALLY_ROOTED(cmpswap_names); + TRACE_GLOBALLY_ROOTED(jl_global_roots_list); + TRACE_GLOBALLY_ROOTED(jl_global_roots_keyset); + TRACE_GLOBALLY_ROOTED(precompile_field_replace); +} + +JL_DLLEXPORT void jl_mmtk_scan_vm_specific_roots(RootsWorkClosure* closure) +{ + // Create a new buf + RootsWorkBuffer buf = (closure->report_nodes_func)((void**)0, 0, 0, closure->data, true); + size_t len = 0; + + // globally rooted + trace_full_globally_rooted(closure, &buf, &len); + + // Simply pin things in global roots table + size_t i; + // for (i = 0; i < jl_array_len(jl_global_roots_table); i++) { + // jl_value_t* root = jl_array_ptr_ref(jl_global_roots_table, i); + // add_node_to_roots_buffer(closure, &buf, &len, root); + // } + // for (i = 0; i < jl_global_roots_list->length; i++) { + // jl_value_t* root = jl_genericmemory_ptr_ref(jl_global_roots_list, i); + // add_node_to_roots_buffer(closure, &buf, &len, root); + // } + // for (i = 0; i < jl_global_roots_keyset->length; i++) { + // jl_value_t* root = jl_genericmemory_ptr_ref(jl_global_roots_keyset, i); + // add_node_to_roots_buffer(closure, &buf, &len, root); + // } + // add_node_to_roots_buffer(closure, &buf, &len, jl_global_roots_list); + // add_node_to_roots_buffer(closure, &buf, &len, jl_global_roots_keyset); + + // // add module + // add_node_to_roots_buffer(closure, &buf, &len, jl_main_module); + + // // buildin values + // add_node_to_roots_buffer(closure, &buf, &len, jl_an_empty_vec_any); + // add_node_to_roots_buffer(closure, &buf, &len, jl_module_init_order); + // for (size_t i = 0; i < jl_current_modules.size; i += 2) { + // if (jl_current_modules.table[i + 1] != HT_NOTFOUND) { + // add_node_to_roots_buffer(closure, &buf, &len, jl_current_modules.table[i]); + // } + // } + // add_node_to_roots_buffer(closure, &buf, &len, jl_anytuple_type_type); + // for (size_t i = 0; i < N_CALL_CACHE; i++) { + // jl_typemap_entry_t *v = jl_atomic_load_relaxed(&call_cache[i]); + // add_node_to_roots_buffer(closure, &buf, &len, v); + // } + // add_node_to_roots_buffer(closure, &buf, &len, _jl_debug_method_invalidation); + + // // constants + // add_node_to_roots_buffer(closure, &buf, &len, jl_emptytuple_type); + // add_node_to_roots_buffer(closure, &buf, &len, cmpswap_names); + // add_node_to_roots_buffer(closure, &buf, &len, precompile_field_replace); // jl_global_roots_table must be transitively pinned RootsWorkBuffer tpinned_buf = (closure->report_tpinned_nodes_func)((void**)0, 0, 0, closure->data, true); size_t tpinned_len = 0; - add_node_to_tpinned_roots_buffer(closure, &tpinned_buf, &tpinned_len, jl_global_roots_list); - add_node_to_tpinned_roots_buffer(closure, &tpinned_buf, &tpinned_len, jl_global_roots_keyset); + // add_node_to_tpinned_roots_buffer(closure, &tpinned_buf, &tpinned_len, jl_global_roots_list); + // add_node_to_tpinned_roots_buffer(closure, &tpinned_buf, &tpinned_len, jl_global_roots_keyset); // Push the result of the work. (closure->report_nodes_func)(buf.ptr, len, buf.cap, closure->data, false); @@ -791,6 +1050,8 @@ JL_DLLEXPORT jl_weakref_t *jl_gc_new_weakref_th(jl_ptls_t ptls, jl_value_t *valu { jl_weakref_t *wr = (jl_weakref_t*)jl_gc_alloc(ptls, sizeof(void*), jl_weakref_type); wr->value = value; // NOTE: wb not needed here + // Note: we are using MMTk's weak ref processing. If we switch to Julia's weak ref processing, + // we need to make sure the value and the weak ref won't be moved (e.g. pin them) mmtk_add_weak_candidate(wr); return wr; } diff --git a/src/gc-stock.c b/src/gc-stock.c index e4f386323c798..773a5861ca640 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -4015,6 +4015,10 @@ JL_DLLEXPORT unsigned char jl_gc_pin_object(void* obj) { return 0; } +JL_DLLEXPORT unsigned char jl_gc_pin_pointer(void* ptr) { + return 0; +} + // added for MMTk integration JL_DLLEXPORT void jl_gc_wb1_noinline(const void *parent) JL_NOTSAFEPOINT diff --git a/src/genericmemory.c b/src/genericmemory.c index b22ee10a74a20..5b283baa08efd 100644 --- a/src/genericmemory.c +++ b/src/genericmemory.c @@ -109,7 +109,7 @@ JL_DLLEXPORT jl_genericmemory_t *jl_string_to_genericmemory(jl_value_t *str) m->length = jl_string_len(str); m->ptr = jl_string_data(str); jl_genericmemory_data_owner_field(m) = str; - PTR_PIN(str); + OBJ_PIN(str); return m; } @@ -164,7 +164,7 @@ JL_DLLEXPORT jl_genericmemory_t *jl_ptr_to_genericmemory(jl_value_t *mtype, void m->length = nel; jl_genericmemory_data_owner_field(m) = own_buffer ? (jl_value_t*)m : NULL; if (own_buffer) { - PTR_PIN(m); + OBJ_PIN(m); int isaligned = 0; // TODO: allow passing memalign'd buffers jl_gc_track_malloced_genericmemory(ct->ptls, m, isaligned); size_t allocated_bytes = memory_block_usable_size(data, isaligned); diff --git a/src/gf.c b/src/gf.c index bbf065a4fac0d..5fd427b47f3c6 100644 --- a/src/gf.c +++ b/src/gf.c @@ -562,6 +562,8 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst( jl_atomic_store_relaxed(&codeinst->ipo_purity_bits, effects); codeinst->analysis_results = analysis_results; codeinst->relocatability = relocatability; + // Pin codeinst, as they are referenced by vectors and maps in _jl_codegen_params_t + OBJ_PIN(codeinst); return codeinst; } diff --git a/src/jitlayers.h b/src/jitlayers.h index f18ee2d0af98e..c8e1051e4412a 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -228,6 +228,7 @@ struct jl_codegen_params_t { typedef StringMap SymMapGV; // outputs jl_workqueue_t workqueue; + // This map may hold Julia obj ref in the native heap. We need to pin the void*. std::map global_targets; jl_array_t *temporary_roots = nullptr; std::map, GlobalVariable*> external_fns; @@ -308,7 +309,7 @@ void add_named_global(StringRef name, void *addr) JL_NOTSAFEPOINT; static inline Constant *literal_static_pointer_val(const void *p, Type *T) JL_NOTSAFEPOINT { - PTR_PIN((void*)p); + PTR_PIN((void*)p); // This may point to non-mmtk heap memory. // this function will emit a static pointer into the generated code // the generated code will only be valid during the current session, // and thus, this should typically be avoided in new API's diff --git a/src/jl_uv.c b/src/jl_uv.c index 3498952622dce..3ab1961457918 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -469,6 +469,7 @@ JL_DLLEXPORT void jl_forceclose_uv(uv_handle_t *handle) JL_DLLEXPORT void jl_uv_associate_julia_struct(uv_handle_t *handle, jl_value_t *data) { + OBJ_PIN(data); handle->data = data; } @@ -479,6 +480,7 @@ JL_DLLEXPORT void jl_uv_associate_julia_struct(uv_handle_t *handle, */ JL_DLLEXPORT void jl_uv_disassociate_julia_struct(uv_handle_t *handle) { + // TODO: unpin here -- we need to implement pin count before we can unpin objects. handle->data = NULL; } diff --git a/src/julia.h b/src/julia.h index 6e8ff6fda91c7..69438df6502da 100644 --- a/src/julia.h +++ b/src/julia.h @@ -84,10 +84,13 @@ extern "C" { // FIXME: Pinning objects that get hashed in the ptrhash table // until we implement address space hashing. -#define PTRHASH_PIN(key) jl_gc_pin_object(key); +#define PTRHASH_PIN(key) if (key) jl_gc_pin_pointer(key); // Called when pinning objects that would cause an error if moved -#define PTR_PIN(key) jl_gc_pin_object(key); +// The difference: the argument for pin_object needs to pointer to an object (jl_value_t*), +// but the argument for pin_pointer can be an internal pointer. +#define OBJ_PIN(key) if (key) jl_gc_pin_object(key); +#define PTR_PIN(key) if (key) jl_gc_pin_pointer(key); // core data types ------------------------------------------------------------ diff --git a/src/method.c b/src/method.c index 8e3bb7d0060b7..852ed8416d301 100644 --- a/src/method.c +++ b/src/method.c @@ -632,6 +632,8 @@ JL_DLLEXPORT jl_method_instance_t *jl_new_method_instance_uninit(void) jl_atomic_store_relaxed(&mi->cache, NULL); mi->cache_with_orig = 0; jl_atomic_store_relaxed(&mi->flags, 0); + // jl_method_instance_t needs to be pinned, as it is referenced in a map in JITDebugInfoRegistry + OBJ_PIN(mi); return mi; } diff --git a/src/module.c b/src/module.c index 38f4b980a72fd..99dc167746dbf 100644 --- a/src/module.c +++ b/src/module.c @@ -110,6 +110,7 @@ JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, ui jl_module_public(m, name, 1); JL_GC_POP(); } + OBJ_PIN(m); // modules are referenced in jl_current_modules (htable). They cannot move. return m; } diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index 49f757a377bde..755923face2ba 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -82,7 +82,7 @@ static uint64_t jl_worklist_key(jl_array_t *worklist) JL_NOTSAFEPOINT return 0; } -static jl_array_t *newly_inferred JL_GLOBALLY_ROOTED /*FIXME*/; +jl_array_t *newly_inferred JL_GLOBALLY_ROOTED /*FIXME*/; // Mutex for newly_inferred jl_mutex_t newly_inferred_mutex; extern jl_mutex_t world_counter_lock; diff --git a/src/task.c b/src/task.c index 4e220c3cf5b97..365aa62faa88a 100644 --- a/src/task.c +++ b/src/task.c @@ -307,7 +307,7 @@ CFI_NORETURN #endif /* Rooted by the base module */ -static _Atomic(jl_function_t*) task_done_hook_func JL_GLOBALLY_ROOTED = NULL; +_Atomic(jl_function_t*) task_done_hook_func JL_GLOBALLY_ROOTED = NULL; void JL_NORETURN jl_finish_task(jl_task_t *ct) { @@ -1097,6 +1097,8 @@ JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, jl_value_t *completion jl_task_t *ct = jl_current_task; jl_task_t *t = (jl_task_t*)jl_gc_alloc(ct->ptls, sizeof(jl_task_t), jl_task_type); jl_set_typetagof(t, jl_task_tag, 0); + // Task cannot be moved, as jl_mutex_t (as globals) references tasks + OBJ_PIN(t); JL_PROBE_RT_NEW_TASK(ct, t); t->ctx.copy_stack = 0; if (ssize == 0) { @@ -1128,6 +1130,12 @@ JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, jl_value_t *completion t->start = start; t->result = jl_nothing; t->donenotify = completion_future; + // completion_future is a GenericCondition with SpinLock. + // I am not sure why we have to pin this. But, if we don't pin it, + // it may get moved, and we still use the invalid old reference somehow. + // See https://github.com/mmtk/mmtk-julia/issues/179. + // TODO: We should understand where we get the invalid reference from. + OBJ_PIN(completion_future); jl_atomic_store_relaxed(&t->_isexception, 0); // Inherit scope from parent task t->scope = ct->scope; @@ -1554,6 +1562,8 @@ jl_task_t *jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi) jl_nothing = jl_gc_permobj(0, jl_nothing_type); jl_task_t *ct = (jl_task_t*)jl_gc_alloc(ptls, sizeof(jl_task_t), jl_task_type); jl_set_typetagof(ct, jl_task_tag, 0); + // Task cannot be moved, as jl_mutex_t (as globals) references tasks + OBJ_PIN(ct); memset(ct, 0, sizeof(jl_task_t)); void *stack = stack_lo; size_t ssize = (char*)stack_hi - (char*)stack_lo; diff --git a/src/toplevel.c b/src/toplevel.c index b49055f393a4a..ab591da5faf29 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -141,7 +141,7 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex JL_GC_PUSH1(&form); JL_LOCK(&jl_modules_mutex); PTRHASH_PIN(newm) - PTRHASH_PIN((void*)((uintptr_t)HT_NOTFOUND + 1)) + // 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); From 7aa7e2451d4c668056567219ea040474e7a25b3e Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Mon, 13 Jan 2025 04:16:11 +0000 Subject: [PATCH 2/4] Pin jl_genericmemory_t if its data is inlined (internal pointer). Differentiate ptr pin and obj pin for hash maps --- src/genericmemory.c | 2 ++ src/ircode.c | 4 ++-- src/julia.h | 1 + src/runtime_ccall.cpp | 4 ++-- src/staticdata.c | 14 +++++++------- src/staticdata_utils.c | 2 +- src/toplevel.c | 4 ++-- 7 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/genericmemory.c b/src/genericmemory.c index 5b283baa08efd..332e496cee406 100644 --- a/src/genericmemory.c +++ b/src/genericmemory.c @@ -56,6 +56,8 @@ jl_genericmemory_t *_new_genericmemory_(jl_value_t *mtype, size_t nel, int8_t is m = (jl_genericmemory_t*)jl_gc_alloc(ct->ptls, tot, mtype); if (pooled) { data = (char*)m + JL_SMALL_BYTE_ALIGNMENT; + // Data is inlined and ptr is an internal pointer. We pin the object so the ptr will not be invalid. + OBJ_PIN(m); } else { int isaligned = 1; // jl_gc_managed_malloc is always aligned diff --git a/src/ircode.c b/src/ircode.c index 71ee0681a1e62..2b47d73a2d93f 100644 --- a/src/ircode.c +++ b/src/ircode.c @@ -1501,14 +1501,14 @@ void jl_init_serializer(void) for (i = 2; i < 256; i++) { if (deser_tag[i]) { - PTRHASH_PIN(deser_tag[i]) + OBJHASH_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]) + OBJHASH_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 69438df6502da..fe4aa3081047e 100644 --- a/src/julia.h +++ b/src/julia.h @@ -84,6 +84,7 @@ extern "C" { // FIXME: Pinning objects that get hashed in the ptrhash table // until we implement address space hashing. +#define OBJHASH_PIN(key) if (key) jl_gc_pin_object(key); #define PTRHASH_PIN(key) if (key) jl_gc_pin_pointer(key); // Called when pinning objects that would cause an error if moved diff --git a/src/runtime_ccall.cpp b/src/runtime_ccall.cpp index 5c49034843741..9be3cb6b2fa13 100644 --- a/src/runtime_ccall.cpp +++ b/src/runtime_ccall.cpp @@ -324,8 +324,8 @@ jl_value_t *jl_get_cfunction_trampoline( tramp = trampoline_alloc(); ((void**)result)[0] = tramp; init_trampoline(tramp, nval); - PTRHASH_PIN((void*)fobj) - PTRHASH_PIN(result) + OBJHASH_PIN((void*)fobj) + OBJHASH_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 4f68be90681e9..7554b2fb06e76 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -740,8 +740,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 { if (*addr != newval) { - PTRHASH_PIN((void*)addr) - PTRHASH_PIN((void*)newval) + OBJHASH_PIN((void*)addr) + OBJHASH_PIN((void*)newval) ptrhash_put(&field_replace, (void*)addr, newval); } } @@ -2473,8 +2473,8 @@ static jl_svec_t *jl_prune_type_cache_hash(jl_svec_t *cache) JL_GC_DISABLED assert(serialization_queue.items[from_seroder_entry(idx)] == cache); cache = cache_rehash_set(cache, sz); // redirect all references to the old cache to relocate to the new cache object - PTRHASH_PIN((void*)cache) - PTRHASH_PIN((void*)idx) + OBJHASH_PIN((void*)cache) + // OBJHASH_PIN((void*)idx) ptrhash_put(&serialization_order, cache, idx); serialization_queue.items[from_seroder_entry(idx)] = cache; return cache; @@ -3676,7 +3676,7 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl assert(tag == 0); arraylist_push(&delay_list, obj); arraylist_push(&delay_list, pfld); - PTRHASH_PIN(obj) + OBJHASH_PIN(obj) ptrhash_put(&new_dt_objs, (void*)obj, obj); // mark obj as invalid *pfld = (uintptr_t)NULL; continue; @@ -3711,8 +3711,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) + OBJHASH_PIN(newdt) + OBJHASH_PIN(dt) ptrhash_put(&new_dt_objs, (void*)newdt, dt); } else { diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index 755923face2ba..4e09bbb669980 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -285,7 +285,7 @@ static void jl_collect_new_roots(htable_t *relocatable_ext_cis, jl_array_t *root assert(jl_is_code_instance(ci)); jl_method_t *m = ci->def->def.method; assert(jl_is_method(m)); - PTRHASH_PIN(m) + OBJHASH_PIN(m) ptrhash_put(&mset, (void*)m, (void*)m); ptrhash_put(relocatable_ext_cis, (void*)ci, (void*)ci); } diff --git a/src/toplevel.c b/src/toplevel.c index ab591da5faf29..a9a9f24e5937d 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -140,8 +140,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)) + OBJHASH_PIN(newm) + // OBJHASH_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); From 260756afbd41d0006514459fcedb2d801e820c5e Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Tue, 28 Jan 2025 04:21:40 +0000 Subject: [PATCH 3/4] Temporarily transitively pin objects in global roots table. --- src/gc-mmtk.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gc-mmtk.c b/src/gc-mmtk.c index 6cd90ce7d9123..90431f51d8cdd 100644 --- a/src/gc-mmtk.c +++ b/src/gc-mmtk.c @@ -783,10 +783,11 @@ JL_DLLEXPORT void jl_mmtk_scan_vm_specific_roots(RootsWorkClosure* closure) // add_node_to_roots_buffer(closure, &buf, &len, precompile_field_replace); // jl_global_roots_table must be transitively pinned + // FIXME: We need to remove transitive pinning of global roots. Otherwise they may pin most of the objects in the heap. RootsWorkBuffer tpinned_buf = (closure->report_tpinned_nodes_func)((void**)0, 0, 0, closure->data, true); size_t tpinned_len = 0; - // add_node_to_tpinned_roots_buffer(closure, &tpinned_buf, &tpinned_len, jl_global_roots_list); - // add_node_to_tpinned_roots_buffer(closure, &tpinned_buf, &tpinned_len, jl_global_roots_keyset); + add_node_to_tpinned_roots_buffer(closure, &tpinned_buf, &tpinned_len, jl_global_roots_list); + add_node_to_tpinned_roots_buffer(closure, &tpinned_buf, &tpinned_len, jl_global_roots_keyset); // Push the result of the work. (closure->report_nodes_func)(buf.ptr, len, buf.cap, closure->data, false); From 5ebfa7a03394f135e4abd818d0a6280f69536e71 Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Tue, 4 Feb 2025 23:55:21 +0000 Subject: [PATCH 4/4] Add comments for some OBJ_PINs --- src/ast.c | 2 ++ src/cgutils.cpp | 1 + src/codegen.cpp | 6 +++--- src/gc-interface.h | 2 -- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ast.c b/src/ast.c index e748fc23ca475..1e26e4fadf048 100644 --- a/src/ast.c +++ b/src/ast.c @@ -780,6 +780,8 @@ static value_t julia_to_list2_noalloc(fl_context_t *fl_ctx, jl_value_t *a, jl_va static value_t julia_to_scm_(fl_context_t *fl_ctx, jl_value_t *v, int check_valid) { + // The following code will take internal pointers to v's fields. We need to make sure + // that v will not be moved by GC. OBJ_PIN(v); value_t retval; if (julia_to_scm_noalloc1(fl_ctx, v, &retval)) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index a07af2ab0c0e6..f2899d8747e0c 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -571,6 +571,7 @@ static Value *literal_pointer_val(jl_codectx_t &ctx, jl_value_t *p) { if (p == NULL) return Constant::getNullValue(ctx.types().T_pjlvalue); + // Pointers to p will be emitted into the code. Make sure p won't be moved by GC. OBJ_PIN(p); Value *pgv = literal_pointer_val_slot(ctx, p); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); diff --git a/src/codegen.cpp b/src/codegen.cpp index 8c2fd9e51d075..bc8da5e67e67e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6261,7 +6261,7 @@ static void emit_phinode_assign(jl_codectx_t &ctx, ssize_t idx, jl_value_t *r) decay_derived(ctx, phi)); jl_cgval_t val = mark_julia_slot(ptr, phiType, Tindex_phi, best_tbaa(ctx.tbaa(), phiType)); val.Vboxed = ptr_phi; - OBJ_PIN(r); + OBJ_PIN(r); // r will be saved to a data structure in the native heap, make sure it won't be moved by GC. ctx.PhiNodes.push_back(std::make_tuple(val, BB, dest, ptr_phi, roots, r)); ctx.SAvalues[idx] = val; ctx.ssavalue_assigned[idx] = true; @@ -6271,7 +6271,7 @@ static void emit_phinode_assign(jl_codectx_t &ctx, ssize_t idx, jl_value_t *r) PHINode *Tindex_phi = PHINode::Create(getInt8Ty(ctx.builder.getContext()), jl_array_nrows(edges), "tindex_phi"); Tindex_phi->insertInto(BB, InsertPt); jl_cgval_t val = mark_julia_slot(NULL, phiType, Tindex_phi, ctx.tbaa().tbaa_stack); - OBJ_PIN(r); + OBJ_PIN(r); // r will be saved to a data structure in the native heap, make sure it won't be moved by GC. ctx.PhiNodes.push_back(std::make_tuple(val, BB, dest, (PHINode*)nullptr, roots, r)); ctx.SAvalues[idx] = val; ctx.ssavalue_assigned[idx] = true; @@ -6322,7 +6322,7 @@ static void emit_phinode_assign(jl_codectx_t &ctx, ssize_t idx, jl_value_t *r) value_phi->insertInto(BB, InsertPt); slot = mark_julia_type(ctx, value_phi, isboxed, phiType); } - OBJ_PIN(r); + OBJ_PIN(r); // r will be saved to a data structure in the native heap, make sure it won't be moved by GC. ctx.PhiNodes.push_back(std::make_tuple(slot, BB, dest, value_phi, roots, r)); ctx.SAvalues[idx] = slot; ctx.ssavalue_assigned[idx] = true; diff --git a/src/gc-interface.h b/src/gc-interface.h index 13dc799ac8172..9e06f31d990fe 100644 --- a/src/gc-interface.h +++ b/src/gc-interface.h @@ -105,8 +105,6 @@ JL_DLLEXPORT int gc_is_collector_thread(int tid) JL_NOTSAFEPOINT; JL_DLLEXPORT unsigned char jl_gc_pin_object(void* obj); // Pinning objects through a potential internal pointer; Returns whether the object has been pinned by this call. JL_DLLEXPORT unsigned char jl_gc_pin_pointer(void* ptr); -// Returns the version of which GC implementation is being used according to the list of supported GCs -JL_DLLEXPORT const char* jl_active_gc_impl(void); // Returns which GC implementation is being used and possibly its version according to the list of supported GCs // NB: it should clearly identify the GC by including e.g. ‘stock’ or ‘mmtk’ as a substring. JL_DLLEXPORT const char* jl_gc_active_impl(void);