diff options
Diffstat (limited to 'clang/lib/AST/ByteCode')
-rw-r--r-- | clang/lib/AST/ByteCode/ByteCodeEmitter.cpp | 19 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Compiler.cpp | 49 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Descriptor.cpp | 46 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/DynamicAllocator.cpp | 19 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Interp.h | 8 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/InterpState.cpp | 22 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Opcodes.td | 4 |
7 files changed, 113 insertions, 54 deletions
diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp index 3288585..d474605 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp @@ -137,21 +137,21 @@ int32_t ByteCodeEmitter::getOffset(LabelTy Label) { template <typename T> static void emit(Program &P, std::vector<std::byte> &Code, const T &Val, bool &Success) { + size_t ValPos = Code.size(); size_t Size; if constexpr (std::is_pointer_v<T>) - Size = sizeof(uint32_t); + Size = align(sizeof(uint32_t)); else - Size = sizeof(T); + Size = align(sizeof(T)); - if (Code.size() + Size > std::numeric_limits<unsigned>::max()) { + if (ValPos + Size > std::numeric_limits<unsigned>::max()) { Success = false; return; } // Access must be aligned! - size_t ValPos = align(Code.size()); - Size = align(Size); + assert(aligned(ValPos)); assert(aligned(ValPos + Size)); Code.resize(ValPos + Size); @@ -168,17 +168,16 @@ static void emit(Program &P, std::vector<std::byte> &Code, const T &Val, template <typename T> static void emitSerialized(std::vector<std::byte> &Code, const T &Val, bool &Success) { - size_t Size = Val.bytesToSerialize(); + size_t ValPos = Code.size(); + size_t Size = align(Val.bytesToSerialize()); - if (Code.size() + Size > std::numeric_limits<unsigned>::max()) { + if (ValPos + Size > std::numeric_limits<unsigned>::max()) { Success = false; return; } // Access must be aligned! - assert(aligned(Code.size())); - size_t ValPos = Code.size(); - Size = align(Size); + assert(aligned(ValPos)); assert(aligned(ValPos + Size)); Code.resize(ValPos + Size); diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index d0ddb2e..6e451ac 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -106,25 +106,14 @@ bool InitLink::emit(Compiler<Emitter> *Ctx, const Expr *E) const { return true; } -/// Scope managing label targets. -template <class Emitter> class LabelScope { -public: - virtual ~LabelScope() {} - -protected: - LabelScope(Compiler<Emitter> *Ctx) : Ctx(Ctx) {} - /// Compiler instance. - Compiler<Emitter> *Ctx; -}; - /// Sets the context for break/continue statements. -template <class Emitter> class LoopScope final : public LabelScope<Emitter> { +template <class Emitter> class LoopScope final { public: using LabelTy = typename Compiler<Emitter>::LabelTy; using OptLabelTy = typename Compiler<Emitter>::OptLabelTy; LoopScope(Compiler<Emitter> *Ctx, LabelTy BreakLabel, LabelTy ContinueLabel) - : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel), + : Ctx(Ctx), OldBreakLabel(Ctx->BreakLabel), OldContinueLabel(Ctx->ContinueLabel), OldBreakVarScope(Ctx->BreakVarScope), OldContinueVarScope(Ctx->ContinueVarScope) { @@ -142,6 +131,7 @@ public: } private: + Compiler<Emitter> *Ctx; OptLabelTy OldBreakLabel; OptLabelTy OldContinueLabel; VariableScope<Emitter> *OldBreakVarScope; @@ -149,7 +139,7 @@ private: }; // Sets the context for a switch scope, mapping labels. -template <class Emitter> class SwitchScope final : public LabelScope<Emitter> { +template <class Emitter> class SwitchScope final { public: using LabelTy = typename Compiler<Emitter>::LabelTy; using OptLabelTy = typename Compiler<Emitter>::OptLabelTy; @@ -157,7 +147,7 @@ public: SwitchScope(Compiler<Emitter> *Ctx, CaseMap &&CaseLabels, LabelTy BreakLabel, OptLabelTy DefaultLabel) - : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel), + : Ctx(Ctx), OldBreakLabel(Ctx->BreakLabel), OldDefaultLabel(this->Ctx->DefaultLabel), OldCaseLabels(std::move(this->Ctx->CaseLabels)), OldLabelVarScope(Ctx->BreakVarScope) { @@ -175,6 +165,7 @@ public: } private: + Compiler<Emitter> *Ctx; OptLabelTy OldBreakLabel; OptLabelTy OldDefaultLabel; CaseMap OldCaseLabels; @@ -340,6 +331,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { } case CK_FloatingToIntegral: { + if (!CE->getType()->isIntegralOrEnumerationType()) + return false; if (!this->visit(SubExpr)) return false; PrimType ToT = classifyPrim(CE); @@ -457,13 +450,17 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { assert(isPtrType(*FromT)); assert(isPtrType(*ToT)); if (FromT == ToT) { - if (CE->getType()->isVoidPointerType()) + if (CE->getType()->isVoidPointerType() && + !SubExprTy->isFunctionPointerType()) { return this->delegate(SubExpr); + } if (!this->visit(SubExpr)) return false; - if (CE->getType()->isFunctionPointerType()) - return true; + if (CE->getType()->isFunctionPointerType() || + SubExprTy->isFunctionPointerType()) { + return this->emitFnPtrCast(CE); + } if (FromT == PT_Ptr) return this->emitPtrPtrCast(SubExprTy->isVoidPointerType(), CE); return true; @@ -1374,10 +1371,15 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) { // BitAdd/BitOr/BitXor/Shl/Shr doesn't support bool type, we need perform the // integer promotion. bool NeedIntPromot = ElemT == PT_Bool && (E->isBitwiseOp() || E->isShiftOp()); - QualType PromotTy = - Ctx.getASTContext().getPromotedIntegerType(Ctx.getASTContext().BoolTy); - PrimType PromotT = classifyPrim(PromotTy); - PrimType OpT = NeedIntPromot ? PromotT : ElemT; + QualType PromotTy; + PrimType PromotT = PT_Bool; + PrimType OpT = ElemT; + if (NeedIntPromot) { + PromotTy = + Ctx.getASTContext().getPromotedIntegerType(Ctx.getASTContext().BoolTy); + PromotT = classifyPrim(PromotTy); + OpT = PromotT; + } auto getElem = [=](unsigned Offset, PrimType ElemT, unsigned Index) { if (!this->emitGetLocal(PT_Ptr, Offset, E)) @@ -1763,6 +1765,9 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, if (Inits.size() == 1 && E->getType() == Inits[0]->getType()) return this->delegate(Inits[0]); + if (!R) + return false; + auto initPrimitiveField = [=](const Record::Field *FieldToInit, const Expr *Init, PrimType T, bool Activate = false) -> bool { diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp index 5b9f445..7403e90 100644 --- a/clang/lib/AST/ByteCode/Descriptor.cpp +++ b/clang/lib/AST/ByteCode/Descriptor.cpp @@ -21,14 +21,31 @@ using namespace clang; using namespace clang::interp; +template <typename T> static constexpr bool needsCtor() { + if constexpr (std::is_same_v<T, Integral<8, true>> || + std::is_same_v<T, Integral<8, false>> || + std::is_same_v<T, Integral<16, true>> || + std::is_same_v<T, Integral<16, false>> || + std::is_same_v<T, Integral<32, true>> || + std::is_same_v<T, Integral<32, false>> || + std::is_same_v<T, Integral<64, true>> || + std::is_same_v<T, Integral<64, false>> || + std::is_same_v<T, Boolean>) + return false; + + return true; +} + template <typename T> static void ctorTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool, const Descriptor *) { + static_assert(needsCtor<T>()); new (Ptr) T(); } template <typename T> static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) { + static_assert(needsCtor<T>()); reinterpret_cast<T *>(Ptr)->~T(); } @@ -45,9 +62,11 @@ static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool, const Descriptor *D) { new (Ptr) InitMapPtr(std::nullopt); - Ptr += sizeof(InitMapPtr); - for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { - new (&reinterpret_cast<T *>(Ptr)[I]) T(); + if constexpr (needsCtor<T>()) { + Ptr += sizeof(InitMapPtr); + for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { + new (&reinterpret_cast<T *>(Ptr)[I]) T(); + } } } @@ -57,9 +76,12 @@ static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) { if (IMP) IMP = std::nullopt; - Ptr += sizeof(InitMapPtr); - for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { - reinterpret_cast<T *>(Ptr)[I].~T(); + + if constexpr (needsCtor<T>()) { + Ptr += sizeof(InitMapPtr); + for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { + reinterpret_cast<T *>(Ptr)[I].~T(); + } } } @@ -74,10 +96,14 @@ static void moveArrayTy(Block *, std::byte *Src, std::byte *Dst, } Src += sizeof(InitMapPtr); Dst += sizeof(InitMapPtr); - for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { - auto *SrcPtr = &reinterpret_cast<T *>(Src)[I]; - auto *DstPtr = &reinterpret_cast<T *>(Dst)[I]; - new (DstPtr) T(std::move(*SrcPtr)); + if constexpr (!needsCtor<T>()) { + std::memcpy(Dst, Src, D->getNumElems() * D->getElemSize()); + } else { + for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { + auto *SrcPtr = &reinterpret_cast<T *>(Src)[I]; + auto *DstPtr = &reinterpret_cast<T *>(Dst)[I]; + new (DstPtr) T(std::move(*SrcPtr)); + } } } diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.cpp b/clang/lib/AST/ByteCode/DynamicAllocator.cpp index 169250c..9b8b664 100644 --- a/clang/lib/AST/ByteCode/DynamicAllocator.cpp +++ b/clang/lib/AST/ByteCode/DynamicAllocator.cpp @@ -13,6 +13,25 @@ using namespace clang; using namespace clang::interp; +// FIXME: There is a peculiar problem with the way we track pointers +// to blocks and the way we allocate dynamic memory. +// +// When we have code like this: +// while (true) { +// char *buffer = new char[1024]; +// delete[] buffer; +// } +// +// We have a local variable 'buffer' pointing to the heap allocated memory. +// When deallocating the memory via delete[], that local variable still +// points to the memory, which means we will create a DeadBlock for it and move +// it over to that block, essentially duplicating the allocation. Moving +// the data is also slow. +// +// However, when we actually try to access the allocation after it has been +// freed, we need the block to still exist (alive or dead) so we can tell +// that it's a dynamic allocation. + DynamicAllocator::~DynamicAllocator() { cleanup(); } void DynamicAllocator::cleanup() { diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 1869500..9a325ab 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -2682,6 +2682,14 @@ static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) { return true; } +static inline bool FnPtrCast(InterpState &S, CodePtr OpPC) { + const SourceInfo &E = S.Current->getSource(OpPC); + S.CCEDiag(E, diag::note_constexpr_invalid_cast) + << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret + << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC); + return true; +} + static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) { const auto &Ptr = S.Stk.peek<Pointer>(); diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp index 3010847..32ad07b 100644 --- a/clang/lib/AST/ByteCode/InterpState.cpp +++ b/clang/lib/AST/ByteCode/InterpState.cpp @@ -77,27 +77,27 @@ void InterpState::deallocate(Block *B) { const Descriptor *Desc = B->getDescriptor(); assert(Desc); + // The block might have a pointer saved in a field in its data + // that points to the block itself. We call the dtor first, + // which will destroy all the data but leave InlineDescriptors + // intact. If the block THEN still has pointers, we create a + // DeadBlock for it. + if (B->IsInitialized) + B->invokeDtor(); + if (B->hasPointers()) { size_t Size = B->getSize(); - // Allocate a new block, transferring over pointers. char *Memory = reinterpret_cast<char *>(std::malloc(sizeof(DeadBlock) + Size)); auto *D = new (Memory) DeadBlock(DeadBlocks, B); - std::memset(D->B.rawData(), 0, D->B.getSize()); - - // Move data and metadata from the old block to the new (dead)block. - if (B->IsInitialized && Desc->MoveFn) { - Desc->MoveFn(B, B->data(), D->data(), Desc); - if (Desc->getMetadataSize() > 0) - std::memcpy(D->rawData(), B->rawData(), Desc->getMetadataSize()); - } + // Since the block doesn't hold any actual data anymore, we can just + // memcpy() everything over. + std::memcpy(D->rawData(), B->rawData(), Desc->getAllocSize()); D->B.IsInitialized = B->IsInitialized; // We moved the contents over to the DeadBlock. B->IsInitialized = false; - } else if (B->IsInitialized) { - B->invokeDtor(); } } diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index abfed77..95a4433 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -412,7 +412,7 @@ def CheckDecl : Opcode { def CheckEnumValue : Opcode { let Args = [ArgEnumDecl]; - let Types = [FixedSizeIntegralTypeClass]; + let Types = [IntegralTypeClass]; let HasGroup = 1; } @@ -735,6 +735,8 @@ def PtrPtrCast : Opcode { } +def FnPtrCast : Opcode; + def DecayPtr : Opcode { let Types = [PtrTypeClass, PtrTypeClass]; let HasGroup = 1; |