Skip to content

Commit 06130ed

Browse files
authored
Reapply "[clang][bytecode] Stack-allocate bottom function frame" (rust-lang#12… (llvm#125349)
…5325) Move the BottomFrame to InterpState instead.
1 parent 2791843 commit 06130ed

File tree

7 files changed

+46
-21
lines changed

7 files changed

+46
-21
lines changed

clang/lib/AST/ByteCode/Context.cpp

+1-4
Original file line numberDiff line numberDiff line change
@@ -212,14 +212,11 @@ const llvm::fltSemantics &Context::getFloatSemantics(QualType T) const {
212212
bool Context::Run(State &Parent, const Function *Func) {
213213

214214
{
215-
InterpState State(Parent, *P, Stk, *this);
216-
State.Current = new InterpFrame(State, Func, /*Caller=*/nullptr, CodePtr(),
217-
Func->getArgSize());
215+
InterpState State(Parent, *P, Stk, *this, Func);
218216
if (Interpret(State)) {
219217
assert(Stk.empty());
220218
return true;
221219
}
222-
223220
// State gets destroyed here, so the Stk.clear() below doesn't accidentally
224221
// remove values the State's destructor might access.
225222
}

clang/lib/AST/ByteCode/EvalEmitter.cpp

+1-5
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@ using namespace clang::interp;
1717

1818
EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent,
1919
InterpStack &Stk)
20-
: Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) {
21-
// Create a dummy frame for the interpreter which does not have locals.
22-
S.Current =
23-
new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr(), 0);
24-
}
20+
: Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) {}
2521

