Skip to content

Commit

Permalink
Make jl_binding_t into a first-class object (#47592)
Browse files Browse the repository at this point in the history
* Make jl_binding_t into a first-class object (called Binding)

* remove special handling for bindings in GC

This removes a feature where all bindings were promoted to old if the
module containing them was old and cleans up some odd dead code for
scanparent. It could be restored explicitly by calling
jl_gc_force_mark_old during construction and sweeping.

Co-authored-by: Jameson Nash <vtjnash@gmail.com>
  • Loading branch information
apaz-cli and vtjnash authored Dec 14, 2022
1 parent 0fcf896 commit 437ebe1
Show file tree
Hide file tree
Showing 26 changed files with 72 additions and 222 deletions.
2 changes: 1 addition & 1 deletion base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2490,7 +2490,7 @@ function abstract_eval_globalref(g::GlobalRef)
g.binding != C_NULL && return Const(ccall(:jl_binding_value, Any, (Ptr{Cvoid},), g.binding))
return Const(getglobal(g.mod, g.name))
end
ty = ccall(:jl_binding_type, Any, (Any, Any), g.mod, g.name)
ty = ccall(:jl_get_binding_type, Any, (Any, Any), g.mod, g.name)
ty === nothing && return Any
return ty
end
Expand Down
4 changes: 2 additions & 2 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2526,7 +2526,7 @@ end

function global_assignment_nothrow(M::Module, s::Symbol, @nospecialize(newty))
if isdefined(M, s) && !isconst(M, s)
ty = ccall(:jl_binding_type, Any, (Any, Any), M, s)
ty = ccall(:jl_get_binding_type, Any, (Any, Any), M, s)
return ty === nothing || newty ty
end
return false
Expand All @@ -2536,7 +2536,7 @@ end
if M isa Const && s isa Const
M, s = M.val, s.val
if M isa Module && s isa Symbol
return ccall(:jl_binding_type, Any, (Any, Any), M, s) !== nothing
return ccall(:jl_get_binding_type, Any, (Any, Any), M, s) !== nothing
end
end
return false
Expand Down
3 changes: 2 additions & 1 deletion src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -1228,7 +1228,7 @@ JL_CALLABLE(jl_f_get_binding_type)
JL_TYPECHK(get_binding_type, symbol, args[1]);
jl_module_t *mod = (jl_module_t*)args[0];
jl_sym_t *sym = (jl_sym_t*)args[1];
jl_value_t *ty = jl_binding_type(mod, sym);
jl_value_t *ty = jl_get_binding_type(mod, sym);
if (ty == (jl_value_t*)jl_nothing) {
jl_binding_t *b = jl_get_binding_wr(mod, sym, 0);
if (b && b->owner == mod) {
Expand Down Expand Up @@ -2057,6 +2057,7 @@ void jl_init_primitives(void) JL_GC_DISABLED
add_builtin("UpsilonNode", (jl_value_t*)jl_upsilonnode_type);
add_builtin("QuoteNode", (jl_value_t*)jl_quotenode_type);
add_builtin("NewvarNode", (jl_value_t*)jl_newvarnode_type);
add_builtin("Binding", (jl_value_t*)jl_binding_type);
add_builtin("GlobalRef", (jl_value_t*)jl_globalref_type);
add_builtin("NamedTuple", (jl_value_t*)jl_namedtuple_type);

Expand Down
8 changes: 0 additions & 8 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3488,14 +3488,6 @@ static void emit_write_barrier(jl_codectx_t &ctx, Value *parent, ArrayRef<Value*
ctx.builder.CreateCall(prepare_call(jl_write_barrier_func), decay_ptrs);
}

static void emit_write_barrier_binding(jl_codectx_t &ctx, Value *parent, Value *ptr)
{
SmallVector<Value*, 8> decay_ptrs;
decay_ptrs.push_back(maybe_decay_untracked(ctx, emit_bitcast(ctx, parent, ctx.types().T_prjlvalue)));
decay_ptrs.push_back(maybe_decay_untracked(ctx, emit_bitcast(ctx, ptr, ctx.types().T_prjlvalue)));
ctx.builder.CreateCall(prepare_call(jl_write_barrier_binding_func), decay_ptrs);
}

static void find_perm_offsets(jl_datatype_t *typ, SmallVector<unsigned,4> &res, unsigned offset)
{
// This is a inlined field at `offset`.
Expand Down
2 changes: 1 addition & 1 deletion src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2604,7 +2604,7 @@ static void emit_globalset(jl_codectx_t &ctx, jl_binding_t *bnd, Value *bp, cons
StoreInst *v = ctx.builder.CreateAlignedStore(rval, julia_binding_pvalue(ctx, bp), Align(sizeof(void*)));
v->setOrdering(Order);
tbaa_decorate(ctx.tbaa().tbaa_binding, v);
emit_write_barrier_binding(ctx, bp, rval);
emit_write_barrier(ctx, bp, rval);
return;
}
}
Expand Down
1 change: 0 additions & 1 deletion src/common_symbols1.inc
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,3 @@ jl_symbol("structdiff"),
jl_symbol("undef"),
jl_symbol("sizeof"),
jl_symbol("String"),
jl_symbol("namedtuple.jl"),
2 changes: 1 addition & 1 deletion src/common_symbols2.inc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
jl_symbol("namedtuple.jl"),
jl_symbol("pop"),
jl_symbol("inbounds"),
jl_symbol("strings/string.jl"),
Expand Down Expand Up @@ -251,4 +252,3 @@ jl_symbol("view"),
jl_symbol("GitError"),
jl_symbol("zeros"),
jl_symbol("InexactError"),
jl_symbol("LogLevel"),
4 changes: 2 additions & 2 deletions src/gc-debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -1385,8 +1385,8 @@ NOINLINE void gc_mark_loop_unwind(jl_ptls_t ptls, jl_gc_mark_sp_t sp, int pc_off
jl_safe_printf("Mark stack unwind overflow -- ABORTING !!!\n");
break;
}
jl_safe_printf("%p: %s Module (bindings) %p (bits %d) -- [%p, %p)\n",
(void*)data, prefix, (void*)data->parent, (int)data->bits,
jl_safe_printf("%p: %s Module (bindings) %p -- [%p, %p)\n",
(void*)data, prefix, (void*)data->parent,
(void*)data->begin, (void*)data->end);
}
else {
Expand Down
103 changes: 11 additions & 92 deletions src/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1467,7 +1467,9 @@ static jl_taggedvalue_t **sweep_page(jl_gc_pool_t *p, jl_gc_pagemeta_t *pg, jl_t
else { // marked young or old
if (*ages & msk || bits == GC_OLD_MARKED) { // old enough
// `!age && bits == GC_OLD_MARKED` is possible for
// non-first-class objects like `jl_binding_t`
// non-first-class objects like array buffers
// (they may get promoted by jl_gc_wb_buf for example,
// or explicitly by jl_gc_force_mark_old)
if (sweep_full || bits == GC_MARKED) {
bits = v->bits.gc = GC_OLD; // promote
}
Expand Down Expand Up @@ -1751,14 +1753,6 @@ void jl_gc_queue_multiroot(const jl_value_t *parent, const jl_value_t *ptr) JL_N
}
}

JL_DLLEXPORT void jl_gc_queue_binding(jl_binding_t *bnd)
{
jl_ptls_t ptls = jl_current_task->ptls;
jl_taggedvalue_t *buf = jl_astaggedvalue(bnd);
buf->bits.gc = GC_MARKED;
arraylist_push(&ptls->heap.rem_bindings, bnd);
}


#ifdef JL_DEBUG_BUILD
static void *volatile gc_findval; // for usage from gdb, for finding the gc-root for a value
Expand Down Expand Up @@ -2543,61 +2537,18 @@ module_binding: {
gc_mark_binding_t *binding = gc_pop_markdata(&sp, gc_mark_binding_t);
jl_binding_t **begin = binding->begin;
jl_binding_t **end = binding->end;
uint8_t mbits = binding->bits;
for (; begin < end; begin += 2) {
jl_binding_t *b = *begin;
if (b == (jl_binding_t*)HT_NOTFOUND)
continue;
if (jl_object_in_image((jl_value_t*)b)) {
jl_taggedvalue_t *buf = jl_astaggedvalue(b);
uintptr_t tag = buf->header;
uint8_t bits;
if (!gc_marked(tag))
gc_setmark_tag(buf, GC_OLD_MARKED, tag, &bits);
}
else {
gc_setmark_buf_(ptls, b, mbits, sizeof(jl_binding_t));
}
void *vb = jl_astaggedvalue(b);
verify_parent1("module", binding->parent, &vb, "binding_buff");
verify_parent1("module", binding->parent, begin, "binding_buff");
// Record the size used for the box for non-const bindings
gc_heap_snapshot_record_module_to_binding(binding->parent, b);
(void)vb;
jl_value_t *ty = jl_atomic_load_relaxed(&b->ty);
if (ty && ty != (jl_value_t*)jl_any_type) {
verify_parent2("module", binding->parent,
&b->ty, "binding(%s)", jl_symbol_name(b->name));
if (gc_try_setmark(ty, &binding->nptr, &tag, &bits)) {
new_obj = ty;
gc_repush_markdata(&sp, gc_mark_binding_t);
goto mark;
}
}
jl_value_t *value = jl_atomic_load_relaxed(&b->value);
jl_value_t *globalref = jl_atomic_load_relaxed(&b->globalref);
if (value) {
verify_parent2("module", binding->parent,
&b->value, "binding(%s)", jl_symbol_name(b->name));
if (gc_try_setmark(value, &binding->nptr, &tag, &bits)) {
new_obj = value;
begin += 2;
binding->begin = begin;
gc_repush_markdata(&sp, gc_mark_binding_t);
uintptr_t gr_tag;
uint8_t gr_bits;
if (gc_try_setmark(globalref, &binding->nptr, &gr_tag, &gr_bits)) {
gc_mark_marked_obj_t data = {globalref, gr_tag, gr_bits};
gc_mark_stack_push(&ptls->gc_cache, &sp, gc_mark_laddr(marked_obj),
&data, sizeof(data), 1);
}
goto mark;
}
}
if (gc_try_setmark(globalref, &binding->nptr, &tag, &bits)) {
if (gc_try_setmark((jl_value_t*)b, &binding->nptr, &tag, &bits)) {
begin += 2;
binding->begin = begin;
gc_repush_markdata(&sp, gc_mark_binding_t);
new_obj = globalref;
new_obj = (jl_value_t*)b;
goto mark;
}
}
Expand All @@ -2614,6 +2565,7 @@ module_binding: {
gc_mark_objarray_t data = {(jl_value_t*)m, objary_begin, objary_end, 1, binding->nptr};
gc_mark_stack_push(&ptls->gc_cache, &sp, gc_mark_laddr(objarray),
&data, sizeof(data), 0);
// gc_mark_scan_objarray will eventually handle the remset for m
if (!scanparent) {
objary = (gc_mark_objarray_t*)sp.data;
goto objarray_loaded;
Expand All @@ -2622,6 +2574,7 @@ module_binding: {
sp.pc++;
}
else {
// done with m
gc_mark_push_remset(ptls, (jl_value_t*)m, binding->nptr);
}
if (scanparent) {
Expand Down Expand Up @@ -2810,7 +2763,7 @@ mark: {
jl_binding_t **table = (jl_binding_t**)m->bindings.table;
size_t bsize = m->bindings.size;
uintptr_t nptr = ((bsize + m->usings.len + 1) << 2) | (bits & GC_OLD);
gc_mark_binding_t markdata = {m, table + 1, table + bsize, nptr, bits};
gc_mark_binding_t markdata = {m, table + 1, table + bsize, nptr};
gc_mark_stack_push(&ptls->gc_cache, &sp, gc_mark_laddr(module_binding),
&markdata, sizeof(markdata), 0);
sp.data = (jl_gc_mark_data_t *)(((char*)sp.data) + sizeof(markdata));
Expand Down Expand Up @@ -3181,12 +3134,6 @@ static void jl_gc_premark(jl_ptls_t ptls2)
objprofile_count(jl_typeof(item), 2, 0);
jl_astaggedvalue(item)->bits.gc = GC_OLD_MARKED;
}
len = ptls2->heap.rem_bindings.len;
items = ptls2->heap.rem_bindings.items;
for (size_t i = 0; i < len; i++) {
void *ptr = items[i];
jl_astaggedvalue(ptr)->bits.gc = GC_OLD_MARKED;
}
}

static void jl_gc_queue_remset(jl_gc_mark_cache_t *gc_cache, jl_gc_mark_sp_t *sp, jl_ptls_t ptls2)
Expand All @@ -3195,29 +3142,6 @@ static void jl_gc_queue_remset(jl_gc_mark_cache_t *gc_cache, jl_gc_mark_sp_t *sp
void **items = ptls2->heap.last_remset->items;
for (size_t i = 0; i < len; i++)
gc_mark_queue_scan_obj(gc_cache, sp, (jl_value_t*)items[i]);
int n_bnd_refyoung = 0;
len = ptls2->heap.rem_bindings.len;
items = ptls2->heap.rem_bindings.items;
for (size_t i = 0; i < len; i++) {
jl_binding_t *ptr = (jl_binding_t*)items[i];
// A null pointer can happen here when the binding is cleaned up
// as an exception is thrown after it was already queued (#10221)
int bnd_refyoung = 0;
jl_value_t *v = jl_atomic_load_relaxed(&ptr->value);
if (v != NULL && gc_mark_queue_obj(gc_cache, sp, v))
bnd_refyoung = 1;
jl_value_t *ty = jl_atomic_load_relaxed(&ptr->ty);
if (ty != NULL && gc_mark_queue_obj(gc_cache, sp, ty))
bnd_refyoung = 1;
jl_value_t *globalref = jl_atomic_load_relaxed(&ptr->globalref);
if (globalref != NULL && gc_mark_queue_obj(gc_cache, sp, globalref))
bnd_refyoung = 1;
if (bnd_refyoung) {
items[n_bnd_refyoung] = ptr;
n_bnd_refyoung++;
}
}
ptls2->heap.rem_bindings.len = n_bnd_refyoung;
}

static void jl_gc_queue_bt_buf(jl_gc_mark_cache_t *gc_cache, jl_gc_mark_sp_t *sp, jl_ptls_t ptls2)
Expand Down Expand Up @@ -3263,7 +3187,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
jl_ptls_t ptls2 = gc_all_tls_states[t_i];
if (ptls2 == NULL)
continue;
// 2.1. mark every object in the `last_remsets` and `rem_binding`
// 2.1. mark every object in the `last_remsets`
jl_gc_queue_remset(gc_cache, &sp, ptls2);
// 2.2. mark every thread local root
jl_gc_queue_thread_local(gc_cache, &sp, ptls2);
Expand Down Expand Up @@ -3438,16 +3362,12 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
continue;
if (!sweep_full) {
for (int i = 0; i < ptls2->heap.remset->len; i++) {
jl_astaggedvalue(ptls2->heap.remset->items[i])->bits.gc = GC_MARKED;
}
for (int i = 0; i < ptls2->heap.rem_bindings.len; i++) {
void *ptr = ptls2->heap.rem_bindings.items[i];
void *ptr = ptls2->heap.remset->items[i];
jl_astaggedvalue(ptr)->bits.gc = GC_MARKED;
}
}
else {
ptls2->heap.remset->len = 0;
ptls2->heap.rem_bindings.len = 0;
}
}

Expand Down Expand Up @@ -3636,7 +3556,6 @@ void jl_init_thread_heap(jl_ptls_t ptls)
heap->mallocarrays = NULL;
heap->mafreelist = NULL;
heap->big_objects = NULL;
arraylist_new(&heap->rem_bindings, 0);
heap->remset = &heap->_remset[0];
heap->last_remset = &heap->_remset[1];
arraylist_new(heap->remset, 0);
Expand Down
1 change: 0 additions & 1 deletion src/gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ typedef struct {
jl_binding_t **begin; // The first slot to be scanned.
jl_binding_t **end; // The end address (after the last slot to be scanned)
uintptr_t nptr; // See notes about `nptr` above.
uint8_t bits; // GC bits of the module (the bits to mark the binding buffer with)
} gc_mark_binding_t;

// Finalizer (or object) list
Expand Down
1 change: 1 addition & 0 deletions src/jl_exported_data.inc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
XX(jl_float64_type) \
XX(jl_floatingpoint_type) \
XX(jl_function_type) \
XX(jl_binding_type) \
XX(jl_globalref_type) \
XX(jl_gotoifnot_type) \
XX(jl_gotonode_type) \
Expand Down
11 changes: 11 additions & 0 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2727,6 +2727,16 @@ void jl_init_types(void) JL_GC_DISABLED

jl_value_t *pointer_void = jl_apply_type1((jl_value_t*)jl_pointer_type, (jl_value_t*)jl_nothing_type);

jl_binding_type =
jl_new_datatype(jl_symbol("Binding"), core, jl_any_type, jl_emptysvec,
jl_perm_symsvec(6, "name", "value", "globalref", "owner", "ty", "flags"),
jl_svec(6, jl_symbol_type, jl_any_type, jl_any_type/*jl_globalref_type*/, jl_module_type, jl_any_type, jl_uint8_type),
jl_emptysvec, 0, 1, 1);
const static uint32_t binding_constfields[1] = { 0x0001 }; // Set fields 1 as const
const static uint32_t binding_atomicfields[1] = { 0x0016 }; // Set fields 2, 3, 5 as atomic
jl_binding_type->name->constfields = binding_constfields;
jl_binding_type->name->atomicfields = binding_atomicfields;

jl_globalref_type =
jl_new_datatype(jl_symbol("GlobalRef"), core, jl_any_type, jl_emptysvec,
jl_perm_symsvec(3, "mod", "name", "binding"),
Expand Down Expand Up @@ -2772,6 +2782,7 @@ void jl_init_types(void) JL_GC_DISABLED
jl_svecset(jl_method_instance_type->types, 6, jl_code_instance_type);
jl_svecset(jl_code_instance_type->types, 13, jl_voidpointer_type);
jl_svecset(jl_code_instance_type->types, 14, jl_voidpointer_type);
jl_svecset(jl_binding_type->types, 2, jl_globalref_type);

jl_compute_field_offsets(jl_datatype_type);
jl_compute_field_offsets(jl_typename_type);
Expand Down
6 changes: 4 additions & 2 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ typedef struct {
} jl_weakref_t;

typedef struct {
// not first-class
JL_DATA_TYPE
jl_sym_t *name;
_Atomic(jl_value_t*) value;
_Atomic(jl_value_t*) globalref; // cached GlobalRef for this binding
Expand Down Expand Up @@ -779,6 +779,7 @@ extern JL_DLLIMPORT jl_value_t *jl_array_symbol_type JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_value_t *jl_array_int32_type JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_value_t *jl_array_uint64_type JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_datatype_t *jl_expr_type JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_datatype_t *jl_binding_type JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_datatype_t *jl_globalref_type JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_datatype_t *jl_linenumbernode_type JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_datatype_t *jl_gotonode_type JL_GLOBALLY_ROOTED;
Expand Down Expand Up @@ -1235,6 +1236,7 @@ static inline int jl_is_layout_opaque(const jl_datatype_layout_t *l) JL_NOTSAFEP
#define jl_is_ssavalue(v) jl_typeis(v,jl_ssavalue_type)
#define jl_is_slot(v) (jl_typeis(v,jl_slotnumber_type) || jl_typeis(v,jl_typedslot_type))
#define jl_is_expr(v) jl_typeis(v,jl_expr_type)
#define jl_is_binding(v) jl_typeis(v,jl_binding_type)
#define jl_is_globalref(v) jl_typeis(v,jl_globalref_type)
#define jl_is_gotonode(v) jl_typeis(v,jl_gotonode_type)
#define jl_is_gotoifnot(v) jl_typeis(v,jl_gotoifnot_type)
Expand Down Expand Up @@ -1623,7 +1625,7 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_
JL_DLLEXPORT jl_binding_t *jl_get_binding_or_error(jl_module_t *m, jl_sym_t *var);
JL_DLLEXPORT jl_binding_t *jl_get_binding_if_bound(jl_module_t *m, jl_sym_t *var);
JL_DLLEXPORT jl_value_t *jl_module_globalref(jl_module_t *m, jl_sym_t *var);
JL_DLLEXPORT jl_value_t *jl_binding_type(jl_module_t *m, jl_sym_t *var);
JL_DLLEXPORT jl_value_t *jl_get_binding_type(jl_module_t *m, jl_sym_t *var);
// get binding for assignment
JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, int alloc);
JL_DLLEXPORT jl_binding_t *jl_get_binding_wr_or_error(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var);
Expand Down
6 changes: 2 additions & 4 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -560,14 +560,11 @@ void jl_gc_run_all_finalizers(jl_task_t *ct);
void jl_release_task_stack(jl_ptls_t ptls, jl_task_t *task);
void jl_gc_add_finalizer_(jl_ptls_t ptls, void *v, void *f) JL_NOTSAFEPOINT;

JL_DLLEXPORT void jl_gc_queue_binding(jl_binding_t *bnd) JL_NOTSAFEPOINT;
void gc_setmark_buf(jl_ptls_t ptls, void *buf, uint8_t, size_t) JL_NOTSAFEPOINT;

STATIC_INLINE void jl_gc_wb_binding(jl_binding_t *bnd, void *val) JL_NOTSAFEPOINT // val isa jl_value_t*
{
if (__unlikely(jl_astaggedvalue(bnd)->bits.gc == 3 &&
(jl_astaggedvalue(val)->bits.gc & 1) == 0))
jl_gc_queue_binding(bnd);
jl_gc_wb(bnd, val);
}

STATIC_INLINE void jl_gc_wb_buf(void *parent, void *bufptr, size_t minsz) JL_NOTSAFEPOINT // parent isa jl_value_t*
Expand Down Expand Up @@ -1543,6 +1540,7 @@ extern JL_DLLEXPORT jl_sym_t *jl_return_sym;
extern JL_DLLEXPORT jl_sym_t *jl_lineinfo_sym;
extern JL_DLLEXPORT jl_sym_t *jl_lambda_sym;
extern JL_DLLEXPORT jl_sym_t *jl_assign_sym;
extern JL_DLLEXPORT jl_sym_t *jl_binding_sym;
extern JL_DLLEXPORT jl_sym_t *jl_globalref_sym;
extern JL_DLLEXPORT jl_sym_t *jl_do_sym;
extern JL_DLLEXPORT jl_sym_t *jl_method_sym;
Expand Down
1 change: 0 additions & 1 deletion src/julia_threads.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ typedef struct {
struct _bigval_t *big_objects;

// variables for tracking "remembered set"
arraylist_t rem_bindings;
arraylist_t _remset[2]; // contains jl_value_t*
// lower bound of the number of pointers inside remembered values
int remset_nptr;
Expand Down
Loading

0 comments on commit 437ebe1

Please sign in to comment.