|
20 | 20 | using namespace swift;
|
21 | 21 |
|
22 | 22 | void ClassHierarchyAnalysis::init() {
|
| 23 | + auto module = M->getSwiftModule(); |
| 24 | + |
23 | 25 | // For each class declaration in our V-table list:
|
24 | 26 | for (auto &VT : M->getVTableList()) {
|
25 | 27 | ClassDecl *C = VT.getClass();
|
26 |
| - // Ignore classes that are at the top of the class hierarchy: |
27 |
| - if (!C->hasSuperclass()) |
28 |
| - continue; |
29 | 28 |
|
30 |
| - // Add the superclass to the list of inherited classes. |
31 |
| - ClassDecl *Super = C->getSuperclassDecl(); |
32 |
| - auto &K = DirectSubclassesCache[Super]; |
33 |
| - assert(std::find(K.begin(), K.end(), C) == K.end() && |
34 |
| - "Class vector must be unique"); |
35 |
| - K.push_back(C); |
| 29 | + while (true) { |
| 30 | + // Ignore classes that are at the top of the class hierarchy: |
| 31 | + if (!C->hasSuperclass()) |
| 32 | + break; |
| 33 | + |
| 34 | + ClassDecl *super = C->getSuperclassDecl(); |
| 35 | + auto superModule = super->getModuleContext(); |
| 36 | + |
| 37 | + // Don't bother collecting subclasses for classes from a different module. |
| 38 | + // TODO: cross-module WMO |
| 39 | + if (superModule != module) |
| 40 | + break; |
| 41 | + |
| 42 | + // Find the superclass's list of direct subclasses. If it's non-empty, |
| 43 | + // we've previously walked up to the class, so there's no reason to keep |
| 44 | + // walking from this point. |
| 45 | + auto &list = DirectSubclassesCache[super]; |
| 46 | + bool shouldVisitSuper = list.empty(); |
| 47 | + |
| 48 | + // Check whether C is already in the list, which can happen |
| 49 | + // if we had a v-table that was a subclass of C. |
| 50 | + // We expect a linear scan to be cheap enough for this. |
| 51 | + if (std::find(list.begin(), list.end(), C) != list.end()) |
| 52 | + break; |
| 53 | + |
| 54 | + list.push_back(C); |
| 55 | + |
| 56 | + // Keep walking if this is the first time we reached this superclass. |
| 57 | + // We have to do this because the SILModule might not have v-tables for |
| 58 | + // every class in the module. |
| 59 | + if (!shouldVisitSuper) |
| 60 | + break; |
| 61 | + |
| 62 | + C = super; |
| 63 | + } |
36 | 64 | }
|
37 | 65 | }
|
38 | 66 |
|
|
0 commit comments