Skip to content

Commit cfbc8fe

Browse files
committed
GC support for stack allocated objects
Only works with copy_stacks for now. The code is not used anywhere in codegen right now, it can be tested by using (:stknew typ args...) instead of :new. It is essentially the GC side of #8134 but without the global alloca stack & unmarking. Stack objects are kept marked (+young) permanently and are only scanned when coming from the owning task.
1 parent 328a752 commit cfbc8fe

File tree

8 files changed

+82
-54
lines changed

8 files changed

+82
-54
lines changed

base/inference.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,7 @@ function abstract_eval(e::ANY, vtypes, sv::StaticVarInfo)
961961
t = abstract_eval_call(e, vtypes, sv)
962962
elseif is(e.head,:null)
963963
t = Void
964-
elseif is(e.head,:new)
964+
elseif is(e.head,:new) || is(e.head,:stknew)
965965
t = abstract_eval(e.args[1], vtypes, sv)
966966
if isType(t)
967967
t = t.parameters[1]

src/alloc.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ jl_sym_t *compositetype_sym; jl_sym_t *type_goto_sym;
9999
jl_sym_t *global_sym; jl_sym_t *tuple_sym;
100100
jl_sym_t *dot_sym; jl_sym_t *newvar_sym;
101101
jl_sym_t *boundscheck_sym; jl_sym_t *copyast_sym;
102-
jl_sym_t *fastmath_sym;
102+
jl_sym_t *fastmath_sym; jl_sym_t *stknew_sym;
103103
jl_sym_t *simdloop_sym; jl_sym_t *meta_sym;
104104
jl_sym_t *arrow_sym; jl_sym_t *inert_sym;
105105
jl_sym_t *vararg_sym;

src/cgutils.cpp

+13-5
Original file line numberDiff line numberDiff line change
@@ -1790,7 +1790,7 @@ static void emit_write_barrier(jl_codectx_t* ctx, Value *parent, Value *ptr)
17901790
{
17911791
Value* parenttag = builder.CreateBitCast(emit_typeptr_addr(parent), T_psize);
17921792
Value* parent_type = builder.CreateLoad(parenttag);
1793-
Value* parent_mark_bits = builder.CreateAnd(parent_type, 1);
1793+
Value* parent_mark_bits = builder.CreateAnd(parent_type, 3);
17941794

17951795
// the branch hint does not seem to make it to the generated code
17961796
//builder.CreateCall(expect_func, {parent_marked, ConstantInt::get(T_int1, 0)});
@@ -1857,7 +1857,7 @@ static void emit_setfield(jl_datatype_t *sty, const jl_cgval_t &strct, size_t id
18571857
}
18581858
}
18591859

