@@ -136,15 +136,18 @@ static jl_binding_partition_t *jl_implicit_import_resolved(jl_binding_t *b, stru
136136 if (jl_is_binding_partition (gap .parent )) {
137137 // Check if we can merge this into the previous binding partition
138138 jl_binding_partition_t * prev = (jl_binding_partition_t * )gap .parent ;
139+ assert (new_max_world != ~(size_t )0 ); // It is inconsistent to have a gap with `gap.parent` set, but max_world == ~(size_t)0
139140 size_t expected_prev_min_world = new_max_world + 1 ;
140141 if (prev -> restriction == resolution .binding_or_const && prev -> kind == new_kind ) {
142+ retry :
141143 if (!jl_atomic_cmpswap (& prev -> min_world , & expected_prev_min_world , new_min_world )) {
142144 if (expected_prev_min_world <= new_min_world ) {
143145 return prev ;
144146 }
145147 else if (expected_prev_min_world <= new_max_world ) {
146- // Concurrent modification by another thread - bail.
147- return NULL ;
148+ // Concurrent modification of the partition. However, our lookup is still valid,
149+ // so we should still be able to extend the partition.
150+ goto retry ;
148151 }
149152 // There remains a gap - proceed
150153 } else {
@@ -154,7 +157,7 @@ static jl_binding_partition_t *jl_implicit_import_resolved(jl_binding_t *b, stru
154157 for (;;) {
155158 // We've updated the previous partition - check if we've closed a gap
156159 size_t next_max_world = jl_atomic_load_relaxed (& next -> max_world );
157- if (next_max_world = = expected_prev_min_world - 1 && next -> kind == new_kind && next -> restriction == resolution .binding_or_const ) {
160+ if (next_max_world > = expected_prev_min_world - 1 && next -> kind == new_kind && next -> restriction == resolution .binding_or_const ) {
158161 if (jl_atomic_cmpswap (& prev -> min_world , & expected_prev_min_world , next_min_world )) {
159162 jl_binding_partition_t * nextnext = jl_atomic_load_relaxed (& next -> next );
160163 if (!jl_atomic_cmpswap (& prev -> next , & next , nextnext )) {
@@ -370,15 +373,15 @@ JL_DLLEXPORT void jl_update_loaded_bpart(jl_binding_t *b, jl_binding_partition_t
370373 bpart -> kind = resolution .ultimate_kind ;
371374}
372375
373- STATIC_INLINE jl_binding_partition_t * jl_get_binding_partition_ (jl_binding_t * b JL_PROPAGATES_ROOT , jl_value_t * parent , _Atomic (jl_binding_partition_t * )* insert , size_t world , modstack_t * st ) JL_GLOBALLY_ROOTED
376+ STATIC_INLINE jl_binding_partition_t * jl_get_binding_partition_ (jl_binding_t * b JL_PROPAGATES_ROOT , jl_value_t * parent , _Atomic (jl_binding_partition_t * )* insert , size_t world , size_t max_world , modstack_t * st ) JL_GLOBALLY_ROOTED
374377{
375378 assert (jl_is_binding (b ));
376379 struct implicit_search_gap gap ;
377380 gap .parent = parent ;
378381 gap .insert = insert ;
379382 gap .inherited_flags = 0 ;
380383 gap .min_world = 0 ;
381- gap .max_world = ~( size_t ) 0 ;
384+ gap .max_world = max_world ;
382385 while (1 ) {
383386 gap .replace = jl_atomic_load_relaxed (gap .insert );
384387 jl_binding_partition_t * bpart = jl_get_binding_partition__ (b , world , & gap );
@@ -395,15 +398,14 @@ jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b, size_t world)
395398 if (!b )
396399 return NULL ;
397400 // Duplicate the code for the entry frame for branch prediction
398- return jl_get_binding_partition_ (b , (jl_value_t * )b , & b -> partitions , world , NULL );
401+ return jl_get_binding_partition_ (b , (jl_value_t * )b , & b -> partitions , world , ~( size_t ) 0 , NULL );
399402}
400403
401404jl_binding_partition_t * jl_get_binding_partition_with_hint (jl_binding_t * b , jl_binding_partition_t * prev , size_t world ) JL_GLOBALLY_ROOTED {
402405 // Helper for getting a binding partition for an older world after we've already looked up the partition for a newer world
403406 assert (b );
404- // TODO: Is it possible for a concurrent lookup to have expanded this bpart, making this false?
405- assert (jl_atomic_load_relaxed (& prev -> min_world ) > world );
406- return jl_get_binding_partition_ (b , (jl_value_t * )prev , & prev -> next , world , NULL );
407+ size_t prev_min_world = jl_atomic_load_relaxed (& prev -> min_world );
408+ return jl_get_binding_partition_ (b , (jl_value_t * )prev , & prev -> next , world , prev_min_world - 1 , NULL );
407409}
408410
409411jl_binding_partition_t * jl_get_binding_partition_all (jl_binding_t * b , size_t min_world , size_t max_world ) {
0 commit comments