From 1dc145984474474e1686d02a7cff34625d163af7 Mon Sep 17 00:00:00 2001 From: Diogo Correia Netto Date: Thu, 19 Jun 2025 19:24:39 -0300 Subject: [PATCH 1/4] optimize pinning in ast.c --- src/ast.c | 26 ++++++++++++++++---------- src/gc-mmtk.c | 8 ++++---- src/julia.h | 1 + 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/ast.c b/src/ast.c index 9369279780fa1..cc0e1330a2a4d 100644 --- a/src/ast.c +++ b/src/ast.c @@ -136,7 +136,7 @@ typedef struct _jl_ast_context_t { value_t ssavalue_sym; value_t slot_sym; jl_module_t *module; // context module for `current-julia-module-counter` - struct _jl_ast_context_t *next; // invasive list pointer for getting free contexts + arraylist_t pinned_objects; } jl_ast_context_t; static jl_ast_context_t jl_ast_main_ctx; @@ -279,27 +279,29 @@ static void jl_init_ast_ctx(jl_ast_context_t *ctx) JL_NOTSAFEPOINT ctx->slot_sym = symbol(fl_ctx, "slot"); ctx->module = NULL; set(symbol(fl_ctx, "*scopewarn-opt*"), fixnum(jl_options.warn_scope)); + arraylist_new(&ctx->pinned_objects, 0); } // There should be no GC allocation while holding this lock static uv_mutex_t flisp_lock; -static jl_ast_context_t *jl_ast_ctx_freed = NULL; +int flisp_initialized = 0; +arraylist_t jl_ast_ctx_freed; +arraylist_t jl_ast_ctx_used; static jl_ast_context_t *jl_ast_ctx_enter(jl_module_t *m) JL_GLOBALLY_ROOTED JL_NOTSAFEPOINT { JL_SIGATOMIC_BEGIN(); uv_mutex_lock(&flisp_lock); - jl_ast_context_t *ctx = jl_ast_ctx_freed; - if (ctx != NULL) { - jl_ast_ctx_freed = ctx->next; - ctx->next = NULL; - } + jl_ast_context_t *ctx = (jl_ast_context_t*)arraylist_pop(&jl_ast_ctx_freed); uv_mutex_unlock(&flisp_lock); if (ctx == NULL) { // Construct a new one if we can't find any ctx = (jl_ast_context_t*)calloc(1, sizeof(jl_ast_context_t)); jl_init_ast_ctx(ctx); } + uv_mutex_lock(&flisp_lock); + arraylist_push(&jl_ast_ctx_used, ctx); + uv_mutex_unlock(&flisp_lock); ctx->module = m; return ctx; } @@ -308,16 +310,20 @@ static void jl_ast_ctx_leave(jl_ast_context_t *ctx) { uv_mutex_lock(&flisp_lock); ctx->module = NULL; - ctx->next = jl_ast_ctx_freed; - jl_ast_ctx_freed = ctx; + ctx->pinned_objects.len = 0; // clear pinned objects + arraylist_pop(&jl_ast_ctx_used); + arraylist_push(&jl_ast_ctx_freed, ctx); uv_mutex_unlock(&flisp_lock); JL_SIGATOMIC_END(); } void jl_init_flisp(void) { - if (jl_ast_ctx_freed) + if (flisp_initialized) return; + flisp_initialized = 1; + arraylist_new(&jl_ast_ctx_freed, 0); + arraylist_new(&jl_ast_ctx_used, 0); uv_mutex_init(&flisp_lock); jl_init_ast_ctx(&jl_ast_main_ctx); // To match the one in jl_ast_ctx_leave diff --git a/src/gc-mmtk.c b/src/gc-mmtk.c index 9c1529d0ddd78..9502954179d32 100644 --- a/src/gc-mmtk.c +++ b/src/gc-mmtk.c @@ -254,7 +254,7 @@ JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection) { // print_fragmentation(); } -void gc_pin_objects_from_inference_engine(arraylist_t *objects_pinned_by_call) +void gc_pin_objects_from_compiler_frontend(arraylist_t *objects_pinned_by_call) { for (size_t i = 0; i < gc_pinned_objects.len; i++) { void *obj = gc_pinned_objects.items[i]; @@ -265,7 +265,7 @@ void gc_pin_objects_from_inference_engine(arraylist_t *objects_pinned_by_call) } } -void gc_unpin_objects_from_inference_engine(arraylist_t *objects_pinned_by_call) +void gc_unpin_objects_from_compiler_frontend(arraylist_t *objects_pinned_by_call) { for (size_t i = 0; i < objects_pinned_by_call->len; i++) { void *obj = objects_pinned_by_call->items[i]; @@ -337,9 +337,9 @@ JL_DLLEXPORT void jl_gc_prepare_to_collect(void) #ifndef __clang_gcanalyzer__ arraylist_t objects_pinned_by_call; arraylist_new(&objects_pinned_by_call, 0); - gc_pin_objects_from_inference_engine(&objects_pinned_by_call); + gc_pin_objects_from_compiler_frontend(&objects_pinned_by_call); mmtk_block_thread_for_gc(); - gc_unpin_objects_from_inference_engine(&objects_pinned_by_call); + gc_unpin_objects_from_compiler_frontend(&objects_pinned_by_call); arraylist_free(&objects_pinned_by_call); #endif JL_UNLOCK_NOGC(&finalizers_lock); diff --git a/src/julia.h b/src/julia.h index 42e0692c9091f..64ecbfc686101 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2439,6 +2439,7 @@ JL_DLLEXPORT void jl_register_newmeth_tracer(void (*callback)(jl_method_t *trace // AST access JL_DLLEXPORT jl_value_t *jl_copy_ast(jl_value_t *expr JL_MAYBE_UNROOTED); +extern arraylist_t jl_ast_ctx_used; // IR representation JL_DLLEXPORT jl_value_t *jl_compress_ir(jl_method_t *m, jl_code_info_t *code); From 2b68949795ea1de76910f94c786d9f9ee37e8acf Mon Sep 17 00:00:00 2001 From: Diogo Correia Netto Date: Thu, 19 Jun 2025 19:43:15 -0300 Subject: [PATCH 2/4] pass ast context to julia_to_scm --- src/ast.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/ast.c b/src/ast.c index cc0e1330a2a4d..2add0fdf869fa 100644 --- a/src/ast.c +++ b/src/ast.c @@ -153,7 +153,7 @@ struct macroctx_stack { }; static jl_value_t *scm_to_julia(fl_context_t *fl_ctx, value_t e, jl_module_t *mod); -static value_t julia_to_scm(fl_context_t *fl_ctx, jl_value_t *v); +static value_t julia_to_scm(jl_ast_context_t *ctx, jl_value_t *v); static jl_value_t *jl_expand_macros(jl_value_t *expr, jl_module_t *inmodule, struct macroctx_stack *macroctx, int onelevel, size_t world, int throw_load_error); static jl_sym_t *scmsym_to_julia(fl_context_t *fl_ctx, value_t s) @@ -680,14 +680,15 @@ static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, jl_module_t *m jl_error("malformed tree"); } -static value_t julia_to_scm_(fl_context_t *fl_ctx, jl_value_t *v, int check_valid); +static value_t julia_to_scm_(jl_ast_context_t *ctx, jl_value_t *v, int check_valid); -static value_t julia_to_scm(fl_context_t *fl_ctx, jl_value_t *v) +static value_t julia_to_scm(jl_ast_context_t *ctx, jl_value_t *v) { value_t temp; // need try/catch to reset GC handle stack in case of error + fl_context_t *fl_ctx = &ctx->fl; FL_TRY_EXTERN(fl_ctx) { - temp = julia_to_scm_(fl_ctx, v, 1); + temp = julia_to_scm_(ctx, v, 1); } FL_CATCH_EXTERN(fl_ctx) { temp = fl_ctx->lasterror; @@ -695,22 +696,24 @@ static value_t julia_to_scm(fl_context_t *fl_ctx, jl_value_t *v) return temp; } -static void array_to_list(fl_context_t *fl_ctx, jl_array_t *a, value_t *pv, int check_valid) +static void array_to_list(jl_ast_context_t *ctx, jl_array_t *a, value_t *pv, int check_valid) { value_t temp; + fl_context_t *fl_ctx = &ctx->fl; for (long i = jl_array_nrows(a) - 1; i >= 0; i--) { *pv = fl_cons(fl_ctx, fl_ctx->NIL, *pv); - temp = julia_to_scm_(fl_ctx, jl_array_ptr_ref(a, i), check_valid); + temp = julia_to_scm_(ctx, jl_array_ptr_ref(a, i), check_valid); // note: must be separate statement car_(*pv) = temp; } } -static value_t julia_to_list2(fl_context_t *fl_ctx, jl_value_t *a, jl_value_t *b, int check_valid) +static value_t julia_to_list2(jl_ast_context_t *ctx, jl_value_t *a, jl_value_t *b, int check_valid) { - value_t sa = julia_to_scm_(fl_ctx, a, check_valid); + fl_context_t *fl_ctx = &ctx->fl; + value_t sa = julia_to_scm_(ctx, a, check_valid); fl_gc_handle(fl_ctx, &sa); - value_t sb = julia_to_scm_(fl_ctx, b, check_valid); + value_t sb = julia_to_scm_(ctx, b, check_valid); value_t l = fl_list2(fl_ctx, sa, sb); fl_free_gc_handles(fl_ctx, 1); return l; @@ -784,12 +787,13 @@ static value_t julia_to_list2_noalloc(fl_context_t *fl_ctx, jl_value_t *a, jl_va return l; } -static value_t julia_to_scm_(fl_context_t *fl_ctx, jl_value_t *v, int check_valid) +static value_t julia_to_scm_(jl_ast_context_t *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; + fl_context_t *fl_ctx = &ctx->fl; if (julia_to_scm_noalloc1(fl_ctx, v, &retval)) return retval; if (jl_is_expr(v)) { @@ -798,12 +802,12 @@ static value_t julia_to_scm_(fl_context_t *fl_ctx, jl_value_t *v, int check_vali fl_gc_handle(fl_ctx, &args); if (jl_expr_nargs(ex) > 520000 && ex->head != jl_block_sym) lerror(fl_ctx, symbol(fl_ctx, "error"), "expression too large"); - array_to_list(fl_ctx, ex->args, &args, check_valid); - value_t hd = julia_to_scm_(fl_ctx, (jl_value_t*)ex->head, check_valid); + array_to_list(ctx, ex->args, &args, check_valid); + value_t hd = julia_to_scm_(ctx, (jl_value_t*)ex->head, check_valid); if (ex->head == jl_lambda_sym && jl_expr_nargs(ex)>0 && jl_is_array(jl_exprarg(ex,0))) { value_t llist = fl_ctx->NIL; fl_gc_handle(fl_ctx, &llist); - array_to_list(fl_ctx, (jl_array_t*)jl_exprarg(ex,0), &llist, check_valid); + array_to_list(ctx, (jl_array_t*)jl_exprarg(ex,0), &llist, check_valid); car_(args) = llist; fl_free_gc_handles(fl_ctx, 1); } @@ -819,7 +823,7 @@ static value_t julia_to_scm_(fl_context_t *fl_ctx, jl_value_t *v, int check_vali jl_value_t *line = jl_fieldref(v,0); value_t args = julia_to_list2_noalloc(fl_ctx, line, file, check_valid); fl_gc_handle(fl_ctx, &args); - value_t hd = julia_to_scm_(fl_ctx, (jl_value_t*)jl_line_sym, check_valid); + value_t hd = julia_to_scm_(ctx, (jl_value_t*)jl_line_sym, check_valid); value_t scmv = fl_cons(fl_ctx, hd, args); fl_free_gc_handles(fl_ctx, 1); return scmv; @@ -827,18 +831,18 @@ static value_t julia_to_scm_(fl_context_t *fl_ctx, jl_value_t *v, int check_vali if (jl_typetagis(v, jl_gotonode_type)) return julia_to_list2_noalloc(fl_ctx, (jl_value_t*)jl_goto_sym, jl_fieldref(v,0), check_valid); if (jl_typetagis(v, jl_quotenode_type)) - return julia_to_list2(fl_ctx, (jl_value_t*)jl_inert_sym, jl_fieldref_noalloc(v,0), 0); + return julia_to_list2(ctx, (jl_value_t*)jl_inert_sym, jl_fieldref_noalloc(v,0), 0); if (jl_typetagis(v, jl_newvarnode_type)) return julia_to_list2_noalloc(fl_ctx, (jl_value_t*)jl_newvar_sym, jl_fieldref(v,0), check_valid); if (jl_typetagis(v, jl_globalref_type)) { jl_module_t *m = jl_globalref_mod(v); jl_sym_t *sym = jl_globalref_name(v); if (m == jl_core_module) - return julia_to_list2(fl_ctx, (jl_value_t*)jl_core_sym, + return julia_to_list2(ctx, (jl_value_t*)jl_core_sym, (jl_value_t*)sym, check_valid); - value_t args = julia_to_list2(fl_ctx, (jl_value_t*)m, (jl_value_t*)sym, check_valid); + value_t args = julia_to_list2(ctx, (jl_value_t*)m, (jl_value_t*)sym, check_valid); fl_gc_handle(fl_ctx, &args); - value_t hd = julia_to_scm_(fl_ctx, (jl_value_t*)jl_globalref_sym, check_valid); + value_t hd = julia_to_scm_(ctx, (jl_value_t*)jl_globalref_sym, check_valid); value_t scmv = fl_cons(fl_ctx, hd, args); fl_free_gc_handles(fl_ctx, 1); return scmv; @@ -906,8 +910,8 @@ JL_DLLEXPORT jl_value_t *jl_fl_parse(const char *text, size_t text_len, static jl_value_t *jl_call_scm_on_ast(const char *funcname, jl_value_t *expr, jl_module_t *inmodule) { jl_ast_context_t *ctx = jl_ast_ctx_enter(inmodule); + value_t arg = julia_to_scm(ctx, expr); fl_context_t *fl_ctx = &ctx->fl; - value_t arg = julia_to_scm(fl_ctx, expr); value_t e = fl_applyn(fl_ctx, 1, symbol_value(symbol(fl_ctx, funcname)), arg); jl_value_t *result = scm_to_julia(fl_ctx, e, inmodule); JL_GC_PUSH1(&result); @@ -920,8 +924,8 @@ jl_value_t *jl_call_scm_on_ast_and_loc(const char *funcname, jl_value_t *expr, jl_module_t *inmodule, const char *file, int line) { jl_ast_context_t *ctx = jl_ast_ctx_enter(inmodule); + value_t arg = julia_to_scm(ctx, expr); fl_context_t *fl_ctx = &ctx->fl; - value_t arg = julia_to_scm(fl_ctx, expr); value_t e = fl_applyn(fl_ctx, 3, symbol_value(symbol(fl_ctx, funcname)), arg, symbol(fl_ctx, file), fixnum(line)); jl_value_t *result = scm_to_julia(fl_ctx, e, inmodule); @@ -1322,8 +1326,8 @@ JL_DLLEXPORT jl_value_t *jl_expand_with_loc_warn(jl_value_t *expr, jl_module_t * expr = jl_copy_ast(expr); expr = jl_expand_macros(expr, inmodule, NULL, 0, ~(size_t)0, 1); jl_ast_context_t *ctx = jl_ast_ctx_enter(inmodule); + value_t arg = julia_to_scm(ctx, expr); fl_context_t *fl_ctx = &ctx->fl; - value_t arg = julia_to_scm(fl_ctx, expr); value_t e = fl_applyn(fl_ctx, 4, symbol_value(symbol(fl_ctx, "jl-expand-to-thunk-warn")), arg, symbol(fl_ctx, file), fixnum(line), fl_ctx->F); expr = scm_to_julia(fl_ctx, e, inmodule); From 5180f3b6755d722c419e5e8feb46ee3e9f217ad3 Mon Sep 17 00:00:00 2001 From: Diogo Correia Netto Date: Thu, 19 Jun 2025 20:10:34 -0300 Subject: [PATCH 3/4] call pin function on AST ctx --- src/ast.c | 11 +++++++++++ src/gc-mmtk.c | 11 +++++++++++ src/julia.h | 1 + 3 files changed, 23 insertions(+) diff --git a/src/ast.c b/src/ast.c index 2add0fdf869fa..4957f8e6dbd50 100644 --- a/src/ast.c +++ b/src/ast.c @@ -139,6 +139,17 @@ typedef struct _jl_ast_context_t { arraylist_t pinned_objects; } jl_ast_context_t; +// FIXME: Ugly hack to get a pointer to the pinned objects +arraylist_t *extract_pinned_objects_from_ast_ctx(void *ctx) +{ + // This is used to extract pinned objects from the context + // for the purpose of pinning them in MMTk. + if (ctx == NULL) + return NULL; + jl_ast_context_t *jl_ctx = (jl_ast_context_t*)ctx; + return &jl_ctx->pinned_objects; +} + static jl_ast_context_t jl_ast_main_ctx; #ifdef __clang_gcanalyzer__ diff --git a/src/gc-mmtk.c b/src/gc-mmtk.c index 9502954179d32..4f4bd25642478 100644 --- a/src/gc-mmtk.c +++ b/src/gc-mmtk.c @@ -263,6 +263,17 @@ void gc_pin_objects_from_compiler_frontend(arraylist_t *objects_pinned_by_call) arraylist_push(objects_pinned_by_call, obj); } } + for (size_t i = 0; i < jl_ast_ctx_used.len; i++) { + void *ctx = jl_ast_ctx_used.items[i]; + arraylist_t *pinned_objects = extract_pinned_objects_from_ast_ctx(ctx); + for (size_t j = 0; j < pinned_objects->len; j++) { + void *obj = pinned_objects->items[j]; + unsigned char got_pinned = mmtk_pin_object(obj); + if (got_pinned) { + arraylist_push(objects_pinned_by_call, obj); + } + } + } } void gc_unpin_objects_from_compiler_frontend(arraylist_t *objects_pinned_by_call) diff --git a/src/julia.h b/src/julia.h index 64ecbfc686101..677ef41282f4a 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2439,6 +2439,7 @@ JL_DLLEXPORT void jl_register_newmeth_tracer(void (*callback)(jl_method_t *trace // AST access JL_DLLEXPORT jl_value_t *jl_copy_ast(jl_value_t *expr JL_MAYBE_UNROOTED); +arraylist_t *extract_pinned_objects_from_ast_ctx(void *ctx); extern arraylist_t jl_ast_ctx_used; // IR representation From 367a3ca8c9a63a0f51cb6b6846d3d1a18b1f388e Mon Sep 17 00:00:00 2001 From: Diogo Correia Netto Date: Thu, 19 Jun 2025 20:16:44 -0300 Subject: [PATCH 4/4] push into pinned_objects --- src/ast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast.c b/src/ast.c index 4957f8e6dbd50..a33d1dd980c96 100644 --- a/src/ast.c +++ b/src/ast.c @@ -802,7 +802,7 @@ static value_t julia_to_scm_(jl_ast_context_t *ctx, jl_value_t *v, int check_val { // 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); + arraylist_push(&ctx->pinned_objects, v); value_t retval; fl_context_t *fl_ctx = &ctx->fl; if (julia_to_scm_noalloc1(fl_ctx, v, &retval))