From 67b5290ac2cecc37726f208949f500fcf643d1f5 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Tue, 22 Apr 2025 12:36:52 -0700 Subject: [PATCH] Disable runtime cow verification for mutableSpan property --- stdlib/public/core/Array.swift | 22 ++++++++++++++++--- stdlib/public/core/ArrayBuffer.swift | 17 +++++++++++++- stdlib/public/core/ArraySlice.swift | 12 +++++++--- stdlib/public/core/ContiguousArray.swift | 11 +++++++--- .../public/core/ContiguousArrayBuffer.swift | 10 +++++++++ 5 files changed, 62 insertions(+), 10 deletions(-) diff --git a/stdlib/public/core/Array.swift b/stdlib/public/core/Array.swift index e0798e85977..533b7143040 100644 --- a/stdlib/public/core/Array.swift +++ b/stdlib/public/core/Array.swift @@ -355,6 +355,17 @@ extension Array { } } +#if INTERNAL_CHECKS_ENABLED && COW_CHECKS_ENABLED + @inlinable + @_semantics("array.make_mutable") + @_effects(notEscaping self.**) + internal mutating func _makeMutableAndUniqueUnchecked() { + if _slowPath(!_buffer.beginCOWMutationUnchecked()) { + _buffer = _buffer._consumeAndCreateNew() + } + } +#endif + /// Marks the end of an Array mutation. /// /// After a call to `_endMutation` the buffer must not be mutated until a call @@ -1735,10 +1746,15 @@ extension Array { @lifetime(&self) @_alwaysEmitIntoClient mutating get { + // _makeMutableAndUnique*() inserts begin_cow_mutation. + // LifetimeDependence analysis inserts call to end_cow_mutation_addr since we cannot schedule it in the stdlib for mutableSpan property. +#if INTERNAL_CHECKS_ENABLED && COW_CHECKS_ENABLED + // We have runtime verification to check if begin_cow_mutation/end_cow_mutation are properly nested in asserts build of stdlib, + // disable checking whenever it is turned on since the compiler generated `end_cow_mutation_addr` is conservative and cannot be verified. + _makeMutableAndUniqueUnchecked() +#else _makeMutableAndUnique() - // NOTE: We don't have the ability to schedule a call to - // ContiguousArrayBuffer.endCOWMutation(). - // rdar://146785284 (lifetime analysis for end of mutation) +#endif let pointer = unsafe _buffer.firstElementAddress let count = _buffer.mutableCount let span = unsafe MutableSpan(_unsafeStart: pointer, count: count) diff --git a/stdlib/public/core/ArrayBuffer.swift b/stdlib/public/core/ArrayBuffer.swift index e0b49bcb2c2..306b9672da8 100644 --- a/stdlib/public/core/ArrayBuffer.swift +++ b/stdlib/public/core/ArrayBuffer.swift @@ -135,7 +135,22 @@ extension _ArrayBuffer { #endif return isUnique } - + +#if INTERNAL_CHECKS_ENABLED && COW_CHECKS_ENABLED + @_alwaysEmitIntoClient + internal mutating func beginCOWMutationUnchecked() -> Bool { + let isUnique: Bool + if !_isClassOrObjCExistential(Element.self) { + isUnique = _storage.beginCOWMutationUnflaggedNative() + } else if !_storage.beginCOWMutationNative() { + return false + } else { + isUnique = _isNative + } + return isUnique + } +#endif + /// Puts the buffer in an immutable state. /// /// - Precondition: The buffer must be mutable or the empty array singleton. diff --git a/stdlib/public/core/ArraySlice.swift b/stdlib/public/core/ArraySlice.swift index 282830234f9..51fb00165e9 100644 --- a/stdlib/public/core/ArraySlice.swift +++ b/stdlib/public/core/ArraySlice.swift @@ -1305,10 +1305,16 @@ extension ArraySlice { @lifetime(/*inout*/&self) @_alwaysEmitIntoClient mutating get { + // _makeMutableAndUnique*() inserts begin_cow_mutation. + // LifetimeDependence analysis inserts call to end_cow_mutation_addr since we cannot schedule it in the stdlib for mutableSpan property. +#if INTERNAL_CHECKS_ENABLED && COW_CHECKS_ENABLED + // We have runtime verification to check if begin_cow_mutation/end_cow_mutation are properly nested in asserts build of stdlib, + // disable checking whenever it is turned on since the compiler generated `end_cow_mutation_addr` is conservative and cannot be verified. + _makeMutableAndUniqueUnchecked() +#else _makeMutableAndUnique() - // NOTE: We don't have the ability to schedule a call to - // ContiguousArrayBuffer.endCOWMutation(). - // rdar://146785284 (lifetime analysis for end of mutation) +#endif + // LifetimeDependence analysis inserts call to Builtin.endCOWMutation. let (pointer, count) = unsafe (_buffer.firstElementAddress, _buffer.count) let span = unsafe MutableSpan(_unsafeStart: pointer, count: count) return unsafe _overrideLifetime(span, mutating: &self) diff --git a/stdlib/public/core/ContiguousArray.swift b/stdlib/public/core/ContiguousArray.swift index 6537d818ab1..19b5daf8e91 100644 --- a/stdlib/public/core/ContiguousArray.swift +++ b/stdlib/public/core/ContiguousArray.swift @@ -1247,10 +1247,15 @@ extension ContiguousArray { @lifetime(&self) @_alwaysEmitIntoClient mutating get { + // _makeMutableAndUnique*() inserts begin_cow_mutation. + // LifetimeDependence analysis inserts call to end_cow_mutation_addr since we cannot schedule it in the stdlib for mutableSpan property. +#if INTERNAL_CHECKS_ENABLED && COW_CHECKS_ENABLED + // We have runtime verification to check if begin_cow_mutation/end_cow_mutation are properly nested in asserts build of stdlib, + // disable checking whenever it is turned on since the compiler generated `end_cow_mutation_addr` is conservative and cannot be verified. + _makeMutableAndUniqueUnchecked() +#else _makeMutableAndUnique() - // NOTE: We don't have the ability to schedule a call to - // ContiguousArrayBuffer.endCOWMutation(). - // rdar://146785284 (lifetime analysis for end of mutation) +#endif let pointer = unsafe _buffer.firstElementAddress let count = _buffer.mutableCount let span = unsafe MutableSpan(_unsafeStart: pointer, count: count) diff --git a/stdlib/public/core/ContiguousArrayBuffer.swift b/stdlib/public/core/ContiguousArrayBuffer.swift index f49d15fb5af..4f5daa3461f 100644 --- a/stdlib/public/core/ContiguousArrayBuffer.swift +++ b/stdlib/public/core/ContiguousArrayBuffer.swift @@ -818,6 +818,16 @@ internal struct _ContiguousArrayBuffer: _ArrayBufferProtocol { return false; } +#if INTERNAL_CHECKS_ENABLED && COW_CHECKS_ENABLED + @_alwaysEmitIntoClient + internal mutating func beginCOWMutationUnchecked() -> Bool { + if Bool(Builtin.beginCOWMutation(&_storage)) { + return true + } + return false; + } +#endif + /// Puts the buffer in an immutable state. /// /// - Precondition: The buffer must be mutable or the empty array singleton.