Skip to content

Commit 215a8e9

Browse files
vtjnashJeffBezanson
authored andcommitted
types: per comment, avoid copy when t is not bound (#32176)
As mentioned in #9378. Fix recursion issue mentioned in #25796 by using inst_datatype_inner instead of inst_datatype, so that we shouldn't be making copies of any non-bound objects (anything maybe-cacheable) now. (cherry picked from commit 217507f)
1 parent 3fcb168 commit 215a8e9

File tree

1 file changed

+76
-82
lines changed

1 file changed

+76
-82
lines changed

src/jltypes.c

Lines changed: 76 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -819,8 +819,21 @@ static int within_typevar(jl_value_t *t, jl_value_t *vlb, jl_value_t *vub)
819819
struct _jl_typestack_t;
820820
typedef struct _jl_typestack_t jl_typestack_t;
821821

822-
static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp,
823-
int cacheable, jl_typestack_t *stack);
822+
static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp,
823+
int cacheable, jl_typestack_t *stack, jl_typeenv_t *env);
824+
825+
// Build an environment mapping a TypeName's parameters to parameter values.
826+
// This is the environment needed for instantiating a type's supertype and field types.
827+
static jl_value_t *inst_datatype_env(jl_value_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp,
828+
int cacheable, jl_typestack_t *stack, jl_typeenv_t *env, int c)
829+
{
830+
if (jl_is_datatype(dt))
831+
return inst_datatype_inner((jl_datatype_t*)dt, p, iparams, ntp, cacheable, stack, env);
832+
assert(jl_is_unionall(dt));
833+
jl_unionall_t *ua = (jl_unionall_t*)dt;
834+
jl_typeenv_t e = { ua->var, iparams[c], env };
835+
return inst_datatype_env(ua->body, p, iparams, ntp, cacheable, stack, &e, c + 1);
836+
}
824837

825838
jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n)
826839
{
@@ -836,12 +849,13 @@ jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n)
836849
if (jl_is_datatype(u) && n == jl_nparams((jl_datatype_t*)u) &&
837850
((jl_datatype_t*)u)->name->wrapper == tc) {
838851
int cacheable = 1;
839-
for(i=0; i < n; i++) {
852+
for (i = 0; i < n; i++) {
840853
if (jl_has_free_typevars(params[i])) {
841-
cacheable = 0; break;
854+
cacheable = 0;
855+
break;
842856
}
843857
}
844-
return inst_datatype((jl_datatype_t*)u, NULL, params, n, cacheable, NULL);
858+
return inst_datatype_env(tc, NULL, params, n, cacheable, NULL, NULL, 0);
845859
}
846860
}
847861
JL_GC_PUSH1(&tc);
@@ -1068,6 +1082,8 @@ static jl_value_t *normalize_vararg(jl_value_t *va)
10681082
return va;
10691083
}
10701084

1085+
static jl_value_t *_jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals, jl_typeenv_t *prev, jl_typestack_t *stack);
1086+
10711087
static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp,
10721088
int cacheable, jl_typestack_t *stack, jl_typeenv_t *env)
10731089
{
@@ -1244,6 +1260,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
12441260
if (cacheable && !ndt->abstract)
12451261
ndt->uid = jl_assign_type_uid();
12461262

1263+
jl_datatype_t *primarydt = ((jl_datatype_t*)jl_unwrap_unionall(tn->wrapper));
12471264
if (istuple || isnamedtuple) {
12481265
ndt->super = jl_any_type;
12491266
}
@@ -1252,10 +1269,12 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
12521269
jl_gc_wb(ndt, ndt->super);
12531270
}
12541271
jl_svec_t *ftypes = dt->types;
1272+
if (ftypes == NULL)
1273+
ftypes = primarydt->types;
12551274
if (ftypes == NULL || dt->super == NULL) {
12561275
// in the process of creating this type definition:
12571276
// need to instantiate the super and types fields later
1258-
assert(inside_typedef && !istuple && !isnamedtuple);
1277+
assert((inside_typedef || primarydt->super) && !istuple && !isnamedtuple);
12591278
arraylist_push(&partial_inst, ndt);
12601279
}
12611280
else {
@@ -1292,25 +1311,6 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
12921311
return (jl_value_t*)ndt;
12931312
}
12941313

