Skip to content

Commit 3bfebf1

Browse files
committed
runtime lib: a mechanism to set an "immutable" flag on an object for COW buffer runtime checking.
In an assert built of the library, store an extra boolean flag (isImmutable) in the object side-buffer table. This flag can be set and get by the Array implementation to sanity check the immutability status of the buffer object.
1 parent 1559fe3 commit 3bfebf1

File tree

4 files changed

+69
-0
lines changed

4 files changed

+69
-0
lines changed

stdlib/public/SwiftShims/RefCount.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,11 @@ class RefCounts {
12711271
// Note that this is not equal to the number of outstanding weak pointers.
12721272
uint32_t getWeakCount() const;
12731273

1274+
#ifndef NDEBUG
1275+
bool isImmutableCOWBuffer();
1276+
bool setIsImmutableCOWBuffer(bool immutable);
1277+
#endif
1278+
12741279
// DO NOT TOUCH.
12751280
// This exists for the benefits of the Refcounting.cpp tests. Do not use it
12761281
// elsewhere.
@@ -1301,6 +1306,11 @@ class HeapObjectSideTableEntry {
13011306
std::atomic<HeapObject*> object;
13021307
SideTableRefCounts refCounts;
13031308

1309+
#ifndef NDEBUG
1310+
// Used for runtime consistency checking of COW buffers.
1311+
bool immutableCOWBuffer = false;
1312+
#endif
1313+
13041314
public:
13051315
HeapObjectSideTableEntry(HeapObject *newObject)
13061316
: object(newObject), refCounts()
@@ -1455,6 +1465,16 @@ class HeapObjectSideTableEntry {
14551465
void *getSideTable() {
14561466
return refCounts.getSideTable();
14571467
}
1468+
1469+
#ifndef NDEBUG
1470+
bool isImmutableCOWBuffer() const {
1471+
return immutableCOWBuffer;
1472+
}
1473+
1474+
void setIsImmutableCOWBuffer(bool immutable) {
1475+
immutableCOWBuffer = immutable;
1476+
}
1477+
#endif
14581478
};
14591479

14601480

stdlib/public/core/Builtin.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,16 @@ internal func _class_getInstancePositiveExtentSize(_ theClass: AnyClass) -> Int
345345
#endif
346346
}
347347

348+
#if INTERNAL_CHECKS_ENABLED
349+
@usableFromInline
350+
@_silgen_name("_swift_isImmutableCOWBuffer")
351+
internal func _swift_isImmutableCOWBuffer(_ object: AnyObject) -> Bool
352+
353+
@usableFromInline
354+
@_silgen_name("_swift_setImmutableCOWBuffer")
355+
internal func _swift_setImmutableCOWBuffer(_ object: AnyObject, _ immutable: Bool) -> Bool
356+
#endif
357+
348358
@inlinable
349359
internal func _isValidAddress(_ address: UInt) -> Bool {
350360
// TODO: define (and use) ABI max valid pointer value

stdlib/public/runtime/HeapObject.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,23 @@ WeakReference *swift::swift_weakTakeAssign(WeakReference *dest,
887887

888888
#ifndef NDEBUG
889889

890+
/// Returns true if the "immutable" flag is set on \p object.
891+
///
892+
/// Used for runtime consistency checking of COW buffers.
893+
SWIFT_RUNTIME_EXPORT
894+
bool _swift_isImmutableCOWBuffer(HeapObject *object) {
895+
return object->refCounts.isImmutableCOWBuffer();
896+
}
897+
898+
/// Sets the "immutable" flag on \p object to \p immutable and returns the old
899+
/// value of the flag.
900+
///
901+
/// Used for runtime consistency checking of COW buffers.
902+
SWIFT_RUNTIME_EXPORT
903+
bool _swift_setImmutableCOWBuffer(HeapObject *object, bool immutable) {
904+
return object->refCounts.setIsImmutableCOWBuffer(immutable);
905+
}
906+
890907
void HeapObject::dump() const {
891908
auto *Self = const_cast<HeapObject *>(this);
892909
printf("HeapObject: %p\n", Self);

stdlib/public/runtime/RefCount.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,28 @@ void _swift_stdlib_immortalize(void *obj) {
156156
heapObj->refCounts.setIsImmortal(true);
157157
}
158158

159+
#ifndef NDEBUG
160+
// SideTableRefCountBits specialization intentionally does not exist.
161+
template <>
162+
bool RefCounts<InlineRefCountBits>::isImmutableCOWBuffer() {
163+
if (!hasSideTable())
164+
return false;
165+
HeapObjectSideTableEntry *sideTable = allocateSideTable(false);
166+
assert(sideTable);
167+
return sideTable->isImmutableCOWBuffer();
168+
}
169+
170+
template <>
171+
bool RefCounts<InlineRefCountBits>::setIsImmutableCOWBuffer(bool immutable) {
172+
HeapObjectSideTableEntry *sideTable = allocateSideTable(false);
173+
assert(sideTable);
174+
bool oldValue = sideTable->isImmutableCOWBuffer();
175+
sideTable->setIsImmutableCOWBuffer(immutable);
176+
return oldValue;
177+
}
178+
179+
#endif
180+
159181
// namespace swift
160182
} // namespace swift
161183

0 commit comments

Comments
 (0)