@@ -80,6 +80,29 @@ int asprintf(char **strp, const char *fmt, ...) {
80
80
81
81
using namespace swift ;
82
82
83
+ class FieldType {
84
+ const Metadata *type;
85
+ bool indirect;
86
+ TypeReferenceOwnership referenceOwnership;
87
+ public:
88
+
89
+ constexpr FieldType () : type(nullptr ), indirect(false ), referenceOwnership() { }
90
+ constexpr FieldType (const Metadata *T) : type(T), indirect(false ), referenceOwnership() { }
91
+
92
+ static constexpr FieldType untypedEnumCase (bool indirect) {
93
+ FieldType type{};
94
+ type.indirect = indirect;
95
+ return type;
96
+ }
97
+ const Metadata *getType () const { return type; }
98
+ const TypeReferenceOwnership getReferenceOwnership () const { return referenceOwnership; }
99
+ bool isIndirect () const { return indirect; }
100
+ void setIndirect (bool value) { indirect = value; }
101
+ void setReferenceOwnership (TypeReferenceOwnership newOwnership) {
102
+ referenceOwnership = newOwnership;
103
+ }
104
+ };
105
+
83
106
#if SWIFT_OBJC_INTEROP
84
107
// Declare the debugQuickLookObject selector.
85
108
@interface DeclareSelectors
@@ -123,58 +146,60 @@ - (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
+ type->vw_initializeWithCopy (destContainer, fieldData);
168
+ }
169
+
170
+ static AnyReturn copyFieldContents (OpaqueValue *fieldData,
171
+ const FieldType fieldType) {
172
+ Any outValue;
173
+ auto *type = fieldType.getType ();
174
+ outValue.Type = type;
175
+ auto ownership = fieldType.getReferenceOwnership ();
176
+ auto *destContainer = type->allocateBoxForExistentialIn (&outValue.Buffer );
177
+
178
+ if (ownership.isStrong ()) {
179
+ type->vw_initializeWithCopy (destContainer, fieldData);
180
+ }
181
+
182
+ // Generate a conditional clause for every known ownership type
183
+ // If this causes errors, it's because someone added a new ownership type
184
+ // to ReferenceStorage.def and missed some related updates.
185
+ #define REF_STORAGE (Name, ...) \
186
+ else if (ownership.is ##Name ()) { \
187
+ copy##Name##FieldContents (destContainer, type, fieldData); \
188
+ }
189
+ #include " swift/AST/ReferenceStorage.def"
190
+
191
+ else {
192
+ // The field was declared with a reference type we don't understand.
193
+ warning (0 , " Value with unrecognized reference type is reflected as ()" );
194
+ // Clean up the buffer allocated above
195
+ type->deallocateBufferIn (&outValue.Buffer );
196
+ // Return an existential containing Void
197
+ Any emptyOutValue;
198
+ emptyOutValue.Type = &METADATA_SYM (EMPTY_TUPLE_MANGLING);
199
+ return AnyReturn (emptyOutValue);
200
+ }
201
+
202
+ return AnyReturn (outValue);
178
203
}
179
204
180
205
@@ -310,11 +335,7 @@ static bool _shouldReportMissingReflectionMetadataWarnings() {
310
335
" type '%*s' that claims to be reflectable. Its fields will show up as "
311
336
" 'unknown' in Mirrors\n " ,
312
337
(int )typeName.length , typeName.data );
313
- return {" unknown" ,
314
- FieldType ()
315
- .withType (&METADATA_SYM (EMPTY_TUPLE_MANGLING))
316
- .withIndirect (false )
317
- .withWeak (false )};
338
+ return {" unknown" , FieldType (&METADATA_SYM (EMPTY_TUPLE_MANGLING))};
318
339
};
319
340
320
341
auto *baseDesc = base->getTypeContextDescriptor ();
@@ -325,14 +346,13 @@ static bool _shouldReportMissingReflectionMetadataWarnings() {
325
346
if (!fields)
326
347
return failedToFindMetadata ();
327
348
328
- const FieldDescriptor &descriptor = *fields;
329
- auto &field = descriptor.getFields ()[index];
349
+ auto &field = fields->getFields ()[index];
330
350
// Bounds are always valid as the offset is constant.
331
351
auto name = field.getFieldName ();
332
352
333
353
// Enum cases don't always have types.
334
354
if (!field.hasMangledTypeName ())
335
- return {name, FieldType (). withIndirect (field.isIndirectCase ())};
355
+ return {name, FieldType::untypedEnumCase (field.isIndirectCase ())};
336
356
337
357
auto typeName = field.getMangledTypeName ();
338
358
@@ -360,10 +380,10 @@ static bool _shouldReportMissingReflectionMetadataWarnings() {
360
380
(int )typeName.size (), typeName.data ());
361
381
}
362
382
363
- return {name, FieldType ()
364
- . withType (typeInfo. getMetadata ())
365
- . withIndirect (field. isIndirectCase ())
366
- . withWeak (typeInfo. isWeak ()) };
383
+ auto fieldType = FieldType (typeInfo. getMetadata ());
384
+ fieldType. setIndirect (field. isIndirectCase ());
385
+ fieldType. setReferenceOwnership (typeInfo. getReferenceOwnership ());
386
+ return {name, fieldType };
367
387
}
368
388
369
389
// Implementation for structs.
@@ -397,7 +417,6 @@ AnyReturn subscript(intptr_t i, const char **outName,
397
417
// Load the offset from its respective vector.
398
418
auto fieldOffset = Struct->getFieldOffsets ()[i];
399
419
400
- Any result;
401
420
StringRef name;
402
421
FieldType fieldInfo;
403
422
std::tie (name, fieldInfo) = getFieldAt (type, i);
@@ -409,15 +428,7 @@ AnyReturn subscript(intptr_t i, const char **outName,
409
428
auto *bytes = reinterpret_cast <char *>(value);
410
429
auto *fieldData = reinterpret_cast <OpaqueValue *>(bytes + fieldOffset);
411
430
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);
431
+ return copyFieldContents (fieldData, fieldInfo);
421
432
}
422
433
};
423
434
@@ -559,7 +570,6 @@ AnyReturn subscript(intptr_t i, const char **outName,
559
570
#endif
560
571
}
561
572
562
- Any result;
563
573
StringRef name;
564
574
FieldType fieldInfo;
565
575
std::tie (name, fieldInfo) = getFieldAt (type, i);
@@ -571,15 +581,7 @@ AnyReturn subscript(intptr_t i, const char **outName,
571
581
*outName = name.data ();
572
582
*outFreeFunc = nullptr ;
573
583
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);
584
+ return copyFieldContents (fieldData, fieldInfo);
583
585
}
584
586
585
587
#if SWIFT_OBJC_INTEROP
0 commit comments