1295-
// Build an environment mapping a TypeName's parameters to parameter values.
1296-
// This is the environment needed for instantiating a type's supertype and field types.
1297-
static jl_value_t *inst_datatype_env(jl_value_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp,
1298-
int cacheable, jl_typestack_t *stack, jl_typeenv_t *env, int c)
1299-
{
1300-
if (jl_is_datatype(dt))
1301-
return inst_datatype_inner((jl_datatype_t*)dt, p, iparams, ntp, cacheable, stack, env);
1302-
assert(jl_is_unionall(dt));
1303-
jl_unionall_t *ua = (jl_unionall_t*)dt;
1304-
jl_typeenv_t e = { ua->var, iparams[c], env };
1305-
return inst_datatype_env(ua->body, p, iparams, ntp, cacheable, stack, &e, c+1);
1306-
}
1307-
1308-
static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp,
1309-
int cacheable, jl_typestack_t *stack)
1310-
{
1311-
return inst_datatype_env(dt->name->wrapper, p, iparams, ntp, cacheable, stack, NULL, 0);
1312-
}
1313-
13141314
static jl_tupletype_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec_t *params)
13151315
{
13161316
int cacheable = 1;
@@ -1319,9 +1319,7 @@ static jl_tupletype_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec
13191319
if (!jl_is_concrete_type(p[i]))
13201320
cacheable = 0;
13211321
}
1322-
jl_datatype_t *ndt = (jl_datatype_t*)inst_datatype(jl_anytuple_type, params, p, np,
1323-
cacheable, NULL);
1324-
return ndt;
1322+
return (jl_datatype_t*)inst_datatype_inner(jl_anytuple_type, params, p, np, cacheable, NULL, NULL);
13251323
}
13261324

13271325
JL_DLLEXPORT jl_tupletype_t *jl_apply_tuple_type(jl_svec_t *params)
@@ -1336,12 +1334,12 @@ JL_DLLEXPORT jl_tupletype_t *jl_apply_tuple_type_v(jl_value_t **p, size_t np)
13361334

13371335
jl_datatype_t *jl_inst_concrete_tupletype(jl_svec_t *p)
13381336
{
1339-
return (jl_datatype_t*)inst_datatype(jl_anytuple_type, p, jl_svec_data(p), jl_svec_len(p), 1, NULL);
1337+
return (jl_datatype_t*)inst_datatype_inner(jl_anytuple_type, p, jl_svec_data(p), jl_svec_len(p), 1, NULL, NULL);
13401338
}
13411339

13421340
jl_datatype_t *jl_inst_concrete_tupletype_v(jl_value_t **p, size_t np)
13431341
{
1344-
return (jl_datatype_t*)inst_datatype(jl_anytuple_type, NULL, p, np, 1, NULL);
1342+
return (jl_datatype_t*)inst_datatype_inner(jl_anytuple_type, NULL, p, np, 1, NULL, NULL);
13451343
}
13461344

13471345
static jl_svec_t *inst_all(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *stack, int check)
@@ -1363,7 +1361,7 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_
13631361
jl_svec_t *tp = tt->parameters;
13641362
size_t ntp = jl_svec_len(tp);
13651363
// Instantiate NTuple{3,Int}
1366-
// Note this does not instantiate Tuple{Vararg{Int,3}}; that's done in inst_datatype
1364+
// Note this does not instantiate Tuple{Vararg{Int,3}}; that's done in inst_datatype_inner
13671365
if (jl_is_va_tuple(tt) && ntp == 1) {
13681366
// If this is a Tuple{Vararg{T,N}} with known N, expand it to
13691367
// a fixed-length tuple
@@ -1389,12 +1387,13 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_
13891387
jl_value_t **iparams;
13901388
int onstack = ntp < jl_page_size/sizeof(jl_value_t*);
13911389
JL_GC_PUSHARGS(iparams, onstack ? ntp : 1);
1392-
jl_svec_t *ip_heap=NULL;
1390+
jl_svec_t *ip_heap = NULL;
13931391
if (!onstack) {
13941392
ip_heap = jl_alloc_svec(ntp);
13951393
iparams[0] = (jl_value_t*)ip_heap;
13961394
iparams = jl_svec_data(ip_heap);
13971395
}
1396+
int bound = 0;
13981397
int cacheable = 1;
13991398
if (jl_is_va_tuple(tt))
14001399
cacheable = 0;
@@ -1405,12 +1404,14 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_
14051404
iparams[i] = pi;
14061405
if (ip_heap)
14071406
jl_gc_wb(ip_heap, pi);
1407+
bound |= (pi != elt);
14081408
if (cacheable && !jl_is_concrete_type(pi))
14091409
cacheable = 0;
14101410
}
1411-
jl_value_t *result = inst_datatype((jl_datatype_t*)tt, ip_heap, iparams, ntp, cacheable, stack);
1411+
if (bound)
1412+
t = inst_datatype_inner(tt, ip_heap, iparams, ntp, cacheable, stack, env);
14121413
JL_GC_POP();
1413-
return result;
1414+
return t;
14141415
}
14151416

