diff --git a/include/swift/SIL/SILBasicBlock.h b/include/swift/SIL/SILBasicBlock.h index 98ae485a1007a..bd8c016a50c6f 100644 --- a/include/swift/SIL/SILBasicBlock.h +++ b/include/swift/SIL/SILBasicBlock.h @@ -30,6 +30,7 @@ class SILArgument; class SILBasicBlock : public llvm::ilist_node, public SILAllocated { friend class SILSuccessor; + friend class SILFunction; public: using InstListType = llvm::iplist; private: diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 9aad22a32a632..e177cf38fa0ea 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -88,6 +88,13 @@ class SILInstruction : public ValueBase,public llvm::ilist_node{ : ValueBase(Kind, TypeList), ParentBB(0), Location(*DebugLoc) {} public: + /// Instructions should be allocated using a dedicated instruction allocation + /// function from the ContextTy. + template + void *operator new(size_t Bytes, const ContextTy &C, + size_t Alignment = alignof(ValueBase)) { + return C.allocateInst(Bytes, Alignment); + } enum class MemoryBehavior { None, diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h index af7537f8a2fef..ac5e90eb1d84f 100644 --- a/include/swift/SIL/SILModule.h +++ b/include/swift/SIL/SILModule.h @@ -531,12 +531,13 @@ class SILModule { bool PrintASTDecls = true) const; /// Allocate memory using the module's internal allocator. - void *allocate(unsigned Size, unsigned Align) const { - if (getASTContext().LangOpts.UseMalloc) - return AlignedAlloc(Size, Align); + void *allocate(unsigned Size, unsigned Align) const; - return BPA.Allocate(Size, Align); - } + /// Allocate memory for an instruction using the module's internal allocator. + void *allocateInst(unsigned Size, unsigned Align) const; + + /// Deallocate memory of an instruction. + void deallocateInst(SILInstruction *I); /// \brief Looks up the llvm intrinsic ID and type for the builtin function. /// diff --git a/lib/SIL/SILBasicBlock.cpp b/lib/SIL/SILBasicBlock.cpp index 78ee2b06b9de2..90cc45dbc3fd8 100644 --- a/lib/SIL/SILBasicBlock.cpp +++ b/lib/SIL/SILBasicBlock.cpp @@ -37,18 +37,25 @@ SILBasicBlock::SILBasicBlock(SILFunction *parent, SILBasicBlock *afterBB) } } SILBasicBlock::~SILBasicBlock() { - // Notify the delete handlers that the instructions in this block are - // being deleted. - for (auto I = begin(), E = end(); I != E; ++I) { - getModule().notifyDeleteHandlers(&*I); - } - // Invalidate all of the basic block arguments. for (auto *Arg : BBArgList) { getModule().notifyDeleteHandlers(Arg); } + dropAllReferences(); + + // Notify the delete handlers that the instructions in this block are + // being deleted. + auto &M = getModule(); + for (auto I = begin(), E = end(); I != E;) { + auto Inst = &*I; + ++I; + M.notifyDeleteHandlers(Inst); + erase(Inst); + } + // iplist's destructor is going to destroy the InstList. + InstList.clearAndLeakNodesUnsafely(); } int SILBasicBlock::getDebugID() { @@ -86,7 +93,9 @@ void SILBasicBlock::remove(SILInstruction *I) { void SILBasicBlock::erase(SILInstruction *I) { // Notify the delete handlers that this instruction is going away. getModule().notifyDeleteHandlers(&*I); + auto *F = getParent(); InstList.erase(I); + F->getModule().deallocateInst(I); } /// This method unlinks 'self' from the containing SILFunction and deletes it. diff --git a/lib/SIL/SILFunction.cpp b/lib/SIL/SILFunction.cpp index 2a5ed7b3fb074..dd29f11aed1b3 100644 --- a/lib/SIL/SILFunction.cpp +++ b/lib/SIL/SILFunction.cpp @@ -102,14 +102,29 @@ SILFunction::SILFunction(SILModule &Module, SILLinkage Linkage, } SILFunction::~SILFunction() { -#ifndef NDEBUG // If the function is recursive, a function_ref inst inside of the function // will give the function a non-zero ref count triggering the assertion. Thus // we drop all instruction references before we erase. + // We also need to drop all references if instructions are allocated using + // an allocator that may recycle freed memory. dropAllReferences(); + + auto &M = getModule(); + for (auto &BB : *this) { + for (auto I = BB.begin(), E = BB.end(); I != E;) { + auto Inst = &*I; + ++I; + SILInstruction::destroy(Inst); + // TODO: It is only safe to directly deallocate an + // instruction if this BB is being removed in scope + // of destructing a SILFunction. + M.deallocateInst(Inst); + } + BB.InstList.clearAndLeakNodesUnsafely(); + } + assert(RefCount == 0 && "Function cannot be deleted while function_ref's still exist"); -#endif } void SILFunction::setDeclContext(Decl *D) { diff --git a/lib/SIL/SILInstructions.cpp b/lib/SIL/SILInstructions.cpp index 1b90cdcea14d0..454391df11fba 100644 --- a/lib/SIL/SILInstructions.cpp +++ b/lib/SIL/SILInstructions.cpp @@ -127,8 +127,8 @@ AllocExistentialBoxInst *AllocExistentialBoxInst::create( SILType ConcreteLoweredType, ArrayRef Conformances, SILFunction *F) { SILModule &Mod = F->getModule(); - void *Buffer = Mod.allocate(sizeof(AllocExistentialBoxInst), - alignof(AllocExistentialBoxInst)); + void *Buffer = Mod.allocateInst(sizeof(AllocExistentialBoxInst), + alignof(AllocExistentialBoxInst)); for (ProtocolConformance *C : Conformances) declareWitnessTable(Mod, C); return ::new (Buffer) AllocExistentialBoxInst(Loc, @@ -143,7 +143,7 @@ BuiltinInst *BuiltinInst::create(SILDebugLocation *Loc, Identifier Name, ArrayRef Substitutions, ArrayRef Args, SILFunction &F) { - void *Buffer = F.getModule().allocate( + void *Buffer = F.getModule().allocateInst( sizeof(BuiltinInst) + decltype(Operands)::getExtraSize(Args.size()) + sizeof(Substitution) * Substitutions.size(), @@ -190,7 +190,7 @@ bool swift::doesApplyCalleeHaveSemantics(SILValue callee, StringRef semantics) { } void *swift::allocateApplyInst(SILFunction &F, size_t size, size_t alignment) { - return F.getModule().allocate(size, alignment); + return F.getModule().allocateInst(size, alignment); } PartialApplyInst::PartialApplyInst(SILDebugLocation *Loc, SILValue Callee, @@ -276,14 +276,14 @@ static unsigned getWordsForBitWidth(unsigned bits) { template static void *allocateLiteralInstWithTextSize(SILFunction &F, unsigned length) { - return F.getModule().allocate(sizeof(INST) + length, alignof(INST)); + return F.getModule().allocateInst(sizeof(INST) + length, alignof(INST)); } template static void *allocateLiteralInstWithBitSize(SILFunction &F, unsigned bits) { unsigned words = getWordsForBitWidth(bits); - return F.getModule().allocate(sizeof(INST) + sizeof(llvm::integerPart)*words, - alignof(INST)); + return F.getModule().allocateInst( + sizeof(INST) + sizeof(llvm::integerPart)*words, alignof(INST)); } IntegerLiteralInst::IntegerLiteralInst(SILDebugLocation *Loc, SILType Ty, @@ -409,7 +409,7 @@ AssignInst::AssignInst(SILDebugLocation *Loc, SILValue Src, SILValue Dest) MarkFunctionEscapeInst * MarkFunctionEscapeInst::create(SILDebugLocation *Loc, ArrayRef Elements, SILFunction &F) { - void *Buffer = F.getModule().allocate(sizeof(MarkFunctionEscapeInst) + + void *Buffer = F.getModule().allocateInst(sizeof(MarkFunctionEscapeInst) + decltype(Operands)::getExtraSize(Elements.size()), alignof(MarkFunctionEscapeInst)); return ::new(Buffer) MarkFunctionEscapeInst(Loc, Elements); @@ -452,7 +452,7 @@ UnconditionalCheckedCastAddrInst::UnconditionalCheckedCastAddrInst( StructInst *StructInst::create(SILDebugLocation *Loc, SILType Ty, ArrayRef Elements, SILFunction &F) { - void *Buffer = F.getModule().allocate(sizeof(StructInst) + + void *Buffer = F.getModule().allocateInst(sizeof(StructInst) + decltype(Operands)::getExtraSize(Elements.size()), alignof(StructInst)); return ::new(Buffer) StructInst(Loc, Ty, Elements); @@ -466,7 +466,7 @@ StructInst::StructInst(SILDebugLocation *Loc, SILType Ty, TupleInst *TupleInst::create(SILDebugLocation *Loc, SILType Ty, ArrayRef Elements, SILFunction &F) { - void *Buffer = F.getModule().allocate(sizeof(TupleInst) + + void *Buffer = F.getModule().allocateInst(sizeof(TupleInst) + decltype(Operands)::getExtraSize(Elements.size()), alignof(TupleInst)); return ::new(Buffer) TupleInst(Loc, Ty, Elements); @@ -669,7 +669,7 @@ BranchInst *BranchInst::create(SILDebugLocation *Loc, SILBasicBlock *DestBB, BranchInst *BranchInst::create(SILDebugLocation *Loc, SILBasicBlock *DestBB, ArrayRef Args, SILFunction &F) { - void *Buffer = F.getModule().allocate(sizeof(BranchInst) + + void *Buffer = F.getModule().allocateInst(sizeof(BranchInst) + decltype(Operands)::getExtraSize(Args.size()), alignof(BranchInst)); return ::new (Buffer) BranchInst(Loc, DestBB, Args); @@ -703,7 +703,7 @@ CondBranchInst::create(SILDebugLocation *Loc, SILValue Condition, Args.append(TrueArgs.begin(), TrueArgs.end()); Args.append(FalseArgs.begin(), FalseArgs.end()); - void *Buffer = F.getModule().allocate(sizeof(CondBranchInst) + + void *Buffer = F.getModule().allocateInst(sizeof(CondBranchInst) + decltype(Operands)::getExtraSize(Args.size()), alignof(CondBranchInst)); return ::new (Buffer) CondBranchInst(Loc, Condition, TrueBB, FalseBB, Args, @@ -853,7 +853,7 @@ SwitchValueInst *SwitchValueInst::create( size_t bufSize = sizeof(SwitchValueInst) + decltype(Operands)::getExtraSize(Cases.size()) + sizeof(SILSuccessor) * numSuccessors; - void *buf = F.getModule().allocate(bufSize, alignof(SwitchValueInst)); + void *buf = F.getModule().allocateInst(bufSize, alignof(SwitchValueInst)); return ::new (buf) SwitchValueInst(Loc, Operand, DefaultBB, Cases, BBs); } @@ -901,7 +901,7 @@ SelectValueInst::create(SILDebugLocation *Loc, SILValue Operand, SILType Type, size_t bufSize = sizeof(SelectValueInst) + decltype(Operands)::getExtraSize( CaseValuesAndResults.size()); - void *buf = F.getModule().allocate(bufSize, alignof(SelectValueInst)); + void *buf = F.getModule().allocateInst(bufSize, alignof(SelectValueInst)); return ::new (buf) SelectValueInst(Loc, Operand, Type, DefaultResult, CaseValuesAndResults); } @@ -942,7 +942,7 @@ SELECT_ENUM_INST *SelectEnumInstBase::createSelectEnum( // and `CaseBBs.size() + (DefaultBB ? 1 : 0)` values. unsigned numCases = CaseValues.size(); - void *buf = F.getModule().allocate( + void *buf = F.getModule().allocateInst( sizeof(SELECT_ENUM_INST) + sizeof(EnumElementDecl*) * numCases + TailAllocatedOperandList<1>::getExtraSize(numCases + (bool)DefaultValue), alignof(SELECT_ENUM_INST)); @@ -1063,7 +1063,7 @@ SWITCH_ENUM_INST *SwitchEnumInstBase::createSwitchEnum( unsigned numCases = CaseBBs.size(); unsigned numSuccessors = numCases + (DefaultBB ? 1 : 0); - void *buf = F.getModule().allocate(sizeof(SWITCH_ENUM_INST) + void *buf = F.getModule().allocateInst(sizeof(SWITCH_ENUM_INST) + sizeof(EnumElementDecl*) * numCases + sizeof(SILSuccessor) * numSuccessors, alignof(SWITCH_ENUM_INST)); @@ -1129,8 +1129,8 @@ DynamicMethodBranchInst * DynamicMethodBranchInst::create(SILDebugLocation *Loc, SILValue Operand, SILDeclRef Member, SILBasicBlock *HasMethodBB, SILBasicBlock *NoMethodBB, SILFunction &F) { - void *Buffer = F.getModule().allocate(sizeof(DynamicMethodBranchInst), - alignof(DynamicMethodBranchInst)); + void *Buffer = F.getModule().allocateInst(sizeof(DynamicMethodBranchInst), + alignof(DynamicMethodBranchInst)); return ::new (Buffer) DynamicMethodBranchInst(Loc, Operand, Member, HasMethodBB, NoMethodBB); } @@ -1172,7 +1172,7 @@ WitnessMethodInst::create(SILDebugLocation *Loc, CanType LookupType, SILValue OpenedExistential, bool Volatile) { SILModule &Mod = F->getModule(); void *Buffer = - Mod.allocate(sizeof(WitnessMethodInst), alignof(WitnessMethodInst)); + Mod.allocateInst(sizeof(WitnessMethodInst), alignof(WitnessMethodInst)); declareWitnessTable(Mod, Conformance); return ::new (Buffer) WitnessMethodInst(Loc, LookupType, Conformance, Member, @@ -1184,8 +1184,8 @@ InitExistentialAddrInst *InitExistentialAddrInst::create( SILType ConcreteLoweredType, ArrayRef Conformances, SILFunction *F) { SILModule &Mod = F->getModule(); - void *Buffer = Mod.allocate(sizeof(InitExistentialAddrInst), - alignof(InitExistentialAddrInst)); + void *Buffer = Mod.allocateInst(sizeof(InitExistentialAddrInst), + alignof(InitExistentialAddrInst)); for (ProtocolConformance *C : Conformances) declareWitnessTable(Mod, C); return ::new (Buffer) InitExistentialAddrInst(Loc, Existential, @@ -1200,8 +1200,8 @@ InitExistentialRefInst::create(SILDebugLocation *Loc, SILType ExistentialType, ArrayRef Conformances, SILFunction *F) { SILModule &Mod = F->getModule(); - void *Buffer = Mod.allocate(sizeof(InitExistentialRefInst), - alignof(InitExistentialRefInst)); + void *Buffer = Mod.allocateInst(sizeof(InitExistentialRefInst), + alignof(InitExistentialRefInst)); for (ProtocolConformance *C : Conformances) { if (!C) continue; @@ -1235,7 +1235,7 @@ InitExistentialMetatypeInst *InitExistentialMetatypeInst::create( unsigned size = sizeof(InitExistentialMetatypeInst); size += conformances.size() * sizeof(ProtocolConformance *); - void *buffer = M.allocate(size, alignof(InitExistentialMetatypeInst)); + void *buffer = M.allocateInst(size, alignof(InitExistentialMetatypeInst)); for (ProtocolConformance *conformance : conformances) if (!M.lookUpWitnessTable(conformance, false).first) declareWitnessTable(M, conformance); diff --git a/lib/SIL/SILModule.cpp b/lib/SIL/SILModule.cpp index a08b0d5db7ab7..588e0f5b9d907 100644 --- a/lib/SIL/SILModule.cpp +++ b/lib/SIL/SILModule.cpp @@ -124,6 +124,21 @@ SILModule::~SILModule() { delete (SILTypeListUniquingType*)TypeListUniquing; } +void *SILModule::allocate(unsigned Size, unsigned Align) const { + if (getASTContext().LangOpts.UseMalloc) + return AlignedAlloc(Size, Align); + + return BPA.Allocate(Size, Align); +} + +void *SILModule::allocateInst(unsigned Size, unsigned Align) const { + return AlignedAlloc(Size, Align); +} + +void SILModule::deallocateInst(SILInstruction *I) { + AlignedFree(I); +} + SILWitnessTable * SILModule::createWitnessTableDeclaration(ProtocolConformance *C, SILLinkage linkage) {