Skip to content

Commit c245179

Browse files
authored
fix missing gc root on store to iparams (#49820)
Try to optimize the order of this code a bit more, given that these checks are somewhat infrequently to be needed. Fix #49762
1 parent 45748b8 commit c245179

File tree

1 file changed

+59
-16
lines changed

1 file changed

+59
-16
lines changed

src/jltypes.c

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,13 +1844,8 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
18441844
jl_typename_t *tn = dt->name;
18451845
int istuple = (tn == jl_tuple_typename);
18461846
int isnamedtuple = (tn == jl_namedtuple_typename);
1847-
if (check && tn != jl_type_typename) {
1848-
size_t i;
1849-
for (i = 0; i < ntp; i++)
1850-
iparams[i] = normalize_unionalls(iparams[i]);
1851-
}
18521847

1853-
// check type cache, if applicable
1848+
// check if type cache will be applicable
18541849
int cacheable = 1;
18551850
if (istuple) {
18561851
size_t i;
@@ -1886,26 +1881,32 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
18861881
if (jl_has_free_typevars(iparams[i]))
18871882
cacheable = 0;
18881883
}
1884+
// if applicable, check the cache first for a match
18891885
if (cacheable) {
1886+
jl_value_t *lkup = (jl_value_t*)lookup_type(tn, iparams, ntp);
1887+
if (lkup != NULL)
1888+
return lkup;
1889+
}
1890+
// if some normalization might be needed, do that now
1891+
// it is probably okay to mutate iparams, and we only store globally rooted objects here
1892+
if (check && cacheable) {
18901893
size_t i;
18911894
for (i = 0; i < ntp; i++) {
18921895
jl_value_t *pi = iparams[i];
18931896
if (pi == jl_bottom_type)
18941897
continue;
18951898
if (jl_is_datatype(pi))
18961899
continue;
1897-
if (jl_is_vararg(pi)) {
1898-
pi = jl_unwrap_vararg(pi);
1899-
if (jl_has_free_typevars(pi))
1900-
continue;
1901-
}
1902-
// normalize types equal to wrappers (prepare for wrapper_id)
1900+
if (jl_is_vararg(pi))
1901+
// This would require some special handling, but is not needed
1902+
// at the moment (and might be better handled in jl_wrap_vararg instead).
1903+
continue;
1904+
if (!cacheable && jl_has_free_typevars(pi))
1905+
continue;
1906+
// normalize types equal to wrappers (prepare for Typeofwrapper)
19031907
jl_value_t *tw = extract_wrapper(pi);
19041908
if (tw && tw != pi && (tn != jl_type_typename || jl_typeof(pi) == jl_typeof(tw)) &&
19051909
jl_types_equal(pi, tw)) {
1906-
// This would require some special handling, but is never used at
1907-
// the moment.
1908-
assert(!jl_is_vararg(iparams[i]));
19091910
iparams[i] = tw;
19101911
if (p) jl_gc_wb(p, tw);
19111912
}
@@ -1915,6 +1916,9 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
19151916
// normalize Type{Type{Union{}}} to Type{TypeofBottom}
19161917
iparams[0] = (jl_value_t*)jl_typeofbottom_type;
19171918
}
1919+
}
1920+
// then check the cache again, if applicable
1921+
if (cacheable) {
19181922
jl_value_t *lkup = (jl_value_t*)lookup_type(tn, iparams, ntp);
19191923
if (lkup != NULL)
19201924
return lkup;
@@ -1923,12 +1927,15 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
19231927
if (stack_lkup)
19241928
return stack_lkup;
19251929

1930+
// check parameters against bounds in type definition
1931+
// for whether this is even valid
19261932
if (check && !istuple) {
1927-
// check parameters against bounds in type definition
1933+
assert(ntp > 0);
19281934
check_datatype_parameters(tn, iparams, ntp);
19291935
}
19301936
else if (ntp == 0 && jl_emptytuple_type != NULL) {
19311937
// empty tuple type case
1938+
assert(istuple);
19321939
return (jl_value_t*)jl_emptytuple_type;
19331940
}
19341941

@@ -1974,6 +1981,42 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
19741981
jl_svecset(p, i, iparams[i]);
19751982
}
19761983

1984+
// try to simplify some type parameters
1985+
if (check && tn != jl_type_typename) {
1986+
size_t i;
1987+
int changed = 0;
1988+
if (istuple) // normalization might change Tuple's, but not other types's, cacheable status
1989+
cacheable = 1;
1990+
for (i = 0; i < ntp; i++) {
1991+
jl_value_t *newp = normalize_unionalls(iparams[i]);
1992+
if (newp != iparams[i]) {
1993+
iparams[i] = newp;
1994+
jl_svecset(p, i, newp);
1995+
changed = 1;
1996+
}
1997+
if (istuple && cacheable && !jl_is_concrete_type(newp))
1998+
cacheable = 0;
1999+
}
2000+
if (changed) {
2001+
// If this changed something, we need to check the cache again, in
2002+
// case we missed the match earlier before the normalizations
2003+
//
2004+
// e.g. return inst_datatype_inner(dt, p, iparams, ntp, stack, env, 0);
2005+
if (cacheable) {
2006+
jl_value_t *lkup = (jl_value_t*)lookup_type(tn, iparams, ntp);
2007+
if (lkup != NULL) {
2008+
JL_GC_POP();
2009+
return lkup;
2010+
}
2011+
}
2012+
jl_value_t *stack_lkup = lookup_type_stack(stack, dt, ntp, iparams);
2013+
if (stack_lkup) {
2014+
JL_GC_POP();
2015+
return stack_lkup;
2016+
}
2017+
}
2018+
}
2019+
19772020
// acquire the write lock now that we know we need a new object
19782021
// since we're going to immediately leak it globally via the instantiation stack
19792022
if (cacheable) {

0 commit comments

Comments
 (0)