Skip to content

Commit a3fd4d3

Browse files
committed
Moving write barrier away from genericmemory.c
1 parent a3e4f0d commit a3fd4d3

File tree

3 files changed

+106
-74
lines changed

3 files changed

+106
-74
lines changed

src/gc-interface.h

+15
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#define JL_GC_INTERFACE_H
99

1010
#include "dtypes.h"
11+
#include "julia_atomics.h"
1112

1213
#ifdef __cplusplus
1314
extern "C" {
@@ -17,6 +18,7 @@ struct _jl_tls_states_t;
1718
struct _jl_value_t;
1819
struct _jl_weakref_t;
1920
struct _jl_datatype_t;
21+
struct _jl_genericmemory_t;
2022

2123
// ========================================================================= //
2224
// GC Metrics
@@ -250,6 +252,19 @@ STATIC_INLINE void jl_gc_wb_knownold(const void *parent, const void *ptr) JL_NOT
250252
STATIC_INLINE void jl_gc_multi_wb(const void *parent,
251253
const struct _jl_value_t *ptr) JL_NOTSAFEPOINT;
252254

255+
// Write-barrier function that must be used after copying fields of elements of genericmemory objects
256+
// into another. It should be semantically equivalent to triggering multiple write barriers – one
257+
// per field of the object being copied, but may be special-cased for performance reasons.
258+
STATIC_INLINE void jl_gc_wb_genericmemory_copy_ptr(const struct _jl_value_t *owner, struct _jl_genericmemory_t *src, char* src_p,
259+
size_t n, struct _jl_datatype_t *dt) JL_NOTSAFEPOINT;
260+
261+
// Similar to jl_gc_wb_genericmemory_copy but must be used when copying *boxed* elements of a genericmemory
262+
// object. Note that this barrier also performs the copying unlike jl_gc_wb_genericmemory_copy_ptr.
263+
// The parameters src_p, dest_p and n will be modified and will contain information about
264+
// the *uncopied* data after performing this barrier, and will be copied using memmove_refs.
265+
STATIC_INLINE void jl_gc_wb_genericmemory_copy_boxed(const struct _jl_value_t *owner, _Atomic(void*) * dest_p,
266+
struct _jl_genericmemory_t *src, _Atomic(void*) * src_p,
267+
size_t* n) JL_NOTSAFEPOINT;
253268
#ifdef __cplusplus
254269
}
255270
#endif

src/genericmemory.c

