// Unsafe, assume inbounds and that dest and src have the same eltype JL_DLLEXPORT void jl_array_ptr_copy(jl_array_t *dest, void **dest_p, jl_array_t *src, void **src_p, ssize_t n) { assert(dest->flags.ptrarray && src->flags.ptrarray); jl_value_t *owner = jl_array_owner(dest); // Destination is old and doesn't refer to any young object if (__unlikely(jl_astaggedvalue(owner)->bits.gc == GC_OLD_MARKED)) { jl_value_t *src_owner = jl_array_owner(src); // Source is young or being promoted or might refer to young objects // (i.e. source is not an old object that doesn't have wb triggered) if (jl_astaggedvalue(src_owner)->bits.gc != GC_OLD_MARKED) { ssize_t done; if (dest_p < src_p || dest_p > src_p + n) { done = jl_array_ptr_copy_forward(owner, src_p, dest_p, n); dest_p += done; src_p += done; } else { done = jl_array_ptr_copy_backward(owner, src_p, dest_p, n); } n -= done; } } memmove(dest_p, src_p, n * sizeof(void*)); }
static NOINLINE ssize_t jl_array_ptr_copy_backward(jl_value_t *owner, void **src_p, void **dest_p, ssize_t n) { for (ssize_t i = 0; i < n; i++) { void *val = src_p[n - i - 1]; dest_p[n - i - 1] = val; // `val` is young or old-unmarked if (val && !(jl_astaggedvalue(val)->bits.gc & GC_MARKED)) { jl_gc_queue_root(owner); return i; } } return n; }
// Create function versions of some useful macros JL_DLLEXPORT jl_taggedvalue_t *(jl_astaggedvalue)(jl_value_t *v) { return jl_astaggedvalue(v); }