Skip to content

Commit 0241c5f

Browse files
committed
turn Method.specializations into a simpler list+keyhash
1 parent 91153df commit 0241c5f

File tree

12 files changed

+389
-102
lines changed

12 files changed

+389
-102
lines changed

base/compiler/utilities.jl

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,9 @@ end
126126
# get a handle to the unique specialization object representing a particular instantiation of a call
127127
function specialize_method(method::Method, @nospecialize(atypes), sparams::SimpleVector, preexisting::Bool=false)
128128
if preexisting
129-
if method.specializations !== nothing
130-
# check cached specializations
131-
# for an existing result stored there
132-
return ccall(:jl_specializations_lookup, Any, (Any, Any), method, atypes)
133-
end
134-
return nothing
129+
# check cached specializations
130+
# for an existing result stored there
131+
return ccall(:jl_specializations_lookup, Any, (Any, Any), method, atypes)
135132
end
136133
return ccall(:jl_specializations_get_linfo, Ref{MethodInstance}, (Any, Any, Any), method, atypes, sparams)
137134
end

src/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ FLAGS += -I$(LOCALBASE)/include
4040
endif
4141

4242
RUNTIME_SRCS := \
43-
jltypes gf typemap ast builtins module interpreter symbol \
43+
jltypes gf typemap smallintset ast builtins module interpreter symbol \
4444
dlload sys init task array dump staticdata toplevel jl_uv datatype \
4545
simplevector runtime_intrinsics precompile \
4646
threading partr stackwalk gc gc-debug gc-pages gc-stacks method \

src/dump.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,7 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li
851851
assert((jl_value_t*)mt != jl_nothing);
852852
external_mt = !module_in_worklist(mt->module);
853853
jl_serialize_value(s, m->specializations);
854+
jl_serialize_value(s, m->speckeyset);
854855
jl_serialize_value(s, (jl_value_t*)m->name);
855856
jl_serialize_value(s, (jl_value_t*)m->file);
856857
write_int32(s->s, m->line);
@@ -1149,14 +1150,6 @@ static void collect_backedges(jl_method_instance_t *callee) JL_GC_DISABLED
11491150
}
11501151

11511152

1152-
static int jl_collect_backedges_to_mod(jl_typemap_entry_t *ml, void *closure) JL_GC_DISABLED
1153-
{
1154-
(void)(jl_array_t*)closure;
1155-
jl_method_instance_t *callee = ml->func.linfo;
1156-
collect_backedges(callee);
1157-
return 1;
1158-
}
1159-
11601153
static int jl_collect_methcache_from_mod(jl_typemap_entry_t *ml, void *closure) JL_GC_DISABLED
11611154
{
11621155
jl_array_t *s = (jl_array_t*)closure;
@@ -1166,7 +1159,13 @@ static int jl_collect_methcache_from_mod(jl_typemap_entry_t *ml, void *closure)
11661159
jl_array_ptr_1d_push(s, (jl_value_t*)ml->simplesig);
11671160
}
11681161
else {
1169-
jl_typemap_visitor(m->specializations, jl_collect_backedges_to_mod, closure);
1162+
jl_svec_t *specializations = m->specializations;
1163+
size_t i, l = jl_svec_len(specializations);
1164+
for (i = 0; i < l; i++) {
1165+
jl_method_instance_t *callee = (jl_method_instance_t*)jl_svecref(specializations, i);
1166+
if (callee != NULL)
1167+
collect_backedges(callee);
1168+
}
11701169
}
11711170
return 1;
11721171
}
@@ -1719,8 +1718,10 @@ static jl_value_t *jl_deserialize_value_method(jl_serializer_state *s, jl_value_
17191718
arraylist_push(&flagref_list, (void*)pos);
17201719
return (jl_value_t*)m;
17211720
}
1722-
m->specializations = jl_deserialize_value(s, (jl_value_t**)&m->specializations);
1721+
m->specializations = (jl_svec_t*)jl_deserialize_value(s, (jl_value_t**)&m->specializations);
17231722
jl_gc_wb(m, m->specializations);
1723+
m->speckeyset = (jl_array_t*)jl_deserialize_value(s, (jl_value_t**)&m->speckeyset);
1724+
jl_gc_wb(m, m->speckeyset);
17241725
m->name = (jl_sym_t*)jl_deserialize_value(s, NULL);
17251726
jl_gc_wb(m, m->name);
17261727
m->file = (jl_sym_t*)jl_deserialize_value(s, NULL);

src/gf.c

Lines changed: 145 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -86,34 +86,119 @@ static int8_t jl_cachearg_offset(jl_methtable_t *mt)
8686

8787
/// ----- Insertion logic for special entries ----- ///
8888

