Skip to content

Commit

Permalink
Give undefined constants their own binding kind (#56968)
Browse files Browse the repository at this point in the history
As noted in
#56649 (comment),
there needs to be a separate kind for undefined constants, so we know
whether or not it is safe to call `partition_restriction`.
  • Loading branch information
Keno authored Jan 7, 2025
1 parent 22134ca commit ec2b509
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 14 deletions.
6 changes: 4 additions & 2 deletions base/runtime_internals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,12 @@ const BINDING_KIND_IMPORTED = 0x5
const BINDING_KIND_FAILED = 0x6
const BINDING_KIND_DECLARED = 0x7
const BINDING_KIND_GUARD = 0x8
const BINDING_KIND_UNDEF_CONST = 0x9

is_some_const_binding(kind::UInt8) = (kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT)
is_defined_const_binding(kind::UInt8) = (kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT)
is_some_const_binding(kind::UInt8) = (is_defined_const_binding(kind) || kind == BINDING_KIND_UNDEF_CONST)
is_some_imported(kind::UInt8) = (kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_EXPLICIT || kind == BINDING_KIND_IMPORTED)
is_some_guard(kind::UInt8) = (kind == BINDING_KIND_GUARD || kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_FAILED)
is_some_guard(kind::UInt8) = (kind == BINDING_KIND_GUARD || kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_FAILED || kind == BINDING_KIND_UNDEF_CONST)

function lookup_binding_partition(world::UInt, b::Core.Binding)
ccall(:jl_get_binding_partition, Ref{Core.BindingPartition}, (Any, UInt), b, world)
Expand Down
6 changes: 4 additions & 2 deletions base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1045,7 +1045,7 @@ function check_world_bounded(tn::Core.TypeName)
isdefined(bnd, :partitions) || return nothing
partition = @atomic bnd.partitions
while true
if is_some_const_binding(binding_kind(partition)) && partition_restriction(partition) <: tn.wrapper
if is_defined_const_binding(binding_kind(partition)) && partition_restriction(partition) <: tn.wrapper
max_world = @atomic partition.max_world
max_world == typemax(UInt) && return nothing
return Int(partition.min_world):Int(max_world)
Expand Down Expand Up @@ -3364,9 +3364,11 @@ function print_partition(io::IO, partition::Core.BindingPartition)
end
print(io, " - ")
kind = binding_kind(partition)
if is_some_const_binding(kind)
if is_defined_const_binding(kind)
print(io, "constant binding to ")
print(io, partition_restriction(partition))
elseif kind == BINDING_KIND_UNDEF_CONST
print(io, "undefined const binding")
elseif kind == BINDING_KIND_GUARD
print(io, "undefined binding - guard entry")
elseif kind == BINDING_KIND_FAILED
Expand Down
8 changes: 6 additions & 2 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ typedef struct _jl_weakref_t {

// N.B: Needs to be synced with runtime_internals.jl
enum jl_partition_kind {
// Constant: This binding partition is a constant declared using `const`
// Constant: This binding partition is a constant declared using `const _ = ...`
// ->restriction holds the constant value
BINDING_KIND_CONST = 0x0,
// Import Constant: This binding partition is a constant declared using `import A`
Expand All @@ -649,7 +649,11 @@ enum jl_partition_kind {
BINDING_KIND_DECLARED = 0x7,
// Guard: The binding was looked at, but no global or import was resolved at the time
// ->restriction is NULL.
BINDING_KIND_GUARD = 0x8
BINDING_KIND_GUARD = 0x8,
// Undef Constant: This binding partition is a constant declared using `const`, but
// without a value.
// ->restriction is NULL
BINDING_KIND_UNDEF_CONST = 0x9
};

#ifdef _P64
Expand Down
19 changes: 16 additions & 3 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -924,8 +924,13 @@ EXTERN_INLINE_DECLARE enum jl_partition_kind decode_restriction_kind(jl_ptr_kind
uint8_t bits = (pku & 0x7);
jl_value_t *val = (jl_value_t*)(pku & ~0x7);

if (val == NULL && bits == BINDING_KIND_IMPLICIT) {
return BINDING_KIND_GUARD;
if (val == NULL) {
if (bits == BINDING_KIND_IMPLICIT) {
return BINDING_KIND_GUARD;
}
if (bits == BINDING_KIND_CONST) {
return BINDING_KIND_UNDEF_CONST;
}
}

return (enum jl_partition_kind)bits;
Expand All @@ -947,10 +952,14 @@ STATIC_INLINE jl_value_t *decode_restriction_value(jl_ptr_kind_union_t JL_PROPAG
STATIC_INLINE jl_ptr_kind_union_t encode_restriction(jl_value_t *val, enum jl_partition_kind kind) JL_NOTSAFEPOINT
{
#ifdef _P64
if (kind == BINDING_KIND_GUARD || kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_FAILED)
if (kind == BINDING_KIND_GUARD || kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_FAILED || kind == BINDING_KIND_UNDEF_CONST)
assert(val == NULL);
else if (kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_CONST)
assert(val != NULL);
if (kind == BINDING_KIND_GUARD)
kind = BINDING_KIND_IMPLICIT;
else if (kind == BINDING_KIND_UNDEF_CONST)
kind = BINDING_KIND_CONST;
assert((((uintptr_t)val) & 0x7) == 0);
return ((jl_ptr_kind_union_t)val) | kind;
#else
Expand All @@ -964,6 +973,10 @@ STATIC_INLINE int jl_bkind_is_some_import(enum jl_partition_kind kind) JL_NOTSAF
}

STATIC_INLINE int jl_bkind_is_some_constant(enum jl_partition_kind kind) JL_NOTSAFEPOINT {
return kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT || kind == BINDING_KIND_UNDEF_CONST;
}

STATIC_INLINE int jl_bkind_is_defined_constant(enum jl_partition_kind kind) JL_NOTSAFEPOINT {
return kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT;
}

Expand Down
5 changes: 4 additions & 1 deletion src/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,10 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_resolved(jl_binding_t *b)
JL_DLLEXPORT jl_value_t *jl_bpart_get_restriction_value(jl_binding_partition_t *bpart)
{
jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction);
return decode_restriction_value(pku);
jl_value_t *v = decode_restriction_value(pku);
if (!v)
jl_throw(jl_undefref_exception);
return v;
}

typedef struct _modstack_t {
Expand Down
7 changes: 3 additions & 4 deletions src/toplevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ 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_binding_partition_t *bpart = jl_get_binding_partition(b, ct->world_age);
jl_ptr_kind_union_t pku = encode_restriction(NULL, BINDING_KIND_CONST);
jl_ptr_kind_union_t pku = encode_restriction(NULL, BINDING_KIND_UNDEF_CONST);
jl_ptr_kind_union_t new_pku = encode_restriction((jl_value_t*)newm, BINDING_KIND_CONST);
if (!jl_atomic_cmpswap(&bpart->restriction, &pku, new_pku)) {
if (decode_restriction_kind(pku) != BINDING_KIND_CONST) {
Expand Down Expand Up @@ -749,8 +749,7 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val2(jl_binding_t *b, j
while (1) {
if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) {
if (!val) {
JL_GC_POP();
return bpart;
break;
}
jl_value_t *old = decode_restriction_value(pku);
JL_GC_PROMISE_ROOTED(old);
Expand Down Expand Up @@ -787,7 +786,7 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val2(jl_binding_t *b, j

JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *val)
{
return jl_declare_constant_val2(b, mod, var, val, BINDING_KIND_CONST);
return jl_declare_constant_val2(b, mod, var, val, val ? BINDING_KIND_CONST : BINDING_KIND_UNDEF_CONST);
}

JL_DLLEXPORT void jl_eval_const_decl(jl_module_t *m, jl_value_t *arg, jl_value_t *val)
Expand Down

0 comments on commit ec2b509

Please sign in to comment.