bool SILLinkerVisitor::visitProtocolConformance( ProtocolConformanceRef ref, const Optional<SILDeclRef> &Member) { // If an abstract protocol conformance was passed in, just return false. if (ref.isAbstract()) return false; // Otherwise try and lookup a witness table for C. auto C = ref.getConcrete(); SILWitnessTable *WT = Mod.lookUpWitnessTable(C); // If we don't find any witness table for the conformance, bail and return // false. if (!WT) { Mod.createWitnessTableDeclaration( C, getLinkageForProtocolConformance( C->getRootNormalConformance(), NotForDefinition)); return false; } // If the looked up witness table is a declaration, there is nothing we can // do here. Just bail and return false. if (WT->isDeclaration()) return false; bool performFuncDeserialization = false; // For each entry in the witness table... for (auto &E : WT->getEntries()) { // If the entry is a witness method... if (E.getKind() == SILWitnessTable::WitnessKind::Method) { // And we are only interested in deserializing a specific requirement // and don't have that requirement, don't deserialize this method. if (Member.hasValue() && E.getMethodWitness().Requirement != *Member) continue; // The witness could be removed by dead function elimination. if (!E.getMethodWitness().Witness) continue; // Otherwise if it is the requirement we are looking for or we just want // to deserialize everything, add the function to the list of functions // to deserialize. performFuncDeserialization = true; addFunctionToWorklist(E.getMethodWitness().Witness); } } return performFuncDeserialization; }
void SILLinkerVisitor::visitProtocolConformance( ProtocolConformanceRef ref, const Optional<SILDeclRef> &Member) { // If an abstract protocol conformance was passed in, just return false. if (ref.isAbstract()) return; bool mustDeserialize = mustDeserializeProtocolConformance(Mod, ref); // Otherwise try and lookup a witness table for C. auto C = ref.getConcrete(); if (!VisitedConformances.insert(C).second) return; SILWitnessTable *WT = Mod.lookUpWitnessTable(C, true); // If we don't find any witness table for the conformance, bail and return // false. if (!WT) { Mod.createWitnessTableDeclaration( C, getLinkageForProtocolConformance( C->getRootNormalConformance(), NotForDefinition)); // Adding the declaration may allow us to now deserialize the body. // Force the body if we must deserialize this witness table. if (mustDeserialize) { WT = Mod.lookUpWitnessTable(C, true); assert(WT && WT->isDefinition() && "unable to deserialize witness table when we must?!"); } else { return; } } // If the looked up witness table is a declaration, there is nothing we can // do here. Just bail and return false. if (WT->isDeclaration()) return; auto maybeVisitRelatedConformance = [&](ProtocolConformanceRef c) { // Formally all conformances referenced by a used conformance are used. // However, eagerly visiting them all at this point leads to a large blowup // in the amount of SIL we read in. For optimization purposes we can defer // reading in most conformances until we need them for devirtualization. // However, we *must* pull in shared clang-importer-derived conformances // we potentially use, since we may not otherwise have a local definition. if (mustDeserializeProtocolConformance(Mod, c)) visitProtocolConformance(c, None); }; // For each entry in the witness table... for (auto &E : WT->getEntries()) { switch (E.getKind()) { // If the entry is a witness method... case SILWitnessTable::WitnessKind::Method: { // And we are only interested in deserializing a specific requirement // and don't have that requirement, don't deserialize this method. if (Member.hasValue() && E.getMethodWitness().Requirement != *Member) continue; // The witness could be removed by dead function elimination. if (!E.getMethodWitness().Witness) continue; // Otherwise, deserialize the witness if it has shared linkage, or if // we were asked to deserialize everything. maybeAddFunctionToWorklist(E.getMethodWitness().Witness); break; } // If the entry is a related witness table, see whether we need to // eagerly deserialize it. case SILWitnessTable::WitnessKind::BaseProtocol: { auto baseConformance = E.getBaseProtocolWitness().Witness; maybeVisitRelatedConformance(ProtocolConformanceRef(baseConformance)); break; } case SILWitnessTable::WitnessKind::AssociatedTypeProtocol: { auto assocConformance = E.getAssociatedTypeProtocolWitness().Witness; maybeVisitRelatedConformance(assocConformance); break; } case SILWitnessTable::WitnessKind::AssociatedType: case SILWitnessTable::WitnessKind::Invalid: break; } } }