1
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2
2
3
- module StaticData
4
-
5
3
using . Core: CodeInstance, MethodInstance
6
- using . Base: JLOptions, Compiler, get_world_counter, _methods_by_ftype, get_methodtable, get_ci_mi
4
+ using . Base: JLOptions, Compiler, get_world_counter, _methods_by_ftype, get_methodtable, get_ci_mi, morespecific
7
5
8
6
const WORLD_AGE_REVALIDATION_SENTINEL:: UInt = 1
9
7
const _jl_debug_method_invalidation = Ref {Union{Nothing,Vector{Any}}} (nothing )
@@ -282,22 +280,47 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi
282
280
return 0 , minworld, maxworld
283
281
end
284
282
283
+ function get_method_from_edge (@nospecialize t)
284
+ if t isa Method
285
+ return t
286
+ else
287
+ if t isa CodeInstance
288
+ t = get_ci_mi (t):: MethodInstance
289
+ else
290
+ t = t:: MethodInstance
291
+ end
292
+ return t. def:: Method
293
+ end
294
+ end
295
+
285
296
function verify_call (@nospecialize (sig), expecteds:: Core.SimpleVector , i:: Int , n:: Int , world:: UInt , fully_covers:: Bool )
286
297
# verify that these edges intersect with the same methods as before
287
298
mi = nothing
288
- if n == 1
299
+ expected_deleted = false
300
+ for j = 1 : n
301
+ t = expecteds[i+ j- 1 ]
302
+ meth = get_method_from_edge (t)
303
+ if iszero (meth. dispatch_status & METHOD_SIG_LATEST_WHICH)
304
+ expected_deleted = true
305
+ break
306
+ end
307
+ end
308
+ if expected_deleted
309
+ if _jl_debug_method_invalidation[] === nothing && world == get_world_counter ()
310
+ result = Any[] # result is unused
311
+ return UInt (1 ), UInt (0 ), result
312
+ end
313
+ elseif n == 1
289
314
# first, fast-path a check if the expected method simply dominates its sig anyways
290
315
# so the result of ml_matches is already simply known
291
316
let t = expecteds[i], meth, minworld, maxworld, result
292
- if t isa Method
293
- meth = t
294
- else
317
+ meth = get_method_from_edge (t)
318
+ if ! (t isa Method)
295
319
if t isa CodeInstance
296
320
mi = get_ci_mi (t):: MethodInstance
297
321
else
298
322
mi = t:: MethodInstance
299
323
end
300
- meth = mi. def:: Method
301
324
# Fast path is legal when fully_covers=true OR when METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC is unset
302
325
if (fully_covers || iszero (meth. dispatch_status & METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC)) &&
303
326
! iszero (mi. dispatch_status & METHOD_SIG_LATEST_ONLY)
@@ -319,7 +342,83 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n
319
342
end
320
343
end
321
344
end
322
- end
345
+ elseif n > 1
346
+ # Try the interference set fast path: check if all interference sets are covered by expecteds
347
+ interference_fast_path_success = true
348
+ if ! fully_covers
349
+ # If expected doesn't fully cover, then need to make sure that no new methods are possibly present
350
+ for j = 1 : n
351
+ meth = get_method_from_edge (expecteds[i+ j- 1 ])
352
+ if ! iszero (meth. dispatch_status & METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC)
353
+ interference_fast_path_success = false
354
+ for j = reverse (1 : n)
355
+ meth2 = get_method_from_edge (expecteds[i+ j- 1 ])
356
+ if meth != = meth2 && typeintersect (sig, meth. sig) <: meth2.sig && ! (meth2. sig <: meth.sig )
357
+ interference_fast_path_success = true
358
+ end
359
+ end
360
+ if ! interference_fast_path_success
361
+ break
362
+ end
363
+ end
364
+ end
365
+ end
366
+ if interference_fast_path_success
367
+ local interference_minworld:: UInt = 1
368
+ for j = 1 : n
369
+ meth = get_method_from_edge (expecteds[i+ j- 1 ])
370
+ if interference_minworld < meth. primary_world
371
+ interference_minworld = meth. primary_world
372
+ end
373
+ interferences = meth. interferences
374
+ for k = 1 : length (interferences)
375
+ isassigned (interferences, k) || break # no more entries
376
+ interference_method = interferences[k]:: Method
377
+ if iszero (interference_method. dispatch_status & METHOD_SIG_LATEST_WHICH)
378
+ # detected a deleted interference_method, so need the full lookup to compute minworld
379
+ interference_fast_path_success = false
380
+ break
381
+ end
382
+ world < interference_method. primary_world && break # this and later entries are for a future world
383
+ local found_in_expecteds = false
384
+ for j = 1 : n
385
+ if interference_method === get_method_from_edge (expecteds[i+ j- 1 ])
386
+ found_in_expecteds = true
387
+ break
388
+ end
389
+ end
390
+ if ! found_in_expecteds
391
+ ti = typeintersect (sig, interference_method. sig)
392
+ if ! (ti === Union{})
393
+ # try looking for a different expected method that fully hides the interference_method anyways
394
+ for j = 1 : n
395
+ meth2 = get_method_from_edge (expecteds[i+ j- 1 ])
396
+ if meth2 != = interference_method && ti <: meth2.sig && morespecific (meth2, interference_method)
397
+ found_in_expecteds = true
398
+ break
399
+ end
400
+ end
401
+ if ! found_in_expecteds
402
+ meth2 = get_method_from_edge (expecteds[i])
403
+ interference_fast_path_success = false
404
+ break
405
+ end
406
+ end
407
+ end
408
+ end
409
+ if ! interference_fast_path_success
410
+ break
411
+ end
412
+ end
413
+ if interference_fast_path_success
414
+ # All interference sets are covered by expecteds, can return success
415
+ @assert interference_minworld ≤ world
416
+ maxworld = typemax (UInt)
417
+ result = Any[] # result is unused
418
+ return interference_minworld, maxworld, result
419
+ end
420
+ end
421
+ end
323
422
# next, compare the current result of ml_matches to the old result
324
423
lim = _jl_debug_method_invalidation[] != = nothing ? Int (typemax (Int32)) : n
325
424
minworld = Ref {UInt} (1 )
@@ -339,17 +438,7 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n
339
438
local found = false
340
439
for j = 1 : n
341
440
t = expecteds[i+ j- 1 ]
342
- if t isa Method
343
- meth = t
344
- else
345
- if t isa CodeInstance
346
- t = get_ci_mi (t):: MethodInstance
347
- else
348
- t = t:: MethodInstance
349
- end
350
- meth = t. def:: Method
351
- end
352
- if match. method == meth
441
+ if match. method == get_method_from_edge (t)
353
442
found = true
354
443
break
355
444
end
@@ -412,6 +501,4 @@ function verify_invokesig(@nospecialize(invokesig), expected::Method, world::UIn
412
501
end
413
502
end
414
503
return minworld, maxworld, matched
415
- end
416
-
417
- end # module StaticData
504
+ end
0 commit comments