Skip to content

Commit d6fc306

Browse files
committed
[Reflection] Improve size computation for remote type metadata reading.
Take advantage of the ability to iterate over TrailingObjects when computing the size of certain kinds of type metadata. This avoids the occasional issue where a new trailing object is added to a type, the remote metadata reader isn't fully updated for it, and doesn't read enough data. This change fixes an issue with function type metadata where we didn't read the global actor field. Not all type metadata is amenable to this, as some don't use TrailingObjects for their trailing data (e.g. various nominal types) and extended existentials need to dereference their Shape pointer to determine the number of TrailingObjects, which needs some additional code when done remotely. We are able to automatically calculate the sizes of Existential and Function. rdar://162855053
1 parent a1b41ac commit d6fc306

File tree

3 files changed

+148
-96
lines changed

3 files changed

+148
-96
lines changed

include/swift/ABI/TrailingObjects.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,15 @@ class swift_ptrauth_struct_derived(BaseTy) TrailingObjects
421421
}
422422
};
423423

424+
// Helper function to determine at build time if a type has TrailingObjects.
425+
// This is useful for determining if trailingTypeCount and
426+
// sizeWithTrailingTypeCount are available for code that reads TrailingObjects
427+
// values in a generalized fashion.
428+
template <typename T>
429+
static constexpr bool typeHasTrailingObjects() {
430+
return std::is_base_of_v<trailing_objects_internal::TrailingObjectsBase, T>;
431+
}
432+
424433
} // end namespace ABI
425434
} // end namespace swift
426435

include/swift/Remote/MetadataReader.h

