Skip to content

Commit bafb0e9

Browse files
committed
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
1 parent 380ddd7 commit bafb0e9

File tree

6 files changed

+59
-32
lines changed

6 files changed

+59
-32
lines changed

include/swift/SIL/SILInstruction.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ class SILInstruction : public ValueBase,public llvm::ilist_node<SILInstruction>{
8888
: ValueBase(Kind, TypeList), ParentBB(0), Location(*DebugLoc) {}
8989

9090
public:
91+
/// Instructions should be allocated using a dedicated instruction allocation
92+
/// function from the ContextTy.
93+
template <typename ContextTy>
94+
void *operator new(size_t Bytes, const ContextTy &C,
95+
size_t Alignment = alignof(ValueBase)) {
96+
return C.allocateInst(Bytes, Alignment);
97+
}
9198

9299
enum class MemoryBehavior {
93100
None,

include/swift/SIL/SILModule.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -499,12 +499,12 @@ class SILModule {
499499
bool PrintASTDecls = true) const;
500500

501501
/// Allocate memory using the module's internal allocator.
502-
void *allocate(unsigned Size, unsigned Align) const {
503-
if (getASTContext().LangOpts.UseMalloc)
504-
return AlignedAlloc(Size, Align);
502+
void *allocate(unsigned Size, unsigned Align) const;
503+
504+
/// Allocate memory for an instruction using the module's internal allocator.
505+
void *allocateInst(unsigned Size, unsigned Align) const;
506+
505507

506-
return BPA.Allocate(Size, Align);
507-
}
508508

509509
/// \brief Looks up the llvm intrinsic ID and type for the builtin function.
510510
///

lib/SIL/SILFunction.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,14 @@ SILFunction::SILFunction(SILModule &Module, SILLinkage Linkage,
102102
}
103103

104104
SILFunction::~SILFunction() {
105-
#ifndef NDEBUG
106105
// If the function is recursive, a function_ref inst inside of the function
107106
// will give the function a non-zero ref count triggering the assertion. Thus
108107
// we drop all instruction references before we erase.
108+
// We also need to drop all references if instructions are allocated using
109+
// an allocator that may recycle freed memory.
109110
dropAllReferences();
110111
assert(RefCount == 0 &&
111112
"Function cannot be deleted while function_ref's still exist");
112-
#endif
113113
}
114114

115115
void SILFunction::setDeclContext(Decl *D) {

lib/SIL/SILInstruction.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,19 @@ void SILInstruction::replaceAllUsesWithUndef() {
176176
}
177177
}
178178

179+
namespace swift {
180+
void deallocate(void *Ptr) {
181+
AlignedFree(Ptr);
182+
}
183+
}
184+
179185
namespace {
180186
class InstructionDestroyer : public SILVisitor<InstructionDestroyer> {
181187
public:
182-
#define VALUE(CLASS, PARENT) void visit##CLASS(CLASS *I) { I->~CLASS(); }
188+
#define VALUE(CLASS, PARENT) void visit##CLASS(CLASS *I) { \
189+
I->~CLASS();\
190+
deallocate(I);\
191+
}
183192
#include "swift/SIL/SILNodes.def"
184193
};
185194
} // end anonymous namespace

lib/SIL/SILInstructions.cpp

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ AllocExistentialBoxInst *AllocExistentialBoxInst::create(
126126
SILType ConcreteLoweredType, ArrayRef<ProtocolConformance *> Conformances,
127127
SILFunction *F) {
128128
SILModule &Mod = F->getModule();
129-
void *Buffer = Mod.allocate(sizeof(AllocExistentialBoxInst),
130-
alignof(AllocExistentialBoxInst));
129+
void *Buffer = Mod.allocateInst(sizeof(AllocExistentialBoxInst),
130+
alignof(AllocExistentialBoxInst));
131131
for (ProtocolConformance *C : Conformances)
132132
declareWitnessTable(Mod, C);
133133
return ::new (Buffer) AllocExistentialBoxInst(Loc,
@@ -142,7 +142,7 @@ BuiltinInst *BuiltinInst::create(SILDebugLocation *Loc, Identifier Name,
142142
ArrayRef<Substitution> Substitutions,
143143
ArrayRef<SILValue> Args,
144144
SILFunction &F) {
145-
void *Buffer = F.getModule().allocate(
145+
void *Buffer = F.getModule().allocateInst(
146146
sizeof(BuiltinInst)
147147
+ decltype(Operands)::getExtraSize(Args.size())
148148
+ sizeof(Substitution) * Substitutions.size(),
@@ -189,7 +189,7 @@ bool swift::doesApplyCalleeHaveSemantics(SILValue callee, StringRef semantics) {
189189
}
190190

191191
void *swift::allocateApplyInst(SILFunction &F, size_t size, size_t alignment) {
192-
return F.getModule().allocate(size, alignment);
192+
return F.getModule().allocateInst(size, alignment);
193193
}
194194

195195
PartialApplyInst::PartialApplyInst(SILDebugLocation *Loc, SILValue Callee,
@@ -275,14 +275,14 @@ static unsigned getWordsForBitWidth(unsigned bits) {
275275

276276
template<typename INST>
277277
static void *allocateLiteralInstWithTextSize(SILFunction &F, unsigned length) {
278-
return F.getModule().allocate(sizeof(INST) + length, alignof(INST));
278+
return F.getModule().allocateInst(sizeof(INST) + length, alignof(INST));
279279
}
280280

281281
template<typename INST>
282282
static void *allocateLiteralInstWithBitSize(SILFunction &F, unsigned bits) {
283283
unsigned words = getWordsForBitWidth(bits);
284-
return F.getModule().allocate(sizeof(INST) + sizeof(llvm::integerPart)*words,
285-
alignof(INST));
284+
return F.getModule().allocateInst(
285+
sizeof(INST) + sizeof(llvm::integerPart)*words, alignof(INST));
286286
}
287287

288288
IntegerLiteralInst::IntegerLiteralInst(SILDebugLocation *Loc, SILType Ty,
@@ -408,7 +408,7 @@ AssignInst::AssignInst(SILDebugLocation *Loc, SILValue Src, SILValue Dest)
408408
MarkFunctionEscapeInst *
409409
MarkFunctionEscapeInst::create(SILDebugLocation *Loc,
410410
ArrayRef<SILValue> Elements, SILFunction &F) {
411-
void *Buffer = F.getModule().allocate(sizeof(MarkFunctionEscapeInst) +
411+
void *Buffer = F.getModule().allocateInst(sizeof(MarkFunctionEscapeInst) +
412412
decltype(Operands)::getExtraSize(Elements.size()),
413413
alignof(MarkFunctionEscapeInst));
414414
return ::new(Buffer) MarkFunctionEscapeInst(Loc, Elements);
@@ -456,7 +456,7 @@ UnconditionalCheckedCastAddrInst::UnconditionalCheckedCastAddrInst(
456456

457457
StructInst *StructInst::create(SILDebugLocation *Loc, SILType Ty,
458458
ArrayRef<SILValue> Elements, SILFunction &F) {
459-
void *Buffer = F.getModule().allocate(sizeof(StructInst) +
459+
void *Buffer = F.getModule().allocateInst(sizeof(StructInst) +
460460
decltype(Operands)::getExtraSize(Elements.size()),
461461
alignof(StructInst));
462462
return ::new(Buffer) StructInst(Loc, Ty, Elements);
@@ -470,7 +470,7 @@ StructInst::StructInst(SILDebugLocation *Loc, SILType Ty,
470470

471471
TupleInst *TupleInst::create(SILDebugLocation *Loc, SILType Ty,
472472
ArrayRef<SILValue> Elements, SILFunction &F) {
473-
void *Buffer = F.getModule().allocate(sizeof(TupleInst) +
473+
void *Buffer = F.getModule().allocateInst(sizeof(TupleInst) +
474474
decltype(Operands)::getExtraSize(Elements.size()),
475475
alignof(TupleInst));
476476
return ::new(Buffer) TupleInst(Loc, Ty, Elements);
@@ -673,7 +673,7 @@ BranchInst *BranchInst::create(SILDebugLocation *Loc, SILBasicBlock *DestBB,
673673
BranchInst *BranchInst::create(SILDebugLocation *Loc,
674674
SILBasicBlock *DestBB, ArrayRef<SILValue> Args,
675675
SILFunction &F) {
676-
void *Buffer = F.getModule().allocate(sizeof(BranchInst) +
676+
void *Buffer = F.getModule().allocateInst(sizeof(BranchInst) +
677677
decltype(Operands)::getExtraSize(Args.size()),
678678
alignof(BranchInst));
679679
return ::new (Buffer) BranchInst(Loc, DestBB, Args);
@@ -707,7 +707,7 @@ CondBranchInst::create(SILDebugLocation *Loc, SILValue Condition,
707707
Args.append(TrueArgs.begin(), TrueArgs.end());
708708
Args.append(FalseArgs.begin(), FalseArgs.end());
709709

710-
void *Buffer = F.getModule().allocate(sizeof(CondBranchInst) +
710+
void *Buffer = F.getModule().allocateInst(sizeof(CondBranchInst) +
711711
decltype(Operands)::getExtraSize(Args.size()),
712712
alignof(CondBranchInst));
713713
return ::new (Buffer) CondBranchInst(Loc, Condition, TrueBB, FalseBB, Args,
@@ -857,7 +857,7 @@ SwitchValueInst *SwitchValueInst::create(
857857
size_t bufSize = sizeof(SwitchValueInst) +
858858
decltype(Operands)::getExtraSize(Cases.size()) +
859859
sizeof(SILSuccessor) * numSuccessors;
860-
void *buf = F.getModule().allocate(bufSize, alignof(SwitchValueInst));
860+
void *buf = F.getModule().allocateInst(bufSize, alignof(SwitchValueInst));
861861
return ::new (buf) SwitchValueInst(Loc, Operand, DefaultBB, Cases, BBs);
862862
}
863863

@@ -905,7 +905,7 @@ SelectValueInst::create(SILDebugLocation *Loc, SILValue Operand, SILType Type,
905905

906906
size_t bufSize = sizeof(SelectValueInst) + decltype(Operands)::getExtraSize(
907907
CaseValuesAndResults.size());
908-
void *buf = F.getModule().allocate(bufSize, alignof(SelectValueInst));
908+
void *buf = F.getModule().allocateInst(bufSize, alignof(SelectValueInst));
909909
return ::new (buf)
910910
SelectValueInst(Loc, Operand, Type, DefaultResult, CaseValuesAndResults);
911911
}
@@ -946,7 +946,7 @@ SELECT_ENUM_INST *SelectEnumInstBase::createSelectEnum(
946946
// and `CaseBBs.size() + (DefaultBB ? 1 : 0)` values.
947947
unsigned numCases = CaseValues.size();
948948

949-
void *buf = F.getModule().allocate(
949+
void *buf = F.getModule().allocateInst(
950950
sizeof(SELECT_ENUM_INST) + sizeof(EnumElementDecl*) * numCases
951951
+ TailAllocatedOperandList<1>::getExtraSize(numCases + (bool)DefaultValue),
952952
alignof(SELECT_ENUM_INST));
@@ -1067,7 +1067,7 @@ SWITCH_ENUM_INST *SwitchEnumInstBase::createSwitchEnum(
10671067
unsigned numCases = CaseBBs.size();
10681068
unsigned numSuccessors = numCases + (DefaultBB ? 1 : 0);
10691069

1070-
void *buf = F.getModule().allocate(sizeof(SWITCH_ENUM_INST)
1070+
void *buf = F.getModule().allocateInst(sizeof(SWITCH_ENUM_INST)
10711071
+ sizeof(EnumElementDecl*) * numCases
10721072
+ sizeof(SILSuccessor) * numSuccessors,
10731073
alignof(SWITCH_ENUM_INST));
@@ -1133,8 +1133,8 @@ DynamicMethodBranchInst *
11331133
DynamicMethodBranchInst::create(SILDebugLocation *Loc, SILValue Operand,
11341134
SILDeclRef Member, SILBasicBlock *HasMethodBB,
11351135
SILBasicBlock *NoMethodBB, SILFunction &F) {
1136-
void *Buffer = F.getModule().allocate(sizeof(DynamicMethodBranchInst),
1137-
alignof(DynamicMethodBranchInst));
1136+
void *Buffer = F.getModule().allocateInst(sizeof(DynamicMethodBranchInst),
1137+
alignof(DynamicMethodBranchInst));
11381138
return ::new (Buffer)
11391139
DynamicMethodBranchInst(Loc, Operand, Member, HasMethodBB, NoMethodBB);
11401140
}
@@ -1176,7 +1176,7 @@ WitnessMethodInst::create(SILDebugLocation *Loc, CanType LookupType,
11761176
SILValue OpenedExistential, bool Volatile) {
11771177
SILModule &Mod = F->getModule();
11781178
void *Buffer =
1179-
Mod.allocate(sizeof(WitnessMethodInst), alignof(WitnessMethodInst));
1179+
Mod.allocateInst(sizeof(WitnessMethodInst), alignof(WitnessMethodInst));
11801180

11811181
declareWitnessTable(Mod, Conformance);
11821182
return ::new (Buffer) WitnessMethodInst(Loc, LookupType, Conformance, Member,
@@ -1188,8 +1188,8 @@ InitExistentialAddrInst *InitExistentialAddrInst::create(
11881188
SILType ConcreteLoweredType, ArrayRef<ProtocolConformance *> Conformances,
11891189
SILFunction *F) {
11901190
SILModule &Mod = F->getModule();
1191-
void *Buffer = Mod.allocate(sizeof(InitExistentialAddrInst),
1192-
alignof(InitExistentialAddrInst));
1191+
void *Buffer = Mod.allocateInst(sizeof(InitExistentialAddrInst),
1192+
alignof(InitExistentialAddrInst));
11931193
for (ProtocolConformance *C : Conformances)
11941194
declareWitnessTable(Mod, C);
11951195
return ::new (Buffer) InitExistentialAddrInst(Loc, Existential,
@@ -1204,8 +1204,8 @@ InitExistentialRefInst::create(SILDebugLocation *Loc, SILType ExistentialType,
12041204
ArrayRef<ProtocolConformance *> Conformances,
12051205
SILFunction *F) {
12061206
SILModule &Mod = F->getModule();
1207-
void *Buffer = Mod.allocate(sizeof(InitExistentialRefInst),
1208-
alignof(InitExistentialRefInst));
1207+
void *Buffer = Mod.allocateInst(sizeof(InitExistentialRefInst),
1208+
alignof(InitExistentialRefInst));
12091209
for (ProtocolConformance *C : Conformances) {
12101210
if (!C)
12111211
continue;
@@ -1239,7 +1239,7 @@ InitExistentialMetatypeInst *InitExistentialMetatypeInst::create(
12391239
unsigned size = sizeof(InitExistentialMetatypeInst);
12401240
size += conformances.size() * sizeof(ProtocolConformance *);
12411241

1242-
void *buffer = M.allocate(size, alignof(InitExistentialMetatypeInst));
1242+
void *buffer = M.allocateInst(size, alignof(InitExistentialMetatypeInst));
12431243
for (ProtocolConformance *conformance : conformances)
12441244
if (!M.lookUpWitnessTable(conformance, false).first)
12451245
declareWitnessTable(M, conformance);

lib/SIL/SILModule.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@ SILModule::~SILModule() {
124124
delete (SILTypeListUniquingType*)TypeListUniquing;
125125
}
126126

127+
void *SILModule::allocate(unsigned Size, unsigned Align) const {
128+
if (getASTContext().LangOpts.UseMalloc)
129+
return AlignedAlloc(Size, Align);
130+
131+
return BPA.Allocate(Size, Align);
132+
}
133+
134+
void *SILModule::allocateInst(unsigned Size, unsigned Align) const {
135+
return AlignedAlloc(Size, Align);
136+
}
137+
127138
SILWitnessTable *
128139
SILModule::createWitnessTableDeclaration(ProtocolConformance *C,
129140
SILLinkage linkage) {

0 commit comments

Comments
 (0)