From 5ceb55d6682c482533a0fd113090949d23808d7c Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 16 Nov 2022 16:17:00 -0500 Subject: [PATCH] ensure bindings handle write barriers for ty and globalref (#47580) This has probably been wrong for a long time (since being introduced in 79082468986). --- src/builtins.c | 472 +++++++++++++++++++++++++++++++------------------ src/gc.c | 11 +- src/module.c | 2 +- 3 files changed, 308 insertions(+), 177 deletions(-) diff --git a/src/builtins.c b/src/builtins.c index 62bfd431584c3..a6c904c851c95 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -35,8 +35,8 @@ extern "C" { static int bits_equal(const void *a, const void *b, int sz) JL_NOTSAFEPOINT { switch (sz) { - case 1: return *(int8_t*)a == *(int8_t*)b; - // Let compiler constant folds the following. + case 1: return *(uint8_t*)a == *(uint8_t*)b; + // Let compiler constant folds the following, though we may not know alignment of them case 2: return memcmp(a, b, 2) == 0; case 4: return memcmp(a, b, 4) == 0; case 8: return memcmp(a, b, 8) == 0; @@ -116,7 +116,7 @@ static int NOINLINE compare_fields(const jl_value_t *a, const jl_value_t *b, jl_ } } if (!ft->layout->haspadding) { - if (!bits_equal(ao, bo, ft->size)) + if (!bits_equal(ao, bo, ft->layout->size)) return 0; } else { @@ -147,10 +147,10 @@ static int egal_types(const jl_value_t *a, const jl_value_t *b, jl_typeenv_t *en { if (a == b) return 1; - jl_datatype_t *dt = (jl_datatype_t*)jl_typeof(a); - if (dt != (jl_datatype_t*)jl_typeof(b)) + uintptr_t dtag = jl_typetagof(a); + if (dtag != jl_typetagof(b)) return 0; - if (dt == jl_datatype_type) { + if (dtag == jl_datatype_tag << 4) { jl_datatype_t *dta = (jl_datatype_t*)a; jl_datatype_t *dtb = (jl_datatype_t*)b; if (dta->name != dtb->name) @@ -164,7 +164,7 @@ static int egal_types(const jl_value_t *a, const jl_value_t *b, jl_typeenv_t *en } return 1; } - if (dt == jl_tvar_type) { + if (dtag == jl_tvar_tag << 4) { jl_typeenv_t *pe = env; while (pe != NULL) { if (pe->var == (jl_tvar_t*)a) @@ -173,7 +173,7 @@ static int egal_types(const jl_value_t *a, const jl_value_t *b, jl_typeenv_t *en } return 0; } - if (dt == jl_unionall_type) { + if (dtag == jl_unionall_tag << 4) { jl_unionall_t *ua = (jl_unionall_t*)a; jl_unionall_t *ub = (jl_unionall_t*)b; if (tvar_names && ua->var->name != ub->var->name) @@ -183,11 +183,11 @@ static int egal_types(const jl_value_t *a, const jl_value_t *b, jl_typeenv_t *en jl_typeenv_t e = { ua->var, (jl_value_t*)ub->var, env }; return egal_types(ua->body, ub->body, &e, tvar_names); } - if (dt == jl_uniontype_type) { + if (dtag == jl_uniontype_tag << 4) { return egal_types(((jl_uniontype_t*)a)->a, ((jl_uniontype_t*)b)->a, env, tvar_names) && egal_types(((jl_uniontype_t*)a)->b, ((jl_uniontype_t*)b)->b, env, tvar_names); } - if (dt == jl_vararg_type) { + if (dtag == jl_vararg_tag << 4) { jl_vararg_t *vma = (jl_vararg_t*)a; jl_vararg_t *vmb = (jl_vararg_t*)b; jl_value_t *vmaT = vma->T ? vma->T : (jl_value_t*)jl_any_type; @@ -198,10 +198,8 @@ static int egal_types(const jl_value_t *a, const jl_value_t *b, jl_typeenv_t *en return egal_types(vma->N, vmb->N, env, tvar_names); return !vma->N && !vmb->N; } - if (dt == jl_symbol_type) - return 0; - assert(!dt->name->mutabl); - return jl_egal__bits(a, b, dt); + assert(dtag == jl_symbol_tag << 4 || dtag == jl_module_tag << 4 || !((jl_datatype_t*)jl_typeof(a))->name->mutabl); + return jl_egal__bitstag(a, b, dtag); } JL_DLLEXPORT int jl_types_egal(jl_value_t *a, jl_value_t *b) @@ -215,36 +213,72 @@ JL_DLLEXPORT int (jl_egal)(const jl_value_t *a JL_MAYBE_UNROOTED, const jl_value return jl_egal(a, b); } -JL_DLLEXPORT int jl_egal__unboxed(const jl_value_t *a JL_MAYBE_UNROOTED, const jl_value_t *b JL_MAYBE_UNROOTED, jl_datatype_t *dt) JL_NOTSAFEPOINT +JL_DLLEXPORT int jl_egal__unboxed(const jl_value_t *a JL_MAYBE_UNROOTED, const jl_value_t *b JL_MAYBE_UNROOTED, uintptr_t dtag) JL_NOTSAFEPOINT { // warning: a,b may NOT have been gc-rooted by the caller - return jl_egal__unboxed_(a, b, dt); -} - -int jl_egal__special(const jl_value_t *a JL_MAYBE_UNROOTED, const jl_value_t *b JL_MAYBE_UNROOTED, jl_datatype_t *dt) JL_NOTSAFEPOINT -{ - if (dt == jl_simplevector_type) - return compare_svec((jl_svec_t*)a, (jl_svec_t*)b); - if (dt == jl_datatype_type) { - jl_datatype_t *dta = (jl_datatype_t*)a; - jl_datatype_t *dtb = (jl_datatype_t*)b; - if (dta->name != dtb->name) - return 0; - if (dta->name != jl_tuple_typename && (dta->isconcretetype || dtb->isconcretetype)) + return jl_egal__unboxed_(a, b, dtag); +} + +JL_DLLEXPORT int jl_egal__bitstag(const jl_value_t *a JL_MAYBE_UNROOTED, const jl_value_t *b JL_MAYBE_UNROOTED, uintptr_t dtag) JL_NOTSAFEPOINT +{ + if (dtag < jl_max_tags << 4) { + switch ((enum jlsmall_typeof_tags)(dtag >> 4)) { + case jl_int8_tag: + case jl_uint8_tag: + return *(uint8_t*)a == *(uint8_t*)b; + case jl_int16_tag: + case jl_uint16_tag: + return *(uint16_t*)a == *(uint16_t*)b; + case jl_int32_tag: + case jl_uint32_tag: + case jl_char_tag: + return *(uint32_t*)a == *(uint32_t*)b; + case jl_int64_tag: + case jl_uint64_tag: + return *(uint64_t*)a == *(uint64_t*)b; + case jl_unionall_tag: + return egal_types(a, b, NULL, 1); + case jl_uniontype_tag: + return compare_fields(a, b, jl_uniontype_type); + case jl_vararg_tag: + return compare_fields(a, b, jl_vararg_type); + case jl_task_tag: + case jl_tvar_tag: + case jl_symbol_tag: + case jl_module_tag: + case jl_bool_tag: return 0; - return compare_svec(dta->parameters, dtb->parameters); - } - if (dt == jl_string_type) { - size_t l = jl_string_len(a); - if (jl_string_len(b) != l) - return 0; - return !memcmp(jl_string_data(a), jl_string_data(b), l); + case jl_simplevector_tag: + return compare_svec((jl_svec_t*)a, (jl_svec_t*)b); + case jl_string_tag: { + size_t l = jl_string_len(a); + if (jl_string_len(b) != l) + return 0; + return !memcmp(jl_string_data(a), jl_string_data(b), l); + } + case jl_datatype_tag: { + jl_datatype_t *dta = (jl_datatype_t*)a; + jl_datatype_t *dtb = (jl_datatype_t*)b; + if (dta->name != dtb->name) + return 0; + if (dta->name != jl_tuple_typename && (dta->isconcretetype || dtb->isconcretetype)) + return 0; + return compare_svec(dta->parameters, dtb->parameters); + } +#ifndef NDEBUG + default: +#endif + case jl_max_tags: + case jl_null_tag: + case jl_typeofbottom_tag: + case jl_tags_count: + abort(); + } } - assert(0 && "unreachable"); - return 0; + return jl_egal__bits(a, b, (jl_datatype_t*)dtag); } -int jl_egal__bits(const jl_value_t *a JL_MAYBE_UNROOTED, const jl_value_t *b JL_MAYBE_UNROOTED, jl_datatype_t *dt) JL_NOTSAFEPOINT +inline int jl_egal__bits(const jl_value_t *a JL_MAYBE_UNROOTED, const jl_value_t *b JL_MAYBE_UNROOTED, jl_datatype_t *dt) JL_NOTSAFEPOINT { size_t sz = jl_datatype_size(dt); if (sz == 0) @@ -252,8 +286,6 @@ int jl_egal__bits(const jl_value_t *a JL_MAYBE_UNROOTED, const jl_value_t *b JL_ size_t nf = jl_datatype_nfields(dt); if (nf == 0 || !dt->layout->haspadding) return bits_equal(a, b, sz); - if (dt == jl_unionall_type) - return egal_types(a, b, NULL, 1); return compare_fields(a, b, dt); } @@ -347,6 +379,8 @@ static uintptr_t type_object_id_(jl_value_t *v, jl_varidx_t *env) JL_NOTSAFEPOIN } if (tv == jl_symbol_type) return ((jl_sym_t*)v)->hash; + if (tv == jl_module_type) + return ((jl_module_t*)v)->hash; assert(!tv->name->mutabl); return immut_id_(tv, v, tv->hash); } @@ -414,6 +448,10 @@ static uintptr_t NOINLINE jl_object_id__cold(jl_datatype_t *dt, jl_value_t *v) J return memhash32_seed(jl_string_data(v), jl_string_len(v), 0xedc3b677); #endif } + if (dt == jl_module_type) { + jl_module_t *m = (jl_module_t*)v; + return m->hash; + } if (dt->name->mutabl) return inthash((uintptr_t)v); return immut_id_(dt, v, dt->hash); @@ -569,7 +607,7 @@ STATIC_INLINE void _grow_to(jl_value_t **root, jl_value_t ***oldargs, jl_svec_t *n_alloc = newalloc; } -static jl_value_t *do_apply( jl_value_t **args, uint32_t nargs, jl_value_t *iterate) +static jl_value_t *do_apply(jl_value_t **args, uint32_t nargs, jl_value_t *iterate) { jl_function_t *f = args[0]; if (nargs == 2) { @@ -893,10 +931,14 @@ static inline size_t get_checked_fieldindex(const char *name, jl_datatype_t *st, if (idx >= jl_datatype_nfields(st)) jl_bounds_error(v, arg); } - else { - JL_TYPECHKS(name, symbol, arg); + else if (jl_is_symbol(arg)) { idx = jl_field_index(st, (jl_sym_t*)arg, 1); } + else { + jl_value_t *ts[2] = {(jl_value_t*)jl_long_type, (jl_value_t*)jl_symbol_type}; + jl_value_t *t = jl_type_union(ts, 2); + jl_type_error("getfield", t, arg); + } if (mutabl && jl_field_isconst(st, idx)) { jl_errorf("%s: const field .%s of type %s cannot be changed", name, jl_symbol_name((jl_sym_t*)jl_svec_ref(jl_field_names(st), idx)), jl_symbol_name(st->name->name)); @@ -921,22 +963,18 @@ JL_CALLABLE(jl_f_getfield) } jl_value_t *v = args[0]; jl_value_t *vt = jl_typeof(v); - if (vt == (jl_value_t*)jl_module_type) { - JL_TYPECHK(getfield, symbol, args[1]); - v = jl_eval_global_var((jl_module_t*)v, (jl_sym_t*)args[1]); // is seq_cst already - } - else { - jl_datatype_t *st = (jl_datatype_t*)vt; - size_t idx = get_checked_fieldindex("getfield", st, v, args[1], 0); - int isatomic = jl_field_isatomic(st, idx); - if (!isatomic && order != jl_memory_order_notatomic && order != jl_memory_order_unspecified) - jl_atomic_error("getfield: non-atomic field cannot be accessed atomically"); - if (isatomic && order == jl_memory_order_notatomic) - jl_atomic_error("getfield: atomic field cannot be accessed non-atomically"); - v = jl_get_nth_field_checked(v, idx); - if (order >= jl_memory_order_acq_rel || order == jl_memory_order_acquire) - jl_fence(); // `v` already had at least consume ordering - } + if (vt == (jl_value_t*)jl_module_type) + return jl_f_getglobal(NULL, args, 2); // we just ignore the atomic order and boundschecks + jl_datatype_t *st = (jl_datatype_t*)vt; + size_t idx = get_checked_fieldindex("getfield", st, v, args[1], 0); + int isatomic = jl_field_isatomic(st, idx); + if (!isatomic && order != jl_memory_order_notatomic && order != jl_memory_order_unspecified) + jl_atomic_error("getfield: non-atomic field cannot be accessed atomically"); + if (isatomic && order == jl_memory_order_notatomic) + jl_atomic_error("getfield: atomic field cannot be accessed non-atomically"); + v = jl_get_nth_field_checked(v, idx); + if (order >= jl_memory_order_acq_rel || order == jl_memory_order_acquire) + jl_fence(); // `v` already had at least consume ordering return v; } @@ -945,7 +983,7 @@ JL_CALLABLE(jl_f_setfield) enum jl_memory_order order = jl_memory_order_notatomic; JL_NARGS(setfield!, 3, 4); if (nargs == 4) { - JL_TYPECHK(getfield, symbol, args[3]); + JL_TYPECHK(setfield!, symbol, args[3]); order = jl_get_atomic_order_checked((jl_sym_t*)args[3], 0, 1); } jl_value_t *v = args[0]; @@ -1180,26 +1218,121 @@ JL_CALLABLE(jl_f_isdefined) } +// module bindings + +JL_CALLABLE(jl_f_getglobal) +{ + enum jl_memory_order order = jl_memory_order_monotonic; + JL_NARGS(getglobal, 2, 3); + if (nargs == 3) { + JL_TYPECHK(getglobal, symbol, args[2]); + order = jl_get_atomic_order_checked((jl_sym_t*)args[2], 1, 0); + } + jl_module_t *mod = (jl_module_t*)args[0]; + jl_sym_t *sym = (jl_sym_t*)args[1]; + JL_TYPECHK(getglobal, module, (jl_value_t*)mod); + JL_TYPECHK(getglobal, symbol, (jl_value_t*)sym); + if (order == jl_memory_order_notatomic) + jl_atomic_error("getglobal: module binding cannot be read non-atomically"); + jl_value_t *v = jl_eval_global_var(mod, sym); + // is seq_cst already, no fence needed + return v; +} + +JL_CALLABLE(jl_f_setglobal) +{ + enum jl_memory_order order = jl_memory_order_release; + JL_NARGS(setglobal!, 3, 4); + if (nargs == 4) { + JL_TYPECHK(setglobal!, symbol, args[3]); + order = jl_get_atomic_order_checked((jl_sym_t*)args[3], 0, 1); + } + jl_module_t *mod = (jl_module_t*)args[0]; + jl_sym_t *var = (jl_sym_t*)args[1]; + JL_TYPECHK(setglobal!, module, (jl_value_t*)mod); + JL_TYPECHK(setglobal!, symbol, (jl_value_t*)var); + if (order == jl_memory_order_notatomic) + jl_atomic_error("setglobal!: module binding cannot be written non-atomically"); + // is seq_cst already, no fence needed + jl_binding_t *b = jl_get_binding_wr(mod, var); + jl_checked_assignment(b, mod, var, args[2]); + return args[2]; +} + +JL_CALLABLE(jl_f_get_binding_type) +{ + JL_NARGS(get_binding_type, 2, 2); + jl_module_t *mod = (jl_module_t*)args[0]; + jl_sym_t *var = (jl_sym_t*)args[1]; + JL_TYPECHK(get_binding_type, module, (jl_value_t*)mod); + JL_TYPECHK(get_binding_type, symbol, (jl_value_t*)var); + jl_value_t *ty = jl_get_binding_type(mod, var); + if (ty == (jl_value_t*)jl_nothing) { + jl_binding_t *b = jl_get_module_binding(mod, var, 0); + if (b == NULL) + return (jl_value_t*)jl_any_type; + jl_binding_t *b2 = jl_atomic_load_relaxed(&b->owner); + if (b2 != b) + return (jl_value_t*)jl_any_type; + jl_value_t *old_ty = NULL; + jl_atomic_cmpswap_relaxed(&b->ty, &old_ty, (jl_value_t*)jl_any_type); + return jl_atomic_load_relaxed(&b->ty); + } + return ty; +} + +JL_CALLABLE(jl_f_set_binding_type) +{ + JL_NARGS(set_binding_type!, 2, 3); + jl_module_t *m = (jl_module_t*)args[0]; + jl_sym_t *s = (jl_sym_t*)args[1]; + JL_TYPECHK(set_binding_type!, module, (jl_value_t*)m); + JL_TYPECHK(set_binding_type!, symbol, (jl_value_t*)s); + jl_value_t *ty = nargs == 2 ? (jl_value_t*)jl_any_type : args[2]; + JL_TYPECHK(set_binding_type!, type, ty); + jl_binding_t *b = jl_get_binding_wr(m, s); + jl_value_t *old_ty = NULL; + if (!jl_atomic_cmpswap_relaxed(&b->ty, &old_ty, ty) && ty != old_ty) { + if (nargs == 2) + return jl_nothing; + jl_errorf("cannot set type for global %s.%s. It already has a value or is already set to a different type.", + jl_symbol_name(m->name), jl_symbol_name(s)); + } + jl_gc_wb_binding(b, ty); + return jl_nothing; +} + + // apply_type ----------------------------------------------------------------- -int jl_valid_type_param(jl_value_t *v) +static int is_nestable_type_param(jl_value_t *t) { - if (jl_is_tuple(v)) { + if (jl_is_namedtuple_type(t)) + t = jl_tparam1(t); + if (jl_is_tuple_type(t)) { // NOTE: tuples of symbols are not currently bits types, but have been // allowed as type parameters. this is a bit ugly. - jl_value_t *tt = jl_typeof(v); - size_t i, l = jl_nparams(tt); - for(i=0; i < l; i++) { - jl_value_t *pi = jl_tparam(tt,i); - if (!(pi == (jl_value_t*)jl_symbol_type || jl_isbits(pi))) + size_t i, l = jl_nparams(t); + for (i = 0; i < l; i++) { + jl_value_t *pi = jl_tparam(t, i); + if (!(pi == (jl_value_t*)jl_symbol_type || jl_isbits(pi) || is_nestable_type_param(pi) || + jl_is_module(pi))) return 0; } return 1; } + return 0; +} + +int jl_valid_type_param(jl_value_t *v) +{ + if (jl_is_tuple(v) || jl_is_namedtuple(v)) + return is_nestable_type_param(jl_typeof(v)); if (jl_is_vararg(v)) return 0; // TODO: maybe more things - return jl_is_type(v) || jl_is_typevar(v) || jl_is_symbol(v) || jl_isbits(jl_typeof(v)); + return jl_is_type(v) || jl_is_typevar(v) || jl_is_symbol(v) || jl_isbits(jl_typeof(v)) || + jl_is_module(v); } JL_CALLABLE(jl_f_apply_type) @@ -1219,7 +1352,7 @@ JL_CALLABLE(jl_f_apply_type) jl_type_error_rt("Tuple", "parameter", (jl_value_t*)jl_type_type, pi); } } - return (jl_value_t*)jl_apply_tuple_type_v(&args[1], nargs-1); + return jl_apply_tuple_type_v(&args[1], nargs-1); } else if (args[0] == (jl_value_t*)jl_uniontype_type) { // Union{} has extra restrictions, so it needs to be checked after @@ -1275,50 +1408,6 @@ JL_CALLABLE(jl_f_invoke) return res; } -JL_CALLABLE(jl_f_invoke_kwsorter) -{ - JL_NARGSV(invoke, 3); - jl_value_t *kwargs = args[0]; - // args[1] is `invoke` itself - jl_value_t *func = args[2]; - jl_value_t *argtypes = args[3]; - jl_value_t *kws = jl_get_keyword_sorter(func); - JL_GC_PUSH1(&argtypes); - if (jl_is_tuple_type(argtypes)) { - // construct a tuple type for invoking a keyword sorter by putting the kw container type - // and the type of the function at the front. - size_t i, nt = jl_nparams(argtypes) + 2; - if (nt < jl_page_size/sizeof(jl_value_t*)) { - jl_value_t **types = (jl_value_t**)alloca(nt*sizeof(jl_value_t*)); - types[0] = (jl_value_t*)jl_namedtuple_type; - types[1] = jl_is_type(func) ? (jl_value_t*)jl_wrap_Type(func) : jl_typeof(func); - for (i = 2; i < nt; i++) - types[i] = jl_tparam(argtypes, i - 2); - argtypes = (jl_value_t*)jl_apply_tuple_type_v(types, nt); - } - else { - jl_svec_t *types = jl_alloc_svec_uninit(nt); - JL_GC_PUSH1(&types); - jl_svecset(types, 0, jl_namedtuple_type); - jl_svecset(types, 1, jl_is_type(func) ? (jl_value_t*)jl_wrap_Type(func) : jl_typeof(func)); - for (i = 2; i < nt; i++) - jl_svecset(types, i, jl_tparam(argtypes, i - 2)); - argtypes = (jl_value_t*)jl_apply_tuple_type(types); - JL_GC_POP(); - } - } - else { - // invoke will throw an error - } - args[0] = kws; - args[1] = argtypes; - args[2] = kwargs; - args[3] = func; - jl_value_t *res = jl_f_invoke(NULL, args, nargs); - JL_GC_POP(); - return res; -} - // Expr constructor for internal use ------------------------------------------ jl_expr_t *jl_exprn(jl_sym_t *head, size_t n) @@ -1360,6 +1449,7 @@ JL_DLLEXPORT jl_tvar_t *jl_new_typevar(jl_sym_t *name, jl_value_t *lb, jl_value_ jl_type_error_rt("TypeVar", "upper bound", (jl_value_t *)jl_type_type, ub); jl_task_t *ct = jl_current_task; jl_tvar_t *tv = (jl_tvar_t *)jl_gc_alloc(ct->ptls, sizeof(jl_tvar_t), jl_tvar_type); + jl_set_typetagof(tv, jl_tvar_tag, 0); tv->name = name; tv->lb = lb; tv->ub = ub; @@ -1491,16 +1581,25 @@ JL_CALLABLE(jl_f__primitivetype) static void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) { - if (!jl_is_datatype(super) || !jl_is_abstracttype(super) || - tt->super != NULL || - tt->name == ((jl_datatype_t*)super)->name || - jl_is_tuple_type(super) || - jl_is_namedtuple_type(super) || - jl_subtype(super, (jl_value_t*)jl_type_type) || - jl_subtype(super, (jl_value_t*)jl_builtin_type)) { - jl_errorf("invalid subtyping in definition of %s", - jl_symbol_name(tt->name->name)); - } + const char *error = NULL; + if (!jl_is_datatype(super)) + error = "can only subtype data types"; + else if (tt->super != NULL) + error = "type already has a supertype"; + else if (tt->name == ((jl_datatype_t*)super)->name) + error = "a type cannot subtype itself"; + else if (jl_is_tuple_type(super)) + error = "cannot subtype a tuple type"; + else if (jl_is_namedtuple_type(super)) + error = "cannot subtype a named tuple type"; + else if (jl_subtype(super, (jl_value_t*)jl_type_type)) + error = "cannot add subtypes to Type"; + else if (jl_subtype(super, (jl_value_t*)jl_builtin_type)) + error = "cannot add subtypes to Core.Builtin"; + else if (!jl_is_abstracttype(super)) + error = "can only subtype abstract types"; + if (error) + jl_errorf("invalid subtyping in definition of %s: %s.", jl_symbol_name(tt->name->name), error); tt->super = (jl_datatype_t*)super; jl_gc_wb(tt, tt->super); } @@ -1519,6 +1618,58 @@ JL_CALLABLE(jl_f_donotdelete) return jl_nothing; } +JL_CALLABLE(jl_f_compilerbarrier) +{ + JL_NARGS(compilerbarrier, 2, 2); + JL_TYPECHK(compilerbarrier, symbol, args[0]) + jl_sym_t *setting = (jl_sym_t*)args[0]; + if (!(setting == jl_symbol("type") || + setting == jl_symbol("const") || + setting == jl_symbol("conditional"))) + jl_error("The first argument of `compilerbarrier` must be either of `:type`, `:const` or `:conditional`."); + jl_value_t *val = args[1]; + return val; +} + +JL_CALLABLE(jl_f_finalizer) +{ + // NOTE the compiler may temporarily insert additional argument for the later inlining pass + JL_NARGS(finalizer, 2, 4); + jl_task_t *ct = jl_current_task; + jl_gc_add_finalizer_(ct->ptls, args[1], args[0]); + return jl_nothing; +} + +JL_CALLABLE(jl_f__compute_sparams) +{ + JL_NARGSV(_compute_sparams, 1); + jl_method_t *m = (jl_method_t*)args[0]; + JL_TYPECHK(_compute_sparams, method, (jl_value_t*)m); + jl_datatype_t *tt = jl_inst_arg_tuple_type(args[1], &args[2], nargs-1, 1); + jl_svec_t *env = jl_emptysvec; + JL_GC_PUSH2(&env, &tt); + jl_type_intersection_env((jl_value_t*)tt, m->sig, &env); + JL_GC_POP(); + return (jl_value_t*)env; +} + +JL_CALLABLE(jl_f__svec_ref) +{ + JL_NARGS(_svec_ref, 3, 3); + jl_value_t *b = args[0]; + jl_svec_t *s = (jl_svec_t*)args[1]; + jl_value_t *i = (jl_value_t*)args[2]; + JL_TYPECHK(_svec_ref, bool, b); + JL_TYPECHK(_svec_ref, simplevector, (jl_value_t*)s); + JL_TYPECHK(_svec_ref, long, i); + size_t len = jl_svec_len(s); + ssize_t idx = jl_unbox_long(i); + if (idx < 1 || idx > len) { + jl_bounds_error_int((jl_value_t*)s, idx); + } + return jl_svec_ref(s, idx-1); +} + static int equiv_field_types(jl_value_t *old, jl_value_t *ft) { size_t nf = jl_svec_len(ft); @@ -1532,7 +1683,7 @@ static int equiv_field_types(jl_value_t *old, jl_value_t *ft) if (!jl_has_free_typevars(tb) || !jl_egal(ta, tb)) return 0; } - else if (jl_has_free_typevars(tb) || jl_typeof(ta) != jl_typeof(tb) || + else if (jl_has_free_typevars(tb) || jl_typetagof(ta) != jl_typetagof(tb) || !jl_types_equal(ta, tb)) { return 0; } @@ -1645,12 +1796,13 @@ static int equiv_type(jl_value_t *ta, jl_value_t *tb) if (!jl_is_datatype(dta)) return 0; jl_datatype_t *dtb = (jl_datatype_t*)jl_unwrap_unionall(tb); - if (!(jl_typeof(dta) == jl_typeof(dtb) && + if (!(jl_typetagof(dta) == jl_typetagof(dtb) && dta->name->name == dtb->name->name && dta->name->abstract == dtb->name->abstract && dta->name->mutabl == dtb->name->mutabl && dta->name->n_uninitialized == dtb->name->n_uninitialized && - (jl_svec_len(jl_field_names(dta)) != 0 || dta->size == dtb->size) && + dta->isprimitivetype == dtb->isprimitivetype && + (!dta->isprimitivetype || dta->layout->size == dtb->layout->size) && (dta->name->atomicfields == NULL ? dtb->name->atomicfields == NULL : (dtb->name->atomicfields != NULL && @@ -1702,44 +1854,6 @@ JL_CALLABLE(jl_f__equiv_typedef) return equiv_type(args[0], args[1]) ? jl_true : jl_false; } -JL_CALLABLE(jl_f_get_binding_type) -{ - JL_NARGS(get_binding_type, 2, 2); - JL_TYPECHK(get_binding_type, module, args[0]); - 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); - if (ty == (jl_value_t*)jl_nothing) { - jl_binding_t *b = jl_get_binding_wr(mod, sym, 0); - if (b) { - jl_value_t *old_ty = NULL; - jl_atomic_cmpswap_relaxed(&b->ty, &old_ty, (jl_value_t*)jl_any_type); - return jl_atomic_load_relaxed(&b->ty); - } - return (jl_value_t*)jl_any_type; - } - return ty; -} - -JL_CALLABLE(jl_f_set_binding_type) -{ - JL_NARGS(set_binding_type!, 2, 3); - JL_TYPECHK(set_binding_type!, module, args[0]); - JL_TYPECHK(set_binding_type!, symbol, args[1]); - jl_value_t *ty = nargs == 2 ? (jl_value_t*)jl_any_type : args[2]; - JL_TYPECHK(set_binding_type!, type, ty); - jl_binding_t *b = jl_get_binding_wr((jl_module_t*)args[0], (jl_sym_t*)args[1], 1); - jl_value_t *old_ty = NULL; - if (!jl_atomic_cmpswap_relaxed(&b->ty, &old_ty, ty) && ty != old_ty) { - if (nargs == 2) - return jl_nothing; - jl_errorf("cannot set type for global %s. It already has a value or is already set to a different type.", - jl_symbol_name(b->name)); - } - return jl_nothing; -} - // IntrinsicFunctions --------------------------------------------------------- static void (*runtime_fp[num_intrinsics])(void); @@ -1812,7 +1926,7 @@ static void add_intrinsic_properties(enum intrinsic f, unsigned nargs, void (*pf static void add_intrinsic(jl_module_t *inm, const char *name, enum intrinsic f) JL_GC_DISABLED { - jl_value_t *i = jl_permbox32(jl_intrinsic_type, (int32_t)f); + jl_value_t *i = jl_permbox32(jl_intrinsic_type, 0, (int32_t)f); jl_sym_t *sym = jl_symbol(name); jl_set_const(inm, sym, i); jl_module_export(inm, sym); @@ -1831,7 +1945,7 @@ void jl_init_intrinsic_properties(void) JL_GC_DISABLED void jl_init_intrinsic_functions(void) JL_GC_DISABLED { - jl_module_t *inm = jl_new_module(jl_symbol("Intrinsics")); + jl_module_t *inm = jl_new_module(jl_symbol("Intrinsics"), NULL); inm->parent = jl_core_module; jl_set_const(jl_core_module, jl_symbol("Intrinsics"), (jl_value_t*)inm); jl_mk_builtin_func(jl_intrinsic_type, "IntrinsicFunction", jl_f_intrinsic_call); @@ -1839,6 +1953,11 @@ void jl_init_intrinsic_functions(void) JL_GC_DISABLED (jl_datatype_t*)jl_unwrap_unionall((jl_value_t*)jl_opaque_closure_type), "OpaqueClosure", jl_f_opaque_closure_call); + // Save a reference to the just created OpaqueClosure method, so we can provide special + // codegen for it later. + jl_opaque_closure_method = (jl_method_t*)jl_methtable_lookup(jl_opaque_closure_typename->mt, + (jl_value_t*)jl_anytuple_type, 1); + #define ADD_I(name, nargs) add_intrinsic(inm, #name, name); #define ADD_HIDDEN(name, nargs) #define ALIAS ADD_I @@ -1889,6 +2008,12 @@ void jl_init_primitives(void) JL_GC_DISABLED jl_builtin_nfields = add_builtin_func("nfields", jl_f_nfields); jl_builtin_isdefined = add_builtin_func("isdefined", jl_f_isdefined); + // module bindings + jl_builtin_getglobal = add_builtin_func("getglobal", jl_f_getglobal); + jl_builtin_setglobal = add_builtin_func("setglobal!", jl_f_setglobal); + add_builtin_func("get_binding_type", jl_f_get_binding_type); + add_builtin_func("set_binding_type!", jl_f_set_binding_type); + // array primitives jl_builtin_arrayref = add_builtin_func("arrayref", jl_f_arrayref); jl_builtin_const_arrayref = add_builtin_func("const_arrayref", jl_f_arrayref); @@ -1898,11 +2023,6 @@ void jl_init_primitives(void) JL_GC_DISABLED // method table utils jl_builtin_applicable = add_builtin_func("applicable", jl_f_applicable); jl_builtin_invoke = add_builtin_func("invoke", jl_f_invoke); - jl_typename_t *itn = ((jl_datatype_t*)jl_typeof(jl_builtin_invoke))->name; - jl_value_t *ikws = jl_new_generic_function_with_supertype(itn->name, jl_core_module, jl_builtin_type); - itn->mt->kwsorter = ikws; - jl_gc_wb(itn->mt, ikws); - jl_mk_builtin_func((jl_datatype_t*)jl_typeof(ikws), jl_symbol_name(jl_gf_name(ikws)), jl_f_invoke_kwsorter); // internal functions jl_builtin_apply_type = add_builtin_func("apply_type", jl_f_apply_type); @@ -1920,9 +2040,11 @@ void jl_init_primitives(void) JL_GC_DISABLED add_builtin_func("_setsuper!", jl_f__setsuper); jl_builtin__typebody = add_builtin_func("_typebody!", jl_f__typebody); add_builtin_func("_equiv_typedef", jl_f__equiv_typedef); - add_builtin_func("get_binding_type", jl_f_get_binding_type); - add_builtin_func("set_binding_type!", jl_f_set_binding_type); jl_builtin_donotdelete = add_builtin_func("donotdelete", jl_f_donotdelete); + jl_builtin_compilerbarrier = add_builtin_func("compilerbarrier", jl_f_compilerbarrier); + add_builtin_func("finalizer", jl_f_finalizer); + add_builtin_func("_compute_sparams", jl_f__compute_sparams); + add_builtin_func("_svec_ref", jl_f__svec_ref); // builtin types add_builtin("Any", (jl_value_t*)jl_any_type); @@ -1938,6 +2060,7 @@ void jl_init_primitives(void) JL_GC_DISABLED add_builtin("Tuple", (jl_value_t*)jl_anytuple_type); add_builtin("TypeofVararg", (jl_value_t*)jl_vararg_type); add_builtin("SimpleVector", (jl_value_t*)jl_simplevector_type); + add_builtin("Vararg", (jl_value_t*)jl_wrap_vararg(NULL, NULL)); add_builtin("Module", (jl_value_t*)jl_module_type); add_builtin("MethodTable", (jl_value_t*)jl_methtable_type); @@ -1947,9 +2070,7 @@ void jl_init_primitives(void) JL_GC_DISABLED add_builtin("TypeMapLevel", (jl_value_t*)jl_typemap_level_type); add_builtin("Symbol", (jl_value_t*)jl_symbol_type); add_builtin("SSAValue", (jl_value_t*)jl_ssavalue_type); - add_builtin("Slot", (jl_value_t*)jl_abstractslot_type); add_builtin("SlotNumber", (jl_value_t*)jl_slotnumber_type); - add_builtin("TypedSlot", (jl_value_t*)jl_typedslot_type); add_builtin("Argument", (jl_value_t*)jl_argument_type); add_builtin("Const", (jl_value_t*)jl_const_type); add_builtin("PartialStruct", (jl_value_t*)jl_partial_struct_type); @@ -1983,6 +2104,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); diff --git a/src/gc.c b/src/gc.c index e1ac14d4772f2..75f385b699977 100644 --- a/src/gc.c +++ b/src/gc.c @@ -3086,8 +3086,17 @@ static void jl_gc_queue_remset(jl_gc_mark_cache_t *gc_cache, jl_gc_mark_sp_t *sp 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)) { + 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++; } diff --git a/src/module.c b/src/module.c index 63dff3ae6deb7..f5fdbffcec83c 100644 --- a/src/module.c +++ b/src/module.c @@ -419,7 +419,7 @@ JL_DLLEXPORT jl_value_t *jl_module_globalref(jl_module_t *m, jl_sym_t *var) if (jl_atomic_cmpswap_relaxed(&b->globalref, &globalref, newref)) { JL_GC_PROMISE_ROOTED(newref); globalref = newref; - jl_gc_wb(m, globalref); + jl_gc_wb_binding(b, globalref); } } JL_UNLOCK(&m->lock); // may GC