/// 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; }
/// Recursively check for conflicts with in-progress accesses at the given /// apply. /// /// Any captured variable accessed by a noescape closure is considered to be /// accessed at the point that the closure is fully applied. This includes /// variables captured by address by the noescape closure being applied or by /// any other noescape closure that is itself passed as an argument to that /// closure. /// /// (1) Use AccessSummaryAnalysis to check each argument for statically /// enforced accesses nested within the callee. /// /// (2) If an applied argument is itself a function type, recursively check for /// violations on the closure being passed as an argument. /// /// (3) Walk up the chain of partial applies to recursively visit all arguments. /// /// Note: This handles closures that are called immediately: /// var i = 7 /// ({ (p: inout Int) in i = 8})(&i) // Overlapping access to 'i' /// /// Note: This handles chains of partial applies: /// pa1 = partial_apply f(c) : $(a, b, c) /// pa2 = partial_apply pa1(b) : $(a, b) /// apply pa2(a) static void checkForViolationAtApply(ApplySite Apply, AccessState &State) { // First, check access to variables immediately captured at this apply site. checkCaptureAccess(Apply, State); // Next, recursively check any noescape closures passed as arguments at this // apply site. TinyPtrVector<PartialApplyInst *> partialApplies; for (SILValue Argument : Apply.getArguments()) { auto FnType = getSILFunctionTypeForValue(Argument); if (!FnType || !FnType->isNoEscape()) continue; findClosuresForFunctionValue(Argument, partialApplies); } // Continue recursively walking up the chain of applies if necessary. findClosuresForFunctionValue(Apply.getCallee(), partialApplies); for (auto *PAI : partialApplies) checkForViolationAtApply(ApplySite(PAI), State); }
/// 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; }