/// 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 &gen, SILLocation loc, ManagedValue swiftValue) { // Dig out the nominal type we're bridging from. Type swiftValueType = swiftValue.getSwiftType()->getRValueType(); // Dig out its conformance to _ObjectiveCBridgeable. auto conformance = gen.SGM.getConformanceToObjectiveCBridgeable(loc, swiftValueType); if (!conformance) return None; return emitBridgeNativeToObjectiveC(gen, loc, swiftValue, conformance); }
/// 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 &gen, SILLocation loc, ManagedValue swiftValue, ProtocolConformance *conformance) { // Dig out the nominal type we're bridging from. Type swiftValueType = swiftValue.getSwiftType()->getRValueType(); // Find the _bridgeToObjectiveC requirement. auto requirement = gen.SGM.getBridgeToObjectiveCRequirement(loc); if (!requirement) return None; // Retrieve the _bridgeToObjectiveC witness. auto witness = conformance->getWitness(requirement, nullptr); assert(witness); // Determine the type we're bridging to. auto objcTypeReq = gen.SGM.getBridgedObjectiveCTypeRequirement(loc); if (!objcTypeReq) return None; Type objcType = conformance->getTypeWitness(objcTypeReq, nullptr).getReplacement(); assert(objcType); // Create a reference to the witness. SILDeclRef witnessConstant(witness.getDecl()); auto witnessRef = gen.emitGlobalFunctionRef(loc, witnessConstant); // Determine the substitutions. ArrayRef<Substitution> substitutions; auto witnessFnTy = witnessRef->getType(); if (auto valueTypeBGT = swiftValueType->getAs<BoundGenericType>()) { // Compute the substitutions. substitutions = valueTypeBGT->getSubstitutions(gen.SGM.SwiftModule, nullptr); // Substitute into the witness function tye. witnessFnTy = witnessFnTy.substGenericArgs(gen.SGM.M, substitutions); } // Call the witness. SILType resultTy = gen.getLoweredType(objcType); SILValue bridgedValue = gen.B.createApply(loc, witnessRef, witnessFnTy, resultTy, substitutions, swiftValue.borrow() .getUnmanagedValue()); return gen.emitManagedRValueWithCleanup(bridgedValue); }
/// 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 forwardedParameters = fd->getParameterLists(); // 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 = forwardedParameters[0]->getType(getASTContext()); forwardedParameters = forwardedParameters.slice(1); } SmallVector<SILValue, 8> params; for (auto *paramList : reversed(forwardedParameters)) bindParametersForForwarding(paramList, 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: case ParameterConvention::Indirect_InoutAliasable: 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 subs = getForwardingSubstitutions(); auto fn = getThunkedForeignFunctionRef(*this, fd, foreignDeclRef, args, subs, foreignCI); auto fnType = fn.getType().castTo<SILFunctionType>(); fnType = fnType->substGenericArgs(SGM.M, SGM.SwiftModule, subs); result = emitApply(fd, ManagedValue::forUnmanaged(fn), subs, args, fnType, AbstractionPattern(nativeFormalResultTy), nativeFormalResultTy, ApplyOptions::None, None, foreignError, SGFContext()) .forward(*this); } B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(fd), result); // Emit the throw destination. emitRethrowEpilog(fd); }