@@ -89,29 +89,6 @@ - (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
-
115
92
// / The layout of Any.
116
93
using Any = OpaqueExistentialContainer;
117
94
@@ -146,63 +123,58 @@ void setReferenceOwnership(TypeReferenceOwnership newOwnership) {
146
123
return std::make_tuple (T, Value);
147
124
}
148
125
149
- static void copyWeakFieldContents (OpaqueValue *destContainer, const Metadata *type, OpaqueValue *fieldData) {
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
- }
157
-
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
- }
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 ;
186
132
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
- }
133
+ auto type = fieldType.getType ();
134
+ assert (type->getKind () == MetadataKind::Optional);
204
135
205
- return AnyReturn (outValue);
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 ;
206
178
}
207
179
208
180
@@ -338,7 +310,11 @@ static bool _shouldReportMissingReflectionMetadataWarnings() {
338
310
" type '%*s' that claims to be reflectable. Its fields will show up as "
339
311
" 'unknown' in Mirrors\n " ,
340
312
(int )typeName.length , typeName.data );
341
- return {" unknown" , FieldType (&METADATA_SYM (EMPTY_TUPLE_MANGLING))};
313
+ return {" unknown" ,
314
+ FieldType ()
315
+ .withType (&METADATA_SYM (EMPTY_TUPLE_MANGLING))
316
+ .withIndirect (false )
317
+ .withWeak (false )};
342
318
};
343
319
344
320
auto *baseDesc = base->getTypeContextDescriptor ();
@@ -349,13 +325,14 @@ static bool _shouldReportMissingReflectionMetadataWarnings() {
349
325
if (!fields)
350
326
return failedToFindMetadata ();
351
327
352
- auto &field = fields->getFields ()[index];
328
+ const FieldDescriptor &descriptor = *fields;
329
+ auto &field = descriptor.getFields ()[index];
353
330
// Bounds are always valid as the offset is constant.
354
331
auto name = field.getFieldName ();
355
332
356
333
// Enum cases don't always have types.
357
334
if (!field.hasMangledTypeName ())
358
- return {name, FieldType::untypedEnumCase (field.isIndirectCase ())};
335
+ return {name, FieldType (). withIndirect (field.isIndirectCase ())};
359
336
360
337
auto typeName = field.getMangledTypeName ();
361
338
@@ -383,10 +360,10 @@ static bool _shouldReportMissingReflectionMetadataWarnings() {
383
360
(int )typeName.size (), typeName.data ());
384
361
}
385
362
386
- auto fieldType = FieldType (typeInfo. getMetadata ());
387
- fieldType. setIndirect (field. isIndirectCase ());
388
- fieldType. setReferenceOwnership (typeInfo. getReferenceOwnership ());
389
- return {name, fieldType };
363
+ return {name, FieldType ()
364
+ . withType (typeInfo. getMetadata ())
365
+ . withIndirect (field. isIndirectCase ())
366
+ . withWeak (typeInfo. isWeak ()) };
390
367
}
391
368
392
369
// Implementation for structs.
@@ -420,6 +397,7 @@ AnyReturn subscript(intptr_t i, const char **outName,
420
397
// Load the offset from its respective vector.
421
398
auto fieldOffset = Struct->getFieldOffsets ()[i];
422
399
400
+ Any result;
423
401
StringRef name;
424
402
FieldType fieldInfo;
425
403
std::tie (name, fieldInfo) = getFieldAt (type, i);
@@ -431,7 +409,15 @@ AnyReturn subscript(intptr_t i, const char **outName,
431
409
auto *bytes = reinterpret_cast <char *>(value);
432
410
auto *fieldData = reinterpret_cast <OpaqueValue *>(bytes + fieldOffset);
433
411
434
- return copyFieldContents (fieldData, fieldInfo);
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);
435
421
}
436
422
};
437
423
@@ -573,6 +559,7 @@ AnyReturn subscript(intptr_t i, const char **outName,
573
559
#endif
574
560
}
575
561
562
+ Any result;
576
563
StringRef name;
577
564
FieldType fieldInfo;
578
565
std::tie (name, fieldInfo) = getFieldAt (type, i);
@@ -584,7 +571,15 @@ AnyReturn subscript(intptr_t i, const char **outName,
584
571
*outName = name.data ();
585
572
*outFreeFunc = nullptr ;
586
573
587
- return copyFieldContents (fieldData, fieldInfo);
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);
588
583
}
589
584
590
585
#if SWIFT_OBJC_INTEROP
0 commit comments