diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index 9763fe89b7374..3f64aea4183f6 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -17,10 +17,9 @@ using namespace clang::interp; EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk) - : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) { - // Create a dummy frame for the interpreter which does not have locals. - S.Current = - new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr(), 0); + : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx), + BottomFrame(S) { + S.Current = &BottomFrame; } EvalEmitter::~EvalEmitter() { diff --git a/clang/lib/AST/ByteCode/EvalEmitter.h b/clang/lib/AST/ByteCode/EvalEmitter.h index e7c9e80d75d93..0b58b100f85fa 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.h +++ b/clang/lib/AST/ByteCode/EvalEmitter.h @@ -125,6 +125,8 @@ class EvalEmitter : public SourceMapper { /// Active block which should be executed. LabelTy ActiveLabel = 0; + InterpFrame BottomFrame; + protected: #define GET_EVAL_PROTO #include "Opcodes.inc" diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 063970afec9e3..91a82a25944fb 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -325,11 +325,11 @@ bool Ret(InterpState &S, CodePtr &PC) { if (InterpFrame *Caller = S.Current->Caller) { PC = S.Current->getRetPC(); - delete S.Current; + InterpFrame::free(S.Current); S.Current = Caller; S.Stk.push(Ret); } else { - delete S.Current; + InterpFrame::free(S.Current); S.Current = nullptr; // The topmost frame should come from an EvalEmitter, // which has its own implementation of the Ret<> instruction. diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp index 20f67d9b1fd42..cfcc9dc80d535 100644 --- a/clang/lib/AST/ByteCode/InterpFrame.cpp +++ b/clang/lib/AST/ByteCode/InterpFrame.cpp @@ -23,6 +23,10 @@ using namespace clang; using namespace clang::interp; +InterpFrame::InterpFrame(InterpState &S) + : Caller(nullptr), S(S), Depth(0), Func(nullptr), RetPC(CodePtr()), + ArgSize(0), Args(nullptr), FrameOffset(0), IsBottom(true) {} + InterpFrame::InterpFrame(InterpState &S, const Function *Func, InterpFrame *Caller, CodePtr RetPC, unsigned ArgSize) : Caller(Caller), S(S), Depth(Caller ? Caller->Depth + 1 : 0), Func(Func), diff --git a/clang/lib/AST/ByteCode/InterpFrame.h b/clang/lib/AST/ByteCode/InterpFrame.h index 7cfc3ac68b4f3..8cabb9cd06fac 100644 --- a/clang/lib/AST/ByteCode/InterpFrame.h +++ b/clang/lib/AST/ByteCode/InterpFrame.h @@ -28,6 +28,9 @@ class InterpFrame final : public Frame { /// The frame of the previous function. InterpFrame *Caller; + /// Bottom Frame. + InterpFrame(InterpState &S); + /// Creates a new frame for a method call. InterpFrame(InterpState &S, const Function *Func, InterpFrame *Caller, CodePtr RetPC, unsigned ArgSize); @@ -42,6 +45,11 @@ class InterpFrame final : public Frame { /// Destroys the frame, killing all live pointers to stack slots. ~InterpFrame(); + static void free(InterpFrame *F) { + if (!F->isBottomFrame()) + delete F; + } + /// Invokes the destructors for a scope. void destroy(unsigned Idx); void initScope(unsigned Idx); @@ -119,6 +127,8 @@ class InterpFrame final : public Frame { bool isStdFunction() const; + bool isBottomFrame() const { return IsBottom; } + void dump() const { dump(llvm::errs(), 0); } void dump(llvm::raw_ostream &OS, unsigned Indent = 0) const; @@ -167,6 +177,7 @@ class InterpFrame final : public Frame { const size_t FrameOffset; /// Mapping from arg offsets to their argument blocks. llvm::DenseMap> Params; + bool IsBottom = false; }; } // namespace interp diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp index 287c3bd3bca3a..8aa44e48842e9 100644 --- a/clang/lib/AST/ByteCode/InterpState.cpp +++ b/clang/lib/AST/ByteCode/InterpState.cpp @@ -27,7 +27,7 @@ bool InterpState::inConstantContext() const { } InterpState::~InterpState() { - while (Current) { + while (Current && !Current->isBottomFrame()) { InterpFrame *Next = Current->Caller; delete Current; Current = Next;