Skip to content

Commit a420279

Browse files
authored
Merge pull request #4060 from bitjammer/weak-reference-in-mirror-existential
Always, no, never... forget to check your references
2 parents af36803 + 302fe96 commit a420279

File tree

6 files changed

+263
-22
lines changed

6 files changed

+263
-22
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ class FieldType {
520520
// some high bits as well.
521521
enum : int_type {
522522
Indirect = 1,
523+
Weak = 2,
523524

524525
TypeMask = ((uintptr_t)-1) & ~(alignof(void*) - 1),
525526
};
@@ -537,10 +538,19 @@ class FieldType {
537538
| (indirect ? Indirect : 0));
538539
}
539540

541+
constexpr FieldType withWeak(bool weak) const {
542+
return FieldType((Data & ~Weak)
543+
| (weak ? Weak : 0));
544+
}
545+
540546
bool isIndirect() const {
541547
return bool(Data & Indirect);
542548
}
543549

550+
bool isWeak() const {
551+
return bool(Data & Weak);
552+
}
553+
544554
const Metadata *getType() const {
545555
return (const Metadata *)(Data & TypeMask);
546556
}

include/swift/Runtime/HeapObject.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -899,8 +899,8 @@ extern "C" void *swift_unknownWeakLoadStrong(WeakReference *ref);
899899

900900
#else
901901

