blob: ac21adb1a27b2054e07de01fdadb84807799f795 [file] [log] [blame]
//===--- 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 "RValue.h"
#include "ResultPlan.h"
#include "SILGenFunction.h"
#include "SILGenFunctionBuilder.h"
#include "Scope.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/ParameterList.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILUndef.h"
#include "swift/SIL/TypeLowering.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->getDecl() == errorProtocol ||
proto->getDecl()->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)SGM.SwiftModule->lookupConformance(type, errorProtocol);
}
/// Bridge the given Swift value to its corresponding Objective-C
/// object, using the appropriate witness for the
/// _ObjectiveCBridgeable._bridgeToObjectiveC requirement.
static Optional<ManagedValue>
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 None;
// 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 None;
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<FuncDecl>(witness)->isGeneric() &&
"Generic witnesses not supported");
auto *dc = cast<FuncDecl>(witness)->getDeclContext();
auto typeSubMap = swiftValueType->getContextSubstitutionMap(
SGF.SGM.SwiftModule, 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<SILFunctionType>(),
SGF.SGM.M);
if (witnessConv.isSILIndirect(witnessConv.getParameters()[0])
&& !swiftValue.getType().isAddress()) {
auto tmp = SGF.emitTemporaryAllocation(loc, swiftValue.getType());
SGF.B.createStoreBorrowOrTrivial(loc, swiftValue.borrow(SGF, loc), tmp);
swiftValue = ManagedValue::forUnmanaged(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 Optional<ManagedValue>
emitBridgeObjectiveCToNative(SILGenFunction &SGF,
SILLocation loc,
ManagedValue objcValue,
CanType bridgedType,
ProtocolConformance *conformance) {
// Find the _unconditionallyBridgeFromObjectiveC requirement.
auto requirement =
SGF.SGM.getUnconditionallyBridgeFromObjectiveCRequirement(loc);
if (!requirement) return None;
// Find the _ObjectiveCType requirement.
auto objcTypeRequirement = SGF.SGM.getBridgedObjectiveCTypeRequirement(loc);
if (!objcTypeRequirement) return None;
// 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<SILFunctionType>();
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<MetatypeType>(metatypeParam.getInterfaceType()) &&
cast<MetatypeType>(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::forUnmanaged(witnessRef), subs,
{objcValue, ManagedValue::forUnmanaged(metatypeValue)},
calleeTypeInfo, ApplyOptions::None, context, None);
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), false);
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::forUnmanaged(value);
case ParameterConvention::Direct_Unowned:
// We need to independently retain the value.
return SGF.emitManagedRetain(loc, value, valueTL);
case ParameterConvention::Indirect_Inout:
return ManagedValue::forLValue(value);
case ParameterConvention::Indirect_In_Guaranteed:
if (valueTL.isLoadable()) {
return SGF.B.createLoadBorrow(loc, ManagedValue::forUnmanaged(value));
} else {
return ManagedValue::forUnmanaged(value);
}
case ParameterConvention::Indirect_In:
if (valueTL.isLoadable()) {
return SGF.emitLoad(loc, value, valueTL, SGFContext(), IsTake);
} else {
return SGF.emitManagedRValueWithCleanup(value, valueTL);
}
case ParameterConvention::Indirect_In_Constant:
case ParameterConvention::Indirect_InoutAliasable:
llvm_unreachable("unexpected convention");
}
llvm_unreachable("bad convention");
}
/// Get the type of each parameter, filtering out empty tuples.
static SmallVector<CanType, 8>
getParameterTypes(AnyFunctionType::CanParamArrayRef params,
bool hasSelfParam=false) {
SmallVector<CanType, 8> results;
for (auto n : indices(params)) {
bool isSelf = (hasSelfParam ? n == params.size() - 1 : false);
const auto &param = 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::get(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);
}
}
// 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<ManagedValue, 4> args;
for (unsigned i : indices(funcTy->getParameters())) {
auto &param = 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_Constant:
case ParameterConvention::Indirect_In_Guaranteed:
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
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::None,
None, None, 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<SILFunctionType>();
// 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<SILFunctionType>(
loweredFuncUnsubstTy->mapTypeOutOfContext()->getCanonicalType());
auto blockInterfaceTy = cast<SILFunctionType>(
loweredBlockTy->mapTypeOutOfContext()->getCanonicalType());
assert(!blockInterfaceTy->isCoroutine());
auto storageTy = SILBlockStorageType::get(loweredFuncUnsubstTy);
auto storageInterfaceTy = SILBlockStorageType::get(fnInterfaceTy);
// Build the invoke function type.
SmallVector<SILParameterInfo, 4> 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() ? Optional<SILResultInfo>() : 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());
// 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<AnyMetatypeType>(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::forUnmanaged(native);
}
}
// Bridge native functions to blocks.
auto bridgedFTy = dyn_cast<AnyFunctionType>(bridgedType);
if (bridgedFTy && bridgedFTy->getRepresentation()
== AnyFunctionType::Representation::Block) {
auto nativeFTy = cast<AnyFunctionType>(nativeType);
if (nativeFTy->getRepresentation()
!= AnyFunctionType::Representation::Block)
return SGF.emitFuncToBlock(loc, v, nativeFTy, bridgedFTy,
loweredBridgedTy.castTo<SILFunctionType>());
}
// 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<AnyFunctionType>(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 = OpenedArchetypeType::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;
},
MakeAbstractConformanceForGenericType());
// 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::get(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<ManagedValue, 4> 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 &param = 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].isConsumed()) {
mv = mv.ensurePlusOne(SGF, loc);
}
args.push_back(mv);
}
// Add the block argument.
SILValue blockV =
entry->createFunctionArgument(SILType::getPrimitiveObjectType(blockTy));
ManagedValue block = ManagedValue::forUnmanaged(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::None,
/*override CC*/ SILFunctionTypeRepresentation::Block,
/*foreign error*/ None,
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<SILValue>());
// 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.verify();
}
/// 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<SILFunctionType>();
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());
// 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,
CanType nativeType,
SILType loweredNativeTy,
bool isCallResult,
SGFContext C) {
assert(loweredNativeTy.isObject());
SILType loweredBridgedTy = v.getType();
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,
nativeObjectType,
loweredNativeObjectTy,
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,
nativeObjectType, loweredNativeObjectTy,
isCallResult, C);
};
return SGF.emitOptionalToOptional(loc, v, loweredNativeTy, helper, C);
}
// Bridge ObjCBool, DarwinBoolean, WindowsBool to Bool when requested.
if (nativeType == SGF.SGM.Types.getBoolType()) {
if (bridgedType == SGF.SGM.Types.getObjCBoolType()) {
return emitBridgeForeignBoolToBool(SGF, loc, v,
SGF.SGM.getObjCBoolToBoolFn());
}
if (bridgedType == SGF.SGM.Types.getDarwinBooleanType()) {
return emitBridgeForeignBoolToBool(SGF, loc, v,
SGF.SGM.getDarwinBooleanToBoolFn());
}
if (bridgedType == SGF.SGM.Types.getWindowsBoolType()) {
return emitBridgeForeignBoolToBool(SGF, loc, v,
SGF.SGM.getWindowsBoolToBoolFn());
}
}
// Bridge Objective-C to thick metatypes.
if (isa<AnyMetatypeType>(nativeType)) {
auto bridgedMetaTy = cast<AnyMetatypeType>(bridgedType);
if (bridgedMetaTy->hasRepresentation() &&
bridgedMetaTy->getRepresentation() == MetatypeRepresentation::ObjC) {
SILValue native =
SGF.B.emitObjCToThickMetatype(loc, 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::forUnmanaged(native);
}
}
// Bridge blocks back into native function types.
if (auto nativeFTy = dyn_cast<AnyFunctionType>(nativeType)) {
auto bridgedFTy = cast<AnyFunctionType>(bridgedType);
if (bridgedFTy->getRepresentation()
== AnyFunctionType::Representation::Block
&& nativeFTy->getRepresentation()
!= AnyFunctionType::Representation::Block) {
return SGF.emitBlockToFunc(loc, v, bridgedFTy, nativeFTy,
loweredNativeTy.castTo<SILFunctionType>());
}
}
// Bridge via _ObjectiveCBridgeable.
if (auto conformance =
SGF.SGM.getConformanceToObjectiveCBridgeable(loc, nativeType)) {
if (auto result = emitBridgeObjectiveCToNative(SGF, loc, v, bridgedType,
conformance))
return *result;
assert(SGF.SGM.getASTContext().Diags.hadAnyError() &&
"Bridging code should have complained");
return SGF.emitUndef(nativeType);
}
// id-to-Any bridging.
if (nativeType->isAny()) {
// If this is not a call result, use the normal erasure logic.
if (!isCallResult) {
return SGF.emitTransformedValue(loc, v, bridgedType, nativeType, C);
}
// Otherwise, we use more complicated logic that handles results that
// were unexpetedly null.
assert(bridgedType.isAnyClassReferenceType());
// Convert to AnyObject if necessary.
CanType anyObjectTy =
SGF.getASTContext().getAnyObjectType()->getCanonicalType();
if (bridgedType != anyObjectTy) {
v = SGF.emitTransformedValue(loc, 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, v, optionalBridgedTy);
return SGF.emitApplyOfLibraryIntrinsic(loc,
SGF.getASTContext().getBridgeAnyObjectToAny(),
SubstitutionMap(), optionalMV, C)
.getAsSingleValue(SGF, loc);
}
// Bridge NSError to Error.
if (bridgedType == SGF.SGM.Types.getNSErrorType())
return SGF.emitBridgedToNativeError(loc, v);
return v;
}
ManagedValue SILGenFunction::emitBridgedToNativeValue(SILLocation loc,
ManagedValue v,
CanType bridgedType,
CanType nativeType,
SILType loweredNativeTy,
SGFContext C,
bool isCallResult) {
loweredNativeTy = loweredNativeTy.getObjectType();
return emitCBridgedToNativeValue(*this, loc, v, bridgedType, nativeType,
loweredNativeTy, 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<SILFunctionType>();
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().getExceptionType());
auto bridgeFn = emitGlobalFunctionRef(loc, SGM.getErrorToNSErrorFn());
auto bridgeFnType = bridgeFn->getType().castTo<SILFunctionType>();
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::get(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 address-only, make a +1 copy and operate on that.
if (lowering.isAddressOnly()) {
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<GenericFunctionType>(fnType)) {
return cast<FunctionType>(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<SILValue> &args,
SILValue &foreignErrorSlot,
SILValue &foreignAsyncSlot,
Optional<ForeignErrorConvention> &foreignError,
Optional<ForeignAsyncConvention> &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<ManagedValue, 8> bridgedArgs;
bridgedArgs.reserve(objcFnTy->getParameters().size());
// Find the foreign error and async conventions if we have one.
if (thunk.hasDecl()) {
if (auto func = dyn_cast<AbstractFunctionDecl>(thunk.getDecl())) {
foreignError = func->getForeignErrorConvention();
foreignAsync = func->getForeignAsyncConvention();
}
}
// We don't know what to do with indirect results from the Objective-C side.
assert(objcFnTy->getNumIndirectFormalResults() == 0
&& "Objective-C methods cannot have indirect results");
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();
assert(nativeInputs.size() == bridgedFormalTypes.size());
assert(nativeInputs.size() == nativeFormalTypes.size());
assert(inputs.size() ==
nativeInputs.size() + unsigned(foreignError.hasValue())
+ unsigned(foreignAsync.hasValue()));
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()) {
foreignAsyncSlot = 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].isConsumed())
SGF.emitManagedRValueWithCleanup(arg);
arg = copy;
}
// Convert the argument to +1 if necessary.
else if (!inputs[i].isConsumed()) {
arg = emitObjCUnconsumedArgument(SGF, loc, arg);
}
auto managedArg = SGF.emitManagedRValueWithCleanup(arg);
bridgedArgs.push_back(managedArg);
}
assert(bridgedArgs.size()
+ unsigned(foreignError.hasValue())
+ unsigned(foreignAsync.hasValue())
== objcFnTy->getParameters().size() &&
"objc inputs don't match number of arguments?!");
assert(bridgedArgs.size() == swiftFnTy->getParameters().size() &&
"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());
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 (nativeInputs[i].isFormalIndirect() &&
!native.getType().isAddress()) {
auto buf = SGF.emitTemporaryAllocation(loc, native.getType());
native.forwardInto(SGF, loc, buf);
native = SGF.emitManagedBufferWithCleanup(buf);
}
if (nativeInputs[i].isConsumed()) {
argValue = native.forward(SGF);
} else if (nativeInputs[i].isGuaranteed()) {
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<SILValue, 4> 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);
if (!input.isConsumed()) {
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 just swiftcc and async.
auto closureExtInfo = objcFnTy->getExtInfo().intoBuilder()
.withRepresentation(SILFunctionTypeRepresentation::Thin)
.withAsync()
.build();
auto closureTy = objcFnTy->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 += "yyYcfU_"; // 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.isSerialized(),
ProfileCounter(),
IsThunk,
IsNotDynamic);
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(SGM.Types.getEmptyTupleType(), F));
return closure;
}
void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
assert(thunk.isForeign);
SILDeclRef native = thunk.asForeign(false);
// 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<ConstructorDecl>(native.getDecl())) {
if (!ctor->isDesignatedInit() && !ctor->isObjC()) {
isInitializingToAllocatingInitThunk = true;
native = SILDeclRef(ctor, SILDeclRef::Kind::Allocator);
}
}
}
auto nativeInfo = getConstantInfo(getTypeExpansionContext(), native);
auto subs = F.getForwardingSubstitutionMap();
auto substTy = nativeInfo.SILFnType->substGenericArgs(
SGM.M, subs, getTypeExpansionContext());
SILFunctionConventions substConv(substTy, SGM.M);
// Use the same generic environment as the native entry point.
F.setGenericEnvironment(SGM.Types.getConstantGenericEnvironment(native));
auto loc = thunk.getAsRegularLocation();
loc.markAutoGenerated();
Scope scope(Cleanups, CleanupLocation::get(loc));
// If we are bridging a Swift method with an Any return value, create a
// stack allocation to hold the result, since Any is address-only.
SmallVector<SILValue, 4> args;
if (substConv.hasIndirectSILResults()) {
args.push_back(emitTemporaryAllocation(
loc, substConv.getSingleSILResultType(getTypeExpansionContext())));
}
// If the '@objc' was inferred due to deprecated rules,
// emit a Builtin.swift3ImplicitObjCEntrypoint().
//
// However, don't do so for 'dynamic' members, which must use Objective-C
// dispatch and therefore create many false positives.
if (thunk.hasDecl()) {
auto decl = thunk.getDecl();
// For an accessor, look at the storage declaration's attributes.
if (auto accessor = dyn_cast<AccessorDecl>(decl)) {
decl = accessor->getStorage();
}
if (auto attr = decl->getAttrs().getAttribute<ObjCAttr>()) {
// If @objc was inferred based on the Swift 3 @objc inference rules, emit
// a call to Builtin.swift3ImplicitObjCEntrypoint() to enable runtime
// logging of the uses of such entrypoints.
if (attr->isSwift3Inferred() && !decl->shouldUseObjCDispatch()) {
// Get the starting source location of the declaration so we can say
// exactly where to stick '@objc'.
SourceLoc objcInsertionLoc =
decl->getAttributeInsertionLoc(/*modifier*/ false);
auto objcInsertionLocArgs
= emitSourceLocationArgs(objcInsertionLoc, loc);
B.createBuiltin(loc,
getASTContext().getIdentifier("swift3ImplicitObjCEntrypoint"),
getModule().Types.getEmptyTupleType(), { }, {
objcInsertionLocArgs.filenameStartPointer.forward(*this),
objcInsertionLocArgs.filenameLength.forward(*this),
objcInsertionLocArgs.line.forward(*this),
objcInsertionLocArgs.column.forward(*this)
});
}
}
}
// 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::get(loc));
// Bridge the arguments.
Optional<ForeignErrorConvention> foreignError;
Optional<ForeignAsyncConvention> foreignAsync;
SILValue foreignErrorSlot, 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;
// 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<SILValue, 2> completionHandlerArgs;
auto completionTy = foreignAsyncSlot->getType().castTo<SILFunctionType>();
auto asyncResult = emitManagedRValueWithCleanup(result);
auto pushArg = [&](ManagedValue arg,
CanType nativeFormalTy,
SILParameterInfo param) {
auto bridgedTy = param.getInterfaceType();
auto bridgedArg = emitNativeToBridgedValue(loc,
arg, nativeFormalTy,
bridgedTy,
SILType::getPrimitiveObjectType(bridgedTy));
completionHandlerArgs.push_back(bridgedArg.borrow(*this, loc).getValue());
};
auto errorParamIndex = foreignAsync->completionHandlerErrorParamIndex();
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.hasValue();
if (numResults == 1) {
if (errorParamIndex && *errorParamIndex == 0) {
pushErrorPlaceholder();
}
pushArg(asyncResult,
nativeFormalResultType,
completionTy->getParameters()[completionHandlerArgs.size()]);
if (errorParamIndex && *errorParamIndex == 1) {
pushErrorPlaceholder();
}
} else {
// A tuple return maps to multiple completion handler parameters.
auto formalTuple = cast<TupleType>(nativeFormalResultType);
for (unsigned paramI : indices(completionTy->getParameters())) {
if (errorParamIndex && paramI == *errorParamIndex) {
pushErrorPlaceholder();
continue;
}
auto elementI = paramI - (errorParamIndex && paramI > *errorParamIndex);
auto param = completionTy->getParameters()[paramI];
auto formalTy = formalTuple.getElementType(elementI);
auto argPiece = B.createTupleExtract(loc, asyncResult, elementI);
pushArg(argPiece, formalTy, param);
}
}
// Pass the bridged results on to the completion handler.
B.createApply(loc, foreignAsyncSlot, {}, completionHandlerArgs);
// The immediate function result is an empty tuple.
return SILUndef::get(SGM.Types.getEmptyTupleType(), F);
};
if (!substTy->hasErrorResult()) {
// Create the apply.
result = B.createApply(loc, nativeFn, subs, args);
if (substConv.hasIndirectSILResults()) {
assert(substTy->getNumResults() == 1);
result = args[0];
}
// 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 {
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 (substConv.hasIndirectSILResults()) {
assert(substTy->getNumResults() == 1);
nativeResult = args[0];
}
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 {
// 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);
SmallVector<SILValue, 2> completionHandlerArgs;
auto completionTy = foreignAsyncSlot->getType().castTo<SILFunctionType>();
auto errorParamIndex = *foreignAsync->completionHandlerErrorParamIndex();
auto completionErrorTy = completionTy->getParameters()[errorParamIndex]
.getInterfaceType();
auto bridgedError = emitNativeToBridgedError(loc,
emitManagedRValueWithCleanup(nativeError),
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;
}
// 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, the value passed doesn't matter.
completionHandlerArgs.push_back(SILUndef::get(paramTy, F.getModule()));
} 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 results on to the completion handler.
B.createApply(loc, foreignAsyncSlot, {}, completionHandlerArgs);
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(SGM.Types.getEmptyTupleType(), F);
} else {
result = contBB->createPhiArgument(objcResultTy, OwnershipKind::Owned);
}
// Leave the scope now.
argScope.pop();
}
scope.pop();
B.createReturn(loc, result);
}
static SILValue
getThunkedForeignFunctionRef(SILGenFunction &SGF,
SILLocation loc,
SILDeclRef foreign,
ArrayRef<ManagedValue> args,
const SILConstantInfo &foreignCI) {
assert(foreign.isForeign);
// Produce an objc_method when thunking ObjC methods.
if (foreignCI.SILFnType->getRepresentation()
== SILFunctionTypeRepresentation::ObjCMethod) {
SILValue thisArg = args.back().getValue();
return SGF.B.createObjCMethod(loc, thisArg, foreign,
foreignCI.getSILType());
}
// Otherwise, emit a function_ref.
return SGF.emitGlobalFunctionRef(loc, 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<AbstractFunctionDecl>(thunk.getDecl());
auto nativeCI = getConstantInfo(getTypeExpansionContext(), thunk);
auto nativeFnTy = F.getLoweredFunctionType();
assert(nativeFnTy == nativeCI.SILFnType);
// 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.
bool hasError = false;
Optional<ForeignAsyncConvention> foreignAsync;
if (nativeFnTy->isAsync()) {
foreignAsync = fd->getForeignAsyncConvention();
assert(foreignAsync && "couldn't find foreign async convention?!");
}
Optional<ForeignErrorConvention> foreignError;
if (nativeFnTy->hasErrorResult()) {
hasError = true;
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()));
}
// Forward the arguments.
SmallVector<SILValue, 8> params;
bindParametersForForwarding(fd->getParameters(), params);
if (thunk.kind != SILDeclRef::Kind::Allocator)
if (auto *selfDecl = fd->getImplicitSelfDecl())
bindParameterForForwarding(selfDecl, params);
// For allocating constructors, 'self' is a metatype, not the 'self' value
// formally present in the constructor body.
Type allocatorSelfType;
if (thunk.kind == SILDeclRef::Kind::Allocator) {
auto *selfDecl = fd->getImplicitSelfDecl();
allocatorSelfType = F.mapTypeIntoContext(
fd->getDeclContext()->getSelfInterfaceType());
auto selfMetatype =
CanMetatypeType::get(allocatorSelfType->getCanonicalType());
auto selfArg = F.begin()->createFunctionArgument(
getLoweredLoadableType(selfMetatype), selfDecl);
params.push_back(selfArg);
}
// Set up the throw destination if necessary.
CleanupLocation cleanupLoc(fd);
if (hasError) {
prepareRethrowEpilog(cleanupLoc);
}
SILValue result;
{
Scope scope(Cleanups, fd);
// Bridge all the arguments.
SmallVector<ManagedValue, 8> 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)) {
// Bring the parameter to +1.
auto paramValue = params[nativeParamIndex];
auto thunkParam = nativeFnTy->getParameters()[nativeParamIndex];
// 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 = emitManagedRetain(fd, paramValue);
break;
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
param = ManagedValue::forLValue(paramValue);
break;
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::Indirect_In_Constant:
llvm_unreachable("unsupported convention");
}
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);
// Handle C pointer arguments imported as indirect `self` arguments.
if (foreignParam.getConvention() == ParameterConvention::Indirect_In) {
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<SILFunctionType>();
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());
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::forUnmanaged(fn), subs, args,
calleeTypeInfo, ApplyOptions::None, context, None)
.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::getImplicitReturnLoc(fd), result);
// Emit the throw destination.
emitRethrowEpilog(fd);
}