Example #1
0
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);
}
Example #2
0
static RValue emitImplicitValueConstructorArg(SILGenFunction &SGF,
                                              SILLocation loc,
                                              CanType interfaceType,
                                              DeclContext *DC) {
  auto type = DC->mapTypeIntoContext(interfaceType)->getCanonicalType();

  // Restructure tuple arguments.
  if (auto tupleTy = dyn_cast<TupleType>(interfaceType)) {
    RValue tuple(type);
    for (auto fieldType : tupleTy.getElementTypes())
      tuple.addElement(emitImplicitValueConstructorArg(SGF, loc, fieldType, DC));
    return tuple;
  }

  auto &AC = SGF.getASTContext();
  auto VD = new (AC) ParamDecl(VarDecl::Specifier::Default, SourceLoc(), SourceLoc(),
                               AC.getIdentifier("$implicit_value"),
                               SourceLoc(),
                               AC.getIdentifier("$implicit_value"), Type(),
                               DC);
  VD->setInterfaceType(interfaceType);
  SILFunctionArgument *arg =
      SGF.F.begin()->createFunctionArgument(SGF.getLoweredType(type), VD);
  ManagedValue mvArg;
  if (arg->getArgumentConvention().isOwnedConvention()) {
    mvArg = SGF.emitManagedRValueWithCleanup(arg);
  } else {
    mvArg = ManagedValue::forUnmanaged(arg);
  }
  return RValue(SGF, loc, type, mvArg);
}
Example #3
0
static RValue emitImplicitValueConstructorArg(SILGenFunction &gen,
                                              SILLocation loc,
                                              CanType interfaceType,
                                              DeclContext *DC) {
  auto type = DC->mapTypeIntoContext(interfaceType)->getCanonicalType();

  // Restructure tuple arguments.
  if (CanTupleType tupleTy = dyn_cast<TupleType>(interfaceType)) {
    RValue tuple(type);
    for (auto fieldType : tupleTy.getElementTypes())
      tuple.addElement(emitImplicitValueConstructorArg(gen, loc, fieldType, DC));

    return tuple;
  } else {
    auto &AC = gen.getASTContext();
    auto VD = new (AC) ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(),
                                 AC.getIdentifier("$implicit_value"),
                                 SourceLoc(),
                                 AC.getIdentifier("$implicit_value"), Type(),
                                 DC);
    VD->setInterfaceType(interfaceType);
    SILValue arg =
        gen.F.begin()->createFunctionArgument(gen.getLoweredType(type), VD);
    return RValue(gen, loc, type, gen.emitManagedRValueWithCleanup(arg));
  }
}
Example #4
0
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);
}
Example #5
0
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);
}
Example #6
0
/// Specialized emitter for Builtin.castReferenceFromBridgeObject.
static ManagedValue emitBuiltinCastReferenceFromBridgeObject(
                                                  SILGenFunction &gen,
                                                  SILLocation loc,
                                                  SubstitutionList subs,
                                                  ArrayRef<ManagedValue> args,
                                                  CanFunctionType formalApplyType,
                                                  SGFContext C) {
  assert(args.size() == 1 && "cast should have one argument");
  assert(subs.size() == 1 && "cast should have a type substitution");

  // The substitution determines the destination type.
  SILType destType = gen.getLoweredType(subs[0].getReplacement());
  
  // Bail if the source type is not a class reference of some kind.
  if (!subs[0].getReplacement()->isBridgeableObjectType()
      || !destType.isObject()) {
    gen.SGM.diagnose(loc, diag::invalid_sil_builtin,
                 "castReferenceFromBridgeObject dest must be an object type");
    // Recover by propagating an undef result.
    SILValue result = SILUndef::get(destType, gen.SGM.M);
    return ManagedValue::forUnmanaged(result);
  }
  
  SILValue result = gen.B.createBridgeObjectToRef(loc, args[0].forward(gen),
                                                  destType);
  return gen.emitManagedRValueWithCleanup(result);
}
Example #7
0
/// Specialized emitter for Builtin.castReference.
static ManagedValue
emitBuiltinCastReference(SILGenFunction &gen,
                         SILLocation loc,
                         ArrayRef<Substitution> substitutions,
                         ArrayRef<ManagedValue> args,
                         CanFunctionType formalApplyType,
                         SGFContext C) {
  assert(args.size() == 1 && "castReference should be given one argument");
  assert(substitutions.size() == 2 && "castReference should have two subs");

  auto fromTy = substitutions[0].getReplacement();
  auto toTy = substitutions[1].getReplacement();
  auto &fromTL = gen.getTypeLowering(fromTy);
  auto &toTL = gen.getTypeLowering(toTy);
  assert(!fromTL.isTrivial() && !toTL.isTrivial() && "expected ref type");

  if (fromTL.isLoadable() || toTL.isLoadable()) { 
    if (auto refCast = gen.B.tryCreateUncheckedRefCast(loc, args[0].getValue(),
                                                       toTL.getLoweredType())) {
      // Create a reference cast, forwarding the cleanup.
      // The cast takes the source reference.
      return ManagedValue(refCast, args[0].getCleanup());
    }
  }
  // We are either casting between address-only types, or cannot promote to a
  // cast of reference values.
  //
  // If the from/to types are invalid, then use a cast that will fail at
  // runtime. We cannot catch these errors with SIL verification because they
  // may legitimately occur during code specialization on dynamically
  // unreachable paths.
  //
  // TODO: For now, we leave invalid casts in address form so that the runtime
  // will trap. We could emit a noreturn call here instead which would provide
  // more information to the optimizer.
  SILValue srcVal = args[0].forward(gen);
  SILValue fromAddr;
  if (fromTL.isLoadable()) {
    // Move the loadable value into a "source temp".  Since the source and
    // dest are RC identical, store the reference into the source temp without
    // a retain. The cast will load the reference from the source temp and
    // store it into a dest temp effectively forwarding the cleanup.
    fromAddr = gen.emitTemporaryAllocation(loc, srcVal->getType());
    gen.B.createStore(loc, srcVal, fromAddr);
  } else {
    // The cast loads directly from the source address.
    fromAddr = srcVal;
  }
  // Create a "dest temp" to hold the reference after casting it.
  SILValue toAddr = gen.emitTemporaryAllocation(loc, toTL.getLoweredType());
  gen.B.createUncheckedRefCastAddr(loc, fromAddr, fromTy->getCanonicalType(),
                                   toAddr, toTy->getCanonicalType());
  // Forward it along and register a cleanup.
  if (toTL.isAddressOnly())
    return gen.emitManagedBufferWithCleanup(toAddr);

  // Load the destination value.
  auto result = gen.B.createLoad(loc, toAddr);
  return gen.emitManagedRValueWithCleanup(result);
}
/// Emit a copy of this value with independent ownership.
ManagedValue ManagedValue::copy(SILGenFunction &gen, SILLocation l) {
  if (!cleanup.isValid()) {
    assert(gen.getTypeLowering(getType()).isTrivial());
    return *this;
  }
  
  auto &lowering = gen.getTypeLowering(getType());
  assert(!lowering.isTrivial() && "trivial value has cleanup?");
  
  if (!lowering.isAddressOnly()) {
    lowering.emitRetainValue(gen.B, l, getValue());
    return gen.emitManagedRValueWithCleanup(getValue(), lowering);
  }
  
  SILValue buf = gen.emitTemporaryAllocation(l, getType());
  gen.B.createCopyAddr(l, getValue(), buf, IsNotTake, IsInitialization);
  return gen.emitManagedRValueWithCleanup(buf, lowering);
}
Example #9
0
/// This is the same operation as 'copy', but works on +0 values that don't
/// have cleanups.  It returns a +1 value with one.
ManagedValue ManagedValue::copyUnmanaged(SILGenFunction &SGF, SILLocation loc) {
  if (getType().isObject()) {
    return SGF.B.createCopyValue(loc, *this);
  }

  SILValue result = SGF.emitTemporaryAllocation(loc, getType());
  SGF.B.createCopyAddr(loc, getValue(), result, IsNotTake, IsInitialization);
  return SGF.emitManagedRValueWithCleanup(result);
}
Example #10
0
static void boxIndirectEnumPayload(SILGenFunction &gen,
                                   ManagedValue &payload,
                                   SILLocation loc,
                                   EnumElementDecl *element) {
  // If the payload is indirect, we'll need to box it.
  if (payload && (element->isIndirect() ||
                  element->getParentEnum()->isIndirect())) {
    auto box = gen.B.createAllocBox(loc, payload.getType());
    payload.forwardInto(gen, loc, box->getAddressResult());
    payload = gen.emitManagedRValueWithCleanup(box);
  }
}
Example #11
0
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);
}
Example #12
0
/// Emit a copy of this value with independent ownership.
ManagedValue ManagedValue::copy(SILGenFunction &SGF, SILLocation loc) {
  auto &lowering = SGF.getTypeLowering(getType());
  if (lowering.isTrivial())
    return *this;

  if (getType().isObject()) {
    return SGF.B.createCopyValue(loc, *this, lowering);
  }

  SILValue buf = SGF.emitTemporaryAllocation(loc, getType());
  SGF.B.createCopyAddr(loc, getValue(), buf, IsNotTake, IsInitialization);
  return SGF.emitManagedRValueWithCleanup(buf, lowering);
}
Example #13
0
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);
}
Example #14
0
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);
}
Example #15
0
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);
}
Example #16
0
/// Perform a foreign error check by testing whether the call result is nil.
static ManagedValue
emitResultIsNilErrorCheck(SILGenFunction &gen, SILLocation loc,
                          ManagedValue origResult, ManagedValue errorSlot,
                          bool suppressErrorCheck) {
  // Take local ownership of the optional result value.
  SILValue optionalResult = origResult.forward(gen);

  OptionalTypeKind optKind;
  SILType resultObjectType =
    optionalResult->getType().getAnyOptionalObjectType(gen.SGM.M, optKind);

  ASTContext &ctx = gen.getASTContext();

  // If we're suppressing the check, just do an unchecked take.
  if (suppressErrorCheck) {
    SILValue objectResult =
      gen.B.createUncheckedEnumData(loc, optionalResult,
                                    ctx.getOptionalSomeDecl(optKind));
    return gen.emitManagedRValueWithCleanup(objectResult);
  }

  // Switch on the optional result.
  SILBasicBlock *errorBB = gen.createBasicBlock(FunctionSection::Postmatter);
  SILBasicBlock *contBB = gen.createBasicBlock();
  gen.B.createSwitchEnum(loc, optionalResult, /*default*/ nullptr,
                         { { ctx.getOptionalSomeDecl(optKind), contBB },
                           { ctx.getOptionalNoneDecl(optKind), errorBB } });

  // Emit the error block.
  gen.emitForeignErrorBlock(loc, errorBB, errorSlot);

  // In the continuation block, take ownership of the now non-optional
  // result value.
  gen.B.emitBlock(contBB);
  SILValue objectResult = contBB->createBBArg(resultObjectType);
  return gen.emitManagedRValueWithCleanup(objectResult);
}
Example #17
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);
}
Example #18
0
ManagedValue RValue::getAsSingleValue(SILGenFunction &gen, SILLocation l) && {
  // Avoid killing and re-emitting the cleanup if the enclosed value isn't a
  // tuple.
  if (!isa<TupleType>(type)) {
    assert(values.size() == 1 && "exploded non-tuple?!");
    ManagedValue result = values[0];
    makeUsed();
    return result;
  }

  // Forward into a single value, then install a cleanup on the resulting
  // imploded value.
  return gen.emitManagedRValueWithCleanup(
                                std::move(*this).forwardAsSingleValue(gen, l));
}
/// This is the same operation as 'copy', but works on +0 values that don't
/// have cleanups.  It returns a +1 value with one.
ManagedValue ManagedValue::copyUnmanaged(SILGenFunction &gen, SILLocation loc) {
  auto &lowering = gen.getTypeLowering(getType());
  
  if (lowering.isTrivial())
    return *this;
  
  SILValue result;
  if (!lowering.isAddressOnly()) {
    lowering.emitRetainValue(gen.B, loc, getValue());
    result = getValue();
  } else {
    result = gen.emitTemporaryAllocation(loc, getType());
    gen.B.createCopyAddr(loc, getValue(), result, IsNotTake,IsInitialization);
  }
  return gen.emitManagedRValueWithCleanup(result, lowering);
}
Example #20
0
static ManagedValue emitBuiltinTryPin(SILGenFunction &SGF,
                                      SILLocation loc,
                                      SubstitutionList subs,
                                      ArrayRef<ManagedValue> args,
                                      SGFContext C) {
  assert(args.size() == 1);

  if (!requireIsOptionalNativeObject(SGF, loc, subs[0].getReplacement())) {
    return SGF.emitUndef(loc, subs[0].getReplacement());
  }

  // The value was produced at +1, but pinning is only a conditional
  // retain, so we have to leave the cleanup in place.  TODO: try to
  // emit the argument at +0.
  SILValue result =
      SGF.B.createStrongPin(loc, args[0].getValue(), SGF.B.getDefaultAtomicity());

  // The handle, if non-null, is effectively +1.
  return SGF.emitManagedRValueWithCleanup(result);
}
Example #21
0
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);
}
Example #22
0
static RValue emitImplicitValueConstructorArg(SILGenFunction &gen,
                                              SILLocation loc,
                                              CanType ty,
                                              DeclContext *DC) {
  // Restructure tuple arguments.
  if (CanTupleType tupleTy = dyn_cast<TupleType>(ty)) {
    RValue tuple(ty);
    for (auto fieldType : tupleTy.getElementTypes())
      tuple.addElement(emitImplicitValueConstructorArg(gen, loc, fieldType, DC));

    return tuple;
  } else {
    auto &AC = gen.getASTContext();
    auto VD = new (AC) ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(),
                                 AC.getIdentifier("$implicit_value"),
                                 SourceLoc(),
                                 AC.getIdentifier("$implicit_value"), ty, DC);
    SILValue arg = new (gen.F.getModule()) SILArgument(gen.F.begin(),
                                                       gen.getLoweredType(ty),
                                                       VD);
    return RValue(gen, loc, ty, gen.emitManagedRValueWithCleanup(arg));
  }
}
Example #23
0
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_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);
}
Example #24
0
/// Emit a store of a native error to the foreign-error slot.
static void emitStoreToForeignErrorSlot(SILGenFunction &SGF,
                                        SILLocation loc,
                                        SILValue foreignErrorSlot,
                                        const BridgedErrorSource &errorSrc) {
  ASTContext &ctx = SGF.getASTContext();

  // The foreign error slot has type SomePointer<SomeError?>,
  // or possibly an optional thereof.

  // If the pointer itself is optional, we need to branch based on
  // whether it's really there.
  if (SILType errorPtrObjectTy =
          foreignErrorSlot->getType().getOptionalObjectType()) {
    SILBasicBlock *contBB = SGF.createBasicBlock();
    SILBasicBlock *noSlotBB = SGF.createBasicBlock();
    SILBasicBlock *hasSlotBB = SGF.createBasicBlock();
    SGF.B.createSwitchEnum(loc, foreignErrorSlot, nullptr,
                 { { ctx.getOptionalSomeDecl(), hasSlotBB },
                   { ctx.getOptionalNoneDecl(), noSlotBB } });

    // If we have the slot, emit a store to it.
    SGF.B.emitBlock(hasSlotBB);
    SILValue slot = hasSlotBB->createPHIArgument(errorPtrObjectTy,
                                                 ValueOwnershipKind::Owned);
    emitStoreToForeignErrorSlot(SGF, loc, slot, errorSrc);
    SGF.B.createBranch(loc, contBB);

    // Otherwise, just release the error.
    SGF.B.emitBlock(noSlotBB);
    errorSrc.emitRelease(SGF, loc);
    SGF.B.createBranch(loc, contBB);

    // Continue.
    SGF.B.emitBlock(contBB);
    return;
  }

  // Okay, break down the components of SomePointer<SomeError?>.
  // TODO: this should really be an unlowered AST type?
  auto bridgedErrorPtrType = foreignErrorSlot->getType().getASTType();

  PointerTypeKind ptrKind;
  CanType bridgedErrorProto =
    CanType(bridgedErrorPtrType->getAnyPointerElementType(ptrKind));

  FullExpr scope(SGF.Cleanups, CleanupLocation::get(loc));
  FormalEvaluationScope writebacks(SGF);

  // Convert the error to a bridged form.
  SILValue bridgedError = errorSrc.emitBridged(SGF, loc, bridgedErrorProto);

  // Store to the "pointee" property.
  // If we can't find it, diagnose and then just don't store anything.
  VarDecl *pointeeProperty = ctx.getPointerPointeePropertyDecl(ptrKind);
  if (!pointeeProperty) {
    SGF.SGM.diagnose(loc, diag::could_not_find_pointer_pointee_property,
                     bridgedErrorPtrType);
    return;
  }

  // Otherwise, do a normal assignment.
  LValue lvalue =
    SGF.emitPropertyLValue(loc, ManagedValue::forUnmanaged(foreignErrorSlot),
                           bridgedErrorPtrType, pointeeProperty,
                           LValueOptions(),
                           AccessKind::Write,
                           AccessSemantics::Ordinary);
  RValue rvalue(SGF, loc, bridgedErrorProto,
                SGF.emitManagedRValueWithCleanup(bridgedError));
  SGF.emitAssignToLValue(loc, std::move(rvalue), std::move(lvalue));
}
Example #25
0
RValue Lowering::emitConditionalCheckedCast(SILGenFunction &SGF,
                                            SILLocation loc,
                                            ManagedValue operand,
                                            Type operandType,
                                            Type optTargetType,
                                            CheckedCastKind castKind,
                                            SGFContext C) {
  // Drill into the result type.
  CanType resultObjectType =
    optTargetType->getCanonicalType().getAnyOptionalObjectType();
  assert(resultObjectType);

  // Handle collection downcasts directly; they have specific library
  // entry points.
  if (castKind == CheckedCastKind::ArrayDowncast ||
      castKind == CheckedCastKind::DictionaryDowncast ||
      castKind == CheckedCastKind::SetDowncast) {
    return emitCollectionDowncastExpr(SGF, operand, operandType, loc,
                                      resultObjectType, C,
                                      /*conditional=*/true);
  }

  operand = adjustForConditionalCheckedCastOperand(loc, operand,
                                               operandType->getCanonicalType(),
                                                   resultObjectType, SGF);

  auto someDecl = SGF.getASTContext().getOptionalSomeDecl();
  auto &resultTL = SGF.getTypeLowering(optTargetType);

  // Set up a result buffer if desirable/required.
  SILValue resultBuffer;
  SILValue resultObjectBuffer;
  Optional<TemporaryInitialization> resultObjectTemp;
  SGFContext resultObjectCtx;
  if (resultTL.isAddressOnly() ||
      (C.getEmitInto() && C.getEmitInto()->getAddressOrNull())) {
    SILType resultTy = resultTL.getLoweredType();
    resultBuffer = SGF.getBufferForExprResult(loc, resultTy, C);
    resultObjectBuffer =
      SGF.B.createInitEnumDataAddr(loc, resultBuffer, someDecl,
                    resultTy.getAnyOptionalObjectType().getAddressType());
    resultObjectTemp.emplace(resultObjectBuffer, CleanupHandle::invalid());
    resultObjectCtx = SGFContext(&resultObjectTemp.getValue());
  }

  // Prepare a jump destination here.
  ExitableFullExpr scope(SGF, CleanupLocation::get(loc));

  auto operandCMV = ConsumableManagedValue::forOwned(operand);
  SGF.emitCheckedCastBranch(loc, operandCMV, operandType,
                            resultObjectType, resultObjectCtx,
    // The success path.
    [&](ManagedValue objectValue) {
      // If we're not emitting into a temporary, just wrap up the result
      // in Some and go to the continuation block.
      if (!resultObjectTemp) {
        auto some = SGF.B.createEnum(loc, objectValue.forward(SGF),
                                     someDecl, resultTL.getLoweredType());
        SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, { some });
        return;
      }

      // Otherwise, make sure the value is in the context.
      if (!objectValue.isInContext()) {
        objectValue.forwardInto(SGF, loc, resultObjectBuffer);
      }
      SGF.B.createInjectEnumAddr(loc, resultBuffer, someDecl);
      SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc);
    },
    // The failure path.
    [&] {
      auto noneDecl = SGF.getASTContext().getOptionalNoneDecl();

      // If we're not emitting into a temporary, just wrap up the result
      // in None and go to the continuation block.
      if (!resultObjectTemp) {
        auto none =
          SGF.B.createEnum(loc, nullptr, noneDecl, resultTL.getLoweredType());
        SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, { none });

      // Just construct the enum directly in the context.
      } else {
        SGF.B.createInjectEnumAddr(loc, resultBuffer, noneDecl);
        SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc);
      }
    });

  // Enter the continuation block.
  auto contBB = scope.exit();

  ManagedValue result;
  if (resultObjectTemp) {
    result = SGF.manageBufferForExprResult(resultBuffer, resultTL, C);
  } else {
    auto argument =
      new (SGF.F.getModule()) SILArgument(contBB, resultTL.getLoweredType());
    result = SGF.emitManagedRValueWithCleanup(argument, resultTL);
  }

  return RValue(SGF, loc, optTargetType->getCanonicalType(), result);
}
Example #26
0
/// Emit a store of a native error to the foreign-error slot.
static void emitStoreToForeignErrorSlot(SILGenFunction &gen,
                                        SILLocation loc,
                                        SILValue foreignErrorSlot,
                                        const BridgedErrorSource &errorSrc) {
  ASTContext &ctx = gen.getASTContext();

  // The foreign error slot has type SomePointer<SomeErrorProtocol?>,
  // or possibly an optional thereof.

  // If the pointer itself is optional, we need to branch based on
  // whether it's really there.
  // FIXME: this code is written expecting pointer types to actually
  // be optional, as opposed to simply having a null inhabitant.
  OptionalTypeKind errorPtrOptKind;
  if (SILType errorPtrObjectTy =
        foreignErrorSlot->getType()
                        .getAnyOptionalObjectType(gen.SGM.M, errorPtrOptKind)) {
    SILBasicBlock *contBB = gen.createBasicBlock();
    SILBasicBlock *noSlotBB = gen.createBasicBlock();
    SILBasicBlock *hasSlotBB = gen.createBasicBlock();
    gen.B.createSwitchEnum(loc, foreignErrorSlot, nullptr,
                 { { ctx.getOptionalSomeDecl(errorPtrOptKind), hasSlotBB },
                   { ctx.getOptionalNoneDecl(errorPtrOptKind),  noSlotBB } });

    // If we have the slot, emit a store to it.
    gen.B.emitBlock(hasSlotBB);
    SILValue slot = hasSlotBB->createBBArg(errorPtrObjectTy);
    emitStoreToForeignErrorSlot(gen, loc, slot, errorSrc);
    gen.B.createBranch(loc, contBB);

    // Otherwise, just release the error.
    gen.B.emitBlock(noSlotBB);
    errorSrc.emitRelease(gen, loc);
    gen.B.createBranch(loc, contBB);

    // Continue.
    gen.B.emitBlock(contBB);
    return;
  }

  // Okay, break down the components of SomePointer<SomeErrorProtocol?>.
  // TODO: this should really be an unlowered AST type?
  CanType bridgedErrorPtrType =
    foreignErrorSlot->getType().getSwiftRValueType();

  PointerTypeKind ptrKind;
  CanType bridgedErrorProtocol =
    CanType(bridgedErrorPtrType->getAnyPointerElementType(ptrKind));

  FullExpr scope(gen.Cleanups, CleanupLocation::get(loc));
  WritebackScope writebacks(gen);

  // Convert the error to a bridged form.
  SILValue bridgedError = errorSrc.emitBridged(gen, loc, bridgedErrorProtocol);

  // Store to the "pointee" property.
  // If we can't find it, diagnose and then just don't store anything.
  VarDecl *pointeeProperty = ctx.getPointerPointeePropertyDecl(ptrKind);
  if (!pointeeProperty) {
    gen.SGM.diagnose(loc, diag::could_not_find_pointer_pointee_property,
                     bridgedErrorPtrType);
    return;
  }

  // Otherwise, do a normal assignment.
  LValue lvalue =
    gen.emitPropertyLValue(loc, ManagedValue::forUnmanaged(foreignErrorSlot),
                           bridgedErrorPtrType, pointeeProperty,
                           AccessKind::Write,
                           AccessSemantics::Ordinary);
  RValue rvalue(gen, loc, bridgedErrorProtocol,
                gen.emitManagedRValueWithCleanup(bridgedError));
  gen.emitAssignToLValue(loc, std::move(rvalue), std::move(lvalue));
}