Revision 2edf2b26d08b1fe39c25424a7bc993fae1d07480 authored by Jordan Rose on 12 July 2017, 03:39:57 UTC, committed by GitHub on 12 July 2017, 03:39:57 UTC
aa215e7e54 made sure we didn't try to construct Sets and Dictionaries
with a non-Hashable key. However, that commit was a little too
restrictive: there was no handling for imported generic parameters
that were constrained to inherit from NSObject. Fortunately,
recovering that information is fairly straightforward.

rdar://problem/33222646
1 parent d067b63
Raw File
TBDGen.cpp
//===--- TBDGen.cpp - Swift TBD Generation --------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements the entrypoints into TBD file generation.
//
//===----------------------------------------------------------------------===//

#include "swift/TBDGen/TBDGen.h"

#include "swift/AST/ASTMangler.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/Module.h"
#include "swift/AST/ParameterList.h"
#include "swift/Basic/LLVM.h"
#include "swift/IRGen/Linking.h"
#include "swift/SIL/FormalLinkage.h"
#include "swift/SIL/SILDeclRef.h"
#include "swift/SIL/SILWitnessTable.h"
#include "swift/SIL/TypeLowering.h"
#include "llvm/ADT/StringSet.h"

using namespace swift;
using namespace swift::irgen;
using StringSet = llvm::StringSet<>;

static bool isPrivateDecl(ValueDecl *VD) {
  return getDeclLinkage(VD) != FormalLinkage::PublicUnique;
}

namespace {
class TBDGenVisitor : public ASTVisitor<TBDGenVisitor> {
  StringSet &Symbols;
  const UniversalLinkageInfo &UniversalLinkInfo;
  ModuleDecl *SwiftModule;
  bool FileHasEntryPoint;
  bool SILSerializeWitnessTables;

  void addSymbol(StringRef name) {
    auto isNewValue = Symbols.insert(name).second;
    (void)isNewValue;
    assert(isNewValue && "already inserted");
  }

  void addSymbol(SILDeclRef declRef, bool checkSILOnly = true);

  void addSymbol(LinkEntity entity) {
    auto linkage =
        LinkInfo::get(UniversalLinkInfo, SwiftModule, entity, ForDefinition);

    auto externallyVisible =
        llvm::GlobalValue::isExternalLinkage(linkage.getLinkage()) &&
        linkage.getVisibility() != llvm::GlobalValue::HiddenVisibility;

    if (externallyVisible)
      addSymbol(linkage.getName());
  }

  void addConformances(DeclContext *DC);

public:
  TBDGenVisitor(StringSet &symbols,
                const UniversalLinkageInfo &universalLinkInfo,
                ModuleDecl *swiftModule, bool fileHasEntryPoint,
                bool silSerializeWitnessTables)
      : Symbols(symbols), UniversalLinkInfo(universalLinkInfo),
        SwiftModule(swiftModule), FileHasEntryPoint(fileHasEntryPoint),
        SILSerializeWitnessTables(silSerializeWitnessTables) {}

  void visitMembers(Decl *D) {
    SmallVector<Decl *, 4> members;
    auto addMembers = [&](DeclRange range) {
      for (auto member : range)
        members.push_back(member);
    };
    if (auto ED = dyn_cast<ExtensionDecl>(D))
      addMembers(ED->getMembers());
    else if (auto NTD = dyn_cast<NominalTypeDecl>(D))
      addMembers(NTD->getMembers());
    else if (auto VD = dyn_cast<VarDecl>(D))
      VD->getAllAccessorFunctions(members);

    for (auto member : members) {
      ASTVisitor::visit(member);
    }
  }

  void visitPatternBindingDecl(PatternBindingDecl *PBD);

  void visitValueDecl(ValueDecl *VD);

  void visitAbstractFunctionDecl(AbstractFunctionDecl *AFD);

  void visitTypeAliasDecl(TypeAliasDecl *TAD) {
    // any information here is encoded elsewhere
  }

