Call SILFunction destructor when we cleanup functions so that if the function contains a function_ref, the function referenced by the function_ref has its refcount properly decrement.

Otherwise a function_ref which was supposed to be deallocated would keep
functions alive.

rdar://16287331

Swift SVN r16192
This commit is contained in:
Michael Gottesman
2014-04-11 01:44:38 +00:00
parent 60a52651e2
commit 0bc4f9c936
7 changed files with 64 additions and 16 deletions

View File

@@ -134,6 +134,13 @@ public:
/// \brief Remove all block arguments.
void dropAllArgs() { BBArgList.clear(); }
/// \brief Drops all uses that belong to this basic block.
void dropAllReferences() {
dropAllArgs();
for (SILInstruction &I : *this)
I.dropAllReferences();
}
//===--------------------------------------------------------------------===//
// Predecessors and Successors
//===--------------------------------------------------------------------===//

View File

@@ -124,6 +124,14 @@ public:
void incrementRefCount() { RefCount++; }
void decrementRefCount() { RefCount--; }
/// Drops all uses belonging to instructions in this function. The only valid
/// operation performable on this object after this is called is called the
/// destructor or deallocation.
void dropAllReferences() {
for (SILBasicBlock &BB : *this)
BB.dropAllReferences();
}
/// Returns the calling convention used by this entry point.
AbstractCC getAbstractCC() const {
return getLoweredFunctionType()->getAbstractCC();
@@ -281,7 +289,7 @@ public:
SILFunction *provideInitialHead() const { return createSentinel(); }
SILFunction *ensureHead(SILFunction*) const { return createSentinel(); }
static void noteHead(SILFunction*, SILFunction*) {}
static void deleteNode(SILFunction *V) {}
static void deleteNode(SILFunction *V) { V->~SILFunction(); }
private:
void createNode(const SILFunction &);

View File

@@ -597,6 +597,8 @@ public:
/// Return the referenced function.
SILFunction *getReferencedFunction() const { return Function; }
void dropReferencedFunction();
/// getType() is ok since this is known to only have one type.
SILType getType(unsigned i = 0) const { return ValueBase::getType(i); }

View File

@@ -98,15 +98,29 @@ private:
/// The swift Module associated with this SILModule.
Module *TheSwiftModule;
/// Lookup table for SIL functions. This needs to be declared before \p
/// functions so that the destructor of \p functions is called first.
llvm::StringMap<SILFunction *> FunctionTable;
/// The list of SILFunctions in the module.
FunctionListType functions;
/// Lookup table for SIL vtables from class decls.
llvm::DenseMap<const ClassDecl *, SILVTable *> VTableLookupTable;
/// The list of SILVTables in the module.
VTableListType vtables;
/// Lookup table for SIL witness tables from conformances.
llvm::DenseMap<const NormalProtocolConformance *, SILWitnessTable *>
WitnessTableLookupCache;
/// The list of SILWitnessTables in the module.
WitnessTableListType witnessTables;
/// Lookup table for SIL Global Variables.
llvm::StringMap<SILGlobalVariable *> GlobalVariableTable;
/// The list of SILGlobalVariables in the module.
/// FIXME: Merge with 'globals'.
GlobalListType silGlobals;
@@ -115,19 +129,6 @@ private:
/// FIXME: Remove this when SILGlobalVariable is ready.
llvm::SetVector<VarDecl*> globals;
/// Lookup table for SIL functions.
llvm::StringMap<SILFunction*> FunctionTable;
/// Lookup table for SIL global variables.
llvm::StringMap<SILGlobalVariable*> GlobalVariableTable;
/// Lookup table for SIL witness tables from conformances.
llvm::DenseMap<const NormalProtocolConformance *, SILWitnessTable *>
WitnessTableLookupCache;
/// Lookup table for SIL vtables from class decls.
llvm::DenseMap<const ClassDecl *, SILVTable *> VTableLookupTable;
/// This is a cache of intrinsic Function declarations to numeric ID mappings.
llvm::DenseMap<Identifier, IntrinsicInfo> IntrinsicIDCache;
@@ -181,7 +182,6 @@ public:
/// Erase a function from the module.
void eraseFunction(SILFunction *F) {
FunctionTable.erase(F->getName());
getFunctionList().erase(F);
}

View File

@@ -72,8 +72,15 @@ 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.
dropAllReferences();
assert(RefCount == 0 &&
"Function cannot be deleted while function_ref's still exist");
#endif
getModule().FunctionTable.erase(Name);
}

View File

@@ -114,6 +114,14 @@ void SILInstruction::dropAllReferences() {
OpE = PossiblyDeadOps.end(); OpI != OpE; ++OpI) {
OpI->drop();
}
// If we have a function ref inst, we need to especially drop its function
// argument so that it gets a proper ref decement.
auto *FRI = dyn_cast<FunctionRefInst>(this);
if (!FRI || !FRI->getReferencedFunction())
return;
FRI->dropReferencedFunction();
}
namespace {
@@ -624,9 +632,16 @@ FunctionRefInst::FunctionRefInst(SILLocation Loc, SILFunction *F)
}
FunctionRefInst::~FunctionRefInst() {
if (Function)
Function->decrementRefCount();
}
void FunctionRefInst::dropReferencedFunction() {
if (Function)
Function->decrementRefCount();
Function = nullptr;
}
SILGlobalAddrInst::SILGlobalAddrInst(SILLocation Loc, SILGlobalVariable *Global)
: LiteralInst(ValueKind::SILGlobalAddrInst, Loc,
Global->getLoweredType().getAddressType()),

View File

@@ -91,6 +91,15 @@ SILModule::SILModule(Module *SwiftModule)
}
SILModule::~SILModule() {
// Drop everything functions in this module reference.
//
// This is necessary since the functions may reference each other. We don't
// need to worry about sil_witness_tables since witness tables reference each
// other via protocol conformances and sil_vtables don't reference each other
// at all.
for (SILFunction &F : *this)
F.dropAllReferences();
delete (SILTypeListUniquingType*)TypeListUniquing;
}