Skip to content

Commit 4456be2

Browse files
committed
Add global tests and fixes
TODO: codegen for typed_store/typed_load of a global to correctly throw UndefVarError TODO: optimization for modifyglobal and memoryrefmodify
1 parent c7def9b commit 4456be2

File tree

8 files changed

+352
-45
lines changed

8 files changed

+352
-45
lines changed

base/compiler/tfuncs.jl

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1987,23 +1987,19 @@ end
19871987
return memoryrefget_tfunc(𝕃, mem, order, boundscheck)
19881988
end
19891989
@nospecs function memoryrefmodify!_tfunc(𝕃::AbstractLattice, mem, op, v, success_order, failure_order, boundscheck)
1990-
T = get_binding_type_tfunc(𝕃, M, s)
1990+
T = _memoryref_elemtype(mem)
19911991
T === Bottom && return Bottom
1992-
T isa Const || return Pair
1993-
T = T.value
1994-
return Pair{T, T}
1992+
PT = Const(Pair)
1993+
return instanceof_tfunc(apply_type_tfunc(𝕃, PT, T, T), true)[1]
19951994
end
1996-
@nospecs function memoryrefreplace!_tfunc(𝕃𝕃::AbstractLattice, mem, x, v, success_order, failure_order, boundscheck)
1997-
v = memoryrefset!_tfunc(𝕃, o, f, v)
1998-
v === Bottom && return Bottom
1999-
T = get_binding_type_tfunc(𝕃, M, s)
1995+
@nospecs function memoryrefreplace!_tfunc(𝕃::AbstractLattice, mem, x, v, success_order, failure_order, boundscheck)
1996+
T = _memoryref_elemtype(mem)
20001997
T === Bottom && return Bottom
2001-
T isa Const || return ccall(:jl_apply_cmpswap_type, Any, (Any,), T) where T
2002-
T = T.value
2003-
return ccall(:jl_apply_cmpswap_type, Any, (Any,), T)
1998+
PT = Const(ccall(:jl_apply_cmpswap_type, Any, (Any,), T) where T)
1999+
return instanceof_tfunc(apply_type_tfunc(𝕃, PT, T), true)[1]
20042000
end
20052001
@nospecs function memoryrefsetonce!_tfunc(𝕃::AbstractLattice, mem, v, success_order, failure_order, boundscheck)
2006-
memoryrefsetonce!_tfunc(𝕃, o, f, v) === Bottom && return Bottom
2002+
memoryrefsetonce!_tfunc(𝕃, mem, v) === Bottom && return Bottom
20072003
return Bool
20082004
end
20092005

@@ -2064,7 +2060,7 @@ add_tfunc(memoryrefoffset, 1, 1, memoryrefoffset_tfunc, 5)
20642060
return true
20652061
end
20662062

2067-
function memoryref_elemtype(@nospecialize mem)
2063+
@nospecs function memoryref_elemtype(@nospecialize mem)
20682064
m = widenconst(mem)
20692065
if !has_free_typevars(m) && m <: GenericMemoryRef
20702066
m0 = m
@@ -2080,6 +2076,23 @@ function memoryref_elemtype(@nospecialize mem)
20802076
return Any
20812077
end
20822078

