@@ -314,77 +314,127 @@ static int type_recursively_external(jl_datatype_t *dt) JL_NOTSAFEPOINT
314
314
return 1 ;
315
315
}
316
316
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
+
317
339
// When we infer external method instances, ensure they link back to the
318
340
// 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 )
320
342
{
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
329
343
jl_module_t * mod = mi -> def .module ;
330
344
if (jl_is_method (mod ))
331
345
mod = ((jl_method_t * )mod )-> module ;
332
346
assert (jl_is_module (mod ));
333
347
if (mi -> precompiled || module_in_worklist (mod )) {
334
- * bp = (void * )((char * )HT_NOTFOUND + 2 ); // found
335
348
return 1 ;
336
349
}
337
350
if (!mi -> backedges ) {
338
351
return 0 ;
339
352
}
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
340
362
size_t i = 0 , n = jl_array_len (mi -> backedges );
341
- jl_method_instance_t * be ;
363
+ int cycle = 0 ;
342
364
while (i < n ) {
365
+ jl_method_instance_t * be ;
343
366
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 );
348
376
}
349
377
}
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 ;
351
398
}
352
399
353
400
// given the list of MethodInstances that were inferred during the
354
401
// 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.
356
404
static size_t queue_external_mis (jl_array_t * list )
357
405
{
406
+ if (list == NULL )
407
+ return 0 ;
358
408
size_t i , n = 0 ;
359
409
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 ++ ;
382
432
}
383
433
}
384
434
}
385
435
}
386
- htable_free (& visited );
387
436
}
437
+ htable_free (& visited );
388
438
return n ;
389
439
}
390
440
@@ -1163,7 +1213,7 @@ static void serialize_htable_keys(jl_serializer_state *s, htable_t *ht, int nite
1163
1213
// or method instances not in the queue
1164
1214
//
1165
1215
// 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 )
1167
1217
{
1168
1218
jl_array_t * backedges = mt -> backedges ;
1169
1219
if (backedges ) {
@@ -1252,7 +1302,7 @@ static void jl_collect_extext_methods_from_mod(jl_array_t *s, jl_module_t *m) JL
1252
1302
(jl_value_t * )mt != jl_nothing &&
1253
1303
(mt != jl_type_type_mt && mt != jl_nonfunction_mt )) {
1254
1304
jl_collect_methtable_from_mod (s , mt );
1255
- jl_collect_missing_backedges_to_mod (mt );
1305
+ jl_collect_missing_backedges (mt );
1256
1306
}
1257
1307
}
1258
1308
}
@@ -2854,11 +2904,11 @@ JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist)
2854
2904
jl_collect_extext_methods_from_mod (extext_methods , m );
2855
2905
}
2856
2906
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 );
2858
2908
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 );
2860
2910
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.
2862
2912
// Process this to extract `edges` and `ext_targets`.
2863
2913
jl_collect_backedges (edges , ext_targets );
2864
2914
0 commit comments