Re-apply "Reduce memory footprint of the Swift compiler"

Use malloc/free for allocating/freeing SIL instructions instead of using the BumpPtrAllocator. This allows for memory reuse and significantly reduces the memory footprint of the compiler.

For example, a peak memory usage during a compilation of the standard library and StdlibUnitTest is reduced by 25%-30%. The performance of the compiler seems to be not affected by this change, i.e. no slowdown is measured.

The use-after-free issues reported by build bots are fixed now.

rdar://23303031
This commit is contained in:
Roman Levenstein
2015-12-09 11:31:58 -08:00
parent 13b679d9ba
commit 46b58ac699
7 changed files with 85 additions and 37 deletions

View File

@@ -30,6 +30,7 @@ class SILArgument;
class SILBasicBlock :
public llvm::ilist_node<SILBasicBlock>, public SILAllocated<SILBasicBlock> {
friend class SILSuccessor;
friend class SILFunction;
public:
using InstListType = llvm::iplist<SILInstruction>;
private:

View File

@@ -88,6 +88,13 @@ protected:
: ValueBase(Kind, TypeList), ParentBB(0), Location(*DebugLoc) {}
public:
/// Instructions should be allocated using a dedicated instruction allocation
/// function from the ContextTy.
template <typename ContextTy>
void *operator new(size_t Bytes, const ContextTy &C,
size_t Alignment = alignof(ValueBase)) {
return C.allocateInst(Bytes, Alignment);
}
enum class MemoryBehavior {
None,

View File

@@ -531,12 +531,13 @@ public:
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.
///

View File

@@ -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.

View File

@@ -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) {

View File

@@ -127,7 +127,7 @@ AllocExistentialBoxInst *AllocExistentialBoxInst::create(
SILType ConcreteLoweredType, ArrayRef<ProtocolConformance *> Conformances,
SILFunction *F) {
SILModule &Mod = F->getModule();
void *Buffer = Mod.allocate(sizeof(AllocExistentialBoxInst),
void *Buffer = Mod.allocateInst(sizeof(AllocExistentialBoxInst),
alignof(AllocExistentialBoxInst));
for (ProtocolConformance *C : Conformances)
declareWitnessTable(Mod, C);
@@ -143,7 +143,7 @@ BuiltinInst *BuiltinInst::create(SILDebugLocation *Loc, Identifier Name,
ArrayRef<Substitution> Substitutions,
ArrayRef<SILValue> 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<typename INST>
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<typename INST>
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<SILValue> 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<SILValue> 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<SILValue> 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<SILValue> 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,7 +1129,7 @@ DynamicMethodBranchInst *
DynamicMethodBranchInst::create(SILDebugLocation *Loc, SILValue Operand,
SILDeclRef Member, SILBasicBlock *HasMethodBB,
SILBasicBlock *NoMethodBB, SILFunction &F) {
void *Buffer = F.getModule().allocate(sizeof(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,7 +1184,7 @@ InitExistentialAddrInst *InitExistentialAddrInst::create(
SILType ConcreteLoweredType, ArrayRef<ProtocolConformance *> Conformances,
SILFunction *F) {
SILModule &Mod = F->getModule();
void *Buffer = Mod.allocate(sizeof(InitExistentialAddrInst),
void *Buffer = Mod.allocateInst(sizeof(InitExistentialAddrInst),
alignof(InitExistentialAddrInst));
for (ProtocolConformance *C : Conformances)
declareWitnessTable(Mod, C);
@@ -1200,7 +1200,7 @@ InitExistentialRefInst::create(SILDebugLocation *Loc, SILType ExistentialType,
ArrayRef<ProtocolConformance *> Conformances,
SILFunction *F) {
SILModule &Mod = F->getModule();
void *Buffer = Mod.allocate(sizeof(InitExistentialRefInst),
void *Buffer = Mod.allocateInst(sizeof(InitExistentialRefInst),
alignof(InitExistentialRefInst));
for (ProtocolConformance *C : Conformances) {
if (!C)
@@ -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);

View File

@@ -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) {