Skip to content

Commit 827366d

Browse files
authored
Merge pull request #4323 from bitjammer/weak-var-runtime-mirror-27348445
Weak var runtime mirror 27348445
2 parents cf989c4 + 4c6e234 commit 827366d

File tree

6 files changed

+254
-22
lines changed

6 files changed

+254
-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
}

test/1_stdlib/WeakMirror.swift

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
//===--- Mirror.swift -----------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
// RUN: rm -rf %t
13+
// RUN: mkdir -p %t
14+
//
15+
// RUN: if [ %target-runtime == "objc" ]; \
16+
// RUN: then \
17+
// RUN: %target-clang %S/Inputs/Mirror/Mirror.mm -c -o %t/Mirror.mm.o -g && \
18+
// RUN: %target-build-swift -Xfrontend -disable-access-control %s -I %S/Inputs/Mirror/ -Xlinker %t/Mirror.mm.o -o %t/Mirror; \
19+
// RUN: else \
20+
// RUN: %target-build-swift %s -Xfrontend -disable-access-control -o %t/Mirror; \
21+
// RUN: fi
22+
// RUN: %target-run %t/Mirror
23+
// REQUIRES: executable_test
24+
25+
import StdlibUnittest
26+
27+
var mirrors = TestSuite("Mirrors")
28+
29+
class NativeSwiftClass : NativeClassBoundExistential {}
30+
31+
protocol NativeClassBoundExistential : class {}
32+
class NativeSwiftClassHasWeak {
33+
weak var weakProperty: AnyObject?
34+
}
35+
36+
class NativeSwiftClassHasNativeClassBoundExistential {
37+
weak var weakProperty: NativeClassBoundExistential?
38+
}
39+
40+
struct StructHasNativeWeakReference {
41+
weak var weakProperty: AnyObject?
42+
}
43+
44+
mirrors.test("class/NativeSwiftClassHasNativeWeakReference") {
45+
let c1 = NativeSwiftClassHasWeak()
46+
let c2 = NativeSwiftClass()
47+
c1.weakProperty = c2
48+
let classChild = _reflect(c1)[0].1.value
49+
print(classChild)
50+
}
51+
52+
mirrors.test("class/NativeSwiftClassHasNativeClassBoundExistential") {
53+
let c1 = NativeSwiftClassHasNativeClassBoundExistential()
54+
let e = NativeSwiftClass() as NativeClassBoundExistential
55+
c1.weakProperty = e
56+
let classChild = _reflect(c1)[0].1.value
57+
print(classChild)
58+
}
59+
60+
mirrors.test("struct/StructHasNativeWeakReference") {
61+
var s = StructHasNativeWeakReference()
62+
let c2 = NativeSwiftClass()
63+
s.weakProperty = c2
64+
let structChild = _reflect(s)[0].1.value
65+
print(structChild)
66+
}
67+
68+
#if _runtime(_ObjC)
69+
70+
import Foundation
71+
72+
@objc protocol ObjCClassBoundExistential : class {}
73+
74+
@objc protocol ObjCProtocol : class {
75+
weak var weakProperty: AnyObject? { get set }
76+
}
77+
78+
class NativeSwiftClassHasObjCClassBoundExistential {
79+
weak var weakProperty: NSObjectProtocol?
80+
}
81+
82+
class ObjCClassHasWeak : NSObject {
83+
weak var weakProperty: AnyObject?
84+
}
85+
86+
class ObjCClassHasNativeClassBoundExistential : NSObject {
87+
weak var weakProperty: NativeClassBoundExistential?
88+
}
89+
90+
class ObjCClassHasObjCClassBoundExistential : NSObject {
91+
weak var weakProperty: NSObjectProtocol?
92+
}
93+
94+
struct StructHasObjCWeakReference {
95+
weak var weakProperty: NSObject?
96+
}
97+
98+
struct StructHasObjCClassBoundExistential {
99+
weak var weakProperty: NSObjectProtocol?
100+
}
101+
102+
mirrors.test("class/NativeSwiftClassHasObjCWeakReference") {
103+
let c1 = NativeSwiftClassHasWeak()
104+
let nso = NSObject()
105+
c1.weakProperty = nso
106+
let classChild = _reflect(c1)[0].1.value
107+
print(classChild)
108+
}
109+
110+
mirrors.test("class/NativeSwiftClassHasObjCClassBoundExistential") {
111+
let c1 = NativeSwiftClassHasObjCClassBoundExistential()
112+
let nso = NSObject() as NSObjectProtocol
113+
c1.weakProperty = nso
114+
let classChild = _reflect(c1)[0].1.value
115+
print(classChild)
116+
}
117+
118+
mirrors.test("class/ObjCClassHasNativeWeak") {
119+
let c1 = ObjCClassHasWeak()
120+
let c2 = NativeSwiftClass()
121+
c1.weakProperty = c2
122+
let classChild = _reflect(c1)[0].1.value
123+
print(classChild)
124+
}
125+
126+
mirrors.test("class/ObjcCClassHasObjCWeakReference") {
127+
let c1 = ObjCClassHasWeak()
128+
let nso = NSObject()
129+
c1.weakProperty = nso
130+
let classChild = _reflect(c1)[0].1.value
131+
print(classChild)
132+
}
133+
134+
mirrors.test("class/ObjCClassHasNativeClassBoundExistential") {
135+
let c1 = ObjCClassHasNativeClassBoundExistential()
136+
let e = NativeSwiftClass() as NativeClassBoundExistential
137+
c1.weakProperty = e
138+
let classChild = _reflect(c1)[0].1.value
139+
print(classChild)
140+
}
141+
142+
mirrors.test("class/ObjCClassHasObjCClassBoundExistential") {
143+
let c1 = ObjCClassHasObjCClassBoundExistential()
144+
let nsop = NSObject() as NSObjectProtocol
145+
c1.weakProperty = nsop
146+
let classChild = _reflect(c1)[0].1.value
147+
print(classChild)
148+
}
149+
150+
mirrors.test("struct/StructHasObjCWeakReference") {
151+
var s = StructHasObjCWeakReference()
152+
let nso = NSObject()
153+
s.weakProperty = nso
154+
let structChild = _reflect(s)[0].1.value
155+
print(structChild)
156+
}
157+
158+
mirrors.test("struct/StructHasObjCClassBoundExistential") {
159+
var s = StructHasObjCClassBoundExistential()
160+
let nsop = NSObject() as NSObjectProtocol
161+
s.weakProperty = nsop
162+
let structChild = _reflect(s)[0].1.value
163+
print(structChild)
164+
}
165+
166+
#endif
167+
168+
runAllTests()

0 commit comments

Comments
 (0)