@@ -89,6 +89,29 @@ - (id)debugQuickLookObject;
89
89
90
90
namespace {
91
91
92
+ class FieldType {
93
+ const Metadata *type;
94
+ bool indirect;
95
+ TypeReferenceOwnership referenceOwnership;
96
+ public:
97
+
98
+ constexpr FieldType () : type(nullptr ), indirect(false ), referenceOwnership() { }
99
+ constexpr FieldType (const Metadata *T) : type(T), indirect(false ), referenceOwnership() { }
100
+
101
+ static constexpr FieldType untypedEnumCase (bool indirect) {
102
+ FieldType type{};
103
+ type.indirect = indirect;
104
+ return type;
105
+ }
106
+ const Metadata *getType () const { return type; }
107
+ const TypeReferenceOwnership getReferenceOwnership () const { return referenceOwnership; }
108
+ bool isIndirect () const { return indirect; }
109
+ void setIndirect (bool value) { indirect = value; }
110
+ void setReferenceOwnership (TypeReferenceOwnership newOwnership) {
111
+ referenceOwnership = newOwnership;
112
+ }
113
+ };
114
+
92
115
// / The layout of Any.
93
116
using Any = OpaqueExistentialContainer;
94
117
@@ -123,58 +146,63 @@ - (id)debugQuickLookObject;
123
146
return std::make_tuple (T, Value);
124
147
}
125
148
126
- static bool loadSpecialReferenceStorage (OpaqueValue *fieldData,
127
- const FieldType fieldType,
128
- Any *outValue) {
129
- // isWeak() implies a reference type via Sema.
130
- if (!fieldType.isWeak ())
131
- return false ;
132
-
133
- auto type = fieldType.getType ();
149
+ static void copyWeakFieldContents (OpaqueValue *destContainer, const Metadata *type, OpaqueValue *fieldData) {
134
150
assert (type->getKind () == MetadataKind::Optional);
151
+ auto *srcContainer = reinterpret_cast <WeakClassExistentialContainer*>(fieldData);
152
+ auto *destClassContainer = reinterpret_cast <ClassExistentialContainer*>(destContainer);
153
+ destClassContainer->Value = swift_unknownObjectWeakLoadStrong (&srcContainer->Value );
154
+ auto witnessTablesSize = type->vw_size () - sizeof (WeakClassExistentialContainer);
155
+ memcpy (destClassContainer->getWitnessTables (), srcContainer->getWitnessTables (), witnessTablesSize);
156
+ }
135
157
136
- auto *weakField = reinterpret_cast <WeakReference *>(fieldData);
137
- auto *strongValue = swift_unknownObjectWeakLoadStrong (weakField);
138
-
139
- // Now that we have a strong reference, we need to create a temporary buffer
140
- // from which to copy the whole value, which might be a native class-bound
141
- // existential, which means we also need to copy n witness tables, for
142
- // however many protocols are in the protocol composition. For example, if we
143
- // are copying a:
144
- // weak var myWeakProperty : (Protocol1 & Protocol2)?
145
- // then we need to copy three values:
146
- // - the instance
147
- // - the witness table for Protocol1
148
- // - the witness table for Protocol2
149
-
150
- auto *weakContainer =
151
- reinterpret_cast <WeakClassExistentialContainer *>(fieldData);
152
-
153
- // Create a temporary existential where we can put the strong reference.
154
- // The allocateBuffer value witness requires a ValueBuffer to own the
155
- // allocated storage.
156
- ValueBuffer temporaryBuffer;
157
-
158
- auto *temporaryValue = reinterpret_cast <ClassExistentialContainer *>(
159
- type->allocateBufferIn (&temporaryBuffer));
160
-
161
- // Now copy the entire value out of the parent, which will include the
162
- // witness tables.
163
- temporaryValue->Value = strongValue;
164
- auto valueWitnessesSize = type->getValueWitnesses ()->getSize () -
165
- sizeof (WeakClassExistentialContainer);
166
- memcpy (temporaryValue->getWitnessTables (), weakContainer->getWitnessTables (),
167
- valueWitnessesSize);
168
-
169
- outValue->Type = type;
170
- auto *opaqueValueAddr = type->allocateBoxForExistentialIn (&outValue->Buffer );
171
- type->vw_initializeWithCopy (opaqueValueAddr,
172
- reinterpret_cast <OpaqueValue *>(temporaryValue));
173
-
174
- type->deallocateBufferIn (&temporaryBuffer);
175
- swift_unknownObjectRelease (strongValue);
176
-
177
- return true ;
158
+ static void copyUnownedFieldContents (OpaqueValue *destContainer, const Metadata *type, OpaqueValue *fieldData) {
159
+ auto *srcContainer = reinterpret_cast <UnownedClassExistentialContainer*>(fieldData);
160
+ auto *destClassContainer = reinterpret_cast <ClassExistentialContainer*>(destContainer);
161
+ destClassContainer->Value = swift_unknownObjectUnownedLoadStrong (&srcContainer->Value );
162
+ auto witnessTablesSize = type->vw_size () - sizeof (UnownedClassExistentialContainer);
163
+ memcpy (destClassContainer->getWitnessTables (), srcContainer->getWitnessTables (), witnessTablesSize);
164
+ }
165
+
166
+ static void copyUnmanagedFieldContents (OpaqueValue *destContainer, const Metadata *type, OpaqueValue *fieldData) {
167
+ // Also known as "unowned(unsafe)".
168
+ // This is simpler than the unowned/weak cases because unmanaged
169
+ // references are fundamentally the same as strong ones, so we
170
+ // can use the regular strong reference support that already
171
+ // knows how to handle existentials and Obj-C references.
172
+ type->vw_initializeWithCopy (destContainer, fieldData);
173
+ }
174
+
175
+ static AnyReturn copyFieldContents (OpaqueValue *fieldData,
176
+ const FieldType fieldType) {
177
+ Any outValue;
178
+ auto *type = fieldType.getType ();
179
+ outValue.Type = type;
180
+ auto ownership = fieldType.getReferenceOwnership ();
181
+ auto *destContainer = type->allocateBoxForExistentialIn (&outValue.Buffer );
182
+
183
+ if (ownership.isStrong ()) {
184
+ type->vw_initializeWithCopy (destContainer, fieldData);
185
+ }
186
+
187
+ // Generate a conditional clause for every known ownership type.
188
+ // If this causes errors, it's because someone added a new ownership type
189
+ // to ReferenceStorage.def and missed some related updates.
190
+ #define REF_STORAGE (Name, ...) \
191
+ else if (ownership.is ##Name ()) { \
192
+ copy##Name##FieldContents (destContainer, type, fieldData); \
193
+ }
194
+ #include " swift/AST/ReferenceStorage.def"
195
+
196
+ else {
197
+ // The field was declared with a reference type we don't understand.
198
+ warning (0 , " Value with unrecognized reference type is reflected as ()" );
199
+ // Clean up the buffer allocated above
200
+ type->deallocateBoxForExistentialIn (&outValue.Buffer );
201
+ // Return an existential containing Void
202
+ outValue.Type = &METADATA_SYM (EMPTY_TUPLE_MANGLING);
203
+ }
204
+
205
+ return AnyReturn (outValue);
178
206
}
179
207
180
208
@@ -310,11 +338,7 @@ static bool _shouldReportMissingReflectionMetadataWarnings() {
310
338
" type '%*s' that claims to be reflectable. Its fields will show up as "
311
339
" 'unknown' in Mirrors\n " ,
312
340
(int )typeName.length , typeName.data );
313
- return {" unknown" ,
314
- FieldType ()
315
- .withType (&METADATA_SYM (EMPTY_TUPLE_MANGLING))
316
- .withIndirect (false )
317
- .withWeak (false )};
341
+ return {" unknown" , FieldType (&METADATA_SYM (EMPTY_TUPLE_MANGLING))};
318
342
};
319
343
320
344
auto *baseDesc = base->getTypeContextDescriptor ();
@@ -325,14 +349,13 @@ static bool _shouldReportMissingReflectionMetadataWarnings() {
325
349
if (!fields)
326
350
return failedToFindMetadata ();
327
351
328
- const FieldDescriptor &descriptor = *fields;
329
- auto &field = descriptor.getFields ()[index];
352
+ auto &field = fields->getFields ()[index];
330
353
// Bounds are always valid as the offset is constant.
331
354
auto name = field.getFieldName ();
332
355
333
356
// Enum cases don't always have types.
334
357
if (!field.hasMangledTypeName ())
335
- return {name, FieldType (). withIndirect (field.isIndirectCase ())};
358
+ return {name, FieldType::untypedEnumCase (field.isIndirectCase ())};
336
359
337
360
auto typeName = field.getMangledTypeName ();
338
361
@@ -360,10 +383,10 @@ static bool _shouldReportMissingReflectionMetadataWarnings() {
360
383
(int )typeName.size (), typeName.data ());
361
384
}
362
385
363
- return {name, FieldType ()
364
- . withType (typeInfo. getMetadata ())
365
- . withIndirect (field. isIndirectCase ())
366
- . withWeak (typeInfo. isWeak ()) };
386
+ auto fieldType = FieldType (typeInfo. getMetadata ());
387
+ fieldType. setIndirect (field. isIndirectCase ());
388
+ fieldType. setReferenceOwnership (typeInfo. getReferenceOwnership ());
389
+ return {name, fieldType };
367
390
}
368
391
369
392
// Implementation for structs.
@@ -397,7 +420,6 @@ AnyReturn subscript(intptr_t i, const char **outName,
397
420
// Load the offset from its respective vector.
398
421
auto fieldOffset = Struct->getFieldOffsets ()[i];
399
422
400
- Any result;
401
423
StringRef name;
402
424
FieldType fieldInfo;
403
425
std::tie (name, fieldInfo) = getFieldAt (type, i);
@@ -409,15 +431,7 @@ AnyReturn subscript(intptr_t i, const char **outName,
409
431
auto *bytes = reinterpret_cast <char *>(value);
410
432
auto *fieldData = reinterpret_cast <OpaqueValue *>(bytes + fieldOffset);
411
433
412
- bool didLoad = loadSpecialReferenceStorage (fieldData, fieldInfo, &result);
413
- if (!didLoad) {
414
- result.Type = fieldInfo.getType ();
415
- auto *opaqueValueAddr = result.Type ->allocateBoxForExistentialIn (&result.Buffer );
416
- result.Type ->vw_initializeWithCopy (opaqueValueAddr,
417
- const_cast <OpaqueValue *>(fieldData));
418
- }
419
-
420
- return AnyReturn (result);
434
+ return copyFieldContents (fieldData, fieldInfo);
421
435
}
422
436
};
423
437
@@ -559,7 +573,6 @@ AnyReturn subscript(intptr_t i, const char **outName,
559
573
#endif
560
574
}
561
575
562
- Any result;
563
576
StringRef name;
564
577
FieldType fieldInfo;
565
578
std::tie (name, fieldInfo) = getFieldAt (type, i);
@@ -571,15 +584,7 @@ AnyReturn subscript(intptr_t i, const char **outName,
571
584
*outName = name.data ();
572
585
*outFreeFunc = nullptr ;
573
586
574
- bool didLoad = loadSpecialReferenceStorage (fieldData, fieldInfo, &result);
575
- if (!didLoad) {
576
- result.Type = fieldInfo.getType ();
577
- auto *opaqueValueAddr = result.Type ->allocateBoxForExistentialIn (&result.Buffer );
578
- result.Type ->vw_initializeWithCopy (opaqueValueAddr,
579
- const_cast <OpaqueValue *>(fieldData));
580
- }
581
-
582
- return AnyReturn (result);
587
+ return copyFieldContents (fieldData, fieldInfo);
583
588
}
584
589
585
590
#if SWIFT_OBJC_INTEROP
0 commit comments