2622
EvalEmitter::~EvalEmitter() {
2723
for (auto &[K, V] : Locals) {

clang/lib/AST/ByteCode/Interp.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -325,11 +325,11 @@ bool Ret(InterpState &S, CodePtr &PC) {
325325

326326
if (InterpFrame *Caller = S.Current->Caller) {
327327
PC = S.Current->getRetPC();
328-
delete S.Current;
328+
InterpFrame::free(S.Current);
329329
S.Current = Caller;
330330
S.Stk.push<T>(Ret);
331331
} else {
332-
delete S.Current;
332+
InterpFrame::free(S.Current);
333333
S.Current = nullptr;
334334
// The topmost frame should come from an EvalEmitter,
335335
// which has its own implementation of the Ret<> instruction.
@@ -345,10 +345,10 @@ inline bool RetVoid(InterpState &S, CodePtr &PC) {
345345

346346
if (InterpFrame *Caller = S.Current->Caller) {
347347
PC = S.Current->getRetPC();
348-
delete S.Current;
348+
InterpFrame::free(S.Current);
349349
S.Current = Caller;
350350
} else {
351-
delete S.Current;
351+
InterpFrame::free(S.Current);
352352
S.Current = nullptr;
353353
}
354354
return true;

clang/lib/AST/ByteCode/InterpFrame.cpp

+14-6
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,15 @@
2323
using namespace clang;
2424
using namespace clang::interp;
2525

26+
InterpFrame::InterpFrame(InterpState &S)
27+
: Caller(nullptr), S(S), Depth(0), Func(nullptr), RetPC(CodePtr()),
28+
ArgSize(0), Args(nullptr), FrameOffset(0), IsBottom(true) {}
29+
2630
InterpFrame::InterpFrame(InterpState &S, const Function *Func,
2731
InterpFrame *Caller, CodePtr RetPC, unsigned ArgSize)
2832
: Caller(Caller), S(S), Depth(Caller ? Caller->Depth + 1 : 0), Func(Func),
2933
RetPC(RetPC), ArgSize(ArgSize), Args(static_cast<char *>(S.Stk.top())),
30-
FrameOffset(S.Stk.size()) {
34+
FrameOffset(S.Stk.size()), IsBottom(!Caller) {
3135
if (!Func)
3236
return;
3337

@@ -73,11 +77,15 @@ InterpFrame::~InterpFrame() {
7377
// When destroying the InterpFrame, call the Dtor for all block
7478
// that haven't been destroyed via a destroy() op yet.
7579
// This happens when the execution is interruped midway-through.
76-
if (Func) {
77-
for (auto &Scope : Func->scopes()) {
78-
for (auto &Local : Scope.locals()) {
79-
S.deallocate(localBlock(Local.Offset));
80-
}
80+
destroyScopes();
81+
}
82+
83+
void InterpFrame::destroyScopes() {
84+
if (!Func)
85+
return;
86+
for (auto &Scope : Func->scopes()) {
87+
for (auto &Local : Scope.locals()) {
88+
S.deallocate(localBlock(Local.Offset));
8189
}
8290
}
8391
}

clang/lib/AST/ByteCode/InterpFrame.h

+12
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ class InterpFrame final : public Frame {
2828
/// The frame of the previous function.
2929
InterpFrame *Caller;
3030

31+
/// Bottom Frame.
32+
InterpFrame(InterpState &S);
33+
3134
/// Creates a new frame for a method call.
3235
InterpFrame(InterpState &S, const Function *Func, InterpFrame *Caller,
3336
CodePtr RetPC, unsigned ArgSize);
@@ -42,9 +45,15 @@ class InterpFrame final : public Frame {
4245
/// Destroys the frame, killing all live pointers to stack slots.
4346
~InterpFrame();
4447

48+
static void free(InterpFrame *F) {
49+
if (!F->isBottomFrame())
50+
delete F;
51+
}
52+
4553
/// Invokes the destructors for a scope.
4654
void destroy(unsigned Idx);
4755
void initScope(unsigned Idx);
56+
void destroyScopes();
4857

4958
/// Describes the frame with arguments for diagnostic purposes.
5059
void describe(llvm::raw_ostream &OS) const override;
@@ -119,6 +128,8 @@ class InterpFrame final : public Frame {
119128

120129
bool isStdFunction() const;
121130

131+
bool isBottomFrame() const { return IsBottom; }
132+
122133
void dump() const { dump(llvm::errs(), 0); }
123134
void dump(llvm::raw_ostream &OS, unsigned Indent = 0) const;
124135

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

172184
} // namespace interp

clang/lib/AST/ByteCode/InterpState.cpp

+10-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,14 @@ using namespace clang::interp;
1717

1818
InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
1919
Context &Ctx, SourceMapper *M)
20-
: Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), Current(nullptr) {}
20+
: Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), BottomFrame(*this),
21+
Current(&BottomFrame) {}
22+
23+
InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
24+
Context &Ctx, const Function *Func)
25+
: Parent(Parent), M(nullptr), P(P), Stk(Stk), Ctx(Ctx),
26+
BottomFrame(*this, Func, nullptr, CodePtr(), Func->getArgSize()),
27+
Current(&BottomFrame) {}
2128

2229
bool InterpState::inConstantContext() const {
2330
if (ConstantContextOverride)
@@ -27,11 +34,12 @@ bool InterpState::inConstantContext() const {
2734
}
2835

2936
InterpState::~InterpState() {
30-
while (Current) {
37+
while (Current && !Current->isBottomFrame()) {
3138
InterpFrame *Next = Current->Caller;
3239
delete Current;
3340
Current = Next;
3441
}
42+
BottomFrame.destroyScopes();
3543

3644
while (DeadBlocks) {
3745
DeadBlock *Next = DeadBlocks->Next;

clang/lib/AST/ByteCode/InterpState.h

+4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class InterpState final : public State, public SourceMapper {
3737
public:
3838
InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
3939
SourceMapper *M = nullptr);
40+
InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
41+
const Function *Func);
4042

4143
~InterpState();
4244

@@ -134,6 +136,8 @@ class InterpState final : public State, public SourceMapper {
134136
InterpStack &Stk;
135137
/// Interpreter Context.
136138
Context &Ctx;
139+
/// Bottom function frame.
140+
InterpFrame BottomFrame;
137141
/// The current frame.
138142
InterpFrame *Current = nullptr;
139143
/// Source location of the evaluating expression

0 commit comments

Comments
 (0)