Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support moving GCs in MMTk #57294

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion deps/mmtk_julia.mk
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Both MMTK_MOVING and MMTK_PLAN should be specified in the Make.user file.
# At this point, since we only support non-moving this is always set to 0
# FIXME: change it to `?:` when introducing moving plans
MMTK_MOVING := 0
MMTK_MOVING ?= 0
MMTK_VARS := MMTK_PLAN=$(MMTK_PLAN) MMTK_MOVING=$(MMTK_MOVING)

ifneq ($(USE_BINARYBUILDER_MMTK_JULIA),1)
Expand Down
1 change: 1 addition & 0 deletions src/aotcompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ typedef struct {
SmallVector<GlobalValue*, 0> jl_sysimg_fvars;
SmallVector<GlobalValue*, 0> jl_sysimg_gvars;
std::map<jl_code_instance_t*, std::tuple<uint32_t, uint32_t>> jl_fvar_map;
// This holds references to the heap. Need to be pinned.
SmallVector<void*, 0> jl_value_to_llvm;
SmallVector<jl_code_instance_t*, 0> jl_external_to_llvm;
} jl_native_code_desc_t;
Expand Down
3 changes: 3 additions & 0 deletions src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,9 @@ 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))
return retval;
Expand Down
11 changes: 11 additions & 0 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,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.
OBJ_PIN(v);
uintptr_t bits = jl_astaggedvalue(v)->header;
if (bits & GC_IN_IMAGE)
return ((uintptr_t*)v)[-2];
Expand Down Expand Up @@ -400,6 +403,10 @@ static uintptr_t immut_id_(jl_datatype_t *dt, jl_value_t *v, uintptr_t h) JL_NOT
// a few select pointers (notably symbol) also have special hash values
// which may affect the stability of the objectid hash, even though
// they don't affect egal comparison

// FIXME: Pinning objects that get hashed
// until we implement address space hashing.
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)
Expand Down Expand Up @@ -460,6 +467,10 @@ static uintptr_t NOINLINE jl_object_id__cold(uintptr_t tv, jl_value_t *v) JL_NOT
uintptr_t bits = jl_astaggedvalue(v)->header;
if (bits & GC_IN_IMAGE)
return ((uintptr_t*)v)[-2];