14161417
static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check)
@@ -1421,88 +1422,78 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t
14211422
while (e != NULL) {
14221423
if (e->var == (jl_tvar_t*)t) {
14231424
jl_value_t *val = e->val;
1424-
// TODO jb/subtype this seems unnecessary
1425-
//if (check && !jl_is_typevar(val) && !within_typevar(val, (jl_tvar_t*)t)) {
1426-
// jl_type_error_rt("type parameter",
1427-
// jl_symbol_name(((jl_tvar_t*)t)->name), t, val);
1428-
//}
14291425
return val;
14301426
}
14311427
e = e->prev;
14321428
}
1433-
return (jl_value_t*)t;
1429+
return t;
14341430
}
14351431
if (jl_is_unionall(t)) {
1436-
if (!jl_has_free_typevars(t))
1437-
return t;
14381432
jl_unionall_t *ua = (jl_unionall_t*)t;
1439-
jl_value_t *res=NULL, *lb=ua->var->lb, *ub=ua->var->ub;
1440-
JL_GC_PUSH3(&lb, &ub, &res);
1441-
res = jl_new_struct(jl_unionall_type, ua->var, NULL);
1442-
if (jl_has_bound_typevars(ua->var->lb, env))
1443-
lb = inst_type_w_(ua->var->lb, env, stack, check);
1444-
if (jl_has_bound_typevars(ua->var->ub, env))
1445-
ub = inst_type_w_(ua->var->ub, env, stack, check);
1446-
if (lb != ua->var->lb || ub != ua->var->ub) {
1447-
((jl_unionall_t*)res)->var = jl_new_typevar(ua->var->name, lb, ub);
1448-
jl_gc_wb(res, ((jl_unionall_t*)res)->var);
1433+
jl_value_t *lb = NULL;
1434+
jl_value_t *var = NULL;
1435+
jl_value_t *newbody = NULL;
1436+
JL_GC_PUSH3(&lb, &var, &newbody);
1437+
lb = inst_type_w_(ua->var->lb, env, stack, check);
1438+
var = inst_type_w_(ua->var->ub, env, stack, check);
1439+
if (lb != ua->var->lb || var != ua->var->ub) {
1440+
var = (jl_value_t*)jl_new_typevar(ua->var->name, lb, var);
1441+
}
1442+
else {
1443+
var = (jl_value_t*)ua->var;
14491444
}
1450-
jl_typeenv_t newenv = { ua->var, (jl_value_t*)((jl_unionall_t*)res)->var, env };
1451-
jl_value_t *newbody = inst_type_w_(ua->body, &newenv, stack, check);
1445+
jl_typeenv_t newenv = { ua->var, var, env };
1446+
newbody = inst_type_w_(ua->body, &newenv, stack, check);
14521447
if (newbody == (jl_value_t*)jl_emptytuple_type) {
14531448
// NTuple{0} => Tuple{} can make a typevar disappear
1454-
res = (jl_value_t*)jl_emptytuple_type;
1449+
t = (jl_value_t*)jl_emptytuple_type;
14551450
}
1456-
else {
1457-
((jl_unionall_t*)res)->body = newbody;
1458-
jl_gc_wb(res, newbody);
1451+
else if (newbody != ua->body || var != (jl_value_t*)ua->var) {
1452+
// if t's parameters are not bound in the environment, return it uncopied (#9378)
1453+
t = jl_new_struct(jl_unionall_type, var, newbody);
14591454
}
14601455
JL_GC_POP();
1461-
return res;
1456+
return t;
14621457
}
14631458
if (jl_is_uniontype(t)) {
14641459
jl_uniontype_t *u = (jl_uniontype_t*)t;
14651460
jl_value_t *a = inst_type_w_(u->a, env, stack, check);
14661461
jl_value_t *b = NULL;
14671462
JL_GC_PUSH2(&a, &b);
14681463
b = inst_type_w_(u->b, env, stack, check);
1469-
jl_value_t *res;
1470-
if (a == u->a && b == u->b) {
1471-
res = t;
1472-
}
1473-
else {
1464+
if (a != u->a || b != u->b) {
14741465
jl_value_t *uargs[2] = {a, b};
1475-
res = jl_type_union(uargs, 2);
1466+
t = jl_type_union(uargs, 2);
14761467
}
14771468
JL_GC_POP();
1478-
return res;
1469+
return t;
14791470
}
14801471
if (!jl_is_datatype(t))
14811472
return t;
14821473
jl_datatype_t *tt = (jl_datatype_t*)t;
14831474
jl_svec_t *tp = tt->parameters;
14841475
if (tp == jl_emptysvec)
1485-
return (jl_value_t*)t;
1476+
return t;
14861477
jl_typename_t *tn = tt->name;
14871478
if (tn == jl_tuple_typename)
14881479
return inst_tuple_w_(t, env, stack, check);
14891480
size_t ntp = jl_svec_len(tp);
14901481
jl_value_t **iparams;
14911482
JL_GC_PUSHARGS(iparams, ntp);
14921483
int cacheable = 1, bound = 0;
1493-
for(i=0; i < ntp; i++) {
1484+
for (i = 0; i < ntp; i++) {
14941485
jl_value_t *elt = jl_svecref(tp, i);
1495-
iparams[i] = (jl_value_t*)inst_type_w_(elt, env, stack, check);
1496-
bound |= (iparams[i] != elt);
1497-
if (cacheable && jl_has_free_typevars(iparams[i]))
1486+
jl_value_t *pi = inst_type_w_(elt, env, stack, check);
1487+
iparams[i] = pi;
1488+
bound |= (pi != elt);
1489+
if (cacheable && jl_has_free_typevars(pi))
14981490
cacheable = 0;
14991491
}
15001492
// if t's parameters are not bound in the environment, return it uncopied (#9378)
1501-
if (!bound) { JL_GC_POP(); return (jl_value_t*)t; }
1502-
1503-
jl_value_t *result = inst_datatype((jl_datatype_t*)tt, NULL, iparams, ntp, cacheable, stack);
1493+
if (bound)
1494+
t = inst_datatype_inner(tt, NULL, iparams, ntp, cacheable, stack, env);
15041495
JL_GC_POP();
1505-
return result;
1496+
return t;
15061497
}
15071498

15081499
jl_value_t *instantiate_with(jl_value_t *t, jl_value_t **env, size_t n, jl_typeenv_t *te, jl_typestack_t *stack)
@@ -1519,21 +1510,21 @@ jl_value_t *jl_instantiate_type_with(jl_value_t *t, jl_value_t **env, size_t n)
15191510
return instantiate_with(t, env, n, NULL, NULL);
15201511
}
15211512

1522-
static jl_value_t *_jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals, jl_typeenv_t *prev)
1513+
static jl_value_t *_jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals, jl_typeenv_t *prev, jl_typestack_t *stack)
15231514
{
15241515
jl_typeenv_t en = { env->var, vals[0], prev };
15251516
if (jl_is_unionall(env->body))
1526-
return _jl_instantiate_type_in_env(ty, (jl_unionall_t*)env->body, vals + 1, &en);
1517+
return _jl_instantiate_type_in_env(ty, (jl_unionall_t*)env->body, vals + 1, &en, stack);
15271518
else
1528-
return inst_type_w_(ty, &en, NULL, 1);
1519+
return inst_type_w_(ty, &en, stack, 1);
15291520
}
15301521

