Author: Timm Baeder
Date: 2026-03-20T10:11:21+01:00
New Revision: 78f267f01d93d8083be26c10a070d2d309ac3ecb

URL: 
https://github.com/llvm/llvm-project/commit/78f267f01d93d8083be26c10a070d2d309ac3ecb
DIFF: 
https://github.com/llvm/llvm-project/commit/78f267f01d93d8083be26c10a070d2d309ac3ecb.diff

LOG: Reapply "[clang][bytecode] Allocate local variables in `InterpFrame` … 
(#187644)

…tail storage" (#187410)

This reverts commit bf1db77fc87ce9d2ca7744565321b09a5d23692f.

Avoid using an `InterpFrame` member after calling its destructor this
time. I hope that was the only problem.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
    clang/lib/AST/ByteCode/ByteCodeEmitter.h
    clang/lib/AST/ByteCode/Compiler.cpp
    clang/lib/AST/ByteCode/Context.cpp
    clang/lib/AST/ByteCode/Context.h
    clang/lib/AST/ByteCode/DynamicAllocator.cpp
    clang/lib/AST/ByteCode/EvalEmitter.h
    clang/lib/AST/ByteCode/Function.cpp
    clang/lib/AST/ByteCode/Function.h
    clang/lib/AST/ByteCode/Interp.cpp
    clang/lib/AST/ByteCode/Interp.h
    clang/lib/AST/ByteCode/InterpBlock.cpp
    clang/lib/AST/ByteCode/InterpBlock.h
    clang/lib/AST/ByteCode/InterpFrame.cpp
    clang/lib/AST/ByteCode/InterpFrame.h
    clang/lib/AST/ByteCode/InterpState.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp 
b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
index 35821085ff49b..c08ccf69aef85 100644
--- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
+++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
@@ -55,18 +55,13 @@ void ByteCodeEmitter::compileFunc(const FunctionDecl 
*FuncDecl,
   }
 
   bool IsValid = !FuncDecl->isInvalidDecl();
-  // Register parameters with their offset.
-  unsigned ParamIndex = 0;
-  unsigned Drop = Func->hasRVO() +
-                  (Func->hasThisPointer() && !Func->isThisPointerExplicit());
-
-  for (const auto &ParamDesc : llvm::drop_begin(Func->ParamDescriptors, Drop)) 
{
+  // Register parameters and their index.
+  for (unsigned ParamIndex = 0, N = Func->getNumWrittenParams();
+       ParamIndex != N; ++ParamIndex) {
     const ParmVarDecl *PD = FuncDecl->getParamDecl(ParamIndex);
     if (PD->isInvalidDecl())
       IsValid = false;
-    this->Params.insert(
-        {PD, {ParamDesc.Offset, Ctx.canClassify(PD->getType())}});
-    ++ParamIndex;
+    this->Params.insert({PD, {ParamIndex, Ctx.canClassify(PD->getType())}});
   }
 
   Func->setDefined(true);

diff  --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.h 
b/clang/lib/AST/ByteCode/ByteCodeEmitter.h
index dd18341d52a09..873edeea71d96 100644
--- a/clang/lib/AST/ByteCode/ByteCodeEmitter.h
+++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.h
@@ -67,7 +67,7 @@ class ByteCodeEmitter {
   Local createLocal(Descriptor *D);
 
   /// Parameter indices.
-  llvm::DenseMap<const ParmVarDecl *, ParamOffset> Params;
+  llvm::DenseMap<const ParmVarDecl *, FuncParam> Params;
   /// Lambda captures.
   llvm::DenseMap<const ValueDecl *, ParamOffset> LambdaCaptures;
   /// Offset of the This parameter in a lambda record.

diff  --git a/clang/lib/AST/ByteCode/Compiler.cpp 
b/clang/lib/AST/ByteCode/Compiler.cpp
index fc2da6362d0bb..a881d77a73cbd 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -240,7 +240,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
             return this->emitGetLocal(*SubExprT, It->second.Offset, E);
           } else if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) {
             if (auto It = this->Params.find(PVD); It != this->Params.end()) {
-              return this->emitGetParam(*SubExprT, It->second.Offset, E);
+              return this->emitGetParam(*SubExprT, It->second.Index, E);
             }
           }
         }