  void visitSubscriptDecl(SubscriptDecl *SD) {
    // Any getters and setters etc. exist as independent FuncDecls in the AST,
    // so get processed elsewhere; subscripts don't have any symbols other than
    // these.
  }

  void visitNominalTypeDecl(NominalTypeDecl *NTD);

  void visitClassDecl(ClassDecl *CD);

  void visitExtensionDecl(ExtensionDecl *ED);

  void visitProtocolDecl(ProtocolDecl *PD);

  void visitVarDecl(VarDecl *VD);

  void visitDecl(Decl *D) { visitMembers(D); }
};
} // end anonymous namespace

static bool isGlobalOrStaticVar(VarDecl *VD) {
  return VD->isStatic() || VD->getDeclContext()->isModuleScopeContext();
}

void TBDGenVisitor::visitPatternBindingDecl(PatternBindingDecl *PBD) {
  for (auto &entry : PBD->getPatternList()) {
    auto *var = entry.getAnchoringVarDecl();
    if (isPrivateDecl(var))
      return;

    // Non-global variables might have an explicit initializer symbol.
    if (entry.getInit() && !isGlobalOrStaticVar(var)) {
      auto declRef =
          SILDeclRef(var, SILDeclRef::Kind::StoredPropertyInitializer);
      // Stored property initializers for public properties are currently
      // public, even when the initializer is marked as SIL only (transparent).
      addSymbol(declRef, /*checkSILOnly=*/false);
    }
  }
}

void TBDGenVisitor::addSymbol(SILDeclRef declRef, bool checkSILOnly) {
  bool isPrivate = !hasPublicVisibility(declRef.getLinkage(ForDefinition));
  // Even private methods of open classes (specifically, private methods that
  // are in the vtable) have public symbols, because external subclasses
  // currently need to refer to them by symbol for their own vtable.
  switch (declRef.getSubclassScope()) {
  case SubclassScope::External:
    // Unlike the "truly" public things, private things have public symbols
    // unconditionally, even if they're theoretically SIL only.
    if (isPrivate) {
      isPrivate = false;
      checkSILOnly = false;
    }
    break;
  case SubclassScope::Internal:
  case SubclassScope::NotApplicable:
    break;
  }
  if (isPrivate)
    return;

  // (Most) transparent things don't exist, even if they're public.
  // FIXME: isTransparent should really be "is SIL only".
  if (checkSILOnly && declRef.isTransparent())
    return;

  addSymbol(declRef.mangle());
}

