diff --git a/gen/irstate.h b/gen/irstate.h index 767849097f..93438b0549 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -21,7 +21,6 @@ #include "ir/iraggr.h" #include "ir/irvar.h" #include "gen/dibuilder.h" -#include "gen/llvmhelpers.h" #include #include #include @@ -214,11 +213,11 @@ llvm::CallSite IRState::CreateCallOrInvoke(LLValue* Callee, const T &args, const FuncGen& funcGen = *func()->gen; LLFunction* fn = llvm::dyn_cast(Callee); - const bool haveTemporaries = haveTemporariesToDestruct(); + const bool hasTemporaries = funcGen.hasTemporariesToDestruct(); // intrinsics don't support invoking and 'nounwind' functions don't need it. const bool doesNotThrow = (fn && (fn->isIntrinsic() || fn->doesNotThrow())); - if (doesNotThrow || (!haveTemporaries && funcGen.landingPad == NULL)) + if (doesNotThrow || (!hasTemporaries && funcGen.landingPad == NULL)) { llvm::CallInst* call = ir->CreateCall(Callee, args, Name); if (fn) @@ -226,16 +225,16 @@ llvm::CallSite IRState::CreateCallOrInvoke(LLValue* Callee, const T &args, const return call; } - if (haveTemporaries) - prepareToDestructAllTemporariesOnThrow(); + if (hasTemporaries) + funcGen.prepareToDestructAllTemporariesOnThrow(this); llvm::BasicBlock* oldend = scopeend(); - llvm::BasicBlock* postinvoke = llvm::BasicBlock::Create(gIR->context(), "postinvoke", topfunc(), oldend); + llvm::BasicBlock* postinvoke = llvm::BasicBlock::Create(context(), "postinvoke", topfunc(), oldend); llvm::InvokeInst* invoke = ir->CreateInvoke(Callee, postinvoke, funcGen.landingPad, args, Name); if (fn) invoke->setAttributes(fn->getAttributes()); - if (haveTemporaries) + if (hasTemporaries) funcGen.landingPadInfo.pop(); scope() = IRScope(postinvoke, oldend); diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index 266a75acee..c0dfdab2de 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -239,7 +239,4 @@ DValue *toElem(Expression *e, bool tryGetLvalue); DValue *toElemDtor(Expression *e); LLConstant *toConstElem(Expression *e, IRState *p); -bool haveTemporariesToDestruct(); -void prepareToDestructAllTemporariesOnThrow(); - #endif diff --git a/gen/toir.cpp b/gen/toir.cpp index 45e565ee14..26827457f2 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -265,67 +265,16 @@ DValue* toElem(Expression* e, bool tryGetLvalue) class ToElemVisitor : public Visitor { - // stack of declared temporaries which have yet to be destructed - // static because toElem() calls are re-entrant - static VarDeclarations temporariesWithDtor; - static Array visitors; - IRState *p; DValue *result; - //DValue *lvalue; - - ////////////////////////////////////////////////////////////////////////////////////////// - - static void destructTemporaries(int numToKeep) - { - if (temporariesWithDtor.empty()) - return; - - // pop one temporary after the other from the temporariesWithDtor stack - // and evaluate its destructor expression - // so when an exception occurs in a destructor expression, all older - // temporaries (excl. the one which threw in its destructor) will be - // destructed in a landing pad - for (int i = temporariesWithDtor.size() - 1; i >= numToKeep; --i) - { - VarDeclaration* vd = temporariesWithDtor.pop(); - toElem(vd->edtor); - } - } - - ////////////////////////////////////////////////////////////////////////////////////////// - public: - ToElemVisitor(IRState *p_) : p(p_), result(NULL) - { - visitors.push(this); - } - - ~ToElemVisitor() - { - if (visitors.size() == 1) // outer-most toElem() call only - destructTemporaries(0); - visitors.pop(); - } + ToElemVisitor(IRState *p_) : p(p_), result(NULL) { p->func()->gen->pushToElemScope(); } + ~ToElemVisitor() { p->func()->gen->popToElemScope(); } DValue *getResult() { return result; } ////////////////////////////////////////////////////////////////////////////////////////// - static bool hasTemporariesToDestruct() { return !temporariesWithDtor.empty(); } - - static void destructAllTemporariesAndRestoreStack() - { - if (temporariesWithDtor.empty()) - return; - - VarDeclarations original = temporariesWithDtor; - destructTemporaries(0); - temporariesWithDtor = original; - } - - ////////////////////////////////////////////////////////////////////////////////////////// - // Import all functions from class Visitor using Visitor::visit; @@ -345,7 +294,7 @@ public: { VarDeclaration* vd = varValue->var; if (!vd->isDataseg() && vd->edtor && !vd->noscope) - temporariesWithDtor.push(vd); + p->func()->gen->pushTemporaryToDestruct(vd); } } } @@ -3183,9 +3132,6 @@ public: STUB(PowAssignExp) }; -VarDeclarations ToElemVisitor::temporariesWithDtor; -Array ToElemVisitor::visitors; - ////////////////////////////////////////////////////////////////////////////////////////////// DValue *toElem(Expression *e) @@ -3200,37 +3146,6 @@ DValue *toElemDtor(Expression *e) return toElem(e); } -bool haveTemporariesToDestruct() -{ - return ToElemVisitor::hasTemporariesToDestruct(); -} - -void prepareToDestructAllTemporariesOnThrow() -{ - if (!haveTemporariesToDestruct()) - return; - - class CallDestructors : public IRLandingPadCatchFinallyInfo - { - public: - void toIR(LLValue* /*eh_ptr*/ = NULL) - { - ToElemVisitor::destructAllTemporariesAndRestoreStack(); - } - }; - - CallDestructors* callDestructors = new CallDestructors(); // leaks - - // create landing pad - llvm::BasicBlock* landingpadbb = llvm::BasicBlock::Create(gIR->context(), - "temporariesLandingPad", gIR->topfunc(), gIR->scopeend()); - - // set up the landing pad - IRLandingPad& pad = gIR->func()->gen->landingPadInfo; - pad.addFinally(callDestructors); - pad.push(landingpadbb); -} - // FIXME: Implement & place in right module Symbol *toModuleAssert(Module *m) { diff --git a/ir/irfunction.cpp b/ir/irfunction.cpp index c16c7e3534..4774e6608b 100644 --- a/ir/irfunction.cpp +++ b/ir/irfunction.cpp @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include "gen/llvm.h" +#include "gen/llvmhelpers.h" +#include "gen/irstate.h" #include "gen/tollvm.h" #include "ir/irdsymbol.h" #include "ir/irfunction.h" @@ -17,6 +19,7 @@ FuncGen::FuncGen() { landingPad = NULL; nextUnique.push(0); + toElemScopeCounter = 0; } std::string FuncGen::getScopedLabelName(const char* ident) @@ -44,6 +47,64 @@ void FuncGen::popLabelScope() nextUnique.pop(); } +void FuncGen::pushToElemScope() { ++toElemScopeCounter; } +void FuncGen::popToElemScope() +{ + assert(toElemScopeCounter > 0); + if (toElemScopeCounter == 1) // popping outer-most toElem() scope? + destructAllTemporaries(); + --toElemScopeCounter; +} + +void FuncGen::pushTemporaryToDestruct(VarDeclaration* vd) { temporariesToDestruct.push(vd); } +bool FuncGen::hasTemporariesToDestruct() { return !temporariesToDestruct.empty(); } + +void FuncGen::destructAllTemporaries() +{ + // pop one temporary after the other from the temporariesToDestruct stack + // and evaluate its destructor expression + // so when an exception occurs in a destructor expression, all older + // temporaries (excl. the one which threw in its destructor) will be + // destructed in a landing pad + while (!temporariesToDestruct.empty()) + { + VarDeclaration* vd = temporariesToDestruct.pop(); + toElem(vd->edtor); + } +} + +void FuncGen::destructAllTemporariesAndRestoreStack() +{ + VarDeclarations original = temporariesToDestruct; + destructAllTemporaries(); + temporariesToDestruct = original; +} + +void FuncGen::prepareToDestructAllTemporariesOnThrow(IRState* irState) +{ + class CallDestructors : public IRLandingPadCatchFinallyInfo + { + public: + FuncGen& funcGen; + CallDestructors(FuncGen& funcGen) : funcGen(funcGen) {} + void toIR(LLValue*) + { + funcGen.destructAllTemporariesAndRestoreStack(); + } + }; + + CallDestructors* callDestructors = new CallDestructors(*this); // will leak + + // create landing pad + llvm::BasicBlock* landingpadbb = llvm::BasicBlock::Create(irState->context(), + "temporariesLandingPad", irState->topfunc(), irState->scopeend()); + + // set up the landing pad + landingPadInfo.addFinally(callDestructors); + landingPadInfo.push(landingpadbb); +} + + IrFunction::IrFunction(FuncDeclaration* fd) { decl = fd; diff --git a/ir/irfunction.h b/ir/irfunction.h index a36e6bea38..7d4025d5a0 100644 --- a/ir/irfunction.h +++ b/ir/irfunction.h @@ -27,6 +27,7 @@ class Statement; struct EnclosingTryFinally; +struct IRState; // scope statements that can be target of jumps // includes loops, switch, case, labels @@ -81,6 +82,17 @@ struct FuncGen IRLandingPad landingPadInfo; llvm::BasicBlock* landingPad; + void pushToElemScope(); + void popToElemScope(); + + void pushTemporaryToDestruct(VarDeclaration* vd); + bool hasTemporariesToDestruct(); + void destructAllTemporaries(); + void destructAllTemporariesAndRestoreStack(); + // pushes a landing pad which needs to be popped after the + // following invoke instruction + void prepareToDestructAllTemporariesOnThrow(IRState* irState); + private: // prefix for labels and gotos // used for allowing labels to be emitted twice @@ -88,6 +100,9 @@ private: // next unique id stack std::stack nextUnique; + + int toElemScopeCounter; + VarDeclarations temporariesToDestruct; }; // represents a function