Skip to content

Commit

Permalink
Split Binding
Browse files Browse the repository at this point in the history
  • Loading branch information
Keno committed Jun 26, 2024
1 parent d3c4aaa commit c2cc636
Show file tree
Hide file tree
Showing 12 changed files with 270 additions and 183 deletions.
15 changes: 9 additions & 6 deletions src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
36 changes: 22 additions & 14 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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),
Expand Down
1 change: 1 addition & 0 deletions src/jl_exported_data.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
15 changes: 13 additions & 2 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
34 changes: 28 additions & 6 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
13 changes: 10 additions & 3 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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] == '#')
Expand Down
12 changes: 7 additions & 5 deletions src/method.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit c2cc636

Please sign in to comment.