| //===--- SILGenConstructor.cpp - SILGen for constructors ------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 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 "SILGenFunction.h" |
| #include "ArgumentSource.h" |
| #include "Initialization.h" |
| #include "LValue.h" |
| #include "RValue.h" |
| #include "Scope.h" |
| #include "swift/AST/GenericEnvironment.h" |
| #include "swift/AST/ASTMangler.h" |
| #include "swift/AST/ParameterList.h" |
| #include "swift/SIL/SILArgument.h" |
| #include "swift/SIL/SILUndef.h" |
| #include "swift/SIL/TypeLowering.h" |
| #include "swift/Basic/Defer.h" |
| |
| using namespace swift; |
| using namespace Lowering; |
| |
| static SILValue emitConstructorMetatypeArg(SILGenFunction &SGF, |
| ValueDecl *ctor) { |
| // In addition to the declared arguments, the constructor implicitly takes |
| // the metatype as its first argument, like a static function. |
| Type metatype = ctor->getInterfaceType()->castTo<AnyFunctionType>()->getInput(); |
| auto *DC = ctor->getInnermostDeclContext(); |
| auto &AC = SGF.getASTContext(); |
| auto VD = |
| new (AC) ParamDecl(VarDecl::Specifier::Default, SourceLoc(), SourceLoc(), |
| AC.getIdentifier("$metatype"), SourceLoc(), |
| AC.getIdentifier("$metatype"), Type(), DC); |
| VD->setInterfaceType(metatype); |
| |
| SGF.AllocatorMetatype = SGF.F.begin()->createFunctionArgument( |
| SGF.getLoweredType(DC->mapTypeIntoContext(metatype)), VD); |
| |
| return SGF.AllocatorMetatype; |
| } |
| |
| static RValue emitImplicitValueConstructorArg(SILGenFunction &SGF, |
| SILLocation loc, |
| CanType interfaceType, |
| DeclContext *DC) { |
| auto type = DC->mapTypeIntoContext(interfaceType)->getCanonicalType(); |
| |
| // Restructure tuple arguments. |
| if (auto tupleTy = dyn_cast<TupleType>(interfaceType)) { |
| RValue tuple(type); |
| for (auto fieldType : tupleTy.getElementTypes()) |
| tuple.addElement(emitImplicitValueConstructorArg(SGF, loc, fieldType, DC)); |
| return tuple; |
| } |
| |
| auto &AC = SGF.getASTContext(); |
| auto VD = new (AC) ParamDecl(VarDecl::Specifier::Default, SourceLoc(), SourceLoc(), |
| AC.getIdentifier("$implicit_value"), |
| SourceLoc(), |
| AC.getIdentifier("$implicit_value"), Type(), |
| DC); |
| VD->setInterfaceType(interfaceType); |
| SILFunctionArgument *arg = |
| SGF.F.begin()->createFunctionArgument(SGF.getLoweredType(type), VD); |
| ManagedValue mvArg; |
| if (arg->getArgumentConvention().isOwnedConvention()) { |
| mvArg = SGF.emitManagedRValueWithCleanup(arg); |
| } else { |
| mvArg = ManagedValue::forUnmanaged(arg); |
| } |
| return RValue(SGF, loc, type, mvArg); |
| } |
| |
| static void emitImplicitValueConstructor(SILGenFunction &SGF, |
| ConstructorDecl *ctor) { |
| RegularLocation Loc(ctor); |
| Loc.markAutoGenerated(); |
| // FIXME: Handle 'self' along with the other arguments. |
| auto *paramList = ctor->getParameterList(1); |
| auto *selfDecl = ctor->getImplicitSelfDecl(); |
| auto selfTyCan = selfDecl->getType()->getInOutObjectType(); |
| auto selfIfaceTyCan = selfDecl->getInterfaceType()->getInOutObjectType(); |
| SILType selfTy = SGF.getLoweredType(selfTyCan); |
| |
| // Emit the indirect return argument, if any. |
| SILValue resultSlot; |
| if (selfTy.isAddressOnly(SGF.SGM.M) && SGF.silConv.useLoweredAddresses()) { |
| auto &AC = SGF.getASTContext(); |
| auto VD = new (AC) ParamDecl(VarDecl::Specifier::InOut, |
| SourceLoc(), SourceLoc(), |
| AC.getIdentifier("$return_value"), |
| SourceLoc(), |
| AC.getIdentifier("$return_value"), Type(), |
| ctor); |
| VD->setInterfaceType(selfIfaceTyCan); |
| resultSlot = SGF.F.begin()->createFunctionArgument(selfTy, VD); |
| } |
| |
| // Emit the elementwise arguments. |
| SmallVector<RValue, 4> elements; |
| for (size_t i = 0, size = paramList->size(); i < size; ++i) { |
| auto ¶m = paramList->get(i); |
| |
| elements.push_back( |
| emitImplicitValueConstructorArg( |
| SGF, Loc, param->getInterfaceType()->getCanonicalType(), ctor)); |
| } |
| |
| emitConstructorMetatypeArg(SGF, ctor); |
| |
| auto *decl = selfTy.getStructOrBoundGenericStruct(); |
| assert(decl && "not a struct?!"); |
| |
| // If we have an indirect return slot, initialize it in-place. |
| if (resultSlot) { |
| |
| auto elti = elements.begin(), eltEnd = elements.end(); |
| for (VarDecl *field : decl->getStoredProperties()) { |
| auto fieldTy = selfTy.getFieldType(field, SGF.SGM.M); |
| auto &fieldTL = SGF.getTypeLowering(fieldTy); |
| SILValue slot = SGF.B.createStructElementAddr(Loc, resultSlot, field, |
| fieldTL.getLoweredType().getAddressType()); |
| InitializationPtr init(new KnownAddressInitialization(slot)); |
| |
| // An initialized 'let' property has a single value specified by the |
| // initializer - it doesn't come from an argument. |
| if (!field->isStatic() && field->isLet() && |
| field->getParentInitializer()) { |
| #ifndef NDEBUG |
| auto fieldTy = decl->getDeclContext()->mapTypeIntoContext( |
| field->getInterfaceType()); |
| assert(fieldTy->isEqual(field->getParentInitializer()->getType()) |
| && "Checked by sema"); |
| #endif |
| |
| // Cleanup after this initialization. |
| FullExpr scope(SGF.Cleanups, field->getParentPatternBinding()); |
| SGF.emitExprInto(field->getParentInitializer(), init.get()); |
| continue; |
| } |
| |
| assert(elti != eltEnd && "number of args does not match number of fields"); |
| (void)eltEnd; |
| std::move(*elti).forwardInto(SGF, Loc, init.get()); |
| ++elti; |
| } |
| SGF.B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc), |
| SGF.emitEmptyTuple(Loc)); |
| return; |
| } |
| |
| // Otherwise, build a struct value directly from the elements. |
| SmallVector<SILValue, 4> eltValues; |
| |
| auto elti = elements.begin(), eltEnd = elements.end(); |
| for (VarDecl *field : decl->getStoredProperties()) { |
| auto fieldTy = selfTy.getFieldType(field, SGF.SGM.M); |
| SILValue v; |
| |
| // An initialized 'let' property has a single value specified by the |
| // initializer - it doesn't come from an argument. |
| if (!field->isStatic() && field->isLet() && field->getParentInitializer()) { |
| // Cleanup after this initialization. |
| FullExpr scope(SGF.Cleanups, field->getParentPatternBinding()); |
| v = SGF.emitRValue(field->getParentInitializer()) |
| .forwardAsSingleStorageValue(SGF, fieldTy, Loc); |
| } else { |
| assert(elti != eltEnd && "number of args does not match number of fields"); |
| (void)eltEnd; |
| v = std::move(*elti).forwardAsSingleStorageValue(SGF, fieldTy, Loc); |
| ++elti; |
| } |
| |
| eltValues.push_back(v); |
| } |
| |
| SILValue selfValue = SGF.B.createStruct(Loc, selfTy, eltValues); |
| SGF.B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc), |
| selfValue); |
| return; |
| } |
| |
| void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) { |
| MagicFunctionName = SILGenModule::getMagicFunctionName(ctor); |
| |
| if (ctor->isMemberwiseInitializer()) |
| return emitImplicitValueConstructor(*this, ctor); |
| |
| // True if this constructor delegates to a peer constructor with self.init(). |
| bool isDelegating = ctor->getDelegatingOrChainedInitKind(nullptr) == |
| ConstructorDecl::BodyInitKind::Delegating; |
| |
| // Get the 'self' decl and type. |
| VarDecl *selfDecl = ctor->getImplicitSelfDecl(); |
| auto &lowering = getTypeLowering(selfDecl->getType()->getInOutObjectType()); |
| SILType selfTy = lowering.getLoweredType(); |
| (void)selfTy; |
| assert(!selfTy.getClassOrBoundGenericClass() |
| && "can't emit a class ctor here"); |
| |
| // Decide if we need to do extra work to warn on unsafe behavior in pre-Swift-5 |
| // modes. |
| MarkUninitializedInst::Kind MUIKind; |
| if (isDelegating) { |
| MUIKind = MarkUninitializedInst::DelegatingSelf; |
| } else if (getASTContext().isSwiftVersionAtLeast(5)) { |
| MUIKind = MarkUninitializedInst::RootSelf; |
| } else { |
| auto *dc = ctor->getParent(); |
| if (isa<ExtensionDecl>(dc) && |
| dc->getAsStructOrStructExtensionContext()->getParentModule() != |
| dc->getParentModule()) { |
| MUIKind = MarkUninitializedInst::CrossModuleRootSelf; |
| } else { |
| MUIKind = MarkUninitializedInst::RootSelf; |
| } |
| } |
| |
| // Allocate the local variable for 'self'. |
| emitLocalVariableWithCleanup(selfDecl, MUIKind)->finishInitialization(*this); |
| SILValue selfLV = VarLocs[selfDecl].value; |
| |
| // Emit the prolog. |
| emitProlog(ctor->getParameterList(1), |
| ctor->getResultInterfaceType(), ctor, |
| ctor->hasThrows()); |
| emitConstructorMetatypeArg(*this, ctor); |
| |
| // Create a basic block to jump to for the implicit 'self' return. |
| // We won't emit this until after we've emitted the body. |
| // The epilog takes a void return because the return of 'self' is implicit. |
| prepareEpilog(Type(), ctor->hasThrows(), CleanupLocation(ctor)); |
| |
| // If the constructor can fail, set up an alternative epilog for constructor |
| // failure. |
| SILBasicBlock *failureExitBB = nullptr; |
| SILArgument *failureExitArg = nullptr; |
| auto resultType = ctor->mapTypeIntoContext(ctor->getResultInterfaceType()); |
| auto &resultLowering = getTypeLowering(resultType); |
| |
| if (ctor->getFailability() != OTK_None) { |
| SILBasicBlock *failureBB = createBasicBlock(FunctionSection::Postmatter); |
| |
| // On failure, we'll clean up everything (except self, which should have |
| // been cleaned up before jumping here) and return nil instead. |
| SILGenSavedInsertionPoint savedIP(*this, failureBB, |
| FunctionSection::Postmatter); |
| failureExitBB = createBasicBlock(); |
| Cleanups.emitCleanupsForReturn(ctor); |
| // Return nil. |
| if (F.getConventions().hasIndirectSILResults()) { |
| // Inject 'nil' into the indirect return. |
| assert(F.getIndirectResults().size() == 1); |
| B.createInjectEnumAddr(ctor, F.getIndirectResults()[0], |
| getASTContext().getOptionalNoneDecl()); |
| B.createBranch(ctor, failureExitBB); |
| |
| B.setInsertionPoint(failureExitBB); |
| B.createReturn(ctor, emitEmptyTuple(ctor)); |
| } else { |
| // Pass 'nil' as the return value to the exit BB. |
| failureExitArg = failureExitBB->createPHIArgument( |
| resultLowering.getLoweredType(), ValueOwnershipKind::Owned); |
| SILValue nilResult = |
| B.createEnum(ctor, SILValue(), getASTContext().getOptionalNoneDecl(), |
| resultLowering.getLoweredType()); |
| B.createBranch(ctor, failureExitBB, nilResult); |
| |
| B.setInsertionPoint(failureExitBB); |
| B.createReturn(ctor, failureExitArg); |
| } |
| |
| FailDest = JumpDest(failureBB, Cleanups.getCleanupsDepth(), ctor); |
| } |
| |
| // If this is not a delegating constructor, emit member initializers. |
| if (!isDelegating) { |
| auto *typeDC = ctor->getDeclContext(); |
| auto *nominal = typeDC->getAsNominalTypeOrNominalTypeExtensionContext(); |
| emitMemberInitializers(ctor, selfDecl, nominal); |
| } |
| |
| emitProfilerIncrement(ctor->getBody()); |
| // Emit the constructor body. |
| emitStmt(ctor->getBody()); |
| |
| |
| // Build a custom epilog block, since the AST representation of the |
| // constructor decl (which has no self in the return type) doesn't match the |
| // SIL representation. |
| SILValue selfValue; |
| { |
| SILGenSavedInsertionPoint savedIP(*this, ReturnDest.getBlock()); |
| assert(B.getInsertionBB()->empty() && "Epilog already set up?"); |
| |
| auto cleanupLoc = CleanupLocation::get(ctor); |
| |
| if (!F.getConventions().hasIndirectSILResults()) { |
| // Otherwise, load and return the final 'self' value. |
| selfValue = lowering.emitLoad(B, cleanupLoc, selfLV, |
| LoadOwnershipQualifier::Copy); |
| |
| // Inject the self value into an optional if the constructor is failable. |
| if (ctor->getFailability() != OTK_None) { |
| selfValue = B.createEnum(cleanupLoc, selfValue, |
| getASTContext().getOptionalSomeDecl(), |
| getLoweredLoadableType(resultType)); |
| } |
| } else { |
| // If 'self' is address-only, copy 'self' into the indirect return slot. |
| assert(F.getConventions().getNumIndirectSILResults() == 1 |
| && "no indirect return for address-only ctor?!"); |
| |
| // Get the address to which to store the result. |
| SILValue completeReturnAddress = F.getIndirectResults()[0]; |
| SILValue returnAddress; |
| switch (ctor->getFailability()) { |
| // For non-failable initializers, store to the return address directly. |
| case OTK_None: |
| returnAddress = completeReturnAddress; |
| break; |
| // If this is a failable initializer, project out the payload. |
| case OTK_Optional: |
| case OTK_ImplicitlyUnwrappedOptional: |
| returnAddress = B.createInitEnumDataAddr(cleanupLoc, |
| completeReturnAddress, |
| getASTContext().getOptionalSomeDecl(), |
| selfLV->getType()); |
| break; |
| } |
| |
| // We have to do a non-take copy because someone else may be using the |
| // box (e.g. someone could have closed over it). |
| B.createCopyAddr(cleanupLoc, selfLV, returnAddress, |
| IsNotTake, IsInitialization); |
| |
| // Inject the enum tag if the result is optional because of failability. |
| if (ctor->getFailability() != OTK_None) { |
| // Inject the 'Some' tag. |
| B.createInjectEnumAddr(cleanupLoc, completeReturnAddress, |
| getASTContext().getOptionalSomeDecl()); |
| } |
| } |
| } |
| |
| // Finally, emit the epilog and post-matter. |
| auto returnLoc = emitEpilog(ctor, /*UsesCustomEpilog*/true); |
| |
| // Finish off the epilog by returning. If this is a failable ctor, then we |
| // actually jump to the failure epilog to keep the invariant that there is |
| // only one SIL return instruction per SIL function. |
| if (B.hasValidInsertionPoint()) { |
| if (!failureExitBB) { |
| // If we're not returning self, then return () since we're returning Void. |
| if (!selfValue) { |
| SILLocation loc(ctor); |
| loc.markAutoGenerated(); |
| selfValue = emitEmptyTuple(loc); |
| } |
| |
| B.createReturn(returnLoc, selfValue); |
| } else { |
| if (selfValue) |
| B.createBranch(returnLoc, failureExitBB, selfValue); |
| else |
| B.createBranch(returnLoc, failureExitBB); |
| } |
| } |
| } |
| |
| void SILGenFunction::emitEnumConstructor(EnumElementDecl *element) { |
| CanType enumIfaceTy = element->getParentEnum() |
| ->getDeclaredInterfaceType() |
| ->getCanonicalType(); |
| CanType enumTy = F.mapTypeIntoContext(enumIfaceTy) |
| ->getCanonicalType(); |
| auto &enumTI = getTypeLowering(enumTy); |
| |
| RegularLocation Loc(element); |
| CleanupLocation CleanupLoc(element); |
| Loc.markAutoGenerated(); |
| |
| // Emit the indirect return slot. |
| std::unique_ptr<Initialization> dest; |
| if (enumTI.isAddressOnly() && silConv.useLoweredAddresses()) { |
| auto &AC = getASTContext(); |
| auto VD = new (AC) ParamDecl(VarDecl::Specifier::InOut, |
| SourceLoc(), SourceLoc(), |
| AC.getIdentifier("$return_value"), |
| SourceLoc(), |
| AC.getIdentifier("$return_value"), Type(), |
| element->getDeclContext()); |
| VD->setInterfaceType(enumIfaceTy); |
| auto resultSlot = |
| F.begin()->createFunctionArgument(enumTI.getLoweredType(), VD); |
| dest = std::unique_ptr<Initialization>( |
| new KnownAddressInitialization(resultSlot)); |
| } |
| |
| Scope scope(Cleanups, CleanupLoc); |
| |
| // Emit the exploded constructor argument. |
| ArgumentSource payload; |
| if (element->hasAssociatedValues()) { |
| RValue arg = emitImplicitValueConstructorArg |
| (*this, Loc, element->getArgumentInterfaceType()->getCanonicalType(), |
| element->getDeclContext()); |
| payload = ArgumentSource(Loc, std::move(arg)); |
| } |
| |
| // Emit the metatype argument. |
| emitConstructorMetatypeArg(*this, element); |
| |
| // If possible, emit the enum directly into the indirect return. |
| SGFContext C = (dest ? SGFContext(dest.get()) : SGFContext()); |
| ManagedValue mv = emitInjectEnum(Loc, std::move(payload), |
| enumTI.getLoweredType(), |
| element, C); |
| |
| // Return the enum. |
| auto ReturnLoc = ImplicitReturnLocation::getImplicitReturnLoc(Loc); |
| |
| if (mv.isInContext()) { |
| assert(enumTI.isAddressOnly()); |
| scope.pop(); |
| B.createReturn(ReturnLoc, emitEmptyTuple(Loc)); |
| } else { |
| assert(enumTI.isLoadable() || !silConv.useLoweredAddresses()); |
| SILValue result = mv.ensurePlusOne(*this, ReturnLoc).forward(*this); |
| scope.pop(); |
| B.createReturn(ReturnLoc, result); |
| } |
| } |
| |
| bool Lowering::usesObjCAllocator(ClassDecl *theClass) { |
| while (true) { |
| // If the root class was implemented in Objective-C, use Objective-C's |
| // allocation methods because they may have been overridden. |
| if (!theClass->hasSuperclass()) |
| return theClass->hasClangNode(); |
| |
| theClass = theClass->getSuperclass()->getClassOrBoundGenericClass(); |
| } |
| } |
| |
| void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) { |
| assert(!ctor->isFactoryInit() && "factories should not be emitted here"); |
| |
| // Emit the prolog. Since we're just going to forward our args directly |
| // to the initializer, don't allocate local variables for them. |
| RegularLocation Loc(ctor); |
| Loc.markAutoGenerated(); |
| |
| // Forward the constructor arguments. |
| // FIXME: Handle 'self' along with the other body patterns. |
| SmallVector<SILValue, 8> args; |
| bindParametersForForwarding(ctor->getParameterList(1), args); |
| |
| SILValue selfMetaValue = emitConstructorMetatypeArg(*this, ctor); |
| |
| // Allocate the "self" value. |
| VarDecl *selfDecl = ctor->getImplicitSelfDecl(); |
| SILType selfTy = getLoweredType(selfDecl->getType()); |
| assert(selfTy.hasReferenceSemantics() && |
| "can't emit a value type ctor here"); |
| |
| // Use alloc_ref to allocate the object. |
| // TODO: allow custom allocation? |
| // FIXME: should have a cleanup in case of exception |
| auto selfClassDecl = ctor->getDeclContext()->getAsClassOrClassExtensionContext(); |
| |
| SILValue selfValue; |
| |
| // Allocate the 'self' value. |
| bool useObjCAllocation = usesObjCAllocator(selfClassDecl); |
| |
| if (ctor->isConvenienceInit() || ctor->hasClangNode()) { |
| // For a convenience initializer or an initializer synthesized |
| // for an Objective-C class, allocate using the metatype. |
| SILValue allocArg = selfMetaValue; |
| |
| // When using Objective-C allocation, convert the metatype |
| // argument to an Objective-C metatype. |
| if (useObjCAllocation) { |
| auto metaTy = allocArg->getType().castTo<MetatypeType>(); |
| metaTy = CanMetatypeType::get(metaTy.getInstanceType(), |
| MetatypeRepresentation::ObjC); |
| allocArg = B.createThickToObjCMetatype(Loc, allocArg, |
| getLoweredType(metaTy)); |
| } |
| |
| selfValue = B.createAllocRefDynamic(Loc, allocArg, selfTy, |
| useObjCAllocation, {}, {}); |
| } else { |
| // For a designated initializer, we know that the static type being |
| // allocated is the type of the class that defines the designated |
| // initializer. |
| selfValue = B.createAllocRef(Loc, selfTy, useObjCAllocation, false, |
| ArrayRef<SILType>(), ArrayRef<SILValue>()); |
| } |
| args.push_back(selfValue); |
| |
| // Call the initializer. Always use the Swift entry point, which will be a |
| // bridging thunk if we're calling ObjC. |
| auto initConstant = SILDeclRef(ctor, SILDeclRef::Kind::Initializer); |
| |
| ManagedValue initVal; |
| SILType initTy; |
| |
| // Call the initializer. |
| SubstitutionMap subMap; |
| if (auto *genericEnv = ctor->getGenericEnvironmentOfContext()) { |
| auto *genericSig = genericEnv->getGenericSignature(); |
| subMap = genericSig->getSubstitutionMap( |
| [&](SubstitutableType *t) -> Type { |
| return genericEnv->mapTypeIntoContext( |
| t->castTo<GenericTypeParamType>()); |
| }, |
| MakeAbstractConformanceForGenericType()); |
| } |
| |
| std::tie(initVal, initTy) |
| = emitSiblingMethodRef(Loc, selfValue, initConstant, subMap); |
| |
| SILValue initedSelfValue = emitApplyWithRethrow(Loc, initVal.forward(*this), |
| initTy, subMap, args); |
| |
| emitProfilerIncrement(ctor->getBody()); |
| |
| // Return the initialized 'self'. |
| B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc), |
| initedSelfValue); |
| } |
| |
| void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) { |
| MagicFunctionName = SILGenModule::getMagicFunctionName(ctor); |
| |
| assert(ctor->getBody() && "Class constructor without a body?"); |
| |
| // True if this constructor delegates to a peer constructor with self.init(). |
| bool isDelegating = false; |
| if (!ctor->hasStubImplementation()) { |
| isDelegating = ctor->getDelegatingOrChainedInitKind(nullptr) == |
| ConstructorDecl::BodyInitKind::Delegating; |
| } |
| |
| // Set up the 'self' argument. If this class has a superclass, we set up |
| // self as a box. This allows "self reassignment" to happen in super init |
| // method chains, which is important for interoperating with Objective-C |
| // classes. We also use a box for delegating constructors, since the |
| // delegated-to initializer may also replace self. |
| // |
| // TODO: If we could require Objective-C classes to have an attribute to get |
| // this behavior, we could avoid runtime overhead here. |
| VarDecl *selfDecl = ctor->getImplicitSelfDecl(); |
| auto *dc = ctor->getDeclContext(); |
| auto selfClassDecl = dc->getAsClassOrClassExtensionContext(); |
| bool NeedsBoxForSelf = isDelegating || |
| (selfClassDecl->hasSuperclass() && !ctor->hasStubImplementation()); |
| bool usesObjCAllocator = Lowering::usesObjCAllocator(selfClassDecl); |
| |
| // If needed, mark 'self' as uninitialized so that DI knows to |
| // enforce its DI properties on stored properties. |
| MarkUninitializedInst::Kind MUKind; |
| |
| if (isDelegating) |
| MUKind = MarkUninitializedInst::DelegatingSelf; |
| else if (selfClassDecl->requiresStoredPropertyInits() && |
| usesObjCAllocator) { |
| // Stored properties will be initialized in a separate |
| // .cxx_construct method called by the Objective-C runtime. |
| assert(selfClassDecl->hasSuperclass() && |
| "Cannot use ObjC allocation without a superclass"); |
| MUKind = MarkUninitializedInst::DerivedSelfOnly; |
| } else if (selfClassDecl->hasSuperclass()) |
| MUKind = MarkUninitializedInst::DerivedSelf; |
| else |
| MUKind = MarkUninitializedInst::RootSelf; |
| |
| if (NeedsBoxForSelf) { |
| // Allocate the local variable for 'self'. |
| emitLocalVariableWithCleanup(selfDecl, MUKind)->finishInitialization(*this); |
| } |
| |
| // Emit the prolog for the non-self arguments. |
| // FIXME: Handle self along with the other body patterns. |
| uint16_t ArgNo = emitProlog(ctor->getParameterList(1), |
| TupleType::getEmpty(F.getASTContext()), ctor, |
| ctor->hasThrows()); |
| |
| SILType selfTy = getLoweredLoadableType(selfDecl->getType()); |
| ManagedValue selfArg = B.createInputFunctionArgument(selfTy, selfDecl); |
| |
| if (!NeedsBoxForSelf) { |
| SILLocation PrologueLoc(selfDecl); |
| PrologueLoc.markAsPrologue(); |
| SILDebugVariable DbgVar(selfDecl->isLet(), ++ArgNo); |
| B.createDebugValue(PrologueLoc, selfArg.getValue(), DbgVar); |
| } |
| |
| if (!ctor->hasStubImplementation()) { |
| assert(selfTy.hasReferenceSemantics() && |
| "can't emit a value type ctor here"); |
| if (NeedsBoxForSelf) { |
| SILLocation prologueLoc = RegularLocation(ctor); |
| prologueLoc.markAsPrologue(); |
| // SEMANTIC ARC TODO: When the verifier is complete, review this. |
| B.emitStoreValueOperation(prologueLoc, selfArg.forward(*this), |
| VarLocs[selfDecl].value, |
| StoreOwnershipQualifier::Init); |
| } else { |
| selfArg = B.createMarkUninitialized(selfDecl, selfArg, MUKind); |
| VarLocs[selfDecl] = VarLoc::get(selfArg.getValue()); |
| } |
| } |
| |
| // Prepare the end of initializer location. |
| SILLocation endOfInitLoc = RegularLocation(ctor); |
| endOfInitLoc.pointToEnd(); |
| |
| // Create a basic block to jump to for the implicit 'self' return. |
| // We won't emit the block until after we've emitted the body. |
| prepareEpilog(Type(), ctor->hasThrows(), |
| CleanupLocation::get(endOfInitLoc)); |
| |
| auto resultType = ctor->mapTypeIntoContext(ctor->getResultInterfaceType()); |
| |
| // If the constructor can fail, set up an alternative epilog for constructor |
| // failure. |
| SILBasicBlock *failureExitBB = nullptr; |
| SILArgument *failureExitArg = nullptr; |
| auto &resultLowering = getTypeLowering(resultType); |
| |
| if (ctor->getFailability() != OTK_None) { |
| SILBasicBlock *failureBB = createBasicBlock(FunctionSection::Postmatter); |
| |
| RegularLocation loc(ctor); |
| loc.markAutoGenerated(); |
| |
| // On failure, we'll clean up everything and return nil instead. |
| SILGenSavedInsertionPoint savedIP(*this, failureBB, |
| FunctionSection::Postmatter); |
| |
| failureExitBB = createBasicBlock(); |
| failureExitArg = failureExitBB->createPHIArgument( |
| resultLowering.getLoweredType(), ValueOwnershipKind::Owned); |
| |
| Cleanups.emitCleanupsForReturn(ctor); |
| SILValue nilResult = |
| B.createEnum(loc, SILValue(), getASTContext().getOptionalNoneDecl(), |
| resultLowering.getLoweredType()); |
| B.createBranch(loc, failureExitBB, nilResult); |
| |
| B.setInsertionPoint(failureExitBB); |
| B.createReturn(loc, failureExitArg); |
| |
| FailDest = JumpDest(failureBB, Cleanups.getCleanupsDepth(), ctor); |
| } |
| |
| // Handle member initializers. |
| if (isDelegating) { |
| // A delegating initializer does not initialize instance |
| // variables. |
| } else if (ctor->hasStubImplementation()) { |
| // Nor does a stub implementation. |
| } else if (selfClassDecl->requiresStoredPropertyInits() && |
| usesObjCAllocator) { |
| // When the class requires all stored properties to have initial |
| // values and we're using Objective-C's allocation, stored |
| // properties are initialized via the .cxx_construct method, which |
| // will be called by the runtime. |
| |
| // Note that 'self' has been fully initialized at this point. |
| } else { |
| // Emit the member initializers. |
| emitMemberInitializers(ctor, selfDecl, selfClassDecl); |
| } |
| |
| emitProfilerIncrement(ctor->getBody()); |
| // Emit the constructor body. |
| emitStmt(ctor->getBody()); |
| |
| // Emit the call to super.init() right before exiting from the initializer. |
| if (NeedsBoxForSelf) { |
| if (auto *SI = ctor->getSuperInitCall()) { |
| B.setInsertionPoint(ReturnDest.getBlock()); |
| |
| emitRValue(SI); |
| |
| B.emitBlock(B.splitBlockForFallthrough(), ctor); |
| |
| ReturnDest = JumpDest(B.getInsertionBB(), |
| ReturnDest.getDepth(), |
| ReturnDest.getCleanupLocation()); |
| B.clearInsertionPoint(); |
| } |
| } |
| |
| CleanupStateRestorationScope SelfCleanupSave(Cleanups); |
| |
| // Build a custom epilog block, since the AST representation of the |
| // constructor decl (which has no self in the return type) doesn't match the |
| // SIL representation. |
| { |
| // Ensure that before we add additional cleanups, that we have emitted all |
| // cleanups at this point. |
| assert(!Cleanups.hasAnyActiveCleanups(getCleanupsDepth(), |
| ReturnDest.getDepth()) && |
| "emitting epilog in wrong scope"); |
| |
| SILGenSavedInsertionPoint savedIP(*this, ReturnDest.getBlock()); |
| auto cleanupLoc = CleanupLocation(ctor); |
| |
| // If we're using a box for self, reload the value at the end of the init |
| // method. |
| if (NeedsBoxForSelf) { |
| ManagedValue storedSelf = |
| ManagedValue::forUnmanaged(VarLocs[selfDecl].value); |
| selfArg = B.createLoadCopy(cleanupLoc, storedSelf); |
| } else { |
| // We have to do a retain because we are returning the pointer +1. |
| // |
| // SEMANTIC ARC TODO: When the verifier is complete, we will need to |
| // change this to selfArg = B.emitCopyValueOperation(...). Currently due |
| // to the way that SILGen performs folding of copy_value, destroy_value, |
| // the returned selfArg may be deleted causing us to have a |
| // dead-pointer. Instead just use the old self value since we have a |
| // class. |
| selfArg = B.createCopyValue(cleanupLoc, selfArg); |
| } |
| |
| // Inject the self value into an optional if the constructor is failable. |
| if (ctor->getFailability() != OTK_None) { |
| RegularLocation loc(ctor); |
| loc.markAutoGenerated(); |
| selfArg = B.createEnum(loc, selfArg, |
| getASTContext().getOptionalSomeDecl(), |
| getLoweredLoadableType(resultType)); |
| } |
| |
| // Save our cleanup state. We want all other potential cleanups to fire, but |
| // not this one. |
| if (selfArg.hasCleanup()) |
| SelfCleanupSave.pushCleanupState(selfArg.getCleanup(), |
| CleanupState::Dormant); |
| |
| // Translate our cleanup to the new top cleanup. |
| // |
| // This is needed to preserve the invariant in getEpilogBB that when |
| // cleanups are emitted, everything above ReturnDest.getDepth() has been |
| // emitted. This is not true if we use ManagedValue and friends in the |
| // epilogBB, thus the translation. We perform the same check above that |
| // getEpilogBB performs to ensure that we still do not have the same |
| // problem. |
| ReturnDest = std::move(ReturnDest).translate(getTopCleanup()); |
| } |
| |
| // Emit the epilog and post-matter. |
| auto returnLoc = emitEpilog(ctor, /*UsesCustomEpilog*/true); |
| |
| // Unpop our selfArg cleanup, so we can forward. |
| std::move(SelfCleanupSave).pop(); |
| |
| // Finish off the epilog by returning. If this is a failable ctor, then we |
| // actually jump to the failure epilog to keep the invariant that there is |
| // only one SIL return instruction per SIL function. |
| if (B.hasValidInsertionPoint()) { |
| if (failureExitBB) |
| B.createBranch(returnLoc, failureExitBB, selfArg.forward(*this)); |
| else |
| B.createReturn(returnLoc, selfArg.forward(*this)); |
| } |
| } |
| |
| static ManagedValue emitSelfForMemberInit(SILGenFunction &SGF, SILLocation loc, |
| VarDecl *selfDecl) { |
| CanType selfFormalType = selfDecl->getType() |
| ->getInOutObjectType()->getCanonicalType(); |
| if (selfFormalType->hasReferenceSemantics()) |
| return SGF.emitRValueForDecl(loc, selfDecl, selfDecl->getType(), |
| AccessSemantics::DirectToStorage, |
| SGFContext::AllowImmediatePlusZero) |
| .getAsSingleValue(SGF, loc); |
| else |
| return SGF.emitLValueForDecl(loc, selfDecl, |
| selfDecl->getType()->getCanonicalType(), |
| AccessKind::Write, |
| AccessSemantics::DirectToStorage); |
| } |
| |
| static LValue emitLValueForMemberInit(SILGenFunction &SGF, SILLocation loc, |
| VarDecl *selfDecl, |
| VarDecl *property) { |
| CanType selfFormalType = selfDecl->getType() |
| ->getInOutObjectType()->getCanonicalType(); |
| auto self = emitSelfForMemberInit(SGF, loc, selfDecl); |
| return SGF.emitPropertyLValue(loc, self, selfFormalType, property, |
| LValueOptions(), AccessKind::Write, |
| AccessSemantics::DirectToStorage); |
| } |
| |
| /// Emit a member initialization for the members described in the |
| /// given pattern from the given source value. |
| static void emitMemberInit(SILGenFunction &SGF, VarDecl *selfDecl, |
| Pattern *pattern, RValue &&src) { |
| switch (pattern->getKind()) { |
| case PatternKind::Paren: |
| return emitMemberInit(SGF, selfDecl, |
| cast<ParenPattern>(pattern)->getSubPattern(), |
| std::move(src)); |
| |
| case PatternKind::Tuple: { |
| auto tuple = cast<TuplePattern>(pattern); |
| auto fields = tuple->getElements(); |
| |
| SmallVector<RValue, 4> elements; |
| std::move(src).extractElements(elements); |
| for (unsigned i = 0, n = fields.size(); i != n; ++i) { |
| emitMemberInit(SGF, selfDecl, fields[i].getPattern(), |
| std::move(elements[i])); |
| } |
| break; |
| } |
| |
| case PatternKind::Named: { |
| auto named = cast<NamedPattern>(pattern); |
| // Form the lvalue referencing this member. |
| FormalEvaluationScope scope(SGF); |
| LValue memberRef = emitLValueForMemberInit(SGF, pattern, selfDecl, |
| named->getDecl()); |
| |
| // Assign to it. |
| SGF.emitAssignToLValue(pattern, std::move(src), std::move(memberRef)); |
| return; |
| } |
| |
| case PatternKind::Any: |
| return; |
| |
| case PatternKind::Typed: |
| return emitMemberInit(SGF, selfDecl, |
| cast<TypedPattern>(pattern)->getSubPattern(), |
| std::move(src)); |
| |
| case PatternKind::Var: |
| return emitMemberInit(SGF, selfDecl, |
| cast<VarPattern>(pattern)->getSubPattern(), |
| std::move(src)); |
| |
| #define PATTERN(Name, Parent) |
| #define REFUTABLE_PATTERN(Name, Parent) case PatternKind::Name: |
| #include "swift/AST/PatternNodes.def" |
| llvm_unreachable("Refutable pattern in pattern binding"); |
| } |
| } |
| |
| static SILValue getBehaviorInitStorageFn(SILGenFunction &SGF, |
| VarDecl *behaviorVar) { |
| Mangle::ASTMangler NewMangler; |
| std::string behaviorInitName = NewMangler.mangleBehaviorInitThunk(behaviorVar); |
| |
| SILFunction *thunkFn; |
| // Skip out early if we already emitted this thunk. |
| if (auto existing = SGF.SGM.M.lookUpFunction(behaviorInitName)) { |
| thunkFn = existing; |
| } else { |
| auto init = behaviorVar->getBehavior()->InitStorageDecl.getDecl(); |
| auto initFn = SGF.SGM.getFunction(SILDeclRef(init), NotForDefinition); |
| |
| // Emit a thunk to inject the `self` metatype and implode tuples. |
| auto storageVar = behaviorVar->getBehavior()->StorageDecl; |
| auto selfTy = behaviorVar->getDeclContext()->getDeclaredInterfaceType(); |
| auto initTy = SGF.getLoweredType(selfTy).getFieldType(behaviorVar, |
| SGF.SGM.M); |
| auto storageTy = SGF.getLoweredType(selfTy).getFieldType(storageVar, |
| SGF.SGM.M); |
| |
| auto initConstantTy = initFn->getLoweredType().castTo<SILFunctionType>(); |
| |
| auto param = SILParameterInfo(initTy.getASTType(), |
| initTy.isAddress() ? ParameterConvention::Indirect_In |
| : ParameterConvention::Direct_Owned); |
| auto result = SILResultInfo(storageTy.getASTType(), |
| storageTy.isAddress() ? ResultConvention::Indirect |
| : ResultConvention::Owned); |
| |
| initConstantTy = SILFunctionType::get(initConstantTy->getGenericSignature(), |
| initConstantTy->getExtInfo(), |
| SILCoroutineKind::None, |
| ParameterConvention::Direct_Unowned, |
| param, |
| /*yields*/ {}, |
| result, |
| // TODO: throwing initializer? |
| None, |
| SGF.getASTContext()); |
| |
| // TODO: Generate the body of the thunk. |
| thunkFn = SGF.SGM.M.getOrCreateFunction(SILLocation(behaviorVar), |
| behaviorInitName, |
| SILLinkage::PrivateExternal, |
| initConstantTy, |
| IsBare, IsTransparent, IsSerialized); |
| |
| |
| } |
| return SGF.B.createFunctionRef(behaviorVar, thunkFn); |
| } |
| |
| static SILValue getBehaviorSetterFn(SILGenFunction &SGF, VarDecl *behaviorVar) { |
| auto set = behaviorVar->getSetter(); |
| auto setFn = SGF.SGM.getFunction(SILDeclRef(set), NotForDefinition); |
| |
| // TODO: The setter may need to be a thunk, to implode tuples or perform |
| // reabstractions. |
| return SGF.B.createFunctionRef(behaviorVar, setFn); |
| } |
| |
| static Type getInitializationTypeInContext( |
| DeclContext *fromDC, DeclContext *toDC, |
| Pattern *pattern) { |
| auto interfaceType = pattern->getType()->mapTypeOutOfContext(); |
| auto resultType = toDC->mapTypeIntoContext(interfaceType); |
| |
| return resultType; |
| } |
| |
| void SILGenFunction::emitMemberInitializers(DeclContext *dc, |
| VarDecl *selfDecl, |
| NominalTypeDecl *nominal) { |
| for (auto member : nominal->getMembers()) { |
| // Find instance pattern binding declarations that have initializers. |
| if (auto pbd = dyn_cast<PatternBindingDecl>(member)) { |
| if (pbd->isStatic()) continue; |
| |
| for (auto entry : pbd->getPatternList()) { |
| auto init = entry.getInit(); |
| if (!init) continue; |
| |
| // Cleanup after this initialization. |
| FullExpr scope(Cleanups, entry.getPattern()); |
| |
| // We want a substitution list written in terms of the generic |
| // signature of the type, with replacement archetypes from the |
| // constructor's context (which might be in an extension of |
| // the type, which adds additional generic requirements). |
| SubstitutionMap subs; |
| auto *genericEnv = dc->getGenericEnvironmentOfContext(); |
| auto typeGenericSig = nominal->getGenericSignatureOfContext(); |
| |
| if (genericEnv && typeGenericSig) { |
| // Generate a set of substitutions for the initialization function, |
| // whose generic signature is that of the type context, and whose |
| // replacement types are the archetypes of the initializer itself. |
| subs = typeGenericSig->getSubstitutionMap( |
| [&](SubstitutableType *type) { |
| if (auto gp = type->getAs<GenericTypeParamType>()) { |
| return genericEnv->mapTypeIntoContext(gp); |
| } |
| |
| return Type(type); |
| }, |
| [](CanType dependentType, |
| Type conformingReplacementType, |
| ProtocolType *conformedProtocol) { |
| return ProtocolConformanceRef( |
| conformedProtocol->getDecl()); |
| }); |
| } |
| |
| // Get the type of the initialization result, in terms |
| // of the constructor context's archetypes. |
| CanType resultType = getInitializationTypeInContext( |
| pbd->getDeclContext(), dc, entry.getPattern())->getCanonicalType(); |
| AbstractionPattern origResultType(resultType); |
| |
| // FIXME: Can emitMemberInit() share code with |
| // InitializationForPattern in SILGenDecl.cpp? |
| RValue result = emitApplyOfStoredPropertyInitializer( |
| init, entry, subs, |
| resultType, origResultType, |
| SGFContext()); |
| |
| emitMemberInit(*this, selfDecl, entry.getPattern(), std::move(result)); |
| } |
| } |
| |
| // Introduce behavior initialization markers for properties that need them. |
| if (auto var = dyn_cast<VarDecl>(member)) { |
| if (var->isStatic()) continue; |
| if (!var->hasBehaviorNeedingInitialization()) continue; |
| |
| // Get the initializer method for behavior. |
| auto init = var->getBehavior()->InitStorageDecl; |
| SILValue initFn = getBehaviorInitStorageFn(*this, var); |
| |
| // Get the behavior's storage we need to initialize. |
| auto storage = var->getBehavior()->StorageDecl; |
| LValue storageRef = emitLValueForMemberInit(*this, var, selfDecl,storage); |
| // Shed any reabstraction over the member. |
| while (storageRef.isLastComponentTranslation()) |
| storageRef.dropLastTranslationComponent(); |
| |
| auto storageAddr = emitAddressOfLValue(var, std::move(storageRef), |
| AccessKind::ReadWrite); |
| |
| // Get the setter. |
| auto setterFn = getBehaviorSetterFn(*this, var); |
| auto self = emitSelfForMemberInit(*this, var, selfDecl); |
| |
| auto mark = B.createMarkUninitializedBehavior(var, |
| initFn, init.getSubstitutions(), |
| storageAddr.getValue(), |
| setterFn, getForwardingSubstitutionMap(), self.getValue(), |
| getLoweredType(var->getType()).getAddressType()); |
| |
| // The mark instruction stands in for the behavior property. |
| VarLocs[var].value = mark; |
| } |
| } |
| } |
| |
| void SILGenFunction::emitIVarInitializer(SILDeclRef ivarInitializer) { |
| auto cd = cast<ClassDecl>(ivarInitializer.getDecl()); |
| RegularLocation loc(cd); |
| loc.markAutoGenerated(); |
| |
| // Emit 'self', then mark it uninitialized. |
| auto selfDecl = cd->getDestructor()->getImplicitSelfDecl(); |
| SILType selfTy = getLoweredLoadableType(selfDecl->getType()); |
| SILValue selfArg = F.begin()->createFunctionArgument(selfTy, selfDecl); |
| SILLocation PrologueLoc(selfDecl); |
| PrologueLoc.markAsPrologue(); |
| // Hard-code self as argument number 1. |
| SILDebugVariable DbgVar(selfDecl->isLet(), 1); |
| B.createDebugValue(PrologueLoc, selfArg, DbgVar); |
| selfArg = B.createMarkUninitialized(selfDecl, selfArg, |
| MarkUninitializedInst::RootSelf); |
| assert(selfTy.hasReferenceSemantics() && "can't emit a value type ctor here"); |
| VarLocs[selfDecl] = VarLoc::get(selfArg); |
| |
| auto cleanupLoc = CleanupLocation::get(loc); |
| prepareEpilog(TupleType::getEmpty(getASTContext()), false, cleanupLoc); |
| |
| // Emit the initializers. |
| emitMemberInitializers(cd, selfDecl, cd); |
| |
| // Return 'self'. |
| B.createReturn(loc, selfArg); |
| |
| emitEpilog(loc); |
| } |