void TBDGenVisitor::addConformances(DeclContext *DC) {
  for (auto conformance : DC->getLocalConformances()) {
    auto protocol = conformance->getProtocol();
    auto needsWTable =
        Lowering::TypeConverter::protocolRequiresWitnessTable(protocol);
    if (!needsWTable)
      continue;

    // Only normal conformances get symbols; the others get any public symbols
    // from their parent normal conformance.
    auto normalConformance = dyn_cast<NormalProtocolConformance>(conformance);
    if (!normalConformance)
      continue;

    addSymbol(LinkEntity::forDirectProtocolWitnessTable(normalConformance));
    addSymbol(
        LinkEntity::forProtocolWitnessTableAccessFunction(normalConformance));

    // FIXME: the logic around visibility in extensions is confusing, and
    // sometimes witness thunks need to be manually made public.

    auto conformanceIsFixed = SILWitnessTable::conformanceIsSerialized(
        normalConformance, SwiftModule->getResilienceStrategy(),
        SILSerializeWitnessTables);
    auto addSymbolIfNecessary = [&](ValueDecl *valueReq,
                                    SILLinkage witnessLinkage) {
      if (conformanceIsFixed &&
          fixmeWitnessHasLinkageThatNeedsToBePublic(witnessLinkage)) {
        Mangle::ASTMangler Mangler;
        addSymbol(Mangler.mangleWitnessThunk(normalConformance, valueReq));
      }
    };
    normalConformance->forEachValueWitness(nullptr, [&](ValueDecl *valueReq,
                                                        Witness witness) {
      if (isa<AbstractFunctionDecl>(valueReq)) {
        auto witnessLinkage =
            SILDeclRef(witness.getDecl()).getLinkage(ForDefinition);
        addSymbolIfNecessary(valueReq, witnessLinkage);
      } else if (auto VD = dyn_cast<AbstractStorageDecl>(valueReq)) {
        // A var or subscript decl needs extra special handling: the things that
        // end up in the witness table are the accessors, but the compiler only
        // talks about the actual storage decl in the conformance, so we have to
        // manually walk over the members, having pulled out something that will
        // have the right linkage.
        auto witnessVD = cast<AbstractStorageDecl>(witness.getDecl());

        SmallVector<Decl *, 4> members;
        VD->getAllAccessorFunctions(members);

        // Grab one of the accessors, and then use that to pull out which of the
        // getter or setter will have the appropriate linkage.
        FuncDecl *witnessWithRelevantLinkage;
        switch (cast<FuncDecl>(members[0])->getAccessorKind()) {
        case AccessorKind::NotAccessor:
          llvm_unreachable("must be an accessor");
        case AccessorKind::IsGetter:
        case AccessorKind::IsAddressor:
          witnessWithRelevantLinkage = witnessVD->getGetter();
          break;
        case AccessorKind::IsSetter:
        case AccessorKind::IsWillSet:
        case AccessorKind::IsDidSet:
        case AccessorKind::IsMaterializeForSet:
        case AccessorKind::IsMutableAddressor:
          witnessWithRelevantLinkage = witnessVD->getSetter();
          break;
        }
        auto witnessLinkage =
            SILDeclRef(witnessWithRelevantLinkage).getLinkage(ForDefinition);
        for (auto member : members) {
          addSymbolIfNecessary(cast<ValueDecl>(member), witnessLinkage);
        }
      }
    });
  }
}

void TBDGenVisitor::visitValueDecl(ValueDecl *VD) {
  addSymbol(SILDeclRef(VD));
  visitMembers(VD);
}

void TBDGenVisitor::visitAbstractFunctionDecl(AbstractFunctionDecl *AFD) {
  // Default arguments (of public functions) are public symbols, as the default
  // values are computed at the call site.
  auto index = 0;
  auto paramLists = AFD->getParameterLists();
  // Skip the first arguments, which contains Self (etc.), can't be defaulted,
  // and are ignored for the purposes of default argument indices.
  if (AFD->getDeclContext()->isTypeContext())
    paramLists = paramLists.slice(1);
  for (auto *paramList : paramLists) {
    for (auto *param : *paramList) {
      if (param->getDefaultValue())
        addSymbol(SILDeclRef::getDefaultArgGenerator(AFD, index));
      index++;
    }
  }

  visitValueDecl(AFD);
}

void TBDGenVisitor::visitVarDecl(VarDecl *VD) {
  if (isPrivateDecl(VD))
    return;

  // statically/globally stored variables have some special handling.
  if (VD->hasStorage() && isGlobalOrStaticVar(VD)) {
    // The actual variable has a symbol.
    Mangle::ASTMangler mangler;
    addSymbol(mangler.mangleEntity(VD, false));

    // Variables in the main file don't get accessors, despite otherwise looking
    // like globals.
    if (!FileHasEntryPoint)
      addSymbol(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor));

    // In this case, the members of the VarDecl don't also appear as top-level
    // decls, so we need to explicitly walk them.
    visitMembers(VD);
  }
}

void TBDGenVisitor::visitNominalTypeDecl(NominalTypeDecl *NTD) {
  auto declaredType = NTD->getDeclaredType()->getCanonicalType();

  addSymbol(LinkEntity::forNominalTypeDescriptor(NTD));

  // Generic types do not get metadata directly, only through the function.
  if (!NTD->isGenericContext()) {
    addSymbol(LinkEntity::forTypeMetadata(declaredType,
                                          TypeMetadataAddress::AddressPoint,
                                          /*isPattern=*/false));
  }
  addSymbol(LinkEntity::forTypeMetadataAccessFunction(declaredType));

  // There are symbols associated with any protocols this type conforms to.
  addConformances(NTD);

  visitMembers(NTD);
}

