mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
///
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user