Author: Timm Baeder
Date: 2026-03-19T19:29:56-07:00
New Revision: bf1db77fc87ce9d2ca7744565321b09a5d23692f

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

LOG: Revert "[clang][bytecode] Allocate local variables in `InterpFrame` tail 
storage" (#187410)

Reverts llvm/llvm-project#185835

Looks like this broke two msan builders:
https://lab.llvm.org/buildbot/#/builders/164/builds/19819
https://lab.llvm.org/buildbot/#/builders/94/builds/16257

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 c08ccf69aef85..35821085ff49b 100644
--- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
+++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
@@ -55,13 +55,18 @@ void ByteCodeEmitter::compileFunc(const FunctionDecl 
*FuncDecl,
   }
 
   bool IsValid = !FuncDecl->isInvalidDecl();
-  // Register parameters and their index.
-  for (unsigned ParamIndex = 0, N = Func->getNumWrittenParams();
-       ParamIndex != N; ++ParamIndex) {
+  // 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)) 
{
     const ParmVarDecl *PD = FuncDecl->getParamDecl(ParamIndex);
     if (PD->isInvalidDecl())
       IsValid = false;
-    this->Params.insert({PD, {ParamIndex, Ctx.canClassify(PD->getType())}});
+    this->Params.insert(
+        {PD, {ParamDesc.Offset, Ctx.canClassify(PD->getType())}});
+    ++ParamIndex;
   }
 
   Func->setDefined(true);

diff  --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.h 
b/clang/lib/AST/ByteCode/ByteCodeEmitter.h
index 873edeea71d96..dd18341d52a09 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 *, FuncParam> Params;
+  llvm::DenseMap<const ParmVarDecl *, ParamOffset> 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 a881d77a73cbd..fc2da6362d0bb 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.Index, E);
+              return this->emitGetParam(*SubExprT, It->second.Offset, 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 ParamIndex = 0;
+  unsigned Offset = align(primSize(PT_Ptr)); // instance pointer.
   for (const ParmVarDecl *PD : Ctor->parameters()) {
     PrimType PT = this->classify(PD->getType()).value_or(PT_Ptr);
 
-    if (!this->emitGetParam(PT, ParamIndex, E))
+    if (!this->emitGetParam(PT, Offset, E))
       return false;
-    ++ParamIndex;
+    Offset += align(primSize(PT));
   }
 
   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.Index, MD))
+    if (!this->emitGetParam(ParamType, It->second.Offset, MD))
       return false;
   }
 
@@ -6702,7 +6702,10 @@ bool Compiler<Emitter>::compileConstructor(const 
CXXConstructorDecl *Ctor) {
     if (!this->emitThis(Ctor))
       return false;
 
-    if (!this->emitGetParam(PT_Ptr, /*ParamIndex=*/0, Ctor))
+    const ParmVarDecl *PVD = Ctor->getParamDecl(0);
+    ParamOffset PO = this->Params[PVD]; // Must exist.
+
+    if (!this->emitGetParam(PT_Ptr, PO.Offset, Ctor))
       return false;
 
     return this->emitMemcpy(Ctor) && this->emitPopPtr(Ctor) &&
@@ -6875,7 +6878,10 @@ bool Compiler<Emitter>::compileUnionAssignmentOperator(
   if (!this->emitThis(MD))
     return false;
 
-  if (!this->emitGetParam(PT_Ptr, /*ParamIndex=*/0, MD))
+  const ParmVarDecl *PVD = MD->getParamDecl(0);
+  ParamOffset PO = this->Params[PVD]; // Must exist.
+
+  if (!this->emitGetParam(PT_Ptr, PO.Offset, MD))
     return false;
 
   return this->emitMemcpy(MD) && this->emitRet(PT_Ptr, MD);
@@ -7447,9 +7453,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.Index, E);
+        return this->emitGetParam(classifyPrim(E), It->second.Offset, E);
 
-      return this->emitGetPtrParam(It->second.Index, E);
+      return this->emitGetPtrParam(It->second.Offset, E);
     }
 
     if (!Ctx.getLangOpts().CPlusPlus23 && IsReference)

diff  --git a/clang/lib/AST/ByteCode/Context.cpp 
b/clang/lib/AST/ByteCode/Context.cpp
index 2b32161fceba0..7d4534a5da5c6 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -498,19 +498,11 @@ 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;
 }
 
@@ -583,6 +575,7 @@ 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));
   }
 
