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