89+
90+
static uint_t speccache_hash(size_t idx, jl_svec_t *data)
91+
{
92+
jl_method_instance_t *ml = (jl_method_instance_t*)jl_svecref(data, idx);
93+
jl_value_t *sig = ml->specTypes;
94+
if (jl_is_unionall(sig))
95+
sig = jl_unwrap_unionall(sig);
96+
return ((jl_datatype_t*)sig)->hash;
97+
}
98+
99+
static int speccache_eq(size_t idx, const void *ty, jl_svec_t *data, uint_t hv)
100+
{
101+
jl_method_instance_t *ml = (jl_method_instance_t*)jl_svecref(data, idx);
102+
jl_value_t *sig = ml->specTypes;
103+
if (ty == sig)
104+
return 1;
105+
uint_t h2 = ((jl_datatype_t*)(jl_is_unionall(sig) ? jl_unwrap_unionall(sig) : sig))->hash;
106+
if (h2 != hv)
107+
return 0;
108+
return jl_types_equal(sig, (jl_value_t*)ty);
109+
}
110+
89111
// get or create the MethodInstance for a specialization
90112
JL_DLLEXPORT jl_method_instance_t *jl_specializations_get_linfo(jl_method_t *m JL_PROPAGATES_ROOT, jl_value_t *type, jl_svec_t *sparams)
91113
{
92-
JL_LOCK(&m->writelock);
93-
struct jl_typemap_assoc search = {type, 1, 0, NULL, 0, ~(size_t)0};
94-
jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(m->specializations, &search, /*offs*/0, /*subtype*/0);
95-
if (sf && jl_is_method_instance(sf->func.value)) {
96-
JL_UNLOCK(&m->writelock);
97-
return sf->func.linfo;
98-
}
99-
jl_method_instance_t *mi = jl_get_specialized(m, type, sparams);
100-
JL_GC_PUSH1(&mi);
101-
// TODO: fuse lookup and insert steps
102-
jl_typemap_insert(&m->specializations, (jl_value_t*)m, (jl_tupletype_t*)type,
103-
NULL, jl_emptysvec, (jl_value_t*)mi, 0, &tfunc_cache,
104-
1, ~(size_t)0);
105-
JL_UNLOCK(&m->writelock);
106-
JL_GC_POP();
107-
return mi;
114+
uint_t hv = ((jl_datatype_t*)(jl_is_unionall(type) ? jl_unwrap_unionall(type) : type))->hash;
115+
for (int locked = 0; ; locked++) {
116+
jl_array_t *speckeyset = jl_atomic_load_acquire(&m->speckeyset);
117+
jl_svec_t *specializations = jl_atomic_load_acquire(&m->specializations);
118+
size_t i, cl = jl_svec_len(specializations);
119+
if (hv) {
120+
ssize_t idx = jl_smallintset_lookup(speckeyset, speccache_eq, type, specializations, hv);
121+
if (idx != -1) {
122+
jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, idx);
123+
JL_GC_PROMISE_ROOTED(mi); // clang-sa doesn't understand jl_atomic_load_relaxed
124+
if (locked)
125+
JL_UNLOCK(&m->writelock);
126+
return mi;
127+
}
128+
}
129+
else {
130+
jl_method_instance_t **data = (jl_method_instance_t**)jl_svec_data(specializations);
131+
JL_GC_PUSH1(&specializations); // clang-sa doesn't realize this loop uses specializations
132+
for (i = cl; i > 0; i--) {
133+
jl_method_instance_t *mi = jl_atomic_load_relaxed(&data[i - 1]);
134+
JL_GC_PROMISE_ROOTED(mi); // clang-sa doesn't understand jl_atomic_load_relaxed
135+
if (mi == NULL)
136+
break;
137+
if (jl_types_equal(mi->specTypes, type)) {
138+
if (locked)
139+
JL_UNLOCK(&m->writelock);
140+
JL_GC_POP();
141+
return mi;
142+
}
143+
}
144+
JL_GC_POP();
145+
}
146+
if (!sparams) // can't insert without knowing this
147+
return NULL;
148+
if (!locked) {
149+
JL_LOCK(&m->writelock);
150+
}
151+
else {
152+
if (hv) {
153+
jl_method_instance_t **data = (jl_method_instance_t**)jl_svec_data(specializations);
154+
for (i = 0; i < cl; i++) {
155+
jl_method_instance_t *mi = jl_atomic_load_relaxed(&data[i]);
156+
JL_GC_PROMISE_ROOTED(mi); // clang-sa doesn't understand jl_atomic_load_relaxed
157+
if (mi == NULL)
158+
break;
159+
assert(!jl_types_equal(mi->specTypes, type));
160+
}
161+
}
162+
jl_method_instance_t *mi = jl_get_specialized(m, type, sparams);
163+
JL_GC_PUSH1(&mi);
164+
if (hv ? (i + 1 >= cl || jl_svecref(specializations, i + 1) != NULL) : (i <= 1 || jl_svecref(specializations, i - 2) != NULL)) {
165+
size_t ncl = cl < 8 ? 8 : (cl*3)>>1;
166+
jl_svec_t *nc = jl_alloc_svec_uninit(ncl);
167+
if (i > 0)
168+
memcpy((char*)jl_svec_data(nc), jl_svec_data(specializations), sizeof(void*) * i);
169+
memset((char*)jl_svec_data(nc) + sizeof(void*) * i, 0, sizeof(void*) * (ncl - cl));
170+
if (i < cl)
171+
memcpy((char*)jl_svec_data(nc) + sizeof(void*) * (i + ncl - cl),
172+
(char*)jl_svec_data(specializations) + sizeof(void*) * i,
173+
sizeof(void*) * (cl - i));
174+
jl_atomic_store_release(&m->specializations, nc);
175+
JL_GC_PROMISE_ROOTED(nc); // clang-sa doesn't understand jl_atomic_store_release
176+
jl_gc_wb(m, nc);
177+
specializations = nc;
178+
if (!hv)
179+
i += ncl - cl;
180+
}
181+
if (!hv)
182+
i -= 1;
183+
assert(jl_svecref(specializations, i) == NULL);
184+
jl_svecset(specializations, i, mi); // jl_atomic_store_release?
185+
if (hv) {
186+
// TODO: fuse lookup and insert steps?
187+
jl_smallintset_insert(&m->speckeyset, (jl_value_t*)m, speccache_hash, i, specializations);
188+
}
189+
JL_UNLOCK(&m->writelock);
190+
JL_GC_POP();
191+
return mi;
192+
}
193+
}
108194
}
109195