Lines changed: 80 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,33 +1493,33 @@ class MetadataReader {
14931493
break;
14941494
case ContextDescriptorKind::Extension:
14951495
success =
1496-
readFullContextDescriptor<TargetExtensionContextDescriptor<Runtime>>(
1497-
remoteAddress, ptr);
1496+
readFullTrailingObjects<TargetExtensionContextDescriptor<Runtime>>(
1497+
remoteAddress, ptr, sizeof(TargetContextDescriptor<Runtime>));
14981498
break;
14991499
case ContextDescriptorKind::Anonymous:
15001500
success =
1501-
readFullContextDescriptor<TargetAnonymousContextDescriptor<Runtime>>(
1502-
remoteAddress, ptr);
1501+
readFullTrailingObjects<TargetAnonymousContextDescriptor<Runtime>>(
1502+
remoteAddress, ptr, sizeof(TargetContextDescriptor<Runtime>));
15031503
break;
15041504
case ContextDescriptorKind::Class:
1505-
success = readFullContextDescriptor<TargetClassDescriptor<Runtime>>(
1506-
remoteAddress, ptr);
1505+
success = readFullTrailingObjects<TargetClassDescriptor<Runtime>>(
1506+
remoteAddress, ptr, sizeof(TargetContextDescriptor<Runtime>));
15071507
break;
15081508
case ContextDescriptorKind::Enum:
1509-
success = readFullContextDescriptor<TargetEnumDescriptor<Runtime>>(
1510-
remoteAddress, ptr);
1509+
success = readFullTrailingObjects<TargetEnumDescriptor<Runtime>>(
1510+
remoteAddress, ptr, sizeof(TargetContextDescriptor<Runtime>));
15111511
break;
15121512
case ContextDescriptorKind::Struct:
1513-
success = readFullContextDescriptor<TargetStructDescriptor<Runtime>>(
1514-
remoteAddress, ptr);
1513+
success = readFullTrailingObjects<TargetStructDescriptor<Runtime>>(
1514+
remoteAddress, ptr, sizeof(TargetContextDescriptor<Runtime>));
15151515
break;
15161516
case ContextDescriptorKind::Protocol:
1517-
success = readFullContextDescriptor<TargetProtocolDescriptor<Runtime>>(
1518-
remoteAddress, ptr);
1517+
success = readFullTrailingObjects<TargetProtocolDescriptor<Runtime>>(
1518+
remoteAddress, ptr, sizeof(TargetContextDescriptor<Runtime>));
15191519
break;
15201520
case ContextDescriptorKind::OpaqueType:
1521-
success = readFullContextDescriptor<TargetOpaqueTypeDescriptor<Runtime>>(
1522-
remoteAddress, ptr);
1521+
success = readFullTrailingObjects<TargetOpaqueTypeDescriptor<Runtime>>(
1522+
remoteAddress, ptr, sizeof(TargetContextDescriptor<Runtime>));
15231523
break;
15241524
default:
15251525
// We don't know about this kind of context.
@@ -1535,12 +1535,18 @@ class MetadataReader {
15351535
return ContextDescriptorRef(remoteAddress, descriptor);
15361536
}
15371537

1538-
template <typename DescriptorTy>
1539-
bool readFullContextDescriptor(RemoteAddress address,
1540-
MemoryReader::ReadBytesResult &ptr) {
1538+
/// Read all memory occupied by a value with TrailingObjects. This will
1539+
/// incrementally read pieces of the object to figure out the full size of it.
1540+
/// - address: The address of the value.
1541+
/// - ptr: The bytes that have been read so far. On return, the full object.
1542+
/// - existingByteCount: The number of bytes in ptr.
1543+
template <typename BaseTy>
1544+
bool readFullTrailingObjects(RemoteAddress address,
1545+
MemoryReader::ReadBytesResult &ptr,
1546+
size_t existingByteCount) {
15411547
// Read the full base descriptor if it's bigger than what we have so far.
1542-
if (sizeof(DescriptorTy) > sizeof(TargetContextDescriptor<Runtime>)) {
1543-
ptr = Reader->template readObj<DescriptorTy>(address);
1548+
if (sizeof(BaseTy) > existingByteCount) {
1549+
ptr = Reader->template readObj<BaseTy>(address);
15441550
if (!ptr)
15451551
return false;
15461552
}
@@ -1556,13 +1562,17 @@ class MetadataReader {
15561562
// size. Once we've walked through all the trailing objects, we've read
15571563
// everything.
15581564

1559-
size_t sizeSoFar = sizeof(DescriptorTy);
1565+
size_t sizeSoFar = sizeof(BaseTy);
15601566

1561-
for (size_t i = 0; i < DescriptorTy::trailingTypeCount(); i++) {
1562-
const DescriptorTy *descriptorSoFar =
1563-
reinterpret_cast<const DescriptorTy *>(ptr.get());
1567+
for (size_t i = 0; i < BaseTy::trailingTypeCount(); i++) {
1568+
const BaseTy *descriptorSoFar =
1569+
reinterpret_cast<const BaseTy *>(ptr.get());
15641570
size_t thisSize = descriptorSoFar->sizeWithTrailingTypeCount(i);
15651571
if (thisSize > sizeSoFar) {
1572+
// Make sure we haven't ended up with a ridiculous size.
1573+
if (thisSize > MaxMetadataSize)
1574+
return false;
1575+
15661576
ptr = Reader->readBytes(address, thisSize);
15671577
if (!ptr)
15681578
return false;
@@ -2141,45 +2151,22 @@ class MetadataReader {
21412151

21422152
switch (getEnumeratedMetadataKind(KindValue)) {
21432153
case MetadataKind::Class:
2144-
2145-
return _readMetadata<TargetClassMetadataType>(address);
2146-
2154+
return _readMetadataFixedSize<TargetClassMetadataType>(address);
21472155
case MetadataKind::Enum:
2148-
return _readMetadata<TargetEnumMetadata>(address);
2156+
return _readMetadataFixedSize<TargetEnumMetadata>(address);
21492157
case MetadataKind::ErrorObject:
2150-
return _readMetadata<TargetEnumMetadata>(address);
2151-
case MetadataKind::Existential: {
2152-
RemoteAddress flagsAddress = address + sizeof(StoredPointer);
2153-
2154-
ExistentialTypeFlags::int_type flagsData;
2155-
if (!Reader->readInteger(flagsAddress, &flagsData))
2156-
return nullptr;
2157-
2158-
ExistentialTypeFlags flags(flagsData);
2159-
2160-
RemoteAddress numProtocolsAddress = flagsAddress + sizeof(flagsData);
2161-
uint32_t numProtocols;
2162-
if (!Reader->readInteger(numProtocolsAddress, &numProtocols))
2163-
return nullptr;
2164-
2165-
// Make sure the number of protocols is reasonable
2166-
if (numProtocols >= 256)
2167-
return nullptr;
2168-
2169-
auto totalSize = sizeof(TargetExistentialTypeMetadata<Runtime>)
2170-
+ numProtocols *
2171-
sizeof(ConstTargetMetadataPointer<Runtime, TargetProtocolDescriptor>);
2172-
2173-
if (flags.hasSuperclassConstraint())
2174-
totalSize += sizeof(StoredPointer);
2175-
2176-
return _readMetadata(address, totalSize);
2177-
}
2158+
return _readMetadataFixedSize<TargetMetadata>(address);
2159+
case MetadataKind::Existential:
2160+
return _readMetadataVariableSize<TargetExistentialTypeMetadata>(
2161+
address);
21782162
case MetadataKind::ExistentialMetatype:
2179-
return _readMetadata<TargetExistentialMetatypeMetadata>(address);
2163+
return _readMetadataFixedSize<TargetExistentialMetatypeMetadata>(
2164+
address);
21802165
case MetadataKind::ExtendedExistential: {
21812166
// We need to read the shape in order to figure out how large
2182-
// the generalization arguments are.
2167+
// the generalization arguments are. This prevents us from using
2168+
// _readMetadataVariableSize, which requires the Shape field to be
2169+
// dereferenceable here.
21832170
RemoteAddress shapeAddress = address + sizeof(StoredPointer);
21842171
RemoteAddress signedShapePtr;
21852172
if (!Reader->template readRemoteAddress<StoredPointer>(shapeAddress,
@@ -2198,46 +2185,24 @@ class MetadataReader {
21982185
return _readMetadata(address, totalSize);
21992186
}
22002187
case MetadataKind::ForeignClass:
2201-
return _readMetadata<TargetForeignClassMetadata>(address);
2188+
return _readMetadataFixedSize<TargetForeignClassMetadata>(address);
22022189
case MetadataKind::ForeignReferenceType:
2203-
return _readMetadata<TargetForeignReferenceTypeMetadata>(address);
2204-
case MetadataKind::Function: {
2205-
StoredSize flagsValue;
2206-
auto flagsAddr =
2207-
address + TargetFunctionTypeMetadata<Runtime>::OffsetToFlags;
2208-
if (!Reader->readInteger(flagsAddr, &flagsValue))
2209-
return nullptr;
2210-
2211-
auto flags =
2212-
TargetFunctionTypeFlags<StoredSize>::fromIntValue(flagsValue);
2213-
2214-
auto totalSize =
2215-
sizeof(TargetFunctionTypeMetadata<Runtime>) +
2216-
flags.getNumParameters() * sizeof(FunctionTypeMetadata::Parameter);
2217-
2218-
if (flags.hasParameterFlags())
2219-
totalSize += flags.getNumParameters() * sizeof(uint32_t);
2220-
2221-
if (flags.isDifferentiable())
2222-
totalSize = roundUpToAlignment(totalSize, sizeof(StoredPointer)) +
2223-
sizeof(TargetFunctionMetadataDifferentiabilityKind<
2224-
typename Runtime::StoredSize>);
2225-
2226-
return _readMetadata(address,
2227-
roundUpToAlignment(totalSize, sizeof(StoredPointer)));
2228-
}
2190+
return _readMetadataFixedSize<TargetForeignReferenceTypeMetadata>(
2191+
address);
2192+
case MetadataKind::Function:
2193+
return _readMetadataVariableSize<TargetFunctionTypeMetadata>(address);
22292194
case MetadataKind::HeapGenericLocalVariable:
2230-
return _readMetadata<TargetGenericBoxHeapMetadata>(address);
2195+
return _readMetadataFixedSize<TargetGenericBoxHeapMetadata>(address);
22312196
case MetadataKind::HeapLocalVariable:
2232-
return _readMetadata<TargetHeapLocalVariableMetadata>(address);
2197+
return _readMetadataFixedSize<TargetHeapLocalVariableMetadata>(address);
22332198
case MetadataKind::Metatype:
2234-
return _readMetadata<TargetMetatypeMetadata>(address);
2199+
return _readMetadataFixedSize<TargetMetatypeMetadata>(address);
22352200
case MetadataKind::ObjCClassWrapper:
2236-
return _readMetadata<TargetObjCClassWrapperMetadata>(address);
2201+
return _readMetadataFixedSize<TargetObjCClassWrapperMetadata>(address);
22372202
case MetadataKind::Optional:
2238-
return _readMetadata<TargetEnumMetadata>(address);
2203+
return _readMetadataFixedSize<TargetEnumMetadata>(address);
22392204
case MetadataKind::Struct:
2240-
return _readMetadata<TargetStructMetadata>(address);
2205+
return _readMetadataFixedSize<TargetStructMetadata>(address);
22412206
case MetadataKind::Tuple: {
22422207
auto numElementsAddress = address +
22432208
TargetTupleTypeMetadata<Runtime>::getOffsetToNumElements();
@@ -2255,7 +2220,7 @@ class MetadataReader {
22552220
}
22562221
case MetadataKind::Opaque:
22572222
default:
2258-
return _readMetadata<TargetOpaqueMetadata>(address);
2223+
return _readMetadataFixedSize<TargetOpaqueMetadata>(address);
22592224
}
22602225

22612226
// We can fall out here if the value wasn't actually a valid
@@ -2333,20 +2298,39 @@ class MetadataReader {
23332298

23342299
private:
23352300
template <template <class R> class M>
2336-
MetadataRef _readMetadata(RemoteAddress address) {
2301+
MetadataRef _readMetadataFixedSize(RemoteAddress address) {
2302+
static_assert(!ABI::typeHasTrailingObjects<M<Runtime>>(),
2303+
"Type must not have trailing objects. Use "
2304+
"_readMetadataVariableSize for types that have them.");
2305+
23372306
return _readMetadata(address, sizeof(M<Runtime>));
23382307
}
23392308

2309+
template <template <class R> class M>
2310+
MetadataRef _readMetadataVariableSize(RemoteAddress address) {
2311+
static_assert(ABI::typeHasTrailingObjects<M<Runtime>>(),
2312+
"Type must have trailing objects. Use _readMetadataFixedSize "
2313+
"for types that don't.");
2314+
2315+
MemoryReader::ReadBytesResult bytes;
2316+
auto readResult = readFullTrailingObjects<M<Runtime>>(address, bytes, 0);
2317+
if (!readResult)
2318+
return nullptr;
2319+
return _cacheMetadata(address, bytes);
2320+
}
2321+
23402322
MetadataRef _readMetadata(RemoteAddress address, size_t sizeAfter) {
23412323
if (sizeAfter > MaxMetadataSize)
23422324
return nullptr;
23432325
auto readResult = Reader->readBytes(address, sizeAfter);
2344-
if (!readResult)
2345-
return nullptr;
2326+
return _cacheMetadata(address, readResult);
2327+
}
23462328

2329+
MetadataRef _cacheMetadata(RemoteAddress address,
2330+
MemoryReader::ReadBytesResult &bytes) {
23472331
auto metadata =
2348-
reinterpret_cast<const TargetMetadata<Runtime> *>(readResult.get());
2349-
MetadataCache.insert(std::make_pair(address, std::move(readResult)));
2332+
reinterpret_cast<const TargetMetadata<Runtime> *>(bytes.get());
2333+
MetadataCache.insert(std::make_pair(address, std::move(bytes)));
23502334
return MetadataRef(address, metadata);
23512335
}
23522336

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Target Swift 5.5 so functions with global actors are encoded as a proper
2+
// mangled name, not a function accessor. Remote Mirror can't call function
3+
// accessors and will fail to read the type.
4+
// RUN: %empty-directory(%t)
5+
// RUN: %target-build-swift -target %target-swift-5.5-abi-triple -lswiftSwiftReflectionTest %s -o %t/function_types
6+
// RUN: %target-codesign %t/function_types
7+
8+
// RUN: %target-run %target-swift-reflection-test %t/function_types | %FileCheck %s --check-prefix=CHECK
9+
10+
// REQUIRES: reflection_test_support
11+
// REQUIRES: executable_test
12+
// UNSUPPORTED: use_os_stdlib
13+
// UNSUPPORTED: asan
14+
15+
import SwiftReflectionTest
16+
17+
struct S {
18+
var f = { @MainActor in }
19+
}
20+
21+
// This Task is necessary to ensure that the concurrency runtime is brought in.
22+
// Without that, the type lookup for @MainActor may fail.
23+
Task {}
24+
25+
// CHECK: Type reference:
26+
// CHECK: (struct function_types.S)
27+
28+
// CHECK: Type info:
29+
// CHECK: (struct size=
30+
// CHECK: (field name=f offset=0
31+
// CHECK: (thick_function size=
32+
// CHECK: (field name=function offset=0
33+
// CHECK: (builtin size=
34+
// CHECK: (field name=context
35+
// CHECK: (reference kind=strong refcounting=native)))))
36+
// CHECK: Mangled name: $s14function_types1SV
37+
// CHECK: Demangled name: function_types.S
38+
reflect(any: S())
39+
40+
// CHECK: Type reference:
41+
// CHECK: (function
42+
// CHECK: (global-actor
43+
// CHECK: (class Swift.MainActor))
44+
// CHECK: (parameters)
45+
// CHECK: (result
46+
// CHECK: (tuple))
47+
48+
// CHECK: Type info:
49+
// CHECK: (thick_function size=
50+
// CHECK: (field name=function offset=0
51+
// CHECK: (builtin size=
52+
// CHECK: (field name=context offset=
53+
// CHECK: (reference kind=strong refcounting=native)))
54+
// CHECK: Mangled name: $syyScMYcc
55+
// CHECK: Demangled name: @Swift.MainActor () -> ()
56+
reflect(any: S().f)
57+
58+
doneReflecting()
59+

0 commit comments

Comments
 (0)