aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/AST/ByteCode
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST/ByteCode')
-rw-r--r--clang/lib/AST/ByteCode/ByteCodeEmitter.cpp19
-rw-r--r--clang/lib/AST/ByteCode/Compiler.cpp49
-rw-r--r--clang/lib/AST/ByteCode/Descriptor.cpp46
-rw-r--r--clang/lib/AST/ByteCode/DynamicAllocator.cpp19
-rw-r--r--clang/lib/AST/ByteCode/Interp.h8
-rw-r--r--clang/lib/AST/ByteCode/InterpState.cpp22
-rw-r--r--clang/lib/AST/ByteCode/Opcodes.td4
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;