Skip to content

Commit

Permalink
Reapply "[clang][bytecode] Stack-allocate bottom function frame" (#12… (
Browse files Browse the repository at this point in the history
llvm#125349)

…5325)

Move the BottomFrame to InterpState instead.
  • Loading branch information
tbaederr authored Feb 1, 2025
1 parent 2791843 commit 06130ed
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 21 deletions.
5 changes: 1 addition & 4 deletions clang/lib/AST/ByteCode/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,14 +212,11 @@ const llvm::fltSemantics &Context::getFloatSemantics(QualType T) const {
bool Context::Run(State &Parent, const Function *Func) {

{
InterpState State(Parent, *P, Stk, *this);
State.Current = new InterpFrame(State, Func, /*Caller=*/nullptr, CodePtr(),
Func->getArgSize());
InterpState State(Parent, *P, Stk, *this, Func);
if (Interpret(State)) {
assert(Stk.empty());
return true;
}

// State gets destroyed here, so the Stk.clear() below doesn't accidentally
// remove values the State's destructor might access.
}
Expand Down
6 changes: 1 addition & 5 deletions clang/lib/AST/ByteCode/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ 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) {}

EvalEmitter::~EvalEmitter() {
for (auto &[K, V] : Locals) {
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(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.
Expand All @@ -345,10 +345,10 @@ inline bool RetVoid(InterpState &S, CodePtr &PC) {

if (InterpFrame *Caller = S.Current->Caller) {
PC = S.Current->getRetPC();
delete S.Current;
InterpFrame::free(S.Current);
S.Current = Caller;
} else {
delete S.Current;
InterpFrame::free(S.Current);
S.Current = nullptr;
}
return true;
Expand Down
20 changes: 14 additions & 6 deletions clang/lib/AST/ByteCode/InterpFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@
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),
RetPC(RetPC), ArgSize(ArgSize), Args(static_cast<char *>(S.Stk.top())),
FrameOffset(S.Stk.size()) {
FrameOffset(S.Stk.size()), IsBottom(!Caller) {
if (!Func)
return;

Expand Down Expand Up @@ -73,11 +77,15 @@ InterpFrame::~InterpFrame() {
// When destroying the InterpFrame, call the Dtor for all block
// that haven't been destroyed via a destroy() op yet.
// This happens when the execution is interruped midway-through.
if (Func) {
for (auto &Scope : Func->scopes()) {
for (auto &Local : Scope.locals()) {
S.deallocate(localBlock(Local.Offset));
}
destroyScopes();
}

void InterpFrame::destroyScopes() {
if (!Func)
return;
for (auto &Scope : Func->scopes()) {
for (auto &Local : Scope.locals()) {
S.deallocate(localBlock(Local.Offset));
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/AST/ByteCode/InterpFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -42,9 +45,15 @@ 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);
void destroyScopes();

/// Describes the frame with arguments for diagnostic purposes.
void describe(llvm::raw_ostream &OS) const override;
Expand Down Expand Up @@ -119,6 +128,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;

Expand Down Expand Up @@ -167,6 +178,7 @@ class InterpFrame final : public Frame {
const size_t FrameOffset;
/// Mapping from arg offsets to their argument blocks.
llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Params;
bool IsBottom = false;
};

} // namespace interp
Expand Down
12 changes: 10 additions & 2 deletions clang/lib/AST/ByteCode/InterpState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@ using namespace clang::interp;

InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
Context &Ctx, SourceMapper *M)
: Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), Current(nullptr) {}
: Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), BottomFrame(*this),
Current(&BottomFrame) {}

InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
Context &Ctx, const Function *Func)
: Parent(Parent), M(nullptr), P(P), Stk(Stk), Ctx(Ctx),
BottomFrame(*this, Func, nullptr, CodePtr(), Func->getArgSize()),
Current(&BottomFrame) {}

bool InterpState::inConstantContext() const {
if (ConstantContextOverride)
Expand All @@ -27,11 +34,12 @@ bool InterpState::inConstantContext() const {
}

InterpState::~InterpState() {
while (Current) {
while (Current && !Current->isBottomFrame()) {
InterpFrame *Next = Current->Caller;
delete Current;
Current = Next;
}
BottomFrame.destroyScopes();

while (DeadBlocks) {
DeadBlock *Next = DeadBlocks->Next;
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/ByteCode/InterpState.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class InterpState final : public State, public SourceMapper {
public:
InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
SourceMapper *M = nullptr);
InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
const Function *Func);

~InterpState();

Expand Down Expand Up @@ -134,6 +136,8 @@ class InterpState final : public State, public SourceMapper {
InterpStack &Stk;
/// Interpreter Context.
Context &Ctx;
/// Bottom function frame.
InterpFrame BottomFrame;
/// The current frame.
InterpFrame *Current = nullptr;
/// Source location of the evaluating expression
Expand Down

0 comments on commit 06130ed

Please sign in to comment.