Skip to content

Commit 0ffba40

Browse files
committedMay 13, 2016
memoize more type properties (#16320)
has-typevars is called pretty heavily during intersection and subtyping so it can be a hot-path fix lowering of TypeVar in TypeConstructor typealias expression: instead have lowering emit the correct TypeVar expression instead of mutating (aka corrupting) the immutable TypeVars in the TypeConstructor constructor avoid corrupting immutable TypeVar after building a DataType for them: instead have lowering emit the correct TypeVar expression instead of modifying them in the DataType constructor fix #12238 fix #16301
1 parent 906e06b commit 0ffba40

10 files changed

+122
-34
lines changed
 

‎base/inference.jl

+1-7
Original file line numberDiff line numberDiff line change
@@ -374,13 +374,7 @@ function type_depth(t::ANY)
374374
t === Bottom && return 0
375375
return maximum(type_depth, t.types) + 1
376376
elseif isa(t, DataType)
377-
t = t::DataType
378-
P = t.parameters
379-
isempty(P) && return 0
380-
if t.depth == 0
381-
t.depth = maximum(type_depth, P) + 1
382-
end
383-
return t.depth
377+
return (t::DataType).depth
384378
end
385379
return 0
386380
end

‎src/alloc.c

+16-4
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,9 @@ JL_DLLEXPORT jl_datatype_t *jl_new_uninitialized_datatype(size_t nfields, int8_t
816816
t->haspadding = 0;
817817
t->pointerfree = 0;
818818
t->depth = 0;
819+
t->hastypevars = 0;
820+
t->haswildcard = 0;
821+
t->isleaftype = 1;
819822
return t;
820823
}
821824

@@ -983,6 +986,7 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype(jl_sym_t *name, jl_datatype_t *super
983986
t->name->primary = (jl_value_t*)t;
984987
jl_gc_wb(t->name, t);
985988
}
989+
jl_precompute_memoized_dt(t);
986990

987991
if (abstract || jl_svec_len(parameters) > 0) {
988992
t->uid = 0;
@@ -1011,14 +1015,22 @@ JL_DLLEXPORT jl_datatype_t *jl_new_bitstype(jl_value_t *name, jl_datatype_t *sup
10111015

10121016
// type constructor -----------------------------------------------------------
10131017

1014-
jl_typector_t *jl_new_type_ctor(jl_svec_t *params, jl_value_t *body)
1018+
JL_DLLEXPORT jl_value_t *jl_new_type_constructor(jl_svec_t *p, jl_value_t *body)
10151019
{
1016-
jl_typector_t *tc = (jl_typector_t*)newobj((jl_value_t*)jl_typector_type,NWORDS(sizeof(jl_typector_t)));
1017-
tc->parameters = params;
1020+
#ifndef NDEBUG
1021+
size_t i, np = jl_svec_len(p);
1022+
for (i = 0; i < np; i++) {
1023+
jl_tvar_t *tv = (jl_tvar_t*)jl_svecref(p, i);
1024+
assert(jl_is_typevar(tv) && !tv->bound);
1025+
}
1026+
#endif
1027+
jl_typector_t *tc = (jl_typector_t*)newobj((jl_value_t*)jl_typector_type, NWORDS(sizeof(jl_typector_t)));
1028+
tc->parameters = p;
10181029
tc->body = body;
1019-
return (jl_typector_t*)tc;
1030+
return (jl_value_t*)tc;
10201031
}
10211032

1033+
10221034
// bits constructors ----------------------------------------------------------
10231035

10241036
#define BOXN_FUNC(nb,nw) \

‎src/builtins.c

-9
Original file line numberDiff line numberDiff line change
@@ -928,15 +928,6 @@ JL_CALLABLE(jl_f_apply_type)
928928
return jl_apply_type_(args[0], &args[1], nargs-1);
929929
}
930930

931-
JL_DLLEXPORT jl_value_t *jl_new_type_constructor(jl_svec_t *p, jl_value_t *t)
932-
{
933-
jl_value_t *tc = (jl_value_t*)jl_new_type_ctor(p, t);
934-
int i;
935-
for(i=0; i < jl_svec_len(p); i++)
936-
((jl_tvar_t*)jl_svecref(p,i))->bound = 0;
937-
return tc;
938-
}
939-
940931
// generic function reflection ------------------------------------------------
941932

942933
static void jl_check_type_tuple(jl_value_t *t, jl_sym_t *name, const char *ctx)

‎src/dump.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,9 @@ static void jl_serialize_datatype(ios_t *s, jl_datatype_t *dt)
546546
write_uint16(s, nf);
547547
write_int32(s, dt->size);
548548
int has_instance = !!(dt->instance != NULL);
549-
write_uint8(s, dt->abstract | (dt->mutabl<<1) | (dt->pointerfree<<2) | (has_instance<<3));
549+
write_uint8(s, dt->abstract | (dt->mutabl<<1) | (dt->pointerfree<<2) | (has_instance<<3) |
550+
(dt->hastypevars<<4) | (dt->haswildcard<<5) | (dt->isleaftype<<6));
551+
write_int32(s, dt->depth);
550552
write_int8(s, dt->fielddesc_type);
551553
if (!dt->abstract) {
552554
write_uint16(s, dt->ninitialized);
@@ -1173,6 +1175,7 @@ static jl_value_t *jl_deserialize_datatype(ios_t *s, int pos, jl_value_t **loc)
11731175
uint16_t nf = read_uint16(s);
11741176
size_t size = read_int32(s);
11751177
uint8_t flags = read_uint8(s);
1178+
uint8_t depth = read_int32(s);
11761179
uint8_t fielddesc_type = read_int8(s);
11771180
jl_datatype_t *dt;
11781181
if (tag == 2)
@@ -1194,6 +1197,10 @@ static jl_value_t *jl_deserialize_datatype(ios_t *s, int pos, jl_value_t **loc)
11941197
dt->abstract = flags&1;
11951198
dt->mutabl = (flags>>1)&1;
11961199
dt->pointerfree = (flags>>2)&1;
1200+
dt->hastypevars = (flags>>4)&1;
1201+
dt->haswildcard = (flags>>5)&1;
1202+
dt->isleaftype = (flags>>6)&1;
1203+
dt->depth = depth;
11971204
if (!dt->abstract) {
11981205
dt->ninitialized = read_uint16(s);
11991206
dt->uid = mode != MODE_MODULE && mode != MODE_MODULE_POSTWORK ? read_int32(s) : 0;

‎src/interpreter.c

+6-3
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,12 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, jl_lambda_info_t *la
345345
jl_datatype_t *dt = NULL;
346346
JL_GC_PUSH4(&para, &super, &temp, &dt);
347347
temp = eval(args[2], locals, lam); // field names
348+
#ifndef NDEBUG
349+
size_t i, l = jl_svec_len(para);
350+
for (i = 0; i < l; i++) {
351+
assert(!((jl_tvar_t*)jl_svecref(para, i))->bound);
352+
}
353+
#endif
348354
dt = jl_new_datatype((jl_sym_t*)name, jl_any_type, (jl_svec_t*)para,
349355
(jl_svec_t*)temp, NULL,
350356
0, args[5]==jl_true ? 1 : 0, jl_unbox_long(args[6]));
@@ -377,9 +383,6 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, jl_lambda_info_t *la
377383
b->value = temp;
378384
jl_rethrow();
379385
}
380-
for(size_t i=0; i < jl_svec_len(para); i++) {
381-
((jl_tvar_t*)jl_svecref(para,i))->bound = 0;
382-
}
383386
jl_compute_field_offsets(dt);
384387
if (para == (jl_value_t*)jl_emptysvec && jl_is_datatype_singleton(dt)) {
385388
dt->instance = newstruct(dt);

‎src/jltypes.c

+75-6
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,22 @@ static int jl_has_typevars__(jl_value_t *v, int incl_wildcard, jl_value_t **p, s
9595
if (jl_is_typector(v))
9696
return incl_wildcard;
9797
jl_svec_t *t;
98+
int expect = -1;
9899
if (jl_is_uniontype(v)) {
99100
t = ((jl_uniontype_t*)v)->types;
100101
}
101102
else if (jl_is_datatype(v)) {
102103
if (is_unspec((jl_datatype_t*)v))
103104
return 0;
105+
if (p == NULL) {
106+
if (incl_wildcard)
107+
expect = ((jl_datatype_t*)v)->haswildcard;
108+
else
109+
expect = ((jl_datatype_t*)v)->hastypevars;
110+
#ifdef NDEBUG
111+
return expect;
112+
#endif
113+
}
104114
t = ((jl_datatype_t*)v)->parameters;
105115
}
106116
else {
@@ -110,14 +120,17 @@ static int jl_has_typevars__(jl_value_t *v, int incl_wildcard, jl_value_t **p, s
110120
for(i=0; i < l; i++) {
111121
jl_value_t *elt = jl_svecref(t, i);
112122
if (elt != v) {
113-
if (jl_has_typevars__(elt, incl_wildcard, p, np))
123+
if (jl_has_typevars__(elt, incl_wildcard, p, np)) {
124+
if (expect >= 0) assert(expect);
114125
return 1;
126+
}
115127
}
116128
}
117129
// probably not necessary; no reason to use match() instead of subtype()
118130
// on the unconstrained version of a type
119131
//if (jl_is_typector(v))
120132
// return jl_svec_len((((jl_typector_t*)v)->parameters) > 0);
133+
if (expect >= 0) assert(!expect);
121134
return 0;
122135
}
123136

@@ -148,26 +161,39 @@ JL_DLLEXPORT int jl_has_typevars(jl_value_t *v)
148161
JL_DLLEXPORT int jl_is_leaf_type(jl_value_t *v)
149162
{
150163
if (jl_is_datatype(v)) {
164+
int isleaf = ((jl_datatype_t*)v)->isleaftype;
165+
#ifdef NDEBUG
166+
return isleaf;
167+
#else
151168
if (((jl_datatype_t*)v)->abstract) {
152-
if (jl_is_type_type(v))
153-
return !jl_is_typevar(jl_tparam0(v));
154-
return 0;
169+
int x = 0;
170+
if (jl_is_type_type(v)) {
171+
x = !jl_is_typevar(jl_tparam0(v));
172+
}
173+
assert(x == isleaf);
174+
return x;
155175
}
156176
jl_svec_t *t = ((jl_datatype_t*)v)->parameters;
157177
size_t l = jl_svec_len(t);
158178
if (((jl_datatype_t*)v)->name == jl_tuple_typename) {
159179
for(int i=0; i < l; i++) {
160-
if (!jl_is_leaf_type(jl_svecref(t,i)))
180+
if (!jl_is_leaf_type(jl_svecref(t,i))) {
181+
assert(!isleaf);
161182
return 0;
183+
}
162184
}
163185
}
164186
else {
165187
for(int i=0; i < l; i++) {
166-
if (jl_is_typevar(jl_svecref(t,i)))
188+
if (jl_is_typevar(jl_svecref(t,i))) {
189+
assert(!isleaf);
167190
return 0;
191+
}
168192
}
169193
}
194+
assert(isleaf);
170195
return 1;
196+
#endif
171197
}
172198
return 0;
173199
}
@@ -2039,6 +2065,45 @@ static jl_value_t *lookup_type_stack(jl_typestack_t *stack, jl_datatype_t *tt, s
20392065
return NULL;
20402066
}
20412067

2068+
static size_t jl_type_depth(jl_value_t *dt)
2069+
{
2070+
if (jl_is_uniontype(dt)) {
2071+
jl_svec_t *t = ((jl_uniontype_t*)dt)->types;
2072+
size_t i, l = jl_svec_len(t);
2073+
size_t depth = 0;
2074+
for (i = 0; i < l; i++) {
2075+
jl_value_t *p = jl_svecref(t, i);
2076+
size_t d = jl_type_depth(p);
2077+
if (d > depth)
2078+
depth = d;
2079+
}
2080+
return depth;
2081+
}
2082+
else if (jl_is_datatype(dt)) {
2083+
return ((jl_datatype_t*)dt)->depth;
2084+
}
2085+
return 0;
2086+
}
2087+
2088+
void jl_precompute_memoized_dt(jl_datatype_t *dt)
2089+
{
2090+
int istuple = dt->name == jl_tuple_typename;
2091+
size_t i, l = jl_nparams(dt);
2092+
dt->isleaftype = !dt->abstract || (jl_type_type != NULL && dt->name == jl_type_type->name);
2093+
for (i = 0; i < l; i++) {
2094+
jl_value_t *p = jl_tparam(dt, i);
2095+
size_t d = jl_type_depth(p) + 1;
2096+
if (d > dt->depth)
2097+
dt->depth = d;
2098+
if (!dt->hastypevars)
2099+
dt->hastypevars = jl_has_typevars__(p, 0, NULL, 0);
2100+
if (!dt->haswildcard)
2101+
dt->haswildcard = jl_has_typevars__(p, 1, NULL, 0);
2102+
if (dt->isleaftype)
2103+
dt->isleaftype = (istuple ? jl_is_leaf_type(p) : !jl_is_typevar(p));
2104+
}
2105+
}
2106+
20422107
static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp,
20432108
int cacheable, int isabstract, jl_typestack_t *stack,
20442109
jl_value_t **env, size_t n)
@@ -2115,6 +2180,7 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
21152180
ndt->ditype = NULL;
21162181
ndt->size = 0;
21172182
ndt->alignment = 1;
2183+
jl_precompute_memoized_dt(ndt);
21182184

21192185
// assign uid as early as possible
21202186
if (cacheable && !ndt->abstract && ndt->uid==0)
@@ -3340,6 +3406,9 @@ void jl_init_types(void)
33403406
//jl_anytuple_type->parameters = jl_svec(1, jl_wrap_vararg((jl_value_t*)NULL, (jl_value_t*)NULL));
33413407
jl_anytuple_type->types = jl_anytuple_type->parameters;
33423408
jl_anytuple_type->nfields = 1;
3409+
jl_anytuple_type->hastypevars = 1;
3410+
jl_anytuple_type->haswildcard = 1;
3411+
jl_anytuple_type->isleaftype = 0;
33433412

33443413
jl_tvar_t *tttvar = jl_new_typevar(jl_symbol("T"),
33453414
(jl_value_t*)jl_bottom_type,(jl_value_t*)jl_any_type);

‎src/julia-syntax.scm

+3-3
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,7 @@
791791
(block
792792
(global ,name) (const ,name)
793793
,@(map (lambda (v) `(local ,v)) params)
794-
,@(map make-assignment params (symbols->typevars params bounds #t))
794+
,@(map make-assignment params (symbols->typevars params bounds #f))
795795
(composite_type ,name (call (core svec) ,@params)
796796
(call (core svec) ,@(map (lambda (x) `',x) field-names))
797797
,super (call (core svec) ,@field-types) ,mut ,min-initialized)))
@@ -1174,7 +1174,7 @@
11741174
,@(map (lambda (v) `(local ,v)) params)
11751175
,@(map (lambda (l r) (make-assignment l (expand-forms r)))
11761176
params
1177-
(symbols->typevars params bounds #t))
1177+
(symbols->typevars params bounds #f))
11781178
(call (core TypeConstructor)
11791179
(call (core svec) ,@params)
11801180
,(expand-forms type-ex))))))))
@@ -2487,7 +2487,7 @@ f(x) = yt(x)
24872487
((,@(map (lambda (p) `(,p Any 18)) P))
24882488
() 0 ())
24892489
(body (global ,name) (const ,name)
2490-
,@(map (lambda (p) `(= ,p (call (core TypeVar) ',p (core Any) true))) P)
2490+
,@(map (lambda (p) `(= ,p (call (core TypeVar) ',p (core Any) false))) P)
24912491
(composite_type ,name (call (core svec) ,@P)
24922492
(call (core svec) ,@(map (lambda (v) `',v) fields))
24932493
,super

‎src/julia.h

+4
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,11 @@ typedef struct _jl_datatype_t {
329329
uint8_t mutabl;
330330
uint8_t pointerfree;
331331
int32_t ninitialized;
332+
// memoized properties
332333
int32_t depth;
334+
int8_t hastypevars; // bound
335+
int8_t haswildcard; // unbound
336+
int8_t isleaftype;
333337
// hidden fields:
334338
uint32_t nfields;
335339
uint32_t alignment : 29; // strictest alignment over all fields

‎src/julia_internal.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,11 @@ STATIC_INLINE int jl_is_type(jl_value_t *v)
182182
}
183183
jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b,
184184
jl_svec_t **penv, jl_svec_t *tvars);
185-
jl_typector_t *jl_new_type_ctor(jl_svec_t *params, jl_value_t *body);
186185
jl_value_t *jl_apply_type_(jl_value_t *tc, jl_value_t **params, size_t n);
187186
jl_value_t *jl_instantiate_type_with(jl_value_t *t, jl_value_t **env, size_t n);
188187
jl_datatype_t *jl_new_abstracttype(jl_value_t *name, jl_datatype_t *super,
189188
jl_svec_t *parameters);
189+
void jl_precompute_memoized_dt(jl_datatype_t *dt);
190190
jl_datatype_t *jl_wrap_Type(jl_value_t *t); // x -> Type{x}
191191
jl_datatype_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n);
192192
void jl_assign_bits(void *dest, jl_value_t *bits);

‎test/core.jl

+8
Original file line numberDiff line numberDiff line change
@@ -4113,6 +4113,14 @@ f16090() = typeof(undefined_x16090::Tuple{Type{Int}})
41134113
undefined_x16090 = (Int,)
41144114
@test_throws TypeError f16090()
41154115

4116+
# issue #12238
4117+
type A12238{T} end
4118+
type B12238{T,S}
4119+
a::A12238{B12238{Int,S}}
4120+
end
4121+
@test B12238.types[1] === A12238{B12238{Int}}
4122+
@test A12238{B12238{Int}}.instance === B12238.types[1].instance
4123+
41164124
# issue #16315
41174125
let a = Any[]
41184126
@noinline f() = a[end]

0 commit comments

Comments
 (0)
Please sign in to comment.