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; }
/// 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"); }
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; }
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; }