110196
JL_DLLEXPORT jl_value_t *jl_specializations_lookup(jl_method_t *m, jl_value_t *type)
111197
{
112-
struct jl_typemap_assoc search = {type, 1, 0, NULL, 0, ~(size_t)0};
113-
jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(m->specializations, &search, /*offs*/0, /*subtype*/0);
114-
if (!sf)
198+
jl_value_t *mi = (jl_value_t*)jl_specializations_get_linfo(m, type, NULL);
199+
if (mi == NULL)
115200
return jl_nothing;
116-
return sf->func.value;
201+
return mi;
117202
}
118203

119204
JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_methtable_t *mt, jl_value_t *type, size_t world)
@@ -318,18 +403,18 @@ JL_DLLEXPORT jl_code_instance_t *jl_set_method_inferred(
318403
return codeinst;
319404
}
320405

321-
static int get_spec_unspec_list(jl_typemap_entry_t *l, void *closure)
322-
{
323-
jl_method_instance_t *mi = l->func.linfo;
324-
assert(jl_is_method_instance(mi));
325-
if (jl_rettype_inferred(mi, jl_world_counter, jl_world_counter) == jl_nothing)
326-
jl_array_ptr_1d_push((jl_array_t*)closure, l->func.value);
327-
return 1;
328-
}
329-
330406
static int get_method_unspec_list(jl_typemap_entry_t *def, void *closure)
331407
{
332-
jl_typemap_visitor(def->func.method->specializations, get_spec_unspec_list, closure);
408+
jl_svec_t *specializations = def->func.method->specializations;
409+
size_t i, l = jl_svec_len(specializations);
410+
for (i = 0; i < l; i++) {
411+
jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, i);
412+
if (mi) {
413+
assert(jl_is_method_instance(mi));
414+
if (jl_rettype_inferred(mi, jl_world_counter, jl_world_counter) == jl_nothing)
415+
jl_array_ptr_1d_push((jl_array_t*)closure, (jl_value_t*)mi);
416+
}
417+
}
333418
return 1;
334419
}
335420

@@ -1440,29 +1525,23 @@ static void invalidate_method_instance(jl_method_instance_t *replaced, size_t ma
14401525
}
14411526

