Skip to content

Commit d4f0567

Browse files
authored
dump: implement cycle handling in has_backedge_to_worklist (#46749)
1 parent ed01ee0 commit d4f0567

File tree

1 file changed

+95
-45
lines changed

1 file changed

+95
-45
lines changed

src/dump.c

Lines changed: 95 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -314,77 +314,127 @@ static int type_recursively_external(jl_datatype_t *dt) JL_NOTSAFEPOINT
314314
return 1;
315315
}
316316

317+
static void mark_backedges_in_worklist(jl_method_instance_t *mi, htable_t *visited, int found)
318+
{
319+
int oldfound = (char*)ptrhash_get(visited, mi) - (char*)HT_NOTFOUND;
320+
if (oldfound < 3)
321+
return; // not in-progress
322+
ptrhash_put(visited, mi, (void*)((char*)HT_NOTFOUND + 1 + found));
323+
#ifndef NDEBUG
324+
jl_module_t *mod = mi->def.module;
325+
if (jl_is_method(mod))
326+
mod = ((jl_method_t*)mod)->module;
327+
assert(jl_is_module(mod));
328+
assert(!mi->precompiled && !module_in_worklist(mod));
329+
assert(mi->backedges);
330+
#endif
331+
size_t i = 0, n = jl_array_len(mi->backedges);
332+
while (i < n) {
333+
jl_method_instance_t *be;
334+
i = get_next_edge(mi->backedges, i, NULL, &be);
335+
mark_backedges_in_worklist(be, visited, found);
336+
}
337+
}
338+
317339
// When we infer external method instances, ensure they link back to the
318340
// package. Otherwise they might be, e.g., for external macros
319-
static int has_backedge_to_worklist(jl_method_instance_t *mi, htable_t *visited)
341+
static int has_backedge_to_worklist(jl_method_instance_t *mi, htable_t *visited, int depth)
320342
{
321-
void **bp = ptrhash_bp(visited, mi);
322-
// HT_NOTFOUND: not yet analyzed
323-
// HT_NOTFOUND + 1: doesn't link back
324-
// HT_NOTFOUND + 2: does link back
325-
if (*bp != HT_NOTFOUND)
326-
return (char*)*bp - (char*)HT_NOTFOUND - 1;
327-
*bp = (void*)((char*)HT_NOTFOUND + 1); // preliminarily mark as "not found"
328-
// TODO: this algorithm deals with cycles incorrectly
329343
jl_module_t *mod = mi->def.module;
330344
if (jl_is_method(mod))
331345
mod = ((jl_method_t*)mod)->module;
332346
assert(jl_is_module(mod));
333347
if (mi->precompiled || module_in_worklist(mod)) {
334-
*bp = (void*)((char*)HT_NOTFOUND + 2); // found
335348
return 1;
336349
}
337350
if (!mi->backedges) {
338351
return 0;
339352
}
353+
void **bp = ptrhash_bp(visited, mi);
354+
// HT_NOTFOUND: not yet analyzed
355+
// HT_NOTFOUND + 1: no link back
356+
// HT_NOTFOUND + 2: does link back
357+
// HT_NOTFOUND + 3 + depth: in-progress
358+
int found = (char*)*bp - (char*)HT_NOTFOUND;
359+
if (found)
360+
return found - 1;
361+
*bp = (void*)((char*)HT_NOTFOUND + 3 + depth); // preliminarily mark as in-progress
340362
size_t i = 0, n = jl_array_len(mi->backedges);
341-
jl_method_instance_t *be;
363+
int cycle = 0;
342364
while (i < n) {
365+
jl_method_instance_t *be;
343366
i = get_next_edge(mi->backedges, i, NULL, &be);
344-
if (has_backedge_to_worklist(be, visited)) {
345-
bp = ptrhash_bp(visited, mi); // re-acquire since rehashing might change the location
346-
*bp = (void*)((char*)HT_NOTFOUND + 2); // found
347-
return 1;
367+
int child_found = has_backedge_to_worklist(be, visited, depth + 1);
368+
if (child_found == 1) {
369+
found = 1;
370+
break;
371+
}
372+
else if (child_found >= 2 && child_found - 2 < cycle) {
373+
// record the cycle will resolve at depth "cycle"
374+
cycle = child_found - 2;
375+
assert(cycle);
348376
}
349377
}
350-
return 0;
378+
if (!found && cycle && cycle != depth)
379+
return cycle + 2;
380+
bp = ptrhash_bp(visited, mi); // re-acquire since rehashing might change the location
381+
*bp = (void*)((char*)HT_NOTFOUND + 1 + found);
382+
if (cycle) {
383+
// If we are the top of the current cycle, now mark all other parts of
384+
// our cycle by re-walking the backedges graph and marking all WIP
385+
// items as found.
386+
// Be careful to only re-walk as far as we had originally scanned above.
387+
// Or if we found a backedge, also mark all of the other parts of the
388+
// cycle as also having an backedge.
389+
n = i;
390+
i = 0;
391+
while (i < n) {
392+
jl_method_instance_t *be;
393+
i = get_next_edge(mi->backedges, i, NULL, &be);
394+
mark_backedges_in_worklist(be, visited, found);
395+
}
396+
}
397+
return found;
351398
}
352399

353400
// given the list of MethodInstances that were inferred during the
354401
// build, select those that are external and have at least one
355-
// relocatable CodeInstance.
402+
// relocatable CodeInstance and are inferred to be called from the worklist
403+
// or explicitly added by a precompile statement.
356404
static size_t queue_external_mis(jl_array_t *list)
357405
{
406+
if (list == NULL)
407+
return 0;
358408
size_t i, n = 0;
359409
htable_t visited;
360-
if (list) {
361-
assert(jl_is_array(list));
362-
size_t n0 = jl_array_len(list);
363-
htable_new(&visited, n0);
364-
for (i = 0; i < n0; i++) {
365-
jl_method_instance_t *mi = (jl_method_instance_t*)jl_array_ptr_ref(list, i);
366-
assert(jl_is_method_instance(mi));
367-
if (jl_is_method(mi->def.value)) {
368-
jl_method_t *m = mi->def.method;
369-
if (!module_in_worklist(m->module)) {
370-
jl_code_instance_t *ci = mi->cache;
371-
int relocatable = 0;
372-
while (ci) {
373-
if (ci->max_world == ~(size_t)0)
374-
relocatable |= ci->relocatability;
375-
ci = ci->next;
376-
}
377-
if (relocatable && ptrhash_get(&external_mis, mi) == HT_NOTFOUND) {
378-
if (has_backedge_to_worklist(mi, &visited)) {
379-
ptrhash_put(&external_mis, mi, mi);
380-
n++;
381-
}
410+
assert(jl_is_array(list));
411+
size_t n0 = jl_array_len(list);
412+
htable_new(&visited, n0);
413+
for (i = 0; i < n0; i++) {
414+
jl_method_instance_t *mi = (jl_method_instance_t*)jl_array_ptr_ref(list, i);
415+
assert(jl_is_method_instance(mi));
416+
if (jl_is_method(mi->def.value)) {
417+
jl_method_t *m = mi->def.method;
418+
if (!module_in_worklist(m->module)) {
419+
jl_code_instance_t *ci = mi->cache;
420+
int relocatable = 0;
421+
while (ci) {
422+
if (ci->max_world == ~(size_t)0)
423+
relocatable |= ci->relocatability;
424+
ci = ci->next;
425+
}
426+
if (relocatable && ptrhash_get(&external_mis, mi) == HT_NOTFOUND) {
427+
int found = has_backedge_to_worklist(mi, &visited, 1);
428+
assert(found == 0 || found == 1);
429+
if (found == 1) {
430+
ptrhash_put(&external_mis, mi, mi);
431+
n++;
382432
}
383433
}
384434
}
385435
}
386-
htable_free(&visited);
387436
}
437+
htable_free(&visited);
388438
return n;
389439
}
390440

@@ -1163,7 +1213,7 @@ static void serialize_htable_keys(jl_serializer_state *s, htable_t *ht, int nite
11631213
// or method instances not in the queue
11641214
//
11651215
// from MethodTables
1166-
static void jl_collect_missing_backedges_to_mod(jl_methtable_t *mt)
1216+
static void jl_collect_missing_backedges(jl_methtable_t *mt)
11671217
{
11681218
jl_array_t *backedges = mt->backedges;
11691219
if (backedges) {
@@ -1252,7 +1302,7 @@ static void jl_collect_extext_methods_from_mod(jl_array_t *s, jl_module_t *m) JL
12521302
(jl_value_t*)mt != jl_nothing &&
12531303
(mt != jl_type_type_mt && mt != jl_nonfunction_mt)) {
12541304
jl_collect_methtable_from_mod(s, mt);
1255-
jl_collect_missing_backedges_to_mod(mt);
1305+
jl_collect_missing_backedges(mt);
12561306
}
12571307
}
12581308
}
@@ -2854,11 +2904,11 @@ JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist)
28542904
jl_collect_extext_methods_from_mod(extext_methods, m);
28552905
}
28562906
jl_collect_methtable_from_mod(extext_methods, jl_type_type_mt);
2857-
jl_collect_missing_backedges_to_mod(jl_type_type_mt);
2907+
jl_collect_missing_backedges(jl_type_type_mt);
28582908
jl_collect_methtable_from_mod(extext_methods, jl_nonfunction_mt);
2859-
jl_collect_missing_backedges_to_mod(jl_nonfunction_mt);
2909+
jl_collect_missing_backedges(jl_nonfunction_mt);
28602910

2861-
// jl_collect_extext_methods_from_mod and jl_collect_missing_backedges_to_mod accumulate data in edges_map.
2911+
// jl_collect_extext_methods_from_mod and jl_collect_missing_backedges accumulate data in edges_map.
28622912
// Process this to extract `edges` and `ext_targets`.
28632913
jl_collect_backedges(edges, ext_targets);
28642914

0 commit comments

Comments
 (0)