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 ¶m = 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); }
static SILValue emitBridgeReturnValue(SILGenFunction &gen, SILLocation loc, SILValue result, SILFunctionTypeRepresentation fnTypeRepr, CanType bridgedTy) { Scope scope(gen.Cleanups, CleanupLocation::get(loc)); ManagedValue native = gen.emitManagedRValueWithCleanup(result); ManagedValue bridged = gen.emitNativeToBridgedValue(loc, native, fnTypeRepr, bridgedTy); return bridged.forward(gen); }
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 ¶m = 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_InoutAliasable: 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_InoutAliasable: 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->hasIndirectResults() && "block thunking func with indirect result not supported"); assert(funcTy->getNumDirectResults() <= 1 && "block thunking func with multiple results not supported"); ManagedValue result = gen.emitMonomorphicApply(loc, fn, args, funcTy->getSILResult().getSwiftRValueType(), ApplyOptions::None, None, None) .getAsSingleValue(gen, loc); // Bridge the result back to ObjC. result = gen.emitNativeToBridgedValue(loc, result, SILFunctionTypeRepresentation::CFunctionPointer, blockTy->getSILResult().getSwiftRValueType()); auto resultVal = result.forward(gen); scope.pop(); gen.B.createReturn(loc, resultVal); }