2079+
@nospecs function _memoryref_elemtype(@nospecialize mem)
2080+
m = widenconst(mem)
2081+
if !has_free_typevars(m) && m <: GenericMemoryRef
2082+
m0 = m
2083+
if isa(m, UnionAll)
2084+
m = unwrap_unionall(m0)
2085+
end
2086+
if isa(m, DataType)
2087+
T = m.parameters[2]
2088+
valid_as_lattice(T, true) || return Bottom
2089+
has_free_typevars(T) || return Const(T)
2090+
return rewrap_unionall(Type{T}, m0)
2091+
end
2092+
end
2093+
return Type
2094+
end
2095+
20832096
@nospecs function opaque_closure_tfunc(𝕃::AbstractLattice, arg, lb, ub, source, env::Vector{Any}, linfo::MethodInstance)
20842097
argt, argt_exact = instanceof_tfunc(arg)
20852098
lbt, lb_exact = instanceof_tfunc(lb)
@@ -3085,7 +3098,7 @@ end
30853098
return Bottom
30863099
end
30873100
T = get_binding_type_tfunc(𝕃, M, s)
3088-
T isa Const && return T.value
3101+
T isa Const && return T.val
30893102
return Any
30903103
end
30913104
@nospecs function setglobal!_tfunc(𝕃::AbstractLattice, M, s, v, order=Symbol)
@@ -3095,27 +3108,27 @@ end
30953108
return v
30963109
end
30973110
@nospecs function swapglobal!_tfunc(𝕃::AbstractLattice, M, s, v, order=Symbol)
3098-
setglobal_tfunc(𝕃, o, f, v) === Bottom && return Bottom
3099-
return getglobal_tfunc(𝕃, o, f)
3111+
setglobal!_tfunc(𝕃, M, s, v) === Bottom && return Bottom
3112+
return getglobal_tfunc(𝕃, M, s)
31003113
end
31013114
@nospecs function modifyglobal!_tfunc(𝕃::AbstractLattice, M, s, op, v, order=Symbol)
31023115
T = get_binding_type_tfunc(𝕃, M, s)
31033116
T === Bottom && return Bottom
31043117
T isa Const || return Pair
3105-
T = T.value
3118+
T = T.val
31063119
return Pair{T, T}
31073120
end
3108-
@nospecs function replaceglobal!_tfunc(𝕃𝕃::AbstractLattice, M, s, x, v, success_order=Symbol, failure_order=Symbol)
3109-
v = setglobal!_tfunc(𝕃, o, f, v)
3121+
@nospecs function replaceglobal!_tfunc(𝕃::AbstractLattice, M, s, x, v, success_order=Symbol, failure_order=Symbol)
3122+
v = setglobal!_tfunc(𝕃, M, s, v)
31103123
v === Bottom && return Bottom
31113124
T = get_binding_type_tfunc(𝕃, M, s)
31123125
T === Bottom && return Bottom
31133126
T isa Const || return ccall(:jl_apply_cmpswap_type, Any, (Any,), T) where T
3114-
T = T.value
3127+
T = T.val
31153128
return ccall(:jl_apply_cmpswap_type, Any, (Any,), T)
31163129
end
31173130
@nospecs function setglobalonce!_tfunc(𝕃::AbstractLattice, M, s, v, success_order=Symbol, failure_order=Symbol)
3118-
setglobal!_tfunc(𝕃, o, f, v) === Bottom && return Bottom
3131+
setglobal!_tfunc(𝕃, M, s, v) === Bottom && return Bottom
31193132
return Bool
31203133
end
31213134

