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