+2-41
Original file line numberDiff line numberDiff line change
@@ -235,36 +235,7 @@ JL_DLLEXPORT void jl_genericmemory_copyto(jl_genericmemory_t *dest, char* destda
235235
_Atomic(void*) * dest_p = (_Atomic(void*)*)destdata;
236236
_Atomic(void*) * src_p = (_Atomic(void*)*)srcdata;
237237
jl_value_t *owner = jl_genericmemory_owner(dest);
238-
if (__unlikely(jl_astaggedvalue(owner)->bits.gc == GC_OLD_MARKED)) {
239-
jl_value_t *src_owner = jl_genericmemory_owner(src);
240-
ssize_t done = 0;
241-
if (jl_astaggedvalue(src_owner)->bits.gc != GC_OLD_MARKED) {
242-
if (dest_p < src_p || dest_p > src_p + n) {
243-
for (; done < n; done++) { // copy forwards
244-
void *val = jl_atomic_load_relaxed(src_p + done);
245-
jl_atomic_store_release(dest_p + done, val);
246-
// `val` is young or old-unmarked
247-
if (val && !(jl_astaggedvalue(val)->bits.gc & GC_MARKED)) {
248-
jl_gc_queue_root(owner);
249-
break;
250-
}
251-
}
252-
src_p += done;
253-
dest_p += done;
254-
} else {
255-
for (; done < n; done++) { // copy backwards
256-
void *val = jl_atomic_load_relaxed(src_p + n - done - 1);
257-
jl_atomic_store_release(dest_p + n - done - 1, val);
258-
// `val` is young or old-unmarked
259-
if (val && !(jl_astaggedvalue(val)->bits.gc & GC_MARKED)) {
260-
jl_gc_queue_root(owner);
261-
break;
262-
}
263-
}
264-
}
265-
n -= done;
266-
}
267-
}
238+
jl_gc_wb_genericmemory_copy_boxed(owner, dest_p, src, src_p, &n);
268239
return memmove_refs(dest_p, src_p, n);
269240
}
270241
size_t elsz = layout->size;
@@ -280,17 +251,7 @@ JL_DLLEXPORT void jl_genericmemory_copyto(jl_genericmemory_t *dest, char* destda
280251
if (layout->first_ptr != -1) {
281252
memmove_refs((_Atomic(void*)*)destdata, (_Atomic(void*)*)srcdata, n * elsz / sizeof(void*));
282253
jl_value_t *owner = jl_genericmemory_owner(dest);
283-
if (__unlikely(jl_astaggedvalue(owner)->bits.gc == GC_OLD_MARKED)) {
284-
jl_value_t *src_owner = jl_genericmemory_owner(src);
285-
if (jl_astaggedvalue(src_owner)->bits.gc != GC_OLD_MARKED) {
286-
dt = (jl_datatype_t*)jl_tparam1(dt);
287-
for (size_t done = 0; done < n; done++) { // copy forwards
288-
char* s = (char*)src_p+done*elsz;
289-
if (*((jl_value_t**)s+layout->first_ptr) != NULL)
290-
jl_gc_queue_multiroot(owner, s, dt);
291-
}
292-
}
293-
}
254+
jl_gc_wb_genericmemory_copy_ptr(owner, src, src_p, n, dt);
294255
}
295256
else {
296257
memmove(destdata, srcdata, n * elsz);

src/julia.h

+89-33
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ typedef struct {
162162
// jl_value_t *data[];
163163
} jl_svec_t;
164164

165-
JL_EXTENSION typedef struct {
165+
JL_EXTENSION typedef struct _jl_genericmemory_t {
166166
JL_DATA_TYPE
167167
size_t length;
168168
void *ptr;
@@ -1137,38 +1137,6 @@ JL_DLLEXPORT void jl_free_stack(void *stkbuf, size_t bufsz);
11371137
// thread-local allocator of the current thread.
11381138
JL_DLLEXPORT jl_weakref_t *jl_gc_new_weakref(jl_value_t *value);
11391139

1140-
// GC write barriers
1141-
1142-
STATIC_INLINE void jl_gc_wb(const void *parent, const void *ptr) JL_NOTSAFEPOINT
1143-
{
1144-
// parent and ptr isa jl_value_t*
1145-
if (__unlikely(jl_astaggedvalue(parent)->bits.gc == 3 /* GC_OLD_MARKED */ && // parent is old and not in remset
1146-
(jl_astaggedvalue(ptr)->bits.gc & 1 /* GC_MARKED */) == 0)) // ptr is young
1147-
jl_gc_queue_root((jl_value_t*)parent);
1148-
}
1149-
1150-
STATIC_INLINE void jl_gc_wb_back(const void *ptr) JL_NOTSAFEPOINT // ptr isa jl_value_t*
1151-
{
1152-
// if ptr is old
1153-
if (__unlikely(jl_astaggedvalue(ptr)->bits.gc == 3 /* GC_OLD_MARKED */)) {
1154-
jl_gc_queue_root((jl_value_t*)ptr);
1155-
}
1156-
}
1157-
1158-
STATIC_INLINE void jl_gc_multi_wb(const void *parent, const jl_value_t *ptr) JL_NOTSAFEPOINT
1159-
{
1160-
// 3 == GC_OLD_MARKED
1161-
// ptr is an immutable object
1162-
if (__likely(jl_astaggedvalue(parent)->bits.gc != 3))
1163-
return; // parent is young or in remset
1164-
if (__likely(jl_astaggedvalue(ptr)->bits.gc == 3))
1165-
return; // ptr is old and not in remset (thus it does not point to young)
1166-
jl_datatype_t *dt = (jl_datatype_t*)jl_typeof(ptr);
1167-
const jl_datatype_layout_t *ly = dt->layout;
1168-
if (ly->npointers)
1169-
jl_gc_queue_multiroot((jl_value_t*)parent, ptr, dt);
1170-
}
1171-
11721140
JL_DLLEXPORT void jl_gc_safepoint(void);
11731141
JL_DLLEXPORT int jl_safepoint_suspend_thread(int tid, int waitstate);
11741142
JL_DLLEXPORT void jl_safepoint_suspend_all_threads(struct _jl_task_t *ct);
@@ -1287,6 +1255,94 @@ STATIC_INLINE jl_value_t *jl_genericmemory_ptr_set(
12871255
}
12881256
#endif
12891257

1258+
// GC write barriers
1259+
1260+
STATIC_INLINE void jl_gc_wb(const void *parent, const void *ptr) JL_NOTSAFEPOINT
1261+
{
1262+
// parent and ptr isa jl_value_t*
1263+
if (__unlikely(jl_astaggedvalue(parent)->bits.gc == 3 /* GC_OLD_MARKED */ && // parent is old and not in remset
1264+
(jl_astaggedvalue(ptr)->bits.gc & 1 /* GC_MARKED */) == 0)) // ptr is young
1265+
jl_gc_queue_root((jl_value_t*)parent);
1266+
}
1267+
1268+
STATIC_INLINE void jl_gc_wb_back(const void *ptr) JL_NOTSAFEPOINT // ptr isa jl_value_t*
1269+
{
1270+
// if ptr is old
1271+
if (__unlikely(jl_astaggedvalue(ptr)->bits.gc == 3 /* GC_OLD_MARKED */)) {
1272+
jl_gc_queue_root((jl_value_t*)ptr);
1273+
}
1274+
}
1275+
1276+
STATIC_INLINE void jl_gc_multi_wb(const void *parent, const jl_value_t *ptr) JL_NOTSAFEPOINT
1277+
{
1278+
// 3 == GC_OLD_MARKED
1279+
// ptr is an immutable object
1280+
if (__likely(jl_astaggedvalue(parent)->bits.gc != 3))
1281+
return; // parent is young or in remset
1282+
if (__likely(jl_astaggedvalue(ptr)->bits.gc == 3))
1283+
return; // ptr is old and not in remset (thus it does not point to young)
1284+
jl_datatype_t *dt = (jl_datatype_t*)jl_typeof(ptr);
1285+
const jl_datatype_layout_t *ly = dt->layout;
1286+
if (ly->npointers)
1287+
jl_gc_queue_multiroot((jl_value_t*)parent, ptr, dt);
1288+
}
1289+
1290+
STATIC_INLINE jl_value_t *jl_genericmemory_owner(jl_genericmemory_t *m JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT;
1291+
1292+
STATIC_INLINE void jl_gc_wb_genericmemory_copy_boxed(const jl_value_t *dest_owner, _Atomic(void*) * dest_p,
1293+
jl_genericmemory_t *src, _Atomic(void*) * src_p,
1294+
size_t* n) JL_NOTSAFEPOINT
1295+
{
1296+
if (__unlikely(jl_astaggedvalue(dest_owner)->bits.gc == 3 /* GC_OLD_MARKED */ )) {
1297+
jl_value_t *src_owner = jl_genericmemory_owner(src);
1298+
size_t done = 0;
1299+
if (jl_astaggedvalue(src_owner)->bits.gc != 3 /* GC_OLD_MARKED */) {
1300+
if (dest_p < src_p || dest_p > src_p + (*n)) {
1301+
for (; done < (*n); done++) { // copy forwards
1302+
void *val = jl_atomic_load_relaxed(src_p + done);
1303+
jl_atomic_store_release(dest_p + done, val);
1304+
// `val` is young or old-unmarked
1305+
if (val && !(jl_astaggedvalue(val)->bits.gc & 1 /* GC_MARKED */)) {
1306+
jl_gc_queue_root(dest_owner);
1307+
break;
1308+
}
1309+
}
1310+
src_p += done;
1311+
dest_p += done;
1312+
}
1313+
else {
1314+
for (; done < (*n); done++) { // copy backwards
1315+
void *val = jl_atomic_load_relaxed(src_p + (*n) - done - 1);
1316+
jl_atomic_store_release(dest_p + (*n) - done - 1, val);
1317+
// `val` is young or old-unmarked
1318+
if (val && !(jl_astaggedvalue(val)->bits.gc & 1 /* GC_MARKED */)) {
1319+
jl_gc_queue_root(dest_owner);
1320+
break;
1321+
}
1322+
}
1323+
}
1324+
(*n) -= done;
1325+
}
1326+
}
1327+
}
1328+
1329+
STATIC_INLINE void jl_gc_wb_genericmemory_copy_ptr(const jl_value_t *owner, jl_genericmemory_t *src, char* src_p,
1330+
size_t n, jl_datatype_t *dt) JL_NOTSAFEPOINT
1331+
{
1332+
if (__unlikely(jl_astaggedvalue(owner)->bits.gc == 3 /* GC_OLD_MARKED */)) {
1333+
jl_value_t *src_owner = jl_genericmemory_owner(src);
1334+
size_t elsz = dt->layout->size;
1335+
if (jl_astaggedvalue(src_owner)->bits.gc != 3 /* GC_OLD_MARKED */) {
1336+
dt = (jl_datatype_t*)jl_tparam1(dt);
1337+
for (size_t done = 0; done < n; done++) { // copy forwards
1338+
char* s = (char*)src_p+done*elsz;
1339+
if (*((jl_value_t**)s+dt->layout->first_ptr) != NULL)
1340+
jl_gc_queue_multiroot(owner, s, dt);
1341+
}
1342+
}
1343+
}
1344+
}
1345+
12901346
STATIC_INLINE uint8_t jl_memory_uint8_ref(void *m, size_t i) JL_NOTSAFEPOINT
12911347
{
12921348
jl_genericmemory_t *m_ = (jl_genericmemory_t*)m;

0 commit comments

Comments
 (0)