// FIXME: Pinning objects that get hashed
// until we implement address space hashing.
OBJ_PIN(v);
return inthash((uintptr_t)v);
}
return immut_id_(dt, v, dt->hash);
Expand Down
3 changes: 3 additions & 0 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ static Constant *julia_pgv(jl_codegen_params_t &params, Module *M, const char *c
// 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 = params.global_targets[addr];
StringRef localname;
std::string gvname;
Expand Down Expand Up @@ -564,6 +565,8 @@ 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.emission_context, jl_Module, p);
jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const);
auto load = ai.decorateInst(maybe_mark_load_dereferenceable(
Expand Down
10 changes: 10 additions & 0 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1822,6 +1822,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;
Expand All @@ -1838,6 +1839,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);
Expand All @@ -1858,6 +1860,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);
}
Expand All @@ -1874,6 +1878,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
Expand Down Expand Up @@ -1946,6 +1952,7 @@ class jl_codectx_t {
std::map<int, jl_varinfo_t> phic_slots;
std::map<int, std::pair<Value*, Value*> > scope_restore;
SmallVector<jl_cgval_t, 0> SAvalues;
// The vector holds reference to Julia obj ref. We need to pin jl_value_t*.
SmallVector<std::tuple<jl_cgval_t, BasicBlock *, AllocaInst *, PHINode *, SmallVector<PHINode*,0>, jl_value_t *>, 0> PhiNodes;
SmallVector<bool, 0> ssavalue_assigned;
SmallVector<int, 0> ssavalue_usecount;
Expand Down Expand Up @@ -6240,6 +6247,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); // 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;
Expand All @@ -6249,6 +6257,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); // 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;
Expand Down Expand Up @@ -6299,6 +6308,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); // 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;
Expand Down
4 changes: 2 additions & 2 deletions src/datatype.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *modu
{
jl_task_t *ct = jl_current_task;
jl_typename_t *tn =
(jl_typename_t*)jl_gc_alloc(ct->ptls, sizeof(jl_typename_t),
(jl_typename_t*)jl_gc_alloc_nonmoving(ct->ptls, sizeof(jl_typename_t),
jl_typename_type);
tn->name = name;
tn->module = module;
Expand Down Expand Up @@ -95,7 +95,7 @@ jl_datatype_t *jl_new_abstracttype(jl_value_t *name, jl_module_t *module, jl_dat
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);
jl_datatype_t *t = (jl_datatype_t*)jl_gc_alloc_nonmoving(ct->ptls, sizeof(jl_datatype_t), jl_datatype_type);
jl_set_typetagof(t, jl_datatype_tag, 0);
t->hash = 0;
t->hasfreetypevars = 0;
Expand Down
5 changes: 5 additions & 0 deletions src/gc-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,11 @@ JL_DLLEXPORT jl_value_t *(jl_gc_alloc)(jl_ptls_t ptls, size_t sz, void *ty)
return jl_gc_alloc_(ptls, sz, ty);
}

JL_DLLEXPORT jl_value_t *(jl_gc_alloc_nonmoving)(jl_ptls_t ptls, size_t sz, void *ty)
{
return jl_gc_alloc_nonmoving_(ptls, sz, ty);
}

JL_DLLEXPORT void *jl_malloc(size_t sz)
{
return jl_gc_counted_malloc(sz);
Expand Down
21 changes: 21 additions & 0 deletions src/gc-interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,27 @@ JL_DLLEXPORT void jl_gc_set_max_memory(uint64_t max_mem);
JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection);
// Returns whether the thread with `tid` is a collector thread
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 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);
// Sweep Julia's stack pools and mtarray buffers. Note that this function has been added to the interface as
// each GC should implement it but it will most likely not be used by other code in the runtime.
// It still needs to be annotated with JL_DLLEXPORT since it is called from Rust by MMTk.
JL_DLLEXPORT void jl_gc_sweep_stack_pools_and_mtarraylist_buffers(jl_ptls_t ptls) JL_NOTSAFEPOINT;
// Notifies the GC that the given thread is about to yield for a GC. ctx is the ucontext for the thread
// if it is already fetched by the caller, otherwise it is NULL.
JL_DLLEXPORT void jl_gc_notify_thread_yield(jl_ptls_t ptls, void* ctx);

// TODO: The preserve hook functions may be temporary. We should see the performance impact of the change.

// Runtime hook for gc preserve begin. The GC needs to make sure that the preserved objects and its children stay alive and won't move.
JL_DLLEXPORT void jl_gc_preserve_begin_hook(int n, ...) JL_NOTSAFEPOINT;
// Runtime hook for gc preserve end. The GC needs to make sure that the preserved objects and its children stay alive and won't move.
JL_DLLEXPORT void jl_gc_preserve_end_hook(void) JL_NOTSAFEPOINT;

// ========================================================================= //
// Metrics
Expand Down Expand Up @@ -148,6 +162,9 @@ JL_DLLEXPORT uint64_t jl_gc_total_hrtime(void);
// **must** also set the type of the returning object to be `ty`. The type `ty` may also be used to record
// an allocation of that type in the allocation profiler.
struct _jl_value_t *jl_gc_alloc_(struct _jl_tls_states_t * ptls, size_t sz, void *ty);
// Similar to jl_gc_alloc_, except that the GC needs to make sure the object allocated from this function will
// not be moved by the GC.
struct _jl_value_t *jl_gc_alloc_nonmoving_(struct _jl_tls_states_t * ptls, size_t sz, void *ty);
// Allocates small objects and increments Julia allocation counterst. Size of the object
// header must be included in the object size. The (possibly unused in some implementations)
// offset to the arena in which we're allocating is passed in the second parameter, and the
Expand Down Expand Up @@ -214,6 +231,10 @@ struct _jl_value_t *jl_gc_permobj(size_t sz, void *ty, unsigned align) JL_NOTSAF
// The GC may use that information to, for instance, determine that such objects should
// be treated as marked and belonged to the old generation in nursery collections.
void jl_gc_notify_image_load(const char* img_data, size_t len);
// This function notifies the GC about memory addresses that are set when allocating the boot image.
// The GC may use that information to, for instance, determine that all objects in that chunk of memory should
// be treated as marked and belonged to the old generation in nursery collections.
void jl_gc_notify_image_alloc(const char* img_data, size_t len);

// ========================================================================= //
// Runtime Write-Barriers
Expand Down
Loading