Skip to content

Commit 1a472bb

Browse files
authored
Trace pinned objects as roots (#91)
Following the suggestion in #89 (comment), trace recently added pinned objects as roots. When we pass those objects as 'nodes' to MMTk, MMTk does not know the slots so MMTk cannot update the reference, thus MMTk will not move those objects. This is essentially the same as pinning those objects before a GC, and unpinning after a GC.
1 parent a3d4e39 commit 1a472bb

File tree

5 files changed

+33
-49
lines changed

5 files changed

+33
-49
lines changed

src/ast.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,18 +136,19 @@ typedef struct _jl_ast_context_t {
136136
value_t ssavalue_sym;
137137
value_t slot_sym;
138138
jl_module_t *module; // context module for `current-julia-module-counter`
139-
arraylist_t pinned_objects;
139+
// These are essentially roots for ast context.
140+
arraylist_t ast_roots;
140141
} jl_ast_context_t;
141142

142143
// FIXME: Ugly hack to get a pointer to the pinned objects
143-
arraylist_t *extract_pinned_objects_from_ast_ctx(void *ctx)
144+
arraylist_t *extract_ast_roots_from_ast_ctx(void *ctx)
144145
{
145146
// This is used to extract pinned objects from the context
146147
// for the purpose of pinning them in MMTk.
147148
if (ctx == NULL)
148149
return NULL;
149150
jl_ast_context_t *jl_ctx = (jl_ast_context_t*)ctx;
150-
return &jl_ctx->pinned_objects;
151+
return &jl_ctx->ast_roots;
151152
}
152153

153154
static jl_ast_context_t jl_ast_main_ctx;
@@ -290,7 +291,7 @@ static void jl_init_ast_ctx(jl_ast_context_t *ctx) JL_NOTSAFEPOINT
290291
ctx->slot_sym = symbol(fl_ctx, "slot");
291292
ctx->module = NULL;
292293
set(symbol(fl_ctx, "*scopewarn-opt*"), fixnum(jl_options.warn_scope));
293-
arraylist_new(&ctx->pinned_objects, 0);
294+
arraylist_new(&ctx->ast_roots, 0);
294295
}
295296

