From c2cc63685d544d659d9b2eb7679b056311b392a8 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Wed, 26 Jun 2024 20:16:24 +0000 Subject: [PATCH] Split Binding --- src/ast.c | 15 ++- src/builtins.c | 1 + src/codegen.cpp | 36 +++--- src/jl_exported_data.inc | 1 + src/jltypes.c | 15 ++- src/julia.h | 34 +++++- src/julia_internal.h | 13 +- src/method.c | 12 +- src/module.c | 251 +++++++++++++++++++++++---------------- src/staticdata.c | 13 +- src/toplevel.c | 60 +++++----- stdlib/REPL/src/REPL.jl | 2 +- 12 files changed, 270 insertions(+), 183 deletions(-) diff --git a/src/ast.c b/src/ast.c index 10432a8a94e3d..040b50280c9df 100644 --- a/src/ast.c +++ b/src/ast.c @@ -175,7 +175,8 @@ static value_t fl_defined_julia_global(fl_context_t *fl_ctx, value_t *args, uint jl_ast_context_t *ctx = jl_ast_ctx(fl_ctx); jl_sym_t *var = scmsym_to_julia(fl_ctx, args[0]); jl_binding_t *b = jl_get_module_binding(ctx->module, var, 0); - return (b != NULL && b->kind == BINDING_KIND_GLOBAL) ? fl_ctx->T : fl_ctx->F; + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + return (bpart != NULL && bpart->kind == BINDING_KIND_GLOBAL) ? fl_ctx->T : fl_ctx->F; } static value_t fl_nothrow_julia_global(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) @@ -204,14 +205,16 @@ static value_t fl_nothrow_julia_global(fl_context_t *fl_ctx, value_t *args, uint var = scmsym_to_julia(fl_ctx, args[1]); } jl_binding_t *b = jl_get_module_binding(mod, var, 0); - while (jl_binding_is_some_import(b)) { - b = (jl_binding_t*)b->restriction; + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + while (jl_bpart_is_some_import(bpart)) { + b = (jl_binding_t*)bpart->restriction; + bpart = jl_get_binding_partition(b, jl_current_task->world_age); } - if (!b) + if (!bpart) return fl_ctx->F; - if (jl_binding_is_some_guard(b)) + if (jl_bpart_is_some_guard(bpart)) return fl_ctx->F; - return (jl_binding_is_some_constant(b) ? b->restriction : jl_atomic_load_relaxed(&b->value)) != NULL ? fl_ctx->T : fl_ctx->F; + return (jl_bpart_is_some_constant(bpart) ? bpart->restriction : jl_atomic_load_relaxed(&b->value)) != NULL ? fl_ctx->T : fl_ctx->F; } static value_t fl_current_module_counter(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) JL_NOTSAFEPOINT diff --git a/src/builtins.c b/src/builtins.c index 1bff7105d6487..3428b64b9eb34 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -2494,6 +2494,7 @@ void jl_init_primitives(void) JL_GC_DISABLED 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("BindingPartition", (jl_value_t*)jl_binding_partition_type); add_builtin("GlobalRef", (jl_value_t*)jl_globalref_type); add_builtin("NamedTuple", (jl_value_t*)jl_namedtuple_type); diff --git a/src/codegen.cpp b/src/codegen.cpp index c560c06d8aaee..644296b7df40e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3212,27 +3212,29 @@ static jl_value_t *jl_ensure_rooted(jl_codectx_t &ctx, jl_value_t *val) static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *name, AtomicOrdering order) { jl_binding_t *bnd = jl_get_module_binding(mod, name, 1); - if (bnd->kind == BINDING_KIND_GUARD || bnd->kind == BINDING_KIND_FAILED || bnd->kind == BINDING_KIND_DECLARED) { + jl_binding_partition_t *bpart = jl_get_binding_partition(bnd, ctx.max_world); + if (jl_bpart_is_some_guard(bpart)) { // try to look this up now. // TODO: This is bad and we'd like to delete it. jl_get_binding(mod, name); } assert(bnd); Value *bp = NULL; - if (jl_binding_is_some_guard(bnd)) { + if (jl_bpart_is_some_guard(bpart)) { // Redo the lookup at runtime bp = julia_binding_gv(ctx, bnd); Value *v = ctx.builder.CreateCall(prepare_call(jlgetbindingvalue_func), { bp }); undef_var_error_ifnot(ctx, ctx.builder.CreateIsNotNull(v), name, (jl_value_t*)mod); return mark_julia_type(ctx, v, true, jl_any_type); } else { - while (jl_binding_is_some_import(bnd)) { + while (jl_bpart_is_some_import(bpart)) { if (bnd->deprecated) { cg_bdw(ctx, name, bnd); } - bnd = (jl_binding_t*)bnd->restriction; + bnd = (jl_binding_t*)bpart->restriction; + bpart = jl_get_binding_partition(bnd, ctx.max_world); } - if (jl_binding_is_some_constant(bnd)) { + if (jl_bpart_is_some_constant(bpart)) { jl_value_t *constval = jl_get_binding_value_if_const(bnd); if (!constval) { undef_var_error_ifnot(ctx, ConstantInt::get(getInt1Ty(ctx.builder.getContext()), 0), name, (jl_value_t*)mod); @@ -3245,8 +3247,8 @@ static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t * if (bnd->deprecated) { cg_bdw(ctx, name, bnd); } - assert(bnd->kind == BINDING_KIND_GLOBAL); - jl_value_t *ty = bnd->restriction; + assert(bpart->kind == BINDING_KIND_GLOBAL); + jl_value_t *ty = bpart->restriction; bp = julia_binding_pvalue(ctx, bp); if (ty == nullptr) ty = (jl_value_t*)jl_any_type; @@ -3260,10 +3262,11 @@ static jl_cgval_t emit_globalop(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *s { jl_binding_t *bnd = NULL; Value *bp = global_binding_pointer(ctx, mod, sym, &bnd, true, alloc); + jl_binding_partition_t *bpart = jl_get_binding_partition(bnd, ctx.max_world); if (bp == NULL) return jl_cgval_t(); - if (bnd && !jl_binding_is_some_constant(bnd)) { - jl_value_t *ty = bnd->restriction; + if (bnd && !jl_bpart_is_some_constant(bpart)) { + jl_value_t *ty = bpart->restriction; if (ty != nullptr) { const std::string fname = issetglobal ? "setglobal!" : isreplaceglobal ? "replaceglobal!" : isswapglobal ? "swapglobal!" : ismodifyglobal ? "modifyglobal!" : "setglobalonce!"; if (!ismodifyglobal) { @@ -5482,17 +5485,22 @@ static Value *global_binding_pointer(jl_codectx_t &ctx, jl_module_t *m, jl_sym_t jl_binding_t **pbnd, bool assign, bool alloc) { jl_binding_t *b = jl_get_module_binding(m, s, 1); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, ctx.max_world); if (assign) { - if (b->kind == BINDING_KIND_GUARD || b->kind == BINDING_KIND_FAILED || b->kind == BINDING_KIND_DECLARED) + if (jl_bpart_is_some_guard(bpart)) // not yet declared b = NULL; } else { - if (b->kind == BINDING_KIND_GUARD || b->kind == BINDING_KIND_FAILED || b->kind == BINDING_KIND_DECLARED) + if (jl_bpart_is_some_guard(bpart)) { // try to look this up now b = jl_get_binding(m, s); - while (jl_binding_is_some_import(b)) - b = (jl_binding_t*)b->restriction; + bpart = jl_get_binding_partition(b, ctx.max_world); + } + while (jl_bpart_is_some_import(bpart)) { + b = (jl_binding_t*)bpart->restriction; + bpart = jl_get_binding_partition(b, ctx.max_world); + } } if (b == NULL) { // var not found. switch to delayed lookup. @@ -5533,7 +5541,7 @@ static Value *global_binding_pointer(jl_codectx_t &ctx, jl_module_t *m, jl_sym_t return p; } if (assign) { - if (b->kind != BINDING_KIND_GLOBAL && !jl_binding_is_some_guard(b)) { + if (bpart->kind != BINDING_KIND_GLOBAL && !jl_bpart_is_some_guard(bpart)) { // this will fail at runtime, so defer to the runtime to create the error ctx.builder.CreateCall(prepare_call(jlgetbindingwrorerror_func), { literal_pointer_val(ctx, (jl_value_t*)m), diff --git a/src/jl_exported_data.inc b/src/jl_exported_data.inc index ff79966b2b01b..8711c14514145 100644 --- a/src/jl_exported_data.inc +++ b/src/jl_exported_data.inc @@ -51,6 +51,7 @@ XX(jl_floatingpoint_type) \ XX(jl_function_type) \ XX(jl_binding_type) \ + XX(jl_binding_partition_type) \ XX(jl_globalref_type) \ XX(jl_gotoifnot_type) \ XX(jl_enternode_type) \ diff --git a/src/jltypes.c b/src/jltypes.c index 41c37c6158abc..fa3294530f0d3 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3098,10 +3098,20 @@ void jl_init_types(void) JL_GC_DISABLED assert(jl_module_type->instance == NULL); jl_compute_field_offsets(jl_module_type); + jl_binding_partition_type = + jl_new_datatype(jl_symbol("BindingPartition"), core, jl_any_type, jl_emptysvec, + jl_perm_symsvec(5, "restriction", "min_world", "max_world", "next", "flags"), + jl_svec(5, jl_any_type, jl_ulong_type, jl_ulong_type, jl_any_type/*jl_binding_partition_type*/, jl_uint8_type), + jl_emptysvec, 0, 1, 0); + const static uint32_t binding_partition_atomicfields[] = { 0x000d }; // Set fields 1, 3, 4 as atomic + jl_binding_partition_type->name->atomicfields = binding_partition_atomicfields; + const static uint32_t binding_partition_constfields[] = { 0x0002 }; // Set field 2 as constant + jl_binding_partition_type->name->constfields = binding_partition_constfields; + jl_binding_type = jl_new_datatype(jl_symbol("Binding"), core, jl_any_type, jl_emptysvec, - jl_perm_symsvec(4, "value", "globalref", "restriction", "flags"), - jl_svec(4, jl_any_type, jl_any_type/*jl_globalref_type*/, jl_type_type, jl_uint8_type), + jl_perm_symsvec(4, "value", "globalref", "partitions", "flags"), + jl_svec(4, jl_any_type, jl_any_type/*jl_globalref_type*/, jl_binding_partition_type, jl_uint8_type), jl_emptysvec, 0, 1, 0); const static uint32_t binding_atomicfields[] = { 0x0005 }; // Set fields 1, 3 as atomic jl_binding_type->name->atomicfields = binding_atomicfields; @@ -3652,6 +3662,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_svecset(jl_code_instance_type->types, 15, jl_voidpointer_type); jl_svecset(jl_code_instance_type->types, 16, jl_voidpointer_type); jl_svecset(jl_binding_type->types, 1, jl_globalref_type); + jl_svecset(jl_binding_partition_type->types, 3, jl_binding_partition_type); jl_compute_field_offsets(jl_datatype_type); jl_compute_field_offsets(jl_typename_type); diff --git a/src/julia.h b/src/julia.h index 3e3a7dda56255..f1c3fc7436e8d 100644 --- a/src/julia.h +++ b/src/julia.h @@ -650,15 +650,35 @@ enum jl_kind_kind { BINDING_KIND_GUARD = 0x8 }; +typedef struct _jl_binding_partition_t { + JL_DATA_TYPE + /* union { + * // For ->kind == BINDING_KIND_GLOBAL + * jl_value_t *type_restriction; + * // For ->kind == BINDING_KIND_CONST(_IMPORT) + * jl_value_t *constval; + * // For ->kind in (BINDING_KIND_IMPLICIT, BINDING_KIND_EXPLICIT, BINDING_KIND_IMPORT) + * jl_binding_t *imported; + * } restriction; + */ + jl_value_t *restriction; + size_t min_world; + _Atomic(size_t) max_world; + _Atomic(struct _jl_binding_partition_t*) next; + uint8_t kind:4; // enum jl_binding_kind + uint8_t padding:4; +} jl_binding_partition_t; + typedef struct _jl_binding_t { JL_DATA_TYPE _Atomic(jl_value_t*) value; jl_globalref_t *globalref; // cached GlobalRef for this binding - jl_value_t *restriction; // binding type or const val + _Atomic(jl_binding_partition_t*) partitions; + uint8_t declared:1; uint8_t exportp:1; // `public foo` sets `publicp`, `export foo` sets both `publicp` and `exportp` uint8_t publicp:1; // exportp without publicp is not allowed. - uint8_t kind:4; // enum jl_binding_kind uint8_t deprecated:2; // 0=not deprecated, 1=renamed, 2=moved to another package + uint8_t padding:3; } jl_binding_t; typedef struct { @@ -950,6 +970,7 @@ extern JL_DLLIMPORT jl_value_t *jl_memoryref_uint8_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_value_t *jl_memoryref_any_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_expr_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_binding_type JL_GLOBALLY_ROOTED; +extern JL_DLLIMPORT jl_datatype_t *jl_binding_partition_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_globalref_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_linenumbernode_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_gotonode_type JL_GLOBALLY_ROOTED; @@ -1523,6 +1544,7 @@ static inline int jl_field_isconst(jl_datatype_t *st, int i) JL_NOTSAFEPOINT #define jl_is_slotnumber(v) jl_typetagis(v,jl_slotnumber_type) #define jl_is_expr(v) jl_typetagis(v,jl_expr_type) #define jl_is_binding(v) jl_typetagis(v,jl_binding_type) +#define jl_is_binding_partition(v) jl_typetagis(v,jl_binding_partition_type) #define jl_is_globalref(v) jl_typetagis(v,jl_globalref_type) #define jl_is_gotonode(v) jl_typetagis(v,jl_gotonode_type) #define jl_is_gotoifnot(v) jl_typetagis(v,jl_gotoifnot_type) @@ -1821,8 +1843,8 @@ JL_DLLEXPORT jl_sym_t *jl_symbol_n(const char *str, size_t len) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_sym_t *jl_gensym(void); JL_DLLEXPORT jl_sym_t *jl_tagged_gensym(const char *str, size_t len); JL_DLLEXPORT jl_sym_t *jl_get_root_symbol(void); -JL_DLLEXPORT jl_value_t *jl_get_binding_value(jl_binding_t *b); -JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_const(jl_binding_t *b); +JL_DLLEXPORT jl_value_t *jl_get_binding_value(jl_binding_t *b JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_const(jl_binding_t *b JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_declare_const_gf(jl_binding_t *b); JL_DLLEXPORT jl_value_t *jl_get_or_declare_local_gf(jl_value_t **bp, jl_module_t *mod, jl_sym_t *name); JL_DLLEXPORT jl_method_t *jl_method_def(jl_svec_t *argdata, jl_methtable_t *mt, jl_code_info_t *f, jl_module_t *module); @@ -1985,8 +2007,8 @@ JL_DLLEXPORT jl_value_t *jl_checked_swap(jl_binding_t *b, jl_module_t *mod, jl_s JL_DLLEXPORT jl_value_t *jl_checked_replace(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *expected, jl_value_t *rhs); JL_DLLEXPORT jl_value_t *jl_checked_modify(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *op, jl_value_t *rhs); JL_DLLEXPORT jl_value_t *jl_checked_assignonce(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs JL_MAYBE_UNROOTED); -JL_DLLEXPORT void jl_declare_constant(jl_binding_t *b); -JL_DLLEXPORT void jl_declare_constant_val(jl_binding_t *b, jl_value_t *val); +JL_DLLEXPORT void jl_declare_constant(jl_binding_t *b) JL_NOTSAFEPOINT; +JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val(jl_binding_t *b JL_ROOTING_ARGUMENT, jl_value_t *val JL_ROOTED_ARGUMENT JL_MAYBE_UNROOTED) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_module_using(jl_module_t *to, jl_module_t *from); JL_DLLEXPORT void jl_module_use(jl_module_t *to, jl_module_t *from, jl_sym_t *s); JL_DLLEXPORT void jl_module_use_as(jl_module_t *to, jl_module_t *from, jl_sym_t *s, jl_sym_t *asname); diff --git a/src/julia_internal.h b/src/julia_internal.h index 0a5489e36f896..93ceac6de301e 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -861,24 +861,31 @@ jl_method_t *jl_make_opaque_closure_method(jl_module_t *module, jl_value_t *name int nargs, jl_value_t *functionloc, jl_code_info_t *ci, int isva, int isinferred); JL_DLLEXPORT int jl_is_valid_oc_argtype(jl_tupletype_t *argt, jl_method_t *source); -STATIC_INLINE int jl_binding_is_some_import(jl_binding_t *b) { +STATIC_INLINE int jl_bpart_is_some_import(jl_binding_partition_t *b) JL_NOTSAFEPOINT { if (!b) return 0; return b->kind == BINDING_KIND_IMPLICIT || b->kind == BINDING_KIND_EXPLICIT || b->kind == BINDING_KIND_IMPORTED; } -STATIC_INLINE int jl_binding_is_some_constant(jl_binding_t *b) { +STATIC_INLINE int jl_bpart_is_some_constant(jl_binding_partition_t *b) JL_NOTSAFEPOINT { if (!b) return 0; return b->kind == BINDING_KIND_CONST || b->kind == BINDING_KIND_CONST_IMPORT; } -STATIC_INLINE int jl_binding_is_some_guard(jl_binding_t *b) { +STATIC_INLINE int jl_bpart_is_some_guard(jl_binding_partition_t *b) JL_NOTSAFEPOINT { if (!b) return 1; return b->kind == BINDING_KIND_FAILED || b->kind == BINDING_KIND_GUARD || b->kind == BINDING_KIND_DECLARED; } +STATIC_INLINE jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b, size_t world) JL_NOTSAFEPOINT { + if (!b) + return NULL; + assert(jl_is_binding(b)); + return jl_atomic_load_relaxed(&b->partitions); +} + STATIC_INLINE int is_anonfn_typename(char *name) { if (name[0] != '#' || name[1] == '#') diff --git a/src/method.c b/src/method.c index 89c8e048f7a6e..e5c8371ce8ce1 100644 --- a/src/method.c +++ b/src/method.c @@ -223,10 +223,11 @@ static jl_value_t *resolve_globals(jl_value_t *expr, jl_module_t *module, jl_sve if (mod == module) { // Assignment does not create bindings in foreign modules (#54678) jl_binding_t *b = jl_get_module_binding(mod, name, 1); - if (b->kind == BINDING_KIND_GUARD || b->kind == BINDING_KIND_FAILED || b->kind == BINDING_KIND_DECLARED) { - b->kind = BINDING_KIND_GLOBAL; - b->restriction = (jl_value_t*)jl_any_type; - jl_gc_wb(b, jl_any_type); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (jl_bpart_is_some_guard(bpart)) { + bpart->kind = BINDING_KIND_GLOBAL; + bpart->restriction = (jl_value_t*)jl_any_type; + jl_gc_wb(bpart, jl_any_type); } } } @@ -1149,7 +1150,8 @@ JL_DLLEXPORT jl_value_t *jl_declare_const_gf(jl_binding_t *b) jl_check_gf(gf, b->globalref->name); return gf; } - if (!jl_binding_is_some_guard(b)) + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (!jl_bpart_is_some_guard(bpart)) jl_errorf("cannot define function %s; it already has a value", jl_symbol_name(b->globalref->name)); gf = (jl_value_t*)jl_new_generic_function(b->globalref->name, b->globalref->mod); jl_declare_constant_val(b, gf); diff --git a/src/module.c b/src/module.c index 3068027660141..d6b34dd9e56d3 100644 --- a/src/module.c +++ b/src/module.c @@ -167,20 +167,32 @@ static jl_globalref_t *jl_new_globalref(jl_module_t *mod, jl_sym_t *name, jl_bin return g; } +static jl_binding_partition_t *new_binding_partition(void) +{ + jl_binding_partition_t *bpart = (jl_binding_partition_t*)jl_gc_alloc(jl_current_task->ptls, sizeof(jl_binding_partition_t), jl_binding_partition_type); + bpart->restriction = NULL; + bpart->min_world = 0; + jl_atomic_store_relaxed(&bpart->max_world, (size_t)-1); + jl_atomic_store_relaxed(&bpart->next, NULL); + bpart->kind = BINDING_KIND_GUARD; + return bpart; +} + static jl_binding_t *new_binding(jl_module_t *mod, jl_sym_t *name) { jl_task_t *ct = jl_current_task; assert(jl_is_module(mod) && jl_is_symbol(name)); jl_binding_t *b = (jl_binding_t*)jl_gc_alloc(ct->ptls, sizeof(jl_binding_t), jl_binding_type); jl_atomic_store_relaxed(&b->value, NULL); - jl_atomic_store_relaxed(&b->restriction, NULL); b->globalref = NULL; b->exportp = 0; b->publicp = 0; - b->kind = BINDING_KIND_GUARD; b->deprecated = 0; JL_GC_PUSH1(&b); b->globalref = jl_new_globalref(mod, name, b); + jl_binding_partition_t *bpart = new_binding_partition(); + jl_atomic_store_relaxed(&b->partitions, bpart); + jl_gc_wb(b, bpart); JL_GC_POP(); return b; } @@ -218,12 +230,14 @@ static jl_module_t *jl_binding_dbgmodule(jl_binding_t *b, jl_module_t *m, jl_sym JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, int alloc) { jl_binding_t *b = jl_get_module_binding(m, var, 1); - if (b->kind != BINDING_KIND_GLOBAL) { - if (b->kind == BINDING_KIND_GUARD || b->kind == BINDING_KIND_FAILED || b->kind == BINDING_KIND_DECLARED) { + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (bpart->kind != BINDING_KIND_GLOBAL) { + if (jl_bpart_is_some_guard(bpart)) { check_safe_newbinding(m, var); if (!alloc) jl_errorf("Global %s.%s does not exist and cannot be assigned. Declare it using `global` before attempting assignment.", jl_symbol_name(m->name), jl_symbol_name(var)); - b->kind = BINDING_KIND_GLOBAL; + bpart->kind = BINDING_KIND_GLOBAL; + bpart->restriction = (jl_value_t*)jl_any_type; } else { jl_module_t *from = jl_binding_dbgmodule(b, m, var); if (from == m) @@ -248,26 +262,30 @@ JL_DLLEXPORT jl_module_t *jl_get_module_of_binding(jl_module_t *m, jl_sym_t *var JL_DLLEXPORT jl_value_t *jl_get_binding_value(jl_binding_t *b) { - while (jl_binding_is_some_import(b)) { - b = (jl_binding_t*)b->restriction; + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + while (jl_bpart_is_some_import(bpart)) { + b = (jl_binding_t*)bpart->restriction; + bpart = jl_get_binding_partition(b, jl_current_task->world_age); } - if (jl_binding_is_some_guard(b)) + if (jl_bpart_is_some_guard(bpart)) return NULL; - if (jl_binding_is_some_constant(b)) - return b->restriction; + if (jl_bpart_is_some_constant(bpart)) + return bpart->restriction; return jl_atomic_load_relaxed(&b->value); } JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_const(jl_binding_t *b) { - while (jl_binding_is_some_import(b)) { - b = (jl_binding_t*)b->restriction; + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + while (jl_bpart_is_some_import(bpart)) { + b = (jl_binding_t*)bpart->restriction; + bpart = jl_get_binding_partition(b, jl_current_task->world_age); } - if (jl_binding_is_some_guard(b)) + if (jl_bpart_is_some_guard(bpart)) return NULL; - if (!jl_binding_is_some_constant(b)) + if (!jl_bpart_is_some_constant(bpart)) return NULL; - return b->restriction; + return bpart->restriction; } typedef struct _modstack_t { @@ -279,7 +297,8 @@ static jl_binding_t *jl_resolve_owner(jl_binding_t *b/*optional*/, jl_module_t * JL_DLLEXPORT jl_value_t *jl_reresolve_binding_value(jl_binding_t *b) { - if (b->kind == BINDING_KIND_GUARD || b->kind == BINDING_KIND_FAILED || b->kind == BINDING_KIND_DECLARED) { + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (jl_bpart_is_some_guard(bpart)) { jl_resolve_owner(b, b->globalref->mod, b->globalref->name, NULL); } return jl_get_binding_value(b); @@ -290,8 +309,9 @@ JL_DLLEXPORT jl_value_t *jl_reresolve_binding_value(jl_binding_t *b) JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_t *var) { jl_binding_t *b = jl_get_module_binding(m, var, 1); - if (b->kind != BINDING_KIND_GLOBAL && !jl_binding_is_some_constant(b)) { - if (b->kind == BINDING_KIND_GUARD || b->kind == BINDING_KIND_FAILED || b->kind == BINDING_KIND_DECLARED) { + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (bpart->kind != BINDING_KIND_GLOBAL && !jl_bpart_is_some_constant(bpart)) { + if (jl_bpart_is_some_guard(bpart)) { check_safe_newbinding(m, var); return b; } @@ -304,7 +324,7 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_ } // TODO: we might want to require explicitly importing types to add constructors // or we might want to drop this error entirely - if (b->kind != BINDING_KIND_IMPORTED && !(f && jl_is_type(f) && strcmp(jl_symbol_name(var), "=>") != 0)) { + if (bpart->kind != BINDING_KIND_IMPORTED && !(f && jl_is_type(f) && strcmp(jl_symbol_name(var), "=>") != 0)) { jl_module_t *from = jl_binding_dbgmodule(b, m, var); jl_errorf("invalid method definition in %s: function %s.%s must be explicitly imported to be extended", jl_symbol_name(m->name), jl_symbol_name(from->name), jl_symbol_name(var)); @@ -324,24 +344,28 @@ static inline jl_module_t *module_usings_getidx(jl_module_t *m JL_PROPAGATES_ROO } #endif -static int eq_bindings(jl_binding_t *owner, jl_binding_t *alias) +static int eq_bindings(jl_binding_partition_t *owner, jl_binding_t *alias, size_t world) { - assert(owner->kind == BINDING_KIND_GLOBAL || jl_binding_is_some_constant(owner)); - if (owner == alias) + assert(owner->kind == BINDING_KIND_GLOBAL || jl_bpart_is_some_constant(owner)); + jl_binding_partition_t *alias_bpart = jl_get_binding_partition(alias, world); + if (owner == alias_bpart) return 1; - if (alias->kind == BINDING_KIND_GLOBAL || jl_binding_is_some_guard(alias)) + if (alias_bpart->kind == BINDING_KIND_GLOBAL || jl_bpart_is_some_guard(alias_bpart)) return 0; - while (jl_binding_is_some_import(alias)) - alias = (jl_binding_t*)alias->restriction; - if (jl_binding_is_some_constant(owner) && jl_binding_is_some_constant(alias) && jl_atomic_load_relaxed(&owner->restriction) && jl_atomic_load_relaxed(&alias->restriction) == jl_atomic_load_relaxed(&owner->restriction)) + while (jl_bpart_is_some_import(alias_bpart)) { + alias = (jl_binding_t*)alias_bpart->restriction; + alias_bpart = jl_get_binding_partition(alias, world); + } + if (jl_bpart_is_some_constant(owner) && jl_bpart_is_some_constant(alias_bpart) && owner->restriction && alias_bpart->restriction == owner->restriction) return 1; - return owner == alias; + return owner == alias_bpart; } // find a binding from a module's `usings` list static jl_binding_t *using_resolve_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, jl_module_t **from, modstack_t *st, int warn) { jl_binding_t *b = NULL; + jl_binding_partition_t *bpart = NULL; jl_module_t *owner = NULL; JL_LOCK(&m->lock); int i = (int)m->usings.len - 1; @@ -356,13 +380,15 @@ static jl_binding_t *using_resolve_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl if (tempb == NULL) // couldn't resolve; try next using (see issue #6105) continue; - assert(tempb->kind == BINDING_KIND_GLOBAL || jl_binding_is_some_constant(tempb)); - if (b != NULL && !tempb->deprecated && !b->deprecated && !eq_bindings(tempb, b)) { + jl_binding_partition_t *tempbpart = jl_get_binding_partition(tempb, jl_current_task->world_age); + assert(tempbpart->kind == BINDING_KIND_GLOBAL || jl_bpart_is_some_constant(tempbpart)); + if (bpart != NULL && !tempb->deprecated && !b->deprecated && !eq_bindings(tempbpart, b, jl_current_task->world_age)) { if (warn) { // set usingfailed=1 to avoid repeating this warning // the owner will still be NULL, so it can be later imported or defined tempb = jl_get_module_binding(m, var, 1); - tempb->kind = BINDING_KIND_FAILED; + tempbpart = jl_get_binding_partition(tempb, jl_current_task->world_age); + tempbpart->kind = BINDING_KIND_FAILED; jl_printf(JL_STDERR, "WARNING: both %s and %s export \"%s\"; uses of it in module %s must be qualified\n", jl_symbol_name(owner->name), @@ -374,6 +400,7 @@ static jl_binding_t *using_resolve_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl if (owner == NULL || !tempb->deprecated) { owner = imp; b = tempb; + bpart = tempbpart; } } } @@ -385,12 +412,14 @@ static jl_binding_t *using_resolve_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl // this might not be the same as the owner of the binding, since the binding itself may itself have been imported from elsewhere static jl_module_t *jl_binding_dbgmodule(jl_binding_t *b, jl_module_t *m, jl_sym_t *var) { - if (b->kind != BINDING_KIND_GLOBAL) { + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (bpart->kind != BINDING_KIND_GLOBAL) { // for implicitly imported globals, try to re-resolve it to find the module we got it from most directly jl_module_t *from = NULL; jl_binding_t *b2 = using_resolve_binding(m, var, &from, NULL, 0); if (b2) { - if (eq_bindings(b2, b)) + jl_binding_partition_t *b2part = jl_get_binding_partition(b2, jl_current_task->world_age); + if (eq_bindings(b2part, b, jl_current_task->world_age)) return from; // if we did not find it (or accidentally found a different one), ignore this } @@ -405,12 +434,13 @@ static jl_binding_t *jl_resolve_owner(jl_binding_t *b/*optional*/, jl_module_t * { if (b == NULL) b = jl_get_module_binding(m, var, 1); - if (b->kind == BINDING_KIND_FAILED) + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (bpart->kind == BINDING_KIND_FAILED) return NULL; - if (b->kind == BINDING_KIND_DECLARED) { + if (bpart->kind == BINDING_KIND_DECLARED) { return NULL; } - if (b->kind == BINDING_KIND_GUARD) { + if (bpart->kind == BINDING_KIND_GUARD) { jl_binding_t *b2 = NULL; modstack_t top = { m, var, st }; modstack_t *tmp = st; @@ -434,8 +464,8 @@ static jl_binding_t *jl_resolve_owner(jl_binding_t *b/*optional*/, jl_module_t * } // do a full import to prevent the result of this lookup from // changing, for example if this var is assigned to later. - b->kind = BINDING_KIND_IMPLICIT; - b->restriction = (jl_value_t*)b2; + bpart->kind = BINDING_KIND_IMPLICIT; + bpart->restriction = (jl_value_t*)b2; if (b2->deprecated) { b->deprecated = 1; // we will warn about this below, but we might want to warn at the use sites too if (m != jl_main_module && m != jl_base_module && @@ -452,8 +482,9 @@ static jl_binding_t *jl_resolve_owner(jl_binding_t *b/*optional*/, jl_module_t * } return b2; } - while (jl_binding_is_some_import(b)) { - b = (jl_binding_t*)b->restriction; + while (jl_bpart_is_some_import(bpart)) { + b = (jl_binding_t*)bpart->restriction; + bpart = jl_get_binding_partition(b, jl_current_task->world_age); } return b; } @@ -462,12 +493,15 @@ static jl_binding_t *jl_resolve_owner(jl_binding_t *b/*optional*/, jl_module_t * JL_DLLEXPORT jl_binding_t *jl_binding_owner(jl_module_t *m, jl_sym_t *var) { jl_binding_t *b = jl_get_module_binding(m, var, 1); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); jl_module_t *from = m; - if (b->kind == BINDING_KIND_GUARD) + if (bpart->kind == BINDING_KIND_GUARD) b = using_resolve_binding(m, var, &from, NULL, 0); - while (jl_binding_is_some_import(b)) - b = (jl_binding_t*)b->restriction; - if (b && b->kind != BINDING_KIND_GLOBAL) + while (jl_bpart_is_some_import(bpart)) { + b = (jl_binding_t*)bpart->restriction; + bpart = jl_get_binding_partition(b, jl_current_task->world_age); + } + if (bpart && bpart->kind != BINDING_KIND_GLOBAL && !jl_bpart_is_some_constant(bpart)) return NULL; return b; } @@ -476,15 +510,18 @@ JL_DLLEXPORT jl_binding_t *jl_binding_owner(jl_module_t *m, jl_sym_t *var) JL_DLLEXPORT jl_value_t *jl_get_binding_type(jl_module_t *m, jl_sym_t *var) { jl_binding_t *b = jl_get_module_binding(m, var, 0); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); if (b == NULL) return jl_nothing; - if (b->kind == BINDING_KIND_GUARD || b->kind == BINDING_KIND_FAILED || b->kind == BINDING_KIND_DECLARED) + while (jl_bpart_is_some_import(bpart)) { + b = (jl_binding_t*)bpart->restriction; + bpart = jl_get_binding_partition(b, jl_current_task->world_age); + } + if (jl_bpart_is_some_guard(bpart)) return jl_nothing; - while (jl_binding_is_some_import(b)) - b = (jl_binding_t*)b->restriction; - if (jl_binding_is_some_constant(b)) - return jl_typeof(b->restriction); - return b->restriction; + if (jl_bpart_is_some_constant(bpart)) + return jl_typeof(bpart->restriction); + return bpart->restriction; } JL_DLLEXPORT jl_binding_t *jl_get_binding(jl_module_t *m, jl_sym_t *var) @@ -515,7 +552,8 @@ JL_DLLEXPORT jl_value_t *jl_module_globalref(jl_module_t *m, jl_sym_t *var) JL_DLLEXPORT int jl_is_imported(jl_module_t *m, jl_sym_t *var) { jl_binding_t *b = jl_get_module_binding(m, var, 0); - return b && b->kind == BINDING_KIND_IMPORTED; + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + return b && bpart->kind == BINDING_KIND_IMPORTED; } extern const char *jl_filename; @@ -582,7 +620,8 @@ static void module_import_(jl_module_t *to, jl_module_t *from, jl_sym_t *asname, jl_symbol_name(to->name)); } else { - assert(b->kind == BINDING_KIND_GLOBAL || jl_binding_is_some_constant(b)); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + assert(bpart->kind == BINDING_KIND_GLOBAL || jl_bpart_is_some_constant(bpart)); if (b->deprecated) { if (jl_get_binding_value(b) == jl_nothing) { // silently skip importing deprecated values assigned to nothing (to allow later mutation) @@ -608,19 +647,19 @@ static void module_import_(jl_module_t *to, jl_module_t *from, jl_sym_t *asname, // importing a binding on top of itself. harmless. return; } - jl_binding_t *ownerto = NULL; - if (bto->kind == BINDING_KIND_GUARD || bto->kind == BINDING_KIND_IMPLICIT) { - bto->kind = (explici != 0) ? BINDING_KIND_IMPORTED : BINDING_KIND_EXPLICIT; + jl_binding_partition_t *btopart = jl_get_binding_partition(bto, jl_current_task->world_age); + if (btopart->kind == BINDING_KIND_GUARD || btopart->kind == BINDING_KIND_IMPLICIT) { + btopart->kind = (explici != 0) ? BINDING_KIND_IMPORTED : BINDING_KIND_EXPLICIT; + btopart->restriction = (jl_value_t*)b; bto->deprecated |= b->deprecated; // we already warned about this above, but we might want to warn at the use sites too - bto->restriction = (jl_value_t*)b; } else { - if (eq_bindings(b, bto)) { + if (eq_bindings(bpart, bto, jl_current_task->world_age)) { // already imported - potentially upgrade to _IMPORTED or _EXPLICIT - bto->kind = (explici != 0) ? BINDING_KIND_IMPORTED : BINDING_KIND_EXPLICIT; - assert((jl_binding_t*)bto->restriction == b); + btopart->kind = (explici != 0) ? BINDING_KIND_IMPORTED : BINDING_KIND_EXPLICIT; + assert((jl_binding_t*)btopart->restriction == b); } - else if (ownerto != bto) { + else if (jl_bpart_is_some_import(btopart)) { // already imported from somewhere else jl_printf(JL_STDERR, "WARNING: ignoring conflicting import of %s.%s into %s\n", @@ -682,17 +721,21 @@ JL_DLLEXPORT void jl_module_using(jl_module_t *to, jl_module_t *from) jl_binding_t *b = (jl_binding_t*)jl_svecref(table, i); if ((void*)b == jl_nothing) break; - if (b->exportp && (b->kind == BINDING_KIND_GLOBAL || b->kind == BINDING_KIND_IMPORTED)) { + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (b->exportp && (bpart->kind == BINDING_KIND_GLOBAL || bpart->kind == BINDING_KIND_IMPORTED)) { jl_sym_t *var = b->globalref->name; jl_binding_t *tob = jl_get_module_binding(to, var, 0); if (tob) { - while (jl_binding_is_some_import(tob)) - tob = (jl_binding_t*)tob->restriction; - if (tob && tob->kind != BINDING_KIND_GUARD && + jl_binding_partition_t *tobpart = jl_get_binding_partition(tob, jl_current_task->world_age); + while (jl_bpart_is_some_import(tobpart)) { + tob = (jl_binding_t*)tobpart->restriction; + tobpart = jl_get_binding_partition(tob, jl_current_task->world_age); + } + if (tob && tobpart->kind != BINDING_KIND_GUARD && // don't warn for conflicts with the module name itself. // see issue #4715 var != to->name && - !eq_bindings(tob, b)) { + !eq_bindings(tobpart, b, jl_current_task->world_age)) { jl_printf(JL_STDERR, "WARNING: using %s.%s in module %s conflicts with an existing identifier.\n", jl_symbol_name(from->name), jl_symbol_name(var), @@ -729,7 +772,8 @@ JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var) // unlike most queries JL_DLLEXPORT int jl_defines_or_exports_p(jl_module_t *m, jl_sym_t *var) { jl_binding_t *b = jl_get_module_binding(m, var, 0); - return b && (b->exportp || b->kind == BINDING_KIND_GLOBAL); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + return b && (b->exportp || bpart->kind == BINDING_KIND_GLOBAL); } JL_DLLEXPORT int jl_module_exports_p(jl_module_t *m, jl_sym_t *var) @@ -747,7 +791,8 @@ JL_DLLEXPORT int jl_module_public_p(jl_module_t *m, jl_sym_t *var) JL_DLLEXPORT int jl_binding_resolved_p(jl_module_t *m, jl_sym_t *var) { jl_binding_t *b = jl_get_module_binding(m, var, 0); - return b && b->kind != BINDING_KIND_GUARD && b->kind != BINDING_KIND_FAILED && b->kind != BINDING_KIND_DECLARED; + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + return !jl_bpart_is_some_guard(bpart); } static uint_t bindingkey_hash(size_t idx, jl_value_t *data) @@ -843,16 +888,18 @@ JL_DLLEXPORT void jl_set_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var { // this function is mostly only used during initialization, so the data races here are not too important to us jl_binding_t *bp = jl_get_module_binding(m, var, 1); - bp->kind = BINDING_KIND_CONST; - bp->restriction = val; - jl_gc_wb(bp, val); + jl_binding_partition_t *bpart = jl_get_binding_partition(bp, jl_current_task->world_age); + bpart->kind = BINDING_KIND_CONST; + bpart->restriction = val; + jl_gc_wb(bpart, val); } JL_DLLEXPORT int jl_globalref_is_const(jl_globalref_t *gr) { jl_binding_t *b = gr->binding; b = jl_resolve_owner(b, gr->mod, gr->name, NULL); - return jl_binding_is_some_constant(b); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + return jl_bpart_is_some_constant(bpart); } JL_DLLEXPORT int jl_globalref_boundp(jl_globalref_t *gr) @@ -865,7 +912,8 @@ JL_DLLEXPORT int jl_globalref_boundp(jl_globalref_t *gr) JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var) { jl_binding_t *b = jl_get_binding(m, var); - return b && jl_binding_is_some_constant(b); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + return b && jl_bpart_is_some_constant(bpart); } // set the deprecated flag for a binding: @@ -895,7 +943,6 @@ void jl_binding_deprecation_warning(jl_module_t *m, jl_sym_t *s, jl_binding_t *b if (b->deprecated == 1 && jl_options.depwarn) { if (jl_options.depwarn != JL_OPTIONS_DEPWARN_ERROR) jl_printf(JL_STDERR, "WARNING: "); - assert(b->kind == BINDING_KIND_GLOBAL); jl_printf(JL_STDERR, "%s.%s is deprecated", jl_symbol_name(m->name), jl_symbol_name(s)); jl_binding_dep_message(m, s, b); @@ -916,23 +963,20 @@ void jl_binding_deprecation_warning(jl_module_t *m, jl_sym_t *s, jl_binding_t *b jl_value_t *jl_check_binding_wr(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs JL_MAYBE_UNROOTED, int reassign) { - jl_value_t *old_ty = NULL; - if (!jl_atomic_cmpswap_relaxed(&b->restriction, &old_ty, (jl_value_t*)jl_any_type)) { - if (old_ty != (jl_value_t*)jl_any_type && jl_typeof(rhs) != old_ty) { - JL_GC_PUSH1(&rhs); // callee-rooted - if (!jl_isa(rhs, old_ty)) - jl_errorf("cannot assign an incompatible value to the global %s.%s.", - jl_symbol_name(mod->name), jl_symbol_name(var)); - JL_GC_POP(); - } - } - else { - old_ty = (jl_value_t*)jl_any_type; - } - if (jl_binding_is_some_constant(b)) { + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + assert(!jl_bpart_is_some_guard(bpart) && !jl_bpart_is_some_import(bpart)); + if (jl_bpart_is_some_constant(bpart)) { jl_errorf("invalid redefinition of constant %s.%s", jl_symbol_name(mod->name), jl_symbol_name(var)); } + jl_value_t *old_ty = bpart->restriction; + if (old_ty != (jl_value_t*)jl_any_type && jl_typeof(rhs) != old_ty) { + JL_GC_PUSH1(&rhs); // callee-rooted + if (!jl_isa(rhs, old_ty)) + jl_errorf("cannot assign an incompatible value to the global %s.%s.", + jl_symbol_name(mod->name), jl_symbol_name(var)); + JL_GC_POP(); + } return old_ty; } @@ -962,12 +1006,12 @@ JL_DLLEXPORT jl_value_t *jl_checked_replace(jl_binding_t *b, jl_module_t *mod, j JL_DLLEXPORT jl_value_t *jl_checked_modify(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *op, jl_value_t *rhs) { - jl_value_t *ty = NULL; - if (jl_atomic_cmpswap_relaxed(&b->restriction, &ty, (jl_value_t*)jl_any_type)) - ty = (jl_value_t*)jl_any_type; - if (jl_binding_is_some_constant(b)) + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + assert(!jl_bpart_is_some_guard(bpart) && !jl_bpart_is_some_import(bpart)); + if (jl_bpart_is_some_constant(bpart)) jl_errorf("invalid redefinition of constant %s.%s", jl_symbol_name(mod->name), jl_symbol_name(var)); + jl_value_t *ty = bpart->restriction; return modify_value(ty, &b->value, (jl_value_t*)b, op, rhs, 1, mod, var); } @@ -982,13 +1026,14 @@ JL_DLLEXPORT jl_value_t *jl_checked_assignonce(jl_binding_t *b, jl_module_t *mod JL_DLLEXPORT void jl_declare_constant(jl_binding_t *b) { - if (jl_binding_is_some_constant(b)) + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (jl_bpart_is_some_constant(bpart)) return; - if (b->kind != BINDING_KIND_GUARD && b->kind != BINDING_KIND_FAILED && b->kind != BINDING_KIND_DECLARED) { + if (!jl_bpart_is_some_guard(bpart)) { jl_errorf("cannot declare %s.%s constant; it already has a value", jl_symbol_name(b->globalref->mod->name), jl_symbol_name(b->globalref->name)); } - b->kind = BINDING_KIND_CONST; + bpart->kind = BINDING_KIND_CONST; } JL_DLLEXPORT jl_value_t *jl_module_usings(jl_module_t *m) @@ -1007,10 +1052,6 @@ JL_DLLEXPORT jl_value_t *jl_module_usings(jl_module_t *m) return (jl_value_t*)a; } -uint8_t _binding_is_from_explicit_using(jl_binding_t *b) { - return b->kind == BINDING_KIND_EXPLICIT; -} - void _append_symbol_to_bindings_array(jl_array_t* a, jl_sym_t *name) { jl_array_grow_end(a, 1); //XXX: change to jl_arrayset if array storage allocation for Array{Symbols,1} changes: @@ -1022,20 +1063,21 @@ static int should_append_binding(jl_module_t *m, jl_binding_t *b, int non_public jl_sym_t *asname = b->globalref->name; int isgenerated = jl_symbol_name(asname)[0]=='#'; int main_public = (m == jl_main_module && !(asname == jl_eval_sym || asname == jl_include_sym)); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); if (b->deprecated && !deprecated) return 0; if (isgenerated && !generated) return 0; - if (b->kind == BINDING_KIND_CONST_IMPORT) // CONST_IMPORT is bit of a hybrid that's gated by the `imported` flag. + if (bpart->kind == BINDING_KIND_CONST_IMPORT) // CONST_IMPORT is bit of a hybrid that's gated by the `imported` flag. return imported; - if (b->kind == BINDING_KIND_GLOBAL || jl_binding_is_some_constant(b)) { + if (bpart->kind == BINDING_KIND_GLOBAL || jl_bpart_is_some_constant(bpart)) { // if it is owned by this module, check if the binding is public: // one exception is bindings imported from other modules, // which might also be owned by this module return non_public || b->publicp || main_public; - } else if (b->kind == BINDING_KIND_IMPORTED) { + } else if (bpart->kind == BINDING_KIND_IMPORTED) { return imported; - } else if (b->kind == BINDING_KIND_EXPLICIT) { + } else if (bpart->kind == BINDING_KIND_EXPLICIT) { return usings_explicit; } return 0; @@ -1122,9 +1164,10 @@ JL_DLLEXPORT void jl_clear_implicit_imports(jl_module_t *m) jl_binding_t *b = (jl_binding_t*)jl_svecref(table, i); if ((void*)b == jl_nothing) break; - if (b->kind == BINDING_KIND_IMPLICIT) { - b->kind = BINDING_KIND_GUARD; - b->restriction = NULL; + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (bpart->kind == BINDING_KIND_IMPLICIT) { + bpart->kind = BINDING_KIND_GUARD; + bpart->restriction = NULL; } } JL_UNLOCK(&m->lock); diff --git a/src/staticdata.c b/src/staticdata.c index ed7174e622541..9f362323859ef 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -100,7 +100,7 @@ extern "C" { // TODO: put WeakRefs on the weak_refs list during deserialization // TODO: handle finalizers -#define NUM_TAGS 191 +#define NUM_TAGS 192 // An array of references that need to be restored from the sysimg // This is a manually constructed dual of the gvars array, which would be produced by codegen for Julia code, for C. @@ -122,6 +122,7 @@ jl_value_t **const*const get_tags(void) { INSERT_TAG(jl_array_type); INSERT_TAG(jl_expr_type); INSERT_TAG(jl_binding_type); + INSERT_TAG(jl_binding_partition_type); INSERT_TAG(jl_globalref_type); INSERT_TAG(jl_string_type); INSERT_TAG(jl_module_type); @@ -912,7 +913,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ for (i = 0; i < np; i++) { uint32_t ptr = jl_ptr_offset(t, i); int mutabl = t->name->mutabl; - if (jl_is_binding(v) && jl_binding_is_some_constant(((jl_binding_t*)v)) && i == 2) // value field depends on constp field + if (jl_is_binding_partition(v) && jl_bpart_is_some_constant(((jl_binding_partition_t*)v)) && i == 0) // value field depends on constp field mutabl = 0; jl_value_t *fld = get_replaceable_field(&((jl_value_t**)data)[ptr], mutabl); jl_queue_for_serialization_(s, fld, 1, immediate); @@ -1352,12 +1353,6 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED jl_binding_t *b = (jl_binding_t*)v; if (b->globalref == NULL || jl_object_in_image((jl_value_t*)b->globalref->mod)) jl_error("Binding cannot be serialized"); // no way (currently) to recover its identity - // Assign type Any to any owned bindings that don't have a type. - // We don't want these accidentally managing to diverge later in different compilation units. - if (b->kind == BINDING_KIND_GLOBAL) { - if (!b->restriction) - jl_atomic_store_relaxed(&b->restriction, (jl_value_t*)jl_any_type); - } } } @@ -1570,7 +1565,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED for (i = 0; i < np; i++) { size_t offset = jl_ptr_offset(t, i) * sizeof(jl_value_t*); int mutabl = t->name->mutabl; - if (jl_is_binding(v) && jl_binding_is_some_constant((jl_binding_t*)v) && i == 2) // value field depends on constp field + if (jl_is_binding_partition(v) && jl_bpart_is_some_constant((jl_binding_partition_t*)v) && i == 0) // value field depends on constp field mutabl = 0; jl_value_t *fld = get_replaceable_field((jl_value_t**)&data[offset], mutabl); size_t fld_pos = offset + reloc_offset; diff --git a/src/toplevel.c b/src/toplevel.c index 216730a8c2b11..1da46ff194dc1 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -156,22 +156,11 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex } else { jl_binding_t *b = jl_get_module_binding(parent_module, name, 1); - jl_declare_constant(b); - jl_value_t *old = NULL; - if (!jl_atomic_cmpswap(&b->restriction, &old, (jl_value_t*)newm)) { - if (!jl_is_module(old)) { - jl_errorf("invalid redefinition of constant %s", jl_symbol_name(name)); - } - if (jl_generating_output()) - jl_errorf("cannot replace module %s during compilation", jl_symbol_name(name)); - jl_printf(JL_STDERR, "WARNING: replacing module %s.\n", jl_symbol_name(name)); - old = jl_atomic_exchange(&b->restriction, (jl_value_t*)newm); - } - jl_gc_wb(b, newm); - if (old != NULL) { + jl_binding_partition_t *bpart = jl_declare_constant_val(b, (jl_value_t*)newm); + if (bpart->next != NULL) { // create a hidden gc root for the old module JL_LOCK(&jl_modules_mutex); - uintptr_t *refcnt = (uintptr_t*)ptrhash_bp(&jl_current_modules, (void*)old); + uintptr_t *refcnt = (uintptr_t*)ptrhash_bp(&jl_current_modules, (void*)bpart->next->restriction); *refcnt += 1; JL_UNLOCK(&jl_modules_mutex); } @@ -289,28 +278,29 @@ static jl_value_t *jl_eval_dot_expr(jl_module_t *m, jl_value_t *x, jl_value_t *f void jl_binding_set_type(jl_binding_t *b, jl_value_t *ty, int error) { - if (b->kind) { - if (b->kind == BINDING_KIND_GUARD || b->kind == BINDING_KIND_FAILED || b->kind == BINDING_KIND_DECLARED) { - b->kind = BINDING_KIND_GLOBAL; - b->restriction = ty; - jl_gc_wb(b, ty); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (bpart->kind != BINDING_KIND_GLOBAL) { + if (jl_bpart_is_some_guard(bpart)) { + bpart->kind = BINDING_KIND_GLOBAL; + bpart->restriction = ty; + jl_gc_wb(bpart, ty); return; } else { jl_errorf("cannot set type for imported global %s.%s.", jl_symbol_name(jl_globalref_mod(b->globalref)->name), jl_symbol_name(jl_globalref_name(b->globalref))); } } - if (jl_binding_is_some_constant(b)) { + if (jl_bpart_is_some_constant(bpart)) { jl_errorf("cannot set type for imported constant %s.%s.", jl_symbol_name(jl_globalref_mod(b->globalref)->name), jl_symbol_name(jl_globalref_name(b->globalref))); } - jl_value_t *old_ty = b->restriction; + jl_value_t *old_ty = bpart->restriction; if (!jl_types_equal(ty, old_ty)) { 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(jl_globalref_mod(b->globalref)->name), jl_symbol_name(jl_globalref_name(b->globalref))); } - b->restriction = ty; - jl_gc_wb(b, ty); + bpart->restriction = ty; + jl_gc_wb(bpart, ty); } void jl_declare_global(jl_module_t *m, jl_value_t *arg, jl_value_t *set_type) { @@ -328,8 +318,9 @@ void jl_declare_global(jl_module_t *m, jl_value_t *arg, jl_value_t *set_type) { gs = (jl_sym_t*)arg; } jl_binding_t *b = jl_get_module_binding(gm, gs, 1); - if (b->kind == BINDING_KIND_GUARD || b->kind == BINDING_KIND_FAILED) { - b->kind = BINDING_KIND_DECLARED; + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (bpart->kind == BINDING_KIND_GUARD || bpart->kind == BINDING_KIND_FAILED) { + bpart->kind = BINDING_KIND_DECLARED; } if (set_type) { jl_binding_set_type(b, set_type, 1); @@ -640,12 +631,13 @@ static void import_module(jl_module_t *JL_NONNULL m, jl_module_t *import, jl_sym jl_binding_t *b = jl_get_module_binding(m, name, 1); if (jl_get_binding_value_if_const(b) == (jl_value_t*)import) return; - if (b->kind != BINDING_KIND_GUARD && b->kind != BINDING_KIND_FAILED) { + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (bpart->kind != BINDING_KIND_GUARD && bpart->kind != BINDING_KIND_FAILED) { jl_errorf("importing %s into %s conflicts with an existing global", jl_symbol_name(name), jl_symbol_name(m->name)); } jl_declare_constant_val(b, (jl_value_t*)import); - b->kind = BINDING_KIND_CONST_IMPORT; + bpart->kind = BINDING_KIND_CONST_IMPORT; } // in `import A.B: x, y, ...`, evaluate the `A.B` part if it exists @@ -707,18 +699,20 @@ static void jl_eval_errorf(jl_module_t *m, const char *filename, int lineno, con JL_GC_POP(); } -JL_DLLEXPORT void jl_declare_constant_val(jl_binding_t *b, jl_value_t *val) +JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val(jl_binding_t *b, jl_value_t *val) { jl_declare_constant(b); - if (b->restriction) { - if (jl_egal(val, b->restriction)) - return; + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (bpart->restriction) { + if (jl_egal(val, bpart->restriction)) + return bpart; jl_errorf("invalid redefinition of constant %s.%s", jl_symbol_name(b->globalref->mod->name), jl_symbol_name(b->globalref->name)); } - b->restriction = val; - jl_gc_wb(b, val); + bpart->restriction = val; + jl_gc_wb(bpart, val); + return bpart; } JL_DLLEXPORT void jl_eval_const_decl(jl_module_t *m, jl_value_t *arg, jl_value_t *val) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 19ab6f6b88e1c..22bd9ad2a5179 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -46,7 +46,7 @@ function UndefVarError_hint(io::IO, ex::UndefVarError) # This is the common case, so do not print that information. # It could be the binding was exported by two modules, which we can detect # by the `usingfailed` flag in the binding: - if isdefined(bnd, :flags) && Bool(bnd.flags >> 4 & 1) # magic location of the `usingfailed` flag + if false # TODO: #isdefined(bnd, :flags) && Bool(bnd.flags >> 4 & 1) # magic location of the `usingfailed` flag print(io, "\nHint: It looks like two or more modules export different ", "bindings with this name, resulting in ambiguity. Try explicitly ", "importing it from a particular module, or qualifying the name ",