Example #1
0
bool ide::printAccessorUSR(const AbstractStorageDecl *D, AccessorKind AccKind,
                           llvm::raw_ostream &OS) {
  // AccKind should always be either IsGetter or IsSetter here, based
  // on whether a reference is a mutating or non-mutating use.  USRs
  // aren't supposed to reflect implementation differences like stored
  // vs. addressed vs. observing.
  //
  // On the other side, the implementation indexer should be
  // registering the getter/setter USRs independently of how they're
  // actually implemented.  So a stored variable should still have
  // getter/setter USRs (pointing to the variable declaration), and an
  // addressed variable should have its "getter" point at the
  // addressor.

  AbstractStorageDecl *SD = const_cast<AbstractStorageDecl*>(D);
  if (shouldUseObjCUSR(SD)) {
    return printObjCUSRForAccessor(SD, AccKind, OS);
  }

  Mangle::ASTMangler NewMangler;
  std::string Mangled = NewMangler.mangleAccessorEntityAsUSR(AccKind,
                          AddressorKind::NotAddressor, SD, getUSRSpacePrefix());

  OS << Mangled;

  return false;
}
/// Get or create SILGlobalVariable for a given global VarDecl.
SILGlobalVariable *SILGenModule::getSILGlobalVariable(VarDecl *gDecl,
                                                      ForDefinition_t forDef) {
  // First, get a mangled name for the declaration.
  std::string mangledName;

  if (auto SILGenName = gDecl->getAttrs().getAttribute<SILGenNameAttr>()) {
    mangledName = SILGenName->Name;
  } else {
    Mangle::ASTMangler NewMangler;
    mangledName = NewMangler.mangleGlobalVariableFull(gDecl);
  }

  // Check if it is already created, and update linkage if necessary.
  if (auto gv = M.lookUpGlobalVariable(mangledName)) {
    // Update the SILLinkage here if this is a definition.
    if (forDef == ForDefinition) {
      gv->setLinkage(getSILLinkage(getDeclLinkage(gDecl), ForDefinition));
      gv->setDeclaration(false);
    }
    return gv;
  }

  // Get the linkage for SILGlobalVariable.
  SILLinkage link = getSILLinkage(getDeclLinkage(gDecl), forDef);
  SILType silTy = M.Types.getLoweredTypeOfGlobal(gDecl);

  auto *silGlobal = SILGlobalVariable::create(M, link, IsNotSerialized,
                                              mangledName, silTy,
                                              None, gDecl);
  silGlobal->setDeclaration(!forDef);

  return silGlobal;
}
Example #3
0
void TBDGenVisitor::visitVarDecl(VarDecl *VD) {
  // Variables inside non-resilient modules have some additional symbols.
  if (!VD->isResilient()) {
    // Non-global variables might have an explicit initializer symbol, in
    // non-resilient modules.
    if (VD->getAttrs().hasAttribute<HasInitialValueAttr>() &&
        !isGlobalOrStaticVar(VD)) {
      auto declRef = SILDeclRef(VD, SILDeclRef::Kind::StoredPropertyInitializer);
      // Stored property initializers for public properties are currently
      // public.
      addSymbol(declRef);
    }

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

      if (VD->isLazilyInitializedGlobal())
        addSymbol(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor));
    }
  }

  visitAbstractStorageDecl(VD);
}
static std::string
getMaterializeForSetCallbackName(ProtocolConformance *conformance,
                                 FuncDecl *requirement) {

  DeclContext *dc = requirement;
  ClosureExpr closure(/*patterns*/ nullptr,
                      /*throws*/ SourceLoc(),
                      /*arrow*/ SourceLoc(),
                      /*in*/ SourceLoc(),
                      /*result*/ TypeLoc(),
                      /*discriminator*/ 0,
                      /*context*/ requirement);
  closure.setType(TupleType::getEmpty(dc->getASTContext()));
  closure.getCaptureInfo().setGenericParamCaptures(true);

  Mangle::ASTMangler Mangler;
  std::string New;
  if (conformance) {
    // Concrete witness thunk for a conformance:
    //
    // Mangle this as if it were a conformance thunk for a closure
    // within the requirement.
    return Mangler.mangleClosureWitnessThunk(conformance, &closure);
  }
  // Default witness thunk or concrete implementation:
  //
  // Mangle this as if it were a closure within the requirement.
  return Mangler.mangleClosureEntity(&closure,
                                 Mangle::ASTMangler::SymbolKind::Default);
}
Example #5
0
SILFunction *SILGenModule::
getOrCreateReabstractionThunk(CanSILFunctionType thunkType,
                              CanSILFunctionType fromType,
                              CanSILFunctionType toType,
                              IsSerialized_t Serialized) {
  // The reference to the thunk is likely @noescape, but declarations are always
  // escaping.
  auto thunkDeclType =
      thunkType->getWithExtInfo(thunkType->getExtInfo().withNoEscape(false));

  // Mangle the reabstraction thunk.
  // Substitute context parameters out of the "from" and "to" types.
  auto fromInterfaceType = fromType->mapTypeOutOfContext()
    ->getCanonicalType();
  auto toInterfaceType = toType->mapTypeOutOfContext()
    ->getCanonicalType();

  Mangle::ASTMangler NewMangler;
  std::string name = NewMangler.mangleReabstractionThunkHelper(thunkType,
                       fromInterfaceType, toInterfaceType, M.getSwiftModule());
  
  auto loc = RegularLocation::getAutoGeneratedLocation();

  return M.getOrCreateSharedFunction(loc, name, thunkDeclType, IsBare,
                                     IsTransparent, IsSerializable,
                                     ProfileCounter(), IsReabstractionThunk);
}
Example #6
0
/// Emit a global initialization.
void SILGenModule::emitGlobalInitialization(PatternBindingDecl *pd,
                                            unsigned pbdEntry) {
  // Generic and dynamic static properties require lazy initialization, which
  // isn't implemented yet.
  if (pd->isStatic()) {
    assert(!pd->getDeclContext()->isGenericContext()
           || pd->getDeclContext()->getGenericSignatureOfContext()
                ->areAllParamsConcrete());
  }

  // Emit the lazy initialization token for the initialization expression.
  auto counter = anonymousSymbolCounter++;

  // Pick one variable of the pattern. Usually it's only one variable, but it
  // can also be something like: var (a, b) = ...
  Pattern *pattern = pd->getPattern(pbdEntry);
  VarDecl *varDecl = nullptr;
  pattern->forEachVariable([&](VarDecl *D) {
    varDecl = D;
  });
  assert(varDecl);

  Mangle::ASTMangler TokenMangler;
  std::string onceTokenBuffer = TokenMangler.mangleGlobalInit(varDecl, counter,
                                                              false);
  
  auto onceTy = BuiltinIntegerType::getWordType(M.getASTContext());
  auto onceSILTy
    = SILType::getPrimitiveObjectType(onceTy->getCanonicalType());

  // TODO: include the module in the onceToken's name mangling.
  // Then we can make it fragile.
  auto onceToken = SILGlobalVariable::create(M, SILLinkage::Private,
                                             makeModuleFragile
                                               ? IsSerialized
                                               : IsNotSerialized,
                                             onceTokenBuffer, onceSILTy);
  onceToken->setDeclaration(false);

  // Emit the initialization code into a function.
  Mangle::ASTMangler FuncMangler;
  std::string onceFuncBuffer = FuncMangler.mangleGlobalInit(varDecl, counter,
                                                            true);
  
  SILFunction *onceFunc = emitLazyGlobalInitializer(onceFuncBuffer, pd,
                                                    pbdEntry);

  // Generate accessor functions for all of the declared variables, which
  // Builtin.once the lazy global initializer we just generated then return
  // the address of the individual variable.
  GenGlobalAccessors(*this, onceToken, onceFunc)
    .visit(pd->getPattern(pbdEntry));
}
Example #7
0
static SILValue getBehaviorInitStorageFn(SILGenFunction &SGF,
                                         VarDecl *behaviorVar) {
  Mangle::ASTMangler NewMangler;
  std::string behaviorInitName = NewMangler.mangleBehaviorInitThunk(behaviorVar);
  
  SILFunction *thunkFn;
  // Skip out early if we already emitted this thunk.
  if (auto existing = SGF.SGM.M.lookUpFunction(behaviorInitName)) {
    thunkFn = existing;
  } else {
    auto init = behaviorVar->getBehavior()->InitStorageDecl.getDecl();
    auto initFn = SGF.SGM.getFunction(SILDeclRef(init), NotForDefinition);
    
    // Emit a thunk to inject the `self` metatype and implode tuples.
    auto storageVar = behaviorVar->getBehavior()->StorageDecl;
    auto selfTy = behaviorVar->getDeclContext()->getDeclaredInterfaceType();
    auto initTy = SGF.getLoweredType(selfTy).getFieldType(behaviorVar,
                                                          SGF.SGM.M);
    auto storageTy = SGF.getLoweredType(selfTy).getFieldType(storageVar,
                                                             SGF.SGM.M);
    
    auto initConstantTy = initFn->getLoweredType().castTo<SILFunctionType>();
    
    auto param = SILParameterInfo(initTy.getASTType(),
                        initTy.isAddress() ? ParameterConvention::Indirect_In
                                           : ParameterConvention::Direct_Owned);
    auto result = SILResultInfo(storageTy.getASTType(),
                              storageTy.isAddress() ? ResultConvention::Indirect
                                                    : ResultConvention::Owned);
    
    initConstantTy = SILFunctionType::get(initConstantTy->getGenericSignature(),
                                          initConstantTy->getExtInfo(),
                                          SILCoroutineKind::None,
                                          ParameterConvention::Direct_Unowned,
                                          param,
                                          /*yields*/ {},
                                          result,
                                          // TODO: throwing initializer?
                                          None,
                                          SGF.getASTContext());
    
    // TODO: Generate the body of the thunk.
    thunkFn = SGF.SGM.M.getOrCreateFunction(SILLocation(behaviorVar),
                                            behaviorInitName,
                                            SILLinkage::PrivateExternal,
                                            initConstantTy,
                                            IsBare, IsTransparent, IsSerialized);
    
    
  }
  return SGF.B.createFunctionRef(behaviorVar, thunkFn);
}
Example #8
0
void TBDGenVisitor::addConformances(DeclContext *DC) {
  for (auto conformance : DC->getLocalConformances()) {
    auto protocol = conformance->getProtocol();
    auto needsWTable =
        Lowering::TypeConverter::protocolRequiresWitnessTable(protocol);
    if (!needsWTable)
      continue;

    // Only root conformances get symbols; the others get any public symbols
    // from their parent conformances.
    auto rootConformance = dyn_cast<RootProtocolConformance>(conformance);
    if (!rootConformance) {
      continue;
    }

    addSymbol(LinkEntity::forProtocolWitnessTable(rootConformance));
    addSymbol(LinkEntity::forProtocolConformanceDescriptor(rootConformance));

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

    auto conformanceIsFixed = SILWitnessTable::conformanceIsSerialized(
        rootConformance);
    auto addSymbolIfNecessary = [&](ValueDecl *requirementDecl,
                                    ValueDecl *witnessDecl) {
      auto witnessLinkage = SILDeclRef(witnessDecl).getLinkage(ForDefinition);
      if (conformanceIsFixed &&
          (isa<SelfProtocolConformance>(rootConformance) ||
           fixmeWitnessHasLinkageThatNeedsToBePublic(witnessLinkage))) {
        Mangle::ASTMangler Mangler;
        addSymbol(
            Mangler.mangleWitnessThunk(rootConformance, requirementDecl));
      }
    };

    rootConformance->forEachValueWitness(
        nullptr, [&](ValueDecl *valueReq, Witness witness) {
          auto witnessDecl = witness.getDecl();
          if (isa<AbstractFunctionDecl>(valueReq)) {
            addSymbolIfNecessary(valueReq, witnessDecl);
          } else if (auto *storage = dyn_cast<AbstractStorageDecl>(valueReq)) {
            auto witnessStorage = cast<AbstractStorageDecl>(witnessDecl);
            storage->visitOpaqueAccessors([&](AccessorDecl *reqtAccessor) {
              auto witnessAccessor =
                witnessStorage->getAccessor(reqtAccessor->getAccessorKind());
              assert(witnessAccessor && "no corresponding witness accessor?");
              addSymbolIfNecessary(reqtAccessor, witnessAccessor);
            });
          }
        });
  }
}
Example #9
0
void TBDGenVisitor::visitVarDecl(VarDecl *VD) {
  // 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));

    // Top-level variables (*not* statics) in the main file don't get accessors,
    // despite otherwise looking like globals.
    if (!FileHasEntryPoint || VD->isStatic())
      addSymbol(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor));
  }

  visitAbstractStorageDecl(VD);
}
Example #10
0
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));

    addSymbol(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor));
  }

  visitMembers(VD);
}
Example #11
0
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));
  }

  visitMembers(VD);
}
Example #12
0
SILFunction *SILGenModule::emitProtocolWitness(
    ProtocolConformanceRef conformance, SILLinkage linkage,
    IsSerialized_t isSerialized, SILDeclRef requirement, SILDeclRef witnessRef,
    IsFreeFunctionWitness_t isFree, Witness witness) {
  auto requirementInfo = Types.getConstantInfo(requirement);

  // Work out the lowered function type of the SIL witness thunk.
  auto reqtOrigTy = cast<GenericFunctionType>(requirementInfo.LoweredType);

  // Mapping from the requirement's generic signature to the witness
  // thunk's generic signature.
  auto reqtSubMap = witness.getRequirementToSyntheticSubs();

  // The generic environment for the witness thunk.
  auto *genericEnv = witness.getSyntheticEnvironment();

  // The type of the witness thunk.
  auto input = reqtOrigTy->getInput().subst(reqtSubMap)->getCanonicalType();
  auto result = reqtOrigTy->getResult().subst(reqtSubMap)->getCanonicalType();

  // If there's something to map to for the witness thunk, the conformance
  // should be phrased in the same terms. This particularly applies to classes
  // where a thunk for a method in a conformance like `extension Class: P where
  // T: Q` will go from its native signature of `<τ_0_0 where τ_0_0: Q>` (with T
  // canonicalised to τ_0_0), to `<τ_0_0, τ_1_0 where τ_0_0: Class<τ_1_0>,
  // τ_1_0: Q>` (with T now represented by τ_1_0). Find the right conformance by
  // looking for the conformance of 'Self'.
  if (reqtSubMap) {
    auto requirement = conformance.getRequirement();
    auto self = requirement->getProtocolSelfType()->getCanonicalType();

    conformance = *reqtSubMap.lookupConformance(self, requirement);
  }

  CanAnyFunctionType reqtSubstTy;
  if (genericEnv) {
    auto *genericSig = genericEnv->getGenericSignature();
    reqtSubstTy = CanGenericFunctionType::get(
        genericSig->getCanonicalSignature(),
        input, result, reqtOrigTy->getExtInfo());
  } else {
    reqtSubstTy = CanFunctionType::get(
        input, result, reqtOrigTy->getExtInfo());
  }

  // FIXME: this needs to pull out the conformances/witness-tables for any
  // conditional requirements from the witness table and pass them to the
  // underlying function in the thunk.

  // Lower the witness thunk type with the requirement's abstraction level.
  auto witnessSILFnType = getNativeSILFunctionType(
      M, AbstractionPattern(reqtOrigTy), reqtSubstTy, witnessRef, conformance);

  // Mangle the name of the witness thunk.
  Mangle::ASTMangler NewMangler;
  auto manglingConformance =
      conformance.isConcrete() ? conformance.getConcrete() : nullptr;
  std::string nameBuffer =
      NewMangler.mangleWitnessThunk(manglingConformance, requirement.getDecl());

  // If the thunked-to function is set to be always inlined, do the
  // same with the witness, on the theory that the user wants all
  // calls removed if possible, e.g. when we're able to devirtualize
  // the witness method call. Otherwise, use the default inlining
  // setting on the theory that forcing inlining off should only
  // effect the user's function, not otherwise invisible thunks.
  Inline_t InlineStrategy = InlineDefault;
  if (witnessRef.isAlwaysInline())
    InlineStrategy = AlwaysInline;

  auto *f = M.createFunction(
      linkage, nameBuffer, witnessSILFnType, genericEnv,
      SILLocation(witnessRef.getDecl()), IsNotBare, IsTransparent, isSerialized,
      ProfileCounter(), IsThunk, SubclassScope::NotApplicable, InlineStrategy);

  f->setDebugScope(new (M)
                   SILDebugScope(RegularLocation(witnessRef.getDecl()), f));

  PrettyStackTraceSILFunction trace("generating protocol witness thunk", f);

  // Create the witness.
  SILGenFunction SGF(*this, *f);

  // Substitutions mapping the generic parameters of the witness to
  // archetypes of the witness thunk generic environment.
  auto witnessSubs = witness.getSubstitutions();

  // Open-code protocol witness thunks for materializeForSet.
  if (auto witnessFn = dyn_cast<AccessorDecl>(witnessRef.getDecl())) {
    if (witnessFn->isMaterializeForSet()) {
      assert(!isFree);

      auto *proto = cast<ProtocolDecl>(requirement.getDecl()->getDeclContext());
      auto selfInterfaceType = proto->getSelfInterfaceType().subst(reqtSubMap);
      auto selfType = GenericEnvironment::mapTypeIntoContext(
          genericEnv, selfInterfaceType);

      auto reqFn = cast<AccessorDecl>(requirement.getDecl());
      assert(reqFn->isMaterializeForSet());

      if (SGF.maybeEmitMaterializeForSetThunk(conformance, linkage,
                                              selfInterfaceType, selfType,
                                              genericEnv, reqFn, witnessFn,
                                              witnessSubs.toList()))
        return f;

      // Proceed down the normal path.
    }
  }

  SGF.emitProtocolWitness(AbstractionPattern(reqtOrigTy), reqtSubstTy,
                          requirement, witnessRef,
                          witnessSubs.toList(), isFree);

  return f;
}
Example #13
0
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);
        }
      }
    });
  }
}
Example #14
0
bool ide::printDeclTypeUSR(const ValueDecl *D, raw_ostream &OS) {
  Mangle::ASTMangler Mangler;
  std::string MangledName = Mangler.mangleDeclType(D);
  OS << MangledName;
  return false;
}
Example #15
0
static std::string mangleTypeAsContext(const NominalTypeDecl *type) {
  Mangle::ASTMangler Mangler;
  return Mangler.mangleTypeAsContextUSR(type);
}
Example #16
0
Optional<SILVTable::Entry>
SILGenModule::emitVTableMethod(ClassDecl *theClass,
                               SILDeclRef derived, SILDeclRef base) {
  assert(base.kind == derived.kind);

  auto *baseDecl = base.getDecl();
  auto *derivedDecl = derived.getDecl();

  // Note: We intentionally don't support extension members here.
  //
  // Once extensions can override or introduce new vtable entries, this will
  // all likely change anyway.
  auto *baseClass = cast<ClassDecl>(baseDecl->getDeclContext());
  auto *derivedClass = cast<ClassDecl>(derivedDecl->getDeclContext());

  // Figure out if the vtable entry comes from the superclass, in which
  // case we won't emit it if building a resilient module.
  SILVTable::Entry::Kind implKind;
  if (baseClass == theClass) {
    // This is a vtable entry for a method of the immediate class.
    implKind = SILVTable::Entry::Kind::Normal;
  } else if (derivedClass == theClass) {
    // This is a vtable entry for a method of a base class, but it is being
    // overridden in the immediate class.
    implKind = SILVTable::Entry::Kind::Override;
  } else {
    // This vtable entry is copied from the superclass.
    implKind = SILVTable::Entry::Kind::Inherited;

    // If the override is defined in a class from a different resilience
    // domain, don't emit the vtable entry.
    if (derivedClass->isResilient(M.getSwiftModule(),
                                  ResilienceExpansion::Maximal)) {
      return None;
    }
  }

  SILFunction *implFn;
  SILLinkage implLinkage;

  // If the member is dynamic, reference its dynamic dispatch thunk so that
  // it will be redispatched, funneling the method call through the runtime
  // hook point.
  if (derivedDecl->isDynamic()
      && derived.kind != SILDeclRef::Kind::Allocator) {
    implFn = getDynamicThunk(derived, Types.getConstantInfo(derived).SILFnType);
    implLinkage = SILLinkage::Public;
  } else {
    implFn = getFunction(derived, NotForDefinition);
    implLinkage = stripExternalFromLinkage(implFn->getLinkage());
  }

  // As a fast path, if there is no override, definitely no thunk is necessary.
  if (derived == base)
    return SILVTable::Entry(base, implFn, implKind, implLinkage);

  // Determine the derived thunk type by lowering the derived type against the
  // abstraction pattern of the base.
  auto baseInfo = Types.getConstantInfo(base);
  auto derivedInfo = Types.getConstantInfo(derived);
  auto basePattern = AbstractionPattern(baseInfo.LoweredType);
  
  auto overrideInfo = M.Types.getConstantOverrideInfo(derived, base);

  // The override member type is semantically a subtype of the base
  // member type. If the override is ABI compatible, we do not need
  // a thunk.
  if (M.Types.checkFunctionForABIDifferences(derivedInfo.SILFnType,
                                             overrideInfo.SILFnType)
      == TypeConverter::ABIDifference::Trivial)
    return SILVTable::Entry(base, implFn, implKind, implLinkage);

  // Generate the thunk name.
  std::string name;
  {
    Mangle::ASTMangler mangler;
    if (isa<FuncDecl>(baseDecl)) {
      name = mangler.mangleVTableThunk(
        cast<FuncDecl>(baseDecl),
        cast<FuncDecl>(derivedDecl));
    } else {
      name = mangler.mangleConstructorVTableThunk(
        cast<ConstructorDecl>(baseDecl),
        cast<ConstructorDecl>(derivedDecl),
        base.kind == SILDeclRef::Kind::Allocator);
    }
  }

  // If we already emitted this thunk, reuse it.
  if (auto existingThunk = M.lookUpFunction(name))
    return SILVTable::Entry(base, existingThunk, implKind, implLinkage);

  // Emit the thunk.
  SILLocation loc(derivedDecl);
  SILGenFunctionBuilder builder(*this);
  auto thunk = builder.createFunction(
      SILLinkage::Private, name, overrideInfo.SILFnType,
      cast<AbstractFunctionDecl>(derivedDecl)->getGenericEnvironment(), loc,
      IsBare, IsNotTransparent, IsNotSerialized);
  thunk->setDebugScope(new (M) SILDebugScope(loc, thunk));

  SILGenFunction(*this, *thunk, theClass)
    .emitVTableThunk(derived, implFn, basePattern,
                     overrideInfo.LoweredType,
                     derivedInfo.LoweredType);

  return SILVTable::Entry(base, thunk, implKind, implLinkage);
}
Example #17
0
bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) {
  if (!D->hasName() && !isa<ParamDecl>(D) && !isa<AccessorDecl>(D))
    return true; // Ignore.
  if (D->getModuleContext()->isBuiltinModule())
    return true; // Ignore.
  if (isa<ModuleDecl>(D))
    return true; // Ignore.

  auto interpretAsClangNode = [](const ValueDecl *D)->ClangNode {
    ClangNode ClangN = D->getClangNode();
    if (auto ClangD = ClangN.getAsDecl()) {
      // NSErrorDomain causes the clang enum to be imported like this:
      //
      // struct MyError {
      //     enum Code : Int32 {
      //         case errFirst
      //         case errSecond
      //     }
      //     static var errFirst: MyError.Code { get }
      //     static var errSecond: MyError.Code { get }
      // }
      //
      // The clang enum constants are associated with both the static vars and
      // the enum cases.
      // But we want unique USRs for the above symbols, so use the clang USR
      // for the enum cases, and the Swift USR for the vars.
      //
      if (auto *ClangEnumConst = dyn_cast<clang::EnumConstantDecl>(ClangD)) {
        if (auto *ClangEnum = dyn_cast<clang::EnumDecl>(ClangEnumConst->getDeclContext())) {
          if (ClangEnum->hasAttr<clang::NSErrorDomainAttr>() && isa<VarDecl>(D))
            return ClangNode();
        }
      }
    }
    return ClangN;
  };

  if (ClangNode ClangN = interpretAsClangNode(D)) {
    llvm::SmallString<128> Buf;
    if (auto ClangD = ClangN.getAsDecl()) {
      bool Ignore = clang::index::generateUSRForDecl(ClangD, Buf);
      if (!Ignore)
        OS << Buf.str();
      return Ignore;
    }

    auto &Importer = *D->getASTContext().getClangModuleLoader();

    auto ClangMacroInfo = ClangN.getAsMacro();
    bool Ignore = clang::index::generateUSRForMacro(
        D->getBaseName().getIdentifier().str(),
        ClangMacroInfo->getDefinitionLoc(),
        Importer.getClangASTContext().getSourceManager(), Buf);
    if (!Ignore)
      OS << Buf.str();
    return Ignore;
  }

  if (shouldUseObjCUSR(D)) {
    return printObjCUSR(D, OS);
  }

  if (!D->hasInterfaceType())
    return true;

  // Invalid code.
  if (D->getInterfaceType().findIf([](Type t) -> bool {
        return t->is<ModuleType>();
      }))
    return true;

  Mangle::ASTMangler NewMangler;
  std::string Mangled = NewMangler.mangleDeclAsUSR(D, getUSRSpacePrefix());

  OS << Mangled;

  return false;
}
Example #18
0
static std::string mangleGetter(VarDecl *varDecl) {
  Mangle::ASTMangler Mangler;
  return Mangler.mangleGlobalGetterEntity(varDecl);
}
std::string SILDefaultWitnessTable::getUniqueName() const {
  Mangle::ASTMangler Mangler;
  return Mangler.mangleTypeWithoutPrefix(getProtocol()->getDeclaredType());
}
Example #20
0
SILFunction *SILGenModule::emitProtocolWitness(
    ProtocolConformanceRef conformance, SILLinkage linkage,
    IsSerialized_t isSerialized, SILDeclRef requirement, SILDeclRef witnessRef,
    IsFreeFunctionWitness_t isFree, Witness witness) {
  auto requirementInfo = Types.getConstantInfo(requirement);

  // Work out the lowered function type of the SIL witness thunk.
  auto reqtOrigTy = cast<GenericFunctionType>(requirementInfo.LoweredType);

  // Mapping from the requirement's generic signature to the witness
  // thunk's generic signature.
  auto reqtSubMap = witness.getRequirementToSyntheticSubs();

  // The generic environment for the witness thunk.
  auto *genericEnv = witness.getSyntheticEnvironment();

  // The type of the witness thunk.
  auto substReqtTy =
        cast<AnyFunctionType>(reqtOrigTy.subst(reqtSubMap)->getCanonicalType());

  // If there's something to map to for the witness thunk, the conformance
  // should be phrased in the same terms. This particularly applies to classes
  // where a thunk for a method in a conformance like `extension Class: P where
  // T: Q` will go from its native signature of `<τ_0_0 where τ_0_0: Q>` (with T
  // canonicalised to τ_0_0), to `<τ_0_0, τ_1_0 where τ_0_0: Class<τ_1_0>,
  // τ_1_0: Q>` (with T now represented by τ_1_0). Find the right conformance by
  // looking for the conformance of 'Self'.
  if (reqtSubMap) {
    auto requirement = conformance.getRequirement();
    auto self = requirement->getProtocolSelfType()->getCanonicalType();

    conformance = *reqtSubMap.lookupConformance(self, requirement);
  }

  CanAnyFunctionType reqtSubstTy;
  if (genericEnv) {
    auto *genericSig = genericEnv->getGenericSignature();
    reqtSubstTy = CanGenericFunctionType::get(
        genericSig->getCanonicalSignature(),
        substReqtTy->getParams(), substReqtTy.getResult(),
        reqtOrigTy->getExtInfo());
  } else {
    reqtSubstTy = CanFunctionType::get(substReqtTy->getParams(),
                                       substReqtTy.getResult(),
                                       reqtOrigTy->getExtInfo());
  }

  // Coroutine lowering requires us to provide these substitutions
  // in order to recreate the appropriate yield types for the accessor
  // because they aren't reflected in the accessor's AST type.
  // But this is expensive, so we only do it for coroutine lowering.
  // When they're part of the AST function type, we can remove this
  // parameter completely.
  Optional<SubstitutionMap> witnessSubsForTypeLowering;
  if (auto accessor = dyn_cast<AccessorDecl>(requirement.getDecl())) {
    if (accessor->isCoroutine()) {
      witnessSubsForTypeLowering =
        witness.getSubstitutions().mapReplacementTypesOutOfContext();
    }
  }

  // FIXME: this needs to pull out the conformances/witness-tables for any
  // conditional requirements from the witness table and pass them to the
  // underlying function in the thunk.

  // Lower the witness thunk type with the requirement's abstraction level.
  auto witnessSILFnType = getNativeSILFunctionType(
      M, AbstractionPattern(reqtOrigTy), reqtSubstTy,
      requirement, witnessRef, witnessSubsForTypeLowering, conformance);

  // Mangle the name of the witness thunk.
  Mangle::ASTMangler NewMangler;
  auto manglingConformance =
      conformance.isConcrete() ? conformance.getConcrete() : nullptr;
  std::string nameBuffer =
      NewMangler.mangleWitnessThunk(manglingConformance, requirement.getDecl());

  // If the thunked-to function is set to be always inlined, do the
  // same with the witness, on the theory that the user wants all
  // calls removed if possible, e.g. when we're able to devirtualize
  // the witness method call. Otherwise, use the default inlining
  // setting on the theory that forcing inlining off should only
  // effect the user's function, not otherwise invisible thunks.
  Inline_t InlineStrategy = InlineDefault;
  if (witnessRef.isAlwaysInline())
    InlineStrategy = AlwaysInline;

  SILGenFunctionBuilder builder(*this);
  auto *f = builder.createFunction(
      linkage, nameBuffer, witnessSILFnType, genericEnv,
      SILLocation(witnessRef.getDecl()), IsNotBare, IsTransparent, isSerialized,
      ProfileCounter(), IsThunk, SubclassScope::NotApplicable, InlineStrategy);

  f->setDebugScope(new (M)
                   SILDebugScope(RegularLocation(witnessRef.getDecl()), f));

  PrettyStackTraceSILFunction trace("generating protocol witness thunk", f);

  // Create the witness.
  SILGenFunction SGF(*this, *f, SwiftModule);

  // Substitutions mapping the generic parameters of the witness to
  // archetypes of the witness thunk generic environment.
  auto witnessSubs = witness.getSubstitutions();

  SGF.emitProtocolWitness(AbstractionPattern(reqtOrigTy), reqtSubstTy,
                          requirement, reqtSubMap, witnessRef,
                          witnessSubs, isFree);

  return f;
}
Example #21
0
bool ide::printTypeUSR(Type Ty, raw_ostream &OS) {
  assert(!Ty->hasArchetype() && "cannot have contextless archetypes mangled.");
  Mangle::ASTMangler Mangler;
  OS << Mangler.mangleTypeForDebugger(Ty->getRValueType(), nullptr, nullptr);
  return false;
}