194 lines
5.3 KiB
C++
194 lines
5.3 KiB
C++
//===--- 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);
|
|
}
|
|
|