@@ -593,8 +586,10 @@ const Function *Context::getOrCreateFunction(const 
FunctionDecl *FuncDecl) {
   if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) {
     if (!IsLambdaStaticInvoker) {
       HasThisPointer = MD->isInstance();
-      if (MD->isImplicitObjectMemberFunction())
+      if (MD->isImplicitObjectMemberFunction()) {
+        ParamDescriptors.emplace_back(nullptr, ParamOffset, PT_Ptr);
         ParamOffset += align(primSize(PT_Ptr));
+      }
     }
 
     if (isLambdaCallOperator(MD)) {
@@ -618,7 +613,6 @@ 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();
@@ -632,10 +626,8 @@ const Function *Context::getOrCreateFunction(const 
FunctionDecl *FuncDecl) {
     Descriptor *Desc = P->createDescriptor(PD, PT, nullptr, std::nullopt,
                                            IsConst, /*IsTemporary=*/false,
                                            /*IsMutable=*/false, IsVolatile);
-    unsigned PrimTSize = align(primSize(PT));
-    ParamDescriptors.emplace_back(Desc, ParamOffset, BlockOffset, PT);
-    ParamOffset += PrimTSize;
-    BlockOffset += sizeof(Block) + PrimTSize;
+    ParamDescriptors.emplace_back(Desc, ParamOffset, PT);
+    ParamOffset += align(primSize(PT));
   }
 
   // Create a handle over the emitted code.
@@ -663,7 +655,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, ~0u, PT);
+    ParamDescriptors.emplace_back(Desc, ParamOffset, PT);
     ParamOffset += align(primSize(PT));
   }
 

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

diff  --git a/clang/lib/AST/ByteCode/EvalEmitter.h 
b/clang/lib/AST/ByteCode/EvalEmitter.h
index 3de12366a2b3d..f5c51c5f3dfa0 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 *, FuncParam> Params;
+  llvm::DenseMap<const ParmVarDecl *, ParamOffset> 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 06a18d4db036e..56d08a64d1024 100644
--- a/clang/lib/AST/ByteCode/Function.cpp
+++ b/clang/lib/AST/ByteCode/Function.cpp
@@ -22,6 +22,10 @@ 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();
@@ -52,6 +56,12 @@ 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 90732d6dc01a4..f67eabf1f27b9 100644
--- a/clang/lib/AST/ByteCode/Function.h
+++ b/clang/lib/AST/ByteCode/Function.h
@@ -109,14 +109,10 @@ 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,
-                    unsigned BlockOffset, PrimType T)
-        : Desc(Desc), Offset(Offset), BlockOffset(BlockOffset), T(T) {}
+    ParamDescriptor(const Descriptor *Desc, unsigned Offset, PrimType T)
+        : Desc(Desc), Offset(Offset), T(T) {}
   };
 
   /// Returns the size of the function's local stack.
@@ -147,9 +143,7 @@ class Function final {
   }
 
   /// Returns a parameter descriptor.
-  ParamDescriptor getParamDescriptor(unsigned Index) const {
-    return ParamDescriptors[Index];
-  }
+  ParamDescriptor getParamDescriptor(unsigned Offset) const;
 
   /// Checks if the first argument is a RVO pointer.
   bool hasRVO() const { return HasRVO; }
