Header line-scan: a hotpath method declared `virtual`. Every call site emits a vtable load + indirect branch (5-10 cyc best case, 15-20 cyc misprediction penalty on polymorphic sites) and the compiler can't inline through it. If there's only one implementation, mark `final` (devirtua
(src_text: str, path: Path, fenced)
| 990 | |
| 991 | |
| 992 | def _virtual_hotpath_findings(src_text: str, path: Path, fenced) -> list: |
| 993 | """Header line-scan: a hotpath method declared `virtual`. Every call |
| 994 | site emits a vtable load + indirect branch (5-10 cyc best case, 15-20 |
| 995 | cyc misprediction penalty on polymorphic sites) and the compiler |
| 996 | can't inline through it. If there's only one implementation, mark |
| 997 | `final` (devirtualizes when the dynamic type is statically known) |
| 998 | or drop `virtual` entirely. |
| 999 | |
| 1000 | Skipped when the method is taken as a Qt member-function pointer |
| 1001 | (`&Class::method`) anywhere in the header or its paired `.cpp` -- |
| 1002 | that means the method is dispatched through Qt's metacall (signal-slot |
| 1003 | or `QMetaObject::invokeMethod`), which can't be devirtualized regardless |
| 1004 | of `final`.""" |
| 1005 | findings: list = [] |
| 1006 | metacall_names = _qt_metacall_referenced_methods(src_text, path) |
| 1007 | for i, raw in enumerate(src_text.split("\n"), start=1): |
| 1008 | if fenced(i): |
| 1009 | continue |
| 1010 | scrubbed = _strip_strings_and_line_comments(raw) |
| 1011 | if "virtual" not in scrubbed: |
| 1012 | continue |
| 1013 | m = _VIRTUAL_HOTPATH_RE.search(scrubbed) |
| 1014 | if m is None: |
| 1015 | continue |
| 1016 | name = m.group(1) |
| 1017 | if name in metacall_names: |
| 1018 | continue |
| 1019 | findings.append( |
| 1020 | Finding( |
| 1021 | i, |
| 1022 | "perf-virtual-hotpath", |
| 1023 | f"hotpath method `{name}` declared `virtual` -- every call " |
| 1024 | f"site emits a vtable load + indirect branch (5-10 cyc best " |
| 1025 | f"case, 15-20 cyc misprediction on polymorphic sites). The " |
| 1026 | f"compiler can't inline through the indirect call. If only " |
| 1027 | f"one implementation exists, drop `virtual` or mark `final` " |
| 1028 | f"so the compiler can devirtualize.", |
| 1029 | ) |
| 1030 | ) |
| 1031 | return findings |
| 1032 | |
| 1033 | |
| 1034 | # API command scopes are <scope>.<verb>; compound scopes are camelCase |
no test coverage detected