Template metadata structures

- Add RuntimeTarget template This will allow for converting between
  metadata structures for native host and remote target architectures.

- Create InProcess and External templates for stored pointers

Add a few more types to abstract pointer access in the runtime
structures but keep native in-process pointer access the same as that
with a plain old pointer type.

There is now a notion of a "stored pointer", which is just the raw value
of the pointer, and the actual pointer type, which is used for loads.
Decoupling these allows us to fork the behavior when looking at metadata
in an external process, but keep things the same for the in-process
case.

There are two basic "runtime targets" that you can use to work with
metadata:

InProcess: Defines the pointer to be trivially a T* and stored as a
uintptr_t. A Metadata * is exactly as it was before, but defined via
AbstractMetadata<InProcess>.

External: A template that requires a target to specify its pointer size.

ExternalPointer: An opaque pointer in another address space that can't
(and shouldn't) be indirected with operator* or operator->.  The memory
reader will fetch the data explicitly.
This commit is contained in:
David Farler
2016-02-24 23:55:01 -08:00
parent 744806a742
commit cd65a8e0b0
12 changed files with 524 additions and 277 deletions

View File

@@ -26,11 +26,13 @@
namespace swift { namespace swift {
struct Metadata; struct InProcess;
template <typename Runtime> struct TargetMetadata;
using Metadata = TargetMetadata<InProcess>;
/// Kinds of Swift metadata records. Some of these are types, some /// Kinds of Swift metadata records. Some of these are types, some
/// aren't. /// aren't.
enum class MetadataKind : uintptr_t { enum class MetadataKind : uint32_t {
#define METADATAKIND(name, value) name = value, #define METADATAKIND(name, value) name = value,
#define ABSTRACTMETADATAKIND(name, start, end) \ #define ABSTRACTMETADATAKIND(name, start, end) \
name##_Start = start, name##_End = end, name##_Start = start, name##_End = end,
@@ -38,7 +40,7 @@ enum class MetadataKind : uintptr_t {
}; };
/// Kinds of Swift nominal type descriptor records. /// Kinds of Swift nominal type descriptor records.
enum class NominalTypeKind : uintptr_t { enum class NominalTypeKind : uint32_t {
#define NOMINALTYPEMETADATAKIND(name, value) name = value, #define NOMINALTYPEMETADATAKIND(name, value) name = value,
#include "MetadataKind.def" #include "MetadataKind.def"
}; };

View File

@@ -83,15 +83,18 @@ static inline void crash(const char *message) {
LLVM_ATTRIBUTE_NORETURN LLVM_ATTRIBUTE_NORETURN
extern void extern void
fatalError(uint32_t flags, const char *format, ...); fatalError(uint32_t flags, const char *format, ...);
struct InProcess;
struct Metadata; template <typename Runtime> struct TargetMetadata;
using Metadata = TargetMetadata<InProcess>;
// swift_dynamicCastFailure halts using fatalError() // swift_dynamicCastFailure halts using fatalError()
// with a description of a failed cast's types. // with a description of a failed cast's types.
LLVM_ATTRIBUTE_NORETURN LLVM_ATTRIBUTE_NORETURN
void void
swift_dynamicCastFailure(const swift::Metadata *sourceType, swift_dynamicCastFailure(const Metadata *sourceType,
const swift::Metadata *targetType, const Metadata *targetType,
const char *message = nullptr); const char *message = nullptr);
// swift_dynamicCastFailure halts using fatalError() // swift_dynamicCastFailure halts using fatalError()

View File

@@ -23,8 +23,14 @@ namespace swift {
struct OpaqueValue; struct OpaqueValue;
struct ValueWitnessTable; struct ValueWitnessTable;
struct Metadata;
struct EnumMetadata; struct InProcess;
template <typename Runtime> struct TargetMetadata;
using Metadata = TargetMetadata<InProcess>;
template <typename Runtime> struct TargetEnumMetadata;
using EnumMetadata = TargetEnumMetadata<InProcess>;
struct TypeLayout; struct TypeLayout;
/// \brief Initialize the value witness table for a generic, single-payload /// \brief Initialize the value witness table for a generic, single-payload

View File

@@ -29,9 +29,15 @@
#include "../../../stdlib/public/SwiftShims/HeapObject.h" #include "../../../stdlib/public/SwiftShims/HeapObject.h"
namespace swift { namespace swift {
struct InProcess;
template <typename Runtime> struct TargetMetadata;
using Metadata = TargetMetadata<InProcess>;
template <typename Runtime> struct TargetHeapMetadata;
using HeapMetadata = TargetHeapMetadata<InProcess>;
struct Metadata;
struct HeapMetadata;
struct OpaqueValue; struct OpaqueValue;
/// Allocates a new heap object. The returned memory is /// Allocates a new heap object. The returned memory is

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,9 @@ struct objc_class;
namespace swift { namespace swift {
struct Metadata; template <typename Runtime> struct TargetMetadata;
using Metadata = TargetMetadata<InProcess>;
struct HeapObject; struct HeapObject;
} // end namespace swift } // end namespace swift

View File

@@ -19,9 +19,14 @@
#include "swift/Basic/type_traits.h" #include "swift/Basic/type_traits.h"
namespace swift { namespace swift {
#endif
struct HeapMetadata; struct InProcess;
template <typename Target> struct TargetHeapMetadata;
using HeapMetadata = TargetHeapMetadata<InProcess>;
#else
typedef struct HeapMetadata HeapMetadata;
#endif
// The members of the HeapObject header that are not shared by a // The members of the HeapObject header that are not shared by a
// standard Objective-C instance // standard Objective-C instance
@@ -32,7 +37,7 @@ struct HeapMetadata;
/// The Swift heap-object header. /// The Swift heap-object header.
struct HeapObject { struct HeapObject {
/// This is always a valid pointer to a metadata object. /// This is always a valid pointer to a metadata object.
struct HeapMetadata const *metadata; HeapMetadata const *metadata;
SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS; SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
// FIXME: allocate two words of metadata on 32-bit platforms // FIXME: allocate two words of metadata on 32-bit platforms

View File

@@ -23,8 +23,17 @@
#include "Visibility.h" #include "Visibility.h"
#ifdef __cplusplus #ifdef __cplusplus
namespace swift { extern "C" { namespace swift {
template <unsigned PointerSize> struct RuntimeTarget;
using HostTarget = RuntimeTarget<sizeof(uintptr_t)>;
template <typename Target> struct TargetMetadata;
using Metadata = TargetMetadata<InProcess>;
extern "C" {
#else #else
typedef struct Metadata Metadata;
#define bool _Bool #define bool _Bool
#endif #endif
@@ -49,14 +58,11 @@ const char *_swift_stdlib_strtod_clocale(const char *nptr, double *outResult);
/// overflow. /// overflow.
SWIFT_RUNTIME_STDLIB_INTERFACE SWIFT_RUNTIME_STDLIB_INTERFACE
const char *_swift_stdlib_strtof_clocale(const char *nptr, float *outResult); const char *_swift_stdlib_strtof_clocale(const char *nptr, float *outResult);
struct Metadata;
/// Return the superclass, if any. The result is nullptr for root /// Return the superclass, if any. The result is nullptr for root
/// classes and class protocol types. /// classes and class protocol types.
SWIFT_RUNTIME_EXPORT SWIFT_RUNTIME_EXPORT
const struct Metadata *swift_class_getSuperclass( const Metadata *swift_class_getSuperclass(const Metadata *);
const struct Metadata *);
SWIFT_RUNTIME_STDLIB_INTERFACE SWIFT_RUNTIME_STDLIB_INTERFACE
void _swift_stdlib_flockfile_stdout(void); void _swift_stdlib_flockfile_stdout(void);

View File

@@ -2071,7 +2071,7 @@ getExistentialValueWitnesses(ExistentialTypeState &E,
} }
} }
ExistentialTypeRepresentation template<> ExistentialTypeRepresentation
ExistentialTypeMetadata::getRepresentation() const { ExistentialTypeMetadata::getRepresentation() const {
// Some existentials use special containers. // Some existentials use special containers.
switch (Flags.getSpecialProtocol()) { switch (Flags.getSpecialProtocol()) {
@@ -2088,7 +2088,7 @@ ExistentialTypeMetadata::getRepresentation() const {
return ExistentialTypeRepresentation::Opaque; return ExistentialTypeRepresentation::Opaque;
} }
bool template<> bool
ExistentialTypeMetadata::mayTakeValue(const OpaqueValue *container) const { ExistentialTypeMetadata::mayTakeValue(const OpaqueValue *container) const {
switch (getRepresentation()) { switch (getRepresentation()) {
// Owning a reference to a class existential is equivalent to owning a // Owning a reference to a class existential is equivalent to owning a
@@ -2112,7 +2112,7 @@ ExistentialTypeMetadata::mayTakeValue(const OpaqueValue *container) const {
} }
} }
void template<> void
ExistentialTypeMetadata::deinitExistentialContainer(OpaqueValue *container) ExistentialTypeMetadata::deinitExistentialContainer(OpaqueValue *container)
const { const {
switch (getRepresentation()) { switch (getRepresentation()) {
@@ -2135,7 +2135,7 @@ const {
} }
} }
const OpaqueValue * template<> const OpaqueValue *
ExistentialTypeMetadata::projectValue(const OpaqueValue *container) const { ExistentialTypeMetadata::projectValue(const OpaqueValue *container) const {
switch (getRepresentation()) { switch (getRepresentation()) {
case ExistentialTypeRepresentation::Class: { case ExistentialTypeRepresentation::Class: {
@@ -2161,7 +2161,7 @@ ExistentialTypeMetadata::projectValue(const OpaqueValue *container) const {
} }
} }
const Metadata * template<> const Metadata *
ExistentialTypeMetadata::getDynamicType(const OpaqueValue *container) const { ExistentialTypeMetadata::getDynamicType(const OpaqueValue *container) const {
switch (getRepresentation()) { switch (getRepresentation()) {
case ExistentialTypeRepresentation::Class: { case ExistentialTypeRepresentation::Class: {
@@ -2183,7 +2183,7 @@ ExistentialTypeMetadata::getDynamicType(const OpaqueValue *container) const {
} }
} }
const WitnessTable * template<> const WitnessTable *
ExistentialTypeMetadata::getWitnessTable(const OpaqueValue *container, ExistentialTypeMetadata::getWitnessTable(const OpaqueValue *container,
unsigned i) const { unsigned i) const {
assert(i < Flags.getNumWitnessTables()); assert(i < Flags.getNumWitnessTables());
@@ -2388,37 +2388,7 @@ swift::swift_getForeignTypeMetadata(ForeignTypeMetadata *nonUnique) {
/*** Other metadata routines ***********************************************/ /*** Other metadata routines ***********************************************/
const NominalTypeDescriptor * template<> const GenericMetadata *
Metadata::getNominalTypeDescriptor() const {
switch (getKind()) {
case MetadataKind::Class: {
const ClassMetadata *cls = static_cast<const ClassMetadata *>(this);
if (!cls->isTypeMetadata())
return nullptr;
if (cls->isArtificialSubclass())
return nullptr;
return cls->getDescription();
}
case MetadataKind::Struct:
case MetadataKind::Enum:
case MetadataKind::Optional:
return static_cast<const StructMetadata *>(this)->Description;
case MetadataKind::ForeignClass:
case MetadataKind::Opaque:
case MetadataKind::Tuple:
case MetadataKind::Function:
case MetadataKind::Existential:
case MetadataKind::ExistentialMetatype:
case MetadataKind::Metatype:
case MetadataKind::ObjCClassWrapper:
case MetadataKind::HeapLocalVariable:
case MetadataKind::HeapGenericLocalVariable:
case MetadataKind::ErrorObject:
return nullptr;
}
}
const GenericMetadata *
Metadata::getGenericPattern() const { Metadata::getGenericPattern() const {
auto ntd = getNominalTypeDescriptor(); auto ntd = getNominalTypeDescriptor();
if (!ntd) if (!ntd)
@@ -2426,7 +2396,7 @@ Metadata::getGenericPattern() const {
return ntd->getGenericMetadataPattern(); return ntd->getGenericMetadataPattern();
} }
const ClassMetadata * template<> const ClassMetadata *
Metadata::getClassObject() const { Metadata::getClassObject() const {
switch (getKind()) { switch (getKind()) {
case MetadataKind::Class: { case MetadataKind::Class: {

View File

@@ -73,10 +73,10 @@ namespace {
public: public:
TypeMetadataCacheEntry(const llvm::StringRef name, TypeMetadataCacheEntry(const llvm::StringRef name,
const struct Metadata *metadata) const ::Metadata *metadata)
: Name(name.str()), Metadata(metadata) {} : Name(name.str()), Metadata(metadata) {}
const struct Metadata *getMetadata(void) { const ::Metadata *getMetadata(void) {
return Metadata; return Metadata;
} }
@@ -230,6 +230,7 @@ swift::swift_registerTypeMetadataRecords(const TypeMetadataRecord *begin,
} }
// copied from ProtocolConformanceRecord::getCanonicalTypeMetadata() // copied from ProtocolConformanceRecord::getCanonicalTypeMetadata()
template<>
const Metadata *TypeMetadataRecord::getCanonicalTypeMetadata() const { const Metadata *TypeMetadataRecord::getCanonicalTypeMetadata() const {
switch (getTypeKind()) { switch (getTypeKind()) {
case TypeMetadataRecordKind::UniqueDirectType: case TypeMetadataRecordKind::UniqueDirectType:
@@ -238,7 +239,7 @@ const Metadata *TypeMetadataRecord::getCanonicalTypeMetadata() const {
return swift_getForeignTypeMetadata((ForeignTypeMetadata *)getDirectType()); return swift_getForeignTypeMetadata((ForeignTypeMetadata *)getDirectType());
case TypeMetadataRecordKind::UniqueDirectClass: case TypeMetadataRecordKind::UniqueDirectClass:
if (auto *ClassMetadata = if (auto *ClassMetadata =
static_cast<const struct ClassMetadata *>(getDirectType())) static_cast<const ::ClassMetadata *>(getDirectType()))
return swift_getObjCClassMetadata(ClassMetadata); return swift_getObjCClassMetadata(ClassMetadata);
else else
return nullptr; return nullptr;

View File

@@ -23,7 +23,6 @@
#include "llvm/Support/Compiler.h" #include "llvm/Support/Compiler.h"
namespace swift { namespace swift {
struct ProtocolDescriptor;
#if SWIFT_HAS_ISA_MASKING #if SWIFT_HAS_ISA_MASKING
SWIFT_RUNTIME_EXPORT SWIFT_RUNTIME_EXPORT

View File

@@ -41,7 +41,7 @@ static const char *class_getName(const ClassMetadata* type) {
reinterpret_cast<Class>(const_cast<ClassMetadata*>(type))); reinterpret_cast<Class>(const_cast<ClassMetadata*>(type)));
} }
void ProtocolConformanceRecord::dump() const { template<> void ProtocolConformanceRecord::dump() const {
auto symbolName = [&](const void *addr) -> const char * { auto symbolName = [&](const void *addr) -> const char * {
Dl_info info; Dl_info info;
int ok = dladdr(addr, &info); int ok = dladdr(addr, &info);
@@ -96,7 +96,7 @@ void ProtocolConformanceRecord::dump() const {
/// Take the type reference inside a protocol conformance record and fetch the /// Take the type reference inside a protocol conformance record and fetch the
/// canonical metadata pointer for the type it refers to. /// canonical metadata pointer for the type it refers to.
/// Returns nil for universal or generic type references. /// Returns nil for universal or generic type references.
const Metadata *ProtocolConformanceRecord::getCanonicalTypeMetadata() template<> const Metadata *ProtocolConformanceRecord::getCanonicalTypeMetadata()
const { const {
switch (getTypeKind()) { switch (getTypeKind()) {
case TypeMetadataRecordKind::UniqueDirectType: case TypeMetadataRecordKind::UniqueDirectType:
@@ -127,7 +127,9 @@ const {
} }
} }
const WitnessTable *ProtocolConformanceRecord::getWitnessTable(const Metadata *type) template<>
const WitnessTable *
ProtocolConformanceRecord::getWitnessTable(const Metadata *type)
const { const {
switch (getConformanceKind()) { switch (getConformanceKind()) {
case ProtocolConformanceReferenceKind::WitnessTable: case ProtocolConformanceReferenceKind::WitnessTable:
@@ -441,7 +443,7 @@ recur_inside_cache_lock:
// For generic and resilient types, nondependent conformances // For generic and resilient types, nondependent conformances
// are keyed by the nominal type descriptor rather than the // are keyed by the nominal type descriptor rather than the
// metadata, so try that. // metadata, so try that.
auto *description = type->getNominalTypeDescriptor(); auto *description = type->getNominalTypeDescriptor().get();
// Hash and lookup the type-protocol pair in the cache. // Hash and lookup the type-protocol pair in the cache.
if (auto *Value = C.findCached(description, protocol)) { if (auto *Value = C.findCached(description, protocol)) {
@@ -483,7 +485,7 @@ bool isRelatedType(const Metadata *type, const void *candidate,
// If the type is resilient or generic, see if there's a witness table // If the type is resilient or generic, see if there's a witness table
// keyed off the nominal type descriptor. // keyed off the nominal type descriptor.
auto *description = type->getNominalTypeDescriptor(); auto *description = type->getNominalTypeDescriptor().get();
if (description == candidate && !candidateIsMetadata) if (description == candidate && !candidateIsMetadata)
return true; return true;