1860-
static jl_cgval_t emit_new_struct(jl_value_t *ty, size_t nargs, jl_value_t **args, jl_codectx_t *ctx)
1860+
static jl_cgval_t emit_new_struct(jl_value_t *ty, size_t nargs, jl_value_t **args, jl_codectx_t *ctx, bool on_stack = false)
18611861
{
18621862
assert(jl_is_datatype(ty));
18631863
assert(jl_is_leaf_type(ty));
@@ -1913,10 +1913,18 @@ static jl_cgval_t emit_new_struct(jl_value_t *ty, size_t nargs, jl_value_t **arg
19131913
if (might_need_root(args[1]) || !fval_info.isboxed)
19141914
make_gcroot(f1, ctx);
19151915
}
1916-
Value *strct = emit_allocobj(sty->size);
1916+
Value *strct;
1917+
Value *tag = literal_pointer_val((jl_value_t*)ty);
1918+
if (on_stack) {
1919+
strct = builder.CreateConstGEP1_32(builder.CreateBitCast(builder.CreateAlloca(T_int8, ConstantInt::get(T_size, sty->size + sizeof(void*))), jl_pvalue_llvmt), 1);
1920+
// set the gc bits as marked & young
1921+
tag = builder.CreateIntToPtr(builder.CreateOr(builder.CreatePtrToInt(tag, T_size), 3), jl_pvalue_llvmt);
1922+
}
1923+
else {
1924+
strct = emit_allocobj(sty->size);
1925+
}
19171926
jl_cgval_t strctinfo = mark_julia_type(strct, ty);
1918-
builder.CreateStore(literal_pointer_val((jl_value_t*)ty),
1919-
emit_typeptr_addr(strct));
1927+
builder.CreateStore(tag, emit_typeptr_addr(strct));
19201928
if (f1) {
19211929
jl_cgval_t f1info = mark_julia_type(f1, jl_any_type);
19221930
if (!jl_subtype(expr_type(args[1],ctx), jl_field_type(sty,0), 0))

src/codegen.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -3443,13 +3443,13 @@ static jl_cgval_t emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, b
34433443
jl_add_linfo_root(ctx->linfo, extype);
34443444
return mark_julia_const(extype);
34453445
}
3446-
else if (head == new_sym) {
3446+
else if (head == new_sym || head == stknew_sym) {
34473447
jl_value_t *ty = expr_type(args[0], ctx);
34483448
size_t nargs = jl_array_len(ex->args);
34493449
if (jl_is_type_type(ty) &&
34503450
jl_is_datatype(jl_tparam0(ty)) &&
34513451
jl_is_leaf_type(jl_tparam0(ty))) {
3452-
return emit_new_struct(jl_tparam0(ty),nargs,args,ctx);
3452+
return emit_new_struct(jl_tparam0(ty),nargs,args,ctx, head == stknew_sym);
34533453
}
34543454
Value *typ = boxed(emit_expr(args[0], ctx), ctx);
34553455
Value *val = emit_jlcall(jlnew_func, typ, &args[1], nargs-1, ctx);

src/gc.c

+59-40
Original file line numberDiff line numberDiff line change
@@ -516,67 +516,66 @@ static inline void objprofile_count(void* ty, int old, int sz)
516516

517517
#define inc_sat(v,s) v = (v) >= s ? s : (v)+1
518518

519-
static inline int gc_setmark_big(void *o, int mark_mode)
519+
static inline int gc_setmark_big(void *o, int bits)
520520
{
521+
int mark_mode = GC_MARKED_NOESC;
521522
#ifdef GC_VERIFY
522523
if (verifying) {
523524
_gc_setmark(o, mark_mode);
524525
return 0;
525526
}
526527
#endif
527528
bigval_t* hdr = bigval_header(o);
528-
int bits = gc_bits(o);
529-
if (bits == GC_QUEUED || bits == GC_MARKED)
530-
mark_mode = GC_MARKED;
531-
if ((mark_mode == GC_MARKED) & (bits != GC_MARKED)) {
532-
// Move hdr from big_objects list to big_objects_marked list
533-
*hdr->prev = hdr->next;
534-
if (hdr->next)
535-
hdr->next->prev = hdr->prev;
536-
hdr->next = big_objects_marked;
537-
hdr->prev = &big_objects_marked;
538-
if (big_objects_marked)
539-
big_objects_marked->prev = &hdr->next;
540-
big_objects_marked = hdr;
541-
}
542529
if (!(bits & GC_MARKED)) {
530+
if (bits == GC_QUEUED)
531+
mark_mode = GC_MARKED;
532+
if ((mark_mode == GC_MARKED) & (bits != GC_MARKED)) {
533+
// Move hdr from big_objects list to big_objects_marked list
534+
*hdr->prev = hdr->next;
535+
if (hdr->next)
536+
hdr->next->prev = hdr->prev;
537+
hdr->next = big_objects_marked;
538+
hdr->prev = &big_objects_marked;
539+
if (big_objects_marked)
540+
big_objects_marked->prev = &hdr->next;
541+
big_objects_marked = hdr;
542+
}
543543
if (mark_mode == GC_MARKED)
544544
perm_scanned_bytes += hdr->sz&~3;
545545
else
546546
scanned_bytes += hdr->sz&~3;
547547
#ifdef OBJPROFILE
548548
objprofile_count(jl_typeof(o), mark_mode == GC_MARKED, hdr->sz&~3);
549549
#endif
550+
_gc_setmark(o, mark_mode);
550551
}
551-
_gc_setmark(o, mark_mode);
552552
verify_val(jl_valueof(o));
553553
return mark_mode;
554554
}
555555

556-
static inline int gc_setmark_pool(void *o, int mark_mode)
556+
static inline int gc_setmark_pool(void *o, int bits)
557557
{
558+
int mark_mode = GC_MARKED_NOESC;
558559
#ifdef GC_VERIFY
559560
if (verifying) {
560561
_gc_setmark(o, mark_mode);
561562
return mark_mode;
562563
}
563564
#endif
564-
gcpage_t* page = page_metadata(o);
565-
int bits = gc_bits(o);
566-
if (bits == GC_QUEUED || bits == GC_MARKED) {
567-
mark_mode = GC_MARKED;
568-
}
569565
if (!(bits & GC_MARKED)) {
566+
if (bits == GC_QUEUED)
567+
mark_mode = GC_MARKED;
568+
gcpage_t* page = page_metadata(o);
570569
if (mark_mode == GC_MARKED)
571570
perm_scanned_bytes += page->osize;
572571
else
573572
scanned_bytes += page->osize;
574573
#ifdef OBJPROFILE
575574
objprofile_count(jl_typeof(o), mark_mode == GC_MARKED, page->osize);
576575
#endif
576+
_gc_setmark(o, mark_mode);
577+
page->gc_bits |= mark_mode;
577578
}
578-
_gc_setmark(o, mark_mode);
579-
page->gc_bits |= mark_mode;
580579
verify_val(jl_valueof(o));
581580
return mark_mode;
582581
}
@@ -601,14 +600,19 @@ static inline int gc_setmark(jl_value_t *v, int sz, int mark_mode)
601600
inline void gc_setmark_buf(void *o, int mark_mode)
602601
{
603602
buff_t *buf = gc_val_buf(o);
603+
int bits = gc_bits(buf);
604+
if (mark_mode == GC_MARKED && bits != GC_MARKED) {
605+
_gc_setmark(buf, GC_QUEUED);
606+
bits = GC_QUEUED;
607+
}
604608
#ifdef MEMDEBUG
605-
gc_setmark_big(buf, mark_mode);
609+
gc_setmark_big(buf, bits);
606610
return;
607611
#endif
608612
if (buf->pooled)
609-
gc_setmark_pool(buf, mark_mode);
613+
gc_setmark_pool(buf, bits);
610614
else
611-
gc_setmark_big(buf, mark_mode);
615+
gc_setmark_big(buf, bits);
612616
}
613617

614618
static NOINLINE void *malloc_page(void)
@@ -1450,16 +1454,20 @@ void jl_gc_setmark(jl_value_t *v) // TODO rename this as it is misleading now
14501454
if (!gc_marked(o)) {
14511455
// objprofile_count(jl_typeof(v), 1, 16);
14521456
#ifdef MEMDEBUG
1453-
gc_setmark_big(o, GC_MARKED_NOESC);
1457+
gc_setmark_big(o, gc_bits(o));
14541458
#else
1455-
gc_setmark_pool(o, GC_MARKED_NOESC);
1459+
gc_setmark_pool(o, gc_bits(o));
14561460
#endif
14571461
}
14581462
// perm_scanned_bytes = s;
14591463
}
1460-
1464+
static char* gc_stack_top;
1465+
static char* gc_stack_bot;
14611466
static void gc_mark_stack(jl_value_t* ta, jl_gcframe_t *s, ptrint_t offset, int d)
14621467
{
1468+
jl_task_t *task = (jl_task_t*)ta;
1469+
char *stkbuf = task == jl_current_task ? gc_stack_top : task->stkbuf;
1470+
char *stkend = task == jl_current_task ? gc_stack_bot : stkbuf + task->ssize;
14631471
while (s != NULL) {
14641472
s = (jl_gcframe_t*)((char*)s + offset);
14651473
jl_value_t ***rts = (jl_value_t***)(((void**)s)+2);
@@ -1473,9 +1481,17 @@ static void gc_mark_stack(jl_value_t* ta, jl_gcframe_t *s, ptrint_t offset, int
14731481
}
14741482
else {
14751483
for(size_t i=0; i < nr; i++) {
1476-
if (rts[i] != NULL) {
1484+
void *v = rts[i];
1485+
if (v != NULL) {
14771486
verify_parent2("task", ta, &rts[i], "stack(%d)", (int)i);
1478-
gc_push_root(rts[i], d);
1487+
if (stkbuf <= (char*)v && (char*)v <= stkend) {
1488+
// if v is on the stack it is kept permanently marked
1489+
// but we still need to scan it once
1490+
push_root(v, d, gc_bits(jl_astaggedvalue(v)));
1491+
}
1492+
else {
1493+
gc_push_root(v, d);
1494+
}
14791495
}
14801496
}
14811497
}
@@ -1576,12 +1592,12 @@ static int push_root(jl_value_t *v, int d, int bits)
15761592
int refyoung = 0;
15771593

15781594
if (vt == (jl_value_t*)jl_weakref_type) {
1579-
bits = gc_setmark(v, sizeof(jl_weakref_t), GC_MARKED_NOESC);
1595+
bits = gc_setmark(v, sizeof(jl_weakref_t), bits);
15801596
goto ret;
15811597
}
15821598
if ((jl_is_datatype(vt) && ((jl_datatype_t*)vt)->pointerfree)) {
15831599
int sz = jl_datatype_size(vt);
1584-
bits = gc_setmark(v, sz, GC_MARKED_NOESC);
1600+
bits = gc_setmark(v, sz, bits);
15851601
goto ret;
15861602
}
15871603
#define MARK(v, s) do { \
@@ -1597,7 +1613,7 @@ static int push_root(jl_value_t *v, int d, int bits)
15971613
// some values have special representations
15981614
if (vt == (jl_value_t*)jl_simplevector_type) {
15991615
size_t l = jl_svec_len(v);
1600-
MARK(v, bits = gc_setmark(v, l*sizeof(void*) + sizeof(jl_svec_t), GC_MARKED_NOESC));
1616+
MARK(v, bits = gc_setmark(v, l*sizeof(void*) + sizeof(jl_svec_t), bits));
16011617
jl_value_t **data = ((jl_svec_t*)v)->data;
16021618
for(size_t i=0; i < l; i++) {
16031619
jl_value_t *elt = data[i];
@@ -1618,7 +1634,7 @@ static int push_root(jl_value_t *v, int d, int bits)
16181634
#define _gc_setmark_pool gc_setmark_pool
16191635
#endif
16201636
MARK(a,
1621-
bits = _gc_setmark_pool(o, GC_MARKED_NOESC);
1637+
bits = _gc_setmark_pool(o, bits);
16221638
if (a->how == 2 && todo) {
16231639
objprofile_count(MATY, gc_bits(o) == GC_MARKED, array_nbytes(a));
16241640
if (gc_bits(o) == GC_MARKED)
@@ -1628,7 +1644,7 @@ static int push_root(jl_value_t *v, int d, int bits)
16281644
});
16291645
else
16301646
MARK(a,
1631-
bits = gc_setmark_big(o, GC_MARKED_NOESC);
1647+
bits = gc_setmark_big(o, bits);
16321648
if (a->how == 2 && todo) {
16331649
objprofile_count(MATY, gc_bits(o) == GC_MARKED, array_nbytes(a));
16341650
if (gc_bits(o) == GC_MARKED)
@@ -1670,11 +1686,11 @@ static int push_root(jl_value_t *v, int d, int bits)
16701686
}
16711687
}
16721688
else if (vt == (jl_value_t*)jl_module_type) {
1673-
MARK(v, bits = gc_setmark(v, sizeof(jl_module_t), GC_MARKED_NOESC));
1689+
MARK(v, bits = gc_setmark(v, sizeof(jl_module_t), bits));
16741690
refyoung |= gc_mark_module((jl_module_t*)v, d);
16751691
}
16761692
else if (vt == (jl_value_t*)jl_task_type) {
1677-
MARK(v, bits = gc_setmark(v, sizeof(jl_task_t), GC_MARKED_NOESC));
1693+
MARK(v, bits = gc_setmark(v, sizeof(jl_task_t), bits));
16781694
gc_mark_task((jl_task_t*)v, d);
16791695
// tasks should always be remarked since we do not trigger the write barrier
16801696
// for stores to stack slots
@@ -1697,7 +1713,7 @@ static int push_root(jl_value_t *v, int d, int bits)
16971713
dtsz = NWORDS(sizeof(jl_datatype_t) + jl_datatype_nfields(v)*sizeof(jl_fielddesc_t))*sizeof(void*);
16981714
else
16991715
dtsz = jl_datatype_size(dt);
1700-
MARK(v, bits = gc_setmark(v, dtsz, GC_MARKED_NOESC));
1716+
MARK(v, bits = gc_setmark(v, dtsz, bits));
17011717
int nf = (int)jl_datatype_nfields(dt);
17021718
// TODO check if there is a perf improvement for objects with a lot of fields
17031719
// int fdsz = sizeof(void*)*nf;
@@ -1956,6 +1972,7 @@ void jl_gc_collect(int full)
19561972
JL_SIGATOMIC_BEGIN();
19571973
jl_in_gc = 1;
19581974
uint64_t t0 = jl_hrtime();
1975+
gc_stack_top = (char*)&t0;
19591976
int recollect = 0;
19601977
#if defined(GC_TIME)
19611978
int wb_activations = mark_sp - saved_mark_sp;
@@ -2366,6 +2383,8 @@ void jl_gc_init(void)
23662383
if (maxmem > max_collect_interval)
23672384
max_collect_interval = maxmem;
23682385
#endif
2386+
char _dummy;
2387+
gc_stack_bot = &_dummy;
23692388
}
23702389

23712390
// GC summary stats

src/interpreter.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl, size_t ng
244244
JL_GC_POP();
245245
return rhs;
246246
}
247-
else if (ex->head == new_sym) {
247+
else if (ex->head == new_sym || ex->head == stknew_sym) {
248248
jl_value_t *thetype = eval(args[0], locals, nl, ngensym);
249249
jl_value_t *v=NULL;
250250
JL_GC_PUSH2(&thetype, &v);

src/jltypes.c

+1
Original file line numberDiff line numberDiff line change
@@ -3534,6 +3534,7 @@ void jl_init_types(void)
35343534
dot_sym = jl_symbol(".");
35353535
boundscheck_sym = jl_symbol("boundscheck");
35363536
fastmath_sym = jl_symbol("fastmath");
3537+
stknew_sym = jl_symbol("stknew");
35373538
newvar_sym = jl_symbol("newvar");
35383539
copyast_sym = jl_symbol("copyast");
35393540
simdloop_sym = jl_symbol("simdloop");

src/julia.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ extern jl_sym_t *abstracttype_sym; extern jl_sym_t *bitstype_sym;
486486
extern jl_sym_t *compositetype_sym; extern jl_sym_t *type_goto_sym;
487487
extern jl_sym_t *global_sym; extern jl_sym_t *tuple_sym;
488488
extern jl_sym_t *boundscheck_sym; extern jl_sym_t *copyast_sym;
489-
extern jl_sym_t *fastmath_sym;
489+
extern jl_sym_t *fastmath_sym; extern jl_sym_t *stknew_sym;
490490
extern jl_sym_t *simdloop_sym; extern jl_sym_t *meta_sym;
491491
extern jl_sym_t *arrow_sym; extern jl_sym_t *inert_sym;
492492

@@ -580,13 +580,13 @@ void gc_setmark_buf(void *buf, int);
580580

581581
static inline void jl_gc_wb_binding(jl_binding_t *bnd, void *val) // val isa jl_value_t*
582582
{
583-
if (__unlikely((*((uintptr_t*)bnd-1) & 1) == 1 && (*(uintptr_t*)jl_astaggedvalue(val) & 1) == 0))
583+
if (__unlikely((*((uintptr_t*)bnd-1) & 3) == 1 && (*(uintptr_t*)jl_astaggedvalue(val) & 1) == 0))
584584
gc_queue_binding(bnd);
585585
}
586586

587587
static inline void jl_gc_wb(void *parent, void *ptr) // parent and ptr isa jl_value_t*
588588
{
589-
if (__unlikely((*((uintptr_t*)jl_astaggedvalue(parent)) & 1) == 1 &&
589+
if (__unlikely((*((uintptr_t*)jl_astaggedvalue(parent)) & 3) == 1 &&
590590
(*((uintptr_t*)jl_astaggedvalue(ptr)) & 1) == 0))
591591
jl_gc_queue_root((jl_value_t*)parent);
592592
}
@@ -602,7 +602,7 @@ static inline void jl_gc_wb_buf(void *parent, void *bufptr) // parent isa jl_val
602602
static inline void jl_gc_wb_back(void *ptr) // ptr isa jl_value_t*
603603
{
604604
// if ptr is marked
605-
if(__unlikely((*((uintptr_t*)jl_astaggedvalue(ptr)) & 1) == 1)) {
605+
if(__unlikely((*((uintptr_t*)jl_astaggedvalue(ptr)) & 3) == 1)) {
606606
jl_gc_queue_root((jl_value_t*)ptr);
607607
}
608608
}

0 commit comments

Comments
 (0)