src/builtins.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1272,6 +1272,10 @@ JL_CALLABLE(jl_f_isdefined)
12721272
JL_TYPECHK(isdefined, symbol, args[1]);
12731273
m = (jl_module_t*)args[0];
12741274
s = (jl_sym_t*)args[1];
1275+
if (order == jl_memory_order_unspecified)
1276+
order = jl_memory_order_unordered;
1277+
if (order < jl_memory_order_unordered)
1278+
jl_atomic_error("isdefined: module binding cannot be accessed non-atomically");
12751279
int bound = jl_boundp(m, s); // seq_cst always
12761280
return bound ? jl_true : jl_false;
12771281
}
@@ -1389,7 +1393,7 @@ JL_CALLABLE(jl_f_set_binding_type)
13891393
JL_TYPECHK(set_binding_type!, type, ty);
13901394
jl_binding_t *b = jl_get_binding_wr(m, s);
13911395
jl_value_t *old_ty = NULL;
1392-
if (!jl_atomic_cmpswap_release(&b->ty, &old_ty, ty) && ty != old_ty) {
1396+
if (!jl_atomic_cmpswap_release(&b->ty, &old_ty, ty) && ty != old_ty) { // TODO: this should use jl_types_egal instead of !=, so that setting it to a non-concrete type doesn't error unnecessarily
13931397
if (nargs == 2)
13941398
return jl_nothing;
13951399
jl_errorf("cannot set type for global %s.%s. It already has a value or is already set to a different type.",

src/codegen.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3181,6 +3181,7 @@ static jl_cgval_t emit_globalop(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *s
31813181
jl_value_t *ty = jl_atomic_load_relaxed(&bnd->ty);
31823182
if (ty && jl_subtype(rval.typ, ty)) {
31833183
// TODO: use typeassert here instead, coordinated with jl_check_binding_wr
3184+
// TODO: this is wrong for ismodifyglobal as well, since its check is part of typed_store
31843185
//emit_typecheck(ctx, rval, ty, "typeassert");
31853186
//rval = update_julia_type(ctx, rval, ty);
31863187
bool isboxed = true;

src/datatype.c

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1789,7 +1789,7 @@ JL_DLLEXPORT jl_value_t *jl_get_nth_field_checked(jl_value_t *v, size_t i)
17891789
return r;
17901790
}
17911791

1792-
void set_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_t *rhs, int isatomic) JL_NOTSAFEPOINT
1792+
inline void set_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_t *rhs, int isatomic) JL_NOTSAFEPOINT
17931793
{
17941794
size_t offs = jl_field_offset(st, i);
17951795
if (rhs == NULL) { // TODO: this should be invalid, but it happens frequently in ircode.c
@@ -1839,7 +1839,7 @@ void set_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_t *rhs,
18391839
}
18401840
}
18411841

1842-
jl_value_t *swap_bits(jl_value_t *ty, char *v, uint8_t *psel, jl_value_t *parent, jl_value_t *rhs, enum atomic_kind isatomic)
1842+
inline jl_value_t *swap_bits(jl_value_t *ty, char *v, uint8_t *psel, jl_value_t *parent, jl_value_t *rhs, enum atomic_kind isatomic)
18431843
{
18441844
jl_value_t *rty = jl_typeof(rhs);
18451845
int hasptr;
@@ -1913,20 +1913,26 @@ jl_value_t *swap_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_
19131913
}
19141914
}
19151915

1916-
jl_value_t *modify_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *parent, jl_value_t *op, jl_value_t *rhs, int isatomic)
1916+
inline jl_value_t *modify_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *parent, jl_value_t *op, jl_value_t *rhs, int isatomic, jl_module_t *mod, jl_sym_t *name)
19171917
{
19181918
jl_value_t *r = isatomic ? jl_atomic_load(p) : jl_atomic_load_relaxed(p);
1919-
if (__unlikely(r == NULL))
1919+
if (__unlikely(r == NULL)) {
1920+
if (mod && name)
1921+
jl_undefined_var_error(name, (jl_value_t*)mod);
19201922
jl_throw(jl_undefref_exception);
1923+
}
19211924
jl_value_t **args;
19221925
JL_GC_PUSHARGS(args, 2);
19231926
args[0] = r;
19241927
while (1) {
19251928
args[1] = rhs;
19261929
jl_value_t *y = jl_apply_generic(op, args, 2);
19271930
args[1] = y;
1928-
if (!jl_isa(y, ty))
1929-
jl_type_error("modifyfield!", ty, y);
1931+
if (!jl_isa(y, ty)) {
1932+
if (mod && name)
1933+
jl_errorf("cannot assign an incompatible value to the global %s.%s.", jl_symbol_name(mod->name), jl_symbol_name(name));
1934+
jl_type_error(jl_is_genericmemory(parent) ? "memoryrefmodify!" : "modifyfield!", ty, y);
1935+
}
19301936
if (isatomic ? jl_atomic_cmpswap(p, &r, y) : jl_atomic_cmpswap_release(p, &r, y)) {
19311937
jl_gc_wb(parent, y);
19321938
break;
@@ -1943,7 +1949,7 @@ jl_value_t *modify_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *pa
19431949
return args[0];
19441950
}
19451951

1946-
jl_value_t *modify_bits(jl_value_t *ty, char *p, uint8_t *psel, jl_value_t *parent, jl_value_t *op, jl_value_t *rhs, enum atomic_kind isatomic)
1952+
inline jl_value_t *modify_bits(jl_value_t *ty, char *p, uint8_t *psel, jl_value_t *parent, jl_value_t *op, jl_value_t *rhs, enum atomic_kind isatomic)
19471953
{
19481954
int hasptr;
19491955
int isunion = psel != NULL;
@@ -1981,8 +1987,9 @@ jl_value_t *modify_bits(jl_value_t *ty, char *p, uint8_t *psel, jl_value_t *pare
19811987
args[1] = rhs;
19821988
jl_value_t *y = jl_apply_generic(op, args, 2);
19831989
args[1] = y;
1984-
if (!jl_isa(y, ty))
1985-
jl_type_error("modifyfield!", ty, y);
1990+
if (!jl_isa(y, ty)) {
1991+
jl_type_error(jl_is_genericmemory(parent) ? "memoryrefmodify!" : "modifyfield!", ty, y);
1992+
}
19861993
jl_value_t *yty = jl_typeof(y);
19871994
if (isatomic && !needlock) {
19881995
assert(yty == rty);
@@ -2039,15 +2046,15 @@ jl_value_t *modify_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_valu
20392046
jl_value_t *ty = jl_field_type_concrete(st, i);
20402047
char *p = (char*)v + offs;
20412048
if (jl_field_isptr(st, i)) {
2042-
return modify_value(ty, (_Atomic(jl_value_t*)*)p, v, op, rhs, isatomic);
2049+
return modify_value(ty, (_Atomic(jl_value_t*)*)p, v, op, rhs, isatomic, NULL, NULL);
20432050
}
20442051
else {
20452052
uint8_t *psel = jl_is_uniontype(ty) ? (uint8_t*)&p[jl_field_size(st, i) - 1] : NULL;
20462053
return modify_bits(ty, p, psel, v, op, rhs, isatomic ? isatomic_object : isatomic_none);
20472054
}
20482055
}
20492056

2050-
jl_value_t *replace_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *parent, jl_value_t *expected, jl_value_t *rhs, int isatomic)
2057+
inline jl_value_t *replace_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *parent, jl_value_t *expected, jl_value_t *rhs, int isatomic, jl_module_t *mod, jl_sym_t *name)
20512058
{
20522059
jl_datatype_t *rettyp = jl_apply_cmpswap_type(ty);
20532060
JL_GC_PROMISE_ROOTED(rettyp); // (JL_ALWAYS_LEAFTYPE)
@@ -2057,8 +2064,11 @@ jl_value_t *replace_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *p
20572064
success = isatomic ? jl_atomic_cmpswap(p, &r, rhs) : jl_atomic_cmpswap_release(p, &r, rhs);
20582065
if (success)
20592066
jl_gc_wb(parent, rhs);
2060-
if (__unlikely(r == NULL))
2067+
if (__unlikely(r == NULL)) {
2068+
if (mod && name)
2069+
jl_undefined_var_error(name, (jl_value_t*)mod);
20612070
jl_throw(jl_undefref_exception);
2071+
}
20622072
if (success || !jl_egal(r, expected))
20632073
break;
20642074
}
@@ -2068,7 +2078,7 @@ jl_value_t *replace_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *p
20682078
return r;
20692079
}
20702080

2071-
jl_value_t *replace_bits(jl_value_t *ty, char *p, uint8_t *psel, jl_value_t *parent, jl_value_t *expected, jl_value_t *rhs, enum atomic_kind isatomic)
2081+
inline jl_value_t *replace_bits(jl_value_t *ty, char *p, uint8_t *psel, jl_value_t *parent, jl_value_t *expected, jl_value_t *rhs, enum atomic_kind isatomic)
20722082
{
20732083
jl_datatype_t *rettyp = jl_apply_cmpswap_type(ty);
20742084
JL_GC_PROMISE_ROOTED(rettyp); // (JL_ALWAYS_LEAFTYPE)
@@ -2144,7 +2154,7 @@ jl_value_t *replace_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_val
21442154
size_t offs = jl_field_offset(st, i);
21452155
char *p = (char*)v + offs;
21462156
if (jl_field_isptr(st, i)) {
2147-
return replace_value(ty, (_Atomic(jl_value_t*)*)p, v, expected, rhs, isatomic);
2157+
return replace_value(ty, (_Atomic(jl_value_t*)*)p, v, expected, rhs, isatomic, NULL, NULL);
21482158
}
21492159
else {
21502160
size_t fsz = jl_field_size(st, i);
@@ -2154,7 +2164,7 @@ jl_value_t *replace_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_val
21542164
}
21552165
}
21562166

2157-
int setonce_bits(jl_datatype_t *rty, char *p, jl_value_t *parent, jl_value_t *rhs, enum atomic_kind isatomic)
2167+
inline int setonce_bits(jl_datatype_t *rty, char *p, jl_value_t *parent, jl_value_t *rhs, enum atomic_kind isatomic)
21582168
{
21592169
size_t fsz = jl_datatype_size((jl_datatype_t*)rty); // need to shrink-wrap the final copy
21602170
assert(rty->layout->first_ptr >= 0);

src/genericmemory.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ JL_DLLEXPORT jl_value_t *jl_memoryrefmodify(jl_genericmemoryref_t m, jl_value_t
570570
char *data = (char*)m.ptr_or_offset;
571571
if (layout->flags.arrayelem_isboxed) {
572572
assert(data - (char*)m.mem->ptr < sizeof(jl_value_t*) * m.mem->length);
573-
return modify_value(eltype, (_Atomic(jl_value_t*)*)data, owner, op, rhs, isatomic);
573+
return modify_value(eltype, (_Atomic(jl_value_t*)*)data, owner, op, rhs, isatomic, NULL, NULL);
574574
}
575575
size_t fsz = layout->size;
576576
uint8_t *psel = NULL;
@@ -597,7 +597,7 @@ JL_DLLEXPORT jl_value_t *jl_memoryrefreplace(jl_genericmemoryref_t m, jl_value_t
597597
char *data = (char*)m.ptr_or_offset;
598598
if (layout->flags.arrayelem_isboxed) {
599599
assert(data - (char*)m.mem->ptr < sizeof(jl_value_t*) * m.mem->length);
600-
return replace_value(eltype, (_Atomic(jl_value_t*)*)data, owner, expected, rhs, isatomic);
600+
return replace_value(eltype, (_Atomic(jl_value_t*)*)data, owner, expected, rhs, isatomic, NULL, NULL);
601601
}
602602
uint8_t *psel = NULL;
603603
if (layout->flags.arrayelem_isunion) {

src/julia_internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -779,9 +779,9 @@ jl_value_t *modify_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_valu
779779
jl_value_t *replace_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_t *expected, jl_value_t *rhs, int isatomic);
780780
int set_nth_fieldonce(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_t *rhs, int isatomic);
781781
jl_value_t *swap_bits(jl_value_t *ty, char *v, uint8_t *psel, jl_value_t *parent, jl_value_t *rhs, enum atomic_kind isatomic);
782-
jl_value_t *replace_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *parent, jl_value_t *expected, jl_value_t *rhs, int isatomic);
782+
jl_value_t *replace_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *parent, jl_value_t *expected, jl_value_t *rhs, int isatomic, jl_module_t *mod, jl_sym_t *name);
783783
jl_value_t *replace_bits(jl_value_t *ty, char *p, uint8_t *psel, jl_value_t *parent, jl_value_t *expected, jl_value_t *rhs, enum atomic_kind isatomic);
784-
jl_value_t *modify_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *parent, jl_value_t *op, jl_value_t *rhs, int isatomic);
784+
jl_value_t *modify_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *parent, jl_value_t *op, jl_value_t *rhs, int isatomic, jl_module_t *mod, jl_sym_t *name);
785785
jl_value_t *modify_bits(jl_value_t *ty, char *p, uint8_t *psel, jl_value_t *parent, jl_value_t *op, jl_value_t *rhs, enum atomic_kind isatomic);
786786
int setonce_bits(jl_datatype_t *rty, char *p, jl_value_t *owner, jl_value_t *rhs, enum atomic_kind isatomic);
787787
jl_expr_t *jl_exprn(jl_sym_t *head, size_t n);

