Implement projectExistentialAndUnwrapClass

Implement a version of projectExistential tailored for LLDB. There are 2
differences when projecting existentials for LLDB:

1 - When it comes to existentials, LLDB stores the address of the error
    pointer, which must be dereferenced.
2 - When the existential wraps a class type, LLDB expects the address
    returned is the class instance itself and not the address of the
    reference.

This patch also adapts the swift reflection test machinery to test
projectExistentialAndUnwrapClass as well. This is done by exposing
the new functionality from swift reflection test.  It is tested in
existentials.swift, and ensures that the typeref information is
exactly the same as what is expected from projectExistential,
except the out address.

(cherry picked from commit 55e971e06750c3ba29722d558cc5400298f6bdaf)
This commit is contained in:
Augusto Noronha
2021-06-08 13:31:08 -03:00
parent 92beb71f8a
commit f41d192b48
7 changed files with 612 additions and 26 deletions

View File

@@ -92,7 +92,7 @@ class ReflectionContext
using super = remote::MetadataReader<Runtime, TypeRefBuilder>;
using super::readMetadata;
using super::readObjCClassName;
using super::readResolvedPointerValue;
std::unordered_map<typename super::StoredPointer, const TypeInfo *> Cache;
/// All buffers we need to keep around long term. This will automatically free them
@@ -789,6 +789,52 @@ public:
}
}
llvm::Optional<std::pair<const TypeRef *, RemoteAddress>>
getDynamicTypeAndAddressClassExistential(RemoteAddress ExistentialAddress) {
auto PointerValue =
readResolvedPointerValue(ExistentialAddress.getAddressData());
if (!PointerValue)
return {};
auto Result = readMetadataFromInstance(*PointerValue);
if (!Result)
return {};
auto TypeResult = readTypeFromMetadata(Result.getValue());
if (!TypeResult)
return {};
return {{std::move(TypeResult), RemoteAddress(*PointerValue)}};
}
llvm::Optional<std::pair<const TypeRef *, RemoteAddress>>
getDynamicTypeAndAddressErrorExistential(RemoteAddress ExistentialAddress,
bool *IsBridgedError = nullptr) {
auto Result = readMetadataAndValueErrorExistential(ExistentialAddress);
if (!Result)
return {};
auto TypeResult =
readTypeFromMetadata(Result->MetadataAddress.getAddressData());
if (!TypeResult)
return {};
if (IsBridgedError)
*IsBridgedError = Result->IsBridgedError;
return {{TypeResult, Result->PayloadAddress}};
}
llvm::Optional<std::pair<const TypeRef *, RemoteAddress>>
getDynamicTypeAndAddressOpaqueExistential(RemoteAddress ExistentialAddress) {
auto Result = readMetadataAndValueOpaqueExistential(ExistentialAddress);
if (!Result)
return {};
auto TypeResult =
readTypeFromMetadata(Result->MetadataAddress.getAddressData());
if (!TypeResult)
return {};
return {{std::move(TypeResult), Result->PayloadAddress}};
}
bool projectExistential(RemoteAddress ExistentialAddress,
const TypeRef *ExistentialTR,
const TypeRef **OutInstanceTR,
@@ -850,6 +896,75 @@ public:
return false;
}
}
/// A version of `projectExistential` tailored for LLDB.
/// This version dereferences the resulting TypeRef if it wraps
/// a class type, it also dereferences the input `ExistentialAddress` before
/// attempting to find its dynamic type and address when dealing with error
/// existentials.
llvm::Optional<std::pair<const TypeRef *, RemoteAddress>>
projectExistentialAndUnwrapClass(RemoteAddress ExistentialAddress,
const TypeRef &ExistentialTR) {
auto IsClass = [](const TypeRef *TypeResult) {
// When the existential wraps a class type, LLDB expects that the
// address returned is the class instance itself and not the address
// of the reference.
bool IsClass = TypeResult->getKind() == TypeRefKind::ForeignClass ||
TypeResult->getKind() == TypeRefKind::ObjCClass;
if (auto *nominal = llvm::dyn_cast<NominalTypeRef>(TypeResult))
IsClass = nominal->isClass();
else if (auto *boundGeneric =
llvm::dyn_cast<BoundGenericTypeRef>(TypeResult))
IsClass = boundGeneric->isClass();
return IsClass;
};
auto DereferenceAndSet = [&](RemoteAddress &Address) {
auto PointerValue = readResolvedPointerValue(Address.getAddressData());
if (!PointerValue)
return false;
Address = RemoteAddress(*PointerValue);
return true;
};
auto ExistentialRecordTI = getRecordTypeInfo(&ExistentialTR, nullptr);
if (!ExistentialRecordTI)
return {};
switch (ExistentialRecordTI->getRecordKind()) {
case RecordKind::ClassExistential:
return getDynamicTypeAndAddressClassExistential(ExistentialAddress);
case RecordKind::ErrorExistential: {
// LLDB stores the address of the error pointer.
if (!DereferenceAndSet(ExistentialAddress))
return {};
bool IsBridgedError = false;
auto Pair = getDynamicTypeAndAddressErrorExistential(ExistentialAddress,
&IsBridgedError);
if (!Pair)
return {};
if (!IsBridgedError && IsClass(std::get<const TypeRef *>(*Pair)))
if (!DereferenceAndSet(std::get<RemoteAddress>(*Pair)))
return {};
return Pair;
}
case RecordKind::OpaqueExistential: {
auto Pair = getDynamicTypeAndAddressOpaqueExistential(ExistentialAddress);
if (!Pair)
return {};
if (IsClass(std::get<const TypeRef *>(*Pair)))
if (!DereferenceAndSet(std::get<RemoteAddress>(*Pair)))
return {};
return Pair;
}
default:
return {};
}
}
/// Projects the value of an enum.
///
@@ -889,6 +1004,12 @@ public:
}
}
const RecordTypeInfo *getRecordTypeInfo(const TypeRef *TR,
remote::TypeInfoProvider *ExternalTypeInfo) {
auto *TypeInfo = getTypeInfo(TR, ExternalTypeInfo);
return dyn_cast_or_null<const RecordTypeInfo>(TypeInfo);
}
/// Iterate the protocol conformance cache tree rooted at NodePtr, calling
/// Call with the type and protocol in each node.
void iterateConformanceTree(StoredPointer NodePtr,

View File

@@ -247,6 +247,19 @@ int swift_reflection_projectExistential(SwiftReflectionContextRef ContextRef,
swift_typeref_t *OutInstanceTypeRef,
swift_addr_t *OutStartOfInstanceData);
/// Like swift_reflection_projectExistential, with 2 differences:
///
/// - When dealing with an error existential, this version will dereference
/// the ExistentialAddress before proceeding.
/// - After setting OutInstanceTypeRef and OutStartOfInstanceData this version
/// may derefence and set OutStartOfInstanceData if OutInstanceTypeRef is a
/// class TypeRef.
SWIFT_REMOTE_MIRROR_LINKAGE
int swift_reflection_projectExistentialAndUnwrapClass(
SwiftReflectionContextRef ContextRef, swift_addr_t ExistentialAddress,
swift_typeref_t ExistentialTypeRef, swift_typeref_t *OutInstanceTypeRef,
swift_addr_t *OutStartOfInstanceData);
/// Projects the value of an enum.
///
/// Takes the address and typeref for an enum and determines the

View File

@@ -17,6 +17,7 @@
//===----------------------------------------------------------------------===//
let RequestInstanceKind = "k"
let RequestShouldUnwrapClassExistential = "u"
let RequestInstanceAddress = "i"
let RequestReflectionInfos = "r"
let RequestImages = "m"
@@ -346,11 +347,15 @@ internal func sendPointerSize() {
/// The parent sends a Done message to indicate that it's done
/// looking at this instance. It will continue to ask for instances,
/// so call doneReflecting() when you don't have any more instances.
internal func reflect(instanceAddress: UInt, kind: InstanceKind) {
internal func reflect(instanceAddress: UInt,
kind: InstanceKind,
shouldUnwrapClassExistential: Bool = false) {
while let command = readLine(strippingNewline: true) {
switch command {
case String(validatingUTF8: RequestInstanceKind)!:
sendValue(kind.rawValue)
case String(validatingUTF8: RequestShouldUnwrapClassExistential)!:
sendValue(shouldUnwrapClassExistential)
case String(validatingUTF8: RequestInstanceAddress)!:
sendValue(instanceAddress)
case String(validatingUTF8: RequestReflectionInfos)!:
@@ -437,12 +442,18 @@ public func reflect(object: AnyObject) {
/// The test doesn't care about the witness tables - we only care
/// about what's in the buffer, so we always put these values into
/// an Any existential.
public func reflect<T>(any: T, kind: InstanceKind = .Existential) {
///
/// If shouldUnwrapClassExistential is set to true, this exercises
/// projectExistentialAndUnwrapClass instead of projectExistential.
public func reflect<T>(any: T, kind: InstanceKind = .Existential,
shouldUnwrapClassExistential: Bool = false) {
let any: Any = any
let anyPointer = UnsafeMutablePointer<Any>.allocate(capacity: MemoryLayout<Any>.size)
anyPointer.initialize(to: any)
let anyPointerValue = UInt(bitPattern: anyPointer)
reflect(instanceAddress: anyPointerValue, kind: kind)
reflect(instanceAddress: anyPointerValue,
kind: kind,
shouldUnwrapClassExistential: shouldUnwrapClassExistential)
anyPointer.deallocate()
}
@@ -474,6 +485,21 @@ public func reflect<T: Error>(error: T) {
reflect(instanceAddress: errorPointerValue, kind: .ErrorExistential)
}
// Like reflect<T: Error>(error: T), but calls projectExistentialAndUnwrapClass
// instead of projectExistential and adds an extra level of indirection, which is
// what projectExistentialAndUnwrapClass expects.
public func reflectUnwrappingClassExistential<T: Error>(error: T) {
let error: Error = error
let errorPointerValue = unsafeBitCast(error, to: UInt.self)
let anyPointer = UnsafeMutablePointer<Any>.allocate(capacity: MemoryLayout<Any>.size)
anyPointer.initialize(to: errorPointerValue)
let anyPointerValue = UInt(bitPattern: anyPointer)
reflect(instanceAddress: anyPointerValue,
kind: .ErrorExistential,
shouldUnwrapClassExistential: true)
anyPointer.deallocate()
}
// Reflect an `Enum`
//
// These are handled like existentials, but

View File

@@ -571,6 +571,23 @@ int swift_reflection_projectExistential(SwiftReflectionContextRef ContextRef,
return Success;
}
int swift_reflection_projectExistentialAndUnwrapClass(SwiftReflectionContextRef ContextRef,
swift_addr_t ExistentialAddress,
swift_typeref_t ExistentialTypeRef,
swift_typeref_t *InstanceTypeRef,
swift_addr_t *StartOfInstanceData) {
auto Context = ContextRef->nativeContext;
auto ExistentialTR = reinterpret_cast<const TypeRef *>(ExistentialTypeRef);
auto RemoteExistentialAddress = RemoteAddress(ExistentialAddress);
auto Pair = Context->projectExistentialAndUnwrapClass(
RemoteExistentialAddress, *ExistentialTR);
if (!Pair.hasValue())
return false;
*InstanceTypeRef = reinterpret_cast<swift_typeref_t>(std::get<const TypeRef *>(*Pair));
*StartOfInstanceData = std::get<RemoteAddress>(*Pair).getAddressData();
return true;
}
int swift_reflection_projectEnumValue(SwiftReflectionContextRef ContextRef,
swift_addr_t EnumAddress,
swift_typeref_t EnumTypeRef,

View File

@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
static const char *REQUEST_INSTANCE_KIND = "k\n";
static const char *REQUEST_SHOULD_UNWRAP_CLASS_EXISTENTIAL = "u\n";
static const char *REQUEST_INSTANCE_ADDRESS = "i\n";
static const char *REQUEST_REFLECTION_INFO = "r\n";
static const char *REQUEST_IMAGES = "m\n";

View File

@@ -238,6 +238,17 @@ PipeMemoryReader_receiveInstanceKind(const PipeMemoryReader *Reader) {
return KindValue;
}
static uint8_t PipeMemoryReader_receiveShouldUnwrapExistential(
const PipeMemoryReader *Reader) {
int WriteFD = PipeMemoryReader_getParentWriteFD(Reader);
write(WriteFD, REQUEST_SHOULD_UNWRAP_CLASS_EXISTENTIAL, 2);
uint8_t ShouldUnwrap = 0;
PipeMemoryReader_collectBytesFromPipe(Reader, &ShouldUnwrap,
sizeof(ShouldUnwrap));
DEBUG_LOG("Requested if should unwrap class existential is", KindValue);
return ShouldUnwrap;
}
static uintptr_t
PipeMemoryReader_receiveInstanceAddress(const PipeMemoryReader *Reader) {
int WriteFD = PipeMemoryReader_getParentWriteFD(Reader);
@@ -445,24 +456,25 @@ int reflectHeapObject(SwiftReflectionContextRef RC,
return 1;
}
int reflectExistential(SwiftReflectionContextRef RC,
const PipeMemoryReader Pipe,
swift_typeref_t MockExistentialTR) {
int reflectExistentialImpl(
SwiftReflectionContextRef RC, const PipeMemoryReader Pipe,
swift_typeref_t MockExistentialTR,
int (*ProjectExistentialFn)(SwiftReflectionContextRef, swift_addr_t,
swift_typeref_t, swift_typeref_t *,
swift_addr_t *)) {
uintptr_t instance = PipeMemoryReader_receiveInstanceAddress(&Pipe);
if (instance == 0) {
// Child has no more instances to examine
PipeMemoryReader_sendDoneMessage(&Pipe);
return 0;
}
printf("Instance pointer in child address space: 0x%lx\n",
instance);
printf("Instance pointer in child address space: 0x%lx\n", instance);
swift_typeref_t InstanceTypeRef;
swift_addr_t StartOfInstanceData = 0;
if (!swift_reflection_projectExistential(RC, instance, MockExistentialTR,
&InstanceTypeRef,
&StartOfInstanceData)) {
if (!ProjectExistentialFn(RC, instance, MockExistentialTR, &InstanceTypeRef,
&StartOfInstanceData)) {
printf("swift_reflection_projectExistential failed.\n");
PipeMemoryReader_sendDoneMessage(&Pipe);
return 0;
@@ -476,10 +488,28 @@ int reflectExistential(SwiftReflectionContextRef RC,
swift_reflection_dumpInfoForTypeRef(RC, InstanceTypeRef);
printf("\n");
printf("Start of instance data: 0x%" PRIx64 "\n", StartOfInstanceData);
printf("\n");
PipeMemoryReader_sendDoneMessage(&Pipe);
return 1;
}
int reflectExistential(SwiftReflectionContextRef RC,
const PipeMemoryReader Pipe,
swift_typeref_t MockExistentialTR) {
return reflectExistentialImpl(RC, Pipe, MockExistentialTR,
swift_reflection_projectExistential);
}
int reflectExistentialAndUnwrapClass(SwiftReflectionContextRef RC,
const PipeMemoryReader Pipe,
swift_typeref_t MockExistentialTR) {
return reflectExistentialImpl(
RC, Pipe, MockExistentialTR,
swift_reflection_projectExistentialAndUnwrapClass);
}
int reflectEnum(SwiftReflectionContextRef RC,
const PipeMemoryReader Pipe) {
static const char Name[] = MANGLING_PREFIX_STR "ypD";
@@ -706,23 +736,38 @@ int doDumpHeapInstance(const char *BinaryFilename) {
break;
case Existential: {
static const char Name[] = MANGLING_PREFIX_STR "ypD";
swift_typeref_t AnyTR
= swift_reflection_typeRefForMangledTypeName(RC,
Name, sizeof(Name)-1);
swift_typeref_t AnyTR = swift_reflection_typeRefForMangledTypeName(
RC, Name, sizeof(Name) - 1);
uint8_t ShouldUnwrap =
PipeMemoryReader_receiveShouldUnwrapExistential(&Pipe);
printf("Reflecting an existential.\n");
if (!reflectExistential(RC, Pipe, AnyTR))
return EXIT_SUCCESS;
if (ShouldUnwrap) {
printf("Reflecting an existential and unwrapping class.\n");
if (!reflectExistentialAndUnwrapClass(RC, Pipe, AnyTR))
return EXIT_SUCCESS;
} else {
printf("Reflecting an existential.\n");
if (!reflectExistential(RC, Pipe, AnyTR))
return EXIT_SUCCESS;
}
break;
}
case ErrorExistential: {
static const char ErrorName[] = MANGLING_PREFIX_STR "s5Error_pD";
swift_typeref_t ErrorTR
= swift_reflection_typeRefForMangledTypeName(RC,
ErrorName, sizeof(ErrorName)-1);
printf("Reflecting an error existential.\n");
if (!reflectExistential(RC, Pipe, ErrorTR))
return EXIT_SUCCESS;
swift_typeref_t ErrorTR = swift_reflection_typeRefForMangledTypeName(
RC, ErrorName, sizeof(ErrorName) - 1);
uint8_t ShouldUnwrap =
PipeMemoryReader_receiveShouldUnwrapExistential(&Pipe);
if (ShouldUnwrap) {
printf("Reflecting an error existential and unwrapping class.\n");
if (!reflectExistentialAndUnwrapClass(RC, Pipe, ErrorTR))
return EXIT_SUCCESS;
} else {
printf("Reflecting an error existential.\n");
if (!reflectExistential(RC, Pipe, ErrorTR))
return EXIT_SUCCESS;
}
break;
}
case Closure:

View File

@@ -71,6 +71,8 @@ reflect(any: mc)
// CHECK-64: Mangled name: $s12existentials7MyClassCyS2iG
// CHECK-64: Demangled name: existentials.MyClass<Swift.Int, Swift.Int>
// CHECK-64: Start of instance data: [[ADDR:0x[0-9a-fA-F]+]]
// CHECK-32: Reflecting an existential.
// CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
// CHECK-32: Type reference:
@@ -82,6 +84,40 @@ reflect(any: mc)
// CHECK-32: Mangled name: $s12existentials7MyClassCyS2iG
// CHECK-32: Demangled name: existentials.MyClass<Swift.Int, Swift.Int>
// CHECK-32: Start of instance data: [[ADDR:0x[0-9a-fA-F]+]]
// Reflect and unwrap class existential should print the exact same info,
// EXCEPT for the start of instance data address.
reflect(any: mc, shouldUnwrapClassExistential: true)
// CHECK-64: Reflecting an existential and unwrapping class.
// CHECK-64: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
// CHECK-64: Type reference:
// CHECK-64: (bound_generic_class existentials.MyClass
// CHECK-64-NEXT: (struct Swift.Int)
// CHECK-64-NEXT: (struct Swift.Int))
// CHECK-64: Type info:
// CHECK-64: (reference kind=strong refcounting=native)
// CHECK-64: Mangled name: $s12existentials7MyClassCyS2iG
// CHECK-64: Demangled name: existentials.MyClass<Swift.Int, Swift.Int>
// CHECK-64: Start of instance data:
// CHECK-64-NOT: ![[ADDR]]
// CHECK-32: Reflecting an existential and unwrapping class.
// CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
// CHECK-32: Type reference:
// CHECK-32: (bound_generic_class existentials.MyClass
// CHECK-32-NEXT: (struct Swift.Int)
// CHECK-32-NEXT: (struct Swift.Int))
// CHECK-32: Type info:
// CHECK-32: (reference kind=strong refcounting=native)
// CHECK-32: Mangled name: $s12existentials7MyClassCyS2iG
// CHECK-32: Demangled name: existentials.MyClass<Swift.Int, Swift.Int>
// CHECK-32: Start of instance data:
// CHECK-32-NOT: ![[ADDR]]
// This value fits in the 3-word buffer in the container.
var smallStruct = MyStruct(x: 1, y: 2, z: 3)
reflect(any: smallStruct)
@@ -111,6 +147,9 @@ reflect(any: smallStruct)
// CHECK-64-NEXT: Mangled name: $s12existentials8MyStructVyS3iG
// CHECK-64-NEXT: Demangled name: existentials.MyStruct<Swift.Int, Swift.Int, Swift.Int>
// CHECK-64: Start of instance data: [[ADDR:0x[0-9a-fA-F]+]]
// CHECK-32: Reflecting an existential.
// CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
// CHECK-32: Type reference:
@@ -136,6 +175,66 @@ reflect(any: smallStruct)
// CHECK-32-NEXT: Mangled name: $s12existentials8MyStructVyS3iG
// CHECK-32-NEXT: Demangled name: existentials.MyStruct<Swift.Int, Swift.Int, Swift.Int>
// CHECK-32: Start of instance data: [[ADDR:0x[0-9a-fA-F]+]]
reflect(any: smallStruct, shouldUnwrapClassExistential: true)
// CHECK-64: Reflecting an existential and unwrapping class.
// CHECK-64: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
// CHECK-64: Type reference:
// CHECK-64: (bound_generic_struct existentials.MyStruct
// CHECK-64-NEXT: (struct Swift.Int)
// CHECK-64-NEXT: (struct Swift.Int)
// CHECK-64-NEXT: (struct Swift.Int))
// CHECK-64: Type info:
// CHECK-64: (struct size=24 alignment=8 stride=24 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=x offset=0
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=_value offset=0
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-64-NEXT: (field name=y offset=8
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=_value offset=0
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-64-NEXT: (field name=z offset=16
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=_value offset=0
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1)))))
// CHECK-64-NEXT: Mangled name: $s12existentials8MyStructVyS3iG
// CHECK-64-NEXT: Demangled name: existentials.MyStruct<Swift.Int, Swift.Int, Swift.Int>
// CHECK-64: Start of instance data:
// CHECK-64-NOT: ![[ADDR]]
// CHECK-32: Reflecting an existential and unwrapping class.
// CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
// CHECK-32: Type reference:
// CHECK-32: (bound_generic_struct existentials.MyStruct
// CHECK-32-NEXT: (struct Swift.Int)
// CHECK-32-NEXT: (struct Swift.Int)
// CHECK-32-NEXT: (struct Swift.Int))
// CHECK-32: Type info:
// CHECK-32: (struct size=12 alignment=4 stride=12 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=x offset=0
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=_value offset=0
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-32-NEXT: (field name=y offset=4
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=_value offset=0
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-32-NEXT: (field name=z offset=8
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=_value offset=0
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1)))))
// CHECK-32-NEXT: Mangled name: $s12existentials8MyStructVyS3iG
// CHECK-32-NEXT: Demangled name: existentials.MyStruct<Swift.Int, Swift.Int, Swift.Int>
// CHECK-32: Start of instance data:
// CHECK-32-NOT: ![[ADDR]]
// This value will be copied into a heap buffer, with a
// pointer to it in the existential.
var largeStruct = MyStruct(x: (1,1,1), y: (2,2,2), z: (3,3,3))
@@ -204,6 +303,9 @@ reflect(any: largeStruct)
// CHECK-64-NEXT: Mangled name: $s12existentials8MyStructVySi_S2itSi_S2itSi_S2itG
// CHECK-64-NEXT: Demangled name: existentials.MyStruct<(Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int)>
// CHECK-64: Start of instance data: [[ADDR:0x[0-9a-fA-F]+]]
// CHECK-32: Reflecting an existential.
// CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
// CHECK-32: Type reference:
@@ -267,6 +369,142 @@ reflect(any: largeStruct)
// CHECK-32-NEXT: Mangled name: $s12existentials8MyStructVySi_S2itSi_S2itSi_S2itG
// CHECK-32-NEXT: Demangled name: existentials.MyStruct<(Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int)>
// CHECK-32: Start of instance data: [[ADDR:0x[0-9a-fA-F]+]]
reflect(any: largeStruct, shouldUnwrapClassExistential: true)
// CHECK-64: Reflecting an existential and unwrapping class.
// CHECK-64: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
// CHECK-64: Type reference:
// CHECK-64: (bound_generic_struct existentials.MyStruct
// CHECK-64-NEXT: (tuple
// CHECK-64-NEXT: (struct Swift.Int)
// CHECK-64-NEXT: (struct Swift.Int)
// CHECK-64-NEXT: (struct Swift.Int))
// CHECK-64-NEXT: (tuple
// CHECK-64-NEXT: (struct Swift.Int)
// CHECK-64-NEXT: (struct Swift.Int)
// CHECK-64-NEXT: (struct Swift.Int))
// CHECK-64-NEXT: (tuple
// CHECK-64-NEXT: (struct Swift.Int)
// CHECK-64-NEXT: (struct Swift.Int)
// CHECK-64-NEXT: (struct Swift.Int)))
// CHECK-64: Type info:
// CHECK-64-NEXT: (struct size=72 alignment=8 stride=72 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=x offset=0
// CHECK-64-NEXT: (tuple size=24 alignment=8 stride=24 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field offset=0
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=_value offset=0
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-64-NEXT: (field offset=8
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=_value offset=0
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-64-NEXT: (field offset=16
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=_value offset=0
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1))))))
// CHECK-64-NEXT: (field name=y offset=24
// CHECK-64-NEXT: (tuple size=24 alignment=8 stride=24 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field offset=0
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=_value offset=0
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-64-NEXT: (field offset=8
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=_value offset=0
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-64-NEXT: (field offset=16
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=_value offset=0
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1))))))
// CHECK-64-NEXT: (field name=z offset=48
// CHECK-64-NEXT: (tuple size=24 alignment=8 stride=24 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field offset=0
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=_value offset=0
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-64-NEXT: (field offset=8
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=_value offset=0
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-64-NEXT: (field offset=16
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=_value offset=0
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1)))))))
// CHECK-64-NEXT: Mangled name: $s12existentials8MyStructVySi_S2itSi_S2itSi_S2itG
// CHECK-64-NEXT: Demangled name: existentials.MyStruct<(Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int)>
// CHECK-64: Start of instance data:
// CHECK-64-NOT: ![[ADDR]]
// CHECK-32: Reflecting an existential and unwrapping class.
// CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
// CHECK-32: Type reference:
// CHECK-32: (bound_generic_struct existentials.MyStruct
// CHECK-32-NEXT: (tuple
// CHECK-32-NEXT: (struct Swift.Int)
// CHECK-32-NEXT: (struct Swift.Int)
// CHECK-32-NEXT: (struct Swift.Int))
// CHECK-32-NEXT: (tuple
// CHECK-32-NEXT: (struct Swift.Int)
// CHECK-32-NEXT: (struct Swift.Int)
// CHECK-32-NEXT: (struct Swift.Int))
// CHECK-32-NEXT: (tuple
// CHECK-32-NEXT: (struct Swift.Int)
// CHECK-32-NEXT: (struct Swift.Int)
// CHECK-32-NEXT: (struct Swift.Int)))
// CHECK-32: Type info:
// CHECK-32: (struct size=36 alignment=4 stride=36 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=x offset=0
// CHECK-32-NEXT: (tuple size=12 alignment=4 stride=12 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field offset=0
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=_value offset=0
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-32-NEXT: (field offset=4
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=_value offset=0
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-32-NEXT: (field offset=8
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=_value offset=0
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1))))))
// CHECK-32-NEXT: (field name=y offset=12
// CHECK-32-NEXT: (tuple size=12 alignment=4 stride=12 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field offset=0
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=_value offset=0
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-32-NEXT: (field offset=4
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=_value offset=0
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-32-NEXT: (field offset=8
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=_value offset=0
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1))))))
// CHECK-32-NEXT: (field name=z offset=24
// CHECK-32-NEXT: (tuple size=12 alignment=4 stride=12 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field offset=0
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=_value offset=0
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-32-NEXT: (field offset=4
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=_value offset=0
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-32-NEXT: (field offset=8
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=_value offset=0
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1)))))))
// CHECK-32-NEXT: Mangled name: $s12existentials8MyStructVySi_S2itSi_S2itSi_S2itG
// CHECK-32-NEXT: Demangled name: existentials.MyStruct<(Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int)>
// CHECK-32: Start of instance data:
// CHECK-32-NOT: ![[ADDR]]
// Function type:
reflect(any: {largeStruct})
// CHECK-64: Mangled name: $s12existentials8MyStructVySi_S2itSi_S2itSi_S2itGyc
@@ -346,6 +584,8 @@ reflect(any: he)
// CHECK-64-NEXT: Mangled name: $s12existentials8HasErrorV
// CHECK-64-NEXT: Demangled name: existentials.HasError
// CHECK-64: Start of instance data: [[ADDR:0x[0-9a-fA-F]+]]
// CHECK-32: Reflecting an existential.
// CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
// CHECK-32: Type reference:
@@ -382,7 +622,91 @@ reflect(any: he)
// CHECK-32-NEXT: Mangled name: $s12existentials8HasErrorV
// CHECK-32-NEXT: Demangled name: existentials.HasError
reflect(error: MyError())
// CHECK-32: Start of instance data: [[ADDR:0x[0-9a-fA-F]+]]
reflect(any: he, shouldUnwrapClassExistential: true)
// CHECK-64: Reflecting an existential and unwrapping class.
// CHECK-64: Instance pointer in child address space: 0x{{[0-9a-fA-F+]}}
// CHECK-64: Type reference:
// CHECK-64: (struct existentials.HasError)
// CHECK-64: Type info:
// CHECK-64: (struct size=144 alignment=8 stride=144
// CHECK-64-NEXT: (field name=singleError offset=0
// CHECK-64-NEXT: (error_existential size=8 alignment=8 stride=8 num_extra_inhabitants=[[#num_extra_inhabitants_64bit]] bitwise_takable=1
// CHECK-64-NEXT: (field name=error offset=0
// CHECK-64-NEXT: (reference kind=strong refcounting=unknown))))
// CHECK-64-NEXT: (field name=errorInComposition offset=8
// CHECK-64-NEXT: (opaque_existential size=48 alignment=8 stride=48 num_extra_inhabitants=[[#num_extra_inhabitants_64bit]] bitwise_takable=1
// CHECK-64-NEXT: (field name=metadata offset=24
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=[[#num_extra_inhabitants_64bit]] bitwise_takable=1))
// CHECK-64-NEXT: (field name=wtable offset=32
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=1 bitwise_takable=1))
// CHECK-64-NEXT: (field name=wtable offset=40
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=1 bitwise_takable=1))))
// CHECK-64-NEXT: (field name=customError offset=56
// CHECK-64-NEXT: (opaque_existential size=40 alignment=8 stride=40 num_extra_inhabitants=[[#num_extra_inhabitants_64bit]] bitwise_takable=1
// CHECK-64-NEXT: (field name=metadata offset=24
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=[[#num_extra_inhabitants_64bit]] bitwise_takable=1))
// CHECK-64-NEXT: (field name=wtable offset=32
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=1 bitwise_takable=1))))
// CHECK-64-NEXT: (field name=customErrorInComposition offset=96
// CHECK-64-NEXT: (opaque_existential size=48 alignment=8 stride=48 num_extra_inhabitants=[[#num_extra_inhabitants_64bit]] bitwise_takable=1
// CHECK-64-NEXT: (field name=metadata offset=24
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=[[#num_extra_inhabitants_64bit]] bitwise_takable=1))
// CHECK-64-NEXT: (field name=wtable offset=32
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=1 bitwise_takable=1))
// CHECK-64-NEXT: (field name=wtable offset=40
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=1 bitwise_takable=1)))))
// CHECK-64-NEXT: Mangled name: $s12existentials8HasErrorV
// CHECK-64-NEXT: Demangled name: existentials.HasError
// CHECK-64: Start of instance data:
// CHECK-64-NOT: ![[ADDR]]
// CHECK-32: Reflecting an existential and unwrapping class.
// CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
// CHECK-32: Type reference:
// CHECK-32: (struct existentials.HasError)
// CHECK-32: Type info:
// CHECK-32: (struct size=72 alignment=4 stride=72 num_extra_inhabitants=4096 bitwise_takable=1
// CHECK-32-NEXT: (field name=singleError offset=0
// CHECK-32-NEXT: (error_existential size=4 alignment=4 stride=4 num_extra_inhabitants=4096 bitwise_takable=1
// CHECK-32-NEXT: (field name=error offset=0
// CHECK-32-NEXT: (reference kind=strong refcounting=unknown))))
// CHECK-32-NEXT: (field name=errorInComposition offset=4
// CHECK-32-NEXT: (opaque_existential size=24 alignment=4 stride=24 num_extra_inhabitants=4096 bitwise_takable=1
// CHECK-32-NEXT: (field name=metadata offset=12
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=4096 bitwise_takable=1))
// CHECK-32-NEXT: (field name=wtable offset=16
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=1 bitwise_takable=1))
// CHECK-32-NEXT: (field name=wtable offset=20
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=1 bitwise_takable=1))))
// CHECK-32-NEXT: (field name=customError offset=28
// CHECK-32-NEXT: (opaque_existential size=20 alignment=4 stride=20 num_extra_inhabitants=4096 bitwise_takable=1
// CHECK-32-NEXT: (field name=metadata offset=12
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=4096 bitwise_takable=1))
// CHECK-32-NEXT: (field name=wtable offset=16
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=1 bitwise_takable=1))))
// CHECK-32-NEXT: (field name=customErrorInComposition offset=48
// CHECK-32-NEXT: (opaque_existential size=24 alignment=4 stride=24 num_extra_inhabitants=4096 bitwise_takable=1
// CHECK-32-NEXT: (field name=metadata offset=12
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=4096 bitwise_takable=1))
// CHECK-32-NEXT: (field name=wtable offset=16
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=1 bitwise_takable=1))
// CHECK-32-NEXT: (field name=wtable offset=20
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=1 bitwise_takable=1)))))
// CHECK-32-NEXT: Mangled name: $s12existentials8HasErrorV
// CHECK-32-NEXT: Demangled name: existentials.HasError
// CHECK-32: Start of instance data:
// CHECK-32-NOT: ![[ADDR]]
let error = MyError()
reflect(error: error)
// CHECK-64: Reflecting an error existential.
// CHECK-64: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
@@ -398,6 +722,8 @@ reflect(error: MyError())
// CHECK-64-NEXT: Mangled name: $s12existentials7MyErrorV
// CHECK-64-NEXT: Demangled name: existentials.MyError
// CHECK-64: Start of instance data: [[ADDR:0x[0-9a-fA-F]+]]
// CHECK-32: Reflecting an error existential.
// CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
// CHECK-32: Type reference:
@@ -412,4 +738,41 @@ reflect(error: MyError())
// CHECK-32-NEXT: Mangled name: $s12existentials7MyErrorV
// CHECK-32-NEXT: Demangled name: existentials.MyError
// CHECK-32: Start of instance data: [[ADDR:0x[0-9a-fA-F]+]]
reflectUnwrappingClassExistential(error: error)
// CHECK-64: Reflecting an error existential and unwrapping class.
// CHECK-64: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
// CHECK-64: Type reference:
// CHECK-64: (struct existentials.MyError)
// CHECK-64: Type info:
// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=i offset=0
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-64-NEXT: (field name=_value offset=0
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1)))))
// CHECK-64-NEXT: Mangled name: $s12existentials7MyErrorV
// CHECK-64-NEXT: Demangled name: existentials.MyError
// CHECK-64: Start of instance data:
// CHECK-64-NOT: ![[ADDR]]
// CHECK-32: Reflecting an error existential and unwrapping class.
// CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
// CHECK-32: Type reference:
// CHECK-32: (struct existentials.MyError)
// CHECK-32: Type info:
// CHECK-32: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=i offset=0
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1
// CHECK-32-NEXT: (field name=_value offset=0
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1)))))
// CHECK-32-NEXT: Mangled name: $s12existentials7MyErrorV
// CHECK-32-NEXT: Demangled name: existentials.MyError
// CHECK-32: Start of instance data:
// CHECK-32-NOT: ![[ADDR]]
doneReflecting()