Exemple #1
0
/// 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);
}
Exemple #2
0
/// 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);
}
Exemple #3
0
/// 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);
}