blob: 96d734e0216b7ffab320d44f05471e8371b3d320 [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 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "SILGenFunction.h"
#include "RValue.h"
#include "Scope.h"
#include "swift/AST/AST.h"
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/Basic/Fallthrough.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/TypeLowering.h"
using namespace swift;
using namespace Lowering;
static ManagedValue emitBridgeStringToNSString(SILGenFunction &gen,
SILLocation loc,
ManagedValue str) {
// func _convertStringToNSString(String) -> NSString
SILValue stringToNSStringFn
= gen.emitGlobalFunctionRef(loc, gen.SGM.getStringToNSStringFn());
SILValue nsstr = gen.B.createApply(loc, stringToNSStringFn,
stringToNSStringFn.getType(),
gen.getLoweredType(gen.SGM.Types.getNSStringType()),
{}, str.forward(gen));
return gen.emitManagedRValueWithCleanup(nsstr);
}
static ManagedValue emitBridgeNSStringToString(SILGenFunction &gen,
SILLocation loc,
ManagedValue nsstr) {
SILValue bridgeFn =
gen.emitGlobalFunctionRef(loc, gen.SGM.getNSStringToStringFn());
Type inputType = nsstr.getType().getSwiftRValueType();
if (!inputType->getOptionalObjectType()) {
SILType loweredOptTy = gen.SGM.getLoweredType(OptionalType::get(inputType));
auto *someDecl = gen.getASTContext().getOptionalSomeDecl();
auto *enumInst = gen.B.createEnum(loc, nsstr.getValue(), someDecl,
loweredOptTy);
nsstr = ManagedValue(enumInst, nsstr.getCleanup());
}
SILType nativeTy = gen.getLoweredType(gen.SGM.Types.getStringType());
SILValue str = gen.B.createApply(loc, bridgeFn, bridgeFn.getType(), nativeTy,
{}, { nsstr.forward(gen) });
return gen.emitManagedRValueWithCleanup(str);
}
static ManagedValue emitBridgeCollectionFromNative(SILGenFunction &gen,
SILLocation loc,
SILDeclRef bridgeFnRef,
ManagedValue collection,
SILType bridgedTy) {
SILValue bridgeFn = gen.emitGlobalFunctionRef(loc, bridgeFnRef);
// If the expected return is optional, we'll need to wrap it.
OptionalTypeKind OTK = OTK_None;
SILType origBridgedTy = bridgedTy;
if (auto bridgedObjTy = bridgedTy.getAnyOptionalObjectType(gen.SGM.M, OTK)) {
bridgedTy = bridgedObjTy;
}
// Figure out the type parameters.
auto inputTy
= collection.getType().getSwiftRValueType()->castTo<BoundGenericType>();
auto subs = inputTy->getSubstitutions(gen.SGM.M.getSwiftModule(), nullptr);
auto substFnType = bridgeFn.getType().substGenericArgs(gen.SGM.M, subs);
SILValue bridged = gen.B.createApply(loc, bridgeFn,
substFnType,
bridgedTy,
subs,
{ collection.forward(gen) });
// Wrap the result if necessary.
if (OTK != OTK_None) {
bridged = gen.B.createEnum(loc, bridged,
gen.getASTContext().getOptionalSomeDecl(OTK),
origBridgedTy);
}
return gen.emitManagedRValueWithCleanup(bridged);
}
static ManagedValue emitBridgeCollectionToNative(SILGenFunction &gen,
SILLocation loc,
SILDeclRef bridgeFnRef,
ManagedValue collection,
SILType nativeTy) {
SILValue bridgeFn = gen.emitGlobalFunctionRef(loc, bridgeFnRef);
auto collectionTy = nativeTy.getSwiftRValueType()->castTo<BoundGenericType>();
auto subs = collectionTy->getSubstitutions(gen.SGM.M.getSwiftModule(),
nullptr);
auto substFnType = bridgeFn.getType().substGenericArgs(gen.SGM.M, subs);
Type inputType = collection.getType().getSwiftRValueType();
if (!inputType->getOptionalObjectType()) {
SILType loweredOptTy = gen.SGM.getLoweredType(OptionalType::get(inputType));
auto *someDecl = gen.getASTContext().getOptionalSomeDecl();
auto *enumInst = gen.B.createEnum(loc, collection.getValue(), someDecl,
loweredOptTy);
collection = ManagedValue(enumInst, collection.getCleanup());
}
SILValue result = gen.B.createApply(loc, bridgeFn,
substFnType,
nativeTy,
subs,
{ collection.forward(gen) });
return gen.emitManagedRValueWithCleanup(result);
}
static ManagedValue emitBridgeBoolToObjCBool(SILGenFunction &gen,
SILLocation loc,
ManagedValue swiftBool) {
// func _convertBoolToObjCBool(Bool) -> ObjCBool
SILValue boolToObjCBoolFn
= gen.emitGlobalFunctionRef(loc, gen.SGM.getBoolToObjCBoolFn());
SILType resultTy =gen.getLoweredLoadableType(gen.SGM.Types.getObjCBoolType());
SILValue result = gen.B.createApply(loc, boolToObjCBoolFn,
boolToObjCBoolFn.getType(),
resultTy, {}, swiftBool.forward(gen));
return gen.emitManagedRValueWithCleanup(result);
}
static ManagedValue emitBridgeBoolToDarwinBoolean(SILGenFunction &gen,
SILLocation loc,
ManagedValue swiftBool) {
// func _convertBoolToDarwinBoolean(Bool) -> DarwinBoolean
SILValue boolToDarwinBooleanFn
= gen.emitGlobalFunctionRef(loc, gen.SGM.getBoolToDarwinBooleanFn());
SILType resultTy =
gen.getLoweredLoadableType(gen.SGM.Types.getDarwinBooleanType());
SILValue result = gen.B.createApply(loc, boolToDarwinBooleanFn,
boolToDarwinBooleanFn.getType(),
resultTy, {}, swiftBool.forward(gen));
return gen.emitManagedRValueWithCleanup(result);
}
static ManagedValue emitBridgeForeignBoolToBool(SILGenFunction &gen,
SILLocation loc,
ManagedValue foreignBool,
SILDeclRef bridgingFnRef) {
// func _convertObjCBoolToBool(ObjCBool) -> Bool
SILValue bridgingFn = gen.emitGlobalFunctionRef(loc, bridgingFnRef);
SILType resultTy = gen.getLoweredLoadableType(gen.SGM.Types.getBoolType());
SILValue result = gen.B.createApply(loc, bridgingFn, bridgingFn.getType(),
resultTy, {}, foreignBool.forward(gen));
return gen.emitManagedRValueWithCleanup(result);
}
static void buildFuncToBlockInvokeBody(SILGenFunction &gen,
SILLocation loc,
CanSILFunctionType blockTy,
CanSILBlockStorageType blockStorageTy,
CanSILFunctionType funcTy) {
Scope scope(gen.Cleanups, CleanupLocation::get(loc));
SILBasicBlock *entry = &*gen.F.begin();
// Get the captured native function value out of the block.
auto storageAddrTy = SILType::getPrimitiveAddressType(blockStorageTy);
auto storage = new (gen.SGM.M) SILArgument(entry, storageAddrTy);
auto capture = gen.B.createProjectBlockStorage(loc, storage);
auto &funcTL = gen.getTypeLowering(funcTy);
auto fn = gen.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");
SmallVector<ManagedValue, 4> args;
for (unsigned i : indices(funcTy->getParameters())) {
auto &funcParam = funcTy->getParameters()[i];
auto &param = blockTy->getParameters()[i];
SILValue v = new (gen.SGM.M) SILArgument(entry, param.getSILType());
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 (param.getSILType().isBlockPointerCompatible()) {
// We still need to consume the original block if it was owned.
switch (param.getConvention()) {
case ParameterConvention::Direct_Owned:
gen.emitManagedRValueWithCleanup(v);
break;
case ParameterConvention::Direct_Deallocating:
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_Out:
llvm_unreachable("indirect params to blocks not supported");
}
SILValue blockCopy = gen.B.createCopyBlock(loc, v);
mv = gen.emitManagedRValueWithCleanup(blockCopy);
} else {
switch (param.getConvention()) {
case ParameterConvention::Direct_Owned:
// Consume owned parameters at +1.
mv = gen.emitManagedRValueWithCleanup(v);
break;
case ParameterConvention::Direct_Guaranteed:
case ParameterConvention::Direct_Unowned:
// We need to independently retain the value.
mv = gen.emitManagedRetain(loc, v);
break;
case ParameterConvention::Direct_Deallocating:
// We do not need to retain the value since the value is already being
// deallocated.
mv = ManagedValue::forUnmanaged(v);
break;
case ParameterConvention::Indirect_In_Guaranteed:
case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_Out:
llvm_unreachable("indirect arguments to blocks not supported");
}
}
args.push_back(gen.emitBridgedToNativeValue(loc, mv,
SILFunctionTypeRepresentation::CFunctionPointer,
funcParam.getType()));
}
// Call the native function.
assert(!funcTy->hasIndirectResult()
&& "block thunking func with indirect result not supported");
ManagedValue result = gen.emitMonomorphicApply(loc, fn, args,
funcTy->getSILResult().getSwiftRValueType(),
ApplyOptions::None,
None, None);
// Bridge the result back to ObjC.
result = gen.emitNativeToBridgedValue(loc, result,
SILFunctionTypeRepresentation::CFunctionPointer,
AbstractionPattern(result.getType().getSwiftRValueType()),
result.getType().getSwiftRValueType(),
blockTy->getSILResult().getSwiftRValueType());
auto resultVal = result.forward(gen);
scope.pop();
// Handle the result convention.
switch (blockTy->getResult().getConvention()) {
case ResultConvention::UnownedInnerPointer:
case ResultConvention::Unowned:
assert(gen.getTypeLowering(resultVal.getType()).isTrivial()
&& "nontrivial result is returned unowned?!");
gen.B.createReturn(loc, resultVal);
break;
case ResultConvention::Autoreleased:
gen.B.createAutoreleaseReturn(loc, resultVal);
break;
case ResultConvention::Owned:
gen.B.createReturn(loc, resultVal);
break;
}
}
/// Bridge a native function to a block with a thunk.
ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc,
ManagedValue fn,
CanSILFunctionType blockTy) {
// Build the invoke function signature. The block will capture the original
// function value.
auto fnTy = fn.getType().castTo<SILFunctionType>();
auto storageTy = SILBlockStorageType::get(fnTy);
// Build the invoke function type.
SmallVector<SILParameterInfo, 4> params;
params.push_back(
SILParameterInfo(storageTy, ParameterConvention::Indirect_Inout));
std::copy(blockTy->getParameters().begin(),
blockTy->getParameters().end(),
std::back_inserter(params));
auto invokeTy =
SILFunctionType::get(nullptr,
SILFunctionType::ExtInfo()
.withRepresentation(SILFunctionType::Representation::
CFunctionPointer),
ParameterConvention::Direct_Unowned,
params,
blockTy->getResult(),
blockTy->getOptionalErrorResult(),
getASTContext());
// Create the invoke function. Borrow the mangling scheme from reabstraction
// thunks, which is what we are in spirit.
auto thunk = SGM.getOrCreateReabstractionThunk(nullptr,
invokeTy,
fnTy,
blockTy,
F.isFragile());
// Build it if necessary.
if (thunk->empty()) {
SILGenFunction thunkSGF(SGM, *thunk);
auto loc = RegularLocation::getAutoGeneratedLocation();
buildFuncToBlockInvokeBody(thunkSGF, loc, blockTy, storageTy, fnTy);
}
// Form the block on the stack.
auto storageAddrTy = SILType::getPrimitiveAddressType(storageTy);
auto storage = emitTemporaryAllocation(loc, storageAddrTy);
auto capture = B.createProjectBlockStorage(loc, storage);
// Store the function to the block without claiming it, so that it still
// gets cleaned up in scope. Copying the block will create an independent
// reference.
B.createStore(loc, fn.getValue(), capture);
auto invokeFn = B.createFunctionRef(loc, thunk);
auto stackBlock = B.createInitBlockStorageHeader(loc, storage, invokeFn,
SILType::getPrimitiveObjectType(blockTy));
// Copy the block so we have an independent heap object we can hand off.
auto heapBlock = B.createCopyBlock(loc, stackBlock);
return emitManagedRValueWithCleanup(heapBlock);
}
static ManagedValue emitNativeToCBridgedNonoptionalValue(SILGenFunction &gen,
SILLocation loc,
ManagedValue v,
SILType bridgedTy) {
CanType loweredBridgedTy = bridgedTy.getSwiftRValueType();
CanType loweredNativeTy = v.getType().getSwiftRValueType();
if (loweredNativeTy == 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 (loweredNativeTy == gen.SGM.Types.get##NativeType##Type() \
&& loweredBridgedTy == gen.SGM.Types.get##BridgedType##Type()) { \
return emitBridge##NativeType##To##BridgedType(gen, loc, v); \
}
#include "swift/SIL/BridgedTypes.def"
// Bridge thick to Objective-C metatypes.
if (auto bridgedMetaTy = dyn_cast<AnyMetatypeType>(loweredBridgedTy)) {
if (bridgedMetaTy->getRepresentation() == MetatypeRepresentation::ObjC) {
SILValue native = gen.B.emitThickToObjCMetatype(loc, v.getValue(),
SILType::getPrimitiveObjectType(loweredBridgedTy));
return ManagedValue(native, v.getCleanup());
}
}
// Bridge native functions to blocks.
auto bridgedFTy = dyn_cast<SILFunctionType>(loweredBridgedTy);
if (bridgedFTy
&& bridgedFTy->getRepresentation() == SILFunctionType::Representation::Block){
auto nativeFTy = cast<SILFunctionType>(loweredNativeTy);
if (nativeFTy->getRepresentation() != SILFunctionType::Representation::Block)
return gen.emitFuncToBlock(loc, v, bridgedFTy);
}
// Bridge Array to NSArray.
if (auto arrayDecl = gen.getASTContext().getArrayDecl()) {
if (v.getType().getSwiftRValueType().getAnyNominal() == arrayDecl) {
SILDeclRef bridgeFn = gen.SGM.getArrayToNSArrayFn();
return emitBridgeCollectionFromNative(gen, loc, bridgeFn, v, bridgedTy);
}
}
// Bridge Dictionary to NSDictionary.
if (auto dictDecl = gen.getASTContext().getDictionaryDecl()) {
if (v.getType().getSwiftRValueType().getAnyNominal() == dictDecl) {
SILDeclRef bridgeFn = gen.SGM.getDictionaryToNSDictionaryFn();
return emitBridgeCollectionFromNative(gen, loc, bridgeFn, v, bridgedTy);
}
}
// Bridge Set to NSSet.
if (auto setDecl = gen.getASTContext().getSetDecl()) {
if (v.getType().getSwiftRValueType().getAnyNominal() == setDecl) {
SILDeclRef bridgeFn = gen.SGM.getSetToNSSetFn();
return emitBridgeCollectionFromNative(gen, loc, bridgeFn, v, bridgedTy);
}
}
return v;
}
static ManagedValue emitNativeToCBridgedValue(SILGenFunction &gen,
SILLocation loc,
ManagedValue v,
SILType bridgedTy) {
CanType loweredBridgedTy = bridgedTy.getSwiftRValueType();
CanType loweredNativeTy = v.getType().getSwiftRValueType();
if (loweredNativeTy == loweredBridgedTy)
return v;
if (loweredNativeTy.getAnyOptionalObjectType()) {
return gen.emitOptionalToOptional(loc, v, bridgedTy,
emitNativeToCBridgedValue);
}
// Check if we need to wrap the bridged result in an optional.
OptionalTypeKind OTK;
if (SILType bridgedObjectType =
bridgedTy.getAnyOptionalObjectType(gen.SGM.M, OTK)) {
auto bridgedPayload
= emitNativeToCBridgedNonoptionalValue(gen, loc, v, bridgedObjectType);
return gen.getOptionalSomeValue(loc, bridgedPayload,
gen.getTypeLowering(bridgedTy));
}
return emitNativeToCBridgedNonoptionalValue(gen, loc, v, bridgedTy);
}
ManagedValue SILGenFunction::emitNativeToBridgedValue(SILLocation loc,
ManagedValue v,
SILFunctionTypeRepresentation destRep,
AbstractionPattern origNativeTy,
CanType substNativeTy,
CanType loweredBridgedTy){
switch (getSILFunctionLanguage(destRep)) {
case SILFunctionLanguage::Swift:
// No additional bridging needed for native functions.
return v;
case SILFunctionLanguage::C:
return emitNativeToCBridgedValue(*this, loc, v,
SILType::getPrimitiveObjectType(loweredBridgedTy));
}
llvm_unreachable("bad CC");
}
static void buildBlockToFuncThunkBody(SILGenFunction &gen,
SILLocation loc,
CanSILFunctionType blockTy,
CanSILFunctionType funcTy) {
// Collect the native arguments, which should all be +1.
Scope scope(gen.Cleanups, CleanupLocation::get(loc));
assert(blockTy->getParameters().size()
== funcTy->getParameters().size()
&& "block and function types don't match");
SmallVector<ManagedValue, 4> args;
SILBasicBlock *entry = &*gen.F.begin();
for (unsigned i : indices(funcTy->getParameters())) {
auto &param = funcTy->getParameters()[i];
auto &blockParam = blockTy->getParameters()[i];
auto &tl = gen.getTypeLowering(param.getSILType());
assert((tl.isTrivial()
? param.getConvention() == ParameterConvention::Direct_Unowned
: param.getConvention() == ParameterConvention::Direct_Owned)
&& "nonstandard conventions for native functions not implemented");
SILValue v = new (gen.SGM.M) SILArgument(entry, param.getSILType());
auto mv = gen.emitManagedRValueWithCleanup(v, tl);
args.push_back(gen.emitNativeToBridgedValue(loc, mv,
SILFunctionTypeRepresentation::Block,
AbstractionPattern(param.getType()),
param.getType(),
blockParam.getType()));
}
// Add the block argument.
SILValue blockV
= new (gen.SGM.M) SILArgument(entry,
SILType::getPrimitiveObjectType(blockTy));
ManagedValue block = gen.emitManagedRValueWithCleanup(blockV);
// Call the block.
assert(!funcTy->hasIndirectResult()
&& "block thunking func with indirect result not supported");
ManagedValue result = gen.emitMonomorphicApply(loc, block, args,
funcTy->getSILResult().getSwiftRValueType(),
ApplyOptions::None,
/*override CC*/ SILFunctionTypeRepresentation::Block,
/*foreign error*/ None);
// Return the result at +1.
auto &resultTL = gen.getTypeLowering(funcTy->getSILResult());
auto convention = funcTy->getResult().getConvention();
assert((resultTL.isTrivial()
? convention == ResultConvention::Unowned
: convention == ResultConvention::Owned)
&& "nonstandard conventions for return not implemented");
(void)convention;
(void)resultTL;
auto r = result.forward(gen);
scope.pop();
gen.B.createReturn(loc, r);
}
/// Bridge a native function to a block with a thunk.
ManagedValue
SILGenFunction::emitBlockToFunc(SILLocation loc,
ManagedValue block,
CanSILFunctionType funcTy) {
CanSILFunctionType substFnTy;
SmallVector<Substitution, 4> subs;
// Declare the thunk.
auto blockTy = block.getType().castTo<SILFunctionType>();
auto thunkTy = buildThunkType(block, funcTy, substFnTy, subs);
auto thunk = SGM.getOrCreateReabstractionThunk(F.getContextGenericParams(),
thunkTy,
blockTy,
funcTy,
F.isFragile());
// Build it if necessary.
if (thunk->empty()) {
SILGenFunction thunkSGF(SGM, *thunk);
thunk->setContextGenericParams(F.getContextGenericParams());
auto loc = RegularLocation::getAutoGeneratedLocation();
buildBlockToFuncThunkBody(thunkSGF, loc, blockTy, funcTy);
}
// Create it in the current function.
auto thunkValue = B.createFunctionRef(loc, thunk);
auto thunkedFn = B.createPartialApply(loc, thunkValue,
SILType::getPrimitiveObjectType(substFnTy),
subs, block.forward(*this),
SILType::getPrimitiveObjectType(funcTy));
return emitManagedRValueWithCleanup(thunkedFn);
}
static ManagedValue emitCBridgedToNativeValue(SILGenFunction &gen,
SILLocation loc,
ManagedValue v,
SILType nativeTy) {
CanType loweredNativeTy = nativeTy.getSwiftRValueType();
CanType loweredBridgedTy = v.getType().getSwiftRValueType();
if (loweredNativeTy == loweredBridgedTy)
return v;
if (loweredNativeTy.getAnyOptionalObjectType()) {
return gen.emitOptionalToOptional(loc, v, nativeTy,
emitCBridgedToNativeValue);
}
// Bridge Bool to ObjCBool or DarwinBoolean when requested.
if (loweredNativeTy == gen.SGM.Types.getBoolType()) {
if (loweredBridgedTy == gen.SGM.Types.getObjCBoolType()) {
return emitBridgeForeignBoolToBool(gen, loc, v,
gen.SGM.getObjCBoolToBoolFn());
}
if (loweredBridgedTy == gen.SGM.Types.getDarwinBooleanType()) {
return emitBridgeForeignBoolToBool(gen, loc, v,
gen.SGM.getDarwinBooleanToBoolFn());
}
}
// Bridge Objective-C to thick metatypes.
if (auto bridgedMetaTy = dyn_cast<AnyMetatypeType>(loweredBridgedTy)){
if (bridgedMetaTy->getRepresentation() == MetatypeRepresentation::ObjC) {
SILValue native = gen.B.emitObjCToThickMetatype(loc, v.getValue(),
gen.getLoweredType(loweredNativeTy));
return ManagedValue(native, v.getCleanup());
}
}
// Bridge blocks back into native function types.
auto bridgedFTy = dyn_cast<SILFunctionType>(loweredBridgedTy);
if (bridgedFTy
&& bridgedFTy->getRepresentation() == SILFunctionType::Representation::Block){
auto nativeFTy = cast<SILFunctionType>(loweredNativeTy);
if (nativeFTy->getRepresentation() != SILFunctionType::Representation::Block)
return gen.emitBlockToFunc(loc, v, nativeFTy);
}
// Bridge NSString to String.
if (auto stringDecl = gen.getASTContext().getStringDecl()) {
if (nativeTy.getSwiftRValueType()->getAnyNominal() == stringDecl) {
return emitBridgeNSStringToString(gen, loc, v);
}
}
// Bridge NSArray to Array.
if (auto arrayDecl = gen.getASTContext().getArrayDecl()) {
if (nativeTy.getSwiftRValueType()->getAnyNominal() == arrayDecl) {
SILDeclRef bridgeFn = gen.SGM.getNSArrayToArrayFn();
return emitBridgeCollectionToNative(gen, loc, bridgeFn, v, nativeTy);
}
}
// Bridge NSDictionary to Dictionary.
if (auto dictDecl = gen.getASTContext().getDictionaryDecl()) {
if (nativeTy.getSwiftRValueType()->getAnyNominal() == dictDecl) {
SILDeclRef bridgeFn = gen.SGM.getNSDictionaryToDictionaryFn();
return emitBridgeCollectionToNative(gen, loc, bridgeFn, v, nativeTy);
}
}
// Bridge NSSet to Set.
if (auto setDecl = gen.getASTContext().getSetDecl()) {
if (nativeTy.getSwiftRValueType()->getAnyNominal() == setDecl) {
SILDeclRef bridgeFn = gen.SGM.getNSSetToSetFn();
return emitBridgeCollectionToNative(gen, loc, bridgeFn, v, nativeTy);
}
}
return v;
}
ManagedValue SILGenFunction::emitBridgedToNativeValue(SILLocation loc,
ManagedValue v,
SILFunctionTypeRepresentation srcRep,
CanType nativeTy) {
switch (getSILFunctionLanguage(srcRep)) {
case SILFunctionLanguage::Swift:
// No additional bridging needed for native functions.
return v;
case SILFunctionLanguage::C:
return emitCBridgedToNativeValue(*this, loc, v, getLoweredType(nativeTy));
}
llvm_unreachable("bad CC");
}
/// Bridge an optional foreign error type to ErrorType.
ManagedValue SILGenFunction::emitBridgedToNativeError(SILLocation loc,
ManagedValue bridgedError) {
#ifndef NDEBUG
{
OptionalTypeKind optKind;
auto objType = bridgedError.getType().getSwiftRValueType()
.getAnyOptionalObjectType(optKind);
assert(optKind == OTK_Optional && "not Optional type");
assert(objType == SGM.Types.getNSErrorType() &&
"only handling NSError for now");
}
#endif
auto bridgeFn = emitGlobalFunctionRef(loc, SGM.getNSErrorToErrorTypeFn());
auto bridgeFnType = bridgeFn.getType().castTo<SILFunctionType>();
auto nativeErrorType = bridgeFnType->getResult().getSILType();
assert(bridgeFnType->getResult().getConvention() == ResultConvention::Owned);
assert(bridgeFnType->getParameters()[0].getConvention()
== ParameterConvention::Direct_Owned);
SILValue nativeError = B.createApply(loc, bridgeFn, bridgeFn.getType(),
nativeErrorType, {},
bridgedError.forward(*this));
return emitManagedRValueWithCleanup(nativeError);
}
/// Bridge ErrorType to a foreign error type.
ManagedValue SILGenFunction::emitNativeToBridgedError(SILLocation loc,
ManagedValue nativeError,
CanType bridgedErrorType) {
assert(bridgedErrorType == SGM.Types.getNSErrorType() &&
"only handling NSError for now");
auto bridgeFn = emitGlobalFunctionRef(loc, SGM.getErrorTypeToNSErrorFn());
auto bridgeFnType = bridgeFn.getType().castTo<SILFunctionType>();
assert(bridgeFnType->getResult().getConvention() == ResultConvention::Owned);
assert(bridgeFnType->getParameters()[0].getConvention()
== ParameterConvention::Direct_Owned);
SILValue bridgedError = B.createApply(loc, bridgeFn, bridgeFn.getType(),
bridgeFnType->getResult().getSILType(),
{}, nativeError.forward(*this));
return emitManagedRValueWithCleanup(bridgedError);
}
//===----------------------------------------------------------------------===//
// ObjC method thunks
//===----------------------------------------------------------------------===//
static SILValue emitBridgeReturnValue(SILGenFunction &gen,
SILLocation loc,
SILValue result,
SILFunctionTypeRepresentation fnTypeRepr,
AbstractionPattern origNativeTy,
CanType substNativeTy,
CanType bridgedTy) {
Scope scope(gen.Cleanups, CleanupLocation::get(loc));
ManagedValue native = gen.emitManagedRValueWithCleanup(result);
ManagedValue bridged = gen.emitNativeToBridgedValue(loc, native, fnTypeRepr,
origNativeTy, substNativeTy, bridgedTy);
return bridged.forward(gen);
}
/// Take a return value at +1 and adjust it to the retain count
/// expected by the given ownership conventions.
static void emitObjCReturnValue(SILGenFunction &gen,
SILLocation loc,
SILValue result,
SILResultInfo resultInfo) {
assert(result.getType() == resultInfo.getSILType());
// Autorelease the bridged result if necessary.
switch (resultInfo.getConvention()) {
case ResultConvention::Autoreleased:
gen.B.createAutoreleaseReturn(loc, result);
return;
case ResultConvention::UnownedInnerPointer:
case ResultConvention::Unowned:
assert(gen.getTypeLowering(result.getType()).isTrivial()
&& "nontrivial result is returned unowned?!");
SWIFT_FALLTHROUGH;
case ResultConvention::Owned:
gen.B.createReturn(loc, result);
return;
}
}
/// Take an argument at +0 and bring it to +1.
static SILValue emitObjCUnconsumedArgument(SILGenFunction &gen,
SILLocation loc,
SILValue arg) {
auto &lowering = gen.getTypeLowering(arg.getType());
// If address-only, make a +1 copy and operate on that.
if (lowering.isAddressOnly()) {
auto tmp = gen.emitTemporaryAllocation(loc, arg.getType().getObjectType());
gen.B.createCopyAddr(loc, arg, tmp, IsNotTake, IsInitialization);
return tmp;
}
lowering.emitRetainValue(gen.B, loc, arg);
return arg;
}
/// Bridge argument types and adjust retain count conventions for an ObjC thunk.
static SILFunctionType *emitObjCThunkArguments(SILGenFunction &gen,
SILLocation loc,
SILDeclRef thunk,
SmallVectorImpl<SILValue> &args,
SILValue &foreignErrorSlot,
Optional<ForeignErrorConvention> &foreignError) {
SILDeclRef native = thunk.asForeign(false);
auto mod = gen.SGM.M.getSwiftModule();
auto subs = gen.F.getForwardingSubstitutions();
auto objcInfo = gen.SGM.Types.getConstantInfo(thunk);
auto objcFnTy = objcInfo.SILFnType->substGenericArgs(gen.SGM.M, mod, subs);
auto swiftInfo = gen.SGM.Types.getConstantInfo(native);
auto swiftFnTy = swiftInfo.SILFnType->substGenericArgs(gen.SGM.M, mod, subs);
// We must have the same context archetypes as the unthunked function.
assert(objcInfo.ContextGenericParams == swiftInfo.ContextGenericParams);
SmallVector<ManagedValue, 8> bridgedArgs;
bridgedArgs.reserve(objcFnTy->getParameters().size());
SILFunction *orig = gen.SGM.getFunction(native, NotForDefinition);
// Find the foreign error convention if we have one.
if (orig->getLoweredFunctionType()->hasErrorResult()) {
auto func = cast<AbstractFunctionDecl>(thunk.getDecl());
foreignError = func->getForeignErrorConvention();
assert(foreignError && "couldn't find foreign error convention!");
}
// Emit the indirect return argument, if any.
if (objcFnTy->hasIndirectResult()) {
SILType argTy = gen.F.mapTypeIntoContext(
objcFnTy->getIndirectResult().getSILType());
auto arg = new (gen.F.getModule()) SILArgument(gen.F.begin(), argTy);
bridgedArgs.push_back(ManagedValue::forUnmanaged(arg));
}
// Emit the other arguments, taking ownership of arguments if necessary.
auto inputs = objcFnTy->getParametersWithoutIndirectResult();
auto nativeInputs = swiftFnTy->getParametersWithoutIndirectResult();
assert(inputs.size() ==
nativeInputs.size() + unsigned(foreignError.hasValue()));
for (unsigned i = 0, e = inputs.size(); i < e; ++i) {
SILType argTy = gen.F.mapTypeIntoContext(inputs[i].getSILType());
SILValue arg = new(gen.F.getModule()) SILArgument(gen.F.begin(), argTy);
// If this parameter is the foreign error slot, pull it out.
// It does not correspond to a native argument.
if (foreignError && i == foreignError->getErrorParameterIndex()) {
foreignErrorSlot = arg;
continue;
}
// If this parameter is deallocating, emit an unmanaged rvalue and
// continue. The object has the deallocating bit set so retain, release is
// irrelevent.
if (inputs[i].isDeallocating()) {
bridgedArgs.push_back(ManagedValue::forUnmanaged(arg));
continue;
}
// If the argument is a block, copy it.
if (argTy.isBlockPointerCompatible()) {
auto copy = gen.B.createCopyBlock(loc, arg);
// If the argument is consumed, we're still responsible for releasing the
// original.
if (inputs[i].isConsumed())
gen.emitManagedRValueWithCleanup(arg);
arg = copy;
}
// Convert the argument to +1 if necessary.
else if (!inputs[i].isConsumed()) {
arg = emitObjCUnconsumedArgument(gen, loc, arg);
}
auto managedArg = gen.emitManagedRValueWithCleanup(arg);
bridgedArgs.push_back(managedArg);
}
assert(bridgedArgs.size() + unsigned(foreignError.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.
Scope scope(gen.Cleanups, CleanupLocation::get(loc));
assert(bridgedArgs.size() == nativeInputs.size());
for (unsigned i = 0, size = bridgedArgs.size(); i < size; ++i) {
SILType argTy = gen.F.mapTypeIntoContext(
swiftFnTy->getParameters()[i].getSILType());
ManagedValue native =
gen.emitBridgedToNativeValue(loc,
bridgedArgs[i],
SILFunctionTypeRepresentation::ObjCMethod,
argTy.getSwiftType());
SILValue argValue;
if (nativeInputs[i].isConsumed())
argValue = native.forward(gen);
else
argValue = native.getValue();
args.push_back(argValue);
}
return objcFnTy;
}
void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
assert(thunk.isForeign);
SILDeclRef native = thunk.asForeign(false);
auto loc = thunk.getAsRegularLocation();
loc.markAutoGenerated();
Scope scope(Cleanups, CleanupLocation::get(loc));
// Bridge the arguments.
SmallVector<SILValue, 4> args;
Optional<ForeignErrorConvention> foreignError;
SILValue foreignErrorSlot;
auto objcFnTy = emitObjCThunkArguments(*this, loc, thunk, args,
foreignErrorSlot, foreignError);
auto nativeInfo = getConstantInfo(native);
auto swiftResultTy = nativeInfo.SILFnType->getResult()
.map([&](CanType t) { return F.mapTypeIntoContext(t)->getCanonicalType(); });
auto objcResultTy = objcFnTy->getResult()
.map([&](CanType t) { return F.mapTypeIntoContext(t)->getCanonicalType(); });
// Call the native entry point.
SILValue nativeFn = emitGlobalFunctionRef(loc, native, nativeInfo);
auto subs = F.getForwardingSubstitutions();
auto substTy = nativeInfo.SILFnType->substGenericArgs(
SGM.M, SGM.M.getSwiftModule(), subs);
SILType substSILTy = SILType::getPrimitiveObjectType(substTy);
CanType substNativeResultType = nativeInfo.LoweredType.getResult();
AbstractionPattern origNativeResultType =
AbstractionPattern(substNativeResultType);
CanType bridgedResultType = objcResultTy.getType();
SILValue result;
assert(foreignError.hasValue() == substTy->hasErrorResult());
if (!substTy->hasErrorResult()) {
// Create the apply.
result = B.createApply(loc, nativeFn, substSILTy,
swiftResultTy.getSILType(), subs, args);
// Leave the scope immediately. This isn't really necessary; it
// just limits lifetimes a little bit more.
scope.pop();
// Now bridge the return value.
result = emitBridgeReturnValue(*this, loc, result,
objcFnTy->getRepresentation(),
origNativeResultType,
substNativeResultType,
bridgedResultType);
} else {
SILBasicBlock *contBB = createBasicBlock();
SILBasicBlock *errorBB = createBasicBlock();
SILBasicBlock *normalBB = createBasicBlock();
B.createTryApply(loc, nativeFn, substSILTy, subs, args,
normalBB, errorBB);
// Emit the non-error destination.
{
B.emitBlock(normalBB);
SILValue nativeResult =
normalBB->createBBArg(swiftResultTy.getSILType());
// 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,
objcFnTy->getRepresentation(),
origNativeResultType,
substNativeResultType,
objcResultTy.getSILType(),
foreignErrorSlot, *foreignError);
B.createBranch(loc, contBB, bridgedResult);
}
// Emit the error destination.
{
B.emitBlock(errorBB);
SILValue nativeError =
errorBB->createBBArg(substTy->getErrorResult().getSILType());
// 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.getSILType(),
foreignErrorSlot, *foreignError);
B.createBranch(loc, contBB, bridgedResult);
}
// Emit the join block.
B.emitBlock(contBB);
result = contBB->createBBArg(objcResultTy.getSILType());
// Leave the scope now.
scope.pop();
}
emitObjCReturnValue(*this, loc, result, objcResultTy);
}
static SILValue
getThunkedForeignFunctionRef(SILGenFunction &gen,
SILLocation loc,
SILDeclRef foreign,
ArrayRef<ManagedValue> args,
const SILConstantInfo &foreignCI) {
assert(!foreign.isCurried
&& "should not thunk calling convention when curried");
// Produce a class_method when thunking ObjC methods.
auto foreignTy = foreignCI.SILFnType;
if (foreignTy->getRepresentation()
== SILFunctionTypeRepresentation::ObjCMethod) {
SILValue thisArg = args.back().getValue();
return gen.B.createClassMethod(loc, thisArg, foreign,
SILType::getPrimitiveObjectType(foreignCI.SILFnType),
/*volatile*/ true);
}
// Otherwise, emit a function_ref.
return gen.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(thunk);
auto nativeFormalResultTy = nativeCI.LoweredInterfaceType.getResult();
auto nativeFnTy = F.getLoweredFunctionType();
assert(nativeFnTy == nativeCI.SILFnType);
// Find the foreign error convention.
Optional<ForeignErrorConvention> foreignError;
if (nativeFnTy->hasErrorResult()) {
foreignError = fd->getForeignErrorConvention();
assert(foreignError && "couldn't find foreign error convention!");
}
// Forward the arguments.
auto forwardedPatterns = fd->getBodyParamPatterns();
// 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) {
allocatorSelfType = forwardedPatterns[0]->getType();
forwardedPatterns = forwardedPatterns.slice(1);
}
SmallVector<SILValue, 8> params;
for (auto *paramPattern : reversed(forwardedPatterns))
bindParametersForForwarding(paramPattern, params);
if (allocatorSelfType) {
auto selfMetatype = CanMetatypeType::get(allocatorSelfType->getCanonicalType(),
MetatypeRepresentation::Thick);
auto selfArg = new (F.getModule()) SILArgument(
F.begin(),
SILType::getPrimitiveObjectType(selfMetatype),
fd->getImplicitSelfDecl());
params.push_back(selfArg);
}
// Set up the throw destination if necessary.
CleanupLocation cleanupLoc(fd);
if (foreignError) {
prepareRethrowEpilog(cleanupLoc);
}
SILValue result;
{
Scope scope(Cleanups, fd);
SILDeclRef foreignDeclRef = thunk.asForeign(true);
SILConstantInfo foreignCI = getConstantInfo(foreignDeclRef);
auto foreignFnTy = foreignCI.SILFnType;
// Bridge all the arguments.
SmallVector<ManagedValue, 8> args;
unsigned foreignArgIndex = 0;
// A helper function to add a function error argument in the
// appropriate position.
auto maybeAddForeignErrorArg = [&] {
if (foreignError &&
foreignArgIndex == foreignError->getErrorParameterIndex()) {
args.push_back(ManagedValue());
foreignArgIndex++;
}
};
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::Direct_Deallocating:
param = ManagedValue::forUnmanaged(paramValue);
break;
case ParameterConvention::Indirect_Inout:
param = ManagedValue::forUnmanaged(paramValue);
break;
case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_In_Guaranteed:
case ParameterConvention::Indirect_Out:
llvm_unreachable("indirect args in foreign thunked method not implemented");
}
maybeAddForeignErrorArg();
SILType foreignArgTy =
foreignFnTy->getParameters()[foreignArgIndex++].getSILType();
args.push_back(emitNativeToBridgedValue(fd, param,
SILFunctionTypeRepresentation::CFunctionPointer,
AbstractionPattern(param.getSwiftType()),
param.getSwiftType(),
foreignArgTy.getSwiftRValueType()));
}
maybeAddForeignErrorArg();
// Call the original.
auto fn = getThunkedForeignFunctionRef(*this, fd, foreignDeclRef, args,
foreignCI);
result = emitMonomorphicApply(fd, ManagedValue::forUnmanaged(fn),
args,
nativeFormalResultTy,
ApplyOptions::None, None, foreignError)
.forward(*this);
}
B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(fd), result);
// Emit the throw destination.
emitRethrowEpilog(fd);
}