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.
This commit is contained in:
Erik Eckstein
2020-06-08 15:00:12 +02:00
parent 1559fe333f
commit 3bfebf10f7
4 changed files with 69 additions and 0 deletions

View File

@@ -1271,6 +1271,11 @@ class RefCounts {
// Note that this is not equal to the number of outstanding weak pointers.
uint32_t getWeakCount() const;
#ifndef NDEBUG
bool isImmutableCOWBuffer();
bool setIsImmutableCOWBuffer(bool immutable);
#endif
// DO NOT TOUCH.
// This exists for the benefits of the Refcounting.cpp tests. Do not use it
// elsewhere.
@@ -1301,6 +1306,11 @@ class HeapObjectSideTableEntry {
std::atomic<HeapObject*> object;
SideTableRefCounts refCounts;
#ifndef NDEBUG
// Used for runtime consistency checking of COW buffers.
bool immutableCOWBuffer = false;
#endif
public:
HeapObjectSideTableEntry(HeapObject *newObject)
: object(newObject), refCounts()
@@ -1455,6 +1465,16 @@ class HeapObjectSideTableEntry {
void *getSideTable() {
return refCounts.getSideTable();
}
#ifndef NDEBUG
bool isImmutableCOWBuffer() const {
return immutableCOWBuffer;
}
void setIsImmutableCOWBuffer(bool immutable) {
immutableCOWBuffer = immutable;
}
#endif
};

View File

@@ -345,6 +345,16 @@ internal func _class_getInstancePositiveExtentSize(_ theClass: AnyClass) -> Int
#endif
}
#if INTERNAL_CHECKS_ENABLED
@usableFromInline
@_silgen_name("_swift_isImmutableCOWBuffer")
internal func _swift_isImmutableCOWBuffer(_ object: AnyObject) -> Bool
@usableFromInline
@_silgen_name("_swift_setImmutableCOWBuffer")
internal func _swift_setImmutableCOWBuffer(_ object: AnyObject, _ immutable: Bool) -> Bool
#endif
@inlinable
internal func _isValidAddress(_ address: UInt) -> Bool {
// TODO: define (and use) ABI max valid pointer value

View File

@@ -887,6 +887,23 @@ WeakReference *swift::swift_weakTakeAssign(WeakReference *dest,
#ifndef NDEBUG
/// Returns true if the "immutable" flag is set on \p object.
///
/// Used for runtime consistency checking of COW buffers.
SWIFT_RUNTIME_EXPORT
bool _swift_isImmutableCOWBuffer(HeapObject *object) {
return object->refCounts.isImmutableCOWBuffer();
}
/// Sets the "immutable" flag on \p object to \p immutable and returns the old
/// value of the flag.
///
/// Used for runtime consistency checking of COW buffers.
SWIFT_RUNTIME_EXPORT
bool _swift_setImmutableCOWBuffer(HeapObject *object, bool immutable) {
return object->refCounts.setIsImmutableCOWBuffer(immutable);
}
void HeapObject::dump() const {
auto *Self = const_cast<HeapObject *>(this);
printf("HeapObject: %p\n", Self);

View File

@@ -156,6 +156,28 @@ void _swift_stdlib_immortalize(void *obj) {
heapObj->refCounts.setIsImmortal(true);
}
#ifndef NDEBUG
// SideTableRefCountBits specialization intentionally does not exist.
template <>
bool RefCounts<InlineRefCountBits>::isImmutableCOWBuffer() {
if (!hasSideTable())
return false;
HeapObjectSideTableEntry *sideTable = allocateSideTable(false);
assert(sideTable);
return sideTable->isImmutableCOWBuffer();
}
template <>
bool RefCounts<InlineRefCountBits>::setIsImmutableCOWBuffer(bool immutable) {
HeapObjectSideTableEntry *sideTable = allocateSideTable(false);
assert(sideTable);
bool oldValue = sideTable->isImmutableCOWBuffer();
sideTable->setIsImmutableCOWBuffer(immutable);
return oldValue;
}
#endif
// namespace swift
} // namespace swift