//===--- 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()->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(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 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 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(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 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( 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 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(); 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(), ArrayRef()); } 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; SmallVector subs; if (auto *genericEnv = ctor->getGenericEnvironmentOfContext()) { auto *genericSig = genericEnv->getGenericSignature(); subMap = genericSig->getSubstitutionMap( [&](SubstitutableType *t) -> Type { return genericEnv->mapTypeIntoContext( t->castTo()); }, MakeAbstractConformanceForGenericType()); genericSig->getSubstitutions(subMap, subs); } std::tie(initVal, initTy) = emitSiblingMethodRef(Loc, selfValue, initConstant, subMap); SILValue initedSelfValue = emitApplyWithRethrow(Loc, initVal.forward(*this), initTy, subs, 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(pattern)->getSubPattern(), std::move(src)); case PatternKind::Tuple: { auto tuple = cast(pattern); auto fields = tuple->getElements(); SmallVector 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(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(pattern)->getSubPattern(), std::move(src)); case PatternKind::Var: return emitMemberInit(SGF, selfDecl, cast(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(); auto param = SILParameterInfo(initTy.getSwiftRValueType(), initTy.isAddress() ? ParameterConvention::Indirect_In : ParameterConvention::Direct_Owned); auto result = SILResultInfo(storageTy.getSwiftRValueType(), 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(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). SubstitutionList 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. auto subMap = typeGenericSig->getSubstitutionMap( [&](SubstitutableType *type) { if (auto gp = type->getAs()) { return genericEnv->mapTypeIntoContext(gp); } return Type(type); }, [](CanType dependentType, Type conformingReplacementType, ProtocolType *conformedProtocol) { return ProtocolConformanceRef( conformedProtocol->getDecl()); }); SmallVector subsVec; typeGenericSig->getSubstitutions(subMap, subsVec); subs = SGM.getASTContext().AllocateCopy(subsVec); } // 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(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, getForwardingSubstitutions(), 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(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); }