14421527
// invalidate cached methods that overlap this definition
1443-
struct invalidate_conflicting_env {
1444-
struct typemap_intersection_env match;
1445-
size_t max_world;
1446-
int invalidated;
1447-
};
1448-
static int invalidate_backedges(jl_typemap_entry_t *oldentry, struct typemap_intersection_env *closure0)
1528+
static int invalidate_backedges(jl_method_instance_t *replaced_linfo, size_t max_world)
14491529
{
1450-
struct invalidate_conflicting_env *closure = container_of(closure0, struct invalidate_conflicting_env, match);
1451-
jl_method_instance_t *replaced_linfo = oldentry->func.linfo;
14521530
JL_LOCK_NOGC(&replaced_linfo->def.method->writelock);
14531531
jl_array_t *backedges = replaced_linfo->backedges;
1532+
int invalidated = 0;
14541533
if (backedges) {
14551534
// invalidate callers (if any)
14561535
replaced_linfo->backedges = NULL;
14571536
size_t i, l = jl_array_len(backedges);
14581537
jl_method_instance_t **replaced = (jl_method_instance_t**)jl_array_ptr_data(backedges);
14591538
for (i = 0; i < l; i++) {
1460-
invalidate_method_instance(replaced[i], closure->max_world, 1);
1539+
invalidate_method_instance(replaced[i], max_world, 1);
14611540
}
1462-
closure->invalidated = 1;
1541+
invalidated = 1;
14631542
}
14641543
JL_UNLOCK_NOGC(&replaced_linfo->def.method->writelock);
1465-
return 1;
1544+
return invalidated;
14661545
}
14671546

14681547
// add a backedge from callee to caller
@@ -1595,10 +1674,13 @@ JL_DLLEXPORT void jl_method_table_disable(jl_methtable_t *mt, jl_method_t *metho
15951674
mt_cache_env.shadowed = (jl_value_t*)method;
15961675
jl_typemap_visitor(mt->cache, invalidate_mt_cache, (void*)&mt_cache_env);
15971676
// Invalidate the backedges
1598-
struct invalidate_conflicting_env env = {{NULL, NULL, NULL}};
1599-
env.invalidated = 0;
1600-
env.max_world = methodentry->max_world;
1601-
jl_typemap_visitor(methodentry->func.method->specializations, (jl_typemap_visitor_fptr)invalidate_backedges, &env.match);
1677+
jl_svec_t *specializations = methodentry->func.method->specializations;
1678+
size_t i, l = jl_svec_len(specializations);
1679+
for (i = 0; i < l; i++) {
1680+
jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, i);
1681+
if (mi)
1682+
invalidate_backedges(mi, methodentry->max_world);
1683+
}
16021684
JL_UNLOCK(&mt->writelock);
16031685
}
16041686

@@ -1667,34 +1749,30 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method
16671749
// mt->cache = jl_nothing;
16681750
//}
16691751

1670-
jl_datatype_t *unw = (jl_datatype_t*)jl_unwrap_unionall(type);
1671-
size_t l = jl_svec_len(unw->parameters);
1672-
jl_value_t *va = NULL;
1673-
if (l > 0) {
1674-
va = jl_tparam(unw, l - 1);
1675-
if (jl_is_vararg_type(va))
1676-
va = jl_unwrap_vararg(va);
1677-
else
1678-
va = NULL;
1679-
}
1680-
struct invalidate_conflicting_env env = {{invalidate_backedges, (jl_value_t*)type, va}};
1681-
env.invalidated = 0;
1682-
env.max_world = max_world;
1683-
env.match.env = NULL;
1684-
1752+
jl_value_t **d;
1753+
size_t j, n;
16851754
if (jl_is_method(oldvalue)) {
1686-
jl_typemap_intersection_visitor(((jl_method_t*)oldvalue)->specializations, 0, &env.match);
1755+
d = &oldvalue;
1756+
n = 1;
16871757
}
16881758
else {
16891759
assert(jl_is_array(oldvalue));
1690-
jl_typemap_entry_t **d = (jl_typemap_entry_t**)jl_array_ptr_data(oldvalue);
1691-
size_t i, n = jl_array_len(oldvalue);
1692-
for (i = 0; i < n; i++) {
1693-
jl_typemap_intersection_visitor(d[i]->func.method->specializations, 0, &env.match);
1760+
d = jl_array_ptr_data(oldvalue);
1761+
n = jl_array_len(oldvalue);
1762+
}
1763+
for (j = 0; j < n; j++) {
1764+
jl_value_t *m = d[j];
1765+
if (jl_is_array(oldvalue))
1766+
m = ((jl_typemap_entry_t*)m)->func.value;
1767+
jl_svec_t *specializations = ((jl_method_t*)m)->specializations;
1768+
size_t i, l = jl_svec_len(specializations);
1769+
for (i = 0; i < l; i++) {
1770+
jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, i);
1771+
if (mi != NULL && !jl_has_empty_intersection(type, (jl_value_t*)mi->specTypes))
1772+
if (invalidate_backedges(mi, max_world))
1773+
invalidated = 1;
16941774
}
16951775
}
1696-
if (env.invalidated)
1697-
invalidated = 1;
16981776
}
16991777
if (invalidated && JL_DEBUG_METHOD_INVALIDATION) {
17001778
jl_uv_puts(JL_STDOUT, ">> ", 3);

0 commit comments

Comments
 (0)