@@ -226,15 +220,13 @@ class Function final {
 
   bool isVariadic() const { return Variadic; }
 
-  unsigned getNumParams() const {
-    return ParamDescriptors.size() + hasThisPointer() + hasRVO();
-  }
+  unsigned getNumParams() const { return ParamDescriptors.size(); }
 
   /// 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 ParamDescriptors.size();
+    return getNumParams() - hasThisPointer() - hasRVO();
   }
   unsigned getWrittenArgSize() const {
     return ArgSize - (align(primSize(PT_Ptr)) * (hasThisPointer() + hasRVO()));
@@ -247,6 +239,14 @@ 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,6 +293,8 @@ 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 360291ef4e9da..3b92c1858126a 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -298,11 +298,6 @@ 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) {
@@ -1661,20 +1656,19 @@ bool CallVar(InterpState &S, CodePtr OpPC, const 
Function *Func,
   if (!CheckCallDepth(S, OpPC))
     return false;
 
-  auto Memory = new char[InterpFrame::allocSize(Func)];
-  auto NewFrame = new (Memory) InterpFrame(S, Func, OpPC, VarArgSize);
+  auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
   InterpFrame *FrameBefore = S.Current;
-  S.Current = NewFrame;
+  S.Current = NewFrame.get();
 
   // 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;
@@ -1745,10 +1739,9 @@ bool Call(InterpState &S, CodePtr OpPC, const Function 
*Func,
   if (!CheckCallDepth(S, OpPC))
     return cleanup();
 
-  auto Memory = new char[InterpFrame::allocSize(Func)];
-  auto NewFrame = new (Memory) InterpFrame(S, Func, OpPC, VarArgSize);
+  auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
   InterpFrame *FrameBefore = S.Current;
-  S.Current = NewFrame;
+  S.Current = NewFrame.get();
 
   InterpStateCCOverride CCOverride(S, Func->isImmediate());
   // Note that we cannot assert(CallResult.hasValue()) here since
@@ -1760,13 +1753,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 eb41021bcf7cf..01ea334f65cd3 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 Index) {
+bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
   if (S.checkingPotentialConstantExpression()) {
     return false;
   }
-  S.Stk.push<T>(S.Current->getParam<T>(Index));
+  S.Stk.push<T>(S.Current->getParam<T>(I));
   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 Index) {
+inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
   if (S.Current->isBottomFrame())
     return false;
-  S.Stk.push<Pointer>(S.Current->getParamPointer(Index));
+  S.Stk.push<Pointer>(S.Current->getParamPointer(I));
   return true;
 }
 

diff  --git a/clang/lib/AST/ByteCode/InterpBlock.cpp 
b/clang/lib/AST/ByteCode/InterpBlock.cpp
index 9199cb09687ec..dc0178afe1246 100644
--- a/clang/lib/AST/ByteCode/InterpBlock.cpp
+++ b/clang/lib/AST/ByteCode/InterpBlock.cpp
@@ -122,18 +122,6 @@ 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 4a1195ef25bbe..57f9e7ec3714d 100644
--- a/clang/lib/AST/ByteCode/InterpBlock.h
+++ b/clang/lib/AST/ByteCode/InterpBlock.h
@@ -94,8 +94,6 @@ 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 0d429e773f88f..3c185a0ad661a 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.cpp
+++ b/clang/lib/AST/ByteCode/InterpFrame.cpp
@@ -31,19 +31,17 @@ 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);
 
-  if (Func->getFrameSize() == 0)
+  unsigned FrameSize = Func->getFrameSize();
+  if (FrameSize == 0)
     return;
 
+  Locals = std::make_unique<char[]>(FrameSize);
   for (auto &Scope : Func->scopes()) {
     for (auto &Local : Scope.locals()) {
-      new (localBlock(Local.Offset)) Block(S.EvalID, Local.Desc);
+      new (localBlock(Local.Offset)) Block(S.Ctx.getEvalID(), 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);
@@ -69,12 +67,8 @@ InterpFrame::InterpFrame(InterpState &S, const Function 
*Func, CodePtr RetPC,
 }
 
 InterpFrame::~InterpFrame() {
-  if (!Func)
-    return;
-
-  // De-initialize all argument blocks.
-  for (unsigned I = 0, N = Func->getNumWrittenParams(); I != N; ++I)
-    S.deallocate(argBlock(I));
+  for (auto &Param : Params)
+    S.deallocate(reinterpret_cast<Block *>(Param.second.get()));
 
   // When destroying the InterpFrame, call the Dtor for all block
   // that haven't been destroyed via a destroy() op yet.
@@ -83,7 +77,7 @@ InterpFrame::~InterpFrame() {
 }
 
 void InterpFrame::destroyScopes() {
-  if (!Func || Func->getFrameSize() == 0)
+  if (!Func)
     return;
   for (auto &Scope : Func->scopes()) {
     for (auto &Local : Scope.locals()) {
@@ -250,21 +244,25 @@ Block *InterpFrame::getLocalBlock(unsigned Offset) const {
   return localBlock(Offset);
 }
 
-Pointer InterpFrame::getParamPointer(unsigned Index) {
+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()));
+
   assert(!isBottomFrame());
 
-  Block *B = argBlock(Index);
+  // 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();
 
   // Copy the initial value.
-  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());
-  }
+  TYPE_SWITCH(PDesc.T, new (B->data()) T(stackRef<T>(Off)));
 
+  // 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 56203658264e4..0879260695d3e 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.h
+++ b/clang/lib/AST/ByteCode/InterpFrame.h
@@ -46,13 +46,6 @@ 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";
@@ -60,10 +53,8 @@ class InterpFrame final : public Frame {
   }
 
   static void free(InterpFrame *F) {
-    F->~InterpFrame();
-    if (!F->isBottomFrame()) {
-      delete[] reinterpret_cast<char *>(F);
-    }
+    if (!F->isBottomFrame())
+      delete F;
   }
 
   /// Invokes the destructors for a scope.
@@ -109,23 +100,22 @@ class InterpFrame final : public Frame {
   Block *getLocalBlock(unsigned Offset) const;
 
   /// Returns the value of an argument.
-  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>();
+  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>();
   }
 
   /// Mutates a local copy of a parameter.
-  template <typename T> void setParam(unsigned Index, const T &Value) {
-    argBlock(Index)->deref<T>() = Value;
+  template <typename T> void setParam(unsigned Offset, const T &Value) {
+    getParamPointer(Offset).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());
@@ -177,32 +167,14 @@ 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() + 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);
+    return reinterpret_cast<Block *>(Locals.get() + Offset - sizeof(Block));
   }
 
   /// Returns the inline descriptor of the local.
   InlineDescriptor *localInlineDesc(unsigned Offset) const {
-    return reinterpret_cast<InlineDescriptor *>(locals() + Offset);
+    return reinterpret_cast<InlineDescriptor *>(Locals.get() + Offset);
   }
 
 private:
@@ -220,8 +192,12 @@ 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 2d6ed98e6b52c..fd69559af5917 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -33,8 +33,9 @@ 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), Current(&BottomFrame),
-      StepsLeft(Ctx.getLangOpts().ConstexprStepLimit),
+      Stk(Stk), Ctx(Ctx),
+      BottomFrame(*this, Func, nullptr, CodePtr(), Func->getArgSize()),
+      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