//===--- RemoteAST.cpp ----------------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://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/Subsystems.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/Types.h" #include "swift/ClangImporter/ClangImporter.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 SILMod; llvm::LLVMContext LLVMContext; irgen::IRGenerator IRGen; irgen::IRGenModule IGM; private: IRGenContext(ASTContext &ctx, ModuleDecl *module) : SILMod(SILModule::createEmptyModule(module, SILOpts)), IRGen(IROpts, *SILMod), IGM(IRGen, IRGen.createTargetMachine(), /*SourceFile*/ nullptr, LLVMContext, "", "") { } public: static std::unique_ptr create(ASTContext &ctx, DeclContext *nominalDC) { auto module = nominalDC->getParentModule(); return std::unique_ptr(new IRGenContext(ctx, module)); } }; /// An implementation of MetadataReader's BuilderType concept that /// just finds and builds things in the AST. class RemoteASTTypeBuilder { ASTContext &Ctx; /// The notional context in which we're writing and type-checking code. /// Created lazily. DeclContext *NotionalDC = nullptr; Optional CurFailure; public: using BuiltType = swift::Type; using BuiltNominalTypeDecl = swift::NominalTypeDecl*; explicit RemoteASTTypeBuilder(ASTContext &ctx) : Ctx(ctx) {} std::unique_ptr createIRGenContext() { return IRGenContext::create(Ctx, getNotionalDC()); } template Result fail(FailureKindTy kind, FailureArgTys &&...failureArgs) { if (!CurFailure) { CurFailure.emplace(kind, std::forward(failureArgs)...); } return Result(); } template Result getFailureAsResult(DefaultFailureKindTy defaultFailureKind, DefaultFailureArgTys &&...defaultFailureArgs) { // If we already have a failure, use that. if (CurFailure) { Result result = std::move(*CurFailure); CurFailure.reset(); return result; } // Otherwise, use the default failure. return Result::emplaceFailure(defaultFailureKind, std::forward(defaultFailureArgs)...); } Type createBuiltinType(const std::string &mangledName) { // TODO return Type(); } NominalTypeDecl *createNominalTypeDecl(StringRef mangledName) { auto node = Demangle::demangleTypeAsNode(mangledName); if (!node) return nullptr; return createNominalTypeDecl(node); } NominalTypeDecl *createNominalTypeDecl(const Demangle::NodePointer &node); Type createNominalType(NominalTypeDecl *decl, Type parent) { // If the declaration is generic, fail. if (decl->getGenericSignature()) return Type(); // Validate the parent type. if (!validateNominalParent(decl, parent)) return Type(); return NominalType::get(decl, parent, Ctx); } Type createBoundGenericType(NominalTypeDecl *decl, ArrayRef args, Type parent) { // If the declaration isn't generic, fail. if (!decl->getGenericSignature()) 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); GenericIdentTypeRepr genericRepr(SourceLoc(), decl->getName(), genericArgReprs.getList(), SourceRange()); genericRepr.setValue(decl); 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 ancestry; for (auto p = parent; p; p = p->getNominalParent()) { ancestry.push_back(p); } struct GenericRepr { TypeReprList GenericArgs; GenericIdentTypeRepr Ident; GenericRepr(BoundGenericType *type) : GenericArgs(type->getGenericArgs()), Ident(SourceLoc(), type->getDecl()->getName(), GenericArgs.getList(), SourceRange()) { Ident.setValue(type->getDecl()); } // 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(SourceLoc(), Identifier(), {}, SourceRange()) { llvm_unreachable("should not be called dynamically"); } }; // Pre-allocate the component vectors so that we can form references // into them safely. SmallVector simpleComponents; SmallVector genericComponents; simpleComponents.reserve(ancestry.size()); genericComponents.reserve(ancestry.size()); // Build the parent hierarchy. SmallVector componentReprs; for (size_t i = ancestry.size(); i != 0; --i) { Type p = ancestry[i - 1]; if (auto boundGeneric = p->getAs()) { genericComponents.emplace_back(boundGeneric); componentReprs.push_back(&genericComponents.back().Ident); } else { auto nominal = p->castTo(); simpleComponents.emplace_back(SourceLoc(), nominal->getDecl()->getName()); componentReprs.push_back(&simpleComponents.back()); } } CompoundIdentTypeRepr compoundRepr(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()) { if (bgt->getDecl() != decl) return Type(); } return genericType; } Type createTupleType(ArrayRef eltTypes, StringRef labels, bool isVariadic) { // Just bail out on variadic tuples for now. if (isVariadic) return Type(); SmallVector 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 args, const std::vector &inOutArgs, Type output, FunctionTypeFlags flags) { assert(args.size() == inOutArgs.size()); 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, /*noreturn*/ false, /*throws*/ flags.throws()); // The result type must be materializable. if (!output->isMaterializable()) return Type(); // All the argument types must be materializable (before inout is applied). for (auto arg : args) { if (!arg->isMaterializable()) return Type(); } Type input; if (args.size() == 1) { input = args[0]; } else { SmallVector elts; elts.reserve(args.size()); for (auto i : indices(args)) { Type arg = args[i]; if (inOutArgs[i]) arg = InOutType::get(arg); elts.push_back(arg); } } return FunctionType::get(input, output, einfo); } Type createProtocolType(StringRef mangledName, StringRef moduleName, StringRef protocolName) { auto module = Ctx.getModuleByName(moduleName); if (!module) return Type(); Identifier name = Ctx.getIdentifier(protocolName); auto decl = findNominalTypeDecl(module, name, Identifier(), Demangle::Node::Kind::Protocol); if (!decl) return Type(); return decl->getDeclaredType(); } Type createProtocolCompositionType(ArrayRef protocols) { for (auto protocol : protocols) { if (!protocol->is()) return Type(); } return ProtocolCompositionType::get(Ctx, protocols); } Type createExistentialMetatypeType(Type instance) { if (!instance->isAnyExistentialType()) return Type(); return ExistentialMetatypeType::get(instance); } Type createMetatypeType(Type instance) { return MetatypeType::get(instance); } Type createGenericTypeParameterType(unsigned depth, unsigned index) { return GenericTypeParamType::get(depth, index, Ctx); } Type createDependentMemberType(StringRef member, Type base, Type protocol) { if (!base->isTypeParameter()) return Type(); // TODO: look up protocol? return DependentMemberType::get(base, Ctx.getIdentifier(member), Ctx); } 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 createObjCClassType(StringRef name) { Identifier ident = Ctx.getIdentifier(name); auto typeDecl = findForeignNominalTypeDecl(ident, 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); bool isForeignModule(const Demangle::NodePointer &node); NominalTypeDecl *findNominalTypeDecl(DeclContext *dc, Identifier name, Identifier privateDiscriminator, Demangle::Node::Kind kind); NominalTypeDecl *findForeignNominalTypeDecl(Identifier name, Demangle::Node::Kind kind); Type checkTypeRepr(TypeRepr *repr) { DeclContext *dc = getNotionalDC(); TypeLoc loc(repr); if (performTypeLocChecking(Ctx, loc, /*SILType*/ false, 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(decl); } else if (kind == Demangle::Node::Kind::Enum) { return dyn_cast(decl); } else if (kind == Demangle::Node::Kind::Protocol) { return dyn_cast(decl); } else { assert(kind == Demangle::Node::Kind::Structure); return dyn_cast(decl); } } DeclContext *getNotionalDC() { if (!NotionalDC) { NotionalDC = ModuleDecl::create(Ctx.getIdentifier(".RemoteAST"), Ctx); NotionalDC = new (Ctx) TopLevelCodeDecl(NotionalDC); } return NotionalDC; } class TypeReprList { SmallVector Reprs; SmallVector Refs; public: explicit TypeReprList(ArrayRef types) { Reprs.reserve(types.size()); Refs.reserve(types.size()); for (auto type : types) { Reprs.emplace_back(type, SourceLoc()); Refs.push_back(&Reprs.back()); } } ArrayRef getList() const { return Refs; } }; }; } NominalTypeDecl * RemoteASTTypeBuilder::createNominalTypeDecl(const Demangle::NodePointer &node) { auto DC = findDeclContext(node); if (!DC) { return fail(Failure::CouldNotResolveTypeDecl, Demangle::mangleNode(node)); } auto decl = dyn_cast(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()); } bool RemoteASTTypeBuilder::isForeignModule(const Demangle::NodePointer &node) { if (node->getKind() == Demangle::Node::Kind::DeclContext) return isForeignModule(node->getFirstChild()); if (node->getKind() != Demangle::Node::Kind::Module) return false; return (node->getText() == "__ObjC"); } 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: { 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(decl); } Identifier name; Identifier privateDiscriminator; if (declNameNode->getKind() == Demangle::Node::Kind::Identifier) { name = Ctx.getIdentifier(declNameNode->getText()); } else if (declNameNode->getKind() == Demangle::Node::Kind::PrivateDeclName) { name = Ctx.getIdentifier(declNameNode->getChild(1)->getText()); privateDiscriminator = Ctx.getIdentifier(declNameNode->getChild(0)->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() && isForeignModule(node->getChild(0))) { return findForeignNominalTypeDecl(name, node->getKind()); } else { return nullptr; } } return findNominalTypeDecl(dc, name, privateDiscriminator, node->getKind()); } // 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 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; } NominalTypeDecl * RemoteASTTypeBuilder::findForeignNominalTypeDecl(Identifier name, Demangle::Node::Kind kind) { // Check to see if we have an importer loaded. auto importer = static_cast(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; auto typeDecl = getAcceptableNominalTypeCandidate(decl, ExpectedKind); if (!typeDecl) return; if (typeDecl == Result) return; if (!Result) { Result = typeDecl; } else { HadError = true; Result = nullptr; } } } consumer(kind); importer->lookupValue(name, consumer); return consumer.Result; } namespace { /// The basic implementation of the RemoteASTContext interface. /// The template subclasses do target-specific logic. class RemoteASTContextImpl { std::unique_ptr IRGen; public: RemoteASTContextImpl() = default; virtual ~RemoteASTContextImpl() = default; virtual Result getTypeForRemoteTypeMetadata(RemoteAddress metadata) = 0; virtual Result getKindForRemoteTypeMetadata(RemoteAddress metadata) = 0; virtual Result getDeclForRemoteNominalTypeDescriptor(RemoteAddress descriptor) = 0; Result getOffsetOfMember(Type type, RemoteAddress optMetadata, StringRef memberName){ // Sanity check: obviously invalid arguments. if (!type || memberName.empty()) return Result::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::emplaceFailure(Failure::DependentArgument); // Split into cases. if (auto typeDecl = type->getNominalOrBoundGenericNominal()) { return getOffsetOfField(type, typeDecl, optMetadata, memberName); } else if (auto tupleType = type->getAs()) { return getOffsetOfTupleElement(tupleType, optMetadata, memberName); } else { return Result::emplaceFailure(Failure::TypeHasNoSuchMember, memberName); } } protected: template Result getFailure() { return getBuilder().getFailureAsResult(Failure::Unknown); } private: virtual RemoteASTTypeBuilder &getBuilder() = 0; virtual MemoryReader &getReader() = 0; virtual bool readWordOffset(RemoteAddress address, int64_t *offset) = 0; virtual std::unique_ptr createIRGenContext() = 0; virtual Result getOffsetOfTupleElementFromMetadata(RemoteAddress metadata, unsigned elementIndex) = 0; virtual Result getOffsetOfFieldFromMetadata(RemoteAddress metadata, StringRef memberName) = 0; IRGenContext *getIRGen() { if (!IRGen) IRGen = createIRGenContext(); return IRGen.get(); } template Result fail(KindTy kind, ArgTys &&...args) { return Result::emplaceFailure(kind, std::forward(args)...); } Result getOffsetOfField(Type type, NominalTypeDecl *typeDecl, RemoteAddress optMetadata, StringRef memberName) { if (!isa(typeDecl) && !isa(typeDecl)) return fail(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(Failure::TypeHasNoSuchMember, memberName); } return fail(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 getOffsetOfFieldFromIRGen(irgen::IRGenModule &IGM, Type type, NominalTypeDecl *typeDecl, RemoteAddress optMetadata, VarDecl *member) { SILType loweredTy = IGM.getSILTypes().getLoweredType(type); MemberAccessStrategy strategy = (isa(typeDecl) ? getPhysicalStructMemberAccessStrategy(IGM, loweredTy, member) : getPhysicalClassMemberAccessStrategy(IGM, loweredTy, member)); switch (strategy.getKind()) { case MemberAccessStrategy::Kind::Complex: return fail(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(); return readDirectOffset(directOffsetAddress, strategy.getDirectOffsetKind()); } case MemberAccessStrategy::Kind::IndirectFixed: { // We can't apply indirect offsets without metadata. if (!optMetadata) return fail(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(Failure::Unimplemented, "access generically-offset members without " "metadata"); RemoteAddress indirectOffsetAddress = getReader().getSymbolAddress(strategy.getIndirectGlobalSymbol()); Size indirectOffset; if (!readOffset(indirectOffsetAddress, strategy.getIndirectOffsetKind(), indirectOffset)) return getFailure(); 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 readIndirectOffset(RemoteAddress metadata, Size indirectOffset, MemberAccessStrategy::OffsetKind kind) { RemoteAddress directOffsetAddress = metadata + indirectOffset; return readDirectOffset(directOffsetAddress, kind); } Result readDirectOffset(RemoteAddress directOffsetAddress, MemberAccessStrategy::OffsetKind kind) { Size directOffset; if (!readOffset(directOffsetAddress, kind, directOffset)) return getFailure(); return uint64_t(directOffset.getValue()); } /// Read the Result 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(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::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(); // 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> getTypeSizeAndAlignment(irgen::IRGenModule &IGM, SILType eltTy) { auto &eltTI = IGM.getTypeInfo(eltTy); if (auto fixedTI = dyn_cast(&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 RemoteASTContextConcreteImpl final : public RemoteASTContextImpl { MetadataReader 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::type; signed_size_t offset; if (!getReader().readInteger(address, &offset)) return false; *extendedOffset = offset; return true; } public: RemoteASTContextConcreteImpl(std::shared_ptr &&reader, ASTContext &ctx) : Reader(std::move(reader), ctx) {} Result getTypeForRemoteTypeMetadata(RemoteAddress metadata) override { if (auto result = Reader.readTypeFromMetadata(metadata.getAddressData())) return result; return getFailure(); } Result getKindForRemoteTypeMetadata(RemoteAddress metadata) override { auto result = Reader.readKindFromMetadata(metadata.getAddressData()); if (result.first) return result.second; return getFailure(); } Result getDeclForRemoteNominalTypeDescriptor(RemoteAddress descriptor) override { if (auto result = Reader.readNominalTypeFromDescriptor(descriptor.getAddressData())) return result; return getFailure(); } std::unique_ptr createIRGenContext() override { return getBuilder().createIRGenContext(); } Result getOffsetOfTupleElementFromMetadata(RemoteAddress metadata, unsigned index) override { typename Runtime::StoredSize offset; if (Reader.readTupleElementOffset(metadata.getAddressData(), index, &offset)) return uint64_t(offset); return getFailure(); } Result getOffsetOfFieldFromMetadata(RemoteAddress metadata, StringRef memberName) override { // TODO: this would be useful for resilience return fail(Failure::Unimplemented, "look up field offset by name"); } }; } // end anonymous namespace static RemoteASTContextImpl *createImpl(ASTContext &ctx, std::shared_ptr &&reader) { auto &target = ctx.LangOpts.Target; assert(target.isArch32Bit() || target.isArch64Bit()); if (target.isArch32Bit()) { using Target = External>; return new RemoteASTContextConcreteImpl(std::move(reader), ctx); } else { using Target = External>; return new RemoteASTContextConcreteImpl(std::move(reader), ctx); } } static RemoteASTContextImpl *asImpl(void *impl) { return static_cast(impl); } RemoteASTContext::RemoteASTContext(ASTContext &ctx, std::shared_ptr reader) : Impl(createImpl(ctx, std::move(reader))) { } RemoteASTContext::~RemoteASTContext() { delete asImpl(Impl); } Result RemoteASTContext::getTypeForRemoteTypeMetadata(RemoteAddress address) { return asImpl(Impl)->getTypeForRemoteTypeMetadata(address); } Result RemoteASTContext::getKindForRemoteTypeMetadata(remote::RemoteAddress address) { return asImpl(Impl)->getKindForRemoteTypeMetadata(address); } Result RemoteASTContext::getDeclForRemoteNominalTypeDescriptor(RemoteAddress address) { return asImpl(Impl)->getDeclForRemoteNominalTypeDescriptor(address); } Result RemoteASTContext::getOffsetOfMember(Type type, RemoteAddress optMetadata, StringRef memberName) { return asImpl(Impl)->getOffsetOfMember(type, optMetadata, memberName); }