/// Generate a new apply of a function_ref to replace an apply of a /// witness_method when we've determined the actual function we'll end /// up calling. static ApplySite devirtualizeWitnessMethod(ApplySite AI, SILFunction *F, ProtocolConformanceRef C, OptRemark::Emitter *ORE) { // We know the witness thunk and the corresponding set of substitutions // required to invoke the protocol method at this point. auto &Module = AI.getModule(); // Collect all the required substitutions. // // The complete set of substitutions may be different, e.g. because the found // witness thunk F may have been created by a specialization pass and have // additional generic parameters. auto SubMap = getWitnessMethodSubstitutions(Module, AI, F, C); // Figure out the exact bound type of the function to be called by // applying all substitutions. auto CalleeCanType = F->getLoweredFunctionType(); auto SubstCalleeCanType = CalleeCanType->substGenericArgs(Module, SubMap); // Collect arguments from the apply instruction. auto Arguments = SmallVector<SILValue, 4>(); // Iterate over the non self arguments and add them to the // new argument list, upcasting when required. SILBuilderWithScope B(AI.getInstruction()); SILFunctionConventions substConv(SubstCalleeCanType, Module); unsigned substArgIdx = AI.getCalleeArgIndexOfFirstAppliedArg(); for (auto arg : AI.getArguments()) { auto paramType = substConv.getSILArgumentType(substArgIdx++); if (arg->getType() != paramType) arg = castValueToABICompatibleType(&B, AI.getLoc(), arg, arg->getType(), paramType); Arguments.push_back(arg); } assert(substArgIdx == substConv.getNumSILArguments()); // Replace old apply instruction by a new apply instruction that invokes // the witness thunk. SILBuilderWithScope Builder(AI.getInstruction()); SILLocation Loc = AI.getLoc(); FunctionRefInst *FRI = Builder.createFunctionRef(Loc, F); ApplySite SAI = replaceApplySite(Builder, Loc, AI, FRI, SubMap, Arguments, substConv); if (ORE) ORE->emit([&]() { using namespace OptRemark; return RemarkPassed("WitnessMethodDevirtualized", *AI.getInstruction()) << "Devirtualized call to " << NV("Method", F); }); NumWitnessDevirt++; return SAI; }
/// For each argument in the range of the callee arguments being applied at the /// given apply site, use the summary analysis to determine whether the /// arguments will be accessed in a way that conflicts with any currently in /// progress accesses. If so, diagnose. static void checkCaptureAccess(ApplySite Apply, AccessState &State) { SILFunction *Callee = Apply.getCalleeFunction(); if (!Callee || Callee->empty()) return; const AccessSummaryAnalysis::FunctionSummary &FS = State.ASA->getOrCreateSummary(Callee); for (unsigned ArgumentIndex : range(Apply.getNumArguments())) { unsigned CalleeIndex = Apply.getCalleeArgIndexOfFirstAppliedArg() + ArgumentIndex; const AccessSummaryAnalysis::ArgumentSummary &AS = FS.getAccessForArgument(CalleeIndex); const auto &SubAccesses = AS.getSubAccesses(); // Is the capture accessed in the callee? if (SubAccesses.empty()) continue; SILValue Argument = Apply.getArgument(ArgumentIndex); assert(Argument->getType().isAddress()); // A valid AccessedStorage should alway sbe found because Unsafe accesses // are not tracked by AccessSummaryAnalysis. const AccessedStorage &Storage = findValidAccessedStorage(Argument); auto AccessIt = State.Accesses->find(Storage); // Are there any accesses in progress at the time of the call? if (AccessIt == State.Accesses->end()) continue; const AccessInfo &Info = AccessIt->getSecond(); if (auto Conflict = findConflictingArgumentAccess(AS, Storage, Info)) State.ConflictingAccesses.push_back(*Conflict); } }
/// Generate a new apply of a function_ref to replace an apply of a /// witness_method when we've determined the actual function we'll end /// up calling. static ApplySite devirtualizeWitnessMethod(ApplySite AI, SILFunction *F, ProtocolConformanceRef C) { // We know the witness thunk and the corresponding set of substitutions // required to invoke the protocol method at this point. auto &Module = AI.getModule(); // Collect all the required substitutions. // // The complete set of substitutions may be different, e.g. because the found // witness thunk F may have been created by a specialization pass and have // additional generic parameters. SmallVector<Substitution, 4> NewSubs; getWitnessMethodSubstitutions(AI, F, C, NewSubs); // Figure out the exact bound type of the function to be called by // applying all substitutions. auto CalleeCanType = F->getLoweredFunctionType(); auto SubstCalleeCanType = CalleeCanType->substGenericArgs(Module, NewSubs); // Collect arguments from the apply instruction. auto Arguments = SmallVector<SILValue, 4>(); // Iterate over the non self arguments and add them to the // new argument list, upcasting when required. SILBuilderWithScope B(AI.getInstruction()); SILFunctionConventions substConv(SubstCalleeCanType, Module); unsigned substArgIdx = AI.getCalleeArgIndexOfFirstAppliedArg(); for (auto arg : AI.getArguments()) { auto paramType = substConv.getSILArgumentType(substArgIdx++); if (arg->getType() != paramType) arg = castValueToABICompatibleType(&B, AI.getLoc(), arg, arg->getType(), paramType); Arguments.push_back(arg); } assert(substArgIdx == substConv.getNumSILArguments()); // Replace old apply instruction by a new apply instruction that invokes // the witness thunk. SILBuilderWithScope Builder(AI.getInstruction()); SILLocation Loc = AI.getLoc(); FunctionRefInst *FRI = Builder.createFunctionRef(Loc, F); auto SubstCalleeSILType = SILType::getPrimitiveObjectType(SubstCalleeCanType); auto ResultSILType = substConv.getSILResultType(); ApplySite SAI; if (auto *A = dyn_cast<ApplyInst>(AI)) SAI = Builder.createApply(Loc, FRI, SubstCalleeSILType, ResultSILType, NewSubs, Arguments, A->isNonThrowing()); if (auto *TAI = dyn_cast<TryApplyInst>(AI)) SAI = Builder.createTryApply(Loc, FRI, SubstCalleeSILType, NewSubs, Arguments, TAI->getNormalBB(), TAI->getErrorBB()); if (auto *PAI = dyn_cast<PartialApplyInst>(AI)) SAI = Builder.createPartialApply(Loc, FRI, SubstCalleeSILType, NewSubs, Arguments, PAI->getType()); NumWitnessDevirt++; return SAI; }