mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Clang-importer-synthesized declarations get an extra tag character included in their mangling, which was not being preserved in type context descriptors. This caused runtime lookup for these synthesized types to fail. Fix this by adding the tag information to type context descriptors and teaching the runtime to match it up when fetching metadata by mangled name. Fixes rdar://problem/40878715.
1232 lines
41 KiB
C++
1232 lines
41 KiB
C++
//===--- RemoteAST.cpp ----------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the RemoteAST interface.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/RemoteAST/RemoteAST.h"
|
|
#include "swift/Remote/MetadataReader.h"
|
|
#include "swift/Strings.h"
|
|
#include "swift/Subsystems.h"
|
|
#include "swift/AST/ASTContext.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/GenericSignature.h"
|
|
#include "swift/AST/Module.h"
|
|
#include "swift/AST/NameLookup.h"
|
|
#include "swift/AST/SubstitutionMap.h"
|
|
#include "swift/AST/Types.h"
|
|
#include "swift/AST/TypeRepr.h"
|
|
#include "swift/Basic/Mangler.h"
|
|
#include "swift/ClangImporter/ClangImporter.h"
|
|
#include "llvm/ADT/StringSwitch.h"
|
|
|
|
// TODO: Develop a proper interface for this.
|
|
#include "swift/AST/IRGenOptions.h"
|
|
#include "swift/AST/SILOptions.h"
|
|
#include "swift/SIL/SILModule.h"
|
|
#include "../IRGen/IRGenModule.h"
|
|
#include "../IRGen/FixedTypeInfo.h"
|
|
#include "../IRGen/GenClass.h"
|
|
#include "../IRGen/GenStruct.h"
|
|
#include "../IRGen/GenTuple.h"
|
|
#include "../IRGen/MemberAccessStrategy.h"
|
|
|
|
using namespace swift;
|
|
using namespace swift::remote;
|
|
using namespace swift::remoteAST;
|
|
|
|
using irgen::Alignment;
|
|
using irgen::Size;
|
|
|
|
static inline RemoteAddress operator+(RemoteAddress address, Size offset) {
|
|
return RemoteAddress(address.getAddressData() + offset.getValue());
|
|
}
|
|
|
|
namespace {
|
|
|
|
/// A "minimal" class for querying IRGen.
|
|
struct IRGenContext {
|
|
IRGenOptions IROpts;
|
|
SILOptions SILOpts;
|
|
std::unique_ptr<SILModule> SILMod;
|
|
llvm::LLVMContext LLVMContext;
|
|
irgen::IRGenerator IRGen;
|
|
irgen::IRGenModule IGM;
|
|
|
|
private:
|
|
IRGenContext(ASTContext &ctx, ModuleDecl *module)
|
|
: IROpts(createIRGenOptions()),
|
|
SILMod(SILModule::createEmptyModule(module, SILOpts)),
|
|
IRGen(IROpts, *SILMod),
|
|
IGM(IRGen, IRGen.createTargetMachine(), /*SourceFile*/ nullptr,
|
|
LLVMContext, "<fake module name>", "<fake output filename>",
|
|
"<fake main input filename>") {}
|
|
|
|
static IRGenOptions createIRGenOptions() {
|
|
IRGenOptions IROpts;
|
|
IROpts.EnableResilienceBypass = true;
|
|
return IROpts;
|
|
}
|
|
|
|
public:
|
|
static std::unique_ptr<IRGenContext>
|
|
create(ASTContext &ctx, DeclContext *nominalDC) {
|
|
auto module = nominalDC->getParentModule();
|
|
return std::unique_ptr<IRGenContext>(new IRGenContext(ctx, module));
|
|
}
|
|
};
|
|
|
|
/// An implementation of MetadataReader's BuilderType concept that
|
|
/// just finds and builds things in the AST.
|
|
class RemoteASTTypeBuilder {
|
|
ASTContext &Ctx;
|
|
Demangle::NodeFactory Factory;
|
|
|
|
/// The notional context in which we're writing and type-checking code.
|
|
/// Created lazily.
|
|
DeclContext *NotionalDC = nullptr;
|
|
|
|
Optional<Failure> CurFailure;
|
|
|
|
public:
|
|
using BuiltType = swift::Type;
|
|
using BuiltNominalTypeDecl = swift::NominalTypeDecl *;
|
|
using BuiltProtocolDecl = swift::ProtocolDecl *;
|
|
explicit RemoteASTTypeBuilder(ASTContext &ctx) : Ctx(ctx) {}
|
|
|
|
std::unique_ptr<IRGenContext> createIRGenContext() {
|
|
return IRGenContext::create(Ctx, getNotionalDC());
|
|
}
|
|
|
|
template <class Result, class FailureKindTy, class... FailureArgTys>
|
|
Result fail(FailureKindTy kind, FailureArgTys &&...failureArgs) {
|
|
if (!CurFailure) {
|
|
CurFailure.emplace(kind, std::forward<FailureArgTys>(failureArgs)...);
|
|
}
|
|
return Result();
|
|
}
|
|
|
|
template <class T, class DefaultFailureKindTy, class... DefaultFailureArgTys>
|
|
Result<T> getFailureAsResult(DefaultFailureKindTy defaultFailureKind,
|
|
DefaultFailureArgTys &&...defaultFailureArgs) {
|
|
// If we already have a failure, use that.
|
|
if (CurFailure) {
|
|
Result<T> result = std::move(*CurFailure);
|
|
CurFailure.reset();
|
|
return result;
|
|
}
|
|
|
|
// Otherwise, use the default failure.
|
|
return Result<T>::emplaceFailure(defaultFailureKind,
|
|
std::forward<DefaultFailureArgTys>(defaultFailureArgs)...);
|
|
}
|
|
|
|
Demangle::NodeFactory &getNodeFactory() { return Factory; }
|
|
|
|
Type createBuiltinType(const std::string &mangledName) {
|
|
// TODO
|
|
return Type();
|
|
}
|
|
|
|
NominalTypeDecl *createNominalTypeDecl(StringRef mangledName) {
|
|
Demangle::Demangler Dem;
|
|
Demangle::NodePointer node = Dem.demangleType(mangledName);
|
|
if (!node) return nullptr;
|
|
|
|
return createNominalTypeDecl(node);
|
|
}
|
|
|
|
NominalTypeDecl *createNominalTypeDecl(const Demangle::NodePointer &node);
|
|
|
|
ProtocolDecl *createProtocolDecl(const Demangle::NodePointer &node) {
|
|
return dyn_cast_or_null<ProtocolDecl>(createNominalTypeDecl(node));
|
|
}
|
|
|
|
Type createNominalType(NominalTypeDecl *decl) {
|
|
// If the declaration is generic, fail.
|
|
if (decl->isGenericContext())
|
|
return Type();
|
|
|
|
return decl->getDeclaredType();
|
|
}
|
|
|
|
Type createNominalType(NominalTypeDecl *decl, Type parent) {
|
|
// If the declaration is generic, fail.
|
|
if (decl->getGenericParams())
|
|
return Type();
|
|
|
|
// Validate the parent type.
|
|
if (!validateNominalParent(decl, parent))
|
|
return Type();
|
|
|
|
return NominalType::get(decl, parent, Ctx);
|
|
}
|
|
|
|
Type createBoundGenericType(NominalTypeDecl *decl, ArrayRef<Type> args) {
|
|
// If the declaration isn't generic, fail.
|
|
if (!decl->isGenericContext())
|
|
return Type();
|
|
|
|
// Build a SubstitutionMap.
|
|
auto *genericSig = decl->getGenericSignature();
|
|
auto genericParams = genericSig->getSubstitutableParams();
|
|
if (genericParams.size() != args.size())
|
|
return Type();
|
|
|
|
auto subMap = SubstitutionMap::get(
|
|
genericSig,
|
|
[&](SubstitutableType *t) -> Type {
|
|
for (unsigned i = 0, e = genericParams.size(); i < e; ++i) {
|
|
if (t->isEqual(genericParams[i]))
|
|
return args[i];
|
|
}
|
|
return Type();
|
|
},
|
|
// FIXME: Wrong module
|
|
LookUpConformanceInModule(decl->getParentModule()));
|
|
|
|
auto origType = decl->getDeclaredInterfaceType();
|
|
|
|
// FIXME: We're not checking that the type satisfies the generic
|
|
// requirements of the signature here.
|
|
auto substType = origType.subst(subMap);
|
|
return substType;
|
|
}
|
|
|
|
Type createBoundGenericType(NominalTypeDecl *decl, ArrayRef<Type> args,
|
|
Type parent) {
|
|
// If the declaration isn't generic, fail.
|
|
if (!decl->getGenericParams())
|
|
return Type();
|
|
|
|
// Validate the parent type.
|
|
if (!validateNominalParent(decl, parent))
|
|
return Type();
|
|
|
|
// Make a generic type repr that's been resolved to this decl.
|
|
TypeReprList genericArgReprs(args);
|
|
auto genericRepr = GenericIdentTypeRepr::create(Ctx, SourceLoc(),
|
|
decl->getName(),
|
|
genericArgReprs.getList(),
|
|
SourceRange());
|
|
// FIXME
|
|
genericRepr->setValue(decl, nullptr);
|
|
|
|
Type genericType;
|
|
|
|
// If we have a parent type, we need to build a compound type repr.
|
|
if (parent) {
|
|
// Life would be much easier if we could just use a FixedTypeRepr for
|
|
// the parent. But we can't! So we have to recursively expand
|
|
// like this; and recursing with a lambda isn't impossible, so it gets
|
|
// even worse.
|
|
SmallVector<Type, 4> ancestry;
|
|
for (auto p = parent; p; p = p->getNominalParent()) {
|
|
ancestry.push_back(p);
|
|
}
|
|
|
|
struct GenericRepr {
|
|
TypeReprList GenericArgs;
|
|
GenericIdentTypeRepr *Ident;
|
|
|
|
GenericRepr(const ASTContext &Ctx, BoundGenericType *type)
|
|
: GenericArgs(type->getGenericArgs()),
|
|
Ident(GenericIdentTypeRepr::create(Ctx, SourceLoc(),
|
|
type->getDecl()->getName(),
|
|
GenericArgs.getList(),
|
|
SourceRange())) {
|
|
// FIXME
|
|
Ident->setValue(type->getDecl(), nullptr);
|
|
}
|
|
|
|
// SmallVector::emplace_back will never need to call this because
|
|
// we reserve the right size, but it does try statically.
|
|
GenericRepr(const GenericRepr &other) : GenericArgs({}), Ident(nullptr) {
|
|
llvm_unreachable("should not be called dynamically");
|
|
}
|
|
};
|
|
|
|
// Pre-allocate the component vectors so that we can form references
|
|
// into them safely.
|
|
SmallVector<SimpleIdentTypeRepr, 4> simpleComponents;
|
|
SmallVector<GenericRepr, 4> genericComponents;
|
|
simpleComponents.reserve(ancestry.size());
|
|
genericComponents.reserve(ancestry.size());
|
|
|
|
// Build the parent hierarchy.
|
|
SmallVector<ComponentIdentTypeRepr*, 4> componentReprs;
|
|
for (size_t i = ancestry.size(); i != 0; --i) {
|
|
Type p = ancestry[i - 1];
|
|
if (auto boundGeneric = p->getAs<BoundGenericType>()) {
|
|
genericComponents.emplace_back(Ctx, boundGeneric);
|
|
componentReprs.push_back(genericComponents.back().Ident);
|
|
} else {
|
|
auto nominal = p->castTo<NominalType>();
|
|
simpleComponents.emplace_back(SourceLoc(),
|
|
nominal->getDecl()->getName());
|
|
// FIXME
|
|
simpleComponents.back().setValue(nominal->getDecl(), nullptr);
|
|
componentReprs.push_back(&simpleComponents.back());
|
|
}
|
|
}
|
|
componentReprs.push_back(genericRepr);
|
|
|
|
auto compoundRepr = CompoundIdentTypeRepr::create(Ctx, componentReprs);
|
|
genericType = checkTypeRepr(compoundRepr);
|
|
} else {
|
|
genericType = checkTypeRepr(genericRepr);
|
|
}
|
|
|
|
// If type-checking failed, we've failed.
|
|
if (!genericType) return Type();
|
|
|
|
// Validate that we used the right decl.
|
|
if (auto bgt = genericType->getAs<BoundGenericType>()) {
|
|
if (bgt->getDecl() != decl)
|
|
return Type();
|
|
}
|
|
|
|
return genericType;
|
|
}
|
|
|
|
Type createTupleType(ArrayRef<Type> eltTypes, StringRef labels,
|
|
bool isVariadic) {
|
|
// Just bail out on variadic tuples for now.
|
|
if (isVariadic) return Type();
|
|
|
|
SmallVector<TupleTypeElt, 4> elements;
|
|
elements.reserve(eltTypes.size());
|
|
for (auto eltType : eltTypes) {
|
|
Identifier label;
|
|
if (!labels.empty()) {
|
|
auto split = labels.split(' ');
|
|
if (!split.first.empty())
|
|
label = Ctx.getIdentifier(split.first);
|
|
labels = split.second;
|
|
}
|
|
elements.emplace_back(eltType, label);
|
|
}
|
|
|
|
return TupleType::get(elements, Ctx);
|
|
}
|
|
|
|
Type createFunctionType(ArrayRef<remote::FunctionParam<Type>> params,
|
|
Type output, FunctionTypeFlags flags) {
|
|
FunctionTypeRepresentation representation;
|
|
switch (flags.getConvention()) {
|
|
case FunctionMetadataConvention::Swift:
|
|
representation = FunctionTypeRepresentation::Swift;
|
|
break;
|
|
case FunctionMetadataConvention::Block:
|
|
representation = FunctionTypeRepresentation::Block;
|
|
break;
|
|
case FunctionMetadataConvention::Thin:
|
|
representation = FunctionTypeRepresentation::Thin;
|
|
break;
|
|
case FunctionMetadataConvention::CFunctionPointer:
|
|
representation = FunctionTypeRepresentation::CFunctionPointer;
|
|
break;
|
|
}
|
|
|
|
auto einfo = AnyFunctionType::ExtInfo(representation,
|
|
/*throws*/ flags.throws());
|
|
if (flags.isEscaping())
|
|
einfo = einfo.withNoEscape(false);
|
|
else
|
|
einfo = einfo.withNoEscape(true);
|
|
|
|
// The result type must be materializable.
|
|
if (!output->isMaterializable()) return Type();
|
|
|
|
llvm::SmallVector<AnyFunctionType::Param, 8> funcParams;
|
|
for (const auto ¶m : params) {
|
|
auto type = param.getType();
|
|
|
|
// All the argument types must be materializable.
|
|
if (!type->isMaterializable())
|
|
return Type();
|
|
|
|
auto label = Ctx.getIdentifier(param.getLabel());
|
|
auto flags = param.getFlags();
|
|
auto ownership = flags.getValueOwnership();
|
|
auto parameterFlags = ParameterTypeFlags()
|
|
.withInOut(ownership == ValueOwnership::InOut)
|
|
.withShared(ownership == ValueOwnership::Shared)
|
|
.withOwned(ownership == ValueOwnership::Owned)
|
|
.withVariadic(flags.isVariadic());
|
|
|
|
funcParams.push_back(AnyFunctionType::Param(type, label, parameterFlags));
|
|
}
|
|
|
|
return FunctionType::get(funcParams, output, einfo);
|
|
}
|
|
|
|
Type createProtocolCompositionType(ArrayRef<ProtocolDecl *> protocols,
|
|
Type superclass,
|
|
bool isClassBound) {
|
|
std::vector<Type> members;
|
|
for (auto protocol : protocols)
|
|
members.push_back(protocol->getDeclaredType());
|
|
if (superclass && superclass->getClassOrBoundGenericClass())
|
|
members.push_back(superclass);
|
|
return ProtocolCompositionType::get(Ctx, members, isClassBound);
|
|
}
|
|
|
|
Type createExistentialMetatypeType(Type instance) {
|
|
if (!instance->isAnyExistentialType())
|
|
return Type();
|
|
return ExistentialMetatypeType::get(instance);
|
|
}
|
|
|
|
Type createMetatypeType(Type instance, bool wasAbstract=false) {
|
|
// FIXME: Plumb through metatype representation and generalize silly
|
|
// 'wasAbstract' flag
|
|
return MetatypeType::get(instance);
|
|
}
|
|
|
|
Type createGenericTypeParameterType(unsigned depth, unsigned index) {
|
|
return GenericTypeParamType::get(depth, index, Ctx);
|
|
}
|
|
|
|
Type createDependentMemberType(StringRef member, Type base,
|
|
ProtocolDecl *protocol) {
|
|
if (!base->isTypeParameter())
|
|
return Type();
|
|
|
|
for (auto member : protocol->lookupDirect(Ctx.getIdentifier(member),
|
|
/*ignoreNew=*/true)) {
|
|
if (auto assocType = dyn_cast<AssociatedTypeDecl>(member))
|
|
return DependentMemberType::get(base, assocType);
|
|
}
|
|
|
|
return Type();
|
|
}
|
|
|
|
Type createUnownedStorageType(Type base) {
|
|
if (!base->allowsOwnership())
|
|
return Type();
|
|
return UnownedStorageType::get(base, Ctx);
|
|
}
|
|
|
|
Type createUnmanagedStorageType(Type base) {
|
|
if (!base->allowsOwnership())
|
|
return Type();
|
|
return UnmanagedStorageType::get(base, Ctx);
|
|
}
|
|
|
|
Type createWeakStorageType(Type base) {
|
|
if (!base->allowsOwnership())
|
|
return Type();
|
|
return WeakStorageType::get(base, Ctx);
|
|
}
|
|
|
|
Type createSILBoxType(Type base) {
|
|
return SILBoxType::get(base->getCanonicalType());
|
|
}
|
|
|
|
Type createObjCClassType(StringRef name) {
|
|
auto typeDecl =
|
|
findForeignNominalTypeDecl(name, /*relatedEntityKind*/{},
|
|
ForeignModuleKind::Imported,
|
|
Demangle::Node::Kind::Class);
|
|
if (!typeDecl) return Type();
|
|
return createNominalType(typeDecl, /*parent*/ Type());
|
|
}
|
|
|
|
Type createForeignClassType(StringRef mangledName) {
|
|
auto typeDecl = createNominalTypeDecl(mangledName);
|
|
if (!typeDecl) return Type();
|
|
|
|
return createNominalType(typeDecl, /*parent*/ Type());
|
|
}
|
|
|
|
Type getUnnamedForeignClassType() {
|
|
return Type();
|
|
}
|
|
|
|
Type getOpaqueType() {
|
|
return Type();
|
|
}
|
|
|
|
private:
|
|
bool validateNominalParent(NominalTypeDecl *decl, Type parent) {
|
|
auto parentDecl =
|
|
decl->getDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext();
|
|
|
|
// If we don't have a parent type, fast-path.
|
|
if (!parent) {
|
|
return parentDecl == nullptr;
|
|
}
|
|
|
|
// We do have a parent type. If the nominal type doesn't, it's an error.
|
|
if (!parentDecl) {
|
|
return false;
|
|
}
|
|
|
|
// FIXME: validate that the parent is a correct application of the
|
|
// enclosing context?
|
|
return true;
|
|
}
|
|
|
|
DeclContext *findDeclContext(const Demangle::NodePointer &node);
|
|
ModuleDecl *findModule(const Demangle::NodePointer &node);
|
|
Demangle::NodePointer findModuleNode(const Demangle::NodePointer &node);
|
|
|
|
enum class ForeignModuleKind {
|
|
Imported,
|
|
SynthesizedByImporter
|
|
};
|
|
|
|
Optional<ForeignModuleKind>
|
|
getForeignModuleKind(const Demangle::NodePointer &node);
|
|
|
|
NominalTypeDecl *findNominalTypeDecl(DeclContext *dc,
|
|
Identifier name,
|
|
Identifier privateDiscriminator,
|
|
Demangle::Node::Kind kind);
|
|
NominalTypeDecl *findForeignNominalTypeDecl(StringRef name,
|
|
StringRef relatedEntityKind,
|
|
ForeignModuleKind lookupKind,
|
|
Demangle::Node::Kind kind);
|
|
|
|
Type checkTypeRepr(TypeRepr *repr) {
|
|
DeclContext *dc = getNotionalDC();
|
|
|
|
TypeLoc loc(repr);
|
|
if (performTypeLocChecking(Ctx, loc, dc, /*diagnose*/ false))
|
|
return Type();
|
|
|
|
return loc.getType();
|
|
}
|
|
|
|
static NominalTypeDecl *getAcceptableNominalTypeCandidate(ValueDecl *decl,
|
|
Demangle::Node::Kind kind) {
|
|
if (kind == Demangle::Node::Kind::Class) {
|
|
return dyn_cast<ClassDecl>(decl);
|
|
} else if (kind == Demangle::Node::Kind::Enum) {
|
|
return dyn_cast<EnumDecl>(decl);
|
|
} else if (kind == Demangle::Node::Kind::Protocol) {
|
|
return dyn_cast<ProtocolDecl>(decl);
|
|
} else {
|
|
assert(kind == Demangle::Node::Kind::Structure);
|
|
return dyn_cast<StructDecl>(decl);
|
|
}
|
|
}
|
|
|
|
DeclContext *getNotionalDC() {
|
|
if (!NotionalDC) {
|
|
NotionalDC = ModuleDecl::create(Ctx.getIdentifier(".RemoteAST"), Ctx);
|
|
NotionalDC = new (Ctx) TopLevelCodeDecl(NotionalDC);
|
|
}
|
|
return NotionalDC;
|
|
}
|
|
|
|
class TypeReprList {
|
|
SmallVector<FixedTypeRepr, 4> Reprs;
|
|
SmallVector<TypeRepr*, 4> Refs;
|
|
|
|
public:
|
|
explicit TypeReprList(ArrayRef<Type> types) {
|
|
Reprs.reserve(types.size());
|
|
Refs.reserve(types.size());
|
|
|
|
for (auto type : types) {
|
|
Reprs.emplace_back(type, SourceLoc());
|
|
Refs.push_back(&Reprs.back());
|
|
}
|
|
}
|
|
|
|
ArrayRef<TypeRepr*> getList() const {
|
|
return Refs;
|
|
}
|
|
};
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
NominalTypeDecl *
|
|
RemoteASTTypeBuilder::createNominalTypeDecl(const Demangle::NodePointer &node) {
|
|
auto DC = findDeclContext(node);
|
|
if (!DC) {
|
|
return fail<NominalTypeDecl*>(Failure::CouldNotResolveTypeDecl,
|
|
Demangle::mangleNode(node));
|
|
}
|
|
|
|
auto decl = dyn_cast<NominalTypeDecl>(DC);
|
|
if (!decl) return nullptr;
|
|
|
|
return decl;
|
|
}
|
|
|
|
ModuleDecl *RemoteASTTypeBuilder::findModule(const Demangle::NodePointer &node){
|
|
assert(node->getKind() == Demangle::Node::Kind::Module);
|
|
const auto &moduleName = node->getText();
|
|
return Ctx.getModuleByName(moduleName);
|
|
}
|
|
|
|
Demangle::NodePointer
|
|
RemoteASTTypeBuilder::findModuleNode(const Demangle::NodePointer &node) {
|
|
if (node->getKind() == Demangle::Node::Kind::Module)
|
|
return node;
|
|
|
|
if (!node->hasChildren()) return nullptr;
|
|
const auto &child = node->getFirstChild();
|
|
if (child->getKind() != Demangle::Node::Kind::DeclContext)
|
|
return nullptr;
|
|
|
|
return findModuleNode(child->getFirstChild());
|
|
}
|
|
|
|
Optional<RemoteASTTypeBuilder::ForeignModuleKind>
|
|
RemoteASTTypeBuilder::getForeignModuleKind(const Demangle::NodePointer &node) {
|
|
if (node->getKind() == Demangle::Node::Kind::DeclContext)
|
|
return getForeignModuleKind(node->getFirstChild());
|
|
|
|
if (node->getKind() != Demangle::Node::Kind::Module)
|
|
return None;
|
|
|
|
return llvm::StringSwitch<Optional<ForeignModuleKind>>(node->getText())
|
|
.Case(MANGLING_MODULE_OBJC, ForeignModuleKind::Imported)
|
|
.Case(MANGLING_MODULE_CLANG_IMPORTER,
|
|
ForeignModuleKind::SynthesizedByImporter)
|
|
.Default(None);
|
|
}
|
|
|
|
DeclContext *
|
|
RemoteASTTypeBuilder::findDeclContext(const Demangle::NodePointer &node) {
|
|
switch (node->getKind()) {
|
|
case Demangle::Node::Kind::DeclContext:
|
|
case Demangle::Node::Kind::Type:
|
|
return findDeclContext(node->getFirstChild());
|
|
|
|
case Demangle::Node::Kind::Module:
|
|
return findModule(node);
|
|
|
|
case Demangle::Node::Kind::Class:
|
|
case Demangle::Node::Kind::Enum:
|
|
case Demangle::Node::Kind::Protocol:
|
|
case Demangle::Node::Kind::Structure:
|
|
case Demangle::Node::Kind::TypeAlias: {
|
|
const auto &declNameNode = node->getChild(1);
|
|
|
|
// Handle local declarations.
|
|
if (declNameNode->getKind() == Demangle::Node::Kind::LocalDeclName) {
|
|
// Find the AST node for the defining module.
|
|
auto moduleNode = findModuleNode(node);
|
|
if (!moduleNode) return nullptr;
|
|
|
|
auto module = findModule(moduleNode);
|
|
if (!module) return nullptr;
|
|
|
|
// Look up the local type by its mangling.
|
|
auto mangledName = Demangle::mangleNode(node);
|
|
auto decl = module->lookupLocalType(mangledName);
|
|
if (!decl) return nullptr;
|
|
|
|
return dyn_cast<DeclContext>(decl);
|
|
}
|
|
|
|
StringRef name;
|
|
StringRef relatedEntityKind;
|
|
Identifier privateDiscriminator;
|
|
if (declNameNode->getKind() == Demangle::Node::Kind::Identifier) {
|
|
name = declNameNode->getText();
|
|
|
|
} else if (declNameNode->getKind() ==
|
|
Demangle::Node::Kind::PrivateDeclName) {
|
|
name = declNameNode->getChild(1)->getText();
|
|
privateDiscriminator =
|
|
Ctx.getIdentifier(declNameNode->getChild(0)->getText());
|
|
|
|
} else if (declNameNode->getKind() ==
|
|
Demangle::Node::Kind::RelatedEntityDeclName) {
|
|
name = declNameNode->getChild(0)->getText();
|
|
relatedEntityKind = declNameNode->getText();
|
|
|
|
// Ignore any other decl-name productions for now.
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
DeclContext *dc = findDeclContext(node->getChild(0));
|
|
if (!dc) {
|
|
// Do some backup logic for foreign type declarations.
|
|
if (privateDiscriminator.empty()) {
|
|
if (auto foreignModuleKind = getForeignModuleKind(node->getChild(0))) {
|
|
return findForeignNominalTypeDecl(name, relatedEntityKind,
|
|
foreignModuleKind.getValue(),
|
|
node->getKind());
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
return findNominalTypeDecl(dc, Ctx.getIdentifier(name),
|
|
privateDiscriminator, node->getKind());
|
|
}
|
|
|
|
case Demangle::Node::Kind::Global:
|
|
return findDeclContext(node->getChild(0));
|
|
|
|
// Bail out on other kinds of contexts.
|
|
// TODO: extensions
|
|
// TODO: local contexts
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
NominalTypeDecl *
|
|
RemoteASTTypeBuilder::findNominalTypeDecl(DeclContext *dc,
|
|
Identifier name,
|
|
Identifier privateDiscriminator,
|
|
Demangle::Node::Kind kind) {
|
|
auto module = dc->getParentModule();
|
|
|
|
SmallVector<ValueDecl *, 4> lookupResults;
|
|
module->lookupMember(lookupResults, dc, name, privateDiscriminator);
|
|
|
|
NominalTypeDecl *result = nullptr;
|
|
for (auto decl : lookupResults) {
|
|
// Ignore results that are not the right kind of nominal type declaration.
|
|
NominalTypeDecl *candidate = getAcceptableNominalTypeCandidate(decl, kind);
|
|
if (!candidate)
|
|
continue;
|
|
|
|
// Ignore results that aren't actually from the defining module.
|
|
if (candidate->getParentModule() != module)
|
|
continue;
|
|
|
|
// This is a viable result.
|
|
|
|
// If we already have a viable result, it's ambiguous, so give up.
|
|
if (result) return nullptr;
|
|
result = candidate;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static Optional<ClangTypeKind>
|
|
getClangTypeKindForNodeKind(Demangle::Node::Kind kind) {
|
|
switch (kind) {
|
|
case Demangle::Node::Kind::Protocol:
|
|
return ClangTypeKind::ObjCProtocol;
|
|
case Demangle::Node::Kind::Class:
|
|
return ClangTypeKind::ObjCClass;
|
|
case Demangle::Node::Kind::TypeAlias:
|
|
return ClangTypeKind::Typedef;
|
|
case Demangle::Node::Kind::Structure:
|
|
case Demangle::Node::Kind::Enum:
|
|
return ClangTypeKind::Tag;
|
|
default:
|
|
return None;
|
|
}
|
|
}
|
|
|
|
NominalTypeDecl *
|
|
RemoteASTTypeBuilder::findForeignNominalTypeDecl(StringRef name,
|
|
StringRef relatedEntityKind,
|
|
ForeignModuleKind foreignKind,
|
|
Demangle::Node::Kind kind) {
|
|
// Check to see if we have an importer loaded.
|
|
auto importer = static_cast<ClangImporter *>(Ctx.getClangModuleLoader());
|
|
if (!importer) return nullptr;
|
|
|
|
// Find the unique declaration that has the right kind.
|
|
struct Consumer : VisibleDeclConsumer {
|
|
Demangle::Node::Kind ExpectedKind;
|
|
NominalTypeDecl *Result = nullptr;
|
|
bool HadError = false;
|
|
|
|
explicit Consumer(Demangle::Node::Kind kind) : ExpectedKind(kind) {}
|
|
|
|
void foundDecl(ValueDecl *decl, DeclVisibilityKind reason) override {
|
|
if (HadError) return;
|
|
if (decl == Result) return;
|
|
if (!Result) {
|
|
// A synthesized type from the Clang importer may resolve to a
|
|
// compatibility alias.
|
|
if (auto resultAlias = dyn_cast<TypeAliasDecl>(decl)) {
|
|
if (resultAlias->isCompatibilityAlias()) {
|
|
Result = resultAlias->getUnderlyingTypeLoc().getType()
|
|
->getAnyNominal();
|
|
}
|
|
} else {
|
|
Result = dyn_cast<NominalTypeDecl>(decl);
|
|
}
|
|
HadError |= !Result;
|
|
} else {
|
|
HadError = true;
|
|
Result = nullptr;
|
|
}
|
|
}
|
|
} consumer(kind);
|
|
|
|
switch (foreignKind) {
|
|
case ForeignModuleKind::SynthesizedByImporter:
|
|
if (!relatedEntityKind.empty()) {
|
|
Optional<ClangTypeKind> lookupKind = getClangTypeKindForNodeKind(kind);
|
|
if (!lookupKind)
|
|
return nullptr;
|
|
importer->lookupRelatedEntity(name, lookupKind.getValue(),
|
|
relatedEntityKind, [&](TypeDecl *found) {
|
|
consumer.foundDecl(found, DeclVisibilityKind::VisibleAtTopLevel);
|
|
});
|
|
break;
|
|
}
|
|
importer->lookupValue(Ctx.getIdentifier(name), consumer);
|
|
if (consumer.Result)
|
|
consumer.Result = getAcceptableNominalTypeCandidate(consumer.Result,kind);
|
|
break;
|
|
case ForeignModuleKind::Imported: {
|
|
Optional<ClangTypeKind> lookupKind = getClangTypeKindForNodeKind(kind);
|
|
if (!lookupKind)
|
|
return nullptr;
|
|
importer->lookupTypeDecl(name, lookupKind.getValue(),
|
|
[&](TypeDecl *found) {
|
|
consumer.foundDecl(found, DeclVisibilityKind::VisibleAtTopLevel);
|
|
});
|
|
}
|
|
}
|
|
|
|
return consumer.Result;
|
|
}
|
|
|
|
namespace {
|
|
|
|
/// The basic implementation of the RemoteASTContext interface.
|
|
/// The template subclasses do target-specific logic.
|
|
class RemoteASTContextImpl {
|
|
std::unique_ptr<IRGenContext> IRGen;
|
|
public:
|
|
RemoteASTContextImpl() = default;
|
|
virtual ~RemoteASTContextImpl() = default;
|
|
|
|
virtual Result<Type>
|
|
getTypeForRemoteTypeMetadata(RemoteAddress metadata, bool skipArtificial) = 0;
|
|
virtual Result<MetadataKind>
|
|
getKindForRemoteTypeMetadata(RemoteAddress metadata) = 0;
|
|
virtual Result<NominalTypeDecl*>
|
|
getDeclForRemoteNominalTypeDescriptor(RemoteAddress descriptor) = 0;
|
|
virtual Result<RemoteAddress>
|
|
getHeapMetadataForObject(RemoteAddress object) = 0;
|
|
|
|
Result<uint64_t>
|
|
getOffsetOfMember(Type type, RemoteAddress optMetadata, StringRef memberName){
|
|
// Sanity check: obviously invalid arguments.
|
|
if (!type || memberName.empty())
|
|
return Result<uint64_t>::emplaceFailure(Failure::BadArgument);
|
|
|
|
// Sanity check: if the caller gave us a dependent type, there's no way
|
|
// we can handle that.
|
|
if (type->hasTypeParameter() || type->hasArchetype())
|
|
return Result<uint64_t>::emplaceFailure(Failure::DependentArgument);
|
|
|
|
// Split into cases.
|
|
if (auto typeDecl = type->getNominalOrBoundGenericNominal()) {
|
|
return getOffsetOfField(type, typeDecl, optMetadata, memberName);
|
|
} else if (auto tupleType = type->getAs<TupleType>()) {
|
|
return getOffsetOfTupleElement(tupleType, optMetadata, memberName);
|
|
} else {
|
|
return Result<uint64_t>::emplaceFailure(Failure::TypeHasNoSuchMember,
|
|
memberName);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
template <class T>
|
|
Result<T> getFailure() {
|
|
return getBuilder().getFailureAsResult<T>(Failure::Unknown);
|
|
}
|
|
|
|
template <class T, class KindTy, class... ArgTys>
|
|
Result<T> fail(KindTy kind, ArgTys &&...args) {
|
|
return Result<T>::emplaceFailure(kind, std::forward<ArgTys>(args)...);
|
|
}
|
|
|
|
private:
|
|
virtual RemoteASTTypeBuilder &getBuilder() = 0;
|
|
virtual MemoryReader &getReader() = 0;
|
|
virtual bool readWordOffset(RemoteAddress address, int64_t *offset) = 0;
|
|
virtual std::unique_ptr<IRGenContext> createIRGenContext() = 0;
|
|
virtual Result<uint64_t>
|
|
getOffsetOfTupleElementFromMetadata(RemoteAddress metadata,
|
|
unsigned elementIndex) = 0;
|
|
virtual Result<uint64_t>
|
|
getOffsetOfFieldFromMetadata(RemoteAddress metadata,
|
|
StringRef memberName) = 0;
|
|
|
|
IRGenContext *getIRGen() {
|
|
if (!IRGen) IRGen = createIRGenContext();
|
|
return IRGen.get();
|
|
}
|
|
|
|
Result<uint64_t>
|
|
getOffsetOfField(Type type, NominalTypeDecl *typeDecl,
|
|
RemoteAddress optMetadata, StringRef memberName) {
|
|
if (!isa<StructDecl>(typeDecl) && !isa<ClassDecl>(typeDecl))
|
|
return fail<uint64_t>(Failure::Unimplemented,
|
|
"access members of this kind of type");
|
|
|
|
// Try to find the member.
|
|
VarDecl *member = findField(typeDecl, memberName);
|
|
|
|
// If we found a member, try to find its offset statically.
|
|
if (member) {
|
|
if (auto irgen = getIRGen()) {
|
|
return getOffsetOfFieldFromIRGen(irgen->IGM, type, typeDecl,
|
|
optMetadata, member);
|
|
}
|
|
}
|
|
|
|
// Try searching the metadata for a member with the given name.
|
|
if (optMetadata) {
|
|
return getOffsetOfFieldFromMetadata(optMetadata, memberName);
|
|
}
|
|
|
|
// Okay, that's everything we know how to try.
|
|
|
|
// Use a specialized diagnostic if we couldn't find any such member.
|
|
if (!member) {
|
|
return fail<uint64_t>(Failure::TypeHasNoSuchMember, memberName);
|
|
}
|
|
|
|
return fail<uint64_t>(Failure::Unknown);
|
|
}
|
|
|
|
/// Look for an instance property of the given nominal type that's
|
|
/// known to be stored.
|
|
VarDecl *findField(NominalTypeDecl *typeDecl, StringRef memberName) {
|
|
for (auto field : typeDecl->getStoredProperties()) {
|
|
if (field->getName().str() == memberName)
|
|
return field;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
using MemberAccessStrategy = irgen::MemberAccessStrategy;
|
|
|
|
Result<uint64_t>
|
|
getOffsetOfFieldFromIRGen(irgen::IRGenModule &IGM, Type type,
|
|
NominalTypeDecl *typeDecl,
|
|
RemoteAddress optMetadata, VarDecl *member) {
|
|
SILType loweredTy = IGM.getSILTypes().getLoweredType(type);
|
|
|
|
MemberAccessStrategy strategy =
|
|
(isa<StructDecl>(typeDecl)
|
|
? getPhysicalStructMemberAccessStrategy(IGM, loweredTy, member)
|
|
: getPhysicalClassMemberAccessStrategy(IGM, loweredTy, member));
|
|
|
|
switch (strategy.getKind()) {
|
|
case MemberAccessStrategy::Kind::Complex:
|
|
return fail<uint64_t>(Failure::Unimplemented,
|
|
"access members with complex storage");
|
|
|
|
case MemberAccessStrategy::Kind::DirectFixed:
|
|
return uint64_t(strategy.getDirectOffset().getValue());
|
|
|
|
case MemberAccessStrategy::Kind::DirectGlobal: {
|
|
RemoteAddress directOffsetAddress =
|
|
getReader().getSymbolAddress(strategy.getDirectGlobalSymbol());
|
|
if (!directOffsetAddress)
|
|
return getFailure<uint64_t>();
|
|
|
|
return readDirectOffset(directOffsetAddress,
|
|
strategy.getDirectOffsetKind());
|
|
}
|
|
|
|
case MemberAccessStrategy::Kind::IndirectFixed: {
|
|
// We can't apply indirect offsets without metadata.
|
|
if (!optMetadata)
|
|
return fail<uint64_t>(Failure::Unimplemented,
|
|
"access generically-offset members without "
|
|
"metadata");
|
|
|
|
Size indirectOffset = strategy.getIndirectOffset();
|
|
return readIndirectOffset(optMetadata, indirectOffset,
|
|
strategy.getDirectOffsetKind());
|
|
}
|
|
|
|
case MemberAccessStrategy::Kind::IndirectGlobal: {
|
|
// We can't apply indirect offsets without metadata.
|
|
if (!optMetadata)
|
|
return fail<uint64_t>(Failure::Unimplemented,
|
|
"access generically-offset members without "
|
|
"metadata");
|
|
|
|
RemoteAddress indirectOffsetAddress =
|
|
getReader().getSymbolAddress(strategy.getIndirectGlobalSymbol());
|
|
|
|
Size indirectOffset;
|
|
if (!readOffset(indirectOffsetAddress,
|
|
strategy.getIndirectOffsetKind(),
|
|
indirectOffset))
|
|
return getFailure<uint64_t>();
|
|
|
|
return readIndirectOffset(optMetadata, indirectOffset,
|
|
strategy.getDirectOffsetKind());
|
|
}
|
|
}
|
|
llvm_unreachable("bad member MemberAccessStrategy");
|
|
}
|
|
|
|
bool readOffset(RemoteAddress address,
|
|
MemberAccessStrategy::OffsetKind kind,
|
|
Size &offset) {
|
|
switch (kind) {
|
|
case MemberAccessStrategy::OffsetKind::Bytes_Word: {
|
|
int64_t rawOffset;
|
|
if (!readWordOffset(address, &rawOffset))
|
|
return false;
|
|
offset = Size(rawOffset);
|
|
return true;
|
|
}
|
|
}
|
|
llvm_unreachable("bad offset kind");
|
|
}
|
|
|
|
Result<uint64_t> readIndirectOffset(RemoteAddress metadata,
|
|
Size indirectOffset,
|
|
MemberAccessStrategy::OffsetKind kind) {
|
|
RemoteAddress directOffsetAddress = metadata + indirectOffset;
|
|
return readDirectOffset(directOffsetAddress, kind);
|
|
}
|
|
|
|
|
|
Result<uint64_t> readDirectOffset(RemoteAddress directOffsetAddress,
|
|
MemberAccessStrategy::OffsetKind kind) {
|
|
Size directOffset;
|
|
if (!readOffset(directOffsetAddress, kind, directOffset))
|
|
return getFailure<uint64_t>();
|
|
|
|
return uint64_t(directOffset.getValue());
|
|
}
|
|
|
|
/// Read the
|
|
Result<uint64_t>
|
|
getOffsetOfTupleElement(TupleType *type, RemoteAddress optMetadata,
|
|
StringRef memberName) {
|
|
// Check that the member "name" is a valid index into the tuple.
|
|
unsigned targetIndex;
|
|
if (memberName.getAsInteger(10, targetIndex) ||
|
|
targetIndex >= type->getNumElements())
|
|
return fail<uint64_t>(Failure::TypeHasNoSuchMember, memberName);
|
|
|
|
// Fast path: element 0 is always at offset 0.
|
|
if (targetIndex == 0) return uint64_t(0);
|
|
|
|
// Create an IRGen instance.
|
|
auto irgen = getIRGen();
|
|
if (!irgen) return Result<uint64_t>::emplaceFailure(Failure::Unknown);
|
|
auto &IGM = irgen->IGM;
|
|
|
|
SILType loweredTy = IGM.getSILTypes().getLoweredType(type);
|
|
|
|
// If the type has a statically fixed offset, return that.
|
|
if (auto offset =
|
|
irgen::getFixedTupleElementOffset(IGM, loweredTy, targetIndex))
|
|
return offset->getValue();
|
|
|
|
// If we have metadata, go load from that.
|
|
if (optMetadata)
|
|
return getOffsetOfTupleElementFromMetadata(optMetadata, targetIndex);
|
|
|
|
// Okay, reproduce tuple layout.
|
|
|
|
// Find the last element with a known offset. Note that we don't
|
|
// have to ask IRGen about element 0 because we know its size is zero.
|
|
Size lastOffset = Size(0);
|
|
unsigned lastIndex = targetIndex;
|
|
for (--lastIndex; lastIndex != 0; --lastIndex) {
|
|
if (auto offset =
|
|
irgen::getFixedTupleElementOffset(IGM, loweredTy, lastIndex)) {
|
|
lastOffset = *offset;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Okay, iteratively build up from there.
|
|
for (; ; ++lastIndex) {
|
|
// Try to get the size and alignment of this element.
|
|
SILType eltTy = loweredTy.getTupleElementType(lastIndex);
|
|
auto sizeAndAlignment = getTypeSizeAndAlignment(IGM, eltTy);
|
|
if (!sizeAndAlignment) return getFailure<uint64_t>();
|
|
|
|
// Round up to the alignment of the element.
|
|
lastOffset = lastOffset.roundUpToAlignment(sizeAndAlignment->second);
|
|
|
|
// If this is the target, we're done.
|
|
if (lastIndex == targetIndex)
|
|
return lastOffset.getValue();
|
|
|
|
// Otherwise, skip forward by the size of the element.
|
|
lastOffset += sizeAndAlignment->first;
|
|
}
|
|
|
|
llvm_unreachable("didn't reach target index");
|
|
}
|
|
|
|
/// Attempt to discover the size and alignment of the given type.
|
|
Optional<std::pair<Size, Alignment>>
|
|
getTypeSizeAndAlignment(irgen::IRGenModule &IGM, SILType eltTy) {
|
|
auto &eltTI = IGM.getTypeInfo(eltTy);
|
|
if (auto fixedTI = dyn_cast<irgen::FixedTypeInfo>(&eltTI)) {
|
|
return std::make_pair(fixedTI->getFixedSize(),
|
|
fixedTI->getFixedAlignment());
|
|
}
|
|
|
|
// TODO: handle resilient types
|
|
return None;
|
|
}
|
|
};
|
|
|
|
/// A template for generating target-specific implementations of the
|
|
/// RemoteASTContext interface.
|
|
template <class Runtime>
|
|
class RemoteASTContextConcreteImpl final : public RemoteASTContextImpl {
|
|
MetadataReader<Runtime, RemoteASTTypeBuilder> Reader;
|
|
|
|
RemoteASTTypeBuilder &getBuilder() override {
|
|
return Reader.Builder;
|
|
}
|
|
|
|
MemoryReader &getReader() override {
|
|
return *Reader.Reader;
|
|
}
|
|
|
|
bool readWordOffset(RemoteAddress address, int64_t *extendedOffset) override {
|
|
using unsigned_size_t = typename Runtime::StoredSize;
|
|
using signed_size_t = typename std::make_signed<unsigned_size_t>::type;
|
|
signed_size_t offset;
|
|
if (!getReader().readInteger(address, &offset))
|
|
return false;
|
|
|
|
*extendedOffset = offset;
|
|
return true;
|
|
}
|
|
|
|
public:
|
|
RemoteASTContextConcreteImpl(std::shared_ptr<MemoryReader> &&reader,
|
|
ASTContext &ctx)
|
|
: Reader(std::move(reader), ctx) {}
|
|
|
|
Result<Type> getTypeForRemoteTypeMetadata(RemoteAddress metadata,
|
|
bool skipArtificial) override {
|
|
if (auto result = Reader.readTypeFromMetadata(metadata.getAddressData(),
|
|
skipArtificial))
|
|
return result;
|
|
return getFailure<Type>();
|
|
}
|
|
|
|
Result<MetadataKind>
|
|
getKindForRemoteTypeMetadata(RemoteAddress metadata) override {
|
|
auto result = Reader.readKindFromMetadata(metadata.getAddressData());
|
|
if (result)
|
|
return *result;
|
|
return getFailure<MetadataKind>();
|
|
}
|
|
|
|
Result<NominalTypeDecl*>
|
|
getDeclForRemoteNominalTypeDescriptor(RemoteAddress descriptor) override {
|
|
if (auto result =
|
|
Reader.readNominalTypeFromDescriptor(descriptor.getAddressData()))
|
|
return result;
|
|
return getFailure<NominalTypeDecl*>();
|
|
}
|
|
|
|
std::unique_ptr<IRGenContext> createIRGenContext() override {
|
|
return getBuilder().createIRGenContext();
|
|
}
|
|
|
|
Result<uint64_t>
|
|
getOffsetOfTupleElementFromMetadata(RemoteAddress metadata,
|
|
unsigned index) override {
|
|
typename Runtime::StoredSize offset;
|
|
if (Reader.readTupleElementOffset(metadata.getAddressData(),
|
|
index, &offset))
|
|
return uint64_t(offset);
|
|
return getFailure<uint64_t>();
|
|
}
|
|
|
|
Result<uint64_t>
|
|
getOffsetOfFieldFromMetadata(RemoteAddress metadata,
|
|
StringRef memberName) override {
|
|
// TODO: this would be useful for resilience
|
|
return fail<uint64_t>(Failure::Unimplemented,
|
|
"look up field offset by name");
|
|
}
|
|
|
|
Result<RemoteAddress>
|
|
getHeapMetadataForObject(RemoteAddress object) override {
|
|
auto result = Reader.readMetadataFromInstance(object.getAddressData());
|
|
if (result) return RemoteAddress(*result);
|
|
return getFailure<RemoteAddress>();
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
static RemoteASTContextImpl *createImpl(ASTContext &ctx,
|
|
std::shared_ptr<MemoryReader> &&reader) {
|
|
auto &target = ctx.LangOpts.Target;
|
|
assert(target.isArch32Bit() || target.isArch64Bit());
|
|
|
|
if (target.isArch32Bit()) {
|
|
using Target = External<RuntimeTarget<4>>;
|
|
return new RemoteASTContextConcreteImpl<Target>(std::move(reader), ctx);
|
|
} else {
|
|
using Target = External<RuntimeTarget<8>>;
|
|
return new RemoteASTContextConcreteImpl<Target>(std::move(reader), ctx);
|
|
}
|
|
}
|
|
|
|
static RemoteASTContextImpl *asImpl(void *impl) {
|
|
return static_cast<RemoteASTContextImpl*>(impl);
|
|
}
|
|
|
|
RemoteASTContext::RemoteASTContext(ASTContext &ctx,
|
|
std::shared_ptr<MemoryReader> reader)
|
|
: Impl(createImpl(ctx, std::move(reader))) {
|
|
}
|
|
|
|
RemoteASTContext::~RemoteASTContext() {
|
|
delete asImpl(Impl);
|
|
}
|
|
|
|
Result<Type>
|
|
RemoteASTContext::getTypeForRemoteTypeMetadata(RemoteAddress address,
|
|
bool skipArtificial) {
|
|
return asImpl(Impl)->getTypeForRemoteTypeMetadata(address, skipArtificial);
|
|
}
|
|
|
|
Result<MetadataKind>
|
|
RemoteASTContext::getKindForRemoteTypeMetadata(remote::RemoteAddress address) {
|
|
return asImpl(Impl)->getKindForRemoteTypeMetadata(address);
|
|
}
|
|
|
|
Result<NominalTypeDecl *>
|
|
RemoteASTContext::getDeclForRemoteNominalTypeDescriptor(RemoteAddress address) {
|
|
return asImpl(Impl)->getDeclForRemoteNominalTypeDescriptor(address);
|
|
}
|
|
|
|
Result<uint64_t>
|
|
RemoteASTContext::getOffsetOfMember(Type type, RemoteAddress optMetadata,
|
|
StringRef memberName) {
|
|
return asImpl(Impl)->getOffsetOfMember(type, optMetadata, memberName);
|
|
}
|
|
|
|
Result<remote::RemoteAddress>
|
|
RemoteASTContext::getHeapMetadataForObject(remote::RemoteAddress address) {
|
|
return asImpl(Impl)->getHeapMetadataForObject(address);
|
|
}
|