aboutsummaryrefslogtreecommitdiffstats
path: root/lib/AST/Interp/InterpFrame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/Interp/InterpFrame.cpp')
-rw-r--r--lib/AST/Interp/InterpFrame.cpp193
1 files changed, 193 insertions, 0 deletions
diff --git a/lib/AST/Interp/InterpFrame.cpp b/lib/AST/Interp/InterpFrame.cpp
new file mode 100644
index 000000000000..9d01bf0333fe
--- /dev/null
+++ b/lib/AST/Interp/InterpFrame.cpp
@@ -0,0 +1,193 @@
+//===--- InterpFrame.cpp - Call Frame implementation for the VM -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "InterpFrame.h"
+#include "Function.h"
+#include "Interp.h"
+#include "InterpStack.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+InterpFrame::InterpFrame(InterpState &S, Function *Func, InterpFrame *Caller,
+ CodePtr RetPC, Pointer &&This)
+ : Caller(Caller), S(S), Func(Func), This(std::move(This)), RetPC(RetPC),
+ ArgSize(Func ? Func->getArgSize() : 0),
+ Args(static_cast<char *>(S.Stk.top())), FrameOffset(S.Stk.size()) {
+ if (Func) {
+ if (unsigned FrameSize = Func->getFrameSize()) {
+ Locals = std::make_unique<char[]>(FrameSize);
+ for (auto &Scope : Func->scopes()) {
+ for (auto &Local : Scope.locals()) {
+ Block *B = new (localBlock(Local.Offset)) Block(Local.Desc);
+ B->invokeCtor();
+ }
+ }
+ }
+ }
+}
+
+InterpFrame::~InterpFrame() {
+ if (Func && Func->isConstructor() && This.isBaseClass())
+ This.initialize();
+ for (auto &Param : Params)
+ S.deallocate(reinterpret_cast<Block *>(Param.second.get()));
+}
+
+void InterpFrame::destroy(unsigned Idx) {
+ for (auto &Local : Func->getScope(Idx).locals()) {
+ S.deallocate(reinterpret_cast<Block *>(localBlock(Local.Offset)));
+ }
+}
+
+void InterpFrame::popArgs() {
+ for (PrimType Ty : Func->args_reverse())
+ TYPE_SWITCH(Ty, S.Stk.discard<T>());
+}
+
+template <typename T>
+static void print(llvm::raw_ostream &OS, const T &V, ASTContext &, QualType) {
+ OS << V;
+}
+
+template <>
+void print(llvm::raw_ostream &OS, const Pointer &P, ASTContext &Ctx,
+ QualType Ty) {
+ if (P.isZero()) {
+ OS << "nullptr";
+ return;
+ }
+
+ auto printDesc = [&OS, &Ctx](Descriptor *Desc) {
+ if (auto *D = Desc->asDecl()) {
+ // Subfields or named values.
+ if (auto *VD = dyn_cast<ValueDecl>(D)) {
+ OS << *VD;
+ return;
+ }
+ // Base classes.
+ if (isa<RecordDecl>(D)) {
+ return;
+ }
+ }
+ // Temporary expression.
+ if (auto *E = Desc->asExpr()) {
+ E->printPretty(OS, nullptr, Ctx.getPrintingPolicy());
+ return;
+ }
+ llvm_unreachable("Invalid descriptor type");
+ };
+
+ if (!Ty->isReferenceType())
+ OS << "&";
+ llvm::SmallVector<Pointer, 2> Levels;
+ for (Pointer F = P; !F.isRoot(); ) {
+ Levels.push_back(F);
+ F = F.isArrayElement() ? F.getArray().expand() : F.getBase();
+ }
+
+ printDesc(P.getDeclDesc());
+ for (auto It = Levels.rbegin(); It != Levels.rend(); ++It) {
+ if (It->inArray()) {
+ OS << "[" << It->expand().getIndex() << "]";
+ continue;
+ }
+ if (auto Index = It->getIndex()) {
+ OS << " + " << Index;
+ continue;
+ }
+ OS << ".";
+ printDesc(It->getFieldDesc());
+ }
+}
+
+void InterpFrame::describe(llvm::raw_ostream &OS) {
+ const FunctionDecl *F = getCallee();
+ auto *M = dyn_cast<CXXMethodDecl>(F);
+ if (M && M->isInstance() && !isa<CXXConstructorDecl>(F)) {
+ print(OS, This, S.getCtx(), S.getCtx().getRecordType(M->getParent()));
+ OS << "->";
+ }
+ OS << *F << "(";
+ unsigned Off = Func->hasRVO() ? primSize(PT_Ptr) : 0;
+ for (unsigned I = 0, N = F->getNumParams(); I < N; ++I) {
+ QualType Ty = F->getParamDecl(I)->getType();
+
+ PrimType PrimTy;
+ if (llvm::Optional<PrimType> T = S.Ctx.classify(Ty)) {
+ PrimTy = *T;
+ } else {
+ PrimTy = PT_Ptr;
+ }
+
+ TYPE_SWITCH(PrimTy, print(OS, stackRef<T>(Off), S.getCtx(), Ty));
+ Off += align(primSize(PrimTy));
+ if (I + 1 != N)
+ OS << ", ";
+ }
+ OS << ")";
+}
+
+Frame *InterpFrame::getCaller() const {
+ if (Caller->Caller)
+ return Caller;
+ return S.getSplitFrame();
+}
+
+SourceLocation InterpFrame::getCallLocation() const {
+ if (!Caller->Func)
+ return S.getLocation(nullptr, {});
+ return S.getLocation(Caller->Func, RetPC - sizeof(uintptr_t));
+}
+
+const FunctionDecl *InterpFrame::getCallee() const {
+ return Func->getDecl();
+}
+
+Pointer InterpFrame::getLocalPointer(unsigned Offset) {
+ assert(Offset < Func->getFrameSize() && "Invalid local offset.");
+ return Pointer(
+ reinterpret_cast<Block *>(Locals.get() + Offset - sizeof(Block)));
+}
+
+Pointer InterpFrame::getParamPointer(unsigned Off) {
+ // Return the block if it was created previously.
+ auto Pt = Params.find(Off);
+ if (Pt != Params.end()) {
+ return Pointer(reinterpret_cast<Block *>(Pt->second.get()));
+ }
+
+ // Allocate memory to store the parameter and the block metadata.
+ const auto &Desc = Func->getParamDescriptor(Off);
+ size_t BlockSize = sizeof(Block) + Desc.second->getAllocSize();
+ auto Memory = std::make_unique<char[]>(BlockSize);
+ auto *B = new (Memory.get()) Block(Desc.second);
+
+ // Copy the initial value.
+ TYPE_SWITCH(Desc.first, new (B->data()) T(stackRef<T>(Off)));
+
+ // Record the param.
+ Params.insert({Off, std::move(Memory)});
+ return Pointer(B);
+}
+
+SourceInfo InterpFrame::getSource(CodePtr PC) const {
+ return S.getSource(Func, PC);
+}
+
+const Expr *InterpFrame::getExpr(CodePtr PC) const {
+ return S.getExpr(Func, PC);
+}
+
+SourceLocation InterpFrame::getLocation(CodePtr PC) const {
+ return S.getLocation(Func, PC);
+}
+