src/module.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -926,19 +926,26 @@ JL_DLLEXPORT jl_value_t *jl_checked_swap(jl_binding_t *b, jl_module_t *mod, jl_s
926926
jl_check_binding_wr(b, mod, var, rhs, 0);
927927
jl_value_t *old = jl_atomic_exchange(&b->value, rhs);
928928
jl_gc_wb(b, rhs);
929+
if (__unlikely(old == NULL))
930+
jl_undefined_var_error(var, (jl_value_t*)mod);
929931
return old;
930932
}
931933

932934
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)
933935
{
934936
jl_value_t *ty = jl_check_binding_wr(b, mod, var, rhs, 0);
935-
return replace_value(ty, &b->value, (jl_value_t*)b, expected, rhs, 1);
937+
return replace_value(ty, &b->value, (jl_value_t*)b, expected, rhs, 1, mod, var);
936938
}
937939

938940
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)
939941
{
940-
jl_value_t *ty = jl_check_binding_wr(b, mod, var, rhs, 0);
941-
return modify_value(ty, &b->value, (jl_value_t*)b, op, rhs, 1);
942+
jl_value_t *ty = NULL;
943+
if (jl_atomic_cmpswap_relaxed(&b->ty, &ty, (jl_value_t*)jl_any_type))
944+
ty = (jl_value_t*)jl_any_type;
945+
if (b->constp)
946+
jl_errorf("invalid redefinition of constant %s.%s",
947+
jl_symbol_name(mod->name), jl_symbol_name(var));
948+
return modify_value(ty, &b->value, (jl_value_t*)b, op, rhs, 1, mod, var);
942949
}
943950

944951
JL_DLLEXPORT jl_value_t *jl_checked_assignonce(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs )

0 commit comments

Comments
 (0)