Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions include/swift/Reflection/ReflectionContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -520,15 +520,14 @@ class ReflectionContext
readMetadataAndValueOpaqueExistential(ExistentialAddress);
if (!OptMetaAndValue)
return false;
RemoteAddress MetadataAddress = OptMetaAndValue->first;
RemoteAddress ValueAddress = OptMetaAndValue->second;

auto InstanceTR = readTypeFromMetadata(MetadataAddress.getAddressData());
auto InstanceTR = readTypeFromMetadata(
OptMetaAndValue->MetadataAddress.getAddressData());
if (!InstanceTR)
return false;

*OutInstanceTR = InstanceTR;
*OutInstanceAddress = ValueAddress;
*OutInstanceAddress = OptMetaAndValue->PayloadAddress;
return true;
}
case RecordKind::ErrorExistential: {
Expand All @@ -537,16 +536,15 @@ class ReflectionContext
if (!OptMetaAndValue)
return false;

RemoteAddress InstanceMetadataAddress = OptMetaAndValue->first;
RemoteAddress InstanceAddress = OptMetaAndValue->second;
// FIXME: Check third value, 'IsBridgedError'

auto InstanceTR =
readTypeFromMetadata(InstanceMetadataAddress.getAddressData());
auto InstanceTR = readTypeFromMetadata(
OptMetaAndValue->MetadataAddress.getAddressData());
if (!InstanceTR)
return false;

*OutInstanceTR = InstanceTR;
*OutInstanceAddress = RemoteAddress(InstanceAddress);
*OutInstanceAddress = OptMetaAndValue->PayloadAddress;
return true;
}
default:
Expand Down
101 changes: 69 additions & 32 deletions include/swift/Remote/MetadataReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,26 @@ struct delete_with_free {
}
};

/// A structure representing an opened existential type.
struct RemoteExistential {
/// The payload's concrete type metadata.
RemoteAddress MetadataAddress;

/// The address of the payload value.
RemoteAddress PayloadAddress;

/// True if this is an NSError instance transparently bridged to an Error
/// existential.
bool IsBridgedError;

RemoteExistential(RemoteAddress MetadataAddress,
RemoteAddress PayloadAddress,
bool IsBridgedError=false)
: MetadataAddress(MetadataAddress),
PayloadAddress(PayloadAddress),
IsBridgedError(IsBridgedError) {}
};

/// A generic reader of metadata.
///
/// BuilderType must implement a particular interface which is currently
Expand Down Expand Up @@ -327,8 +347,10 @@ class MetadataReader {
}

