Esempio n. 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);
}
Esempio n. 2
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);
}