296297
// There should be no GC allocation while holding this lock
@@ -321,7 +322,7 @@ static void jl_ast_ctx_leave(jl_ast_context_t *ctx)
321322
{
322323
uv_mutex_lock(&flisp_lock);
323324
ctx->module = NULL;
324-
ctx->pinned_objects.len = 0; // clear pinned objects
325+
ctx->ast_roots.len = 0; // clear root objects
325326
arraylist_pop(&jl_ast_ctx_used);
326327
arraylist_push(&jl_ast_ctx_freed, ctx);
327328
uv_mutex_unlock(&flisp_lock);
@@ -802,7 +803,7 @@ static value_t julia_to_scm_(jl_ast_context_t *ctx, jl_value_t *v, int check_val
802803
{
803804
// The following code will take internal pointers to v's fields. We need to make sure
804805
// that v will not be moved by GC.
805-
arraylist_push(&ctx->pinned_objects, v);
806+
arraylist_push(&ctx->ast_roots, v);
806807
value_t retval;
807808
fl_context_t *fl_ctx = &ctx->fl;
808809
if (julia_to_scm_noalloc1(fl_ctx, v, &retval))

src/engine.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,15 @@ jl_code_instance_t *jl_engine_reserve(jl_method_instance_t *m, jl_value_t *owner
6464
auto tid = jl_atomic_load_relaxed(&ct->tid);
6565
if (([tid, m, owner, ci] () -> bool { // necessary scope block / lambda for unique_lock
6666
jl_unique_gcsafe_lock lock(engine_lock);
67-
arraylist_push(&gc_pinned_objects, owner);
67+
arraylist_push(&extra_gc_roots, owner);
6868
InferKey key{m, owner};
6969
if ((signed)Awaiting.size() < tid + 1)
7070
Awaiting.resize(tid + 1);
7171
while (1) {
7272
auto record = Reservations.find(key);
7373
if (record == Reservations.end()) {
7474
Reservations[key] = ReservationInfo{tid, ci};
75-
arraylist_pop(&gc_pinned_objects);
75+
arraylist_pop(&extra_gc_roots);
7676
return false;
7777
}
7878
// before waiting, need to run deadlock/cycle detection
@@ -81,7 +81,7 @@ jl_code_instance_t *jl_engine_reserve(jl_method_instance_t *m, jl_value_t *owner
8181
auto wait_tid = record->second.tid;
8282
while (1) {
8383
if (wait_tid == tid) {
84-
arraylist_pop(&gc_pinned_objects);
84+
arraylist_pop(&extra_gc_roots);
8585
return true;
8686
}
8787
if ((signed)Awaiting.size() <= wait_tid)
@@ -99,7 +99,7 @@ jl_code_instance_t *jl_engine_reserve(jl_method_instance_t *m, jl_value_t *owner
9999
lock.wait(engine_wait);
100100
Awaiting[tid] = InferKey{};
101101
}
102-
arraylist_pop(&gc_pinned_objects);
102+
arraylist_pop(&extra_gc_roots);
103103
})())
104104
ct->ptls->engine_nqueued--;
105105
JL_GC_POP();

src/gc-common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,7 @@ JL_DLLEXPORT int jl_gc_enable(int on)
687687
// MISC
688688
// =========================================================================== //
689689

690-
arraylist_t gc_pinned_objects;
690+
arraylist_t extra_gc_roots;
691691

692692
JL_DLLEXPORT jl_weakref_t *jl_gc_new_weakref(jl_value_t *value)
693693
{

src/gc-mmtk.c

Lines changed: 17 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ void jl_gc_init(void) {
7474

7575
jl_set_check_alive_type(mmtk_is_reachable_object);
7676

77-
arraylist_new(&gc_pinned_objects, 0);
77+
arraylist_new(&extra_gc_roots, 0);
7878
arraylist_new(&to_finalize, 0);
7979
arraylist_new(&finalizer_list_marked, 0);
8080
gc_num.interval = default_collect_interval;
@@ -254,36 +254,6 @@ JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection) {
254254
// print_fragmentation();
255255
}
256256

257-
void gc_pin_objects_from_compiler_frontend(arraylist_t *objects_pinned_by_call)
258-
{
259-
for (size_t i = 0; i < gc_pinned_objects.len; i++) {
260-
void *obj = gc_pinned_objects.items[i];
261-
unsigned char got_pinned = mmtk_pin_object(obj);
262-
if (got_pinned) {
263-
arraylist_push(objects_pinned_by_call, obj);
264-
}
265-
}
266-
for (size_t i = 0; i < jl_ast_ctx_used.len; i++) {
267-
void *ctx = jl_ast_ctx_used.items[i];
268-
arraylist_t *pinned_objects = extract_pinned_objects_from_ast_ctx(ctx);
269-
for (size_t j = 0; j < pinned_objects->len; j++) {
270-
void *obj = pinned_objects->items[j];
271-
unsigned char got_pinned = mmtk_pin_object(obj);
272-
if (got_pinned) {
273-
arraylist_push(objects_pinned_by_call, obj);
274-
}
275-
}
276-
}
277-
}
278-
279-
void gc_unpin_objects_from_compiler_frontend(arraylist_t *objects_pinned_by_call)
280-
{
281-
for (size_t i = 0; i < objects_pinned_by_call->len; i++) {
282-
void *obj = objects_pinned_by_call->items[i];
283-
mmtk_unpin_object(obj);
284-
}
285-
}
286-
287257
// Based on jl_gc_collect from gc-stock.c
288258
// called when stopping the thread in `mmtk_block_for_gc`
289259
JL_DLLEXPORT void jl_gc_prepare_to_collect(void)
@@ -346,12 +316,7 @@ JL_DLLEXPORT void jl_gc_prepare_to_collect(void)
346316
jl_gc_notify_thread_yield(ptls, NULL);
347317
JL_LOCK_NOGC(&finalizers_lock); // all the other threads are stopped, so this does not make sense, right? otherwise, failing that, this seems like plausibly a deadlock
348318
#ifndef __clang_gcanalyzer__
349-
arraylist_t objects_pinned_by_call;
350-
arraylist_new(&objects_pinned_by_call, 0);
351-
gc_pin_objects_from_compiler_frontend(&objects_pinned_by_call);
352319
mmtk_block_thread_for_gc();
353-
gc_unpin_objects_from_compiler_frontend(&objects_pinned_by_call);
354-
arraylist_free(&objects_pinned_by_call);
355320
#endif
356321
JL_UNLOCK_NOGC(&finalizers_lock);
357322
}
@@ -838,6 +803,22 @@ JL_DLLEXPORT void jl_gc_scan_vm_specific_roots(RootsWorkClosure* closure)
838803
}
839804
}
840805

806+
// Trace objects in extra_gc_roots
807+
for (size_t i = 0; i < extra_gc_roots.len; i++) {
808+
void* obj = extra_gc_roots.items[i];
809+
add_node_to_roots_buffer(closure, &buf, &len, obj);
810+
}
811+
812+
// Trace objects in jl_ast_ctx_used
813+
for (size_t i = 0; i < jl_ast_ctx_used.len; i++) {
814+
void *ctx = jl_ast_ctx_used.items[i];
815+
arraylist_t *ast_roots = extract_ast_roots_from_ast_ctx(ctx);
816+
for (size_t j = 0; j < ast_roots->len; j++) {
817+
void *obj = ast_roots->items[j];
818+
add_node_to_roots_buffer(closure, &buf, &len, obj);
819+
}
820+
}
821+
841822
// // add module
842823
// add_node_to_roots_buffer(closure, &buf, &len, jl_main_module);
843824

src/julia.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,7 +1346,9 @@ JL_DLLEXPORT JL_CONST_FUNC jl_gcframe_t **(jl_get_pgcstack)(void) JL_GLOBALLY_RO
13461346

13471347
// object pinning ------------------------------------------------------------
13481348

1349-
extern arraylist_t gc_pinned_objects;
1349+
// These 'new roots' are added for moving GCs.
1350+
// We could consider merging this list with global roots list if we can push and pop from global roots list in the same way.
1351+
extern arraylist_t extra_gc_roots;
13501352
typedef bool (*check_alive_fn_type)(void *);
13511353
JL_DLLEXPORT void jl_set_check_alive_type(check_alive_fn_type fn);
13521354
JL_DLLEXPORT void jl_log_pinning_event(void *pinned_object, const char *filename, int lineno);
@@ -2439,7 +2441,7 @@ JL_DLLEXPORT void jl_register_newmeth_tracer(void (*callback)(jl_method_t *trace
24392441

24402442
// AST access
24412443
JL_DLLEXPORT jl_value_t *jl_copy_ast(jl_value_t *expr JL_MAYBE_UNROOTED);
2442-
arraylist_t *extract_pinned_objects_from_ast_ctx(void *ctx);
2444+
arraylist_t *extract_ast_roots_from_ast_ctx(void *ctx);
24432445
extern arraylist_t jl_ast_ctx_used;
24442446

24452447
// IR representation

0 commit comments

Comments
 (0)