Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 638af39

Browse files
committed
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()`.
1 parent e83dd67 commit 638af39

2 files changed

Lines changed: 66 additions & 45 deletions

File tree

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

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ private module Internal {
202202
* Gets a non-exact (see `hasQualifierType()`) qualifier type of this call
203203
* that does not contain type parameters.
204204
*/
205-
TypeWithoutTypeParameters getANonExactQualifierTypeWithoutTypeParameters() {
205+
private TypeWithoutTypeParameters getANonExactQualifierTypeWithoutTypeParameters() {
206206
exists(Type qualifierType | hasQualifierType(qualifierType, false) |
207207
// Qualifier type contains no type parameters: use it
208208
result = qualifierType
@@ -220,6 +220,20 @@ private module Internal {
220220
result = qualifierType.(QualifierTypeWithTypeParameters).getAPotentialInstance()
221221
)
222222
}
223+
224+
/**
225+
* Gets a non-exact (see `hasQualifierType()`) qualifier type of this call.
226+
*/
227+
ValueOrRefType getANonExactQualifierType() {
228+
exists(TypeWithoutTypeParameters t |
229+
t = this.getANonExactQualifierTypeWithoutTypeParameters()
230+
|
231+
result.(ConstructedType).getUnboundGeneric() = t
232+
or
233+
not t instanceof UnboundGenericType and
234+
result = t
235+
)
236+
}
223237
}
224238

225239
private class DynamicFieldOrProperty extends Assignable {
@@ -480,9 +494,9 @@ private module Internal {
480494
* qualifier types are `B.M` and `C.M`, `C.M`, and none, respectively.
481495
*/
482496
private RuntimeInstanceMethod getAViableOverrider() {
483-
exists(TypeWithoutTypeParameters t, NonConstructedOverridableMethod m |
484-
t = getANonExactQualifierTypeWithoutTypeParameters() and
485-
getAStaticTarget() = m.getAConstructingMethodOrSelf() and
497+
exists(ValueOrRefType t, NonConstructedOverridableMethod m |
498+
t = this.getANonExactQualifierType() and
499+
this.getAStaticTarget() = m.getAConstructingMethodOrSelf() and
486500
result = m.getAnOverrider(t)
487501
)
488502
}
@@ -620,9 +634,9 @@ private module Internal {
620634
* respectively.
621635
*/
622636
private RuntimeAccessor getAViableOverrider() {
623-
exists(TypeWithoutTypeParameters t |
624-
t = getANonExactQualifierTypeWithoutTypeParameters() and
625-
result = getAStaticTarget().(OverridableAccessor).getAnOverrider(t)
637+
exists(ValueOrRefType t |
638+
t = this.getANonExactQualifierType() |
639+
result = this.getAStaticTarget().(OverridableAccessor).getAnOverrider(t)
626640
)
627641
}
628642
}

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

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -135,27 +135,33 @@ class OverridableCallable extends Callable {
135135
* - `C2.M = C2.M.getInherited(C3)`.
136136
*/
137137
Callable getInherited(SourceDeclarationType t) {
138-
exists(Callable sourceDecl | result = getInherited1(t, sourceDecl) |
138+
exists(Callable sourceDecl | result = this.getInherited2(t, sourceDecl) |
139139
hasSourceDeclarationCallable(t, sourceDecl)
140140
)
141141
}
142142

143-
private Callable getInherited0(SourceDeclarationType t) {
143+
private Callable getInherited0(ValueOrRefType t) {
144144
// A (transitive, reflexive) overrider
145-
t = this.hasOverrider(result).getASubType*().getSourceDeclaration()
145+
t = this.hasOverrider(result)
146+
or
147+
// A (transitive) overrider of an interface implementation
148+
t = this.hasOverridingImplementor(result)
149+
or
150+
exists(ValueOrRefType mid | result = this.getInherited0(mid) | t = mid.getASubType())
151+
}
152+
153+
private Callable getInherited1(SourceDeclarationType t) {
154+
exists(ValueOrRefType t0 | result = getInherited0(t0) | t = t0.getSourceDeclaration())
146155
or
147156
// An interface implementation
148157
exists(ValueOrRefType s |
149158
result = getAnImplementorSubType(s) and
150159
t = s.getSourceDeclaration()
151160
)
152-
or
153-
// A (transitive) overrider of an interface implementation
154-
t = this.hasOverridingImplementor(result).getASubType*().getSourceDeclaration()
155161
}
156162

157-
private Callable getInherited1(SourceDeclarationType t, Callable sourceDecl) {
158-
result = this.getInherited0(t) and
163+
private Callable getInherited2(SourceDeclarationType t, Callable sourceDecl) {
164+
result = this.getInherited1(t) and
159165
sourceDecl = result.getSourceDeclaration()
160166
}
161167

@@ -171,50 +177,51 @@ class OverridableCallable extends Callable {
171177
result = c.getDeclaringType()
172178
}
173179

174-
/**
175-
* Gets a callable defined in a sub type of `t` that overrides/implements
176-
* this callable, if any.
177-
*
178-
* The type `t` may be a constructed type: For example, if `t = C<int>`,
179-
* then only callables defined in sub types of `C<int>` (and e.g. not
180-
* `C<string>`) are valid. In particular, if `C2<T> : C<T>` and `C2`
181-
* contains a callable that overrides this callable, then only if `C2<int>`
182-
* is ever constructed will the callable in `C2` be considered valid.
183-
*/
184-
Callable getAnOverrider(TypeWithoutTypeParameters t) {
185-
exists(OverridableCallable oc, ValueOrRefType sub |
186-
result = oc.getAnOverriderAux(sub) and
187-
t = oc.getAnOverriderBaseType(sub) and
188-
oc = getABoundInstance()
189-
)
180+
private predicate isDeclaringSubType(ValueOrRefType t) {
181+
t = this.getDeclaringType()
182+
or
183+
exists(ValueOrRefType mid | isDeclaringSubType(mid) | t = mid.getASubType())
190184
}
191185

192-
// predicate folding to get proper join order
193-
private Callable getAnOverriderAux(ValueOrRefType t) {
194-
not declaredInTypeWithTypeParameters() and
186+
pragma[noinline]
187+
private Callable getAnOverrider0(ValueOrRefType t) {
188+
not this.declaredInTypeWithTypeParameters() and
195189
(
196190
// A (transitive) overrider
197-
result = getAnOverrider+() and
191+
result = this.getAnOverrider+() and
198192
t = result.getDeclaringType()
199193
or
200194
// An interface implementation
201-
result = getAnImplementorSubType(t)
195+
result = this.getAnImplementorSubType(t)
202196
or
203197
// A (transitive) overrider of an interface implementation
204-
result = getAnOverridingImplementor() and
198+
result = this.getAnOverridingImplementor() and
205199
t = result.getDeclaringType()
206200
)
207201
}
208202

209-
private TypeWithoutTypeParameters getAnOverriderBaseType(ValueOrRefType t) {
210-
exists(getAnOverriderAux(t)) and
211-
exists(Type t0 | t0 = t.getABaseType*() |
212-
result = t0
213-
or
214-
result = t0.(ConstructedType).getUnboundGeneric()
203+
private Callable getAnOverrider1(ValueOrRefType t) {
204+
result = this.getAnOverrider0(t)
205+
or
206+
exists(ValueOrRefType mid | result = this.getAnOverrider1(mid) |
207+
t = mid.getABaseType() and
208+
this.isDeclaringSubType(t)
215209
)
216210
}
217211

212+
/**
213+
* Gets a callable defined in a sub type of `t` (which is itself a sub type
214+
* of this callable's declaring type) that overrides/implements this callable,
215+
* if any.
216+
*
217+
* The type `t` may be a constructed type: For example, if `t = C<int>`,
218+
* then only callables defined in sub types of `C<int>` (and e.g. not
219+
* `C<string>`) are valid. In particular, if `C2<T> : C<T>` and `C2`
220+
* contains a callable that overrides this callable, then only if `C2<int>`
221+
* is ever constructed will the callable in `C2` be considered valid.
222+
*/
223+
Callable getAnOverrider(ValueOrRefType t) { result = this.getABoundInstance().getAnOverrider1(t) }
224+
218225
/**
219226
* Gets a bound instance of this callable.
220227
*
@@ -264,7 +271,7 @@ class OverridableMethod extends Method, OverridableCallable {
264271
result = OverridableCallable.super.getInherited(t)
265272
}
266273

267-
override Method getAnOverrider(TypeWithoutTypeParameters t) {
274+
override Method getAnOverrider(ValueOrRefType t) {
268275
result = OverridableCallable.super.getAnOverrider(t)
269276
}
270277
}
@@ -311,7 +318,7 @@ class OverridableAccessor extends Accessor, OverridableCallable {
311318
result = OverridableCallable.super.getInherited(t)
312319
}
313320

314-
override Accessor getAnOverrider(TypeWithoutTypeParameters t) {
321+
override Accessor getAnOverrider(ValueOrRefType t) {
315322
result = OverridableCallable.super.getAnOverrider(t)
316323
}
317324
}

0 commit comments

Comments
 (0)