mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
259 lines
8.5 KiB
C++
259 lines
8.5 KiB
C++
//===--- 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 <memory>
|
|
|
|
namespace swift {
|
|
class ASTContext;
|
|
class NominalTypeDecl;
|
|
|
|
namespace remoteAST {
|
|
|
|
template <class T>
|
|
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 <class... ArgTys>
|
|
static Result emplaceSuccess(ArgTys &&...args) {
|
|
Result result(true);
|
|
::new (&result.S.Success) T(std::forward<ArgTys>(args)...);
|
|
return result;
|
|
}
|
|
|
|
template <class KindTy, class... ArgTys>
|
|
static Result emplaceFailure(KindTy kind, ArgTys &&...args) {
|
|
Result result(false);
|
|
::new (&result.S.Failure)
|
|
remote::Failure(kind, std::forward<ArgTys>(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<remote::MemoryReader> 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<Type>
|
|
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<MetadataKind>
|
|
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<NominalTypeDecl *>
|
|
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<uint64_t> getOffsetOfMember(Type type,
|
|
remote::RemoteAddress optMetadataAddress,
|
|
StringRef memberName);
|
|
|
|
/// Given a heap object, resolve its heap metadata.
|
|
Result<remote::RemoteAddress>
|
|
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<OpenedExistential>
|
|
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<OpenedExistential>
|
|
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<Type>
|
|
getUnderlyingTypeForOpaqueType(remote::RemoteAddress opaqueDescriptor,
|
|
SubstitutionMap substitutions,
|
|
unsigned ordinal);
|
|
|
|
};
|
|
|
|
} // end namespace remoteAST
|
|
} // end namespace swift
|
|
|
|
#endif // SWIFT_REMOTEAST_REMOTEAST_H
|