Skip to content

Commit ca693ee

Browse files
authored
Revert "SR-5289: Teach Mirror how to handle unowned/unmanaged references (#28368)"
This reverts commit 9c638ae.
1 parent ea1d5ef commit ca693ee

File tree

7 files changed

+142
-335
lines changed

7 files changed

+142
-335
lines changed

include/swift/ABI/Metadata.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ using TargetRelativeIndirectablePointer
160160

161161
struct HeapObject;
162162
class WeakReference;
163-
struct UnownedReference;
164163

165164
template <typename Runtime> struct TargetMetadata;
166165
using Metadata = TargetMetadata<InProcess>;
@@ -646,9 +645,6 @@ struct TargetMetadata {
646645
// NOTE: This *is* a box for copy-on-write existentials.
647646
OpaqueValue *allocateBoxForExistentialIn(ValueBuffer *Buffer) const;
648647

649-
// Deallocate an out-of-line buffer box if one is present.
650-
void deallocateBoxForExistentialIn(ValueBuffer *Buffer) const;
651-
652648
/// Get the nominal type descriptor if this metadata describes a nominal type,
653649
/// or return null if it does not.
654650
ConstTargetMetadataPointer<Runtime, TargetTypeContextDescriptor>

include/swift/ABI/MetadataValues.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,55 @@ class TargetTupleTypeFlags {
913913
};
914914
using TupleTypeFlags = TargetTupleTypeFlags<size_t>;
915915

916+
/// Field types and flags as represented in a nominal type's field/case type
917+
/// vector.
918+
class FieldType {
919+
typedef uintptr_t int_type;
920+
// Type metadata is always at least pointer-aligned, so we get at least two
921+
// low bits to stash flags. We could use three low bits on 64-bit, and maybe
922+
// some high bits as well.
923+
enum : int_type {
924+
Indirect = 1,
925+
Weak = 2,
926+
927+
TypeMask = ((uintptr_t)-1) & ~(alignof(void*) - 1),
928+
};
929+
int_type Data;
930+
931+
constexpr FieldType(int_type Data) : Data(Data) {}
932+
public:
933+
constexpr FieldType() : Data(0) {}
934+
FieldType withType(const Metadata *T) const {
935+
return FieldType((Data & ~TypeMask) | (uintptr_t)T);
936+
}
937+
938+
constexpr FieldType withIndirect(bool indirect) const {
939+
return FieldType((Data & ~Indirect)
940+
| (indirect ? Indirect : 0));
941+
}
942+
943+
constexpr FieldType withWeak(bool weak) const {
944+
return FieldType((Data & ~Weak)
945+
| (weak ? Weak : 0));
946+
}
947+
948+
bool isIndirect() const {
949+
return bool(Data & Indirect);
950+
}
951+
952+
bool isWeak() const {
953+
return bool(Data & Weak);
954+
}
955+
956+
const Metadata *getType() const {
957+
return (const Metadata *)(Data & TypeMask);
958+
}
959+
960+
int_type getIntValue() const {
961+
return Data;
962+
}
963+
};
964+
916965
/// Flags for exclusivity-checking operations.
917966
enum class ExclusivityFlags : uintptr_t {
918967
Read = 0x0,

include/swift/Runtime/ExistentialContainer.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,6 @@ struct ClassExistentialContainerImpl {
9595
using ClassExistentialContainer = ClassExistentialContainerImpl<void *>;
9696
using WeakClassExistentialContainer =
9797
ClassExistentialContainerImpl<WeakReference>;
98-
using UnownedClassExistentialContainer =
99-
ClassExistentialContainerImpl<UnownedReference>;
10098

10199
} // end swift namespace
102100

stdlib/public/runtime/Metadata.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3862,13 +3862,6 @@ template <> OpaqueValue *Metadata::allocateBoxForExistentialIn(ValueBuffer *buff
38623862
return refAndValueAddr.buffer;
38633863
}
38643864

3865-
template <> void Metadata::deallocateBoxForExistentialIn(ValueBuffer *buffer) const {
3866-
auto *vwt = getValueWitnesses();
3867-
if (vwt->isValueInline())
3868-
return;
3869-
swift_deallocBox(reinterpret_cast<HeapObject *>(buffer->PrivateData[0]));
3870-
}
3871-
38723865
template <> OpaqueValue *Metadata::allocateBufferIn(ValueBuffer *buffer) const {
38733866
auto *vwt = getValueWitnesses();
38743867
if (vwt->isValueInline())

stdlib/public/runtime/Private.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,8 @@ class TypeReferenceOwnership {
5050

5151
#define REF_STORAGE(Name, ...) \
5252
void set##Name() { Data |= Name; } \
53-
bool is##Name() const { return Data == Name; }
53+
bool is##Name() const { return Data & Name; }
5454
#include "swift/AST/ReferenceStorage.def"
55-
56-
bool isStrong() const { return Data == 0; }
5755
};
5856

5957
/// Type information consists of metadata and its ownership info,
@@ -78,11 +76,9 @@ class TypeInfo {
7876
const Metadata *getMetadata() const { return Response.Value; }
7977
MetadataResponse getResponse() const { return Response; }
8078

81-
#define REF_STORAGE(Name, ...) \
82-
bool is##Name() const { return ReferenceOwnership.is##Name(); }
83-
#include "swift/AST/ReferenceStorage.def"
84-
85-
bool isStrong() const { return ReferenceOwnership.isStrong(); }
79+
bool isWeak() const { return ReferenceOwnership.isWeak(); }
80+
bool isUnowned() const { return ReferenceOwnership.isUnowned(); }
81+
bool isUnmanaged() const { return ReferenceOwnership.isUnmanaged(); }
8682

8783
TypeReferenceOwnership getReferenceOwnership() const {
8884
return ReferenceOwnership;

stdlib/public/runtime/ReflectionMirror.mm

Lines changed: 82 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -89,29 +89,6 @@ - (id)debugQuickLookObject;
8989

9090
namespace {
9191

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-
11592
/// The layout of Any.
11693
using Any = OpaqueExistentialContainer;
11794

@@ -146,63 +123,58 @@ void setReferenceOwnership(TypeReferenceOwnership newOwnership) {
146123
return std::make_tuple(T, Value);
147124
}
148125

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;
186132

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);
204135

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;
206178
}
207179

208180

@@ -338,7 +310,11 @@ static bool _shouldReportMissingReflectionMetadataWarnings() {
338310
"type '%*s' that claims to be reflectable. Its fields will show up as "
339311
"'unknown' in Mirrors\n",
340312
(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)};
342318
};
343319

344320
auto *baseDesc = base->getTypeContextDescriptor();
@@ -349,13 +325,14 @@ static bool _shouldReportMissingReflectionMetadataWarnings() {
349325
if (!fields)
350326
return failedToFindMetadata();
351327

352-
auto &field = fields->getFields()[index];
328+
const FieldDescriptor &descriptor = *fields;
329+
auto &field = descriptor.getFields()[index];
353330
// Bounds are always valid as the offset is constant.
354331
auto name = field.getFieldName();
355332

356333
// Enum cases don't always have types.
357334
if (!field.hasMangledTypeName())
358-
return {name, FieldType::untypedEnumCase(field.isIndirectCase())};
335+
return {name, FieldType().withIndirect(field.isIndirectCase())};
359336

360337
auto typeName = field.getMangledTypeName();
361338

@@ -383,10 +360,10 @@ static bool _shouldReportMissingReflectionMetadataWarnings() {
383360
(int)typeName.size(), typeName.data());
384361
}
385362

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())};
390367
}
391368

392369
// Implementation for structs.
@@ -420,6 +397,7 @@ AnyReturn subscript(intptr_t i, const char **outName,
420397
// Load the offset from its respective vector.
421398
auto fieldOffset = Struct->getFieldOffsets()[i];
422399

400+
Any result;
423401
StringRef name;
424402
FieldType fieldInfo;
425403
std::tie(name, fieldInfo) = getFieldAt(type, i);
@@ -431,7 +409,15 @@ AnyReturn subscript(intptr_t i, const char **outName,
431409
auto *bytes = reinterpret_cast<char*>(value);
432410
auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
433411

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);
435421
}
436422
};
437423

@@ -573,6 +559,7 @@ AnyReturn subscript(intptr_t i, const char **outName,
573559
#endif
574560
}
575561

562+
Any result;
576563
StringRef name;
577564
FieldType fieldInfo;
578565
std::tie(name, fieldInfo) = getFieldAt(type, i);
@@ -584,7 +571,15 @@ AnyReturn subscript(intptr_t i, const char **outName,
584571
*outName = name.data();
585572
*outFreeFunc = nullptr;
586573

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);
588583
}
589584

590585
#if SWIFT_OBJC_INTEROP

0 commit comments

Comments
 (0)