void TBDGenVisitor::visitClassDecl(ClassDecl *CD) {
  if (isPrivateDecl(CD))
    return;

  auto &ctxt = CD->getASTContext();
  auto isGeneric = CD->isGenericContext();
  auto objCCompatible = ctxt.LangOpts.EnableObjCInterop && !isGeneric;
  auto isObjC = objCCompatible && CD->isObjC();

  // Metaclasses and ObjC class (duh) are a ObjC thing, and so are not needed in
  // build artifacts/for classes which can't touch ObjC.
  if (objCCompatible) {
    if (isObjC)
      addSymbol(LinkEntity::forObjCClass(CD));

    if (CD->getMetaclassKind() == ClassDecl::MetaclassKind::ObjC)
      addSymbol(LinkEntity::forObjCMetaclass(CD));
    else
      addSymbol(LinkEntity::forSwiftMetaclassStub(CD));
  }

  // Some members of classes get extra handling, beyond members of struct/enums,
  // so let's walk over them manually.
  for (auto *member : CD->getMembers()) {
    auto value = dyn_cast<ValueDecl>(member);
    if (!value)
      continue;

    auto var = dyn_cast<VarDecl>(value);
    auto hasFieldOffset =
        !isGeneric && var && var->hasStorage() && !var->isStatic();
    if (hasFieldOffset) {
      // FIXME: a field only has one sort of offset, but it is moderately
      // non-trivial to compute which one. Including both is less painful than
      // missing the correct one (for now), so we do that.
      addSymbol(LinkEntity::forFieldOffset(var, /*isIndirect=*/false));
      addSymbol(LinkEntity::forFieldOffset(var, /*isIndirect=*/true));
    }

    // The non-allocating forms of the constructors and destructors.
    if (auto ctor = dyn_cast<ConstructorDecl>(value)) {
      addSymbol(SILDeclRef(ctor, SILDeclRef::Kind::Initializer));
    } else if (auto dtor = dyn_cast<DestructorDecl>(value)) {
      // ObjC classes don't have a symbol for their destructor.
      if (!isObjC)
        addSymbol(SILDeclRef(dtor, SILDeclRef::Kind::Destroyer));
    }
  }

  visitNominalTypeDecl(CD);
}

void TBDGenVisitor::visitExtensionDecl(ExtensionDecl *ED) {
  if (!ED->getExtendedType()->isExistentialType()) {
    addConformances(ED);
  }

  visitMembers(ED);
}

void TBDGenVisitor::visitProtocolDecl(ProtocolDecl *PD) {
  if (!PD->isObjC())
    addSymbol(LinkEntity::forProtocolDescriptor(PD));

#ifndef NDEBUG
  // There's no (currently) relevant information about members of a protocol
  // at individual protocols, each conforming type has to handle them
  // individually. Let's assert this fact:
  for (auto *member : PD->getMembers()) {
    auto isExpectedKind =
        isa<TypeAliasDecl>(member) || isa<AssociatedTypeDecl>(member) ||
        isa<AbstractStorageDecl>(member) || isa<PatternBindingDecl>(member) ||
        isa<AbstractFunctionDecl>(member);
    assert(isExpectedKind &&
           "unexpected member of protocol during TBD generation");
  }
#endif
}

void swift::enumeratePublicSymbols(FileUnit *file, StringSet &symbols,
                                   bool hasMultipleIRGenThreads,
                                   bool isWholeModule,
                                   bool silSerializeWitnessTables) {
  UniversalLinkageInfo linkInfo(file->getASTContext().LangOpts.Target,
                                hasMultipleIRGenThreads, isWholeModule);

  SmallVector<Decl *, 16> decls;
  file->getTopLevelDecls(decls);

  auto hasEntryPoint = file->hasEntryPoint();

  TBDGenVisitor visitor(symbols, linkInfo, file->getParentModule(),
                        hasEntryPoint, silSerializeWitnessTables);
  for (auto d : decls)
    visitor.visit(d);

  if (hasEntryPoint)
    symbols.insert("main");
}
back to top