//===--- SILGenBridging.cpp - SILGen for bridging to Clang ASTs -----------===// // // 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 // //===----------------------------------------------------------------------===// #include "ArgumentScope.h" #include "Callee.h" #include "ExecutorBreadcrumb.h" #include "RValue.h" #include "ResultPlan.h" #include "SILGenFunction.h" #include "SILGenFunctionBuilder.h" #include "Scope.h" #include "swift/AST/ConformanceLookup.h" #include "swift/AST/DiagnosticsSIL.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/ModuleLoader.h" #include "swift/AST/NameLookupRequests.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ProtocolConformance.h" #include "swift/Basic/Assertions.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILUndef.h" #include "swift/SIL/TypeLowering.h" #include "clang/AST/DeclObjC.h" using namespace swift; using namespace Lowering; /// Convert to the given formal type, assuming that the lowered type of /// the source type is the same as its formal type. This is a reasonable /// assumption for a wide variety of types. static ManagedValue emitUnabstractedCast(SILGenFunction &SGF, SILLocation loc, ManagedValue value, CanType sourceFormalType, CanType targetFormalType) { SILType loweredResultTy = SGF.getLoweredType(targetFormalType); if (value.getType() == loweredResultTy) return value; return SGF.emitTransformedValue(loc, value, AbstractionPattern(sourceFormalType), sourceFormalType, AbstractionPattern(targetFormalType), targetFormalType, loweredResultTy); } static bool shouldBridgeThroughError(SILGenModule &SGM, CanType type, CanType targetType) { // Never use this logic if the target type is AnyObject. if (targetType->isEqual(SGM.getASTContext().getAnyObjectType())) return false; auto errorProtocol = SGM.getASTContext().getErrorDecl(); if (!errorProtocol) return false; // Existential types are convertible to Error if they are, or imply, Error. if (type.isExistentialType()) { auto layout = type->getExistentialLayout(); for (auto proto : layout.getProtocols()) { if (proto == errorProtocol || proto->inheritsFrom(errorProtocol)) { return true; } } // They're also convertible to Error if they have a class bound that // conforms to Error. if (auto superclass = layout.getSuperclass()) { type = superclass->getCanonicalType(); // Otherwise, they are not convertible to Error. } else { return false; } } return (bool) lookupConformance(type, errorProtocol); } /// Bridge the given Swift value to its corresponding Objective-C /// object, using the appropriate witness for the /// _ObjectiveCBridgeable._bridgeToObjectiveC requirement. static std::optional emitBridgeNativeToObjectiveC(SILGenFunction &SGF, SILLocation loc, ManagedValue swiftValue, CanType swiftValueType, CanType bridgedType, ProtocolConformance *conformance) { // Find the _bridgeToObjectiveC requirement. auto requirement = SGF.SGM.getBridgeToObjectiveCRequirement(loc); if (!requirement) return std::nullopt; // Retrieve the _bridgeToObjectiveC witness. auto witness = conformance->getWitnessDecl(requirement); assert(witness); // Determine the type we're bridging to. auto objcTypeReq = SGF.SGM.getBridgedObjectiveCTypeRequirement(loc); if (!objcTypeReq) return std::nullopt; Type objcType = conformance->getTypeWitness(objcTypeReq); // Create a reference to the witness. SILDeclRef witnessConstant(witness); auto witnessRef = SGF.emitGlobalFunctionRef(loc, witnessConstant); // Determine the substitutions. auto witnessFnTy = witnessRef->getType(); // Compute the substitutions. // FIXME: Figure out the right SubstitutionMap stuff if the witness // has generic parameters of its own. assert(!cast(witness)->hasGenericParamList() && "Generic witnesses not supported"); auto *dc = cast(witness)->getDeclContext(); auto typeSubMap = swiftValueType->getContextSubstitutionMap(dc); // Substitute into the witness function type. witnessFnTy = witnessFnTy.substGenericArgs(SGF.SGM.M, typeSubMap, SGF.getTypeExpansionContext()); // We might have to re-abstract the 'self' value if it is an // Optional. AbstractionPattern origSelfType(witness->getInterfaceType()); origSelfType = origSelfType.getFunctionParamType(0); ArgumentScope scope(SGF, loc); swiftValue = SGF.emitSubstToOrigValue(loc, swiftValue, origSelfType, swiftValueType, SGFContext()); // The witness may be more abstract than the concrete value we're bridging, // for instance, if the value is a concrete instantiation of a generic type. // // Note that we assume that we don't ever have to reabstract the parameter. // This is safe for now, since only nominal types currently can conform to // protocols. SILFunctionConventions witnessConv(witnessFnTy.castTo(), SGF.SGM.M); if (witnessConv.isSILIndirect(witnessConv.getParameters()[0]) && !swiftValue.getType().isAddress()) { auto tmp = SGF.emitTemporaryAllocation(loc, swiftValue.getType()); swiftValue = SGF.emitManagedStoreBorrow( loc, swiftValue.borrow(SGF, loc).getValue(), tmp); } // Call the witness. SILValue bridgedValue = SGF.B.createApply(loc, witnessRef, typeSubMap, swiftValue.borrow(SGF, loc).getValue()); auto bridgedMV = SGF.emitManagedRValueWithCleanup(bridgedValue); bridgedMV = scope.popPreservingValue(bridgedMV); // The Objective-C value doesn't necessarily match the desired type. bridgedMV = emitUnabstractedCast(SGF, loc, bridgedMV, objcType->getCanonicalType(), bridgedType); return bridgedMV; } /// Bridge the given Objective-C object to its corresponding Swift /// value, using the appropriate witness for the /// _ObjectiveCBridgeable._unconditionallyBridgeFromObjectiveC requirement. static std::optional emitBridgeObjectiveCToNative(SILGenFunction &SGF, SILLocation loc, ManagedValue objcValue, CanType bridgedType, ProtocolConformance *conformance) { // Find the _unconditionallyBridgeFromObjectiveC requirement. auto requirement = SGF.SGM.getUnconditionallyBridgeFromObjectiveCRequirement(loc); if (!requirement) return std::nullopt; // Find the _ObjectiveCType requirement. auto objcTypeRequirement = SGF.SGM.getBridgedObjectiveCTypeRequirement(loc); if (!objcTypeRequirement) return std::nullopt; // Retrieve the _unconditionallyBridgeFromObjectiveC witness. auto witness = conformance->getWitnessDeclRef(requirement); assert(witness); // Retrieve the _ObjectiveCType witness. auto objcType = conformance->getTypeWitness(objcTypeRequirement); // Create a reference to the witness. SILDeclRef witnessConstant(witness.getDecl()); auto witnessRef = SGF.emitGlobalFunctionRef(loc, witnessConstant); // Determine the substitutions. auto witnessFnTy = witnessRef->getType().castTo(); CanType swiftValueType = conformance->getType()->getCanonicalType(); auto genericSig = witnessFnTy->getInvocationGenericSignature(); SubstitutionMap typeSubMap = witness.getSubstitutions(); // Substitute into the witness function type. witnessFnTy = witnessFnTy->substGenericArgs(SGF.SGM.M, typeSubMap, SGF.getTypeExpansionContext()); // The witness takes an _ObjectiveCType?, so convert to that type. CanType desiredValueType = OptionalType::get(objcType)->getCanonicalType(); objcValue = emitUnabstractedCast(SGF, loc, objcValue, bridgedType, desiredValueType); // Call the witness. auto metatypeParam = witnessFnTy->getParameters()[1]; assert(isa(metatypeParam.getInterfaceType()) && cast(metatypeParam.getInterfaceType()).getInstanceType() == swiftValueType); SILValue metatypeValue = SGF.B.createMetatype( loc, metatypeParam.getSILStorageType(SGF.SGM.M, witnessFnTy, SGF.getTypeExpansionContext())); auto witnessCI = SGF.getConstantInfo(SGF.getTypeExpansionContext(), witnessConstant); CanType formalResultTy = witnessCI.LoweredType.getResult(); auto subs = witness.getSubstitutions(); // Set up the generic signature, since formalResultTy is an interface type. CalleeTypeInfo calleeTypeInfo( witnessFnTy, AbstractionPattern(genericSig, formalResultTy), swiftValueType); SGFContext context; ResultPlanPtr resultPlan = ResultPlanBuilder::computeResultPlan(SGF, calleeTypeInfo, loc, context); ArgumentScope argScope(SGF, loc); RValue result = SGF.emitApply( std::move(resultPlan), std::move(argScope), loc, ManagedValue::forObjectRValueWithoutOwnership(witnessRef), subs, {objcValue, ManagedValue::forObjectRValueWithoutOwnership(metatypeValue)}, calleeTypeInfo, ApplyOptions(), context, std::nullopt); return std::move(result).getAsSingleValue(SGF, loc); } static ManagedValue emitBridgeBoolToObjCBool(SILGenFunction &SGF, SILLocation loc, ManagedValue swiftBool) { // func _convertBoolToObjCBool(Bool) -> ObjCBool SILValue boolToObjCBoolFn = SGF.emitGlobalFunctionRef(loc, SGF.SGM.getBoolToObjCBoolFn()); SILValue result = SGF.B.createApply(loc, boolToObjCBoolFn, {}, swiftBool.forward(SGF)); return SGF.emitManagedRValueWithCleanup(result); } static ManagedValue emitBridgeBoolToDarwinBoolean(SILGenFunction &SGF, SILLocation loc, ManagedValue swiftBool) { // func _convertBoolToDarwinBoolean(Bool) -> DarwinBoolean SILValue boolToDarwinBooleanFn = SGF.emitGlobalFunctionRef(loc, SGF.SGM.getBoolToDarwinBooleanFn()); SILValue result = SGF.B.createApply(loc, boolToDarwinBooleanFn, {}, swiftBool.forward(SGF)); return SGF.emitManagedRValueWithCleanup(result); } static ManagedValue emitBridgeBoolToWindowsBool(SILGenFunction &SGF, SILLocation L, ManagedValue b) { // func _convertToWindowsBool(Bool) -> WindowsBool SILValue F = SGF.emitGlobalFunctionRef(L, SGF.SGM.getBoolToWindowsBoolFn()); SILValue R = SGF.B.createApply(L, F, {}, b.forward(SGF)); return SGF.emitManagedRValueWithCleanup(R); } static ManagedValue emitBridgeForeignBoolToBool(SILGenFunction &SGF, SILLocation loc, ManagedValue foreignBool, SILDeclRef bridgingFnRef) { // func _convertObjCBoolToBool(ObjCBool) -> Bool SILValue bridgingFn = SGF.emitGlobalFunctionRef(loc, bridgingFnRef); SILValue result = SGF.B.createApply(loc, bridgingFn, {}, foreignBool.forward(SGF)); return SGF.emitManagedRValueWithCleanup(result); } static ManagedValue emitManagedParameter(SILGenFunction &SGF, SILLocation loc, SILParameterInfo param, SILValue value) { const TypeLowering &valueTL = SGF.getTypeLowering(value->getType()); switch (param.getConvention()) { case ParameterConvention::Direct_Owned: // Consume owned parameters at +1. return SGF.emitManagedRValueWithCleanup(value, valueTL); case ParameterConvention::Direct_Guaranteed: // If we have a guaranteed parameter, the object should not need to be // retained or have a cleanup. return ManagedValue::forBorrowedObjectRValue(value); case ParameterConvention::Direct_Unowned: // We need to independently retain the value. return SGF.emitManagedCopy(loc, value, valueTL); case ParameterConvention::Indirect_Inout: return ManagedValue::forLValue(value); case ParameterConvention::Indirect_In_Guaranteed: if (!value->getType().isAddress()) return ManagedValue::forBorrowedObjectRValue(value); if (valueTL.isLoadable()) { return SGF.B.createLoadBorrow( loc, ManagedValue::forBorrowedAddressRValue(value)); } else { return ManagedValue::forBorrowedAddressRValue(value); } case ParameterConvention::Indirect_In_CXX: // Don't emit a cleanup if the parameter is @in_cxx. return ManagedValue::forOwnedRValue(value, CleanupHandle::invalid()); case ParameterConvention::Indirect_In: if (valueTL.isLoadable()) { return SGF.emitLoad(loc, value, valueTL, SGFContext(), IsTake); } else { return SGF.emitManagedRValueWithCleanup(value, valueTL); } case ParameterConvention::Indirect_InoutAliasable: case ParameterConvention::Pack_Guaranteed: case ParameterConvention::Pack_Owned: case ParameterConvention::Pack_Inout: llvm_unreachable("unexpected convention"); } llvm_unreachable("bad convention"); } /// Get the type of each parameter, filtering out empty tuples. static SmallVector getParameterTypes(AnyFunctionType::CanParamArrayRef params, bool hasSelfParam=false) { SmallVector results; for (auto n : indices(params)) { bool isSelf = (hasSelfParam ? n == params.size() - 1 : false); const auto ¶m = params[n]; assert(isSelf || !param.isInOut() && "Only the 'self' parameter can be inout in a bridging thunk"); assert(!param.isVariadic()); if (param.getPlainType()->isVoid()) continue; results.push_back(param.getPlainType()); } return results; } static CanAnyFunctionType getBridgedBlockType(SILGenModule &SGM, CanAnyFunctionType blockType, SILFunctionTypeRepresentation silRep) { return SGM.Types.getBridgedFunctionType( AbstractionPattern(blockType), blockType, Bridgeability::Full, silRep); } static void buildFuncToBlockInvokeBody(SILGenFunction &SGF, SILLocation loc, CanAnyFunctionType formalFuncType, CanAnyFunctionType formalBlockType, CanSILFunctionType funcTy, CanSILFunctionType blockTy, CanSILBlockStorageType blockStorageTy, bool isUnretainedClosureSafe) { Scope scope(SGF.Cleanups, CleanupLocation(loc)); SILBasicBlock *entry = &*SGF.F.begin(); SILFunctionConventions blockConv(blockTy, SGF.SGM.M); SILFunctionConventions funcConv(funcTy, SGF.SGM.M); // Make sure we lower the component types of the formal block type. formalBlockType = getBridgedBlockType(SGF.SGM, formalBlockType, blockTy->getRepresentation()); // Set up the indirect result. SILType blockResultTy = blockTy->getAllResultsSubstType(SGF.SGM.M, SGF.getTypeExpansionContext()); SILValue indirectResult; if (blockTy->getNumResults() != 0) { auto result = blockTy->getSingleResult(); if (result.getConvention() == ResultConvention::Indirect) { indirectResult = entry->createFunctionArgument(blockResultTy.getAddressType()); } } // Get the captured native function value out of the block. auto storageAddrTy = SILType::getPrimitiveAddressType(blockStorageTy); auto storage = entry->createFunctionArgument(storageAddrTy); auto capture = SGF.B.createProjectBlockStorage(loc, storage); auto &funcTL = SGF.getTypeLowering(funcTy); auto fn = isUnretainedClosureSafe ? SGF.emitManagedLoadBorrow(loc, capture) : SGF.emitLoad(loc, capture, funcTL, SGFContext(), IsNotTake); // Collect the block arguments, which may have nonstandard conventions. assert(blockTy->getParameters().size() == funcTy->getParameters().size() && "block and function types don't match"); auto nativeParamTypes = getParameterTypes(formalFuncType.getParams()); auto bridgedParamTypes = getParameterTypes(formalBlockType.getParams()); SmallVector args; for (unsigned i : indices(funcTy->getParameters())) { auto ¶m = blockTy->getParameters()[i]; SILType paramTy = blockConv.getSILType(param, SGF.getTypeExpansionContext()); SILValue v = entry->createFunctionArgument(paramTy); ManagedValue mv; // If the parameter is a block, we need to copy it to ensure it lives on // the heap. The adapted closure value might outlive the block's original // scope. if (SGF.getSILType(param, blockTy).isBlockPointerCompatible()) { // We still need to consume the original block if it was owned. switch (param.getConvention()) { case ParameterConvention::Direct_Owned: SGF.emitManagedRValueWithCleanup(v); break; case ParameterConvention::Direct_Guaranteed: case ParameterConvention::Direct_Unowned: break; case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Pack_Guaranteed: case ParameterConvention::Pack_Owned: case ParameterConvention::Pack_Inout: llvm_unreachable("indirect params to blocks not supported"); } SILValue blockCopy = SGF.B.createCopyBlock(loc, v); mv = SGF.emitManagedRValueWithCleanup(blockCopy); } else { mv = emitManagedParameter(SGF, loc, param, v); } CanType formalBridgedType = bridgedParamTypes[i]; CanType formalNativeType = nativeParamTypes[i]; SILType loweredNativeTy = funcTy->getParameters()[i].getSILStorageType( SGF.SGM.M, funcTy, SGF.getTypeExpansionContext()); args.push_back(SGF.emitBridgedToNativeValue(loc, mv, formalBridgedType, formalNativeType, loweredNativeTy)); } auto init = indirectResult ? SGF.useBufferAsTemporary(indirectResult, SGF.getTypeLowering(indirectResult->getType())) : nullptr; CanType formalNativeResultType = formalFuncType.getResult(); CanType formalBridgedResultType = formalBlockType.getResult(); bool canEmitIntoInit = (indirectResult && indirectResult->getType() == SGF.getLoweredType(formalNativeResultType).getAddressType()); // Call the native function. SGFContext C(canEmitIntoInit ? init.get() : nullptr); ManagedValue result = SGF.emitMonomorphicApply(loc, fn, args, formalNativeResultType, formalNativeResultType, ApplyOptions(), std::nullopt, std::nullopt, C) .getAsSingleValue(SGF, loc); // Bridge the result back to ObjC. if (!canEmitIntoInit) { result = SGF.emitNativeToBridgedValue(loc, result, formalNativeResultType, formalBridgedResultType, blockResultTy, SGFContext(init.get())); } SILValue resultVal; // If we have an indirect result, make sure the result is there. if (indirectResult) { if (!result.isInContext()) { init->copyOrInitValueInto(SGF, loc, result, /*isInit*/ true); init->finishInitialization(SGF); } init->getManagedAddress().forward(SGF); resultVal = SGF.B.createTuple(loc, {}); } else { // Otherwise, return the result at +1. resultVal = result.forward(SGF); } scope.pop(); SGF.B.createReturn(loc, resultVal); } /// Bridge a native function to a block with a thunk. ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc, ManagedValue fn, CanAnyFunctionType funcType, CanAnyFunctionType blockType, CanSILFunctionType loweredBlockTy){ auto loweredFuncTy = fn.getType().castTo(); // If we store a @noescape closure in a block verify that the block has not // escaped by storing a withoutActuallyEscaping closure in the block and after // the block is ultimately destroyed checking that the closure is uniquely // referenced. bool useWithoutEscapingVerification = false; ManagedValue escaping; if (loweredFuncTy->isNoEscape()) { auto escapingTy = loweredFuncTy->getWithExtInfo( loweredFuncTy->getExtInfo().withNoEscape(false)); escaping = createWithoutActuallyEscapingClosure( loc, fn, SILType::getPrimitiveObjectType(escapingTy)); loweredFuncTy = escapingTy; auto escapingAnyTy = funcType.withExtInfo(funcType->getExtInfo().withNoEscape(false)); funcType = escapingAnyTy; fn = escaping.copy(*this, loc); useWithoutEscapingVerification = true; } else { // Since we are going to be storing this into memory, we need fn at +1. fn = fn.ensurePlusOne(*this, loc); } // All different substitutions of a function type can share a thunk. auto loweredFuncUnsubstTy = loweredFuncTy->getUnsubstitutedType(SGM.M); if (loweredFuncUnsubstTy != loweredFuncTy) { fn = B.createConvertFunction(loc, fn, SILType::getPrimitiveObjectType(loweredFuncUnsubstTy)); } // Build the invoke function signature. The block will capture the original // function value. auto fnInterfaceTy = cast( loweredFuncUnsubstTy->mapTypeOutOfContext()->getCanonicalType()); auto blockInterfaceTy = cast( loweredBlockTy->mapTypeOutOfContext()->getCanonicalType()); assert(!blockInterfaceTy->isCoroutine()); auto storageTy = SILBlockStorageType::get(loweredFuncUnsubstTy); auto storageInterfaceTy = SILBlockStorageType::get(fnInterfaceTy); // Build the invoke function type. SmallVector params; params.push_back(SILParameterInfo(storageInterfaceTy, ParameterConvention::Indirect_InoutAliasable)); std::copy(blockInterfaceTy->getParameters().begin(), blockInterfaceTy->getParameters().end(), std::back_inserter(params)); auto results = blockInterfaceTy->getResults(); auto representation = SILFunctionType::Representation::CFunctionPointer; auto *clangFnType = getASTContext().getCanonicalClangFunctionType( params, results.empty() ? std::optional() : results[0], representation); auto extInfo = SILFunctionType::ExtInfoBuilder() .withRepresentation(representation) .withClangFunctionType(clangFnType) .build(); CanGenericSignature genericSig; GenericEnvironment *genericEnv = nullptr; SubstitutionMap subs; if (funcType->hasArchetype() || blockType->hasArchetype()) { genericSig = F.getLoweredFunctionType()->getInvocationGenericSignature(); genericEnv = F.getGenericEnvironment(); subs = F.getForwardingSubstitutionMap(); // The block invoke function must be pseudogeneric. This should be OK for now // since a bridgeable function's parameters and returns should all be // trivially representable in ObjC so not need to exercise the type metadata. // // Ultimately we may need to capture generic parameters in block storage, but // that will require a redesign of the interface to support dependent-layout // context. Currently we don't capture anything directly into a block but a // Swift closure, but that's totally dumb. if (genericSig) extInfo = extInfo.intoBuilder().withIsPseudogeneric().build(); } auto invokeTy = SILFunctionType::get( genericSig, extInfo, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, blockInterfaceTy->getResults(), blockInterfaceTy->getOptionalErrorResult(), SubstitutionMap(), SubstitutionMap(), getASTContext()); // Create the invoke function. Borrow the mangling scheme from reabstraction // thunks, which is what we are in spirit. auto thunk = SGM.getOrCreateReabstractionThunk(invokeTy, loweredFuncUnsubstTy, loweredBlockTy, /*dynamicSelfType=*/CanType(), /*global actor=*/CanType()); // Build it if necessary. if (thunk->empty()) { thunk->setGenericEnvironment(genericEnv); SILGenFunction thunkSGF(SGM, *thunk, FunctionDC); auto loc = RegularLocation::getAutoGeneratedLocation(); // Not retaining the closure in the reabstraction thunk is safe if we hold // another reference for the is_escaping sentinel. buildFuncToBlockInvokeBody(thunkSGF, loc, funcType, blockType, loweredFuncUnsubstTy, loweredBlockTy, storageTy, useWithoutEscapingVerification); SGM.emitLazyConformancesForFunction(thunk); } // Form the block on the stack. auto storageAddrTy = SILType::getPrimitiveAddressType(storageTy); auto storage = emitTemporaryAllocation(loc, storageAddrTy); auto capture = B.createProjectBlockStorage(loc, storage); B.createStore(loc, fn, capture, StoreOwnershipQualifier::Init); auto invokeFn = B.createFunctionRefFor(loc, thunk); auto stackBlock = B.createInitBlockStorageHeader(loc, storage, invokeFn, SILType::getPrimitiveObjectType(loweredBlockTy), subs); // Copy the block so we have an independent heap object we can hand off. // If withoutActuallyEscaping verification is requested we emit a // copy_block_without_escaping %block withoutEscaping %closure instruction. // A mandatory SIL pass will replace this instruction by the required // verification instruction sequence. auto heapBlock = useWithoutEscapingVerification ? SILValue(B.createCopyBlockWithoutEscaping( loc, stackBlock, escaping.forward(*this))) : SILValue(B.createCopyBlock(loc, stackBlock)); return emitManagedRValueWithCleanup(heapBlock); } static ManagedValue emitNativeToCBridgedNonoptionalValue(SILGenFunction &SGF, SILLocation loc, ManagedValue v, CanType nativeType, CanType bridgedType, SILType loweredBridgedTy, SGFContext C) { assert(loweredBridgedTy.isObject()); if (v.getType().getObjectType() == loweredBridgedTy) return v; // If the input is a native type with a bridged mapping, convert it. #define BRIDGE_TYPE(BridgedModule,BridgedType, NativeModule,NativeType,Opt) \ if (nativeType == SGF.SGM.Types.get##NativeType##Type() \ && bridgedType == SGF.SGM.Types.get##BridgedType##Type()) { \ return emitBridge##NativeType##To##BridgedType(SGF, loc, v); \ } #include "swift/SIL/BridgedTypes.def" // Bridge thick to Objective-C metatypes. if (auto bridgedMetaTy = dyn_cast(bridgedType)) { if (bridgedMetaTy->hasRepresentation() && bridgedMetaTy->getRepresentation() == MetatypeRepresentation::ObjC) { SILValue native = SGF.B.emitThickToObjCMetatype(loc, v.getValue(), loweredBridgedTy); // *NOTE*: ObjCMetatypes are trivial types. They only gain ARC semantics // when they are converted to an object via objc_metatype_to_object. assert(!v.hasCleanup() && "Metatypes are trivial and thus should not have cleanups"); return ManagedValue::forObjectRValueWithoutOwnership(native); } } // Bridge native functions to blocks. auto bridgedFTy = dyn_cast(bridgedType); if (bridgedFTy && bridgedFTy->getRepresentation() == AnyFunctionType::Representation::Block) { auto nativeFTy = cast(nativeType); if (nativeFTy->getRepresentation() != AnyFunctionType::Representation::Block) return SGF.emitFuncToBlock(loc, v, nativeFTy, bridgedFTy, loweredBridgedTy.castTo()); } // If the native type conforms to _ObjectiveCBridgeable, use its // _bridgeToObjectiveC witness. if (auto conformance = SGF.SGM.getConformanceToObjectiveCBridgeable(loc, nativeType)) { if (auto result = emitBridgeNativeToObjectiveC(SGF, loc, v, nativeType, bridgedType, conformance)) return *result; assert(SGF.SGM.getASTContext().Diags.hadAnyError() && "Bridging code should have complained"); return SGF.emitUndef(bridgedType); } // Bridge Error, or types that conform to it, to NSError. if (shouldBridgeThroughError(SGF.SGM, nativeType, bridgedType)) { auto errorTy = SGF.SGM.Types.getNSErrorType(); auto error = SGF.emitNativeToBridgedError(loc, v, nativeType, errorTy); if (errorTy != bridgedType) { error = emitUnabstractedCast(SGF, loc, error, errorTy, bridgedType); } return error; } // Fall back to dynamic Any-to-id bridging. // The destination type should be AnyObject in this case. assert(bridgedType->isEqual(SGF.getASTContext().getAnyObjectType())); // Blocks bridge to id with a cast under ObjCInterop. if (auto nativeFnType = dyn_cast(nativeType)) { if (nativeFnType->getRepresentation() == FunctionTypeRepresentation::Block && SGF.getASTContext().LangOpts.EnableObjCInterop) { return SGF.B.createBlockToAnyObject(loc, v, loweredBridgedTy); } } // If the input argument is known to be an existential, save the runtime // some work by opening it. if (nativeType->isExistentialType()) { auto openedType = ExistentialArchetypeType::get(nativeType); FormalEvaluationScope scope(SGF); v = SGF.emitOpenExistential( loc, v, SGF.getLoweredType(openedType), AccessKind::Read); v = v.ensurePlusOne(SGF, loc); nativeType = openedType; } // Call into the stdlib intrinsic. if (auto bridgeAnything = SGF.getASTContext().getBridgeAnythingToObjectiveC()) { auto genericSig = bridgeAnything->getGenericSignature(); auto subMap = SubstitutionMap::get( genericSig, [&](SubstitutableType *t) -> Type { return nativeType; }, LookUpConformanceInModule()); // The intrinsic takes a T; reabstract to the generic abstraction // pattern. v = SGF.emitSubstToOrigValue(loc, v, AbstractionPattern::getOpaque(), nativeType); // Put the value into memory if necessary. assert(v.getOwnershipKind() == OwnershipKind::None || v.hasCleanup()); SILModuleConventions silConv(SGF.SGM.M); // bridgeAnything always takes an indirect argument as @in. // Since we don't have the SIL type here, check the current SIL stage/mode // to determine the convention. if (v.getType().isObject() && silConv.useLoweredAddresses()) { auto tmp = SGF.emitTemporaryAllocation(loc, v.getType()); v.forwardInto(SGF, loc, tmp); v = SGF.emitManagedBufferWithCleanup(tmp); } return SGF.emitApplyOfLibraryIntrinsic(loc, bridgeAnything, subMap, v, C) .getAsSingleValue(SGF, loc); } // Shouldn't get here unless the standard library is busted. return SGF.emitUndef(loweredBridgedTy); } static ManagedValue emitNativeToCBridgedValue(SILGenFunction &SGF, SILLocation loc, ManagedValue v, CanType nativeType, CanType bridgedType, SILType loweredBridgedTy, SGFContext C = SGFContext()) { SILType loweredNativeTy = v.getType(); if (loweredNativeTy.getObjectType() == loweredBridgedTy.getObjectType()) return v; CanType bridgedObjectType = bridgedType.getOptionalObjectType(); CanType nativeObjectType = nativeType.getOptionalObjectType(); // Check for optional-to-optional conversions. if (bridgedObjectType && nativeObjectType) { auto helper = [&](SILGenFunction &SGF, SILLocation loc, ManagedValue v, SILType loweredBridgedObjectTy, SGFContext C) { return emitNativeToCBridgedValue(SGF, loc, v, nativeObjectType, bridgedObjectType, loweredBridgedObjectTy, C); }; return SGF.emitOptionalToOptional(loc, v, loweredBridgedTy, helper, C); } // Check if we need to wrap the bridged result in an optional. if (bridgedObjectType) { auto helper = [&](SILGenFunction &SGF, SILLocation loc, SGFContext C) { auto loweredBridgedObjectTy = loweredBridgedTy.getOptionalObjectType(); return emitNativeToCBridgedValue(SGF, loc, v, nativeType, bridgedObjectType, loweredBridgedObjectTy, C); }; return SGF.emitOptionalSome(loc, loweredBridgedTy, helper, C); } return emitNativeToCBridgedNonoptionalValue(SGF, loc, v, nativeType, bridgedType, loweredBridgedTy, C); } ManagedValue SILGenFunction::emitNativeToBridgedValue(SILLocation loc, ManagedValue v, CanType nativeTy, CanType bridgedTy, SILType loweredBridgedTy, SGFContext C) { loweredBridgedTy = loweredBridgedTy.getObjectType(); return emitNativeToCBridgedValue(*this, loc, v, nativeTy, bridgedTy, loweredBridgedTy, C); } static void buildBlockToFuncThunkBody(SILGenFunction &SGF, SILLocation loc, CanAnyFunctionType formalBlockTy, CanAnyFunctionType formalFuncTy, CanSILFunctionType blockTy, CanSILFunctionType funcTy) { // Collect the native arguments, which should all be +1. Scope scope(SGF.Cleanups, CleanupLocation(loc)); // Make sure we lower the component types of the formal block type. formalBlockTy = getBridgedBlockType(SGF.SGM, formalBlockTy, blockTy->getRepresentation()); assert(blockTy->getNumParameters() == funcTy->getNumParameters() && "block and function types don't match"); SmallVector args; SILBasicBlock *entry = &*SGF.F.begin(); SILFunctionConventions fnConv(funcTy, SGF.SGM.M); // Set up the indirect result slot. SILValue indirectResult; if (funcTy->getNumResults() != 0) { auto result = funcTy->getSingleResult(); if (result.getConvention() == ResultConvention::Indirect) { SILType resultTy = fnConv.getSILType(result, SGF.getTypeExpansionContext()); indirectResult = entry->createFunctionArgument(resultTy); } } auto formalBlockParams = getParameterTypes(formalBlockTy.getParams()); auto formalFuncParams = getParameterTypes(formalFuncTy.getParams()); assert(formalBlockParams.size() == blockTy->getNumParameters()); assert(formalFuncParams.size() == funcTy->getNumParameters()); // Create the arguments for the call. for (unsigned i : indices(funcTy->getParameters())) { auto ¶m = funcTy->getParameters()[i]; CanType formalBlockParamTy = formalBlockParams[i]; CanType formalFuncParamTy = formalFuncParams[i]; auto paramTy = fnConv.getSILType(param, SGF.getTypeExpansionContext()); SILValue v = entry->createFunctionArgument(paramTy); // First get the managed parameter for this function. auto mv = emitManagedParameter(SGF, loc, param, v); SILType loweredBlockArgTy = blockTy->getParameters()[i].getSILStorageType( SGF.SGM.M, blockTy, SGF.getTypeExpansionContext()); // Then bridge the native value to its bridged variant. mv = SGF.emitNativeToBridgedValue(loc, mv, formalFuncParamTy, formalBlockParamTy, loweredBlockArgTy); // Finally change ownership if we need to. We do not need to care about the // case of a +1 parameter being passed to a +0 function since +1 parameters // can be "instantaneously" borrowed at the call site. if (blockTy->getParameters()[i].isConsumedInCaller()) { mv = mv.ensurePlusOne(SGF, loc); } args.push_back(mv); } // Add the block argument. SILValue blockV = entry->createFunctionArgument(SILType::getPrimitiveObjectType(blockTy)); ManagedValue block = ManagedValue::forBorrowedObjectRValue(blockV); CanType formalResultType = formalFuncTy.getResult(); auto init = indirectResult ? SGF.useBufferAsTemporary(indirectResult, SGF.getTypeLowering(indirectResult->getType())) : nullptr; // Call the block. ManagedValue result = SGF.emitMonomorphicApply( loc, block, args, formalBlockTy.getResult(), formalResultType, ApplyOptions(), /*override CC*/ SILFunctionTypeRepresentation::Block, /*foreign error*/ std::nullopt, SGFContext(init.get())) .getAsSingleValue(SGF, loc); SILValue r; // If we have an indirect result, make sure the result is there. if (indirectResult) { if (!result.isInContext()) { init->copyOrInitValueInto(SGF, loc, result, /*isInit*/ true); init->finishInitialization(SGF); } init->getManagedAddress().forward(SGF); r = SGF.B.createTuple( loc, fnConv.getSILResultType(SGF.getTypeExpansionContext()), ArrayRef()); // Otherwise, return the result at +1. } else { r = result.forward(SGF); } scope.pop(); SGF.B.createReturn(loc, r); // Finally, verify the thunk for SIL invariants. SGF.F.verifyIncompleteOSSA(); } /// Bridge a native function to a block with a thunk. ManagedValue SILGenFunction::emitBlockToFunc(SILLocation loc, ManagedValue block, CanAnyFunctionType blockType, CanAnyFunctionType funcType, CanSILFunctionType loweredFuncTy) { // Declare the thunk. auto loweredBlockTy = block.getType().castTo(); SubstitutionMap contextSubs, interfaceSubs; GenericEnvironment *genericEnv = nullptr; // These two are not used here -- but really, bridging thunks // should be emitted using the formal AST type, not the lowered // type CanType inputSubstType, outputSubstType; auto loweredFuncTyWithoutNoEscape = adjustFunctionType( loweredFuncTy, loweredFuncTy->getExtInfo().withNoEscape(false), loweredFuncTy->getWitnessMethodConformanceOrInvalid()); auto loweredFuncUnsubstTy = loweredFuncTyWithoutNoEscape->getUnsubstitutedType(SGM.M); CanType dynamicSelfType; auto thunkTy = buildThunkType(loweredBlockTy, loweredFuncUnsubstTy, inputSubstType, outputSubstType, genericEnv, interfaceSubs, dynamicSelfType); assert(!dynamicSelfType && "Not implemented"); auto thunk = SGM.getOrCreateReabstractionThunk(thunkTy, loweredBlockTy, loweredFuncUnsubstTy, /*dynamicSelfType=*/CanType(), /*global actor=*/CanType()); // Build it if necessary. if (thunk->empty()) { SILGenFunction thunkSGF(SGM, *thunk, FunctionDC); thunk->setGenericEnvironment(genericEnv); auto loc = RegularLocation::getAutoGeneratedLocation(); buildBlockToFuncThunkBody(thunkSGF, loc, blockType, funcType, loweredBlockTy, loweredFuncUnsubstTy); SGM.emitLazyConformancesForFunction(thunk); } CanSILFunctionType substFnTy = thunkTy; if (thunkTy->getInvocationGenericSignature()) { substFnTy = thunkTy->substGenericArgs(F.getModule(), interfaceSubs, getTypeExpansionContext()); } // Create it in the current function. auto thunkValue = B.createFunctionRefFor(loc, thunk); ManagedValue thunkedFn = B.createPartialApply( loc, thunkValue, interfaceSubs, block, loweredFuncTy->getCalleeConvention()); if (loweredFuncUnsubstTy != loweredFuncTyWithoutNoEscape) { thunkedFn = B.createConvertFunction(loc, thunkedFn, SILType::getPrimitiveObjectType(loweredFuncTyWithoutNoEscape)); } if (!loweredFuncTy->isNoEscape()) { return thunkedFn; } // Handle the escaping to noescape conversion. assert(loweredFuncTy->isNoEscape()); return B.createConvertEscapeToNoEscape( loc, thunkedFn, SILType::getPrimitiveObjectType(loweredFuncTy)); } static ManagedValue emitCBridgedToNativeValue( SILGenFunction &SGF, SILLocation loc, ManagedValue v, CanType bridgedType, SILType loweredBridgedTy, CanType nativeType, SILType loweredNativeTy, int bridgedOptionalsToUnwrap, bool isCallResult, SGFContext C) { assert(loweredNativeTy.isObject()); if (loweredNativeTy == loweredBridgedTy.getObjectType()) return v; if (auto nativeObjectType = nativeType.getOptionalObjectType()) { auto bridgedObjectType = bridgedType.getOptionalObjectType(); // Optional injection. if (!bridgedObjectType) { auto helper = [&](SILGenFunction &SGF, SILLocation loc, SGFContext C) { auto loweredNativeObjectTy = loweredNativeTy.getOptionalObjectType(); return emitCBridgedToNativeValue( SGF, loc, v, bridgedType, loweredBridgedTy, nativeObjectType, loweredNativeObjectTy, bridgedOptionalsToUnwrap, isCallResult, C); }; return SGF.emitOptionalSome(loc, loweredNativeTy, helper, C); } // Optional-to-optional. auto helper = [=](SILGenFunction &SGF, SILLocation loc, ManagedValue v, SILType loweredNativeObjectTy, SGFContext C) { return emitCBridgedToNativeValue( SGF, loc, v, bridgedObjectType, loweredBridgedTy.getOptionalObjectType(), nativeObjectType, loweredNativeObjectTy, bridgedOptionalsToUnwrap, isCallResult, C); }; return SGF.emitOptionalToOptional(loc, v, loweredNativeTy, helper, C); } if (auto bridgedObjectType = bridgedType.getOptionalObjectType()) { return emitCBridgedToNativeValue( SGF, loc, v, bridgedObjectType, loweredBridgedTy.getOptionalObjectType(), nativeType, loweredNativeTy, bridgedOptionalsToUnwrap + 1, isCallResult, C); } auto unwrapBridgedOptionals = [&](ManagedValue v) { for (int i = 0; i < bridgedOptionalsToUnwrap; ++i) { v = SGF.emitPreconditionOptionalHasValue(loc, v, /*implicit*/ true); }; return v; }; // Bridge ObjCBool, DarwinBoolean, WindowsBool to Bool when requested. if (nativeType == SGF.SGM.Types.getBoolType()) { if (bridgedType == SGF.SGM.Types.getObjCBoolType()) { return emitBridgeForeignBoolToBool(SGF, loc, unwrapBridgedOptionals(v), SGF.SGM.getObjCBoolToBoolFn()); } if (bridgedType == SGF.SGM.Types.getDarwinBooleanType()) { return emitBridgeForeignBoolToBool(SGF, loc, unwrapBridgedOptionals(v), SGF.SGM.getDarwinBooleanToBoolFn()); } if (bridgedType == SGF.SGM.Types.getWindowsBoolType()) { return emitBridgeForeignBoolToBool(SGF, loc, unwrapBridgedOptionals(v), SGF.SGM.getWindowsBoolToBoolFn()); } } // Bridge Objective-C to thick metatypes. if (isa(nativeType)) { auto bridgedMetaTy = cast(bridgedType); if (bridgedMetaTy->hasRepresentation() && bridgedMetaTy->getRepresentation() == MetatypeRepresentation::ObjC) { SILValue native = SGF.B.emitObjCToThickMetatype( loc, unwrapBridgedOptionals(v).getValue(), loweredNativeTy); // *NOTE*: ObjCMetatypes are trivial types. They only gain ARC semantics // when they are converted to an object via objc_metatype_to_object. assert(!v.hasCleanup() && "Metatypes are trivial and should not have " "cleanups"); return ManagedValue::forUnmanagedOwnedValue(native); } } // Bridge blocks back into native function types. if (auto nativeFTy = dyn_cast(nativeType)) { auto bridgedFTy = cast(bridgedType); if (bridgedFTy->getRepresentation() == AnyFunctionType::Representation::Block && nativeFTy->getRepresentation() != AnyFunctionType::Representation::Block) { return SGF.emitBlockToFunc(loc, unwrapBridgedOptionals(v), bridgedFTy, nativeFTy, loweredNativeTy.castTo()); } } // Bridge via _ObjectiveCBridgeable. if (auto conformance = SGF.SGM.getConformanceToObjectiveCBridgeable(loc, nativeType)) { if (auto result = emitBridgeObjectiveCToNative(SGF, loc, v, bridgedType, conformance)) { --bridgedOptionalsToUnwrap; return unwrapBridgedOptionals(*result); } assert(SGF.SGM.getASTContext().Diags.hadAnyError() && "Bridging code should have complained"); return SGF.emitUndef(nativeType); } // id-to-Any bridging. if (nativeType->isMarkerExistential()) { // If this is not a call result, use the normal erasure logic. if (!isCallResult) { return SGF.emitTransformedValue(loc, unwrapBridgedOptionals(v), bridgedType, nativeType, C); } // Otherwise, we use more complicated logic that handles results that // were unexpectedly null. assert(bridgedType.isAnyClassReferenceType()); // Convert to AnyObject if necessary. CanType anyObjectTy = SGF.getASTContext().getAnyObjectType()->getCanonicalType(); if (bridgedType != anyObjectTy) { v = SGF.emitTransformedValue(loc, unwrapBridgedOptionals(v), bridgedType, anyObjectTy); } // TODO: Ever need to handle +0 values here? assert(v.hasCleanup()); // Use a runtime call to bridge the AnyObject to Any. We do this instead of // a simple AnyObject-to-Any upcast because the ObjC API may have returned // a null object in spite of its annotation. // Bitcast to Optional. This provides a barrier to the optimizer to prevent // it from attempting to eliminate null checks. auto optionalBridgedTy = SILType::getOptionalType(loweredBridgedTy); auto optionalMV = SGF.B.createUncheckedBitCast( loc, unwrapBridgedOptionals(v), optionalBridgedTy); v = SGF.emitApplyOfLibraryIntrinsic(loc, SGF.getASTContext().getBridgeAnyObjectToAny(), SubstitutionMap(), optionalMV, C) .getAsSingleValue(SGF, loc); // Convert to the marker existential if necessary. if (!v.isInContext()) { auto anyType = SGF.getASTContext().getAnyExistentialType(); v = SGF.emitTransformedValue(loc, v, anyType, nativeType); } return v; } // Bridge NSError to Error. if (bridgedType == SGF.SGM.Types.getNSErrorType()) return SGF.emitBridgedToNativeError(loc, unwrapBridgedOptionals(v)); return unwrapBridgedOptionals(v); } ManagedValue SILGenFunction::emitBridgedToNativeValue(SILLocation loc, ManagedValue v, CanType bridgedType, CanType nativeType, SILType loweredNativeTy, SGFContext C, bool isCallResult) { loweredNativeTy = loweredNativeTy.getObjectType(); SILType loweredBridgedTy = v.getType(); return emitCBridgedToNativeValue( *this, loc, v, bridgedType, loweredBridgedTy, nativeType, loweredNativeTy, /*bridgedOptionalsToUnwrap=*/0, isCallResult, C); } /// Bridge a possibly-optional foreign error type to Error. ManagedValue SILGenFunction::emitBridgedToNativeError(SILLocation loc, ManagedValue bridgedError) { // If the incoming error is non-optional, just do an existential erasure. auto bridgedErrorTy = bridgedError.getType().getASTType(); if (!bridgedErrorTy.getOptionalObjectType()) { auto nativeErrorTy = SILType::getExceptionType(getASTContext()); auto conformance = SGM.getNSErrorConformanceToError(); if (!conformance) return emitUndef(nativeErrorTy); ProtocolConformanceRef conformanceArray[] = { ProtocolConformanceRef(conformance) }; auto conformances = getASTContext().AllocateCopy(conformanceArray); return B.createInitExistentialRef(loc, nativeErrorTy, bridgedErrorTy, bridgedError, conformances); } // Otherwise, we need to call a runtime function to potential substitute // a standard error for a nil NSError. auto bridgeFn = emitGlobalFunctionRef(loc, SGM.getNSErrorToErrorFn()); auto bridgeFnType = bridgeFn->getType().castTo(); assert(bridgeFnType->getNumResults() == 1); assert(bridgeFnType->getResults()[0].getConvention() == ResultConvention::Owned); assert(bridgeFnType->getParameters()[0].getConvention() == ParameterConvention::Direct_Guaranteed); (void) bridgeFnType; SILValue arg = bridgedError.getValue(); SILValue nativeError = B.createApply(loc, bridgeFn, {}, arg); return emitManagedRValueWithCleanup(nativeError); } /// Bridge Error to a foreign error type. ManagedValue SILGenFunction::emitNativeToBridgedError(SILLocation loc, ManagedValue nativeError, CanType nativeType, CanType bridgedErrorType){ // Handle injections into optional. if (auto bridgedObjectType = bridgedErrorType.getOptionalObjectType()) { auto loweredBridgedOptionalTy = SILType::getPrimitiveObjectType(bridgedErrorType); return emitOptionalSome( loc, loweredBridgedOptionalTy, [&](SILGenFunction &SGF, SILLocation loc, SGFContext C) { SILType loweredBridgedObjectTy = loweredBridgedOptionalTy.getOptionalObjectType(); return emitNativeToBridgedValue(loc, nativeError, nativeType, bridgedObjectType, loweredBridgedObjectTy); }); } assert(bridgedErrorType == SGM.Types.getNSErrorType() && "only handling NSError for now"); // The native error might just be a value of a type that conforms to // Error. This should be a subtyping or erasure conversion of the sort // that we can do automatically. // FIXME: maybe we should use a different entrypoint for this case, to // avoid the code size and performance overhead of forming the box? nativeError = emitUnabstractedCast(*this, loc, nativeError, nativeType, getASTContext().getErrorExistentialType()); auto bridgeFn = emitGlobalFunctionRef(loc, SGM.getErrorToNSErrorFn()); auto bridgeFnType = bridgeFn->getType().castTo(); assert(bridgeFnType->getNumResults() == 1); assert(bridgeFnType->getResults()[0].getConvention() == ResultConvention::Owned); assert(bridgeFnType->getParameters()[0].getConvention() == ParameterConvention::Direct_Guaranteed); (void) bridgeFnType; SILValue arg = nativeError.getValue(); SILValue bridgedError = B.createApply(loc, bridgeFn, {}, arg); return emitManagedRValueWithCleanup(bridgedError); } //===----------------------------------------------------------------------===// // ObjC method thunks //===----------------------------------------------------------------------===// static SILValue emitBridgeReturnValue(SILGenFunction &SGF, SILLocation loc, SILValue result, CanType formalNativeTy, CanType formalBridgedTy, SILType loweredBridgedTy) { Scope scope(SGF.Cleanups, CleanupLocation(loc)); ManagedValue native = SGF.emitManagedRValueWithCleanup(result); ManagedValue bridged = SGF.emitNativeToBridgedValue(loc, native, formalNativeTy, formalBridgedTy, loweredBridgedTy); return bridged.forward(SGF); } /// Take an argument at +0 and bring it to +1. static SILValue emitObjCUnconsumedArgument(SILGenFunction &SGF, SILLocation loc, SILValue arg) { auto &lowering = SGF.getTypeLowering(arg->getType()); // If arg is non-trivial and has an address type, make a +1 copy and operate // on that. if (!lowering.isTrivial() && arg->getType().isAddress() && SGF.useLoweredAddresses()) { auto tmp = SGF.emitTemporaryAllocation(loc, arg->getType().getObjectType()); SGF.B.createCopyAddr(loc, arg, tmp, IsNotTake, IsInitialization); return tmp; } return lowering.emitCopyValue(SGF.B, loc, arg); } static CanAnyFunctionType substGenericArgs(CanAnyFunctionType fnType, SubstitutionMap subs) { if (auto genericFnType = dyn_cast(fnType)) { return cast(genericFnType->substGenericArgs(subs) ->getCanonicalType()); } return fnType; } /// Bridge argument types and adjust retain count conventions for an ObjC thunk. static SILFunctionType * emitObjCThunkArguments(SILGenFunction &SGF, SILLocation loc, SILDeclRef thunk, SmallVectorImpl &args, SILValue &foreignErrorSlot, SILValue &foreignAsyncSlot, std::optional foreignError, std::optional foreignAsync, CanType &nativeFormalResultTy, CanType &bridgedFormalResultTy) { SILDeclRef native = thunk.asForeign(false); auto subs = SGF.F.getForwardingSubstitutionMap(); auto objcInfo = SGF.SGM.Types.getConstantInfo(SGF.getTypeExpansionContext(), thunk); auto objcFnTy = objcInfo.SILFnType->substGenericArgs( SGF.SGM.M, subs, SGF.getTypeExpansionContext()); auto objcFormalFnTy = substGenericArgs(objcInfo.LoweredType, subs); auto swiftInfo = SGF.SGM.Types.getConstantInfo(SGF.getTypeExpansionContext(), native); auto swiftFnTy = swiftInfo.SILFnType->substGenericArgs( SGF.SGM.M, subs, SGF.getTypeExpansionContext()); auto swiftFormalFnTy = substGenericArgs(swiftInfo.LoweredType, subs); SILFunctionConventions swiftConv(swiftFnTy, SGF.SGM.M); SmallVector bridgedArgs; bridgedArgs.reserve(objcFnTy->getParameters().size()); auto bridgedFormalTypes = getParameterTypes(objcFormalFnTy.getParams()); bridgedFormalResultTy = objcFormalFnTy.getResult(); auto nativeFormalTypes = getParameterTypes(swiftFormalFnTy.getParams()); nativeFormalResultTy = swiftFormalFnTy.getResult(); // Emit the other arguments, taking ownership of arguments if necessary. auto inputs = objcFnTy->getParameters(); auto nativeInputs = swiftFnTy->getParameters(); auto fnConv = SGF.silConv.getFunctionConventions(swiftFnTy); bool nativeInputsHasImplicitIsolatedParam = false; if (auto param = swiftFnTy->maybeGetIsolatedParameter()) nativeInputsHasImplicitIsolatedParam = param->hasOption(SILParameterInfo::ImplicitLeading); assert(nativeInputs.size() - unsigned(nativeInputsHasImplicitIsolatedParam) == bridgedFormalTypes.size()); assert(nativeInputs.size() - unsigned(nativeInputsHasImplicitIsolatedParam) == nativeFormalTypes.size()); assert(inputs.size() == nativeInputs.size() + unsigned(foreignError.has_value()) + unsigned(foreignAsync.has_value()) - unsigned(nativeInputsHasImplicitIsolatedParam)); for (unsigned i = 0, e = inputs.size(); i < e; ++i) { SILType argTy = SGF.getSILType(inputs[i], objcFnTy); SILValue arg = SGF.F.begin()->createFunctionArgument(argTy); // If this parameter is the foreign error or completion slot, pull it out. // It does not correspond to a native argument. if (foreignError && i == foreignError->getErrorParameterIndex()) { foreignErrorSlot = arg; continue; } if (foreignAsync && i == foreignAsync->completionHandlerParamIndex()) { // Copy the block. foreignAsyncSlot = SGF.B.createCopyBlock(loc, arg); // If the argument is consumed, we're still responsible for releasing the // original. if (inputs[i].isConsumedInCallee()) SGF.emitManagedRValueWithCleanup(arg); continue; } // If the argument is a block, copy it. if (argTy.isBlockPointerCompatible()) { auto copy = SGF.B.createCopyBlock(loc, arg); // If the argument is consumed, we're still responsible for releasing the // original. if (inputs[i].isConsumedInCallee()) SGF.emitManagedRValueWithCleanup(arg); arg = copy; } // Convert the argument to +1 if necessary. else if (!inputs[i].isConsumedInCallee()) { arg = emitObjCUnconsumedArgument(SGF, loc, arg); } auto managedArg = SGF.emitManagedRValueWithCleanup(arg); bridgedArgs.push_back(managedArg); } assert(bridgedArgs.size() + unsigned(foreignError.has_value()) + unsigned(foreignAsync.has_value()) == objcFnTy->getParameters().size() && "objc inputs don't match number of arguments?!"); assert(bridgedArgs.size() == swiftFnTy->getParameters().size() - bool(nativeInputsHasImplicitIsolatedParam) && "swift inputs don't match number of arguments?!"); assert((foreignErrorSlot || !foreignError) && "didn't find foreign error slot"); // Bridge the input types. assert(bridgedArgs.size() == nativeInputs.size() - bool(nativeInputsHasImplicitIsolatedParam)); for (unsigned i = 0, size = bridgedArgs.size(); i < size; ++i) { // Consider the bridged values to be "call results" since they're coming // from potentially nil-unsound ObjC callers. ManagedValue native = SGF.emitBridgedToNativeValue( loc, bridgedArgs[i], bridgedFormalTypes[i], nativeFormalTypes[i], swiftFnTy->getParameters()[i].getSILStorageType( SGF.SGM.M, swiftFnTy, SGF.getTypeExpansionContext()), SGFContext(), /*isCallResult*/ true); SILValue argValue; // This can happen if the value is resilient in the calling convention // but not resilient locally. if (fnConv.isSILIndirect(nativeInputs[i]) && !native.getType().isAddress()) { auto buf = SGF.emitTemporaryAllocation(loc, native.getType()); native.forwardInto(SGF, loc, buf); native = SGF.emitManagedBufferWithCleanup(buf); } else if (!fnConv.isSILIndirect(nativeInputs[i]) && native.getType().isAddress() && SGF.useLoweredAddresses()) { // Load the value if the argument has an address type and the native // function expects the argument to be passed directly. native = SGF.emitManagedLoadCopy(loc, native.getValue()); } if (nativeInputs[i].isConsumedInCaller()) { argValue = native.forward(SGF); } else if (nativeInputs[i].isGuaranteedInCaller()) { argValue = native.borrow(SGF, loc).getUnmanagedValue(); } else { argValue = native.getValue(); } args.push_back(argValue); } return objcFnTy; } SILFunction *SILGenFunction::emitNativeAsyncToForeignThunk(SILDeclRef thunk) { assert(thunk.isForeign); assert(thunk.hasAsync()); SILDeclRef native = thunk.asForeign(false); // Use the same generic environment as the native entry point. F.setGenericEnvironment(SGM.Types.getConstantGenericEnvironment(native)); // Collect the arguments and make copies of them we can absorb into the // closure. auto subs = F.getForwardingSubstitutionMap(); SmallVector closureArgs; auto objcInfo = SGM.Types.getConstantInfo(getTypeExpansionContext(), thunk); auto objcFnTy = objcInfo.SILFnType->substGenericArgs( SGM.M, subs, getTypeExpansionContext()); auto loc = thunk.getAsRegularLocation(); loc.markAutoGenerated(); Scope scope(*this, loc); for (auto input : objcFnTy->getParameters()) { SILType argTy = getSILType(input, objcFnTy); SILValue arg = F.begin()->createFunctionArgument(argTy); // Copy block arguments. if (argTy.isBlockPointerCompatible()) { auto argCopy = B.createCopyBlock(loc, arg); // If the argument is consumed, we're still responsible for releasing the // original. if (input.isConsumedInCallee()) emitManagedRValueWithCleanup(arg); arg = argCopy; } else if (!input.isConsumedInCallee()) { arg = emitObjCUnconsumedArgument(*this, loc, arg); } auto managedArg = emitManagedRValueWithCleanup(arg); closureArgs.push_back(managedArg.forward(*this)); } // Create the closure implementation function. It has the same signature, // but is swiftcc and async. auto closureExtInfo = objcFnTy->getExtInfo().intoBuilder() .withRepresentation(SILFunctionTypeRepresentation::Thin) .withAsync() .withSendable() .build(); auto closureTy = objcInfo.SILFnType->getWithExtInfo(closureExtInfo); SmallString<64> closureName(F.getName().begin(), F.getName().end()); // Trim off the thunk suffix and mangle this like a closure nested inside the // thunk (which it sorta is) char thunkSuffix[2] = {closureName.pop_back_val(), closureName.pop_back_val()}; assert(thunkSuffix[1] == 'T' && thunkSuffix[0] == 'o' && "not an objc thunk?"); closureName += "yyYacfU_"; // closure with type () async -> () closureName.push_back(thunkSuffix[1]); closureName.push_back(thunkSuffix[0]); SILGenFunctionBuilder fb(SGM); auto closure = fb.getOrCreateSharedFunction( loc, closureName, closureTy, IsBare, IsNotTransparent, F.getSerializedKind(), ProfileCounter(), IsThunk, IsNotDynamic, IsNotDistributed, IsNotRuntimeAccessible); auto closureRef = B.createFunctionRef(loc, closure); auto closureVal = B.createPartialApply(loc, closureRef, subs, closureArgs, ParameterConvention::Direct_Guaranteed); auto closureMV = emitManagedRValueWithCleanup(closureVal); // Pass the closure on to the intrinsic to spawn it on a task. auto spawnTask = SGM.getRunTaskForBridgedAsyncMethod(); emitApplyOfLibraryIntrinsic(loc, spawnTask, {}, closureMV, SGFContext()); scope.pop(); // Return void to the immediate caller. B.createReturn(loc, SILUndef::get(&F, SGM.Types.getEmptyTupleType())); return closure; } void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) { assert(thunk.isForeign); SILDeclRef native = thunk.asForeign(false); if (thunk.hasDecl()) { if (thunk.getDecl()->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); } // If we're calling a native non-designated class initializer, we have to // discard the `self` object we were given, since // Swift convenience initializers only have allocating entry points that // create whole new objects. bool isInitializingToAllocatingInitThunk = false; if (native.kind == SILDeclRef::Kind::Initializer) { if (auto ctor = dyn_cast(native.getDecl())) { if (!ctor->isDesignatedInit() && !ctor->isObjC()) { isInitializingToAllocatingInitThunk = true; native = SILDeclRef(ctor, SILDeclRef::Kind::Allocator); } } } // Use the same generic environment as the native entry point. // We need to set this before we can call things like // F.getForwardingSubstitutionMap(). F.setGenericEnvironment(SGM.Types.getConstantGenericEnvironment(native)); auto nativeInfo = getConstantInfo(getTypeExpansionContext(), native); auto subs = F.getForwardingSubstitutionMap(); auto substTy = nativeInfo.SILFnType->substGenericArgs( SGM.M, subs, getTypeExpansionContext()); SILFunctionConventions substConv(substTy, SGM.M); auto loc = thunk.getAsRegularLocation(); loc.markAutoGenerated(); Scope scope(Cleanups, CleanupLocation(loc)); std::optional isolation; if (F.isAsync()) { if (thunk.hasDecl()) isolation = getActorIsolation(thunk.getDecl()); } else if (getASTContext() .LangOpts.isDynamicActorIsolationCheckingEnabled()) { if (thunk.hasDecl()) { isolation = getActorIsolation(thunk.getDecl()); } else if (auto globalActor = nativeInfo.FormalType->getGlobalActor()) { isolation = ActorIsolation::forGlobalActor(globalActor); } } // A hop/check is only needed in the thunk if it is global-actor isolated. // Native, instance-isolated async methods will hop in the prologue. if (isolation && isolation->isGlobalActor()) { if (F.isAsync()) { // Hop to the actor for the method's actor constraint. // Note that, since an async native-to-foreign thunk only ever runs in a // task purpose-built for running the Swift async code triggering the // completion handler, there is no need for us to hop back to the existing // executor, since the task will end after we invoke the completion handler. emitPrologGlobalActorHop(loc, isolation->getGlobalActor()); } else { emitPreconditionCheckExpectedExecutor(loc, *isolation, std::nullopt); } } std::optional foreignError; std::optional foreignAsync; // Find the foreign error and async conventions if we have one. if (thunk.hasDecl()) { if (auto func = dyn_cast(thunk.getDecl())) { foreignError = func->getForeignErrorConvention(); foreignAsync = func->getForeignAsyncConvention(); } } // If we are bridging a Swift method with Any return value(s), create a // stack allocation to hold the result(s), since Any is address-only. SmallVector args; SILFunctionConventions funcConv = F.getConventions(); bool needsBridging = true; if (substConv.hasIndirectSILResults()) { for (auto result : substConv.getResults()) { if (!substConv.isSILIndirect(result)) { continue; } if (!foreignAsync && funcConv.hasIndirectSILResults()) { auto resultTy = funcConv.getSingleSILResultType(getTypeExpansionContext()); assert(substConv.getSingleSILResultType(getTypeExpansionContext()) == resultTy); args.push_back(F.begin()->createFunctionArgument(resultTy)); needsBridging = false; break; } args.push_back(emitTemporaryAllocation( loc, substConv.getSILType(result, getTypeExpansionContext()))); } } // Now, enter a cleanup used for bridging the arguments. Note that if we // have an indirect result, it must be outside of this scope, otherwise // we will deallocate it too early. Scope argScope(Cleanups, CleanupLocation(loc)); // See if our native function has an implicitly isolated parameter. In such a // case, we need to pass in the isolation. if (auto isolatedParameter = substTy->maybeGetIsolatedParameter(); isolatedParameter && isolatedParameter->hasOption(SILParameterInfo::ImplicitLeading)) { assert(F.isAsync() && "Can only be async"); assert(isolation && "No isolation?!"); auto value = [&]() -> SILValue { switch (isolation->getKind()) { case ActorIsolation::Unspecified: case ActorIsolation::Nonisolated: case ActorIsolation::NonisolatedUnsafe: case ActorIsolation::CallerIsolationInheriting: return emitNonIsolatedIsolation(loc).getValue(); case ActorIsolation::ActorInstance: llvm::report_fatal_error("Should never see this"); case ActorIsolation::GlobalActor: return emitLoadGlobalActorExecutor(isolation->getGlobalActor()); case ActorIsolation::Erased: llvm::report_fatal_error("Should never see this"); } }(); args.push_back(B.convertToImplicitActor(loc, value)); } // Bridge the arguments. SILValue foreignErrorSlot; SILValue foreignAsyncSlot; CanType nativeFormalResultType, bridgedFormalResultType; auto objcFnTy = emitObjCThunkArguments(*this, loc, thunk, args, foreignErrorSlot, foreignAsyncSlot, foreignError, foreignAsync, nativeFormalResultType, bridgedFormalResultType); // Throw away the partially-initialized `self` value we were given if we're // bridging from an initializing to allocating entry point. if (isInitializingToAllocatingInitThunk) { auto oldSelf = args.pop_back_val(); auto oldSelfTy = B.createValueMetatype(loc, SILType::getPrimitiveObjectType( CanMetatypeType::get(oldSelf->getType().getASTType(), MetatypeRepresentation::Thick)), oldSelf); B.createDeallocPartialRef(loc, oldSelf, oldSelfTy); // Pass the dynamic type on to the native allocating initializer. args.push_back(oldSelfTy); native = SILDeclRef(native.getDecl(), SILDeclRef::Kind::Allocator); } SILFunctionConventions objcConv(CanSILFunctionType(objcFnTy), SGM.M); SILFunctionConventions nativeConv(CanSILFunctionType(nativeInfo.SILFnType), SGM.M); auto swiftResultTy = F.mapTypeIntoContext( nativeConv.getSILResultType(getTypeExpansionContext())); auto objcResultTy = objcConv.getSILResultType(getTypeExpansionContext()); // Call the native entry point. SILValue nativeFn = emitGlobalFunctionRef(loc, native, nativeInfo); SILValue result; CanSILFunctionType completionTy; bool completionIsOptional = false; if (foreignAsyncSlot) { completionTy = foreignAsyncSlot->getType().getAs(); if (!completionTy) { completionTy = foreignAsyncSlot->getType().getOptionalObjectType() .castTo(); completionIsOptional = true; } } // Helper function to take ownership of the completion handler from the // foreign async slot, and unwrap it if it's in an optional. auto consumeAndUnwrapCompletionBlock = [&](SILValue &completionBlock, SILBasicBlock *&doneBBOrNull) { auto completionBlockMV = emitManagedRValueWithCleanup(foreignAsyncSlot); // If the completion handler argument is nullable, and the caller gave us // no completion handler, discard the result. completionBlock = completionBlockMV.borrow(*this, loc).getValue(); doneBBOrNull = nullptr; if (completionIsOptional) { doneBBOrNull = createBasicBlock(); auto hasCompletionBB = createBasicBlock(); auto noCompletionBB = createBasicBlock(); std::pair dests[] = { {getASTContext().getOptionalSomeDecl(), hasCompletionBB}, {getASTContext().getOptionalNoneDecl(), noCompletionBB}, }; auto *switchEnum = B.createSwitchEnum(loc, completionBlock, nullptr, dests); B.emitBlock(noCompletionBB); B.createBranch(loc, doneBBOrNull); B.emitBlock(hasCompletionBB); completionBlock = switchEnum->createOptionalSomeResult(); } }; auto pushErrorFlag = [&](bool hasError, SmallVectorImpl &completionHandlerArgs) { bool errorFlagIsZeroOnError = foreignAsync->completionHandlerFlagIsErrorOnZero(); auto errorFlagIndex = foreignAsync->completionHandlerFlagParamIndex(); auto errorFlagTy = completionTy->getParameters()[*errorFlagIndex] .getSILStorageInterfaceType(); auto errorFlag = emitWrapIntegerLiteral(loc, errorFlagTy, hasError ^ errorFlagIsZeroOnError); completionHandlerArgs.push_back(errorFlag); }; // Helper function to pass a native async function's result as arguments to // the ObjC completion handler block. auto passResultToCompletionHandler = [&](SILValue result) -> SILValue { Scope completionArgScope(*this, loc); SmallVector completionHandlerArgs; auto asyncResult = emitManagedRValueWithCleanup(result); SILValue completionBlock; SILBasicBlock *doneBB; consumeAndUnwrapCompletionBlock(completionBlock, doneBB); auto pushArg = [&](ManagedValue arg, CanType nativeFormalTy, SILParameterInfo param) { auto bridgedTy = param.getInterfaceType(); auto bridgedArg = emitNativeToBridgedValue(loc, arg.borrow(*this, loc), nativeFormalTy, bridgedTy, SILType::getPrimitiveObjectType(bridgedTy)); completionHandlerArgs.push_back(bridgedArg.getValue()); }; Scope completionArgDestructureScope(*this, loc); auto errorParamIndex = foreignAsync->completionHandlerErrorParamIndex(); auto errorFlagIndex = foreignAsync->completionHandlerFlagParamIndex(); auto pushErrorPlaceholder = [&]{ auto errorArgTy = completionTy->getParameters()[*errorParamIndex] .getSILStorageInterfaceType(); // Error type must be optional. We pass nil for a successful return auto none = B.createOptionalNone(loc, errorArgTy); completionHandlerArgs.push_back(none); }; unsigned numResults = completionTy->getParameters().size() - errorParamIndex.has_value() - errorFlagIndex.has_value(); if (numResults == 1) { for (unsigned i = 0; i < completionTy->getNumParameters(); ++i) { if (errorParamIndex && *errorParamIndex == i) { pushErrorPlaceholder(); continue; } if (errorFlagIndex && *errorFlagIndex == i) { pushErrorFlag(/*has error*/ false, completionHandlerArgs); continue; } // Use the indirect return argument if the result is indirect. if (substConv.hasIndirectSILResults()) { pushArg(emitManagedRValueWithCleanup(args[0]), nativeFormalResultType, completionTy->getParameters()[i]); } else { pushArg(asyncResult, nativeFormalResultType, completionTy->getParameters()[i]); } } } else { // A tuple return maps to multiple completion handler parameters. auto formalTuple = cast(nativeFormalResultType); unsigned indirectResultI = 0; unsigned directResultI = 0; auto directResults = substConv.getDirectSILResults(); auto hasMultipleDirectResults = !directResults.empty() && std::next(directResults.begin()) != directResults.end(); for (unsigned paramI : indices(completionTy->getParameters())) { if (errorParamIndex && paramI == *errorParamIndex) { pushErrorPlaceholder(); continue; } if (errorFlagIndex && paramI == *errorFlagIndex) { pushErrorFlag(/*has error*/ false, completionHandlerArgs); continue; } auto elementI = paramI - (errorParamIndex && paramI > *errorParamIndex) - (errorFlagIndex && paramI > *errorFlagIndex); auto param = completionTy->getParameters()[paramI]; auto formalTy = formalTuple.getElementType(elementI); ManagedValue argPiece; auto result = substConv.getResults()[elementI]; if (substConv.isSILIndirect(result)) { // Take the arg piece from the indirect return arguments. argPiece = emitManagedRValueWithCleanup(args[indirectResultI++]); } else if (hasMultipleDirectResults) { // Take the arg piece from one of the tuple elements of the direct // result tuple from the apply. argPiece = B.createTupleExtract(loc, asyncResult, directResultI++); } else { // Take the entire direct result from the apply as the arg piece. argPiece = asyncResult; } pushArg(argPiece, formalTy, param); } } // Pass the bridged results on to the completion handler. B.createApply(loc, completionBlock, {}, completionHandlerArgs); completionArgDestructureScope.pop(); if (doneBB) { B.createBranch(loc, doneBB); B.emitBlock(doneBB); } // The immediate function result is an empty tuple. return SILUndef::get(&F, SGM.Types.getEmptyTupleType()); }; // If the function we're calling isn't actually polymorphic, drop the // substitutions. This should only happen in concrete specializations. if (subs && !nativeFn->getType().castTo()->isPolymorphic()) { assert(subs.getGenericSignature()->areAllParamsConcrete()); subs = SubstitutionMap(); } if (!substTy->hasErrorResult()) { // Create the apply. result = B.createApply(loc, nativeFn, subs, args); // Leave the argument cleanup scope immediately. This isn't really // necessary; it just limits lifetimes a little bit more. argScope.pop(); // Now bridge the return value. // If this is an async method, we forward the results of the async call to // the completion handler. if (foreignAsync) { result = passResultToCompletionHandler(result); } else { if (needsBridging) { if (substConv.hasIndirectSILResults()) { assert(substTy->getNumResults() == 1); result = args[0]; } result = emitBridgeReturnValue(*this, loc, result, nativeFormalResultType, bridgedFormalResultType, objcResultTy); } } } else { SILBasicBlock *contBB = createBasicBlock(); SILBasicBlock *errorBB = createBasicBlock(); SILBasicBlock *normalBB = createBasicBlock(); B.createTryApply(loc, nativeFn, subs, args, normalBB, errorBB); // Emit the non-error destination. { B.emitBlock(normalBB); SILValue nativeResult = normalBB->createPhiArgument(swiftResultTy, OwnershipKind::Owned); if (foreignAsync) { // If the function is async, pass the results as the success argument(s) // to the completion handler, with a nil error. passResultToCompletionHandler(nativeResult); B.createBranch(loc, contBB); } else { if (substConv.hasIndirectSILResults()) { assert(substTy->getNumResults() == 1); nativeResult = args[0]; } // In this branch, the eventual return value is mostly created // by bridging the native return value, but we may need to // adjust it slightly. SILValue bridgedResult = emitBridgeReturnValueForForeignError(loc, nativeResult, nativeFormalResultType, bridgedFormalResultType, objcResultTy, foreignErrorSlot, *foreignError); B.createBranch(loc, contBB, bridgedResult); } } // Emit the error destination. { B.emitBlock(errorBB); SILValue nativeError = errorBB->createPhiArgument( substConv.getSILErrorType(getTypeExpansionContext()), OwnershipKind::Owned); if (foreignAsync) { // If the function is async, pass the bridged error along to the // completion handler, with dummy values for the other argument(s). Scope completionArgScope(*this, loc); auto nativeErrorMV = emitManagedRValueWithCleanup(nativeError); SILValue completionBlock; SILBasicBlock *doneBB; consumeAndUnwrapCompletionBlock(completionBlock, doneBB); Scope completionErrorScope(*this, loc); SmallVector completionHandlerArgs; auto completionTy = completionBlock->getType().castTo(); auto errorParamIndex = *foreignAsync->completionHandlerErrorParamIndex(); auto errorFlagIndex = foreignAsync->completionHandlerFlagParamIndex(); auto completionErrorTy = completionTy->getParameters()[errorParamIndex] .getInterfaceType(); auto bridgedError = emitNativeToBridgedError(loc, nativeErrorMV, nativeError->getType().getASTType(), completionErrorTy); // Fill in placeholder arguments, and put the bridged error in its // rightful place. for (unsigned i : indices(completionTy->getParameters())) { if (i == errorParamIndex) { completionHandlerArgs.push_back(bridgedError.borrow(*this, loc).getValue()); continue; } if (errorFlagIndex && i == *errorFlagIndex) { pushErrorFlag(/*has error*/ true, completionHandlerArgs); continue; } // For non-error arguments, pass a placeholder. // If the argument type is non-trivial, it must be Optional, and // we pass nil. auto param = completionTy->getParameters()[i]; auto paramTy = param.getSILStorageInterfaceType(); if (paramTy.isTrivial(F)) { // If it's trivial, pass a zero value of whatever the type is. auto zero = B.createZeroInitValue(loc, paramTy); completionHandlerArgs.push_back(zero); } else { // If it's not trivial, it must be a nullable class type. Pass // nil. auto none = B.createOptionalNone(loc, paramTy); completionHandlerArgs.push_back(none); } } // Pass the bridged error on to the completion handler. B.createApply(loc, completionBlock, {}, completionHandlerArgs); completionErrorScope.pop(); if (doneBB) { B.createBranch(loc, doneBB); B.emitBlock(doneBB); } completionArgScope.pop(); B.createBranch(loc, contBB); } else { // In this branch, the eventual return value is mostly invented. // Store the native error in the appropriate location and return. SILValue bridgedResult = emitBridgeErrorForForeignError(loc, nativeError, objcResultTy, foreignErrorSlot, *foreignError); B.createBranch(loc, contBB, bridgedResult); } } // Emit the join block. B.emitBlock(contBB); if (foreignAsync) { // After invoking the completion handler, our immediate return value is // void. result = SILUndef::get(&F, SGM.Types.getEmptyTupleType()); } else { result = contBB->createPhiArgument(objcResultTy, OwnershipKind::Owned); } // Leave the scope now. argScope.pop(); } scope.pop(); B.createReturn(loc, result); } static SILValue getThunkedForeignFunctionRef(SILGenFunction &SGF, AbstractFunctionDecl *fd, SILDeclRef foreign, ArrayRef args, const SILConstantInfo &foreignCI) { assert(foreign.isForeign); // Produce an objc_method when thunking ObjC methods. if (foreignCI.SILFnType->getRepresentation() == SILFunctionTypeRepresentation::ObjCMethod) { auto *objcDecl = dyn_cast_or_null(fd->getClangDecl()); const bool isObjCDirect = objcDecl && objcDecl->isDirectMethod(); if (isObjCDirect) { auto *fn = SGF.SGM.getFunction(foreign, NotForDefinition); return SGF.B.createFunctionRef(fd, fn); } SILValue thisArg = args.back().getValue(); return SGF.B.createObjCMethod(fd, thisArg, foreign, foreignCI.getSILType()); } // Otherwise, emit a function_ref. return SGF.emitGlobalFunctionRef(fd, foreign); } /// Generate code to emit a thunk with native conventions that calls a /// function with foreign conventions. void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) { assert(!thunk.isForeign && "foreign-to-native thunks only"); // Wrap the function in its original form. auto fd = cast(thunk.getDecl()); auto nativeCI = getConstantInfo(getTypeExpansionContext(), thunk); auto nativeFnTy = F.getLoweredFunctionType(); assert(nativeFnTy == nativeCI.SILFnType); if (fd->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); // Use the same generic environment as the native entry point. F.setGenericEnvironment(SGM.Types.getConstantGenericEnvironment(thunk)); SILDeclRef foreignDeclRef = thunk.asForeign(true); SILConstantInfo foreignCI = getConstantInfo(getTypeExpansionContext(), foreignDeclRef); auto foreignFnTy = foreignCI.SILFnType; // Find the foreign error/async convention and 'self' parameter index. std::optional thrownErrorType; std::optional foreignAsync; if (nativeFnTy->isAsync()) { foreignAsync = fd->getForeignAsyncConvention(); assert(foreignAsync && "couldn't find foreign async convention?!"); // We might switch to to the callee's actor as part of making the call, // but we don't need to switch back afterwards because we're going to // immediately return. ExpectedExecutor.setUnnecessary(); } std::optional foreignError; if (nativeFnTy->hasErrorResult()) { thrownErrorType = nativeFnTy->getErrorResult().getInterfaceType(); foreignError = fd->getForeignErrorConvention(); assert((foreignError || foreignAsync) && "couldn't find foreign error or async convention for foreign error!"); } ImportAsMemberStatus memberStatus = fd->getImportAsMemberStatus(); // Introduce indirect returns if necessary. // TODO: Handle exploded results? We don't currently need to since the only // bridged indirect type is Any. SILValue indirectResult; SILFunctionConventions nativeConv(nativeFnTy, SGM.M); if (nativeConv.hasIndirectSILResults()) { assert(nativeConv.getNumIndirectSILResults() == 1 && "bridged exploded result?!"); indirectResult = F.begin()->createFunctionArgument( nativeConv.getSingleSILResultType(F.getTypeExpansionContext())); } // Before we do anything, see if our function type is async and has an // implicit isolated parameter. In such a case, we need to implicitly insert // it here before we insert other parameters. // // NOTE: We do not jump to it or do anything further since as mentioned above, // we might switch to the callee's actor as part of making the call... but we // don't need to do anything further than that because we're going to // immediately return. bool hasImplicitIsolatedParameter = false; if (auto isolatedParameter = nativeFnTy->maybeGetIsolatedParameter(); isolatedParameter && nativeFnTy->isAsync() && isolatedParameter->hasOption(SILParameterInfo::ImplicitLeading)) { auto loweredTy = getLoweredTypeForFunctionArgument( isolatedParameter->getArgumentType(&F)); F.begin()->createFunctionArgument(loweredTy); hasImplicitIsolatedParameter = true; } // Forward the arguments. SmallVector params; bindParametersForForwarding(fd->getParameters(), params); Type allocatorSelfType; if (auto *selfDecl = fd->getImplicitSelfDecl()) { // The self declaration sometimes differ in dynamic-self-ness from the // lowered function type, so get the self parameter type from the function // type rather than the declaration. auto selfArgTy = F.getLoweredFunctionType()->getSelfParameter() .getSILStorageType(getModule(), F.getLoweredFunctionType(), getTypeExpansionContext()); auto selfArg = F.begin()->createFunctionArgument(F.mapTypeIntoContext(selfArgTy), selfDecl); params.push_back(selfArg); // For allocating constructors, 'self' is a metatype, not the 'self' value // formally present in the constructor body. if (thunk.kind == SILDeclRef::Kind::Allocator) { allocatorSelfType = F.mapTypeIntoContext( fd->getDeclContext()->getSelfInterfaceType()); } } // Set up the throw destination if necessary. CleanupLocation cleanupLoc(fd); if (thrownErrorType) { prepareRethrowEpilog(fd, AbstractionPattern(*thrownErrorType), *thrownErrorType, cleanupLoc); } SILValue result; { Scope scope(Cleanups, fd); // Bridge all the arguments. SmallVector args; unsigned foreignArgIndex = 0; // A helper function to add a placeholder for a foreign argument in the // appropriate position. auto maybeAddForeignArg = [&]() -> bool { if ((foreignError && foreignArgIndex == foreignError->getErrorParameterIndex()) || (foreignAsync && foreignArgIndex == foreignAsync->completionHandlerParamIndex())) { args.push_back(ManagedValue()); ++foreignArgIndex; return true; } return false; }; { bool hasSelfParam = fd->hasImplicitSelfDecl(); auto foreignFormalParams = getParameterTypes(foreignCI.LoweredType.getParams(), hasSelfParam); auto nativeFormalParams = getParameterTypes(nativeCI.LoweredType.getParams(), hasSelfParam); for (unsigned nativeParamIndex : indices(params)) { // Adjust the parameter if we inserted an implicit isolated parameter. unsigned nativeFnTyParamIndex = nativeParamIndex + hasImplicitIsolatedParameter; // Bring the parameter to +1. auto paramValue = params[nativeParamIndex]; auto thunkParam = nativeFnTy->getParameters()[nativeFnTyParamIndex]; // TODO: Could avoid a retain if the bridged parameter is also +0 and // doesn't require a bridging conversion. ManagedValue param; switch (thunkParam.getConvention()) { case ParameterConvention::Direct_Owned: param = emitManagedRValueWithCleanup(paramValue); break; case ParameterConvention::Direct_Guaranteed: case ParameterConvention::Direct_Unowned: param = emitManagedCopy(fd, paramValue); break; case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: param = ManagedValue::forLValue(paramValue); break; case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Indirect_In: param = emitManagedRValueWithCleanup(paramValue); break; case ParameterConvention::Indirect_In_Guaranteed: { auto tmp = emitTemporaryAllocation(fd, paramValue->getType()); B.createCopyAddr(fd, paramValue, tmp, IsNotTake, IsInitialization); param = emitManagedRValueWithCleanup(tmp); break; } case ParameterConvention::Pack_Guaranteed: case ParameterConvention::Pack_Owned: case ParameterConvention::Pack_Inout: llvm_unreachable("bridging a parameter pack?"); } while (maybeAddForeignArg()); bool isSelf = (hasSelfParam && nativeParamIndex == params.size() - 1); if (memberStatus.isInstance()) { // Leave space for `self` to be filled in later. if (foreignArgIndex == memberStatus.getSelfIndex()) { args.push_back({}); ++foreignArgIndex; } // Use the `self` space we skipped earlier if it's time. if (isSelf) { foreignArgIndex = memberStatus.getSelfIndex(); } } else if (memberStatus.isStatic() && isSelf) { // Lose a static `self` parameter. break; } CanType nativeFormalType = F.mapTypeIntoContext(nativeFormalParams[nativeParamIndex]) ->getCanonicalType(); CanType foreignFormalType = F.mapTypeIntoContext(foreignFormalParams[nativeParamIndex]) ->getCanonicalType(); if (isSelf) { assert(!nativeCI.LoweredType.getParams()[nativeParamIndex].isInOut() || nativeFormalType == foreignFormalType && "Cannot bridge 'self' parameter if passed inout"); } auto foreignParam = foreignFnTy->getParameters()[foreignArgIndex++]; SILType foreignLoweredTy = F.mapTypeIntoContext(foreignParam.getSILStorageType( F.getModule(), foreignFnTy, F.getTypeExpansionContext())); auto bridged = emitNativeToBridgedValue(fd, param, nativeFormalType, foreignFormalType, foreignLoweredTy); if (useLoweredAddresses() && (foreignParam.getConvention() == ParameterConvention::Indirect_In || foreignParam.getConvention() == ParameterConvention::Indirect_In_Guaranteed)) { auto temp = emitTemporaryAllocation(fd, bridged.getType()); bridged.forwardInto(*this, fd, temp); bridged = emitManagedBufferWithCleanup(temp); } if (memberStatus.isInstance() && isSelf) { // Fill in the `self` space. args[memberStatus.getSelfIndex()] = bridged; } else { args.push_back(bridged); } } } while (maybeAddForeignArg()); // Call the original. auto subs = getForwardingSubstitutionMap(); auto fn = getThunkedForeignFunctionRef(*this, fd, foreignDeclRef, args, foreignCI); auto fnType = fn->getType().castTo(); fnType = fnType->substGenericArgs(SGM.M, subs, getTypeExpansionContext()); CanType nativeFormalResultType = fd->mapTypeIntoContext(nativeCI.LoweredType.getResult()) ->getCanonicalType(); CanType bridgedFormalResultType = fd->mapTypeIntoContext(foreignCI.LoweredType.getResult()) ->getCanonicalType(); CalleeTypeInfo calleeTypeInfo( fnType, AbstractionPattern(nativeFnTy->getInvocationGenericSignature(), bridgedFormalResultType), nativeFormalResultType, foreignError, foreignAsync, ImportAsMemberStatus()); calleeTypeInfo.origFormalType = foreignCI.FormalPattern.getFunctionResultType(); auto init = indirectResult ? useBufferAsTemporary(indirectResult, getTypeLowering(indirectResult->getType())) : nullptr; SGFContext context(init.get()); ResultPlanPtr resultPlan = ResultPlanBuilder::computeResultPlan( *this, calleeTypeInfo, fd, context); ArgumentScope argScope(*this, fd); ManagedValue resultMV = emitApply(std::move(resultPlan), std::move(argScope), fd, ManagedValue::forObjectRValueWithoutOwnership(fn), subs, args, calleeTypeInfo, ApplyOptions(), context, std::nullopt) .getAsSingleValue(*this, fd); if (indirectResult) { if (!resultMV.isInContext()) { init->copyOrInitValueInto(*this, fd, resultMV, /*isInit*/ true); init->finishInitialization(*this); } init->getManagedAddress().forward(*this); result = emitEmptyTuple(fd); } else { result = resultMV.forward(*this); } } B.createReturn(ImplicitReturnLocation(fd), result); // Emit the throw destination. emitRethrowEpilog(fd); }