902-
static inline void swift_unknownWeakLoadStrong(WeakReference *ref) {
903-
swift_weakLoadStrong(ref);
902+
static inline void *swift_unknownWeakLoadStrong(WeakReference *ref) {
903+
return static_cast<void *>(swift_weakLoadStrong(ref));
904904
}
905905

906906
#endif /* SWIFT_OBJC_INTEROP */
@@ -918,8 +918,8 @@ extern "C" void *swift_unknownWeakTakeStrong(WeakReference *ref);
918918

919919
#else
920920

921-
static inline void swift_unknownWeakTakeStrong(WeakReference *ref) {
922-
swift_weakTakeStrong(ref);
921+
static inline void *swift_unknownWeakTakeStrong(WeakReference *ref) {
922+
return static_cast<void *>(swift_weakTakeStrong(ref));
923923
}
924924

925925
#endif /* SWIFT_OBJC_INTEROP */

lib/IRGen/GenMeta.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2414,8 +2414,10 @@ namespace {
24142414
NominalTypeDecl::StoredPropertyRange storedProperties){
24152415
SmallVector<FieldTypeInfo, 4> types;
24162416
for (VarDecl *prop : storedProperties) {
2417-
types.push_back(FieldTypeInfo(prop->getType()->getCanonicalType(),
2418-
/*indirect*/ false));
2417+
auto propertyType = prop->getType()->getCanonicalType();
2418+
types.push_back(FieldTypeInfo(propertyType,
2419+
/*indirect*/ false,
2420+
propertyType->is<WeakStorageType>()));
24192421
}
24202422
return getFieldTypeAccessorFn(IGM, type, types);
24212423
}
@@ -2431,7 +2433,7 @@ namespace {
24312433
auto caseType = elt.decl->getArgumentType()->getCanonicalType();
24322434
bool isIndirect = elt.decl->isIndirect()
24332435
|| elt.decl->getParentEnum()->isIndirect();
2434-
types.push_back(FieldTypeInfo(caseType, isIndirect));
2436+
types.push_back(FieldTypeInfo(caseType, isIndirect, /*weak*/ false));
24352437
}
24362438
return getFieldTypeAccessorFn(IGM, type, types);
24372439
}
@@ -2784,9 +2786,13 @@ irgen::emitFieldTypeAccessor(IRGenModule &IGM,
27842786

27852787
auto metadata = IGF.emitTypeMetadataRef(fieldTy);
27862788

2789+
auto fieldTypeInfo = fieldTypes[i];
2790+
27872791
// Mix in flag bits.
2788-
if (fieldTypes[i].isIndirect()) {
2789-
auto flags = FieldType().withIndirect(true);
2792+
if (fieldTypeInfo.hasFlags()) {
2793+
auto flags = FieldType()
2794+
.withIndirect(fieldTypeInfo.isIndirect())
2795+
.withWeak(fieldTypeInfo.isWeak());
27902796
auto metadataBits = IGF.Builder.CreatePtrToInt(metadata, IGF.IGM.SizeTy);
27912797
metadataBits = IGF.Builder.CreateOr(metadataBits,
27922798
llvm::ConstantInt::get(IGF.IGM.SizeTy, flags.getIntValue()));

lib/IRGen/IRGenModule.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,25 +133,30 @@ class IRGenModule;
133133

134134
/// A type descriptor for a field type accessor.
135135
class FieldTypeInfo {
136-
llvm::PointerIntPair<CanType, 1, unsigned> Info;
136+
llvm::PointerIntPair<CanType, 2, unsigned> Info;
137137
/// Bits in the "int" part of the Info pair.
138138
enum : unsigned {
139139
/// Flag indicates that the case is indirectly stored in a box.
140140
Indirect = 1,
141+
/// Indicates a weak optional reference
142+
Weak = 2,
141143
};
142144

143-
static unsigned getFlags(bool indirect) {
144-
return (indirect ? Indirect : 0);
145+
static unsigned getFlags(bool indirect, bool weak) {
146+
return (indirect ? Indirect : 0)
147+
| (weak ? Weak : 0);
145148
// | (blah ? Blah : 0) ...
146149
}
147150

148151
public:
149-
FieldTypeInfo(CanType type, bool indirect)
150-
: Info(type, getFlags(indirect))
152+
FieldTypeInfo(CanType type, bool indirect, bool weak)
153+
: Info(type, getFlags(indirect, weak))
151154
{}
152155

153156
CanType getType() const { return Info.getPointer(); }
154157
bool isIndirect() const { return Info.getInt() & Indirect; }
158+
bool isWeak() const { return Info.getInt() & Weak; }
159+
bool hasFlags() const { return Info.getInt() != 0; }
155160
};
156161

157162
/// The principal singleton which manages all of IR generation.

stdlib/public/runtime/Reflection.mm

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,40 @@ void swift_TupleMirror_subscript(String *outString,
398398
return fieldName;
399399
}
400400

401+
402+
static bool loadSpecialReferenceStorage(HeapObject *owner,
403+
OpaqueValue *fieldData,
404+
const FieldType fieldType,
405+
Mirror *outMirror) {
406+
// TODO: Switch over the other kinds of reference storage here:
407+
// - unowned(safe)
408+
// - unowned(unsafe)
409+
// - class-bound existentials
410+
// - Optional existential types
411+
// This will require a change in the two low flag bits in the field type
412+
// returned from the field type accessor generated by IRGen.
413+
414+
// isWeak() implies a reference type via Sema.
415+
if (!fieldType.isWeak())
416+
return false;
417+
418+
auto weakField = reinterpret_cast<WeakReference *>(fieldData);
419+
auto strongValue = swift_unknownWeakLoadStrong(weakField);
420+
fieldData = reinterpret_cast<OpaqueValue *>(&strongValue);
421+
422+
// This MagicMirror constructor creates a box to hold the loaded refernce
423+
// value, which becomes the new owner for the value.
424+
new (outMirror) MagicMirror(fieldData, fieldType.getType(), /*take*/ true);
425+
426+
// However, swift_StructMirror_subscript and swift_ClassMirror_subscript
427+
// requires that the owner be consumed. Since we have the new heap box as the
428+
// owner now, we need to release the old owner to maintain the contract.
429+
if (owner->metadata->isAnyClass())
430+
swift_unknownRelease(owner);
431+
432+
return true;
433+
}
434+
401435
// -- Struct destructuring.
402436

403437
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
@@ -416,7 +450,7 @@ void swift_StructMirror_subscript(String *outString,
416450
Mirror *outMirror,
417451
intptr_t i,
418452
HeapObject *owner,
419-
const OpaqueValue *value,
453+
OpaqueValue *value,
420454
const Metadata *type) {
421455
auto Struct = static_cast<const StructMetadata *>(type);
422456

@@ -427,13 +461,17 @@ void swift_StructMirror_subscript(String *outString,
427461
auto fieldType = Struct->getFieldTypes()[i];
428462
auto fieldOffset = Struct->getFieldOffsets()[i];
429463

430-
auto bytes = reinterpret_cast<const char*>(value);
431-
auto fieldData = reinterpret_cast<const OpaqueValue *>(bytes + fieldOffset);
464+
auto bytes = reinterpret_cast<char*>(value);
465+
auto fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
432466

433467
new (outString) String(getFieldName(Struct->Description->Struct.FieldNames, i));
434468

435469
// 'owner' is consumed by this call.
436470
assert(!fieldType.isIndirect() && "indirect struct fields not implemented");
471+
472+
if (loadSpecialReferenceStorage(owner, fieldData, fieldType, outMirror))
473+
return;
474+
437475
new (outMirror) Mirror(reflect(owner, fieldData, fieldType.getType()));
438476
}
439477

@@ -614,7 +652,7 @@ void swift_ClassMirror_subscript(String *outString,
614652
Mirror *outMirror,
615653
intptr_t i,
616654
HeapObject *owner,
617-
const OpaqueValue *value,
655+
OpaqueValue *value,
618656
const Metadata *type) {
619657
auto Clas = static_cast<const ClassMetadata*>(type);
620658

@@ -655,10 +693,15 @@ void swift_ClassMirror_subscript(String *outString,
655693
#endif
656694
}
657695

658-
auto bytes = *reinterpret_cast<const char * const*>(value);
659-
auto fieldData = reinterpret_cast<const OpaqueValue *>(bytes + fieldOffset);
660-
661-
new (outString) String(getFieldName(Clas->getDescription()->Class.FieldNames, i));
696+
auto bytes = *reinterpret_cast<char * const *>(value);
697+
auto fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
698+
699+
new (outString) String(getFieldName(Clas->getDescription()->Class.FieldNames,
700+
i));
701+
702+
if (loadSpecialReferenceStorage(owner, fieldData, fieldType, outMirror))
703+
return;
704+
662705
// 'owner' is consumed by this call.
663706
new (outMirror) Mirror(reflect(owner, fieldData, fieldType.getType()));
664707
}

0 commit comments

Comments
 (0)