Skip to content

Commit

Permalink
More GC annotation in C code (#37272)
Browse files Browse the repository at this point in the history
* Mark more functions as not safepoints
* Mark more error throwing function as having callee rooted arguments
* Make runtime symbol lookup function not-safepoint-or-throw
* Use `jl_field_type_concrete` in more places where the input argument is known concrete (return from `jl_typeof`)
* Use `jl_safe_printf` in `jl_checked_assignment` to print constant overwrite warning
  to make it more clear to the analyser that the printing does not allocate.
  • Loading branch information
yuyichao committed Aug 31, 2020
1 parent 2154472 commit 0a77e07
Show file tree
Hide file tree
Showing 17 changed files with 114 additions and 93 deletions.
8 changes: 4 additions & 4 deletions src/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -1196,7 +1196,7 @@ JL_DLLEXPORT jl_array_t *jl_array_copy(jl_array_t *ary)
// we can finish by using `memmove`.
static NOINLINE ssize_t jl_array_ptr_copy_forward(jl_value_t *owner,
void **src_p, void **dest_p,
ssize_t n)
ssize_t n) JL_NOTSAFEPOINT
{
for (ssize_t i = 0; i < n; i++) {
void *val = jl_atomic_load_relaxed(src_p + i);
Expand All @@ -1212,7 +1212,7 @@ static NOINLINE ssize_t jl_array_ptr_copy_forward(jl_value_t *owner,

static NOINLINE ssize_t jl_array_ptr_copy_backward(jl_value_t *owner,
void **src_p, void **dest_p,
ssize_t n)
ssize_t n) JL_NOTSAFEPOINT
{
for (ssize_t i = 0; i < n; i++) {
void *val = jl_atomic_load_relaxed(src_p + n - i - 1);
Expand All @@ -1228,7 +1228,7 @@ static NOINLINE ssize_t jl_array_ptr_copy_backward(jl_value_t *owner,

// 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)
jl_array_t *src, void **src_p, ssize_t n) JL_NOTSAFEPOINT
{
assert(dest->flags.ptrarray && src->flags.ptrarray);
jl_value_t *owner = jl_array_owner(dest);
Expand Down Expand Up @@ -1274,7 +1274,7 @@ JL_DLLEXPORT void jl_array_ptr_1d_append(jl_array_t *a, jl_array_t *a2)
}
}

JL_DLLEXPORT jl_value_t *(jl_array_data_owner)(jl_array_t *a)
JL_DLLEXPORT jl_value_t *(jl_array_data_owner)(jl_array_t *a) JL_NOTSAFEPOINT
{
return jl_array_data_owner(a);
}
Expand Down
2 changes: 1 addition & 1 deletion src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,7 @@ JL_DLLEXPORT int jl_operator_precedence(char *sym)
return res;
}

int jl_has_meta(jl_array_t *body, jl_sym_t *sym)
int jl_has_meta(jl_array_t *body, jl_sym_t *sym) JL_NOTSAFEPOINT
{
size_t i, l = jl_array_len(body);
for (i = 0; i < l; i++) {
Expand Down
10 changes: 4 additions & 6 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -789,12 +789,10 @@ JL_CALLABLE(jl_f_setfield)
{
JL_NARGS(setfield!, 3, 3);
jl_value_t *v = args[0];
jl_value_t *vt = (jl_value_t*)jl_typeof(v);
if (vt == (jl_value_t*)jl_module_type)
jl_datatype_t *st = (jl_datatype_t*)jl_typeof(v);
assert(jl_is_datatype(st));
if (st == jl_module_type)
jl_error("cannot assign variables in other modules");
if (!jl_is_datatype(vt))
jl_type_error("setfield!", (jl_value_t*)jl_datatype_type, v);
jl_datatype_t *st = (jl_datatype_t*)vt;
if (!st->mutabl)
jl_errorf("setfield! immutable struct of type %s cannot be changed", jl_symbol_name(st->name->name));
size_t idx;
Expand All @@ -807,7 +805,7 @@ JL_CALLABLE(jl_f_setfield)
JL_TYPECHK(setfield!, symbol, args[1]);
idx = jl_field_index(st, (jl_sym_t*)args[1], 1);
}
jl_value_t *ft = jl_field_type(st, idx);
jl_value_t *ft = jl_field_type_concrete(st, idx);
if (!jl_isa(args[2], ft)) {
jl_type_error("setfield!", ft, args[2]);
}
Expand Down
20 changes: 10 additions & 10 deletions src/datatype.c
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,7 @@ JL_DLLEXPORT jl_value_t *jl_typemax_uint(jl_value_t *bt)
return v;
}

void jl_assign_bits(void *dest, jl_value_t *bits)
void jl_assign_bits(void *dest, jl_value_t *bits) JL_NOTSAFEPOINT
{
// bits must be a heap box.
size_t nb = jl_datatype_size(jl_typeof(bits));
Expand Down Expand Up @@ -907,7 +907,7 @@ JL_DLLEXPORT jl_value_t *jl_new_structv(jl_datatype_t *type, jl_value_t **args,
if (type->ninitialized > na || na > jl_datatype_nfields(type))
jl_error("invalid struct allocation");
for (size_t i = 0; i < na; i++) {
jl_value_t *ft = jl_field_type(type, i);
jl_value_t *ft = jl_field_type_concrete(type, i);
if (!jl_isa(args[i], ft))
jl_type_error("new", ft, args[i]);
}
Expand Down Expand Up @@ -936,8 +936,8 @@ JL_DLLEXPORT jl_value_t *jl_new_structt(jl_datatype_t *type, jl_value_t *tup)
if (type->instance != NULL) {
jl_datatype_t *tupt = (jl_datatype_t*)jl_typeof(tup);
for (size_t i = 0; i < nargs; i++) {
jl_value_t *ft = jl_field_type(type, i);
jl_value_t *et = jl_field_type(tupt, i);
jl_value_t *ft = jl_field_type_concrete(type, i);
jl_value_t *et = jl_field_type_concrete(tupt, i);
assert(jl_is_concrete_type(ft) && jl_is_concrete_type(et));
if (et != ft)
jl_type_error("new", ft, jl_get_nth_field(tup, i));
Expand All @@ -954,7 +954,7 @@ JL_DLLEXPORT jl_value_t *jl_new_structt(jl_datatype_t *type, jl_value_t *tup)
memset(jl_data_ptr(jv), 0, jl_datatype_size(type));
}
for (size_t i = 0; i < nargs; i++) {
jl_value_t *ft = jl_field_type(type, i);
jl_value_t *ft = jl_field_type_concrete(type, i);
fi = jl_get_nth_field(tup, i);
if (!jl_isa(fi, ft))
jl_type_error("new", ft, fi);
Expand Down Expand Up @@ -1015,7 +1015,7 @@ JL_DLLEXPORT jl_value_t *jl_get_nth_field(jl_value_t *v, size_t i)
if (jl_field_isptr(st, i)) {
return jl_atomic_load_relaxed((jl_value_t**)((char*)v + offs));
}
jl_value_t *ty = jl_field_type(st, i);
jl_value_t *ty = jl_field_type_concrete(st, i);
if (jl_is_uniontype(ty)) {
uint8_t sel = ((uint8_t*)v)[offs + jl_field_size(st, i) - 1];
ty = jl_nth_union_component(ty, sel);
Expand Down Expand Up @@ -1046,7 +1046,7 @@ JL_DLLEXPORT jl_value_t *jl_get_nth_field_checked(jl_value_t *v, size_t i)
jl_throw(jl_undefref_exception);
return fval;
}
jl_value_t *ty = jl_field_type(st, i);
jl_value_t *ty = jl_field_type_concrete(st, i);
if (jl_is_uniontype(ty)) {
size_t fsz = jl_field_size(st, i);
uint8_t sel = ((uint8_t*)v)[offs + fsz - 1];
Expand Down Expand Up @@ -1084,7 +1084,7 @@ void set_nth_field(jl_datatype_t *st, void *v, size_t i, jl_value_t *rhs) JL_NOT
}
}

JL_DLLEXPORT int jl_field_isdefined(jl_value_t *v, size_t i)
JL_DLLEXPORT int jl_field_isdefined(jl_value_t *v, size_t i) JL_NOTSAFEPOINT
{
jl_datatype_t *st = (jl_datatype_t*)jl_typeof(v);
size_t offs = jl_field_offset(st, i);
Expand All @@ -1093,14 +1093,14 @@ JL_DLLEXPORT int jl_field_isdefined(jl_value_t *v, size_t i)
jl_value_t *fval = jl_atomic_load_relaxed((jl_value_t**)fld);
return fval != NULL;
}
jl_datatype_t *ft = (jl_datatype_t*)jl_field_type(st, i);
jl_datatype_t *ft = (jl_datatype_t*)jl_field_type_concrete(st, i);
if (jl_is_datatype(ft) && ft->layout->first_ptr >= 0) {
return ((jl_value_t**)fld)[ft->layout->first_ptr] != NULL;
}
return 1;
}

JL_DLLEXPORT size_t jl_get_field_offset(jl_datatype_t *ty, int field)
JL_DLLEXPORT size_t jl_get_field_offset(jl_datatype_t *ty, int field) JL_NOTSAFEPOINT
{
if (ty->layout == NULL || field > jl_datatype_nfields(ty) || field < 1)
jl_bounds_error_int((jl_value_t*)ty, field);
Expand Down
34 changes: 26 additions & 8 deletions src/dlload.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ static char const *const extensions[] = { "", ".so" };
#endif
#define N_EXTENSIONS (sizeof(extensions) / sizeof(char*))

static int endswith_extension(const char *path)
static int endswith_extension(const char *path) JL_NOTSAFEPOINT
{
if (!path)
return 0;
Expand Down Expand Up @@ -62,7 +62,7 @@ static int endswith_extension(const char *path)
#define JL_RTLD(flags, FLAG) (flags & JL_RTLD_ ## FLAG ? RTLD_ ## FLAG : 0)

#ifdef _OS_WINDOWS_
static void win32_formatmessage(DWORD code, char *reason, int len)
static void win32_formatmessage(DWORD code, char *reason, int len) JL_NOTSAFEPOINT
{
DWORD res;
LPWSTR errmsg;
Expand All @@ -89,7 +89,7 @@ static void win32_formatmessage(DWORD code, char *reason, int len)
}
#endif

JL_DLLEXPORT void *jl_dlopen(const char *filename, unsigned flags)
JL_DLLEXPORT void *jl_dlopen(const char *filename, unsigned flags) JL_NOTSAFEPOINT
{
#if defined(_OS_WINDOWS_)
size_t len = MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
Expand Down Expand Up @@ -122,7 +122,7 @@ JL_DLLEXPORT void *jl_dlopen(const char *filename, unsigned flags)
#endif
}

JL_DLLEXPORT int jl_dlclose(void *handle)
JL_DLLEXPORT int jl_dlclose(void *handle) JL_NOTSAFEPOINT
{
#ifdef _OS_WINDOWS_
if (!handle) return -1;
Expand All @@ -134,7 +134,7 @@ JL_DLLEXPORT int jl_dlclose(void *handle)
#endif
}

JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags, int throw_err)
JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags, int throw_err) JL_NOTSAFEPOINT // (or throw)
{
char path[PATHBUF], relocated[PATHBUF];
int i;
Expand All @@ -156,12 +156,21 @@ JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags,
if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCWSTR)(uintptr_t)(&jl_load_dynamic_library),
(HMODULE*)&handle)) {
#ifndef __clang_analyzer__
// Hide the error throwing from the analyser since there isn't a way to express
// "safepoint only when throwing error" currently.
jl_error("could not load base module");
#endif
}
#else
Dl_info info;
if (!dladdr((void*)(uintptr_t)&jl_load_dynamic_library, &info) || !info.dli_fname)
if (!dladdr((void*)(uintptr_t)&jl_load_dynamic_library, &info) || !info.dli_fname) {
#ifndef __clang_analyzer__
// Hide the error throwing from the analyser since there isn't a way to express
// "safepoint only when throwing error" currently.
jl_error("could not load base module");
#endif
}
handle = dlopen(info.dli_fname, RTLD_NOW);
#endif
goto done;
Expand All @@ -178,7 +187,8 @@ JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags,
such as Windows, so we emulate them here.
*/
if (!abspath && jl_base_module != NULL) {
jl_array_t *DL_LOAD_PATH = (jl_array_t*)jl_get_global(jl_base_module, jl_symbol("DL_LOAD_PATH"));
jl_binding_t *b = jl_get_module_binding(jl_base_module, jl_symbol("DL_LOAD_PATH"));
jl_array_t *DL_LOAD_PATH = (jl_array_t*)(b ? b->value : NULL);
if (DL_LOAD_PATH != NULL) {
size_t j;
for (j = 0; j < jl_array_len(DL_LOAD_PATH); j++) {
Expand Down Expand Up @@ -242,15 +252,19 @@ JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags,
#else
const char *reason = dlerror();
#endif
#ifndef __clang_analyzer__
// Hide the error throwing from the analyser since there isn't a way to express
// "safepoint only when throwing error" currently.
jl_errorf("could not load library \"%s\"\n%s", modname, reason);
#endif
}
handle = NULL;

done:
return handle;
}

JL_DLLEXPORT int jl_dlsym(void *handle, const char *symbol, void ** value, int throw_err)
JL_DLLEXPORT int jl_dlsym(void *handle, const char *symbol, void ** value, int throw_err) JL_NOTSAFEPOINT
{
int symbol_found = 0;

Expand Down Expand Up @@ -278,7 +292,11 @@ JL_DLLEXPORT int jl_dlsym(void *handle, const char *symbol, void ** value, int t
char err[256];
win32_formatmessage(GetLastError(), err, sizeof(err));
#endif
#ifndef __clang_analyzer__
// Hide the error throwing from the analyser since there isn't a way to express
// "safepoint only when throwing error" currently.
jl_errorf("could not load symbol \"%s\":\n%s", symbol, err);
#endif
}
return symbol_found;
}
Expand Down
6 changes: 3 additions & 3 deletions src/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2756,7 +2756,7 @@ JL_DLLEXPORT int jl_gc_is_enabled(void)
return !ptls->disable_gc;
}

JL_DLLEXPORT void jl_gc_get_total_bytes(int64_t *bytes)
JL_DLLEXPORT void jl_gc_get_total_bytes(int64_t *bytes) JL_NOTSAFEPOINT
{
jl_gc_num_t num = gc_num;
combine_thread_gc_counts(&num);
Expand All @@ -2777,7 +2777,7 @@ JL_DLLEXPORT jl_gc_num_t jl_gc_num(void)
}

// TODO: these were supposed to be thread local
JL_DLLEXPORT int64_t jl_gc_diff_total_bytes(void)
JL_DLLEXPORT int64_t jl_gc_diff_total_bytes(void) JL_NOTSAFEPOINT
{
int64_t oldtb = last_gc_total_bytes;
int64_t newtb;
Expand All @@ -2786,7 +2786,7 @@ JL_DLLEXPORT int64_t jl_gc_diff_total_bytes(void)
return newtb - oldtb;
}

JL_DLLEXPORT int64_t jl_gc_sync_total_bytes(int64_t offset)
JL_DLLEXPORT int64_t jl_gc_sync_total_bytes(int64_t offset) JL_NOTSAFEPOINT
{
int64_t oldtb = last_gc_total_bytes;
int64_t newtb;
Expand Down
6 changes: 3 additions & 3 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ extern "C" {
#endif

JL_DLLEXPORT size_t jl_world_counter = 1; // TODO: should this be atomic release/consume?
JL_DLLEXPORT size_t jl_get_world_counter(void)
JL_DLLEXPORT size_t jl_get_world_counter(void) JL_NOTSAFEPOINT
{
return jl_world_counter;
}

JL_DLLEXPORT size_t jl_get_tls_world_age(void)
JL_DLLEXPORT size_t jl_get_tls_world_age(void) JL_NOTSAFEPOINT
{
return jl_get_ptls_states()->world_age;
}
Expand Down Expand Up @@ -526,7 +526,7 @@ static int very_general_type(jl_value_t *t)
return (t == (jl_value_t*)jl_any_type || jl_types_equal(t, (jl_value_t*)jl_type_type));
}

jl_value_t *jl_nth_slot_type(jl_value_t *sig, size_t i)
jl_value_t *jl_nth_slot_type(jl_value_t *sig, size_t i) JL_NOTSAFEPOINT
{
sig = jl_unwrap_unionall(sig);
size_t len = jl_nparams(sig);
Expand Down
2 changes: 1 addition & 1 deletion src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ char jl_using_oprofile_jitevents = 0; // Non-zero if running under OProfile
char jl_using_perf_jitevents = 0;
#endif

int isabspath(const char *in)
int isabspath(const char *in) JL_NOTSAFEPOINT
{
#ifdef _OS_WINDOWS_
char c0 = in[0];
Expand Down
2 changes: 1 addition & 1 deletion src/jl_uv.c
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,7 @@ JL_DLLEXPORT void jl_exit(int exitcode)
exit(exitcode);
}

JL_DLLEXPORT int jl_getpid(void)
JL_DLLEXPORT int jl_getpid(void) JL_NOTSAFEPOINT
{
#ifdef _OS_WINDOWS_
return GetCurrentProcessId();
Expand Down
6 changes: 3 additions & 3 deletions src/jlapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ JL_DLLEXPORT jl_value_t *jl_eval_string(const char *str)
return r;
}

JL_DLLEXPORT jl_value_t *jl_current_exception(void) JL_GLOBALLY_ROOTED
JL_DLLEXPORT jl_value_t *jl_current_exception(void) JL_GLOBALLY_ROOTED JL_NOTSAFEPOINT
{
jl_excstack_t *s = jl_get_ptls_states()->current_task->excstack;
return s && s->top != 0 ? jl_excstack_exception(s, s->top) : jl_nothing;
Expand Down Expand Up @@ -316,7 +316,7 @@ JL_DLLEXPORT void jl_sigatomic_end(void)
JL_SIGATOMIC_END();
}

JL_DLLEXPORT int jl_is_debugbuild(void)
JL_DLLEXPORT int jl_is_debugbuild(void) JL_NOTSAFEPOINT
{
#ifdef JL_DEBUG_BUILD
return 1;
Expand All @@ -325,7 +325,7 @@ JL_DLLEXPORT int jl_is_debugbuild(void)
#endif
}

JL_DLLEXPORT int8_t jl_is_memdebug(void) {
JL_DLLEXPORT int8_t jl_is_memdebug(void) JL_NOTSAFEPOINT {
#ifdef MEMDEBUG
return 1;
#else
Expand Down
Loading

0 comments on commit 0a77e07

Please sign in to comment.