Exemplo n.º 1
0
SILWitnessTable *
SILModule::lookUpWitnessTable(const ProtocolConformance *C,
                              bool deserializeLazily) {
  assert(C && "null conformance passed to lookUpWitnessTable");

  const NormalProtocolConformance *NormalC = C->getRootNormalConformance();
  // Attempt to lookup the witness table from the table.
  auto found = WitnessTableMap.find(NormalC);
  if (found == WitnessTableMap.end()) {
#ifndef NDEBUG
    // Make sure that all witness tables are in the witness table lookup
    // cache.
    //
    // This code should not be hit normally since we add witness tables to the
    // lookup cache when we create them. We don't just assert here since there
    // is the potential for a conformance without a witness table to be passed
    // to this function.
    for (SILWitnessTable &WT : witnessTables)
      assert(WT.getConformance() != NormalC &&
             "Found witness table that is not"
             " in the witness table lookup cache.");
#endif
    return nullptr;
  }

  SILWitnessTable *wtable = found->second;
  assert(wtable != nullptr && "Should never map a conformance to a null witness"
                          " table.");

  // If we have a definition, return it.
  if (wtable->isDefinition())
    return wtable;

  // If the module is at or past the Lowered stage, then we can't do any
  // further deserialization, since pre-IRGen SIL lowering changes the types
  // of definitions to make them incompatible with canonical serialized SIL.
  switch (getStage()) {
  case SILStage::Canonical:
  case SILStage::Raw:
    break;
    
  case SILStage::Lowered:
    return wtable;
  }

  // Otherwise try to deserialize it. If we succeed return the deserialized
  // function.
  //
  // *NOTE* In practice, wtable will be deserializedTable, but I do not want to rely
  // on that behavior for now.
  if (deserializeLazily)
    if (auto deserialized = getSILLoader()->lookupWitnessTable(wtable))
      return deserialized;

  // If we fail, just return the declaration.
  return wtable;
}
Exemplo n.º 2
0
SILWitnessTable *
SILModule::lookUpWitnessTable(const ProtocolConformance *C,
                              bool deserializeLazily) {
  assert(C && "null conformance passed to lookUpWitnessTable");

  const NormalProtocolConformance *NormalC = C->getRootNormalConformance();
  // Attempt to lookup the witness table from the table.
  auto found = WitnessTableMap.find(NormalC);
  if (found == WitnessTableMap.end()) {
#ifndef NDEBUG
    // Make sure that all witness tables are in the witness table lookup
    // cache.
    //
    // This code should not be hit normally since we add witness tables to the
    // lookup cache when we create them. We don't just assert here since there
    // is the potential for a conformance without a witness table to be passed
    // to this function.
    for (SILWitnessTable &WT : witnessTables)
      assert(WT.getConformance() != NormalC &&
             "Found witness table that is not"
             " in the witness table lookup cache.");
#endif
    return nullptr;
  }

  SILWitnessTable *wT = found->second;
  assert(wT != nullptr && "Should never map a conformance to a null witness"
                          " table.");

  // If we have a definition, return it.
  if (wT->isDefinition())
    return wT;

  // Otherwise try to deserialize it. If we succeed return the deserialized
  // function.
  //
  // *NOTE* In practice, wT will be deserializedTable, but I do not want to rely
  // on that behavior for now.
  if (deserializeLazily)
    if (auto deserializedTable = getSILLoader()->lookupWitnessTable(wT))
      return deserializedTable;

  // If we fail, just return the declaration.
  return wT;
}
Exemplo n.º 3
0
std::pair<SILWitnessTable *, ArrayRef<Substitution>>
SILModule::
lookUpWitnessTable(const ProtocolConformance *C, bool deserializeLazily) {
  // If we have a null conformance passed in (a legal value), just return
  // nullptr.
  ArrayRef<Substitution> Subs;
  if (!C)
    return {nullptr, Subs};

  // Walk down to the base NormalProtocolConformance.
  const ProtocolConformance *ParentC = C;
  while (!isa<NormalProtocolConformance>(ParentC)) {
    switch (ParentC->getKind()) {
    case ProtocolConformanceKind::Normal:
      llvm_unreachable("should have exited the loop?!");
    case ProtocolConformanceKind::Inherited:
      ParentC = cast<InheritedProtocolConformance>(ParentC)
        ->getInheritedConformance();
      break;
    case ProtocolConformanceKind::Specialized: {
      auto SC = cast<SpecializedProtocolConformance>(ParentC);
      ParentC = SC->getGenericConformance();
      assert(Subs.empty() && "multiple conformance specializations?!");
      Subs = SC->getGenericSubstitutions();
      break;
    }
    }
  }
  const NormalProtocolConformance *NormalC
    = cast<NormalProtocolConformance>(ParentC);

  // If the normal conformance is for a generic type, and we didn't hit a
  // specialized conformance, collect the substitutions from the generic type.
  // FIXME: The AST should do this for us.
  if (NormalC->getType()->isSpecialized() && Subs.empty()) {
    Subs = NormalC->getType()
      ->gatherAllSubstitutions(NormalC->getDeclContext()->getParentModule(),
                               nullptr);
  }

  // Attempt to lookup the witness table from the table.
  auto found = WitnessTableLookupCache.find(NormalC);
  if (found == WitnessTableLookupCache.end()) {
#ifndef NDEBUG
    // Make sure that all witness tables are in the witness table lookup
    // cache.
    //
    // This code should not be hit normally since we add witness tables to the
    // lookup cache when we create them. We don't just assert here since there
    // is the potential for a conformance without a witness table to be passed
    // to this function.
    for (SILWitnessTable &WT : witnessTables)
      assert(WT.getConformance() != NormalC &&
             "Found witness table that is not"
             " in the witness table lookup cache.");
#endif
    return {nullptr, Subs};
  }

  SILWitnessTable *wT = found->second;
  assert(wT != nullptr && "Should never map a conformance to a null witness"
                          " table.");

  // If we have a definition, return it.
  if (wT->isDefinition())
    return {wT, Subs};

  // Otherwise try to deserialize it. If we succeed return the deserialized
  // function.
  //
  // *NOTE* In practice, wT will be deserializedTable, but I do not want to rely
  // on that behavior for now.
  if (deserializeLazily)
    if (auto deserializedTable = getSILLoader()->lookupWitnessTable(wT))
      return {deserializedTable, Subs};

  // If we fail, just return the declaration.
  return {wT, Subs};
}
Exemplo n.º 4
0
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;
    }
  }
}