diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-17 08:36:19 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-17 08:36:19 +0000 |
| commit | 6a3b31af5dbb22749e6d5a1cad9dfaab6863b615 (patch) | |
| tree | 58d2e7d956c8c605599a3f760040234ec2556d29 /lib/CodeGen/ExceptionHandler.cc | |
| parent | abd56ef20bc8061bbecec29edd1301d324c2cb34 (diff) | |
feat(classes): destroy stack objects during exception unwinding
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/ExceptionHandler.cc')
| -rw-r--r-- | lib/CodeGen/ExceptionHandler.cc | 46 |
1 files changed, 41 insertions, 5 deletions
diff --git a/lib/CodeGen/ExceptionHandler.cc b/lib/CodeGen/ExceptionHandler.cc index 21eb011..3f69417 100644 --- a/lib/CodeGen/ExceptionHandler.cc +++ b/lib/CodeGen/ExceptionHandler.cc @@ -1,6 +1,7 @@ #include "cps/ExceptionHandler.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" +#include "llvm/Support/SaveAndRestore.h" #include <cassert> using namespace llvm; @@ -72,15 +73,50 @@ void ExceptionHandler::endCatch() { if (!Builder.GetInsertBlock()->hasTerminator()) Builder.CreateCall(EndCatch); } -void ExceptionHandler::emitReturnCleanup() { +Instruction *ExceptionHandler::emitReturnCleanup() { auto &State = States[Builder.GetInsertBlock()->getParent()]; - for (unsigned I = 0; I < State.CatchDepth; ++I) Builder.CreateCall(EndCatch); + Instruction *First = nullptr; + for (unsigned I = 0; I < State.CatchDepth; ++I) { + auto *Call = Builder.CreateCall(EndCatch); + if (!First) First = Call; + } + return First; +} + +void ExceptionHandler::enableCleanups(Function *F) { + // Enable before emitting any call: a later DECLARE can already be alive + // when an earlier call executes again through a loop back edge. + States[F].HasCleanups = true; +} + +void ExceptionHandler::recordExit(Instruction *Before, bool Unwinding) { + auto *F = Before->getFunction(); + CleanupPoints[F].push_back({Before, States[F], Unwinding}); +} + +void ExceptionHandler::fillCleanups(Function *F, const std::function<void()> &Destroy) { + IRBuilderBase::InsertPointGuard Guard(Builder); + SaveAndRestore<FunctionState> StateGuard(States[F]); + auto &Points = CleanupPoints[F]; + // Filling a normal exit may add an unwind point for a throwing destructor. + for (size_t I = 0; I < Points.size(); ++I) { + auto Point = Points[I]; + States[F] = Point.State; + SaveAndRestore<bool> UnwindGuard(FillingUnwind, Point.Unwinding); + auto *BB = Point.Before->getParent(); + auto *Continuation = BB->splitBasicBlock(Point.Before->getIterator(), "after_destruction"); + BB->getTerminator()->eraseFromParent(); + Builder.SetInsertPoint(BB); + Destroy(); + Builder.CreateBr(Continuation); + } + Points.clear(); } BasicBlock *ExceptionHandler::emitUnwindDestination() { auto *F = Builder.GetInsertBlock()->getParent(); auto &State = States[F]; - if (State.Handlers.empty() && State.CatchDepth == 0) return nullptr; + if (FillingUnwind || (State.Handlers.empty() && State.CatchDepth == 0 && !State.HasCleanups)) return nullptr; ensureRuntime(); F->setPersonalityFn(cast<Constant>(Personality.getCallee())); auto Saved = Builder.saveIP(); @@ -91,7 +127,7 @@ BasicBlock *ExceptionHandler::emitUnwindDestination() { const Handler *Handler = State.Handlers.empty() ? nullptr : &State.Handlers.back(); unsigned TargetDepth = Handler ? Handler->CatchDepth : 0; if (Handler) LP->addClause(ConstantPointerNull::get(PointerType::getUnqual(Context))); - if (State.CatchDepth > TargetDepth) LP->setCleanup(true); + if (!Handler || State.CatchDepth > TargetDepth) LP->setCleanup(true); // Finish catches we are leaving before entering the outer handler (or // resuming propagation through a function with no local handler). for (unsigned I = TargetDepth; I < State.CatchDepth; ++I) Builder.CreateCall(EndCatch); @@ -99,7 +135,7 @@ BasicBlock *ExceptionHandler::emitUnwindDestination() { Builder.CreateStore(Builder.CreateExtractValue(LP, 0), Handler->Exception); Builder.CreateBr(Handler->Target); } else { - Builder.CreateResume(LP); + recordExit(Builder.CreateResume(LP), true); } Builder.restoreIP(Saved); return Unwind; |
