Skip to content

Commit 946fcf1

Browse files
committed
C#: Speedup DispatchMethodOrAccessorCall::getAViableOverrider()
In addition to improved performance, the analysis no longer applies a closed-world assumption to type parameters. That is, if the type of a receiver is a type parameter, then the call may target any method of a compatible receiver type, not just the types that actually instantiate the type parameter.
1 parent 972cc47 commit 946fcf1

File tree

1 file changed

+110
-75
lines changed

1 file changed

+110
-75
lines changed

csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll

Lines changed: 110 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -233,71 +233,61 @@ private module Internal {
233233
}
234234

235235
pragma[noinline]
236-
private predicate hasOverrider(OverridableCallable oc, ValueOrRefType t) {
237-
exists(oc.getAnOverrider(t))
236+
private predicate hasOverrider(OverridableCallable oc, Gvn::GvnType t) {
237+
exists(oc.getAnOverrider(any(ValueOrRefType t0 | Gvn::getGlobalValueNumber(t0) = t)))
238238
}
239239

240240
pragma[noinline]
241-
private predicate hasCallable(OverridableCallable source, ValueOrRefType t, OverridableCallable c) {
241+
private predicate hasCallable(OverridableCallable source, Gvn::GvnType t, OverridableCallable c) {
242242
c.getUnboundDeclaration() = source and
243-
t.hasCallable(c) and
243+
any(ValueOrRefType t0 | Gvn::getGlobalValueNumber(t0) = t).hasCallable(c) and
244244
hasOverrider(c, t) and
245-
hasQualifierTypeOverridden0(t, _) and
246-
hasQualifierTypeOverridden1(source, _)
245+
source = any(DispatchMethodOrAccessorCall call).getAStaticTargetExt()
247246
}
248247

249-
pragma[noinline]
250-
private Unification::ConstrainedTypeParameter getAConstrainedTypeParameterQualifierType(
251-
DispatchMethodOrAccessorCall call
252-
) {
253-
result = getAPossibleType(call.getQualifier(), false)
254-
}
248+
abstract private class DispatchMethodOrAccessorCall extends DispatchCallImpl {
249+
pragma[noinline]
250+
OverridableCallable getAStaticTargetExt() {
251+
exists(OverridableCallable target | this.getAStaticTarget() = target |
252+
result = target.getUnboundDeclaration()
253+
or
254+
result = target.getAnUltimateImplementor().getUnboundDeclaration()
255+
)
256+
}
255257

256-
pragma[noinline]
257-
private predicate constrainedTypeParameterQualifierTypeSubsumes(
258-
ValueOrRefType t, Unification::ConstrainedTypeParameter tp
259-
) {
260-
tp = getAConstrainedTypeParameterQualifierType(_) and
261-
tp.subsumes(t)
262-
}
258+
pragma[nomagic]
259+
predicate hasQualifierTypeInherited(Type t) { t = getAPossibleType(this.getQualifier(), _) }
263260

264-
pragma[noinline]
265-
private predicate hasQualifierTypeOverridden0(ValueOrRefType t, DispatchMethodOrAccessorCall call) {
266-
hasOverrider(_, t) and
267-
(
268-
exists(Type t0, Type t1 |
269-
t0 = getAPossibleType(call.getQualifier(), false) and
270-
t1 = [t0, t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()]
261+
pragma[noinline]
262+
private predicate hasSubsumedQualifierType(Gvn::GvnType t) {
263+
hasOverrider(_, t) and
264+
exists(Type t0 |
265+
t0 = getAPossibleType(this.getQualifier(), false) and
266+
not t0 instanceof TypeParameter
271267
|
272-
t = t1
268+
t = Gvn::getGlobalValueNumber(t0)
273269
or
274-
Unification::subsumes(t1, t)
270+
Gvn::subsumes(Gvn::getGlobalValueNumber(t0), t)
275271
)
276-
or
277-
constrainedTypeParameterQualifierTypeSubsumes(t,
278-
getAConstrainedTypeParameterQualifierType(call))
279-
)
280-
}
272+
}
281273

282-
pragma[noinline]
283-
private predicate hasQualifierTypeOverridden1(
284-
OverridableCallable c, DispatchMethodOrAccessorCall call
285-
) {
286-
exists(OverridableCallable target | call.getAStaticTarget() = target |
287-
c = target.getUnboundDeclaration()
288-
or
289-
c = target.getAnUltimateImplementor().getUnboundDeclaration()
290-
)
291-
}
274+
pragma[noinline]
275+
private predicate hasConstrainedTypeParameterQualifierType(
276+
Unification::ConstrainedTypeParameter tp
277+
) {
278+
tp = getAPossibleType(this.getQualifier(), false)
279+
}
292280

293-
abstract private class DispatchMethodOrAccessorCall extends DispatchCallImpl {
294-
pragma[nomagic]
295-
predicate hasQualifierTypeInherited(Type t) { t = getAPossibleType(this.getQualifier(), _) }
281+
pragma[noinline]
282+
private predicate hasUnconstrainedTypeParameterQualifierType() {
283+
getAPossibleType(this.getQualifier(), false) instanceof
284+
Unification::UnconstrainedTypeParameter
285+
}
296286

297287
pragma[nomagic]
298-
predicate hasQualifierTypeOverridden(ValueOrRefType t, OverridableCallable c) {
299-
hasQualifierTypeOverridden0(t, this) and
300-
hasCallable(any(OverridableCallable oc | hasQualifierTypeOverridden1(oc, this)), t, c)
288+
predicate hasSubsumedQualifierTypeOverridden(Gvn::GvnType t, OverridableCallable c) {
289+
this.hasSubsumedQualifierType(t) and
290+
hasCallable(any(OverridableCallable oc | oc = this.getAStaticTargetExt()), t, c)
301291
}
302292

303293
/**
@@ -357,12 +347,33 @@ private module Internal {
357347
}
358348

359349
pragma[nomagic]
360-
private Callable getASubsumedStaticTarget0(Type t) {
350+
private predicate contextArgHasConstrainedTypeParameterType(
351+
DispatchCall ctx, Unification::ConstrainedTypeParameter tp
352+
) {
353+
this.contextArgHasType(ctx, tp, false)
354+
}
355+
356+
pragma[nomagic]
357+
private predicate contextArgHasUnconstrainedTypeParameterType(DispatchCall ctx) {
358+
this.contextArgHasType(ctx, any(Unification::UnconstrainedTypeParameter t), false)
359+
}
360+
361+
pragma[nomagic]
362+
private predicate contextArgHasNonTypeParameterType(DispatchCall ctx, Gvn::GvnType t) {
363+
exists(Type t0 |
364+
this.contextArgHasType(ctx, t0, false) and
365+
not t0 instanceof TypeParameter and
366+
t = Gvn::getGlobalValueNumber(t0)
367+
)
368+
}
369+
370+
pragma[nomagic]
371+
private Callable getASubsumedStaticTarget0(Gvn::GvnType t) {
361372
exists(Callable staticTarget, Type declType |
362373
staticTarget = this.getAStaticTarget() and
363374
declType = staticTarget.getDeclaringType() and
364375
result = staticTarget.getUnboundDeclaration() and
365-
Unification::subsumes(declType, t)
376+
Gvn::subsumes(Gvn::getGlobalValueNumber(declType), t)
366377
)
367378
}
368379

@@ -375,7 +386,8 @@ private module Internal {
375386
private Callable getASubsumedStaticTarget() {
376387
result = this.getAStaticTarget()
377388
or
378-
result.getUnboundDeclaration() = this.getASubsumedStaticTarget0(result.getDeclaringType())
389+
result.getUnboundDeclaration() =
390+
this.getASubsumedStaticTarget0(Gvn::getGlobalValueNumber(result.getDeclaringType()))
379391
}
380392

381393
/**
@@ -426,6 +438,12 @@ private module Internal {
426438
)
427439
}
428440

441+
pragma[noinline]
442+
NonConstructedOverridableCallable getAViableOverrider0() {
443+
getAPossibleType(this.getQualifier(), false) instanceof TypeParameter and
444+
result.getAConstructingCallableOrSelf() = this.getAStaticTargetExt()
445+
}
446+
429447
/**
430448
* Gets a callable that is defined in a subtype of the qualifier type of this
431449
* call, and which overrides a static target of this call.
@@ -468,9 +486,22 @@ private module Internal {
468486
*/
469487
private RuntimeCallable getAViableOverrider() {
470488
exists(ValueOrRefType t, NonConstructedOverridableCallable c |
471-
this.hasQualifierTypeOverridden(t, c.getAConstructingCallableOrSelf()) and
489+
this.hasSubsumedQualifierTypeOverridden(Gvn::getGlobalValueNumber(t),
490+
c.getAConstructingCallableOrSelf()) and
472491
result = c.getAnOverrider(t)
473492
)
493+
or
494+
exists(NonConstructedOverridableCallable c |
495+
c = this.getAViableOverrider0() and
496+
result = c.getAnOverrider(_)
497+
|
498+
this.hasUnconstrainedTypeParameterQualifierType()
499+
or
500+
exists(Unification::ConstrainedTypeParameter tp |
501+
this.hasConstrainedTypeParameterQualifierType(tp) and
502+
tp.subsumes(result.getDeclaringType())
503+
)
504+
)
474505
}
475506

476507
override RuntimeCallable getADynamicTarget() {
@@ -510,36 +541,40 @@ private module Internal {
510541
}
511542

512543
pragma[nomagic]
513-
private RuntimeCallable getAViableOverriderInCallContext0(
514-
NonConstructedOverridableCallable c, ValueOrRefType t
515-
) {
516-
result = this.getAViableOverrider() and
517-
this.contextArgHasType(_, _, false) and
518-
result = c.getAnOverrider(t)
544+
private RuntimeCallable getAViableOverriderInCallContext0(Gvn::GvnType t) {
545+
exists(NonConstructedOverridableCallable c |
546+
result = this.getAViableOverrider() and
547+
this.contextArgHasType(_, _, false) and
548+
result = c.getAnOverrider(any(Type t0 | t = Gvn::getGlobalValueNumber(t0))) and
549+
this.getAStaticTarget() = c.getAConstructingCallableOrSelf()
550+
)
519551
}
520552

521553
pragma[nomagic]
522-
private RuntimeCallable getAViableOverriderInCallContext1(
523-
NonConstructedOverridableCallable c, DispatchCall ctx
524-
) {
525-
exists(ValueOrRefType t |
526-
result = this.getAViableOverriderInCallContext0(c, t) and
527-
exists(Type t0, Type t1 |
528-
this.contextArgHasType(ctx, t0, false) and
529-
t1 = [t0, t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()]
530-
|
531-
t = t1
532-
or
533-
Unification::subsumes(t1, t)
534-
)
554+
private predicate contextArgHasSubsumedType(DispatchCall ctx, Gvn::GvnType t) {
555+
hasOverrider(_, t) and
556+
exists(Gvn::GvnType t0 | this.contextArgHasNonTypeParameterType(ctx, t0) |
557+
t = t0
558+
or
559+
Gvn::subsumes(t0, t)
535560
)
536561
}
537562

538563
pragma[nomagic]
539564
private RuntimeCallable getAViableOverriderInCallContext(DispatchCall ctx) {
540-
exists(NonConstructedOverridableCallable c |
541-
result = this.getAViableOverriderInCallContext1(c, ctx) and
542-
this.getAStaticTarget() = c.getAConstructingCallableOrSelf()
565+
exists(Gvn::GvnType t |
566+
result = this.getAViableOverriderInCallContext0(t) and
567+
this.contextArgHasSubsumedType(ctx, t)
568+
)
569+
or
570+
result = this.getAViableOverrider() and
571+
(
572+
this.contextArgHasUnconstrainedTypeParameterType(ctx)
573+
or
574+
exists(Unification::ConstrainedTypeParameter tp |
575+
this.contextArgHasConstrainedTypeParameterType(ctx, tp) and
576+
tp.subsumes(result.getDeclaringType())
577+
)
543578
)
544579
}
545580

0 commit comments

Comments
 (0)