| //===--- 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/ASTDemangler.h" |
| #include "swift/AST/Decl.h" |
| #include "swift/AST/ExistentialLayout.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 "swift/Demangling/Demangler.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(), LLVMContext) {} |
| |
| static IRGenOptions createIRGenOptions() { |
| IRGenOptions IROpts; |
| 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)); |
| } |
| }; |
| |
| /// The basic implementation of the RemoteASTContext interface. |
| /// The template subclasses do target-specific logic. |
| class RemoteASTContextImpl { |
| std::unique_ptr<IRGenContext> IRGen; |
| Optional<Failure> CurFailure; |
| |
| 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; |
| virtual Result<std::pair<Type, RemoteAddress>> |
| getDynamicTypeAndAddressForExistential(RemoteAddress object, |
| Type staticType) = 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, 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)...); |
| } |
| |
| template <class T> |
| Result<T> getFailure() { |
| return 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 ASTBuilder &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 && member->hasStorage() && !typeDecl->isResilient()) { |
| 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, ASTBuilder> Reader; |
| |
| ASTBuilder &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 IRGenContext::create(getBuilder().getASTContext(), |
| getBuilder().getNotionalDC()); |
| } |
| |
| 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>(); |
| } |
| |
| Result<std::pair<Type, RemoteAddress>> |
| getDynamicTypeAndAddressClassExistential(RemoteAddress object) { |
| auto pointerval = Reader.readPointerValue(object.getAddressData()); |
| if (!pointerval) |
| return getFailure<std::pair<Type, RemoteAddress>>(); |
| auto result = Reader.readMetadataFromInstance(*pointerval); |
| if (!result) |
| return getFailure<std::pair<Type, RemoteAddress>>(); |
| auto typeResult = Reader.readTypeFromMetadata(result.getValue()); |
| if (!typeResult) |
| return getFailure<std::pair<Type, RemoteAddress>>(); |
| return std::make_pair<Type, RemoteAddress>(std::move(typeResult), |
| RemoteAddress(*pointerval)); |
| } |
| |
| Result<std::pair<Type, RemoteAddress>> |
| getDynamicTypeAndAddressErrorExistential(RemoteAddress object) { |
| auto pointerval = Reader.readPointerValue(object.getAddressData()); |
| if (!pointerval) |
| return getFailure<std::pair<Type, RemoteAddress>>(); |
| auto result = |
| Reader.readMetadataAndValueErrorExistential(RemoteAddress(*pointerval)); |
| if (!result) |
| return getFailure<std::pair<Type, RemoteAddress>>(); |
| RemoteAddress metadataAddress = result->first; |
| RemoteAddress valueAddress = result->second; |
| |
| auto typeResult = |
| Reader.readTypeFromMetadata(metadataAddress.getAddressData()); |
| if (!typeResult) |
| return getFailure<std::pair<Type, RemoteAddress>>(); |
| return std::make_pair<Type, RemoteAddress>(std::move(typeResult), |
| std::move(valueAddress)); |
| } |
| |
| Result<std::pair<Type, RemoteAddress>> |
| getDynamicTypeAndAddressOpaqueExistential(RemoteAddress object) { |
| auto result = Reader.readMetadataAndValueOpaqueExistential(object); |
| if (!result) |
| return getFailure<std::pair<Type, RemoteAddress>>(); |
| RemoteAddress metadataAddress = result->first; |
| RemoteAddress valueAddress = result->second; |
| |
| auto typeResult = |
| Reader.readTypeFromMetadata(metadataAddress.getAddressData()); |
| if (!typeResult) |
| return getFailure<std::pair<Type, RemoteAddress>>(); |
| return std::make_pair<Type, RemoteAddress>(std::move(typeResult), |
| std::move(valueAddress)); |
| } |
| |
| Result<std::pair<Type, RemoteAddress>> |
| getDynamicTypeAndAddressExistentialMetatype(RemoteAddress object) { |
| // The value of the address is just the input address. |
| // The type is obtained through the following sequence of steps: |
| // 1) Loading a pointer from the input address |
| // 2) Reading it as metadata and resolving the type |
| // 3) Wrapping the resolved type in an existential metatype. |
| auto pointerval = Reader.readPointerValue(object.getAddressData()); |
| if (!pointerval) |
| return getFailure<std::pair<Type, RemoteAddress>>(); |
| auto typeResult = Reader.readTypeFromMetadata(*pointerval); |
| if (!typeResult) |
| return getFailure<std::pair<Type, RemoteAddress>>(); |
| auto wrappedType = ExistentialMetatypeType::get(typeResult); |
| if (!wrappedType) |
| return getFailure<std::pair<Type, RemoteAddress>>(); |
| return std::make_pair<Type, RemoteAddress>(std::move(wrappedType), |
| std::move(object)); |
| } |
| |
| /// Resolve the dynamic type and the value address of an existential, |
| /// given its address and its static type. For class and error existentials, |
| /// this API takes a pointer to the instance reference rather than the |
| /// instance reference itself. |
| Result<std::pair<Type, RemoteAddress>> |
| getDynamicTypeAndAddressForExistential(RemoteAddress object, |
| Type staticType) override { |
| // If this is not an existential, give up. |
| if (!staticType->isAnyExistentialType()) |
| return getFailure<std::pair<Type, RemoteAddress>>(); |
| |
| // Handle the case where this is an ExistentialMetatype. |
| if (!staticType->isExistentialType()) |
| return getDynamicTypeAndAddressExistentialMetatype(object); |
| |
| // This should be an existential type at this point. |
| auto layout = staticType->getExistentialLayout(); |
| switch (layout.getKind()) { |
| case ExistentialLayout::Kind::Class: |
| return getDynamicTypeAndAddressClassExistential(object); |
| case ExistentialLayout::Kind::Error: |
| return getDynamicTypeAndAddressErrorExistential(object); |
| case ExistentialLayout::Kind::Opaque: |
| return getDynamicTypeAndAddressOpaqueExistential(object); |
| } |
| llvm_unreachable("invalid type kind"); |
| } |
| }; |
| |
| } // 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); |
| } |
| |
| Result<std::pair<Type, remote::RemoteAddress>> |
| RemoteASTContext::getDynamicTypeAndAddressForExistential( |
| remote::RemoteAddress address, Type staticType) { |
| return asImpl(Impl)->getDynamicTypeAndAddressForExistential(address, |
| staticType); |
| } |