/// Given a pointer to a known-error existential, attempt to discover the
/// pointer to its metadata address and its value address.
Optional<std::pair<RemoteAddress, RemoteAddress>>
/// pointer to its metadata address, its value address, and whether this
/// is a toll-free-bridged NSError or an actual Error existential wrapper
/// around a native Swift value.
Optional<RemoteExistential>
readMetadataAndValueErrorExistential(RemoteAddress ExistentialAddress) {
// An pointer to an error existential is always an heap object.
auto MetadataAddress =
Expand All @@ -337,13 +359,16 @@ class MetadataReader {
return None;

bool isObjC = false;
bool isBridged = false;

// If we can determine the Objective-C class name, this is probably an
// error existential with NSError-compatible layout.
std::string ObjCClassName;
if (readObjCClassName(*MetadataAddress, ObjCClassName)) {
if (ObjCClassName == "__SwiftNativeNSError")
isObjC = true;
else
isBridged = true;
} else {
// Otherwise, we can check to see if this is a class metadata with the
// kind value's least significant bit set, which indicates a pure
Expand All @@ -356,6 +381,13 @@ class MetadataReader {
isObjC = ClassMeta->isPureObjC();
}

if (isBridged) {
// NSError instances don't need to be unwrapped.
return RemoteExistential(RemoteAddress(*MetadataAddress),
ExistentialAddress,
isBridged);
}

// In addition to the isa pointer and two 32-bit reference counts, if the
// error existential is layout-compatible with NSError, we also need to
// skip over its three word-sized fields: the error code, the domain,
Expand Down Expand Up @@ -387,14 +419,15 @@ class MetadataReader {
auto Offset = (sizeof(HeapObject) + AlignmentMask) & ~AlignmentMask;
InstanceAddress += Offset;

return Optional<std::pair<RemoteAddress, RemoteAddress>>(
{RemoteAddress(*InstanceMetadataAddress),
RemoteAddress(InstanceAddress)});
return RemoteExistential(
RemoteAddress(*InstanceMetadataAddress),
RemoteAddress(InstanceAddress),
isBridged);
}

/// Given a known-opaque existential, attemp to discover the pointer to its
/// metadata address and its value.
Optional<std::pair<RemoteAddress, RemoteAddress>>
Optional<RemoteExistential>
readMetadataAndValueOpaqueExistential(RemoteAddress ExistentialAddress) {
// OpaqueExistentialContainer is the layout of an opaque existential.
// `Type` is the pointer to the metadata.
Expand All @@ -414,8 +447,8 @@ class MetadataReader {
// Inline representation (the value fits in the existential container).
// So, the value starts at the first word of the container.
if (VWT->isValueInline())
return Optional<std::pair<RemoteAddress, RemoteAddress>>(
{RemoteAddress(MetadataAddress), ExistentialAddress});
return RemoteExistential(RemoteAddress(MetadataAddress),
ExistentialAddress);

// Non-inline (box'ed) representation.
// The first word of the container stores the address to the box.
Expand All @@ -426,8 +459,8 @@ class MetadataReader {
auto AlignmentMask = VWT->getAlignmentMask();
auto Offset = (sizeof(HeapObject) + AlignmentMask) & ~AlignmentMask;
auto StartOfValue = BoxAddress + Offset;
return Optional<std::pair<RemoteAddress, RemoteAddress>>(
{RemoteAddress(MetadataAddress), RemoteAddress(StartOfValue)});
return RemoteExistential(RemoteAddress(MetadataAddress),
RemoteAddress(StartOfValue));
}

/// Read a protocol from a reference to said protocol.
Expand Down Expand Up @@ -496,28 +529,8 @@ class MetadataReader {
if (!Meta) return BuiltType();

switch (Meta->getKind()) {
case MetadataKind::Class: {
auto classMeta = cast<TargetClassMetadata<Runtime>>(Meta);
if (!classMeta->isTypeMetadata()) {
std::string className;
if (!readObjCClassName(MetadataAddress, className))
return BuiltType();

BuiltType BuiltObjCClass = Builder.createObjCClassType(std::move(className));
if (!BuiltObjCClass) {
// Try the superclass.
if (!classMeta->Superclass)
return BuiltType();

BuiltObjCClass = readTypeFromMetadata(classMeta->Superclass,
skipArtificialSubclasses);
}

TypeCache[MetadataAddress] = BuiltObjCClass;
return BuiltObjCClass;
}
return readNominalTypeFromMetadata(Meta, skipArtificialSubclasses);
}
case MetadataKind::Class:
return readNominalTypeFromClassMetadata(Meta, skipArtificialSubclasses);
case MetadataKind::Struct:
case MetadataKind::Enum:
case MetadataKind::Optional:
Expand Down Expand Up @@ -2283,6 +2296,30 @@ class MetadataReader {
return nominal;
}

BuiltType readNominalTypeFromClassMetadata(MetadataRef origMetadata,
bool skipArtificialSubclasses = false) {
auto classMeta = cast<TargetClassMetadata<Runtime>>(origMetadata);
if (classMeta->isTypeMetadata())
return readNominalTypeFromMetadata(origMetadata, skipArtificialSubclasses);

std::string className;
if (!readObjCClassName(origMetadata.getAddress(), className))
return BuiltType();

BuiltType BuiltObjCClass = Builder.createObjCClassType(std::move(className));
if (!BuiltObjCClass) {
// Try the superclass.
if (!classMeta->Superclass)
return BuiltType();

BuiltObjCClass = readTypeFromMetadata(classMeta->Superclass,
skipArtificialSubclasses);
}

TypeCache[origMetadata.getAddress()] = BuiltObjCClass;
return BuiltObjCClass;
}

/// Given that the remote process is running the non-fragile Apple runtime,
/// grab the ro-data from a class pointer.
StoredPointer readObjCRODataPtr(StoredPointer classAddress) {
Expand Down
25 changes: 23 additions & 2 deletions include/swift/RemoteAST/RemoteAST.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "swift/Remote/MemoryReader.h"
#include "swift/Basic/LLVM.h"
#include "swift/ABI/MetadataValues.h"
#include "swift/AST/Type.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"

Expand All @@ -31,7 +32,6 @@
namespace swift {
class ASTContext;
class NominalTypeDecl;
class Type;

namespace remoteAST {

Expand Down Expand Up @@ -136,6 +136,21 @@ class Result {
}
};

/// 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
Expand Down Expand Up @@ -212,11 +227,17 @@ class RemoteASTContext {
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<std::pair<Type, remote::RemoteAddress>>
Result<OpenedExistential>
getDynamicTypeAndAddressForExistential(remote::RemoteAddress address,
Type staticType);
};
Expand Down
Loading