//===--- RemoteAST.h - Relating remote metadata to local ASTs ---*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// // // The RemoteAST library defines interfaces for exploring the // relationships between a remote process and a local AST which provides // a (static and incomplete) picture of the code running in that process. // //===----------------------------------------------------------------------===// #ifndef SWIFT_REMOTEAST_REMOTEAST_H #define SWIFT_REMOTEAST_REMOTEAST_H #include "swift/Remote/Failure.h" #include "swift/Remote/MemoryReader.h" #include "swift/Basic/LLVM.h" #include "swift/ABI/MetadataValues.h" #include "swift/AST/Type.h" #include "llvm/ADT/StringRef.h" #include namespace swift { class ASTContext; class NominalTypeDecl; namespace remoteAST { template class Result { union Storage { remote::Failure Failure; T Success; Storage() {} Storage(const Storage &) = delete; Storage &operator=(const Storage &) = delete; ~Storage() {} }; Storage S; bool IsSuccess; Result(bool isSuccess) : IsSuccess(isSuccess) {} public: /*implicit*/ Result(const T &value) : IsSuccess(true) { new (&S.Success) T(value); } /*implicit*/ Result(T &&value) : IsSuccess(true) { new (&S.Success) T(std::move(value)); } /*implicit*/ Result(remote::Failure &&failure) : IsSuccess(false) { new (&S.Failure) remote::Failure(std::move(failure)); } Result(const Result &other) : IsSuccess(other.IsSuccess) { if (IsSuccess) { ::new (&S.Success) T(other.S.Success); } else { ::new (&S.Failure) remote::Failure(other.S.Failure); } } Result(Result &&other) : IsSuccess(other.IsSuccess) { if (IsSuccess) { ::new (&S.Success) T(std::move(other.S.Success)); } else { ::new (&S.Failure) remote::Failure(std::move(other.S.Failure)); } } Result &operator=(const Result &other) { this->~Result(); ::new (this) Result(other); return *this; } Result &operator=(Result &&other) { this->~Result(); ::new (this) Result(std::move(other)); return *this; } ~Result() { if (IsSuccess) { S.Success.~T(); } else { S.Failure.~Failure(); } } template static Result emplaceSuccess(ArgTys &&...args) { Result result(true); ::new (&result.S.Success) T(std::forward(args)...); return result; } template static Result emplaceFailure(KindTy kind, ArgTys &&...args) { Result result(false); ::new (&result.S.Failure) remote::Failure(kind, std::forward(args)...); return result; } explicit operator bool() const { return isSuccess(); } bool isSuccess() const { return IsSuccess; } bool isFailure() const { return !IsSuccess; } const remote::Failure &getFailure() const { assert(isFailure()); return S.Failure; } const T &getValue() const & { assert(isSuccess()); return S.Success; } T &&getValue() && { assert(isSuccess()); return std::move(S.Success); } }; /// A structure representing an opened existential value. struct OpenedExistential { /// The concrete type of the value inside the existential. Type InstanceType; /// The address of the payload. /// /// Note: If the concrete type is a class type, this is the address of the /// instance and not the address of the reference to the instance. remote::RemoteAddress PayloadAddress; OpenedExistential(Type InstanceType, remote::RemoteAddress PayloadAddress) : InstanceType(InstanceType), PayloadAddress(PayloadAddress) {} }; /// A context for performing an operation relating the remote process with /// the AST. This may be discarded and recreated at any time without danger, /// but reusing a context across multiple calls may allow some redundant work /// to be avoided. /// /// The operations on this type must not assert or crash for any of the /// following reasons: /// - the parameters do not satisfy preconditions /// - the memory reader fails for any reason /// - the remote address is invalid /// - the remote address space is corrupt /// - the remote address space contains valid-seeming constructs that /// somehow violate local well-formedness rules /// - the local AST does not contain information for the remote construct /// /// The operations on this type *may* misbehave if the invariants of /// the local AST have been violated. This should not be a problem if the /// local AST is the result of ordinary type-checking. class RemoteASTContext { void *Impl; public: explicit RemoteASTContext(ASTContext &ctx, std::shared_ptr reader); RemoteASTContext(const RemoteASTContext &) = delete; RemoteASTContext &operator=(const RemoteASTContext &) = delete; ~RemoteASTContext(); /// Given an address which is supposedly of type metadata, try to /// resolve it to a specific type in the local AST. /// /// \param skipArtificial If true, the address may be an artificial type /// wrapper that should be ignored. For example, it could be a /// dynamic subclass created by (e.g.) CoreData or KVO; if so, and this /// flag is set, this method will implicitly ignore the subclass /// and instead attempt to resolve a type for the first non-artificial /// superclass. See [NOTE: Dynamic-subclass-KVO]. Result getTypeForRemoteTypeMetadata(remote::RemoteAddress address, bool skipArtificial = false); /// Given an address which is supposedly of type metadata, try to /// resolve it to a specific MetadataKind value for its backing type. Result getKindForRemoteTypeMetadata(remote::RemoteAddress address); /// Given an address which is supposedly of a nominal type descriptor, /// try to resolve it to a specific nominal type declaration in the /// local AST. Result getDeclForRemoteNominalTypeDescriptor(remote::RemoteAddress address); /// Given a type in the local AST, try to resolve the offset of its /// member with the given name. This supports: /// /// - stored properties of structs /// - stored properties of classes /// - elements of tuples /// /// Failure may indicate that an offset for the property could not be /// resolved, or it may simply indicate that the property is not laid /// out at a known offset. /// /// If the caller has the address of type metadata for the type, it may /// pass it in; this may allow the implementation to compute an offset in /// situations where it otherwise cannot. Result getOffsetOfMember(Type type, remote::RemoteAddress optMetadataAddress, StringRef memberName); /// Given a heap object, resolve its heap metadata. Result getHeapMetadataForObject(remote::RemoteAddress address); /// Resolve the dynamic type and the value address of an error existential /// object, Unlike getDynamicTypeAndAddressForExistential(), this function /// takes the address of the instance and not the address of the reference. Result getDynamicTypeAndAddressForError(remote::RemoteAddress object); /// Given an existential and its static type, resolve its dynamic /// type and address. A single step of unwrapping is performed, i.e. if the /// value stored inside the existential is itself an existential, the /// caller can decide whether to iterate itself. Result getDynamicTypeAndAddressForExistential(remote::RemoteAddress address, Type staticType); /// Given a reference to an opaque type descriptor, an ordinal, and a set /// of substitutions, get the underlying type for the opaque type. /// /// This does not recursively apply the transformation if the underlying /// type in turn refers to another opaque type. Result getUnderlyingTypeForOpaqueType(remote::RemoteAddress opaqueDescriptor, SubstitutionMap substitutions, unsigned ordinal); }; } // end namespace remoteAST } // end namespace swift #endif // SWIFT_REMOTEAST_REMOTEAST_H