C#: Dispatch library performance tweaks

- Restrict `OverridableCallable::getAnOverrider(ValueOrRefType t)` to types `t`
  that are sub types of the callable's declaring type.
- Use explicit recursion in `OverridableCallable::getInherited()`.
This commit is contained in:
Tom Hvitved
2019-03-13 12:16:14 +01:00
parent e83dd6708d
commit 638af39aa0
2 changed files with 73 additions and 52 deletions

View File

@@ -202,7 +202,7 @@ private module Internal {
* Gets a non-exact (see `hasQualifierType()`) qualifier type of this call
* that does not contain type parameters.
*/
TypeWithoutTypeParameters getANonExactQualifierTypeWithoutTypeParameters() {
private TypeWithoutTypeParameters getANonExactQualifierTypeWithoutTypeParameters() {
exists(Type qualifierType | hasQualifierType(qualifierType, false) |
// Qualifier type contains no type parameters: use it
result = qualifierType
@@ -220,6 +220,20 @@ private module Internal {
result = qualifierType.(QualifierTypeWithTypeParameters).getAPotentialInstance()
)
}
/**
* Gets a non-exact (see `hasQualifierType()`) qualifier type of this call.
*/
ValueOrRefType getANonExactQualifierType() {
exists(TypeWithoutTypeParameters t |
t = this.getANonExactQualifierTypeWithoutTypeParameters()
|
result.(ConstructedType).getUnboundGeneric() = t
or
not t instanceof UnboundGenericType and
result = t
)
}
}
private class DynamicFieldOrProperty extends Assignable {
@@ -480,9 +494,9 @@ private module Internal {
* qualifier types are `B.M` and `C.M`, `C.M`, and none, respectively.
*/
private RuntimeInstanceMethod getAViableOverrider() {
exists(TypeWithoutTypeParameters t, NonConstructedOverridableMethod m |
t = getANonExactQualifierTypeWithoutTypeParameters() and
getAStaticTarget() = m.getAConstructingMethodOrSelf() and
exists(ValueOrRefType t, NonConstructedOverridableMethod m |
t = this.getANonExactQualifierType() and
this.getAStaticTarget() = m.getAConstructingMethodOrSelf() and
result = m.getAnOverrider(t)
)
}
@@ -620,9 +634,9 @@ private module Internal {
* respectively.
*/
private RuntimeAccessor getAViableOverrider() {
exists(TypeWithoutTypeParameters t |
t = getANonExactQualifierTypeWithoutTypeParameters() and
result = getAStaticTarget().(OverridableAccessor).getAnOverrider(t)
exists(ValueOrRefType t |
t = this.getANonExactQualifierType() |
result = this.getAStaticTarget().(OverridableAccessor).getAnOverrider(t)
)
}
}

View File

@@ -135,27 +135,33 @@ class OverridableCallable extends Callable {
* - `C2.M = C2.M.getInherited(C3)`.
*/
Callable getInherited(SourceDeclarationType t) {
exists(Callable sourceDecl | result = getInherited1(t, sourceDecl) |
exists(Callable sourceDecl | result = this.getInherited2(t, sourceDecl) |
hasSourceDeclarationCallable(t, sourceDecl)
)
}
private Callable getInherited0(SourceDeclarationType t) {
private Callable getInherited0(ValueOrRefType t) {
// A (transitive, reflexive) overrider
t = this.hasOverrider(result).getASubType*().getSourceDeclaration()
t = this.hasOverrider(result)
or
// A (transitive) overrider of an interface implementation
t = this.hasOverridingImplementor(result)
or
exists(ValueOrRefType mid | result = this.getInherited0(mid) | t = mid.getASubType())
}
private Callable getInherited1(SourceDeclarationType t) {
exists(ValueOrRefType t0 | result = getInherited0(t0) | t = t0.getSourceDeclaration())
or
// An interface implementation
exists(ValueOrRefType s |
result = getAnImplementorSubType(s) and
t = s.getSourceDeclaration()
)
or
// A (transitive) overrider of an interface implementation
t = this.hasOverridingImplementor(result).getASubType*().getSourceDeclaration()
}
private Callable getInherited1(SourceDeclarationType t, Callable sourceDecl) {
result = this.getInherited0(t) and
private Callable getInherited2(SourceDeclarationType t, Callable sourceDecl) {
result = this.getInherited1(t) and
sourceDecl = result.getSourceDeclaration()
}
@@ -171,9 +177,42 @@ class OverridableCallable extends Callable {
result = c.getDeclaringType()
}
private predicate isDeclaringSubType(ValueOrRefType t) {
t = this.getDeclaringType()
or
exists(ValueOrRefType mid | isDeclaringSubType(mid) | t = mid.getASubType())
}
pragma[noinline]
private Callable getAnOverrider0(ValueOrRefType t) {
not this.declaredInTypeWithTypeParameters() and
(
// A (transitive) overrider
result = this.getAnOverrider+() and
t = result.getDeclaringType()
or
// An interface implementation
result = this.getAnImplementorSubType(t)
or
// A (transitive) overrider of an interface implementation
result = this.getAnOverridingImplementor() and
t = result.getDeclaringType()
)
}
private Callable getAnOverrider1(ValueOrRefType t) {
result = this.getAnOverrider0(t)
or
exists(ValueOrRefType mid | result = this.getAnOverrider1(mid) |
t = mid.getABaseType() and
this.isDeclaringSubType(t)
)
}
/**
* Gets a callable defined in a sub type of `t` that overrides/implements
* this callable, if any.
* Gets a callable defined in a sub type of `t` (which is itself a sub type
* of this callable's declaring type) that overrides/implements this callable,
* if any.
*
* The type `t` may be a constructed type: For example, if `t = C<int>`,
* then only callables defined in sub types of `C<int>` (and e.g. not
@@ -181,39 +220,7 @@ class OverridableCallable extends Callable {
* contains a callable that overrides this callable, then only if `C2<int>`
* is ever constructed will the callable in `C2` be considered valid.
*/
Callable getAnOverrider(TypeWithoutTypeParameters t) {
exists(OverridableCallable oc, ValueOrRefType sub |
result = oc.getAnOverriderAux(sub) and
t = oc.getAnOverriderBaseType(sub) and
oc = getABoundInstance()
)
}
// predicate folding to get proper join order
private Callable getAnOverriderAux(ValueOrRefType t) {
not declaredInTypeWithTypeParameters() and
(
// A (transitive) overrider
result = getAnOverrider+() and
t = result.getDeclaringType()
or
// An interface implementation
result = getAnImplementorSubType(t)
or
// A (transitive) overrider of an interface implementation
result = getAnOverridingImplementor() and
t = result.getDeclaringType()
)
}
private TypeWithoutTypeParameters getAnOverriderBaseType(ValueOrRefType t) {
exists(getAnOverriderAux(t)) and
exists(Type t0 | t0 = t.getABaseType*() |
result = t0
or
result = t0.(ConstructedType).getUnboundGeneric()
)
}
Callable getAnOverrider(ValueOrRefType t) { result = this.getABoundInstance().getAnOverrider1(t) }
/**
* Gets a bound instance of this callable.
@@ -264,7 +271,7 @@ class OverridableMethod extends Method, OverridableCallable {
result = OverridableCallable.super.getInherited(t)
}
override Method getAnOverrider(TypeWithoutTypeParameters t) {
override Method getAnOverrider(ValueOrRefType t) {
result = OverridableCallable.super.getAnOverrider(t)
}
}
@@ -311,7 +318,7 @@ class OverridableAccessor extends Accessor, OverridableCallable {
result = OverridableCallable.super.getInherited(t)
}
override Accessor getAnOverrider(TypeWithoutTypeParameters t) {
override Accessor getAnOverrider(ValueOrRefType t) {
result = OverridableCallable.super.getAnOverrider(t)
}
}