| //===--- SILGenApply.cpp - Constructs call sites for SILGen ---------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "ArgumentScope.h" |
| #include "ArgumentSource.h" |
| #include "Callee.h" |
| #include "Conversion.h" |
| #include "FormalEvaluation.h" |
| #include "Initialization.h" |
| #include "LValue.h" |
| #include "RValue.h" |
| #include "ResultPlan.h" |
| #include "Scope.h" |
| #include "SpecializedEmitter.h" |
| #include "Varargs.h" |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/DiagnosticsSIL.h" |
| #include "swift/AST/ForeignAsyncConvention.h" |
| #include "swift/AST/ForeignErrorConvention.h" |
| #include "swift/AST/GenericEnvironment.h" |
| #include "swift/AST/GenericSignature.h" |
| #include "swift/AST/Module.h" |
| #include "swift/AST/ModuleLoader.h" |
| #include "swift/AST/ParameterList.h" |
| #include "swift/AST/SubstitutionMap.h" |
| #include "swift/Basic/ExternalUnion.h" |
| #include "swift/Basic/Range.h" |
| #include "swift/Basic/STLExtras.h" |
| #include "swift/Basic/Unicode.h" |
| #include "swift/SIL/PrettyStackTrace.h" |
| #include "swift/SIL/SILArgument.h" |
| #include "clang/AST/DeclCXX.h" |
| #include "llvm/Support/Compiler.h" |
| #include "clang/AST/DeclObjC.h" |
| |
| using namespace swift; |
| using namespace Lowering; |
| |
| //===----------------------------------------------------------------------===// |
| // Utility Functions |
| //===----------------------------------------------------------------------===// |
| |
| SubstitutionMap SILGenModule::mapSubstitutionsForWitnessOverride( |
| AbstractFunctionDecl *original, |
| AbstractFunctionDecl *overridden, |
| SubstitutionMap subs) { |
| // Substitute the 'Self' type of the base protocol. |
| auto origProto = cast<ProtocolDecl>(original->getDeclContext()); |
| Type origProtoSelfType = origProto->getSelfInterfaceType(); |
| auto baseProto = cast<ProtocolDecl>(overridden->getDeclContext()); |
| return SubstitutionMap::getProtocolSubstitutions( |
| baseProto, origProtoSelfType.subst(subs), |
| subs.lookupConformance(origProtoSelfType->getCanonicalType(), baseProto)); |
| } |
| |
| /// Return the abstraction pattern to use when calling a function value. |
| static AbstractionPattern |
| getIndirectApplyAbstractionPattern(SILGenFunction &SGF, |
| CanFunctionType fnType) { |
| assert(fnType); |
| AbstractionPattern pattern(fnType); |
| switch (fnType->getRepresentation()) { |
| case FunctionTypeRepresentation::Swift: |
| case FunctionTypeRepresentation::Thin: |
| return pattern; |
| |
| case FunctionTypeRepresentation::CFunctionPointer: |
| case FunctionTypeRepresentation::Block: { |
| // C and block function parameters and results are implicitly |
| // bridged to a foreign type. |
| auto silRep = |
| SILFunctionTypeRepresentation(fnType->getExtInfo().getRepresentation()); |
| auto bridgedType = SGF.SGM.Types.getBridgedFunctionType( |
| pattern, fnType, Bridgeability::Full, silRep); |
| pattern.rewriteType(CanGenericSignature(), bridgedType); |
| return pattern; |
| } |
| } |
| llvm_unreachable("bad representation"); |
| } |
| |
| /// Return the formal type for the partial-apply result type of a |
| /// dynamic method invocation. |
| static CanFunctionType |
| getPartialApplyOfDynamicMethodFormalType(SILGenModule &SGM, SILDeclRef member, |
| ConcreteDeclRef memberRef) { |
| auto memberCI = |
| SGM.Types.getConstantInfo(TypeExpansionContext::minimal(), member); |
| |
| // Construct a non-generic version of the formal type. |
| // This works because we're only using foreign members, where presumably |
| // substitution doesn't matter. |
| CanAnyFunctionType completeMethodTy = memberCI.LoweredType; |
| if (auto genericFnType = dyn_cast<GenericFunctionType>(completeMethodTy)) { |
| completeMethodTy = cast<FunctionType>( |
| genericFnType->substGenericArgs(memberRef.getSubstitutions()) |
| ->getCanonicalType()); |
| } |
| |
| // Adjust the parameters by removing the self parameter, which we |
| // will be partially applying. |
| auto params = completeMethodTy.getParams().drop_back(); |
| |
| // Adjust the result type to replace dynamic-self with AnyObject. |
| CanType resultType = completeMethodTy.getResult(); |
| if (auto fnDecl = dyn_cast<FuncDecl>(member.getDecl())) { |
| if (fnDecl->hasDynamicSelfResult()) { |
| auto anyObjectTy = SGM.getASTContext().getAnyObjectType(); |
| resultType = resultType->replaceCovariantResultType(anyObjectTy, 0) |
| ->getCanonicalType(); |
| } |
| } |
| |
| // Adjust the ExtInfo by using a Swift representation. |
| auto extInfo = completeMethodTy->getExtInfo() |
| .withRepresentation(FunctionTypeRepresentation::Swift); |
| |
| auto fnType = CanFunctionType::get(params, resultType, extInfo); |
| return fnType; |
| } |
| |
| /// Retrieve the type to use for a method found via dynamic lookup. |
| static SILType |
| getDynamicMethodLoweredType(SILModule &M, |
| SILDeclRef constant, |
| CanAnyFunctionType substMemberTy) { |
| assert(constant.isForeign); |
| auto objcFormalTy = substMemberTy.withExtInfo( |
| substMemberTy->getExtInfo() |
| .intoBuilder() |
| .withSILRepresentation(SILFunctionTypeRepresentation::ObjCMethod) |
| .build()); |
| return SILType::getPrimitiveObjectType( |
| M.Types.getUncachedSILFunctionTypeForConstant( |
| TypeExpansionContext::minimal(), constant, objcFormalTy)); |
| } |
| |
| /// Check if we can perform a dynamic dispatch on a super method call. |
| static bool canUseStaticDispatch(SILGenFunction &SGF, |
| SILDeclRef constant) { |
| auto *funcDecl = cast<AbstractFunctionDecl>(constant.getDecl()); |
| |
| if (funcDecl->isFinal()) |
| return true; |
| |
| // Native initializing entry points are always statically dispatched. |
| if (constant.kind == SILDeclRef::Kind::Initializer |
| && !constant.isForeign) |
| return true; |
| |
| // Extension methods currently must be statically dispatched, unless they're |
| // @objc or dynamic. |
| if (isa<ExtensionDecl>(funcDecl->getDeclContext()) && !constant.isForeign) |
| return true; |
| |
| // We cannot form a direct reference to a method body defined in |
| // Objective-C. |
| if (constant.isForeign) |
| return false; |
| |
| // If we cannot form a direct reference due to resilience constraints, |
| // we have to dynamic dispatch. |
| if (SGF.F.isSerialized()) |
| return false; |
| |
| // If the method is defined in the same module, we can reference it |
| // directly. |
| auto thisModule = SGF.SGM.M.getSwiftModule(); |
| if (thisModule == funcDecl->getModuleContext()) |
| return true; |
| |
| // Otherwise, we must dynamic dispatch. |
| return false; |
| } |
| |
| static SILValue getOriginalSelfValue(SILValue selfValue) { |
| if (auto *TTOI = dyn_cast<ThickToObjCMetatypeInst>(selfValue)) |
| selfValue = TTOI->getOperand(); |
| |
| if (auto *BBI = dyn_cast<BeginBorrowInst>(selfValue)) |
| selfValue = BBI->getOperand(); |
| |
| while (auto *UI = dyn_cast<UpcastInst>(selfValue)) |
| selfValue = UI->getOperand(); |
| |
| if (auto *UTBCI = dyn_cast<UncheckedTrivialBitCastInst>(selfValue)) |
| selfValue = UTBCI->getOperand(); |
| |
| return selfValue; |
| } |
| |
| /// Borrow self and then upcast self to its original type. If self is a |
| /// metatype, we just return the original metatype since metatypes are trivial. |
| static ManagedValue borrowedCastToOriginalSelfType(SILGenFunction &SGF, |
| SILLocation loc, |
| ManagedValue self) { |
| SILValue originalSelf = getOriginalSelfValue(self.getValue()); |
| SILType originalSelfType = originalSelf->getType(); |
| |
| // If we have a metatype, then we just return the original self value since |
| // metatypes are trivial, so we can avoid ownership concerns. |
| if (originalSelfType.is<AnyMetatypeType>()) { |
| assert(originalSelfType.isTrivial(SGF.F) && |
| "Metatypes should always be trivial"); |
| return ManagedValue::forUnmanaged(originalSelf); |
| } |
| |
| // Otherwise, we have a non-metatype. Use a borrow+unchecked_ref_cast. |
| return SGF.B.createUncheckedRefCast(loc, self.formalAccessBorrow(SGF, loc), |
| originalSelfType); |
| } |
| |
| static ManagedValue convertOwnershipConventionGivenParamInfo( |
| SILGenFunction &SGF, SILParameterInfo param, ManagedValue value, |
| SILLocation loc, bool isForCoroutine) { |
| if (param.isConsumed() && |
| value.getOwnershipKind() == OwnershipKind::Guaranteed) { |
| return value.copyUnmanaged(SGF, loc); |
| } |
| |
| // If we are emitting arguments for a coroutine, we need to borrow owned |
| // values to ensure that they are live over the entire closure invocation. If |
| // we do not have a coroutine, then we have an immediate non-consuming use so |
| // no borrow is necessary. |
| if (isForCoroutine && value.getOwnershipKind() == OwnershipKind::Owned) { |
| if (param.isDirectGuaranteed() || (!SGF.silConv.useLoweredAddresses() && |
| param.isIndirectInGuaranteed())) { |
| return value.formalAccessBorrow(SGF, loc); |
| } |
| } |
| |
| return value; |
| } |
| |
| static void convertOwnershipConventionsGivenParamInfos( |
| SILGenFunction &SGF, ArrayRef<SILParameterInfo> params, |
| ArrayRef<ManagedValue> values, SILLocation loc, bool isForCoroutine, |
| llvm::SmallVectorImpl<ManagedValue> &outVar) { |
| assert(params.size() == values.size() && |
| "Different number of params from arguments"); |
| llvm::transform(indices(params), std::back_inserter(outVar), |
| [&](unsigned i) -> ManagedValue { |
| return convertOwnershipConventionGivenParamInfo( |
| SGF, params[i], values[i], loc, isForCoroutine); |
| }); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Callee |
| //===----------------------------------------------------------------------===// |
| |
| namespace { |
| |
| /// Abstractly represents a callee, which may be a constant or function value, |
| /// and knows how to perform dynamic dispatch and reference the appropriate |
| /// entry point at any valid uncurry level. |
| class Callee { |
| public: |
| enum class Kind { |
| /// An indirect function value. |
| IndirectValue, |
| |
| /// A direct standalone function call, referenceable by a FunctionRefInst. |
| StandaloneFunction, |
| |
| /// A direct standalone function call, referenceable by a |
| /// PreviousDynamicFunctionRefInst. |
| StandaloneFunctionDynamicallyReplaceableImpl, |
| |
| /// Enum case constructor call. |
| EnumElement, |
| |
| /// A method call using class method dispatch. |
| ClassMethod, |
| |
| /// A method call using super method dispatch. |
| SuperMethod, |
| |
| /// A method call using protocol witness table dispatch. |
| WitnessMethod, |
| |
| /// A method call using dynamic lookup. |
| DynamicMethod, |
| }; |
| |
| Kind kind; |
| |
| // Move, don't copy. |
| Callee(const Callee &) = delete; |
| Callee &operator=(const Callee &) = delete; |
| |
| private: |
| /// An IndirectValue callee represents something like a swift closure or a c |
| /// function pointer where we have /no/ information at all on what the callee |
| /// is. This contrasts with a class method, where we may not know the exact |
| /// method that is being called, but we have some information from the type |
| /// system that we have an actual method. |
| /// |
| /// *NOTE* This will never be non-null if Constant is non-null. |
| ManagedValue IndirectValue; |
| |
| /// If we are trying to call a specific method or function, this field is set |
| /// to the decl ref information for that callee. |
| /// |
| /// *NOTE* This should never be non-null if IndirectValue is non-null. |
| SILDeclRef Constant; |
| |
| /// The abstraction pattern of the callee. |
| AbstractionPattern OrigFormalInterfaceType; |
| |
| /// The callee's formal type with substitutions applied. |
| CanFunctionType SubstFormalInterfaceType; |
| |
| /// The substitutions applied to OrigFormalInterfaceType to produce |
| /// SubstFormalInterfaceType, substituted into the current type expansion |
| /// context. |
| SubstitutionMap Substitutions; |
| |
| /// The list of values captured by our callee. |
| Optional<SmallVector<ManagedValue, 2>> Captures; |
| |
| // The pointer back to the AST node that produced the callee. |
| SILLocation Loc; |
| |
| static CanFunctionType |
| getSubstFormalInterfaceType(CanAnyFunctionType substFormalType, |
| SubstitutionMap subs) { |
| if (auto *gft = substFormalType->getAs<GenericFunctionType>()) { |
| return cast<FunctionType>( |
| gft->substGenericArgs(subs) |
| ->getCanonicalType()); |
| } |
| |
| return cast<FunctionType>(substFormalType); |
| } |
| |
| /// Constructor for Callee::forIndirect. |
| Callee(ManagedValue indirectValue, |
| AbstractionPattern origFormalType, |
| CanFunctionType substFormalType, |
| SILLocation l) |
| : kind(Kind::IndirectValue), |
| IndirectValue(indirectValue), |
| OrigFormalInterfaceType(origFormalType), |
| SubstFormalInterfaceType(substFormalType), |
| Loc(l) |
| {} |
| |
| /// Constructor for Callee::forDirect. |
| Callee(SILGenFunction &SGF, SILDeclRef standaloneFunction, |
| AbstractionPattern origFormalType, CanAnyFunctionType substFormalType, |
| SubstitutionMap subs, SubstitutionMap formalSubs, SILLocation l, |
| bool callDynamicallyReplaceableImpl = false) |
| : kind(callDynamicallyReplaceableImpl |
| ? Kind::StandaloneFunctionDynamicallyReplaceableImpl |
| : Kind::StandaloneFunction), |
| Constant(standaloneFunction), OrigFormalInterfaceType(origFormalType), |
| SubstFormalInterfaceType( |
| getSubstFormalInterfaceType(substFormalType, formalSubs)), |
| Substitutions(subs), Loc(l) {} |
| |
| /// Constructor called by all for* factory methods except forDirect and |
| /// forIndirect. |
| Callee(Kind methodKind, SILGenFunction &SGF, SILDeclRef methodName, |
| AbstractionPattern origFormalType, CanAnyFunctionType substFormalType, |
| SubstitutionMap subs, SILLocation l) |
| : kind(methodKind), Constant(methodName), |
| OrigFormalInterfaceType(origFormalType), |
| SubstFormalInterfaceType( |
| getSubstFormalInterfaceType(substFormalType, subs)), |
| Substitutions(subs), Loc(l) {} |
| |
| public: |
| |
| static Callee forIndirect(ManagedValue indirectValue, |
| AbstractionPattern origFormalType, |
| CanFunctionType substFormalType, |
| SILLocation l) { |
| return Callee(indirectValue, origFormalType, substFormalType, l); |
| } |
| static Callee forDirect(SILGenFunction &SGF, SILDeclRef c, |
| SubstitutionMap subs, |
| SILLocation l, |
| bool callPreviousDynamicReplaceableImpl = false) { |
| auto &ci = SGF.getConstantInfo(SGF.getTypeExpansionContext(), c); |
| return Callee( |
| SGF, c, ci.FormalPattern, ci.FormalType, |
| subs.mapIntoTypeExpansionContext(SGF.getTypeExpansionContext()), |
| subs, |
| l, |
| callPreviousDynamicReplaceableImpl); |
| } |
| |
| static Callee forEnumElement(SILGenFunction &SGF, SILDeclRef c, |
| SubstitutionMap subs, |
| SILLocation l) { |
| assert(isa<EnumElementDecl>(c.getDecl())); |
| auto &ci = SGF.getConstantInfo(SGF.getTypeExpansionContext(), c); |
| return Callee( |
| Kind::EnumElement, SGF, c, ci.FormalPattern, ci.FormalType, |
| subs.mapIntoTypeExpansionContext(SGF.getTypeExpansionContext()), l); |
| } |
| static Callee forClassMethod(SILGenFunction &SGF, |
| SILDeclRef c, SubstitutionMap subs, |
| SILLocation l) { |
| auto base = c.getOverriddenVTableEntry(); |
| auto &baseCI = SGF.getConstantInfo(SGF.getTypeExpansionContext(), base); |
| auto &derivedCI = SGF.getConstantInfo(SGF.getTypeExpansionContext(), c); |
| return Callee( |
| Kind::ClassMethod, SGF, c, baseCI.FormalPattern, derivedCI.FormalType, |
| subs.mapIntoTypeExpansionContext(SGF.getTypeExpansionContext()), l); |
| } |
| static Callee forSuperMethod(SILGenFunction &SGF, |
| SILDeclRef c, SubstitutionMap subs, |
| SILLocation l) { |
| auto &ci = SGF.getConstantInfo(SGF.getTypeExpansionContext(), c); |
| return Callee( |
| Kind::SuperMethod, SGF, c, ci.FormalPattern, ci.FormalType, |
| subs.mapIntoTypeExpansionContext(SGF.getTypeExpansionContext()), l); |
| } |
| static Callee forWitnessMethod(SILGenFunction &SGF, |
| CanType protocolSelfType, |
| SILDeclRef c, |
| SubstitutionMap subs, |
| SILLocation l) { |
| // Find a witness that has an entry in the witness table. |
| if (!c.requiresNewWitnessTableEntry()) { |
| // Retrieve the constant that has an entry in the witness table. |
| auto original = cast<AbstractFunctionDecl>(c.getDecl()); |
| c = c.getOverriddenWitnessTableEntry(); |
| c = c.asForeign(c.getDecl()->isObjC()); |
| auto overridden = cast<AbstractFunctionDecl>(c.getDecl()); |
| |
| // Substitute the 'Self' type of the base protocol. |
| subs = SILGenModule::mapSubstitutionsForWitnessOverride(original, |
| overridden, |
| subs); |
| } |
| |
| auto &ci = SGF.getConstantInfo(SGF.getTypeExpansionContext(), c); |
| return Callee( |
| Kind::WitnessMethod, SGF, c, ci.FormalPattern, ci.FormalType, |
| subs.mapIntoTypeExpansionContext(SGF.getTypeExpansionContext()), l); |
| } |
| static Callee forDynamic(SILGenFunction &SGF, |
| SILDeclRef c, SubstitutionMap constantSubs, |
| CanAnyFunctionType substFormalType, |
| SubstitutionMap subs, SILLocation l) { |
| auto &ci = SGF.getConstantInfo(SGF.getTypeExpansionContext(), c); |
| AbstractionPattern origFormalType = ci.FormalPattern; |
| |
| // Replace the original self type with the partially-applied subst type. |
| auto origFormalFnType = cast<AnyFunctionType>(origFormalType.getType()); |
| if (auto genericFnType = dyn_cast<GenericFunctionType>(origFormalFnType)) { |
| // If we have a generic function type, substitute it. This is normally |
| // a huge no-no, but the partial-application hacks we're doing here |
| // really kindof mandate it, and it works out because we're always using |
| // a foreign function. If/when we support native dynamic functions, |
| // this will stop working and we will need a completely different |
| // approach. |
| origFormalFnType = |
| cast<FunctionType>(genericFnType->substGenericArgs(constantSubs) |
| ->getCanonicalType()); |
| } |
| origFormalType.rewriteType(CanGenericSignature(), origFormalFnType); |
| |
| return Callee( |
| Kind::DynamicMethod, SGF, c, origFormalType, substFormalType, |
| subs.mapIntoTypeExpansionContext(SGF.getTypeExpansionContext()), l); |
| } |
| |
| Callee(Callee &&) = default; |
| Callee &operator=(Callee &&) = default; |
| |
| void setCaptures(SmallVectorImpl<ManagedValue> &&captures) { |
| Captures = std::move(captures); |
| } |
| |
| ArrayRef<ManagedValue> getCaptures() const { |
| if (Captures) |
| return *Captures; |
| return {}; |
| } |
| |
| bool hasCaptures() const { |
| return Captures.hasValue(); |
| } |
| |
| AbstractionPattern getOrigFormalType() const { |
| return AbstractionPattern(OrigFormalInterfaceType); |
| } |
| |
| CanFunctionType getSubstFormalType() const { |
| return SubstFormalInterfaceType; |
| } |
| |
| unsigned getParameterListCount() const { |
| switch (kind) { |
| case Kind::IndirectValue: |
| return 1; |
| |
| case Kind::StandaloneFunction: |
| case Kind::StandaloneFunctionDynamicallyReplaceableImpl: |
| case Kind::EnumElement: |
| case Kind::ClassMethod: |
| case Kind::SuperMethod: |
| case Kind::WitnessMethod: |
| case Kind::DynamicMethod: |
| return Constant.getParameterListCount(); |
| } |
| |
| llvm_unreachable("Unhandled Kind in switch."); |
| } |
| |
| bool requiresSelfValueForDispatch() const { |
| switch (kind) { |
| case Kind::IndirectValue: |
| case Kind::StandaloneFunction: |
| case Kind::StandaloneFunctionDynamicallyReplaceableImpl: |
| case Kind::EnumElement: |
| return false; |
| case Kind::WitnessMethod: |
| if (Constant.isForeign) |
| return true; |
| return false; |
| case Kind::ClassMethod: |
| case Kind::SuperMethod: |
| case Kind::DynamicMethod: |
| return true; |
| } |
| |
| llvm_unreachable("Unhandled Kind in switch."); |
| } |
| |
| EnumElementDecl *getEnumElementDecl() { |
| assert(kind == Kind::EnumElement); |
| return cast<EnumElementDecl>(Constant.getDecl()); |
| } |
| |
| ValueDecl *getDecl() { |
| return Constant.getDecl(); |
| } |
| |
| CalleeTypeInfo createCalleeTypeInfo(SILGenFunction &SGF, |
| Optional<SILDeclRef> constant, |
| SILType formalFnType) const & { |
| CalleeTypeInfo result; |
| |
| result.substFnType = |
| formalFnType.castTo<SILFunctionType>()->substGenericArgs( |
| SGF.SGM.M, Substitutions, SGF.getTypeExpansionContext()); |
| |
| if (!constant || !constant->isForeign) |
| return result; |
| |
| auto func = cast<AbstractFunctionDecl>(constant->getDecl()); |
| result.foreign = CalleeTypeInfo::ForeignInfo{ |
| func->getForeignErrorConvention(), |
| func->getForeignAsyncConvention(), |
| func->getImportAsMemberStatus(), |
| }; |
| |
| // Remove the metatype "self" parameter by making this a static member. |
| if (constant->getDecl()->getClangDecl() && |
| isa<clang::CXXConstructorDecl>(constant->getDecl()->getClangDecl())) |
| result.foreign.self.setStatic(); |
| |
| return result; |
| } |
| |
| ManagedValue getFnValue(SILGenFunction &SGF, |
| Optional<ManagedValue> borrowedSelf) const & { |
| Optional<SILDeclRef> constant = None; |
| |
| if (Constant) |
| constant = Constant; |
| |
| switch (kind) { |
| case Kind::IndirectValue: |
| assert(Substitutions.empty()); |
| return IndirectValue; |
| case Kind::EnumElement: |
| case Kind::StandaloneFunction: { |
| auto constantInfo = |
| SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); |
| SILValue ref = SGF.emitGlobalFunctionRef(Loc, *constant, constantInfo); |
| return ManagedValue::forUnmanaged(ref); |
| } |
| case Kind::StandaloneFunctionDynamicallyReplaceableImpl: { |
| auto constantInfo = |
| SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); |
| SILValue ref = |
| SGF.emitGlobalFunctionRef(Loc, *constant, constantInfo, true); |
| return ManagedValue::forUnmanaged(ref); |
| } |
| case Kind::ClassMethod: { |
| auto methodTy = SGF.SGM.Types.getConstantOverrideType( |
| SGF.getTypeExpansionContext(), *constant); |
| |
| // Otherwise, do the dynamic dispatch inline. |
| ArgumentScope S(SGF, Loc); |
| |
| SILValue methodVal; |
| if (!constant->isForeign) { |
| methodVal = SGF.emitClassMethodRef( |
| Loc, borrowedSelf->getValue(), *constant, methodTy); |
| } else { |
| methodVal = SGF.B.createObjCMethod( |
| Loc, borrowedSelf->getValue(), *constant, |
| SILType::getPrimitiveObjectType(methodTy)); |
| } |
| S.pop(); |
| return ManagedValue::forUnmanaged(methodVal); |
| } |
| case Kind::SuperMethod: { |
| ArgumentScope S(SGF, Loc); |
| ManagedValue castValue = borrowedCastToOriginalSelfType( |
| SGF, Loc, *borrowedSelf); |
| |
| auto base = constant->getOverriddenVTableEntry(); |
| auto constantInfo = SGF.SGM.Types.getConstantOverrideInfo( |
| SGF.getTypeExpansionContext(), *constant, base); |
| |
| ManagedValue fn; |
| if (!constant->isForeign) { |
| fn = SGF.B.createSuperMethod(Loc, castValue, *constant, |
| constantInfo.getSILType()); |
| } else { |
| fn = SGF.B.createObjCSuperMethod(Loc, castValue, *constant, |
| constantInfo.getSILType()); |
| } |
| S.pop(); |
| return fn; |
| } |
| case Kind::WitnessMethod: { |
| auto constantInfo = |
| SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); |
| |
| // TODO: substOpaqueTypesWithUnderlyingTypes ... |
| auto proto = cast<ProtocolDecl>(Constant.getDecl()->getDeclContext()); |
| auto selfType = proto->getSelfInterfaceType()->getCanonicalType(); |
| auto lookupType = selfType.subst(Substitutions)->getCanonicalType(); |
| auto conformance = Substitutions.lookupConformance(selfType, proto); |
| |
| ArgumentScope S(SGF, Loc); |
| |
| SILValue fn; |
| if (!constant->isForeign) { |
| fn = SGF.B.createWitnessMethod( |
| Loc, lookupType, conformance, *constant, |
| constantInfo.getSILType()); |
| } else { |
| fn = SGF.B.createObjCMethod(Loc, borrowedSelf->getValue(), |
| *constant, constantInfo.getSILType()); |
| } |
| S.pop(); |
| return ManagedValue::forUnmanaged(fn); |
| } |
| case Kind::DynamicMethod: { |
| auto closureType = getDynamicMethodLoweredType( |
| SGF.SGM.M, *constant, getSubstFormalType()); |
| |
| ArgumentScope S(SGF, Loc); |
| SILValue fn = SGF.B.createObjCMethod( |
| Loc, borrowedSelf->getValue(), *constant, |
| closureType); |
| S.pop(); |
| return ManagedValue::forUnmanaged(fn); |
| } |
| } |
| llvm_unreachable("unhandled kind"); |
| } |
| |
| CalleeTypeInfo getTypeInfo(SILGenFunction &SGF) const & { |
| Optional<SILDeclRef> constant = None; |
| |
| if (Constant) |
| constant = Constant; |
| |
| switch (kind) { |
| case Kind::IndirectValue: |
| assert(Substitutions.empty()); |
| return createCalleeTypeInfo(SGF, constant, IndirectValue.getType()); |
| |
| case Kind::StandaloneFunctionDynamicallyReplaceableImpl: |
| case Kind::StandaloneFunction: { |
| auto constantInfo = |
| SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); |
| return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); |
| } |
| case Kind::EnumElement: { |
| // Emit a direct call to the element constructor thunk. |
| auto constantInfo = |
| SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); |
| return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); |
| } |
| case Kind::ClassMethod: { |
| auto constantInfo = SGF.SGM.Types.getConstantOverrideInfo( |
| SGF.getTypeExpansionContext(), *constant); |
| return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); |
| } |
| case Kind::SuperMethod: { |
| auto base = constant->getOverriddenVTableEntry(); |
| auto constantInfo = SGF.SGM.Types.getConstantOverrideInfo( |
| SGF.getTypeExpansionContext(), *constant, base); |
| return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); |
| } |
| case Kind::WitnessMethod: { |
| auto constantInfo = |
| SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); |
| return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); |
| } |
| case Kind::DynamicMethod: { |
| auto formalType = getDynamicMethodLoweredType( |
| SGF.SGM.M, *constant, getSubstFormalType()); |
| return createCalleeTypeInfo(SGF, constant, formalType); |
| } |
| } |
| llvm_unreachable("unhandled kind"); |
| } |
| |
| SubstitutionMap getSubstitutions() const { |
| return Substitutions; |
| } |
| |
| SILDeclRef getMethodName() const { |
| return Constant; |
| } |
| |
| /// Return a specialized emission function if this is a function with a known |
| /// lowering, such as a builtin, or return null if there is no specialized |
| /// emitter. |
| Optional<SpecializedEmitter> |
| getSpecializedEmitter(SILGenModule &SGM) const { |
| switch (kind) { |
| case Kind::StandaloneFunction: { |
| return SpecializedEmitter::forDecl(SGM, Constant); |
| } |
| case Kind::EnumElement: |
| case Kind::IndirectValue: |
| case Kind::ClassMethod: |
| case Kind::SuperMethod: |
| case Kind::WitnessMethod: |
| case Kind::DynamicMethod: |
| case Kind::StandaloneFunctionDynamicallyReplaceableImpl: |
| return None; |
| } |
| llvm_unreachable("bad callee kind"); |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| /// Is this a call to the dynamically replaced function inside of a |
| /// '@_dynamicReplacement(for:)' function. |
| bool isCallToReplacedInDynamicReplacement(SILGenFunction &SGF, |
| AbstractFunctionDecl *afd, |
| bool &isObjCReplacementSelfCall) { |
| if (auto *func = |
| dyn_cast_or_null<AbstractFunctionDecl>(SGF.FunctionDC->getAsDecl())) { |
| if (func->getDynamicallyReplacedDecl() == afd) { |
| isObjCReplacementSelfCall = afd->isObjC(); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // SILGenApply ASTVisitor |
| //===----------------------------------------------------------------------===// |
| |
| /// For ObjC init methods, we generate a shared-linkage Swift allocating entry |
| /// point that does the [[T alloc] init] dance. We want to use this native |
| /// thunk where we expect to be calling an allocating entry point for an ObjC |
| /// constructor. |
| static bool isConstructorWithGeneratedAllocatorThunk(ValueDecl *vd) { |
| return vd->isObjC() && isa<ConstructorDecl>(vd); |
| } |
| |
| namespace { |
| |
| /// An ASTVisitor for decomposing a nesting of ApplyExprs into an initial |
| /// Callee and a list of CallSites. The CallEmission class below uses these |
| /// to generate the actual SIL call. |
| /// |
| /// Formally, an ApplyExpr in the AST always has a single argument, which may |
| /// be of tuple type, possibly empty. Also, some callees have a formal type |
| /// which is curried -- for example, methods have type Self -> Arg -> Result. |
| /// |
| /// However, SIL functions take zero or more parameters and the natural entry |
| /// point of a method takes Self as an additional argument, rather than |
| /// returning a partial application. |
| /// |
| /// Therefore, nested ApplyExprs applied to a constant are flattened into a |
| /// single call of the most uncurried entry point fitting the call site. |
| /// This avoids intermediate closure construction. |
| /// |
| /// For example, a method reference 'self.method' decomposes into curry thunk |
| /// as the callee, with a single call site '(self)'. |
| /// |
| /// On the other hand, a call of a method 'self.method(x)(y)' with a function |
| /// return type decomposes into the method's natural entry point as the callee, |
| /// and two call sites, first '(x, self)' then '(y)'. |
| class SILGenApply : public Lowering::ExprVisitor<SILGenApply> { |
| public: |
| /// The SILGenFunction that we are emitting SIL into. |
| SILGenFunction &SGF; |
| |
| /// The apply callee that abstractly represents the entry point that is being |
| /// called. |
| Optional<Callee> applyCallee; |
| |
| /// The lvalue or rvalue representing the argument source of self. |
| ArgumentSource selfParam; |
| |
| ApplyExpr *selfApply = nullptr; |
| ApplyExpr *callSite = nullptr; |
| Expr *sideEffect = nullptr; |
| |
| SILGenApply(SILGenFunction &SGF) |
| : SGF(SGF) |
| {} |
| |
| void setCallee(Callee &&c) { |
| assert(!applyCallee && "already set callee!"); |
| applyCallee.emplace(std::move(c)); |
| } |
| |
| void setSideEffect(Expr *sideEffectExpr) { |
| assert(!sideEffect && "already set side effect!"); |
| sideEffect = sideEffectExpr; |
| } |
| |
| void setSelfParam(ArgumentSource &&theSelfParam) { |
| assert(!selfParam && "already set this!"); |
| selfParam = std::move(theSelfParam); |
| } |
| |
| bool isSelfApplyOfMethod(ApplyExpr *e) { |
| if (auto *selfApply = dyn_cast<ApplyExpr>(e->getFn())) { |
| if (auto *declRefExpr = dyn_cast<DeclRefExpr>(selfApply->getFn())) |
| return declRefExpr->getDecl()->getNumCurryLevels() == 2; |
| |
| if (isa<OtherConstructorDeclRefExpr>(selfApply->getFn())) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| void decompose(ApplyExpr *e) { |
| callSite = e; |
| |
| if (isSelfApplyOfMethod(e)) { |
| selfApply = cast<ApplyExpr>(e->getFn()); |
| |
| if (selfApply->isSuper()) { |
| applySuper(selfApply); |
| return; |
| } |
| |
| if (applyInitDelegation(selfApply)) |
| return; |
| |
| visit(selfApply->getFn()); |
| return; |
| } |
| |
| visit(e->getFn()); |
| } |
| |
| /// Fall back to an unknown, indirect callee. |
| void visitExpr(Expr *e) { |
| // TODO: preserve the function pointer at its original abstraction level |
| // when loading from memory. |
| |
| ManagedValue fn = SGF.emitRValueAsSingleValue(e); |
| auto substType = cast<FunctionType>(e->getType()->getCanonicalType()); |
| |
| // When calling an C or block function, there's implicit bridging. |
| auto origType = getIndirectApplyAbstractionPattern(SGF, substType); |
| |
| setCallee(Callee::forIndirect(fn, origType, substType, e)); |
| } |
| |
| static constexpr unsigned metatypeRepPair(MetatypeRepresentation a, |
| MetatypeRepresentation b) { |
| return assert(unsigned(a) < 256 && unsigned(b) < 256 |
| && "MetatypeRepresentation got too big for its britches"), |
| unsigned(a) << 8 | unsigned(b); |
| } |
| |
| /// Idempotently convert a metatype to a thick or objc metatype, depending |
| /// on what allocation mechanism we need for a given class hierarchy. |
| std::pair<ManagedValue, SILType> |
| convertToMetatypeForAllocRefDynamic(ManagedValue selfMeta, |
| SILLocation loc, |
| bool usesObjCAllocation) { |
| auto givenMetatype = selfMeta.getType().castTo<AnyMetatypeType>(); |
| CanType instanceType = givenMetatype.getInstanceType(); |
| |
| auto destMetatypeRep = usesObjCAllocation |
| ? MetatypeRepresentation::ObjC |
| : MetatypeRepresentation::Thick; |
| |
| // If we are already the right rep, just return. |
| auto givenMetatypeRep = givenMetatype->getRepresentation(); |
| if (givenMetatypeRep == destMetatypeRep) { |
| return {selfMeta, SGF.getLoweredType(instanceType)}; |
| } |
| |
| CanAnyMetatypeType destMetatype; |
| if (isa<MetatypeType>(givenMetatype)) { |
| destMetatype = |
| CanMetatypeType::get(instanceType, destMetatypeRep); |
| } else { |
| destMetatype = CanExistentialMetatypeType::get(instanceType, |
| destMetatypeRep); |
| } |
| // Metatypes are trivial and thus do not have a cleanup. Only if we |
| // convert them to an object do they become non-trivial. |
| assert(!selfMeta.hasCleanup()); |
| SILValue convertedValue; |
| switch (metatypeRepPair(givenMetatypeRep, destMetatypeRep)) { |
| case metatypeRepPair(MetatypeRepresentation::Thick, |
| MetatypeRepresentation::ObjC): |
| convertedValue = SGF.B.emitThickToObjCMetatype( |
| loc, selfMeta.getValue(), |
| SILType::getPrimitiveObjectType(destMetatype)); |
| break; |
| |
| case metatypeRepPair(MetatypeRepresentation::ObjC, |
| MetatypeRepresentation::Thick): |
| convertedValue = SGF.B.emitObjCToThickMetatype( |
| loc, selfMeta.getValue(), |
| SILType::getPrimitiveObjectType(destMetatype)); |
| break; |
| |
| default: |
| llvm_unreachable("shouldn't happen"); |
| } |
| |
| auto result = ManagedValue::forUnmanaged(convertedValue); |
| return {result, SGF.getLoweredType(instanceType)}; |
| } |
| |
| /// Given a metatype value for the type, allocate an Objective-C |
| /// object (with alloc_ref_dynamic) of that type. |
| /// |
| /// \returns the self object. |
| ManagedValue allocateObject(ManagedValue selfMeta, |
| SILLocation loc, |
| bool usesObjCAllocation) { |
| // Convert to the necessary metatype representation, if needed. |
| ManagedValue selfMetaConverted; |
| SILType instanceType; |
| std::tie(selfMetaConverted, instanceType) = |
| convertToMetatypeForAllocRefDynamic(selfMeta, loc, usesObjCAllocation); |
| |
| // Allocate the object. |
| return SGF.B.createAllocRefDynamic(loc, selfMetaConverted, instanceType, |
| usesObjCAllocation, {}, {}); |
| } |
| |
| void processProtocolMethod(DeclRefExpr *e, AbstractFunctionDecl *afd, |
| ProtocolDecl *proto) { |
| ArgumentSource selfValue = selfApply->getArg(); |
| |
| auto subs = e->getDeclRef().getSubstitutions(); |
| |
| SILDeclRef::Kind kind = SILDeclRef::Kind::Func; |
| if (isa<ConstructorDecl>(afd)) { |
| if (proto->isObjC()) { |
| SILLocation loc = selfApply->getArg(); |
| |
| // For Objective-C initializers, we only have an initializing |
| // initializer. We need to allocate the object ourselves. |
| kind = SILDeclRef::Kind::Initializer; |
| |
| auto metatype = std::move(selfValue).getAsSingleValue(SGF); |
| auto allocated = allocateObject(metatype, loc, /*objc*/ true); |
| auto allocatedType = allocated.getType().getASTType(); |
| selfValue = |
| ArgumentSource(loc, RValue(SGF, loc, allocatedType, allocated)); |
| } else { |
| // For non-Objective-C initializers, we have an allocating |
| // initializer to call. |
| kind = SILDeclRef::Kind::Allocator; |
| } |
| } |
| |
| SILDeclRef constant(afd, kind); |
| constant = constant.asForeign(afd->isObjC()); |
| |
| // Prepare the callee. |
| Callee theCallee = Callee::forWitnessMethod( |
| SGF, selfValue.getSubstRValueType(), |
| constant, subs, e); |
| |
| setSelfParam(std::move(selfValue)); |
| setCallee(std::move(theCallee)); |
| } |
| |
| bool isClassMethod(DeclRefExpr *e, AbstractFunctionDecl *afd) { |
| if (e->getAccessSemantics() != AccessSemantics::Ordinary) |
| return false; |
| |
| if (getMethodDispatch(afd) == MethodDispatch::Static) |
| return false; |
| |
| if (auto ctor = dyn_cast<ConstructorDecl>(afd)) { |
| // Non-required initializers are statically dispatched. |
| if (!ctor->isRequired()) |
| return false; |
| |
| // @objc dynamic initializers are statically dispatched (we're |
| // calling the allocating entry point, which is a thunk that |
| // does the dynamic dispatch for us). |
| if (ctor->shouldUseObjCDispatch()) |
| return false; |
| |
| // Required constructors are statically dispatched when the 'self' |
| // value is statically derived. |
| assert(selfApply->getArg()->getType()->is<AnyMetatypeType>()); |
| if (selfApply->getArg()->isStaticallyDerivedMetatype()) |
| return false; |
| } |
| |
| // Ok, we're dynamically dispatched. |
| return true; |
| } |
| |
| void processClassMethod(DeclRefExpr *e, AbstractFunctionDecl *afd) { |
| ArgumentSource selfArgSource(selfApply->getArg()); |
| setSelfParam(std::move(selfArgSource)); |
| |
| // Directly dispatch to calls of the replaced function inside of |
| // '@_dynamicReplacement(for:)' methods. |
| bool isObjCReplacementCall = false; |
| if (SGF.getOptions() |
| .EnableDynamicReplacementCanCallPreviousImplementation && |
| isCallToReplacedInDynamicReplacement(SGF, afd, isObjCReplacementCall) && |
| selfApply->getArg()->isSelfExprOf( |
| cast<AbstractFunctionDecl>(SGF.FunctionDC->getAsDecl()), false)) { |
| auto constant = SILDeclRef(afd).asForeign( |
| !isObjCReplacementCall && requiresForeignEntryPoint(e->getDecl())); |
| auto subs = e->getDeclRef().getSubstitutions(); |
| if (isObjCReplacementCall) |
| setCallee(Callee::forDirect(SGF, constant, subs, e)); |
| else |
| setCallee(Callee::forDirect( |
| SGF, |
| SILDeclRef(cast<AbstractFunctionDecl>(SGF.FunctionDC->getAsDecl())), |
| subs, e, true)); |
| return; |
| } |
| |
| auto constant = SILDeclRef(afd).asForeign(requiresForeignEntryPoint(afd)); |
| |
| auto subs = e->getDeclRef().getSubstitutions(); |
| |
| bool isObjCDirect = false; |
| if (auto objcDecl = dyn_cast_or_null<clang::ObjCMethodDecl>( |
| afd->getClangDecl())) { |
| isObjCDirect = objcDecl->isDirectMethod(); |
| } |
| |
| if (isObjCDirect) { |
| setCallee(Callee::forDirect(SGF, constant, subs, e)); |
| } else { |
| setCallee(Callee::forClassMethod(SGF, constant, subs, e)); |
| } |
| } |
| |
| // |
| // Known callees. |
| // |
| void visitDeclRefExpr(DeclRefExpr *e) { |
| auto subs = e->getDeclRef().getSubstitutions(); |
| |
| // If this is a direct reference to a vardecl, just emit its value directly. |
| // Recursive references to callable declarations are allowed. |
| if (isa<VarDecl>(e->getDecl())) { |
| visitExpr(e); |
| return; |
| } |
| |
| // Enum case constructor references are open-coded. |
| if (auto *eed = dyn_cast<EnumElementDecl>(e->getDecl())) { |
| if (selfApply) { |
| ArgumentSource selfArgSource(selfApply->getArg()); |
| setSelfParam(std::move(selfArgSource)); |
| } |
| |
| setCallee(Callee::forEnumElement(SGF, SILDeclRef(eed), subs, e)); |
| return; |
| } |
| |
| // Ok, we have a constructor or a function. |
| auto *afd = cast<AbstractFunctionDecl>(e->getDecl()); |
| |
| // Witness method or @objc protocol dispatch. |
| if (auto *proto = dyn_cast<ProtocolDecl>(afd->getDeclContext())) { |
| processProtocolMethod(e, afd, proto); |
| return; |
| } |
| |
| // VTable class method or @objc class method dispatch. |
| if (isClassMethod(e, afd)) { |
| processClassMethod(e, afd); |
| return; |
| } |
| |
| // Otherwise, we have a statically-dispatched call. |
| auto constant = SILDeclRef(e->getDecl()) |
| .asForeign(!isConstructorWithGeneratedAllocatorThunk(e->getDecl()) |
| && requiresForeignEntryPoint(e->getDecl())); |
| |
| auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(constant); |
| if (afd->getDeclContext()->isLocalContext() && |
| !captureInfo.hasGenericParamCaptures()) |
| subs = SubstitutionMap(); |
| |
| // Check whether we have to dispatch to the original implementation of a |
| // dynamically_replaceable inside of a dynamic_replacement(for:) function. |
| ApplyExpr *thisCallSite = (selfApply ? selfApply : callSite); |
| bool isObjCReplacementSelfCall = false; |
| bool isSelfCallToReplacedInDynamicReplacement = |
| SGF.getOptions() |
| .EnableDynamicReplacementCanCallPreviousImplementation && |
| isCallToReplacedInDynamicReplacement( |
| SGF, cast<AbstractFunctionDecl>(constant.getDecl()), |
| isObjCReplacementSelfCall) && |
| (afd->getDeclContext()->isModuleScopeContext() || |
| thisCallSite->getArg()->isSelfExprOf( |
| cast<AbstractFunctionDecl>(SGF.FunctionDC->getAsDecl()), false)); |
| |
| if (isSelfCallToReplacedInDynamicReplacement && !isObjCReplacementSelfCall) |
| setCallee(Callee::forDirect( |
| SGF, |
| SILDeclRef(cast<AbstractFunctionDecl>(SGF.FunctionDC->getAsDecl()), |
| constant.kind), |
| subs, e, true)); |
| else |
| setCallee(Callee::forDirect(SGF, constant, subs, e)); |
| |
| if (selfApply) { |
| // This is a statically-dispatched method with a 'self' parameter. |
| ArgumentSource selfArgSource(selfApply->getArg()); |
| setSelfParam(std::move(selfArgSource)); |
| } |
| |
| // If the decl ref requires captures, emit the capture params. |
| if (!captureInfo.getCaptures().empty()) { |
| SmallVector<ManagedValue, 4> captures; |
| SGF.emitCaptures(e, SILDeclRef(afd), |
| CaptureEmission::ImmediateApplication, |
| captures); |
| applyCallee->setCaptures(std::move(captures)); |
| } |
| } |
| |
| void visitAbstractClosureExpr(AbstractClosureExpr *e) { |
| // Emit the closure body. |
| SGF.SGM.emitClosure(e); |
| |
| // If we're in top-level code, we don't need to physically capture script |
| // globals, but we still need to mark them as escaping so that DI can flag |
| // uninitialized uses. |
| if (&SGF == SGF.SGM.TopLevelSGF) { |
| SGF.SGM.emitMarkFunctionEscapeForTopLevelCodeGlobals(e,e->getCaptureInfo()); |
| } |
| |
| // A directly-called closure can be emitted as a direct call instead of |
| // really producing a closure object. |
| SILDeclRef constant(e); |
| |
| auto captureInfo = SGF.SGM.M.Types.getLoweredLocalCaptures(constant); |
| |
| SubstitutionMap subs; |
| if (captureInfo.hasGenericParamCaptures()) |
| subs = SGF.getForwardingSubstitutionMap(); |
| |
| setCallee(Callee::forDirect(SGF, constant, subs, e)); |
| |
| // If the closure requires captures, emit them. |
| if (!captureInfo.getCaptures().empty()) { |
| SmallVector<ManagedValue, 4> captures; |
| SGF.emitCaptures(e, constant, CaptureEmission::ImmediateApplication, |
| captures); |
| applyCallee->setCaptures(std::move(captures)); |
| } |
| } |
| |
| void visitOtherConstructorDeclRefExpr(OtherConstructorDeclRefExpr *e) { |
| auto subs = e->getDeclRef().getSubstitutions(); |
| |
| // FIXME: We might need to go through ObjC dispatch for references to |
| // constructors imported from Clang (which won't have a direct entry point) |
| // or to delegate to a designated initializer. |
| setCallee(Callee::forDirect(SGF, |
| SILDeclRef(e->getDecl(), SILDeclRef::Kind::Initializer), |
| subs, e)); |
| } |
| |
| void visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *e) { |
| setSideEffect(e->getLHS()); |
| visit(e->getRHS()); |
| } |
| |
| void visitFunctionConversionExpr(FunctionConversionExpr *e) { |
| // FIXME: Check whether this function conversion requires us to build a |
| // thunk. |
| visit(e->getSubExpr()); |
| } |
| |
| void visitCovariantFunctionConversionExpr(CovariantFunctionConversionExpr *e){ |
| // FIXME: These expressions merely adjust the result type for DynamicSelf |
| // in an unchecked, ABI-compatible manner. They shouldn't prevent us form |
| // forming a complete call. |
| visitExpr(e); |
| } |
| |
| void visitImplicitlyUnwrappedFunctionConversionExpr( |
| ImplicitlyUnwrappedFunctionConversionExpr *e) { |
| // These are generated for short term use in the type checker. |
| llvm_unreachable( |
| "We should not see ImplicitlyUnwrappedFunctionConversionExpr here"); |
| } |
| |
| void visitIdentityExpr(IdentityExpr *e) { |
| visit(e->getSubExpr()); |
| } |
| |
| void applySuper(ApplyExpr *apply) { |
| // Load the 'super' argument. |
| Expr *arg = apply->getArg(); |
| RValue super; |
| CanType superFormalType = arg->getType()->getCanonicalType(); |
| |
| // The callee for a super call has to be either a method or constructor. |
| Expr *fn = apply->getFn(); |
| SubstitutionMap substitutions; |
| SILDeclRef constant; |
| if (auto *ctorRef = dyn_cast<OtherConstructorDeclRefExpr>(fn)) { |
| constant = SILDeclRef(ctorRef->getDecl(), SILDeclRef::Kind::Initializer) |
| .asForeign(requiresForeignEntryPoint(ctorRef->getDecl())); |
| |
| if (ctorRef->getDeclRef().isSpecialized()) |
| substitutions = ctorRef->getDeclRef().getSubstitutions(); |
| |
| assert(SGF.SelfInitDelegationState == |
| SILGenFunction::WillSharedBorrowSelf); |
| SGF.SelfInitDelegationState = SILGenFunction::WillExclusiveBorrowSelf; |
| super = SGF.emitRValue(arg); |
| assert(SGF.SelfInitDelegationState == |
| SILGenFunction::DidExclusiveBorrowSelf); |
| |
| // We know that we have a single ManagedValue rvalue for self. |
| ManagedValue superMV = std::move(super).getScalarValue(); |
| |
| // Check if super is not the same as our base type. This means that we |
| // performed an upcast, and we must have consumed the special cleanup |
| // we installed. Install a new special cleanup. |
| if (superMV.getValue() != SGF.InitDelegationSelf.getValue()) { |
| SILValue underlyingSelf = SGF.InitDelegationSelf.getValue(); |
| SGF.InitDelegationSelf = ManagedValue::forUnmanaged(underlyingSelf); |
| CleanupHandle newWriteback = SGF.enterOwnedValueWritebackCleanup( |
| SGF.InitDelegationLoc.getValue(), SGF.InitDelegationSelfBox, |
| superMV.forward(SGF)); |
| SGF.SuperInitDelegationSelf = |
| ManagedValue(superMV.getValue(), newWriteback); |
| super = RValue(SGF, SGF.InitDelegationLoc.getValue(), superFormalType, |
| SGF.SuperInitDelegationSelf); |
| } |
| |
| } else if (auto *declRef = dyn_cast<DeclRefExpr>(fn)) { |
| assert(isa<FuncDecl>(declRef->getDecl()) && "non-function super call?!"); |
| constant = SILDeclRef(declRef->getDecl()) |
| .asForeign(requiresForeignEntryPoint(declRef->getDecl())); |
| |
| if (declRef->getDeclRef().isSpecialized()) |
| substitutions = declRef->getDeclRef().getSubstitutions(); |
| super = SGF.emitRValue(arg); |
| } else { |
| llvm_unreachable("invalid super callee"); |
| } |
| |
| assert(super.isComplete() && "At this point super should be a complete " |
| "rvalue that is not in any special states"); |
| ArgumentSource superArgSource(arg, std::move(super)); |
| if (!canUseStaticDispatch(SGF, constant)) { |
| // ObjC super calls require dynamic dispatch. |
| setCallee(Callee::forSuperMethod(SGF, constant, substitutions, fn)); |
| } else { |
| // Native Swift super calls to final methods are direct. |
| setCallee(Callee::forDirect(SGF, constant, substitutions, fn)); |
| } |
| |
| setSelfParam(std::move(superArgSource)); |
| } |
| |
| /// Walk the given \c selfArg expression that produces the appropriate |
| /// `self` for a call, applying the same transformations to the provided |
| /// \c selfValue (which might be a metatype). |
| /// |
| /// This is used for initializer delegation, so it covers only the narrow |
| /// subset of expressions used there. |
| ManagedValue emitCorrespondingSelfValue(ManagedValue selfValue, |
| Expr *selfArg) { |
| SILLocation loc = selfArg; |
| auto resultTy = selfArg->getType()->getCanonicalType(); |
| while (true) { |
| // Handle archetype-to-super and derived-to-base upcasts. |
| if (isa<ArchetypeToSuperExpr>(selfArg) || |
| isa<DerivedToBaseExpr>(selfArg)) { |
| selfArg = cast<ImplicitConversionExpr>(selfArg)->getSubExpr(); |
| continue; |
| } |
| |
| // Skip over loads. |
| if (auto load = dyn_cast<LoadExpr>(selfArg)) { |
| selfArg = load->getSubExpr(); |
| resultTy = resultTy->getRValueType()->getCanonicalType(); |
| continue; |
| } |
| |
| // Skip over inout expressions. |
| if (auto inout = dyn_cast<InOutExpr>(selfArg)) { |
| selfArg = inout->getSubExpr(); |
| resultTy = resultTy->getInOutObjectType()->getCanonicalType(); |
| continue; |
| } |
| |
| // Declaration references terminate the search. |
| if (isa<DeclRefExpr>(selfArg)) |
| break; |
| |
| llvm_unreachable("unhandled conversion for metatype value"); |
| } |
| assert(isa<DeclRefExpr>(selfArg) && |
| "unexpected expr kind in self argument of initializer delegation"); |
| |
| // If the 'self' value is a metatype, update the target type |
| // accordingly. |
| SILType loweredResultTy; |
| auto selfMetaTy = selfValue.getType().getAs<AnyMetatypeType>(); |
| if (selfMetaTy) { |
| loweredResultTy = SILType::getPrimitiveObjectType( |
| CanMetatypeType::get(resultTy, selfMetaTy->getRepresentation())); |
| } else { |
| loweredResultTy = SGF.getLoweredLoadableType(resultTy); |
| } |
| |
| if (loweredResultTy != selfValue.getType()) { |
| // Introduce dynamic Self if necessary. A class initializer receives |
| // a metatype argument that's formally the non-dynamic base class type |
| // (though always dynamically of Self type), |
| // but when invoking a protocol initializer, we need to pass it as |
| // dynamic Self. |
| if (!selfValue.getType().getASTType()->hasDynamicSelfType() |
| && loweredResultTy.getASTType()->hasDynamicSelfType()) { |
| assert(selfMetaTy); |
| selfValue = SGF.emitManagedRValueWithCleanup( |
| SGF.B.createUncheckedReinterpretCast(loc, selfValue.forward(SGF), |
| loweredResultTy)); |
| } else { |
| selfValue = SGF.emitManagedRValueWithCleanup( |
| SGF.B.createUpcast(loc, selfValue.forward(SGF), loweredResultTy)); |
| } |
| } |
| return selfValue; |
| } |
| |
| /// Try to emit the given application as initializer delegation. |
| bool applyInitDelegation(ApplyExpr *expr) { |
| // Dig out the constructor we're delegating to. |
| Expr *fn = expr->getFn(); |
| auto ctorRef = dyn_cast<OtherConstructorDeclRefExpr>( |
| fn->getSemanticsProvidingExpr()); |
| if (!ctorRef) |
| return false; |
| |
| // Determine whether we'll need to use an allocating constructor (vs. the |
| // initializing constructor). |
| auto nominal = ctorRef->getDecl()->getDeclContext() |
| ->getSelfNominalTypeDecl(); |
| bool useAllocatingCtor; |
| |
| // Value types only have allocating initializers. |
| if (isa<StructDecl>(nominal) || isa<EnumDecl>(nominal)) |
| useAllocatingCtor = true; |
| // Protocols only witness allocating initializers, except for @objc |
| // protocols, which only witness initializing initializers. |
| else if (auto proto = dyn_cast<ProtocolDecl>(nominal)) { |
| useAllocatingCtor = !proto->isObjC(); |
| // Factory initializers are effectively "allocating" initializers with no |
| // corresponding initializing entry point. |
| } else if (ctorRef->getDecl()->isFactoryInit()) { |
| useAllocatingCtor = true; |
| // If we're emitting a class initializer's non-allocating entry point and |
| // delegating to an initializer exposed to Objective-C, use the initializing |
| // entry point to avoid replacing an existing allocated object. |
| } else if (!SGF.AllocatorMetatype && ctorRef->getDecl()->isObjC()) { |
| useAllocatingCtor = false; |
| // In general, though, class initializers self.init-delegate to each other |
| // via their allocating entry points. |
| } else { |
| assert(isa<ClassDecl>(nominal) |
| && "some new kind of init context we haven't implemented"); |
| useAllocatingCtor = !requiresForeignEntryPoint(ctorRef->getDecl()); |
| } |
| |
| // Load the 'self' argument. |
| Expr *arg = expr->getArg(); |
| ManagedValue self; |
| CanType selfFormalType = arg->getType()->getCanonicalType(); |
| |
| // If we're using the allocating constructor, we need to pass along the |
| // metatype. |
| if (useAllocatingCtor) { |
| selfFormalType = CanMetatypeType::get( |
| selfFormalType->getInOutObjectType()->getCanonicalType()); |
| |
| // If the initializer is a C function imported as a member, |
| // there is no 'self' parameter. Mark it undef. |
| if (ctorRef->getDecl()->isImportAsMember()) { |
| self = SGF.emitUndef(selfFormalType); |
| } else if (SGF.AllocatorMetatype) { |
| self = emitCorrespondingSelfValue( |
| ManagedValue::forUnmanaged(SGF.AllocatorMetatype), arg); |
| } else { |
| self = ManagedValue::forUnmanaged(SGF.emitMetatypeOfValue(expr, arg)); |
| } |
| } else { |
| // If we haven't allocated "self" yet at this point, do so. |
| if (SGF.AllocatorMetatype) { |
| bool usesObjCAllocation; |
| if (auto clas = dyn_cast<ClassDecl>(nominal)) { |
| usesObjCAllocation = usesObjCAllocator(clas); |
| } else { |
| // In the protocol extension case, we should only be here if the callee |
| // initializer is @objc. |
| usesObjCAllocation = true; |
| } |
| |
| self = allocateObject( |
| ManagedValue::forUnmanaged(SGF.AllocatorMetatype), arg, |
| usesObjCAllocation); |
| |
| // Perform any adjustments needed to 'self'. |
| self = emitCorrespondingSelfValue(self, arg); |
| } else { |
| assert(SGF.SelfInitDelegationState == |
| SILGenFunction::WillSharedBorrowSelf); |
| SGF.SelfInitDelegationState = SILGenFunction::WillExclusiveBorrowSelf; |
| self = SGF.emitRValueAsSingleValue(arg); |
| assert(SGF.SelfInitDelegationState == |
| SILGenFunction::DidExclusiveBorrowSelf); |
| } |
| } |
| |
| auto subs = ctorRef->getDeclRef().getSubstitutions(); |
| ArgumentSource selfArgSource(arg, RValue(SGF, expr, selfFormalType, self)); |
| |
| SILDeclRef constant(ctorRef->getDecl(), |
| useAllocatingCtor |
| ? SILDeclRef::Kind::Allocator |
| : SILDeclRef::Kind::Initializer); |
| |
| bool isObjCReplacementSelfCall = false; |
| bool isSelfCallToReplacedInDynamicReplacement = |
| SGF.getOptions() |
| .EnableDynamicReplacementCanCallPreviousImplementation && |
| isCallToReplacedInDynamicReplacement( |
| SGF, cast<AbstractFunctionDecl>(constant.getDecl()), |
| isObjCReplacementSelfCall) && |
| arg->isSelfExprOf( |
| cast<AbstractFunctionDecl>(SGF.FunctionDC->getAsDecl()), false); |
| |
| if (!isObjCReplacementSelfCall) { |
| if (useAllocatingCtor) { |
| constant = |
| constant.asForeign(requiresForeignEntryPoint(ctorRef->getDecl())); |
| } else { |
| // Note: if we ever implement delegating from one designated initializer |
| // to another, this won't be correct; that should do a direct dispatch. |
| constant = constant.asForeign(ctorRef->getDecl()->isObjC()); |
| } |
| } |
| |
| // Determine the callee. This is normally the allocating |
| // entry point, unless we're delegating to an ObjC initializer. |
| if (isa<ProtocolDecl>(ctorRef->getDecl()->getDeclContext())) { |
| // Look up the witness for the constructor. |
| setCallee(Callee::forWitnessMethod( |
| SGF, self.getType().getASTType(), |
| constant, subs, expr)); |
| } else if ((useAllocatingCtor || constant.isForeign) && |
| !isSelfCallToReplacedInDynamicReplacement && |
| ((constant.isForeign && !useAllocatingCtor) || |
| getMethodDispatch(ctorRef->getDecl()) == MethodDispatch::Class)) { |
| // Dynamic dispatch to the initializer. |
| Scope S(SGF, expr); |
| setCallee(Callee::forClassMethod( |
| SGF, constant, subs, fn)); |
| } else { |
| // Directly call the peer constructor. |
| if (isObjCReplacementSelfCall || |
| !isSelfCallToReplacedInDynamicReplacement) |
| setCallee(Callee::forDirect(SGF, constant, subs, fn)); |
| else |
| setCallee(Callee::forDirect( |
| SGF, |
| SILDeclRef(cast<AbstractFunctionDecl>(SGF.FunctionDC->getAsDecl()), |
| constant.kind), |
| subs, fn, true)); |
| } |
| |
| setSelfParam(std::move(selfArgSource)); |
| |
| return true; |
| } |
| |
| Callee getCallee() { |
| assert(applyCallee && "did not find callee?!"); |
| return std::move(*applyCallee); |
| } |
| |
| /// Ignore parentheses and implicit conversions. |
| static Expr *ignoreParensAndImpConversions(Expr *expr) { |
| while (true) { |
| if (auto ice = dyn_cast<ImplicitConversionExpr>(expr)) { |
| expr = ice->getSubExpr(); |
| continue; |
| } |
| |
| // Simple optional-to-optional conversions. This doesn't work |
| // for the full generality of OptionalEvaluationExpr, but it |
| // works given that we check the result for certain forms. |
| if (auto eval = dyn_cast<OptionalEvaluationExpr>(expr)) { |
| if (auto inject = dyn_cast<InjectIntoOptionalExpr>(eval->getSubExpr())) { |
| if (auto bind = dyn_cast<BindOptionalExpr>(inject->getSubExpr())) { |
| if (bind->getDepth() == 0) |
| return bind->getSubExpr(); |
| } |
| } |
| } |
| |
| auto valueProviding = expr->getValueProvidingExpr(); |
| if (valueProviding != expr) { |
| expr = valueProviding; |
| continue; |
| } |
| |
| return expr; |
| } |
| } |
| |
| void visitForceValueExpr(ForceValueExpr *e) { |
| // If this application is a dynamic member reference that is forced to |
| // succeed with the '!' operator, emit it as a direct invocation of the |
| // method we found. |
| if (emitForcedDynamicMemberRef(e)) |
| return; |
| |
| visitExpr(e); |
| } |
| |
| /// If this application forces a dynamic member reference with !, emit |
| /// a direct reference to the member. |
| bool emitForcedDynamicMemberRef(ForceValueExpr *e) { |
| // Check whether the argument is a dynamic member reference. |
| auto arg = ignoreParensAndImpConversions(e->getSubExpr()); |
| |
| auto openExistential = dyn_cast<OpenExistentialExpr>(arg); |
| if (openExistential) |
| arg = openExistential->getSubExpr(); |
| |
| auto dynamicMemberRef = dyn_cast<DynamicMemberRefExpr>(arg); |
| if (!dynamicMemberRef) |
| return false; |
| |
| // Since we'll be collapsing this call site, make sure there's another |
| // call site that will actually perform the invocation. |
| if (callSite == nullptr) |
| return false; |
| |
| // Only @objc methods can be forced. |
| auto memberRef = dynamicMemberRef->getMember(); |
| auto *fd = dyn_cast<FuncDecl>(memberRef.getDecl()); |
| if (!fd || !fd->isObjC()) |
| return false; |
| |
| FormalEvaluationScope writebackScope(SGF); |
| |
| // Local function that actually emits the dynamic member reference. |
| auto emitDynamicMemberRef = [&] { |
| // We found it. Emit the base. |
| ArgumentSource baseArgSource(dynamicMemberRef->getBase(), |
| SGF.emitRValue(dynamicMemberRef->getBase())); |
| |
| // Determine the type of the method we referenced, by replacing the |
| // class type of the 'Self' parameter with AnyObject. |
| auto member = SILDeclRef(fd).asForeign(); |
| |
| auto substFormalType = cast<FunctionType>(dynamicMemberRef->getType() |
| ->getCanonicalType() |
| .getOptionalObjectType()); |
| auto substSelfType = dynamicMemberRef->getBase()->getType()->getCanonicalType(); |
| substFormalType = CanFunctionType::get( |
| {AnyFunctionType::Param(substSelfType)}, |
| substFormalType); |
| |
| setCallee(Callee::forDynamic(SGF, member, |
| memberRef.getSubstitutions(), |
| substFormalType, {}, e)); |
| setSelfParam(std::move(baseArgSource)); |
| }; |
| |
| // When we have an open existential, open it and then emit the |
| // member reference. |
| if (openExistential) { |
| SGF.emitOpenExistentialExpr(openExistential, |
| [&](Expr*) { emitDynamicMemberRef(); }); |
| } else { |
| emitDynamicMemberRef(); |
| } |
| return true; |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| static PreparedArguments emitStringLiteral(SILGenFunction &SGF, Expr *E, |
| StringRef Str, SGFContext C, |
| StringLiteralExpr::Encoding encoding) { |
| uint64_t Length; |
| bool isASCII = SGF.getASTContext().isASCIIString(Str); |
| StringLiteralInst::Encoding instEncoding; |
| switch (encoding) { |
| case StringLiteralExpr::UTF8: |
| instEncoding = StringLiteralInst::Encoding::UTF8; |
| Length = Str.size(); |
| break; |
| |
| case StringLiteralExpr::OneUnicodeScalar: { |
| SILType Int32Ty = SILType::getBuiltinIntegerType(32, SGF.getASTContext()); |
| SILValue UnicodeScalarValue = |
| SGF.B.createIntegerLiteral(E, Int32Ty, |
| unicode::extractFirstUnicodeScalar(Str)); |
| |
| AnyFunctionType::Param param(Int32Ty.getASTType()); |
| PreparedArguments args(llvm::ArrayRef<AnyFunctionType::Param>{param}); |
| args.add(E, RValue(SGF, E, Int32Ty.getASTType(), |
| ManagedValue::forUnmanaged(UnicodeScalarValue))); |
| return args; |
| } |
| } |
| |
| // The string literal provides the data. |
| auto *string = SGF.B.createStringLiteral(E, Str, instEncoding); |
| |
| // The length is lowered as an integer_literal. |
| auto WordTy = SILType::getBuiltinWordType(SGF.getASTContext()); |
| auto *lengthInst = SGF.B.createIntegerLiteral(E, WordTy, Length); |
| |
| // The 'isascii' bit is lowered as an integer_literal. |
| auto Int1Ty = SILType::getBuiltinIntegerType(1, SGF.getASTContext()); |
| auto *isASCIIInst = SGF.B.createIntegerLiteral(E, Int1Ty, isASCII); |
| |
| |
| ManagedValue EltsArray[] = { |
| ManagedValue::forUnmanaged(string), |
| ManagedValue::forUnmanaged(lengthInst), |
| ManagedValue::forUnmanaged(isASCIIInst) |
| }; |
| |
| AnyFunctionType::Param TypeEltsArray[] = { |
| AnyFunctionType::Param(EltsArray[0].getType().getASTType()), |
| AnyFunctionType::Param(EltsArray[1].getType().getASTType()), |
| AnyFunctionType::Param(EltsArray[2].getType().getASTType()) |
| }; |
| |
| ArrayRef<ManagedValue> Elts; |
| ArrayRef<AnyFunctionType::Param> TypeElts; |
| switch (instEncoding) { |
| case StringLiteralInst::Encoding::UTF8: |
| Elts = EltsArray; |
| TypeElts = TypeEltsArray; |
| break; |
| |
| case StringLiteralInst::Encoding::Bytes: |
| case StringLiteralInst::Encoding::ObjCSelector: |
| llvm_unreachable("these cannot be formed here"); |
| } |
| |
| PreparedArguments args(TypeElts); |
| for (unsigned i = 0, e = Elts.size(); i != e; ++i) { |
| args.add(E, RValue(SGF, Elts[i], CanType(TypeElts[i].getPlainType()))); |
| } |
| return args; |
| } |
| |
| /// Emit a raw apply operation, performing no additional lowering of |
| /// either the arguments or the result. |
| static void emitRawApply(SILGenFunction &SGF, |
| SILLocation loc, |
| ManagedValue fn, |
| SubstitutionMap subs, |
| ArrayRef<ManagedValue> args, |
| CanSILFunctionType substFnType, |
| ApplyOptions options, |
| ArrayRef<SILValue> indirectResultAddrs, |
| SmallVectorImpl<SILValue> &rawResults) { |
| SILFunctionConventions substFnConv(substFnType, SGF.SGM.M); |
| // Get the callee value. |
| bool isConsumed = substFnType->isCalleeConsumed(); |
| bool isUnowned = substFnType->isCalleeUnowned(); |
| SILValue fnValue = |
| isUnowned ? fn.getValue() |
| : isConsumed ? fn.forward(SGF) |
| : fn.formalAccessBorrow(SGF, loc).getValue(); |
| |
| SmallVector<SILValue, 4> argValues; |
| |
| // Add the buffers for the indirect results if needed. |
| #ifndef NDEBUG |
| assert(indirectResultAddrs.size() == substFnConv.getNumIndirectSILResults()); |
| unsigned resultIdx = 0; |
| for (auto indResultTy : |
| substFnConv.getIndirectSILResultTypes(SGF.getTypeExpansionContext())) { |
| assert(indResultTy == indirectResultAddrs[resultIdx++]->getType()); |
| } |
| #endif |
| argValues.append(indirectResultAddrs.begin(), indirectResultAddrs.end()); |
| |
| auto inputParams = substFnType->getParameters(); |
| assert(inputParams.size() == args.size()); |
| |
| // Gather the arguments. |
| for (auto i : indices(args)) { |
| auto argValue = (inputParams[i].isConsumed() ? args[i].forward(SGF) |
| : args[i].getValue()); |
| #ifndef NDEBUG |
| auto inputTy = |
| substFnConv.getSILType(inputParams[i], SGF.getTypeExpansionContext()); |
| if (argValue->getType() != inputTy) { |
| auto &out = llvm::errs(); |
| out << "TYPE MISMATCH IN ARGUMENT " << i << " OF APPLY AT "; |
| printSILLocationDescription(out, loc, SGF.getASTContext()); |
| out << " argument value: "; |
| argValue->print(out); |
| out << " parameter type: "; |
| inputTy.print(out); |
| out << "\n"; |
| abort(); |
| } |
| #endif |
| argValues.push_back(argValue); |
| } |
| |
| auto resultType = substFnConv.getSILResultType(SGF.getTypeExpansionContext()); |
| |
| // If the function is a coroutine, we need to use 'begin_apply'. |
| if (substFnType->isCoroutine()) { |
| assert(!substFnType->hasErrorResult()); |
| auto apply = SGF.B.createBeginApply(loc, fnValue, subs, argValues); |
| for (auto result : apply->getAllResults()) |
| rawResults.push_back(result); |
| return; |
| } |
| |
| // If we don't have an error result, we can make a simple 'apply'. |
| if (!substFnType->hasErrorResult()) { |
| auto result = SGF.B.createApply(loc, fnValue, subs, argValues); |
| rawResults.push_back(result); |
| |
| // Otherwise, we need to create a try_apply. |
| } else { |
| SILBasicBlock *normalBB = SGF.createBasicBlock(); |
| auto result = normalBB->createPhiArgument(resultType, OwnershipKind::Owned); |
| rawResults.push_back(result); |
| |
| SILBasicBlock *errorBB = |
| SGF.getTryApplyErrorDest(loc, substFnType, |
| substFnType->getErrorResult(), |
| options & ApplyOptions::DoesNotThrow); |
| |
| SGF.B.createTryApply(loc, fnValue, subs, argValues, |
| normalBB, errorBB); |
| SGF.B.emitBlock(normalBB); |
| } |
| } |
| |
| static bool hasUnownedInnerPointerResult(CanSILFunctionType fnType) { |
| for (auto result : fnType->getResults()) { |
| if (result.getConvention() == ResultConvention::UnownedInnerPointer) |
| return true; |
| } |
| return false; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Argument Emission for Builtin Initializer |
| //===----------------------------------------------------------------------===// |
| static inline PreparedArguments |
| buildBuiltinLiteralArgs(SILGenFunction &SGF, SGFContext C, |
| StringLiteralExpr *stringLiteral) { |
| return emitStringLiteral(SGF, stringLiteral, stringLiteral->getValue(), C, |
| stringLiteral->getEncoding()); |
| } |
| |
| static inline PreparedArguments |
| buildBuiltinLiteralArgs(NilLiteralExpr *nilLiteral) { |
| PreparedArguments builtinLiteralArgs; |
| builtinLiteralArgs.emplace({}); |
| return builtinLiteralArgs; |
| } |
| |
| static inline PreparedArguments |
| buildBuiltinLiteralArgs(SILGenFunction &SGF, SGFContext C, |
| BooleanLiteralExpr *booleanLiteral) { |
| PreparedArguments builtinLiteralArgs; |
| auto i1Ty = SILType::getBuiltinIntegerType(1, SGF.getASTContext()); |
| SILValue boolValue = SGF.B.createIntegerLiteral(booleanLiteral, i1Ty, |
| booleanLiteral->getValue()); |
| ManagedValue boolManaged = ManagedValue::forUnmanaged(boolValue); |
| CanType ty = boolManaged.getType().getASTType()->getCanonicalType(); |
| builtinLiteralArgs.emplace(AnyFunctionType::Param(ty)); |
| builtinLiteralArgs.add(booleanLiteral, RValue(SGF, {boolManaged}, ty)); |
| return builtinLiteralArgs; |
| } |
| |
| static inline PreparedArguments |
| buildBuiltinLiteralArgs(SILGenFunction &SGF, SGFContext C, |
| IntegerLiteralExpr *integerLiteral) { |
| PreparedArguments builtinLiteralArgs; |
| ManagedValue integerManaged = |
| ManagedValue::forUnmanaged(SGF.B.createIntegerLiteral( |
| integerLiteral, |
| SILType::getBuiltinIntegerLiteralType(SGF.getASTContext()), |
| integerLiteral->getRawValue())); |
| CanType ty = integerManaged.getType().getASTType(); |
| builtinLiteralArgs.emplace(AnyFunctionType::Param(ty)); |
| builtinLiteralArgs.add(integerLiteral, RValue(SGF, {integerManaged}, ty)); |
| return builtinLiteralArgs; |
| } |
| |
| static inline PreparedArguments |
| buildBuiltinLiteralArgs(SILGenFunction &SGF, SGFContext C, |
| FloatLiteralExpr *floatLiteral) { |
| PreparedArguments builtinLiteralArgs; |
| auto *litTy = floatLiteral->getBuiltinType()->castTo<BuiltinFloatType>(); |
| ManagedValue floatManaged = |
| ManagedValue::forUnmanaged(SGF.B.createFloatLiteral( |
| floatLiteral, |
| SILType::getBuiltinFloatType(litTy->getFPKind(), SGF.getASTContext()), |
| floatLiteral->getValue())); |
| |
| CanType ty = floatManaged.getType().getASTType(); |
| builtinLiteralArgs.emplace(AnyFunctionType::Param(ty)); |
| builtinLiteralArgs.add(floatLiteral, RValue(SGF, {floatManaged}, ty)); |
| return builtinLiteralArgs; |
| } |
| |
| static inline PreparedArguments |
| buildBuiltinLiteralArgs(SILGenFunction &SGF, SGFContext C, |
| MagicIdentifierLiteralExpr *magicLiteral) { |
| ASTContext &ctx = SGF.getASTContext(); |
| SourceLoc loc = magicLiteral->getStartLoc(); |
| |
| switch (magicLiteral->getKind()) { |
| case MagicIdentifierLiteralExpr::FileIDSpelledAsFile: |
| case MagicIdentifierLiteralExpr::FileID: { |
| std::string value = loc.isValid() ? SGF.getMagicFileIDString(loc) : ""; |
| return emitStringLiteral(SGF, magicLiteral, value, C, |
| magicLiteral->getStringEncoding()); |
| } |
| |
| case MagicIdentifierLiteralExpr::FilePathSpelledAsFile: |
| case MagicIdentifierLiteralExpr::FilePath: { |
| StringRef value = loc.isValid() ? SGF.getMagicFilePathString(loc) : ""; |
| return emitStringLiteral(SGF, magicLiteral, value, C, |
| magicLiteral->getStringEncoding()); |
| } |
| |
| case MagicIdentifierLiteralExpr::Function: { |
| StringRef value = loc.isValid() ? SGF.getMagicFunctionString() : ""; |
| return emitStringLiteral(SGF, magicLiteral, value, C, |
| magicLiteral->getStringEncoding()); |
| } |
| |
| case MagicIdentifierLiteralExpr::Line: |
| case MagicIdentifierLiteralExpr::Column: { |
| SourceLoc Loc = magicLiteral->getStartLoc(); |
| unsigned Value = 0; |
| if (Loc.isValid()) { |
| Value = magicLiteral->getKind() == MagicIdentifierLiteralExpr::Line |
| ? ctx.SourceMgr.getPresumedLineAndColumnForLoc(Loc).first |
| : ctx.SourceMgr.getPresumedLineAndColumnForLoc(Loc).second; |
| } |
| |
| auto silTy = SILType::getBuiltinIntegerLiteralType(ctx); |
| auto ty = silTy.getASTType(); |
| SILValue integer = SGF.B.createIntegerLiteral(magicLiteral, silTy, Value); |
| ManagedValue integerManaged = ManagedValue::forUnmanaged(integer); |
| PreparedArguments builtinLiteralArgs; |
| builtinLiteralArgs.emplace(AnyFunctionType::Param(ty)); |
| builtinLiteralArgs.add(magicLiteral, RValue(SGF, {integerManaged}, ty)); |
| return builtinLiteralArgs; |
| } |
| case MagicIdentifierLiteralExpr::DSOHandle: |
| llvm_unreachable("handled elsewhere"); |
| } |
| } |
| |
| static inline PreparedArguments buildBuiltinLiteralArgs(SILGenFunction &SGF, |
| SGFContext C, |
| LiteralExpr *literal) { |
| if (auto stringLiteral = dyn_cast<StringLiteralExpr>(literal)) { |
| return buildBuiltinLiteralArgs(SGF, C, stringLiteral); |
| } else if (auto nilLiteral = dyn_cast<NilLiteralExpr>(literal)) { |
| return buildBuiltinLiteralArgs(nilLiteral); |
| } else if (auto booleanLiteral = dyn_cast<BooleanLiteralExpr>(literal)) { |
| return buildBuiltinLiteralArgs(SGF, C, booleanLiteral); |
| } else if (auto integerLiteral = dyn_cast<IntegerLiteralExpr>(literal)) { |
| return buildBuiltinLiteralArgs(SGF, C, integerLiteral); |
| } else if (auto floatLiteral = dyn_cast<FloatLiteralExpr>(literal)) { |
| return buildBuiltinLiteralArgs(SGF, C, floatLiteral); |
| } else { |
| return buildBuiltinLiteralArgs( |
| SGF, C, cast<MagicIdentifierLiteralExpr>(literal)); |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Argument Emission |
| //===----------------------------------------------------------------------===// |
| |
| /// Count the number of SILParameterInfos that are needed in order to |
| /// pass the given argument. |
| static unsigned getFlattenedValueCount(AbstractionPattern origType, |
| CanType substType) { |
| // The count is always 1 unless the substituted type is a tuple. |
| auto substTuple = dyn_cast<TupleType>(substType); |
| if (!substTuple) |
| return 1; |
| |
| // If the original type is opaque, the count is 1 anyway. |
| if (origType.isTypeParameter()) |
| return 1; |
| |
| // Otherwise, add up the elements. |
| unsigned count = 0; |
| for (auto i : indices(substTuple.getElementTypes())) { |
| count += getFlattenedValueCount(origType.getTupleElementType(i), |
| substTuple.getElementType(i)); |
| } |
| return count; |
| } |
| |
| /// Count the number of SILParameterInfos that are needed in order to |
| /// pass the given argument. |
| static unsigned getFlattenedValueCount(AbstractionPattern origType, |
| CanType substType, |
| ImportAsMemberStatus foreignSelf) { |
| // C functions imported as static methods don't consume any real arguments. |
| if (foreignSelf.isStatic()) |
| return 0; |
| |
| return getFlattenedValueCount(origType, substType); |
| } |
| |
| namespace { |
| |
| /// The original argument expression for some sort of complex |
| /// argument emission. |
| class OriginalArgument { |
| llvm::PointerIntPair<Expr*, 1, bool> ExprAndIsIndirect; |
| |
| public: |
| OriginalArgument() = default; |
| OriginalArgument(Expr *expr, bool indirect) |
| : ExprAndIsIndirect(expr, indirect) {} |
| |
| Expr *getExpr() const { return ExprAndIsIndirect.getPointer(); } |
| bool isIndirect() const { return ExprAndIsIndirect.getInt(); } |
| }; |
| |
| /// A possibly-discontiguous slice of function parameters claimed by a |
| /// function application. |
| class ClaimedParamsRef { |
| public: |
| static constexpr const unsigned NoSkip = (unsigned)-1; |
| private: |
| ArrayRef<SILParameterInfo> Params; |
| |
| // The index of the param excluded from this range, if any, or ~0. |
| unsigned SkipParamIndex; |
| |
| void checkParams() { |
| // The parameters should already have been substituted into the caller's |
| // context, and had the SILFunctionType substitutions applied, before we |
| // queue them up to be claimed. |
| #ifndef NDEBUG |
| for (auto param : Params) { |
| assert(!param.getInterfaceType()->hasTypeParameter() |
| && "params should be substituted into context"); |
| } |
| #endif |
| } |
| |
| friend struct ParamLowering; |
| explicit ClaimedParamsRef(ArrayRef<SILParameterInfo> params, |
| unsigned skip) |
| : Params(params), SkipParamIndex(skip) |
| { |
| checkParams(); |
| // Eagerly chop a skipped parameter off either end. |
| if (SkipParamIndex == 0) { |
| Params = Params.slice(1); |
| SkipParamIndex = NoSkip; |
| } |
| assert(!hasSkip() || SkipParamIndex < Params.size()); |
| } |
| |
| bool hasSkip() const { |
| return SkipParamIndex != (unsigned)NoSkip; |
| } |
| public: |
| ClaimedParamsRef() : Params({}), SkipParamIndex(-1) {} |
| explicit ClaimedParamsRef(ArrayRef<SILParameterInfo> params) |
| : Params(params), SkipParamIndex(NoSkip) |
| { |
| checkParams(); |
| } |
| |
| struct iterator : public std::iterator<std::random_access_iterator_tag, |
| SILParameterInfo> |
| { |
| const SILParameterInfo *Base; |
| unsigned I, SkipParamIndex; |
| |
| iterator(const SILParameterInfo *Base, |
| unsigned I, unsigned SkipParamIndex) |
| : Base(Base), I(I), SkipParamIndex(SkipParamIndex) |
| {} |
| |
| iterator &operator++() { |
| ++I; |
| if (I == SkipParamIndex) |
| ++I; |
| return *this; |
| } |
| iterator operator++(int) { |
| iterator old(*this); |
| ++*this; |
| return old; |
| } |
| iterator &operator--() { |
| --I; |
| if (I == SkipParamIndex) |
| --I; |
| return *this; |
| } |
| iterator operator--(int) { |
| iterator old(*this); |
| --*this; |
| return old; |
| } |
| |
| const SILParameterInfo &operator*() const { |
| return Base[I]; |
| } |
| const SILParameterInfo *operator->() const { |
| return Base + I; |
| } |
| |
| bool operator==(iterator other) const { |
| return Base == other.Base && I == other.I |
| && SkipParamIndex == other.SkipParamIndex; |
| } |
| |
| bool operator!=(iterator other) const { |
| return !(*this == other); |
| } |
| |
| iterator operator+(std::ptrdiff_t distance) const { |
| if (distance > 0) |
| return goForward(distance); |
| if (distance < 0) |
| return goBackward(distance); |
| return *this; |
| } |
| iterator operator-(std::ptrdiff_t distance) const { |
| if (distance > 0) |
| return goBackward(distance); |
| if (distance < 0) |
| return goForward(distance); |
| return *this; |
| } |
| std::ptrdiff_t operator-(iterator other) const { |
| assert(Base == other.Base && SkipParamIndex == other.SkipParamIndex); |
| auto baseDistance = (std::ptrdiff_t)I - (std::ptrdiff_t)other.I; |
| if (std::min(I, other.I) < SkipParamIndex && |
| std::max(I, other.I) > SkipParamIndex) |
| return baseDistance - 1; |
| return baseDistance; |
| } |
| |
| iterator goBackward(unsigned distance) const { |
| auto result = *this; |
| if (I > SkipParamIndex && I <= SkipParamIndex + distance) |
| result.I -= (distance + 1); |
| result.I -= distance; |
| return result; |
| } |
| |
| iterator goForward(unsigned distance) const { |
| auto result = *this; |
| if (I < SkipParamIndex && I + distance >= SkipParamIndex) |
| result.I += distance + 1; |
| result.I += distance; |
| return result; |
| } |
| }; |
| |
| iterator begin() const { |
| return iterator{Params.data(), 0, SkipParamIndex}; |
| } |
| |
| iterator end() const { |
| return iterator{Params.data(), (unsigned)Params.size(), SkipParamIndex}; |
| } |
| |
| unsigned size() const { |
| return Params.size() - (hasSkip() ? 1 : 0); |
| } |
| |
| bool empty() const { return size() == 0; } |
| |
| SILParameterInfo front() const { return *begin(); } |
| |
| ClaimedParamsRef slice(unsigned start) const { |
| if (start >= SkipParamIndex) |
| return ClaimedParamsRef(Params.slice(start + 1), NoSkip); |
| return ClaimedParamsRef(Params.slice(start), |
| hasSkip() ? SkipParamIndex - start : NoSkip); |
| } |
| ClaimedParamsRef slice(unsigned start, unsigned count) const { |
| if (start >= SkipParamIndex) |
| return ClaimedParamsRef(Params.slice(start + 1, count), NoSkip); |
| unsigned newSkip = SkipParamIndex; |
| if (hasSkip()) |
| newSkip -= start; |
| |
| if (newSkip < count) |
| return ClaimedParamsRef(Params.slice(start, count+1), newSkip); |
| return ClaimedParamsRef(Params.slice(start, count), NoSkip); |
| } |
| }; |
| |
| /// A delayed argument. Call arguments are evaluated in two phases: |
| /// a formal evaluation phase and a formal access phase. The primary |
| /// example of this is an l-value that is passed by reference, where |
| /// the access to the l-value does not begin until the formal access |
| /// phase, but there are other examples, generally relating to pointer |
| /// conversions. |
| /// |
| /// A DelayedArgument represents the part of evaluating an argument |
| /// that's been delayed until the formal access phase. |
| class DelayedArgument { |
| public: |
| enum KindTy { |
| /// This is a true inout argument. |
| InOut, |
| |
| LastLVKindWithoutExtra = InOut, |
| |
| /// The l-value needs to be converted to a pointer type. |
| LValueToPointer, |
| |
| /// An array l-value needs to be converted to a pointer type. |
| LValueArrayToPointer, |
| |
| LastLVKind = LValueArrayToPointer, |
| |
| /// An array r-value needs to be converted to a pointer type. |
| RValueArrayToPointer, |
| |
| /// A string r-value needs to be converted to a pointer type. |
| RValueStringToPointer, |
| |
| /// A function conversion needs to occur. |
| FunctionConversion, |
| |
| LastRVKind = FunctionConversion, |
| |
| /// This is an immutable borrow from an l-value. |
| BorrowedLValue, |
| |
| /// A default argument that needs to be evaluated. |
| DefaultArgument, |
| }; |
| |
| private: |
| KindTy Kind; |
| |
| struct LValueStorage { |
| LValue LV; |
| SILLocation Loc; |
| |
| LValueStorage(LValue &&lv, SILLocation loc) : LV(std::move(lv)), Loc(loc) {} |
| }; |
| struct RValueStorage { |
| ManagedValue RV; |
| |
| RValueStorage(ManagedValue rv) : RV(rv) {} |
| }; |
| struct DefaultArgumentStorage { |
| SILLocation loc; |
| ConcreteDeclRef defaultArgsOwner; |
| unsigned destIndex; |
| CanType resultType; |
| AbstractionPattern origResultType; |
| ClaimedParamsRef paramsToEmit; |
| SILFunctionTypeRepresentation functionRepresentation; |
| |
| DefaultArgumentStorage(SILLocation loc, |
| ConcreteDeclRef defaultArgsOwner, |
| unsigned destIndex, |
| CanType resultType, |
| AbstractionPattern origResultType, |
| ClaimedParamsRef paramsToEmit, |
| SILFunctionTypeRepresentation functionRepresentation) |
| : loc(loc), defaultArgsOwner(defaultArgsOwner), destIndex(destIndex), |
| resultType(resultType), origResultType(origResultType), |
| paramsToEmit(paramsToEmit), |
| functionRepresentation(functionRepresentation) |
| {} |
| }; |
| struct BorrowedLValueStorage { |
| LValue LV; |
| SILLocation Loc; |
| AbstractionPattern OrigParamType; |
| ClaimedParamsRef ParamsToEmit; |
| }; |
| |
| using ValueMembers = |
| ExternalUnionMembers<RValueStorage, LValueStorage, |
| DefaultArgumentStorage, |
| BorrowedLValueStorage>; |
| static ValueMembers::Index getValueMemberIndexForKind(KindTy kind) { |
| switch (kind) { |
| case InOut: |
| case LValueToPointer: |
| case LValueArrayToPointer: |
| return ValueMembers::indexOf<LValueStorage>(); |
| case RValueArrayToPointer: |
| case RValueStringToPointer: |
| case FunctionConversion: |
| return ValueMembers::indexOf<RValueStorage>(); |
| case DefaultArgument: |
| return ValueMembers::indexOf<DefaultArgumentStorage>(); |
| case BorrowedLValue: |
| return ValueMembers::indexOf<BorrowedLValueStorage>(); |
| } |
| llvm_unreachable("bad kind"); |
| } |
| |
| /// Storage for either the l-value or the r-value. |
| ExternalUnion<KindTy, ValueMembers, getValueMemberIndexForKind> Value; |
| |
| LValueStorage &LV() { return Value.get<LValueStorage>(Kind); } |
| const LValueStorage &LV() const { return Value.get<LValueStorage>(Kind); } |
| RValueStorage &RV() { return Value.get<RValueStorage>(Kind); } |
| const RValueStorage &RV() const { return Value.get<RValueStorage>(Kind); } |
| |
| /// The original argument expression, which will be emitted down |
| /// to the point from which the l-value or r-value was generated. |
| OriginalArgument Original; |
| |
| using PointerAccessInfo = SILGenFunction::PointerAccessInfo; |
| using ArrayAccessInfo = SILGenFunction::ArrayAccessInfo; |
| |
| using ExtraMembers = |
| ExternalUnionMembers<void, |
| ArrayAccessInfo, |
| PointerAccessInfo>; |
| static ExtraMembers::Index getExtraMemberIndexForKind(KindTy kind) { |
| switch (kind) { |
| case LValueToPointer: |
| return ExtraMembers::indexOf<PointerAccessInfo>(); |
| case LValueArrayToPointer: |
| case RValueArrayToPointer: |
| return ExtraMembers::indexOf<ArrayAccessInfo>(); |
| default: |
| return ExtraMembers::indexOf<void>(); |
| } |
| } |
| |
| ExternalUnion<KindTy, ExtraMembers, getExtraMemberIndexForKind> Extra; |
| |
| public: |
| DelayedArgument(KindTy kind, LValue &&lv, SILLocation loc) |
| : Kind(kind) { |
| assert(kind <= LastLVKindWithoutExtra && |
| "this constructor should only be used for simple l-value kinds"); |
| Value.emplace<LValueStorage>(Kind, std::move(lv), loc); |
| } |
| |
| DelayedArgument(KindTy kind, ManagedValue rv, OriginalArgument original) |
| : Kind(kind), Original(original) { |
| Value.emplace<RValueStorage>(Kind, rv); |
| } |
| |
| DelayedArgument(SILGenFunction::PointerAccessInfo pointerInfo, |
| LValue &&lv, SILLocation loc, OriginalArgument original) |
| : Kind(LValueToPointer), Original(original) { |
| Value.emplace<LValueStorage>(Kind, std::move(lv), loc); |
| Extra.emplace<PointerAccessInfo>(Kind, pointerInfo); |
| } |
| |
| DelayedArgument(SILGenFunction::ArrayAccessInfo arrayInfo, |
| LValue &&lv, SILLocation loc, OriginalArgument original) |
| : Kind(LValueArrayToPointer), Original(original) { |
| Value.emplace<LValueStorage>(Kind, std::move(lv), loc); |
| Extra.emplace<ArrayAccessInfo>(Kind, arrayInfo); |
| } |
| |
| DelayedArgument(KindTy kind, |
| SILGenFunction::ArrayAccessInfo arrayInfo, |
| ManagedValue rv, OriginalArgument original) |
| : Kind(kind), Original(original) { |
| Value.emplace<RValueStorage>(Kind, rv); |
| Extra.emplace<ArrayAccessInfo>(Kind, arrayInfo); |
| } |
| |
| DelayedArgument(LValue &&lv, SILLocation loc, |
| AbstractionPattern origResultType, |
| ClaimedParamsRef params) |
| : Kind(BorrowedLValue) { |
| Value.emplaceAggregate<BorrowedLValueStorage>(Kind, std::move(lv), loc, |
| origResultType, params); |
| } |
| |
| DelayedArgument(SILLocation loc, |
| ConcreteDeclRef defaultArgsOwner, |
| unsigned destIndex, |
| CanType resultType, |
| AbstractionPattern origResultType, |
| ClaimedParamsRef params, |
| SILFunctionTypeRepresentation functionTypeRepresentation) |
| : Kind(DefaultArgument) { |
| Value.emplace<DefaultArgumentStorage>(Kind, loc, defaultArgsOwner, |
| destIndex, |
| resultType, |
| origResultType, params, |
| functionTypeRepresentation); |
| } |
| |
| DelayedArgument(DelayedArgument &&other) |
| : Kind(other.Kind), Original(other.Original) { |
| Value.moveConstruct(Kind, std::move(other.Value)); |
| Extra.moveConstruct(Kind, std::move(other.Extra)); |
| } |
| |
| DelayedArgument &operator=(DelayedArgument &&other) { |
| Value.moveAssign(Kind, other.Kind, std::move(other.Value)); |
| Extra.moveAssign(Kind, other.Kind, std::move(other.Extra)); |
| Kind = other.Kind; |
| Original = other.Original; |
| return *this; |
| } |
| |
| ~DelayedArgument() { |
| Extra.destruct(Kind); |
| Value.destruct(Kind); |
| } |
| |
| bool isSimpleInOut() const { return Kind == InOut; } |
| SILLocation getInOutLocation() const { |
| assert(isSimpleInOut()); |
| return LV().Loc; |
| } |
| |
| void emit(SILGenFunction &SGF, SmallVectorImpl<ManagedValue> &args, |
| size_t &argIndex) { |
| switch (Kind) { |
| case InOut: |
| args[argIndex++] = emitInOut(SGF); |
| return; |
| case LValueToPointer: |
| case LValueArrayToPointer: |
| case RValueArrayToPointer: |
| case RValueStringToPointer: |
| case FunctionConversion: |
| args[argIndex++] = finishOriginalArgument(SGF); |
| return; |
| case DefaultArgument: |
| emitDefaultArgument(SGF, Value.get<DefaultArgumentStorage>(Kind), |
| args, argIndex); |
| return; |
| case BorrowedLValue: |
| emitBorrowedLValue(SGF, Value.get<BorrowedLValueStorage>(Kind), |
| args, argIndex); |
| return; |
| } |
| llvm_unreachable("bad kind"); |
| } |
| |
| private: |
| ManagedValue emitInOut(SILGenFunction &SGF) { |
| return emitAddress(SGF, AccessKind::ReadWrite); |
| } |
| |
| ManagedValue emitBorrowIndirect(SILGenFunction &SGF) { |
| return emitAddress(SGF, AccessKind::Read); |
| } |
| |
| ManagedValue emitBorrowDirect(SILGenFunction &SGF) { |
| ManagedValue address = emitAddress(SGF, AccessKind::Read); |
| return SGF.B.createLoadBorrow(LV().Loc, address); |
| } |
| |
| ManagedValue emitAddress(SILGenFunction &SGF, AccessKind accessKind) { |
| auto tsanKind = |
| (accessKind == AccessKind::Read ? TSanKind::None : TSanKind::InoutAccess); |
| return SGF.emitAddressOfLValue(LV().Loc, std::move(LV().LV), tsanKind); |
| } |
| |
| /// Replay the original argument expression. |
| ManagedValue finishOriginalArgument(SILGenFunction &SGF) { |
| auto results = finishOriginalExpr(SGF, Original.getExpr()); |
| auto value = results.first; // just let the owner go |
| |
| if (Original.isIndirect() && !value.getType().isAddress()) { |
| value = value.materialize(SGF, Original.getExpr()); |
| } |
| |
| return value; |
| } |
| |
| void emitDefaultArgument(SILGenFunction &SGF, |
| const DefaultArgumentStorage &info, |
| SmallVectorImpl<ManagedValue> &args, |
| size_t &argIndex); |
| |
| void emitBorrowedLValue(SILGenFunction &SGF, |
| BorrowedLValueStorage &info, |
| SmallVectorImpl<ManagedValue> &args, |
| size_t &argIndex); |
| |
| // (value, owner) |
| std::pair<ManagedValue, ManagedValue> |
| finishOriginalExpr(SILGenFunction &SGF, Expr *expr) { |
| |
| // This needs to handle all of the recursive cases from |
| // ArgEmission::maybeEmitDelayed. |
| |
| expr = expr->getSemanticsProvidingExpr(); |
| |
| // Handle injections into optionals. |
| if (auto inject = dyn_cast<InjectIntoOptionalExpr>(expr)) { |
| auto ownedValue = |
| finishOriginalExpr(SGF, inject->getSubExpr()); |
| auto &optionalTL = SGF.getTypeLowering(expr->getType()); |
| |
| auto optValue = SGF.emitInjectOptional(inject, optionalTL, SGFContext(), |
| [&](SGFContext ctx) { return ownedValue.first; }); |
| return {optValue, ownedValue.second}; |
| } |
| |
| // Handle try!. |
| if (auto forceTry = dyn_cast<ForceTryExpr>(expr)) { |
| // Handle throws from the accessor? But what if the writeback throws? |
| SILGenFunction::ForceTryEmission emission(SGF, forceTry); |
| return finishOriginalExpr(SGF, forceTry->getSubExpr()); |
| } |
| |
| // Handle optional evaluations. |
| if (auto optEval = dyn_cast<OptionalEvaluationExpr>(expr)) { |
| return finishOptionalEvaluation(SGF, optEval); |
| } |
| |
| // Done with the recursive cases. Make sure we handled everything. |
| assert(isa<InOutToPointerExpr>(expr) || |
| isa<ArrayToPointerExpr>(expr) || |
| isa<StringToPointerExpr>(expr) || |
| isa<FunctionConversionExpr>(expr)); |
| |
| switch (Kind) { |
| case InOut: |
| case BorrowedLValue: |
| case DefaultArgument: |
| llvm_unreachable("no original expr to finish in these cases"); |
| |
| case LValueToPointer: |
| return {SGF.emitLValueToPointer(LV().Loc, std::move(LV().LV), |
| Extra.get<PointerAccessInfo>(Kind)), |
| /*owner*/ ManagedValue()}; |
| |
| case LValueArrayToPointer: |
| return SGF.emitArrayToPointer(LV().Loc, std::move(LV().LV), |
| Extra.get<ArrayAccessInfo>(Kind)); |
| |
| case RValueArrayToPointer: { |
| auto pointerExpr = cast<ArrayToPointerExpr>(expr); |
| auto optArrayValue = RV().RV; |
| auto arrayValue = emitBindOptionals(SGF, optArrayValue, |
| pointerExpr->getSubExpr()); |
| return SGF.emitArrayToPointer(pointerExpr, arrayValue, |
| Extra.get<ArrayAccessInfo>(Kind)); |
| } |
| |
| case RValueStringToPointer: { |
| auto pointerExpr = cast<StringToPointerExpr>(expr); |
| auto optStringValue = RV().RV; |
| auto stringValue = |
| emitBindOptionals(SGF, optStringValue, pointerExpr->getSubExpr()); |
| return SGF.emitStringToPointer(pointerExpr, stringValue, |
| pointerExpr->getType()); |
| } |
| case FunctionConversion: { |
| auto funcConv = cast<FunctionConversionExpr>(expr); |
| auto optFuncValue = RV().RV; |
| auto funcValue = |
| emitBindOptionals(SGF, optFuncValue, funcConv->getSubExpr()); |
| return {SGF.emitTransformedValue(funcConv, funcValue, |
| funcConv->getSubExpr()->getType()->getCanonicalType(), |
| funcConv->getType()->getCanonicalType(), |
| SGFContext()), |
| ManagedValue()}; |
| } |
| } |
| llvm_unreachable("bad kind"); |
| } |
| |
| ManagedValue emitBindOptionals(SILGenFunction &SGF, ManagedValue optValue, |
| Expr *expr) { |
| expr = expr->getSemanticsProvidingExpr(); |
| auto bind = dyn_cast<BindOptionalExpr>(expr); |
| |
| // If we don't find a bind, the value isn't optional. |
| if (!bind) return optValue; |
| |
| // Recurse. |
| optValue = emitBindOptionals(SGF, optValue, bind->getSubExpr()); |
| |
| // Check whether the value is non-nil and if the value is not-nil, return |
| // the unwrapped value. |
| return SGF.emitBindOptional(bind, optValue, bind->getDepth()); |
| } |
| |
| std::pair<ManagedValue, ManagedValue> |
| finishOptionalEvaluation(SILGenFunction &SGF, OptionalEvaluationExpr *eval) { |
| SmallVector<ManagedValue, 2> results; |
| |
| SGF.emitOptionalEvaluation(eval, eval->getType(), results, SGFContext(), |
| [&](SmallVectorImpl<ManagedValue> &results, SGFContext C) { |
| // Recurse. |
| auto values = finishOriginalExpr(SGF, eval->getSubExpr()); |
| |
| // Our primary result is the value. |
| results.push_back(values.first); |
| |
| // Our secondary result is the owner, if we have one. |
| if (auto owner = values.second) results.push_back(owner); |
| }); |
| |
| assert(results.size() == 1 || results.size() == 2); |
| |
| ManagedValue value = results[0]; |
| |
| ManagedValue owner; |
| if (results.size() == 2) { |
| owner = results[1]; |
| |
| // Create a new value-dependence here if the primary result is |
| // trivial. |
| auto &valueTL = SGF.getTypeLowering(value.getType()); |
| if (valueTL.isTrivial()) { |
| SILValue dependentValue = |
| SGF.B.createMarkDependence(eval, value.forward(SGF), |
| owner.getValue()); |
| value = SGF.emitManagedRValueWithCleanup(dependentValue, valueTL); |
| } |
| } |
| |
| return {value, owner}; |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| /// Perform the formal-access phase of call argument emission by emitting |
| /// all of the delayed arguments. |
| static void emitDelayedArguments(SILGenFunction &SGF, |
| MutableArrayRef<DelayedArgument> delayedArgs, |
| MutableArrayRef<SmallVector<ManagedValue, 4>> args) { |
| assert(!delayedArgs.empty()); |
| |
| SmallVector<std::pair<SILValue, SILLocation>, 4> emittedInoutArgs; |
| auto delayedNext = delayedArgs.begin(); |
| |
| // The assumption we make is that 'args' and 'delayedArgs' were built |
| // up in parallel, with empty spots being dropped into 'args' |
| // wherever there's a delayed argument to insert. |
| // |
| // Note that this also begins the formal accesses in evaluation order. |
| for (auto &siteArgs : args) { |
| // NB: siteArgs.size() may change during iteration |
| for (size_t i = 0; i < siteArgs.size(); ) { |
| auto &siteArg = siteArgs[i]; |
| |
| if (siteArg) { |
| ++i; |
| continue; |
| } |
| |
| assert(delayedNext != delayedArgs.end()); |
| auto &delayedArg = *delayedNext; |
| |
| // Emit the delayed argument and replace it in the arguments array. |
| delayedArg.emit(SGF, siteArgs, i); |
| |
| // Remember all the simple inouts we emitted so we can perform |
| // a basic inout-aliasing analysis. |
| // This should be completely obviated by static enforcement. |
| if (delayedArg.isSimpleInOut()) { |
| emittedInoutArgs.push_back({siteArg.getValue(), |
| delayedArg.getInOutLocation()}); |
| } |
| |
| if (++delayedNext == delayedArgs.end()) |
| goto done; |
| } |
| } |
| |
| llvm_unreachable("ran out of null arguments before we ran out of inouts"); |
| |
| done: |
| |
| // Check to see if we have multiple inout arguments which obviously |
| // alias. Note that we could do this in a later SILDiagnostics pass |
| // as well: this would be stronger (more equivalences exposed) but |
| // would have worse source location information. |
| for (auto i = emittedInoutArgs.begin(), e = emittedInoutArgs.end(); |
| i != e; ++i) { |
| for (auto j = emittedInoutArgs.begin(); j != i; ++j) { |
| if (!RValue::areObviouslySameValue(i->first, j->first)) continue; |
| |
| SGF.SGM.diagnose(i->second, diag::inout_argument_alias) |
| .highlight(i->second.getSourceRange()); |
| SGF.SGM.diagnose(j->second, diag::previous_inout_alias) |
| .highlight(j->second.getSourceRange()); |
| } |
| } |
| } |
| |
| static Expr *findStorageReferenceExprForBorrow(Expr *e) { |
| e = e->getSemanticsProvidingExpr(); |
| |
| // These are basically defined as the cases implemented by SILGenLValue. |
| |
| // Direct storage references. |
| if (auto dre = dyn_cast<DeclRefExpr>(e)) { |
| if (isa<VarDecl>(dre->getDecl())) |
| return dre; |
| } else if (auto mre = dyn_cast<MemberRefExpr>(e)) { |
| if (isa<VarDecl>(mre->getDecl().getDecl())) |
| return mre; |
| } else if (isa<SubscriptExpr>(e)) { |
| return e; |
| } else if (isa<OpaqueValueExpr>(e)) { |
| return e; |
| } else if (isa<KeyPathApplicationExpr>(e)) { |
| return e; |
| |
| // Transitive storage references. Look through these to see if the |
| // sub-expression is a storage reference, but don't return the |
| // sub-expression. |
| } else if (auto tue = dyn_cast<TupleElementExpr>(e)) { |
| if (findStorageReferenceExprForBorrow(tue->getBase())) |
| return tue; |
| } else if (auto fve = dyn_cast<ForceValueExpr>(e)) { |
| if (findStorageReferenceExprForBorrow(fve->getSubExpr())) |
| return fve; |
| } else if (auto boe = dyn_cast<BindOptionalExpr>(e)) { |
| if (findStorageReferenceExprForBorrow(boe->getSubExpr())) |
| return boe; |
| } else if (auto oe = dyn_cast<OpenExistentialExpr>(e)) { |
| if (findStorageReferenceExprForBorrow(oe->getExistentialValue()) && |
| findStorageReferenceExprForBorrow(oe->getSubExpr())) |
| return oe; |
| } else if (auto bie = dyn_cast<DotSyntaxBaseIgnoredExpr>(e)) { |
| if (findStorageReferenceExprForBorrow(bie->getRHS())) |
| return bie; |
| } else if (auto te = dyn_cast<AnyTryExpr>(e)) { |
| if (findStorageReferenceExprForBorrow(te->getSubExpr())) |
| return te; |
| } else if (auto ioe = dyn_cast<InOutExpr>(e)) { |
| return ioe; |
| } |
| |
| return nullptr; |
| } |
| |
| Expr *ArgumentSource::findStorageReferenceExprForBorrow() && { |
| if (!isExpr()) return nullptr; |
| |
| auto argExpr = asKnownExpr(); |
| auto lvExpr = ::findStorageReferenceExprForBorrow(argExpr); |
| |
| // Claim the value of this argument if we found a storage reference. |
| if (lvExpr) { |
| (void) std::move(*this).asKnownExpr(); |
| } |
| |
| return lvExpr; |
| } |
| |
| namespace { |
| |
| class ArgEmitter { |
| SILGenFunction &SGF; |
| SILFunctionTypeRepresentation Rep; |
| bool IsYield; |
| bool IsForCoroutine; |
| CalleeTypeInfo::ForeignInfo Foreign; |
| ClaimedParamsRef ParamInfos; |
| SmallVectorImpl<ManagedValue> &Args; |
| |
| /// Track any delayed arguments that are emitted. Each corresponds |
| /// in order to a "hole" (a null value) in Args. |
| SmallVectorImpl<DelayedArgument> &DelayedArguments; |
| |
| public: |
| ArgEmitter(SILGenFunction &SGF, SILFunctionTypeRepresentation Rep, |
| bool isYield, bool isForCoroutine, ClaimedParamsRef paramInfos, |
| SmallVectorImpl<ManagedValue> &args, |
| SmallVectorImpl<DelayedArgument> &delayedArgs, |
| const CalleeTypeInfo::ForeignInfo &foreign) |
| : SGF(SGF), Rep(Rep), IsYield(isYield), IsForCoroutine(isForCoroutine), |
| Foreign(foreign), |
| ParamInfos(paramInfos), Args(args), DelayedArguments(delayedArgs) {} |
| |
| // origParamType is a parameter type. |
| void emitSingleArg(ArgumentSource &&arg, AbstractionPattern origParamType) { |
| // If this is delayed default argument, prepare to emit the default argument |
| // generator later. |
| if (arg.isDelayedDefaultArg()) { |
| auto substParamType = arg.getSubstRValueType(); |
| auto defArg = std::move(arg).asKnownDefaultArg(); |
| |
| auto numParams = getFlattenedValueCount(origParamType, |
| substParamType, |
| ImportAsMemberStatus()); |
| DelayedArguments.emplace_back(defArg, |
| defArg->getDefaultArgsOwner(), |
| defArg->getParamIndex(), |
| substParamType, origParamType, |
| claimNextParameters(numParams), |
| Rep); |
| Args.push_back(ManagedValue()); |
| |
| maybeEmitForeignArgument(); |
| return; |
| } |
| emit(std::move(arg), origParamType); |
| maybeEmitForeignArgument(); |
| } |
| |
| // origFormalType is a function type. |
| void emitPreparedArgs(PreparedArguments &&args, |
| AbstractionPattern origFormalType) { |
| assert(args.isValid()); |
| auto argSources = std::move(args).getSources(); |
| |
| maybeEmitForeignArgument(); |
| for (auto i : indices(argSources)) { |
| emitSingleArg(std::move(argSources[i]), |
| origFormalType.getFunctionParamType(i)); |
| } |
| } |
| |
| private: |
| void emit(ArgumentSource &&arg, AbstractionPattern origParamType) { |
| if (!arg.hasLValueType()) { |
| // If the unsubstituted function type has a parameter of tuple type, |
| // explode the tuple value. |
| if (origParamType.isTuple()) { |
| emitExpanded(std::move(arg), origParamType); |
| return; |
| } |
| } |
| |
| // Okay, everything else will be passed as a single value, one |
| // way or another. |
| |
| // If this is a discarded foreign static 'self' parameter, force the |
| // argument and discard it. |
| if (Foreign.self.isStatic()) { |
| std::move(arg).getAsRValue(SGF); |
| return; |
| } |
| |
| // Adjust for the foreign error or async argument if necessary. |
| maybeEmitForeignArgument(); |
| |
| // The substituted parameter type. Might be different from the |
| // substituted argument type by abstraction and/or bridging. |
| auto paramSlice = claimNextParameters(1); |
| SILParameterInfo param = paramSlice.front(); |
| |
| assert(arg.hasLValueType() == param.isIndirectInOut()); |
| |
| // Make sure we use the same value category for these so that we |
| // can hereafter just use simple equality checks to test for |
| // abstraction. |
| auto substArgType = arg.getSubstRValueType(); |
| SILType loweredSubstArgType = SGF.getLoweredType(substArgType); |
| if (param.isIndirectInOut()) { |
| loweredSubstArgType = |
| SILType::getPrimitiveAddressType(loweredSubstArgType.getASTType()); |
| } |
| SILType loweredSubstParamType = SILType::getPrimitiveType( |
| param.getInterfaceType(), |
| loweredSubstArgType.getCategory()); |
| |
| // If the caller takes the argument indirectly, the argument has an |
| // inout type. |
| if (param.isIndirectInOut()) { |
| emitInOut(std::move(arg), loweredSubstArgType, loweredSubstParamType, |
| origParamType, substArgType); |
|