@@ -136,15 +136,18 @@ static jl_binding_partition_t *jl_implicit_import_resolved(jl_binding_t *b, stru
136
136
if (jl_is_binding_partition (gap .parent )) {
137
137
// Check if we can merge this into the previous binding partition
138
138
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
139
140
size_t expected_prev_min_world = new_max_world + 1 ;
140
141
if (prev -> restriction == resolution .binding_or_const && prev -> kind == new_kind ) {
142
+ retry :
141
143
if (!jl_atomic_cmpswap (& prev -> min_world , & expected_prev_min_world , new_min_world )) {
142
144
if (expected_prev_min_world <= new_min_world ) {
143
145
return prev ;
144
146
}
145
147
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 ;
148
151
}
149
152
// There remains a gap - proceed
150
153
} else {
@@ -154,7 +157,7 @@ static jl_binding_partition_t *jl_implicit_import_resolved(jl_binding_t *b, stru
154
157
for (;;) {
155
158
// We've updated the previous partition - check if we've closed a gap
156
159
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 ) {
158
161
if (jl_atomic_cmpswap (& prev -> min_world , & expected_prev_min_world , next_min_world )) {
159
162
jl_binding_partition_t * nextnext = jl_atomic_load_relaxed (& next -> next );
160
163
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
370
373
bpart -> kind = resolution .ultimate_kind ;
371
374
}
372
375
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
374
377
{
375
378
assert (jl_is_binding (b ));
376
379
struct implicit_search_gap gap ;
377
380
gap .parent = parent ;
378
381
gap .insert = insert ;
379
382
gap .inherited_flags = 0 ;
380
383
gap .min_world = 0 ;
381
- gap .max_world = ~( size_t ) 0 ;
384
+ gap .max_world = max_world ;
382
385
while (1 ) {
383
386
gap .replace = jl_atomic_load_relaxed (gap .insert );
384
387
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)
395
398
if (!b )
396
399
return NULL ;
397
400
// 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 );
399
402
}
400
403
401
404
jl_binding_partition_t * jl_get_binding_partition_with_hint (jl_binding_t * b , jl_binding_partition_t * prev , size_t world ) JL_GLOBALLY_ROOTED {
402
405
// Helper for getting a binding partition for an older world after we've already looked up the partition for a newer world
403
406
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 );
407
409
}
408
410
409
411
jl_binding_partition_t * jl_get_binding_partition_all (jl_binding_t * b , size_t min_world , size_t max_world ) {
0 commit comments