@@ -3852,13 +3852,13 @@ bool Compiler<Emitter>::VisitCXXInheritedCtorInitExpr(
   // This is necessary because the calling code has pushed the pointer
   // of the correct base for  us already, but the arguments need
   // to come after.
-  unsigned Offset = align(primSize(PT_Ptr)); // instance pointer.
+  unsigned ParamIndex = 0;
   for (const ParmVarDecl *PD : Ctor->parameters()) {
     PrimType PT = this->classify(PD->getType()).value_or(PT_Ptr);
 
-    if (!this->emitGetParam(PT, Offset, E))
+    if (!this->emitGetParam(PT, ParamIndex, E))
       return false;
-    Offset += align(primSize(PT));
+    ++ParamIndex;
   }
 
   return this->emitCall(F, 0, E);
@@ -6605,7 +6605,7 @@ bool Compiler<Emitter>::emitLambdaStaticInvokerBody(const 
CXXMethodDecl *MD) {
     // We do the lvalue-to-rvalue conversion manually here, so no need
     // to care about references.
     PrimType ParamType = this->classify(PVD->getType()).value_or(PT_Ptr);
-    if (!this->emitGetParam(ParamType, It->second.Offset, MD))
+    if (!this->emitGetParam(ParamType, It->second.Index, MD))
       return false;
   }
 
@@ -6702,10 +6702,7 @@ bool Compiler<Emitter>::compileConstructor(const 
CXXConstructorDecl *Ctor) {
     if (!this->emitThis(Ctor))
       return false;
 
-    const ParmVarDecl *PVD = Ctor->getParamDecl(0);
-    ParamOffset PO = this->Params[PVD]; // Must exist.
-
-    if (!this->emitGetParam(PT_Ptr, PO.Offset, Ctor))
+    if (!this->emitGetParam(PT_Ptr, /*ParamIndex=*/0, Ctor))
       return false;
 
     return this->emitMemcpy(Ctor) && this->emitPopPtr(Ctor) &&
@@ -6878,10 +6875,7 @@ bool Compiler<Emitter>::compileUnionAssignmentOperator(
   if (!this->emitThis(MD))
     return false;
 
-  const ParmVarDecl *PVD = MD->getParamDecl(0);
-  ParamOffset PO = this->Params[PVD]; // Must exist.
-
-  if (!this->emitGetParam(PT_Ptr, PO.Offset, MD))
+  if (!this->emitGetParam(PT_Ptr, /*ParamIndex=*/0, MD))
     return false;
 
   return this->emitMemcpy(MD) && this->emitRet(PT_Ptr, MD);
@@ -7453,9 +7447,9 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, 
const Expr *E) {
     }
     if (auto It = this->Params.find(PVD); It != this->Params.end()) {
       if (IsReference || !It->second.IsPtr)
-        return this->emitGetParam(classifyPrim(E), It->second.Offset, E);
+        return this->emitGetParam(classifyPrim(E), It->second.Index, E);
 
-      return this->emitGetPtrParam(It->second.Offset, E);
+      return this->emitGetPtrParam(It->second.Index, E);
     }
 
     if (!Ctx.getLangOpts().CPlusPlus23 && IsReference)

diff  --git a/clang/lib/AST/ByteCode/Context.cpp 
b/clang/lib/AST/ByteCode/Context.cpp
index 7d4534a5da5c6..2b32161fceba0 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -498,11 +498,19 @@ const llvm::fltSemantics 
&Context::getFloatSemantics(QualType T) const {
 
 bool Context::Run(State &Parent, const Function *Func) {
   InterpState State(Parent, *P, Stk, *this, Func);
+  auto Memory = std::make_unique<char[]>(InterpFrame::allocSize(Func));
+  InterpFrame *Frame = new (Memory.get()) InterpFrame(
+      State, Func, /*Caller=*/nullptr, CodePtr(), Func->getArgSize());
+  State.Current = Frame;
+
   if (Interpret(State)) {
     assert(Stk.empty());
     return true;
   }
+
   Stk.clear();
+  Frame->~InterpFrame();
+  State.Current = &State.BottomFrame;
   return false;
 }
 
@@ -575,7 +583,6 @@ const Function *Context::getOrCreateFunction(const 
FunctionDecl *FuncDecl) {
   bool HasRVO = false;
   if (!Ty->isVoidType() && !canClassify(Ty)) {
     HasRVO = true;
-    ParamDescriptors.emplace_back(nullptr, ParamOffset, PT_Ptr);
     ParamOffset += align(primSize(PT_Ptr));
   }
 
@@ -586,10 +593,8 @@ const Function *Context::getOrCreateFunction(const 
FunctionDecl *FuncDecl) {
   if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) {
     if (!IsLambdaStaticInvoker) {
       HasThisPointer = MD->isInstance();
-      if (MD->isImplicitObjectMemberFunction()) {
-        ParamDescriptors.emplace_back(nullptr, ParamOffset, PT_Ptr);
+      if (MD->isImplicitObjectMemberFunction())
         ParamOffset += align(primSize(PT_Ptr));
-      }
     }
 
     if (isLambdaCallOperator(MD)) {
@@ -613,6 +618,7 @@ const Function *Context::getOrCreateFunction(const 
FunctionDecl *FuncDecl) {
   // Assign descriptors to all parameters.
   // Composite objects are lowered to pointers.
   const auto *FuncProto = FuncDecl->getType()->getAs<FunctionProtoType>();
+  unsigned BlockOffset = 0;
   for (auto [ParamIndex, PD] : llvm::enumerate(FuncDecl->parameters())) {
     bool IsConst = PD->getType().isConstQualified();
     bool IsVolatile = PD->getType().isVolatileQualified();
@@ -626,8 +632,10 @@ const Function *Context::getOrCreateFunction(const 
FunctionDecl *FuncDecl) {
     Descriptor *Desc = P->createDescriptor(PD, PT, nullptr, std::nullopt,
                                            IsConst, /*IsTemporary=*/false,
                                            /*IsMutable=*/false, IsVolatile);
-    ParamDescriptors.emplace_back(Desc, ParamOffset, PT);
-    ParamOffset += align(primSize(PT));
+    unsigned PrimTSize = align(primSize(PT));
+    ParamDescriptors.emplace_back(Desc, ParamOffset, BlockOffset, PT);
+    ParamOffset += PrimTSize;
+    BlockOffset += sizeof(Block) + PrimTSize;
   }
 
   // Create a handle over the emitted code.
@@ -655,7 +663,7 @@ const Function *Context::getOrCreateObjCBlock(const 
BlockExpr *E) {
     Descriptor *Desc = P->createDescriptor(PD, PT, nullptr, std::nullopt,
                                            IsConst, /*IsTemporary=*/false,
                                            /*IsMutable=*/false, IsVolatile);
-    ParamDescriptors.emplace_back(Desc, ParamOffset, PT);
+    ParamDescriptors.emplace_back(Desc, ParamOffset, ~0u, PT);
     ParamOffset += align(primSize(PT));
   }
 

diff  --git a/clang/lib/AST/ByteCode/Context.h 
b/clang/lib/AST/ByteCode/Context.h
index 1b8c25732a262..f69f3c3d4ca85 100644
--- a/clang/lib/AST/ByteCode/Context.h
+++ b/clang/lib/AST/ByteCode/Context.h
@@ -37,6 +37,11 @@ struct ParamOffset {
   bool IsPtr;
 };
 
+struct FuncParam {
+  unsigned Index;
+  bool IsPtr;
+};
+
 class EvalIDScope;
 /// Holds all information required to evaluate constexpr code in a module.
 class Context final {

diff  --git a/clang/lib/AST/ByteCode/DynamicAllocator.cpp 
b/clang/lib/AST/ByteCode/DynamicAllocator.cpp
index 4fedac667b389..5f53fac923682 100644
--- a/clang/lib/AST/ByteCode/DynamicAllocator.cpp
+++ b/clang/lib/AST/ByteCode/DynamicAllocator.cpp
@@ -27,15 +27,7 @@ void DynamicAllocator::cleanup() {
       assert(!B->isDead());
       assert(B->isInitialized());
       B->invokeDtor();
-
-      if (B->hasPointers()) {
-        while (B->Pointers) {
-          Pointer *Next = B->Pointers->asBlockPointer().Next;
-          B->Pointers->BS.Pointee = nullptr;
-          B->Pointers = Next;
-        }
-        B->Pointers = nullptr;
-      }
+      B->removePointers();
     }
   }
 

diff  --git a/clang/lib/AST/ByteCode/EvalEmitter.h 
b/clang/lib/AST/ByteCode/EvalEmitter.h
index f5c51c5f3dfa0..3de12366a2b3d 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.h
+++ b/clang/lib/AST/ByteCode/EvalEmitter.h
@@ -91,7 +91,7 @@ class EvalEmitter : public SourceMapper {
   }
 
   /// Parameter indices.
-  llvm::DenseMap<const ParmVarDecl *, ParamOffset> Params;
+  llvm::DenseMap<const ParmVarDecl *, FuncParam> Params;
   /// Local descriptors.
   llvm::SmallVector<SmallVector<Local, 8>, 2> Descriptors;
   std::optional<SourceInfo> LocOverride = std::nullopt;

diff  --git a/clang/lib/AST/ByteCode/Function.cpp 
b/clang/lib/AST/ByteCode/Function.cpp
index 56d08a64d1024..06a18d4db036e 100644
--- a/clang/lib/AST/ByteCode/Function.cpp
+++ b/clang/lib/AST/ByteCode/Function.cpp
@@ -22,10 +22,6 @@ Function::Function(Program &P, FunctionDeclTy Source, 
unsigned ArgSize,
       ParamDescriptors(std::move(ParamDescriptors)), IsValid(false),
       IsFullyCompiled(false), HasThisPointer(HasThisPointer), HasRVO(HasRVO),
       HasBody(false), Defined(false) {
-  for (ParamDescriptor PD : this->ParamDescriptors) {
-    Params.insert({PD.Offset, PD});
-  }
-  assert(Params.size() == this->ParamDescriptors.size());
 
   if (const auto *F = dyn_cast<const FunctionDecl *>(Source)) {
     Variadic = F->isVariadic();
@@ -56,12 +52,6 @@ Function::Function(Program &P, FunctionDeclTy Source, 
unsigned ArgSize,
   }
 }
 
-Function::ParamDescriptor Function::getParamDescriptor(unsigned Offset) const {
-  auto It = Params.find(Offset);
-  assert(It != Params.end() && "Invalid parameter offset");
-  return It->second;
-}
-
 SourceInfo Function::getSource(CodePtr PC) const {
   assert(PC >= getCodeBegin() && "PC does not belong to this function");
   assert(PC <= getCodeEnd() && "PC Does not belong to this function");

diff  --git a/clang/lib/AST/ByteCode/Function.h 
b/clang/lib/AST/ByteCode/Function.h
index f67eabf1f27b9..90732d6dc01a4 100644
--- a/clang/lib/AST/ByteCode/Function.h
+++ b/clang/lib/AST/ByteCode/Function.h
@@ -109,10 +109,14 @@ class Function final {
 
   struct ParamDescriptor {
     const Descriptor *Desc;
+    /// Offset on the stack.
     unsigned Offset;
+    /// Offset in the InterpFrame.
+    unsigned BlockOffset;
     PrimType T;
-    ParamDescriptor(const Descriptor *Desc, unsigned Offset, PrimType T)
-        : Desc(Desc), Offset(Offset), T(T) {}
+    ParamDescriptor(const Descriptor *Desc, unsigned Offset,
+                    unsigned BlockOffset, PrimType T)
+        : Desc(Desc), Offset(Offset), BlockOffset(BlockOffset), T(T) {}
   };
 
   /// Returns the size of the function's local stack.
@@ -143,7 +147,9 @@ class Function final {
   }
 
   /// Returns a parameter descriptor.
-  ParamDescriptor getParamDescriptor(unsigned Offset) const;
+  ParamDescriptor getParamDescriptor(unsigned Index) const {
+    return ParamDescriptors[Index];
+  }
 
   /// Checks if the first argument is a RVO pointer.
   bool hasRVO() const { return HasRVO; }
@@ -220,13 +226,15 @@ class Function final {
 
   bool isVariadic() const { return Variadic; }
 
-  unsigned getNumParams() const { return ParamDescriptors.size(); }
+  unsigned getNumParams() const {
+    return ParamDescriptors.size() + hasThisPointer() + hasRVO();
+  }
 
   /// Returns the number of parameter this function takes when it's called,
   /// i.e excluding the instance pointer and the RVO pointer.
   unsigned getNumWrittenParams() const {
     assert(getNumParams() >= (unsigned)(hasThisPointer() + hasRVO()));
-    return getNumParams() - hasThisPointer() - hasRVO();
+    return ParamDescriptors.size();
   }
   unsigned getWrittenArgSize() const {
     return ArgSize - (align(primSize(PT_Ptr)) * (hasThisPointer() + hasRVO()));
@@ -239,14 +247,6 @@ class Function final {
     return false;
   }
 
-  unsigned getParamOffset(unsigned ParamIndex) const {
-    return ParamDescriptors[ParamIndex].Offset;
-  }
-
-  PrimType getParamType(unsigned ParamIndex) const {
-    return ParamDescriptors[ParamIndex].T;
-  }
-
 private:
   /// Construct a function representing an actual function.
   Function(Program &P, FunctionDeclTy Source, unsigned ArgSize,
@@ -293,8 +293,6 @@ class Function final {
   llvm::SmallVector<Scope, 2> Scopes;
   /// List of all parameters, including RVO and instance pointer.
   llvm::SmallVector<ParamDescriptor> ParamDescriptors;
-  /// Map from Parameter offset to parameter descriptor.
-  llvm::DenseMap<unsigned, ParamDescriptor> Params;
   /// Flag to indicate if the function is valid.
   LLVM_PREFERRED_TYPE(bool)
   unsigned IsValid : 1;

diff  --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index 3b92c1858126a..360291ef4e9da 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -298,6 +298,11 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,
   // at the end.
   for (const Function::ParamDescriptor &PDesc : Func->args_reverse())
     TYPE_SWITCH(PDesc.T, S.Stk.discard<T>());
+
+  if (Func->hasThisPointer() && !Func->isThisPointerExplicit())
+    S.Stk.discard<Pointer>();
+  if (Func->hasRVO())
+    S.Stk.discard<Pointer>();
 }
 
 bool isConstexprUnknown(const Pointer &P) {
@@ -1656,19 +1661,20 @@ bool CallVar(InterpState &S, CodePtr OpPC, const 
Function *Func,
   if (!CheckCallDepth(S, OpPC))
     return false;
 
-  auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
+  auto Memory = new char[InterpFrame::allocSize(Func)];
+  auto NewFrame = new (Memory) InterpFrame(S, Func, OpPC, VarArgSize);
   InterpFrame *FrameBefore = S.Current;
-  S.Current = NewFrame.get();
+  S.Current = NewFrame;
 
   // Note that we cannot assert(CallResult.hasValue()) here since
   // Ret() above only sets the APValue if the curent frame doesn't
   // have a caller set.
   if (Interpret(S)) {
-    NewFrame.release(); // Frame was delete'd already.
     assert(S.Current == FrameBefore);
     return true;
   }
 
+  InterpFrame::free(NewFrame);
   // Interpreting the function failed somehow. Reset to
   // previous state.
   S.Current = FrameBefore;
@@ -1739,9 +1745,10 @@ bool Call(InterpState &S, CodePtr OpPC, const Function 
*Func,
   if (!CheckCallDepth(S, OpPC))
     return cleanup();
 
-  auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
+  auto Memory = new char[InterpFrame::allocSize(Func)];
+  auto NewFrame = new (Memory) InterpFrame(S, Func, OpPC, VarArgSize);
   InterpFrame *FrameBefore = S.Current;
-  S.Current = NewFrame.get();
+  S.Current = NewFrame;
 
   InterpStateCCOverride CCOverride(S, Func->isImmediate());
   // Note that we cannot assert(CallResult.hasValue()) here since
@@ -1753,13 +1760,13 @@ bool Call(InterpState &S, CodePtr OpPC, const Function 
*Func,
     S.InitializingBlocks.pop_back();
 
   if (!Success) {
+    InterpFrame::free(NewFrame);
     // Interpreting the function failed somehow. Reset to
     // previous state.
     S.Current = FrameBefore;
     return false;
   }
 
-  NewFrame.release(); // Frame was delete'd already.
   assert(S.Current == FrameBefore);
   return true;
 }

diff  --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 01ea334f65cd3..eb41021bcf7cf 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1426,11 +1426,11 @@ bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) 
{
 }
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
-bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
+bool GetParam(InterpState &S, CodePtr OpPC, uint32_t Index) {
   if (S.checkingPotentialConstantExpression()) {
     return false;
   }
-  S.Stk.push<T>(S.Current->getParam<T>(I));
+  S.Stk.push<T>(S.Current->getParam<T>(Index));
   return true;
 }
 
@@ -1786,10 +1786,10 @@ inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, 
uint32_t I) {
   return true;
 }
 
-inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
+inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t Index) {
   if (S.Current->isBottomFrame())
     return false;
-  S.Stk.push<Pointer>(S.Current->getParamPointer(I));
+  S.Stk.push<Pointer>(S.Current->getParamPointer(Index));
   return true;
 }
 

diff  --git a/clang/lib/AST/ByteCode/InterpBlock.cpp 
b/clang/lib/AST/ByteCode/InterpBlock.cpp
index dc0178afe1246..9199cb09687ec 100644
--- a/clang/lib/AST/ByteCode/InterpBlock.cpp
+++ b/clang/lib/AST/ByteCode/InterpBlock.cpp
@@ -122,6 +122,18 @@ void Block::movePointersTo(Block *B) {
   assert(!this->hasPointers());
 }
 
+void Block::removePointers() {
+  Pointer *P = Pointers;
+  while (P) {
+    Pointer *Next = P->BS.Next;
+    P->BS.Pointee = nullptr;
+    P->BS.Prev = nullptr;
+    P->BS.Next = nullptr;
+    P = Next;
+  }
+  Pointers = nullptr;
+}
+
 DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)
     : Root(Root), B(~0u, Blk->Desc, Blk->isExtern(), Blk->IsStatic,
                     Blk->isWeak(), Blk->isDummy(), /*IsDead=*/true) {

diff  --git a/clang/lib/AST/ByteCode/InterpBlock.h 
b/clang/lib/AST/ByteCode/InterpBlock.h
index 57f9e7ec3714d..4a1195ef25bbe 100644
--- a/clang/lib/AST/ByteCode/InterpBlock.h
+++ b/clang/lib/AST/ByteCode/InterpBlock.h
@@ -94,6 +94,8 @@ class Block final {
   unsigned getEvalID() const { return EvalID; }
   /// Move all pointers from this block to \param B.
   void movePointersTo(Block *B);
+  /// Make all pointers that currently point to this block point to nullptr.
+  void removePointers();
 
   /// Returns a pointer to the stored data.
   /// You are allowed to read Desc->getSize() bytes from this address.

diff  --git a/clang/lib/AST/ByteCode/InterpFrame.cpp 
b/clang/lib/AST/ByteCode/InterpFrame.cpp
index 3c185a0ad661a..0d429e773f88f 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.cpp
+++ b/clang/lib/AST/ByteCode/InterpFrame.cpp
@@ -31,17 +31,19 @@ InterpFrame::InterpFrame(InterpState &S, const Function 
*Func,
     : 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()) {
+
   if (!Func)
     return;
+  // Initialize argument blocks.
+  for (unsigned I = 0, N = Func->getNumWrittenParams(); I != N; ++I)
+    new (argBlock(I)) Block(S.EvalID, Func->getParamDescriptor(I).Desc);
 
-  unsigned FrameSize = Func->getFrameSize();
-  if (FrameSize == 0)
+  if (Func->getFrameSize() == 0)
     return;
 
-  Locals = std::make_unique<char[]>(FrameSize);
   for (auto &Scope : Func->scopes()) {
     for (auto &Local : Scope.locals()) {
-      new (localBlock(Local.Offset)) Block(S.Ctx.getEvalID(), Local.Desc);
+      new (localBlock(Local.Offset)) Block(S.EvalID, Local.Desc);
       // Note that we are NOT calling invokeCtor() here, since that is done
       // via the InitScope op.
       new (localInlineDesc(Local.Offset)) InlineDescriptor(Local.Desc);
@@ -67,8 +69,12 @@ InterpFrame::InterpFrame(InterpState &S, const Function 
*Func, CodePtr RetPC,
 }
 
 InterpFrame::~InterpFrame() {
-  for (auto &Param : Params)
-    S.deallocate(reinterpret_cast<Block *>(Param.second.get()));
+  if (!Func)
+    return;
+
+  // De-initialize all argument blocks.
+  for (unsigned I = 0, N = Func->getNumWrittenParams(); I != N; ++I)
+    S.deallocate(argBlock(I));
 
   // When destroying the InterpFrame, call the Dtor for all block
   // that haven't been destroyed via a destroy() op yet.
@@ -77,7 +83,7 @@ InterpFrame::~InterpFrame() {
 }
 
 void InterpFrame::destroyScopes() {
-  if (!Func)
+  if (!Func || Func->getFrameSize() == 0)
     return;
   for (auto &Scope : Func->scopes()) {
     for (auto &Local : Scope.locals()) {
@@ -244,25 +250,21 @@ Block *InterpFrame::getLocalBlock(unsigned Offset) const {
   return localBlock(Offset);
 }
 
-Pointer InterpFrame::getParamPointer(unsigned Off) {
-  // Return the block if it was created previously.
-  if (auto Pt = Params.find(Off); Pt != Params.end())
-    return Pointer(reinterpret_cast<Block *>(Pt->second.get()));
-
+Pointer InterpFrame::getParamPointer(unsigned Index) {
   assert(!isBottomFrame());
 
-  // Allocate memory to store the parameter and the block metadata.
-  const auto &PDesc = Func->getParamDescriptor(Off);
-  size_t BlockSize = sizeof(Block) + PDesc.Desc->getAllocSize();
-  auto Memory = std::make_unique<char[]>(BlockSize);
-  auto *B = new (Memory.get()) Block(S.Ctx.getEvalID(), PDesc.Desc);
-  B->invokeCtor();
+  Block *B = argBlock(Index);
 
   // Copy the initial value.
-  TYPE_SWITCH(PDesc.T, new (B->data()) T(stackRef<T>(Off)));
+  if (!B->isInitialized()) {
+    unsigned ByteOffset = Func->getParamDescriptor(Index).Offset;
+    assert(B->getDescriptor()->isPrimitive());
+    B->invokeCtor();
+    TYPE_SWITCH(B->getDescriptor()->getPrimType(),
+                new (B->data()) T(stackRef<T>(ByteOffset)));
+    assert(B->isInitialized());
+  }
 
-  // Record the param.
-  Params.insert({Off, std::move(Memory)});
   return Pointer(B);
 }
 

diff  --git a/clang/lib/AST/ByteCode/InterpFrame.h 
b/clang/lib/AST/ByteCode/InterpFrame.h
index 0879260695d3e..8b4da6a14de70 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.h
+++ b/clang/lib/AST/ByteCode/InterpFrame.h
@@ -46,6 +46,13 @@ class InterpFrame final : public Frame {
   /// Destroys the frame, killing all live pointers to stack slots.
   ~InterpFrame();
 
+  /// Returns the number of bytes needed to allocate an InterpFrame for the
+  /// given function.
+  static size_t allocSize(const Function *F) {
+    return sizeof(InterpFrame) + F->getFrameSize() +
+           (F->getArgSize() + (sizeof(Block) * F->getNumWrittenParams()));
+  }
+
   std::string getName() const {
     if (!Func)
       return "Bottom frame";
@@ -53,8 +60,12 @@ class InterpFrame final : public Frame {
   }
 
   static void free(InterpFrame *F) {
-    if (!F->isBottomFrame())
-      delete F;
+    if (!F->isBottomFrame()) {
+      F->~InterpFrame();
+      delete[] reinterpret_cast<char *>(F);
+    } else {
+      F->~InterpFrame();
+    }
   }
 
   /// Invokes the destructors for a scope.
@@ -100,22 +111,23 @@ class InterpFrame final : public Frame {
   Block *getLocalBlock(unsigned Offset) const;
 
   /// Returns the value of an argument.
-  template <typename T> const T &getParam(unsigned Offset) const {
-    auto Pt = Params.find(Offset);
-    if (Pt == Params.end())
-      return stackRef<T>(Offset);
-    return reinterpret_cast<const Block *>(Pt->second.get())->deref<T>();
+  template <typename T> const T &getParam(unsigned Index) const {
+    Block *ArgBlock = argBlock(Index);
+    if (!ArgBlock->isInitialized())
+      return stackRef<T>(Func->getParamDescriptor(Index).Offset);
+    return ArgBlock->deref<T>();
   }
 
   /// Mutates a local copy of a parameter.
-  template <typename T> void setParam(unsigned Offset, const T &Value) {
-    getParamPointer(Offset).deref<T>() = Value;
+  template <typename T> void setParam(unsigned Index, const T &Value) {
+    argBlock(Index)->deref<T>() = Value;
   }
 
   /// Returns a pointer to an argument - lazily creates a block.
   Pointer getParamPointer(unsigned Offset);
 
   bool hasThisPointer() const { return Func && Func->hasThisPointer(); }
+
   /// Returns the 'this' pointer.
   const Pointer &getThis() const {
     assert(hasThisPointer());
@@ -167,14 +179,32 @@ class InterpFrame final : public Frame {
     return localBlock(Offset)->deref<T>();
   }
 
+  /// Pointer to local memory.
+  char *locals() const {
+    return (reinterpret_cast<char *>(const_cast<InterpFrame *>(this))) +
+           align(sizeof(InterpFrame));
+  }
+
+  /// Pointer to argument memory.
+  char *args() const {
+    return (reinterpret_cast<char *>(const_cast<InterpFrame *>(this))) +
+           sizeof(InterpFrame) + Func->getFrameSize();
+  }
+
   /// Returns a pointer to a local's block.
   Block *localBlock(unsigned Offset) const {
-    return reinterpret_cast<Block *>(Locals.get() + Offset - sizeof(Block));
+    return reinterpret_cast<Block *>(locals() + Offset - sizeof(Block));
+  }
+
+  /// Returns a pointer to an argument block.
+  Block *argBlock(unsigned Index) const {
+    unsigned ByteOffset = Func->getParamDescriptor(Index).BlockOffset;
+    return reinterpret_cast<Block *>(args() + ByteOffset);
   }
 
   /// Returns the inline descriptor of the local.
   InlineDescriptor *localInlineDesc(unsigned Offset) const {
-    return reinterpret_cast<InlineDescriptor *>(Locals.get() + Offset);
+    return reinterpret_cast<InlineDescriptor *>(locals() + Offset);
   }
 
 private:
@@ -192,12 +222,8 @@ class InterpFrame final : public Frame {
   const unsigned ArgSize;
   /// Pointer to the arguments in the callee's frame.
   char *Args = nullptr;
-  /// Fixed, initial storage for known local variables.
-  std::unique_ptr<char[]> Locals;
   /// Offset on the stack at entry.
   const size_t FrameOffset;
-  /// Mapping from arg offsets to their argument blocks.
-  llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Params;
 
 public:
   unsigned MSVCConstexprAllowed = 0;

diff  --git a/clang/lib/AST/ByteCode/InterpState.cpp 
b/clang/lib/AST/ByteCode/InterpState.cpp
index fd69559af5917..2d6ed98e6b52c 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -33,9 +33,8 @@ InterpState::InterpState(const State &Parent, Program &P, 
InterpStack &Stk,
 InterpState::InterpState(const State &Parent, Program &P, InterpStack &Stk,
                          Context &Ctx, const Function *Func)
     : State(Ctx.getASTContext(), Parent.getEvalStatus()), M(nullptr), P(P),
-      Stk(Stk), Ctx(Ctx),
-      BottomFrame(*this, Func, nullptr, CodePtr(), Func->getArgSize()),
-      Current(&BottomFrame), StepsLeft(Ctx.getLangOpts().ConstexprStepLimit),
+      Stk(Stk), Ctx(Ctx), BottomFrame(*this), Current(&BottomFrame),
+      StepsLeft(Ctx.getLangOpts().ConstexprStepLimit),
       InfiniteSteps(StepsLeft == 0), EvalID(Ctx.getEvalID()) {
   InConstantContext = Parent.InConstantContext;
   CheckingPotentialConstantExpression =


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to