Esempio n. 1
0
SILFunction *MaterializeForSetEmitter::createCallback(SILFunction &F,
                                                      GeneratorFn generator) {
  auto callbackType =
      SGM.Types.getMaterializeForSetCallbackType(WitnessStorage,
                                                 GenericSig,
                                                 SelfInterfaceType,
                                                 CallbackRepresentation);

  auto *genericEnv = GenericEnv;
  if (GenericEnv && GenericEnv->getGenericSignature()->areAllParamsConcrete())
    genericEnv = nullptr;

  auto callback =
    SGM.M.createFunction(Linkage, CallbackName, callbackType,
                         genericEnv, SILLocation(Witness),
                         IsBare, F.isTransparent(), F.isFragile(),
                         IsNotThunk,
                         /*ClassVisibility=*/SILFunction::NotRelevant,
                         /*InlineStrategy=*/InlineDefault,
                         /*EffectsKind=*/EffectsKind::Unspecified,
                         /*InsertBefore=*/&F);

  callback->setDebugScope(new (SGM.M) SILDebugScope(Witness, callback));

  PrettyStackTraceSILFunction X("silgen materializeForSet callback", callback);
  {
    SILGenFunction gen(SGM, *callback);

    auto makeParam = [&](unsigned index) -> SILArgument * {
      SILType type = gen.F.mapTypeIntoContext(
          gen.getSILType(callbackType->getParameters()[index]));
      return gen.F.begin()->createFunctionArgument(type);
    };

    // Add arguments for all the parameters.
    auto valueBuffer = makeParam(0);
    auto storageBuffer = makeParam(1);
    auto self = makeParam(2);
    (void) makeParam(3);

    SILLocation loc = Witness;
    loc.markAutoGenerated();

    // Call the generator function we were provided.
    {
      LexicalScope scope(gen.Cleanups, gen, CleanupLocation::get(loc));
      generator(gen, loc, valueBuffer, storageBuffer, self);
    }

    // Return void.
    auto result = gen.emitEmptyTuple(loc);
    gen.B.createReturn(loc, result);
  }

  callback->verify();
  return callback;
}
SILFunction *MaterializeForSetEmitter::createCallback(SILFunction &F,
                                                      GeneratorFn generator) {
  auto callbackType =
      SGM.Types.getMaterializeForSetCallbackType(WitnessStorage,
                                                 GenericSig,
                                                 SelfInterfaceType);
  auto callback =
      SGM.M.getOrCreateFunction(Witness, CallbackName, Linkage,
                                callbackType, IsBare,
                                F.isTransparent(),
                                F.isFragile());

  callback->setGenericEnvironment(GenericEnv);
  callback->setDebugScope(new (SGM.M) SILDebugScope(Witness, callback));

  PrettyStackTraceSILFunction X("silgen materializeForSet callback", callback);
  {
    SILGenFunction gen(SGM, *callback);

    auto makeParam = [&](unsigned index) -> SILArgument* {
      SILType type = gen.F.mapTypeIntoContext(
          callbackType->getParameters()[index].getSILType());
      return new (SGM.M) SILArgument(gen.F.begin(), type);
    };

    // Add arguments for all the parameters.
    auto valueBuffer = makeParam(0);
    auto storageBuffer = makeParam(1);
    auto self = makeParam(2);
    (void) makeParam(3);

    SILLocation loc = Witness;
    loc.markAutoGenerated();

    // Call the generator function we were provided.
    {
      LexicalScope scope(gen.Cleanups, gen, CleanupLocation::get(loc));
      generator(gen, loc, valueBuffer, storageBuffer, self);
    }

    // Return void.
    auto result = gen.emitEmptyTuple(loc);
    gen.B.createReturn(loc, result);
  }

  callback->verify();
  return callback;
}
Esempio n. 3
0
/// Emit a check for whether a non-native function call produced an
/// error.
///
/// \c results should be left with only values that match the formal
/// direct results of the function.
void
SILGenFunction::emitForeignErrorCheck(SILLocation loc,
                                      SmallVectorImpl<ManagedValue> &results,
                                      ManagedValue errorSlot,
                                      bool suppressErrorCheck,
                                const ForeignErrorConvention &foreignError) {
  // All of this is autogenerated.
  loc.markAutoGenerated();

  switch (foreignError.getKind()) {
  case ForeignErrorConvention::ZeroPreservedResult:
    assert(results.size() == 1);
    emitResultIsZeroErrorCheck(*this, loc, results[0], errorSlot,
                               suppressErrorCheck,
                               /*zeroIsError*/ true);
    return;
  case ForeignErrorConvention::ZeroResult:
    assert(results.size() == 1);
    emitResultIsZeroErrorCheck(*this, loc, results.pop_back_val(),
                               errorSlot, suppressErrorCheck,
                               /*zeroIsError*/ true);
    return;
  case ForeignErrorConvention::NonZeroResult:
    assert(results.size() == 1);
    emitResultIsZeroErrorCheck(*this, loc, results.pop_back_val(),
                               errorSlot, suppressErrorCheck,
                               /*zeroIsError*/ false);
    return;
  case ForeignErrorConvention::NilResult:
    assert(results.size() == 1);
    results[0] = emitResultIsNilErrorCheck(*this, loc, results[0], errorSlot,
                                           suppressErrorCheck);
    return;
  case ForeignErrorConvention::NonNilError:
    // Leave the direct results alone.
    emitErrorIsNonNilErrorCheck(*this, loc, errorSlot, suppressErrorCheck);
    return;
  }
  llvm_unreachable("bad foreign error convention kind");
}
Esempio n. 4
0
SILFunction *MaterializeForSetEmitter::createCallback(SILFunction &F, GeneratorFn generator) {
  auto &ctx = SGM.getASTContext();
 
  // Mangle this as if it were a conformance thunk for a closure
  // within the witness.
  std::string name;
  {
    ClosureExpr closure(/*patterns*/ nullptr,
                        /*throws*/ SourceLoc(),
                        /*arrow*/ SourceLoc(),
                        /*in*/ SourceLoc(),
                        /*result*/ TypeLoc(),
                        /*discriminator*/ 0,
                        /*context*/ Witness);
    closure.setType(getMaterializeForSetCallbackType(ctx,
                                 getSelfTypeForCallbackDeclaration(Witness)));
    closure.getCaptureInfo().setGenericParamCaptures(true);

    Mangle::Mangler mangler;
    if (Conformance) {
      mangler.append("_TTW");
      mangler.mangleProtocolConformance(Conformance);
    } else {
      mangler.append("_T");
    }
    mangler.mangleClosureEntity(&closure, /*uncurryLevel=*/1);
    name = mangler.finalize();
  }

  // Get lowered formal types for callback parameters.
  Type selfType = SelfInterfaceType;
  Type selfMetatypeType = MetatypeType::get(SelfInterfaceType,
                                            MetatypeRepresentation::Thick);

  {
    GenericContextScope scope(SGM.Types, GenericSig);

    // If 'self' is a metatype, make it @thin or @thick as needed, but not inside
    // selfMetatypeType.
    if (auto metatype = selfType->getAs<MetatypeType>()) {
      if (!metatype->hasRepresentation())
        selfType = SGM.getLoweredType(metatype).getSwiftRValueType();
    }
  }

  // Create the SILFunctionType for the callback.
  SILParameterInfo params[] = {
    { ctx.TheRawPointerType, ParameterConvention::Direct_Unowned },
    { ctx.TheUnsafeValueBufferType, ParameterConvention::Indirect_Inout },
    { selfType->getCanonicalType(), ParameterConvention::Indirect_Inout },
    { selfMetatypeType->getCanonicalType(), ParameterConvention::Direct_Unowned },
  };
  SILResultInfo result = {
    TupleType::getEmpty(ctx), ResultConvention::Unowned
  };
  auto extInfo = 
    SILFunctionType::ExtInfo()
      .withRepresentation(SILFunctionTypeRepresentation::Thin);

  auto callbackType = SILFunctionType::get(GenericSig, extInfo,
                                /*callee*/ ParameterConvention::Direct_Unowned,
                                           params, result, None, ctx);
  auto callback =
    SGM.M.getOrCreateFunction(Witness, name, Linkage, callbackType,
                              IsBare,
                              F.isTransparent(),
                              F.isFragile());

  callback->setContextGenericParams(GenericParams);
  callback->setDebugScope(new (SGM.M) SILDebugScope(Witness, *callback));

  PrettyStackTraceSILFunction X("silgen materializeForSet callback", callback);
  {
    SILGenFunction gen(SGM, *callback);

    auto makeParam = [&](unsigned index) -> SILArgument* {
      SILType type = gen.F.mapTypeIntoContext(params[index].getSILType());
      return new (SGM.M) SILArgument(gen.F.begin(), type);
    };

    // Add arguments for all the parameters.
    auto valueBuffer = makeParam(0);
    auto storageBuffer = makeParam(1);
    auto self = makeParam(2);
    (void) makeParam(3);

    SILLocation loc = Witness;
    loc.markAutoGenerated();

    // Call the generator function we were provided.
    {
      LexicalScope scope(gen.Cleanups, gen, CleanupLocation::get(loc));
      generator(gen, loc, valueBuffer, storageBuffer, self);
    }

    // Return void.
    auto result = gen.emitEmptyTuple(loc);
    gen.B.createReturn(loc, result);
  }

  callback->verify();
  return callback;
}
Esempio n. 5
0
void MaterializeForSetEmitter::emit(SILGenFunction &gen, ManagedValue self,
                                    SILValue resultBuffer,
                                    SILValue callbackBuffer,
                                    ArrayRef<ManagedValue> indices) {
  SILLocation loc = Witness;
  loc.markAutoGenerated();

  // If there's an abstraction difference, we always need to use the
  // get/set pattern.
  AccessStrategy strategy;
  if (WitnessStorage->getType()->is<ReferenceStorageType>() ||
      (Conformance && RequirementStorageType != WitnessStorageType)) {
    strategy = AccessStrategy::DispatchToAccessor;
  } else {
    strategy = WitnessStorage->getAccessStrategy(TheAccessSemantics,
                                                 AccessKind::ReadWrite);
  }

  // Handle the indices.
  RValue indicesRV;
  if (isa<SubscriptDecl>(WitnessStorage)) {
    indicesRV = collectIndicesFromParameters(gen, loc, indices);
  } else {
    assert(indices.empty() && "indices for a non-subscript?");
  }

  // As above, assume that we don't need to reabstract 'self'.

  // Choose the right implementation.
  SILValue address;
  SILFunction *callbackFn = nullptr;
  switch (strategy) {
  case AccessStrategy::Storage:
    address = emitUsingStorage(gen, loc, self, std::move(indicesRV));
    break;

  case AccessStrategy::Addressor:
    address = emitUsingAddressor(gen, loc, self, std::move(indicesRV),
                                 callbackBuffer, callbackFn);
    break;

  case AccessStrategy::DirectToAccessor:
  case AccessStrategy::DispatchToAccessor:
    address = emitUsingGetterSetter(gen, loc, self, std::move(indicesRV),
                                    resultBuffer, callbackBuffer, callbackFn);
    break;
  }

  // Return the address as a Builtin.RawPointer.
  SILType rawPointerTy = SILType::getRawPointerType(gen.getASTContext());
  address = gen.B.createAddressToPointer(loc, address, rawPointerTy);

  SILType resultTupleTy = gen.F.mapTypeIntoContext(
                 gen.F.getLoweredFunctionType()->getResult().getSILType());
  SILType optCallbackTy = resultTupleTy.getTupleElementType(1);

  // Form the callback.
  SILValue callback;
  if (callbackFn) {
    // Make a reference to the function.
    callback = gen.B.createFunctionRef(loc, callbackFn);

    // If it's polymorphic, cast to RawPointer and then back to the
    // right monomorphic type.  The safety of this cast relies on some
    // assumptions about what exactly IRGen can reconstruct from the
    // callback's thick type argument.
    if (callbackFn->getLoweredFunctionType()->isPolymorphic()) {
      callback = gen.B.createThinFunctionToPointer(loc, callback, rawPointerTy);

      OptionalTypeKind optKind;
      auto callbackTy = optCallbackTy.getAnyOptionalObjectType(SGM.M, optKind);
      callback = gen.B.createPointerToThinFunction(loc, callback, callbackTy);
    }

    callback = gen.B.createOptionalSome(loc, callback, optCallbackTy);
  } else {
    callback = gen.B.createOptionalNone(loc, optCallbackTy);
  }

  // Form the result and return.
  auto result = gen.B.createTuple(loc, resultTupleTy, { address, callback });
  gen.Cleanups.emitCleanupsForReturn(CleanupLocation::get(loc));
  gen.B.createReturn(loc, result);
}
void MaterializeForSetEmitter::emit(SILGenFunction &gen) {
  SILLocation loc = Witness;
  loc.markAutoGenerated();

  gen.F.setBare(IsBare);

  SmallVector<ManagedValue, 4> params;
  gen.collectThunkParams(loc, params, /*allowPlusZero*/ true);

  ManagedValue self = params.back();
  SILValue resultBuffer = params[0].getUnmanagedValue();
  SILValue callbackBuffer = params[1].getUnmanagedValue();
  auto indices = ArrayRef<ManagedValue>(params).slice(2).drop_back();

  // If there's an abstraction difference, we always need to use the
  // get/set pattern.
  AccessStrategy strategy;
  if (WitnessStorage->getType()->is<ReferenceStorageType>() ||
      (RequirementStorageType != WitnessStorageType)) {
    strategy = AccessStrategy::DispatchToAccessor;
  } else {
    strategy = WitnessStorage->getAccessStrategy(TheAccessSemantics,
                                                 AccessKind::ReadWrite);
  }

  // Handle the indices.
  RValue indicesRV;
  if (isa<SubscriptDecl>(WitnessStorage)) {
    indicesRV = collectIndicesFromParameters(gen, loc, indices);
  } else {
    assert(indices.empty() && "indices for a non-subscript?");
  }

  // As above, assume that we don't need to reabstract 'self'.

  // Choose the right implementation.
  SILValue address;
  SILFunction *callbackFn = nullptr;
  switch (strategy) {
  case AccessStrategy::BehaviorStorage:
    llvm_unreachable("materializeForSet should never engage in behavior init");
  
  case AccessStrategy::Storage:
    address = emitUsingStorage(gen, loc, self, std::move(indicesRV));
    break;

  case AccessStrategy::Addressor:
    address = emitUsingAddressor(gen, loc, self, std::move(indicesRV),
                                 callbackBuffer, callbackFn);
    break;

  case AccessStrategy::DirectToAccessor:
  case AccessStrategy::DispatchToAccessor:
    address = emitUsingGetterSetter(gen, loc, self, std::move(indicesRV),
                                    resultBuffer, callbackBuffer, callbackFn);
    break;
  }

  // Return the address as a Builtin.RawPointer.
  SILType rawPointerTy = SILType::getRawPointerType(gen.getASTContext());
  address = gen.B.createAddressToPointer(loc, address, rawPointerTy);

  SILType resultTupleTy = gen.F.mapTypeIntoContext(
                 gen.F.getLoweredFunctionType()->getSILResult());
  SILType optCallbackTy = resultTupleTy.getTupleElementType(1);

  // Form the callback.
  SILValue callback;
  if (callbackFn) {
    // Make a reference to the callback.
    callback = gen.B.createFunctionRef(loc, callbackFn);
    callback = gen.B.createThinFunctionToPointer(loc, callback, rawPointerTy);
    callback = gen.B.createOptionalSome(loc, callback, optCallbackTy);
  } else {
    // There is no callback.
    callback = gen.B.createOptionalNone(loc, optCallbackTy);
  }

  // Form the result and return.
  auto result = gen.B.createTuple(loc, resultTupleTy, { address, callback });
  gen.Cleanups.emitCleanupsForReturn(CleanupLocation::get(loc));
  gen.B.createReturn(loc, result);
}
SILFunction *MaterializeForSetEmitter::createCallback(SILFunction &F,
                                                      GeneratorFn generator) {
  auto callbackType =
      SGM.Types.getMaterializeForSetCallbackType(WitnessStorage,
                                                 GenericSig,
                                                 SelfInterfaceType,
                                                 CallbackRepresentation);

  auto *genericEnv = GenericEnv;
  if (GenericEnv && GenericEnv->getGenericSignature()->areAllParamsConcrete())
    genericEnv = nullptr;

  // The callback's symbol is irrelevant (it is just returned as a value from
  // the actual materializeForSet function), and so we only need to make sure we
  // don't break things in cases when there may be multiple definitions.
  auto callbackLinkage =
      F.isSerialized() ? SILLinkage::Shared : SILLinkage::Private;

  auto callback = SGM.M.createFunction(
      callbackLinkage, CallbackName, callbackType, genericEnv,
      SILLocation(Witness), IsBare, F.isTransparent(), F.isSerialized(), IsNotThunk,
      SubclassScope::NotApplicable,
      /*inlineStrategy=*/InlineDefault,
      /*EK=*/EffectsKind::Unspecified,
      /*InsertBefore=*/&F);

  callback->setDebugScope(new (SGM.M) SILDebugScope(Witness, callback));

  PrettyStackTraceSILFunction X("silgen materializeForSet callback", callback);
  {
    SILGenFunction SGF(SGM, *callback);

    auto makeParam = [&](unsigned index) -> SILArgument * {
      SILType type = SGF.F.mapTypeIntoContext(
          SGF.getSILType(callbackType->getParameters()[index]));
      return SGF.F.begin()->createFunctionArgument(type);
    };

    // Add arguments for all the parameters.
    auto valueBuffer = makeParam(0);
    auto storageBuffer = makeParam(1);
    auto self = makeParam(2);
    (void) makeParam(3);

    SILLocation loc = Witness;
    loc.markAutoGenerated();

    // Call the generator function we were provided.
    {
      LexicalScope scope(SGF, CleanupLocation::get(loc));
      generator(SGF, loc, valueBuffer, storageBuffer, self);
    }

    // Return void.
    auto result = SGF.emitEmptyTuple(loc);
    SGF.B.createReturn(loc, result);
  }

  callback->verify();
  return callback;
}