15311522
JL_DLLEXPORT jl_value_t *jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals)
15321523
{
15331524
jl_value_t *typ = ty;
15341525
if (jl_is_unionall(env)) {
15351526
JL_TRY {
1536-
typ = _jl_instantiate_type_in_env(ty, env, vals, NULL);
1527+
typ = _jl_instantiate_type_in_env(ty, env, vals, NULL, NULL);
15371528
}
15381529
JL_CATCH {
15391530
typ = jl_bottom_type;
@@ -1599,11 +1590,14 @@ void jl_reinstantiate_inner_types(jl_datatype_t *t) // can throw!
15991590

16001591
int k;
16011592
assert(ndt->types == NULL);
1602-
ndt->types = jl_alloc_svec(jl_svec_len(t->types));
1603-
jl_gc_wb(ndt, ndt->types);
1593+
jl_svec_t *ft = jl_alloc_svec(jl_svec_len(t->types));
1594+
JL_GC_PUSH1(&ft);
16041595
for (k=0; k < jl_svec_len(t->types); k++) {
1605-
jl_svecset(ndt->types, k, instantiate_with(jl_svecref(t->types,k), env, n, NULL, &top));
1596+
jl_svecset(ft, k, instantiate_with(jl_svecref(t->types,k), env, n, NULL, &top));
16061597
}
1598+
ndt->types = ft;
1599+
jl_gc_wb(ndt, ndt->types);
1600+
JL_GC_POP();
16071601
if (ndt->uid) { // cacheable
16081602
jl_compute_field_offsets(ndt);
16091603
}

0 commit comments

Comments
 (0)