Skip to content

Conversation

@Catfish-Man
Copy link
Contributor

@Catfish-Man Catfish-Man commented Mar 18, 2025

Fixes rdar://148134880

Not tracking termination has several issues:

  • If there exist any cases where we’re not terminated today (unclear, but not disallowed), we will produce incorrect results when bridging to ObjC and calling CFStringGetCStringPtr()
  • Even if no such cases exist today, we are likely to introduce them in the future
  • There exist cases where we are terminated today, but don’t know it, sacrificing performance for withCString, which should be a very fast API

@Catfish-Man Catfish-Man self-assigned this Mar 18, 2025
@Catfish-Man
Copy link
Contributor Author

@swift-ci please smoke test

@Catfish-Man Catfish-Man force-pushed the come-with-me-if-you-want-to-live-forever branch from 97f44db to af21302 Compare March 18, 2025 01:06
@Catfish-Man
Copy link
Contributor Author

@swift-ci please smoke test

@Catfish-Man Catfish-Man force-pushed the come-with-me-if-you-want-to-live-forever branch from af21302 to a8f85e6 Compare March 18, 2025 01:13
@Catfish-Man
Copy link
Contributor Author

@swift-ci please smoke test

@Catfish-Man Catfish-Man force-pushed the come-with-me-if-you-want-to-live-forever branch from a8f85e6 to 76d48b9 Compare March 18, 2025 08:33
@Catfish-Man
Copy link
Contributor Author

@swift-ci please smoke test

@Catfish-Man
Copy link
Contributor Author

@swift-ci please Apple Silicon benchmark

@_alwaysEmitIntoClient
@inline(__always) // Swift 6.1
internal var isKnownNullTerminated: Bool {
if isSmall { return true }
Copy link
Contributor

@stephentyrone stephentyrone Mar 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work when the small count is 15? Need to be slightly careful with this if it's dependent on the spill-for-contiguous-access path zeroing that byte, because I don't think we get to use that path when producing a Span/UTF8Span. (@glessard, @milseman?)

(I.e. I think this probably works today, but if I'm right in my suspicion, we'd need to make sure no one tries to use this for a Span fast-path directly)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is mirroring what the existing isFastZeroTerminated accessor does already, but I'm open to discussion if that's the right thing.

I spoke to @glessard about UTF8Span already and he says it doesn't rely on termination anyway, which is… awkward in general, but convenient here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that we have already handled isSmall where this flag is used, I think I would simply not handle it here and make the definition just be _countAndFlags.isNullTerminated to dodge the question.

Copy link
Contributor

@glessard glessard Mar 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the small count is 15 (or whatever the longest small string is for a particular runtime,) then we are pedantically not null-terminated. I think the point is to know whether we could pass an in-place address and rely on a null being in the right place? In that case I would say if isSmall { return count < _SmallString.capacity }.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good

@Catfish-Man
Copy link
Contributor Author

@swift-ci please smoke test

@Catfish-Man
Copy link
Contributor Author

@swift-ci please Apple Silicon benchmark

@Catfish-Man
Copy link
Contributor Author

Huh. I feel like this one isn't me?

<unknown>:0: error: could not find module 'CxxStdlib' for target 'x86_64-apple-macos'; found: arm64-apple-macos, at: /Users/ec2-user/jenkins/workspace/swift-PR-macos-perf-apple-silicon/Ninja-Release/swift-macosx-arm64/lib/swift/macosx/CxxStdlib.swiftmodule
<unknown>:0: error: could not find module 'CxxStdlib' for target 'x86_64-apple-macos'; found: arm64-apple-macos, at: /Users/ec2-user/jenkins/workspace/swift-PR-macos-perf-apple-silicon/Ninja-Release/swift-macosx-arm64/lib/swift/macosx/CxxStdlib.swiftmodule
/Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk/usr/lib/swift/Darwin.swiftmodule/x86_64-apple-macos.swiftinterface:1:1: error: failed to build module 'Darwin'; this SDK is not supported by the compiler (the SDK is built with 'Apple Swift version 5.9.2 (swiftlang-5.9.2.2.11 clang-1500.1.0.2.2)', while this compiler is 'Swift version 6.2-dev effective-5.10 (LLVM 7135e91d29f6694, Swift 347c10f0e167997)'). Please select a toolchain which matches the SDK.

@stephentyrone
Copy link
Contributor

That is not you.

@Catfish-Man
Copy link
Contributor Author

@swift-ci please smoke test

@Catfish-Man
Copy link
Contributor Author

@swift-ci please Apple Silicon benchmark

@Catfish-Man
Copy link
Contributor Author

@swift-ci please test


SWIFT_RUNTIME_STDLIB_API
const __swift_uint8_t * _Nullable
_swift_stdlib_NSStringUTF8StringTrampoline(id _Nonnull obj);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My kingdom for a way to force swiftc to generate an objc_msgSend_super call so I don't have to do this ridiculous hoop jumping

@Catfish-Man
Copy link
Contributor Author

@swift-ci please test

@Catfish-Man
Copy link
Contributor Author

@swift-ci please Apple Silicon benchmark

@Catfish-Man Catfish-Man marked this pull request as ready for review March 20, 2025 19:10
@Catfish-Man Catfish-Man requested a review from a team as a code owner March 20, 2025 19:10
@Catfish-Man
Copy link
Contributor Author

@swift-ci please test

@Catfish-Man
Copy link
Contributor Author

@swift-ci please Apple Silicon benchmark

@Catfish-Man
Copy link
Contributor Author

@swift-ci please test

final internal func _utf8String() -> UnsafePointer<UInt8>? {
if asString._guts._object.isFastZeroTerminated {
return unsafe start
return start
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not entirely clear on why this doesn't need an unsafe, but it was warning about it

@Catfish-Man
Copy link
Contributor Author

@swift-ci please test

@Catfish-Man
Copy link
Contributor Author

@swift-ci please Apple Silicon benchmark

@Catfish-Man
Copy link
Contributor Author

More unrelated failures

Cancelling nested steps due to timeout
Sending interrupt signal to process
ninja: build stopped: interrupted by user.

@Catfish-Man Catfish-Man enabled auto-merge (squash) March 29, 2025 00:02
@Catfish-Man Catfish-Man changed the title Add a flag to track null termination of string literals Add a flag to track null termination of Strings Mar 29, 2025
@Catfish-Man
Copy link
Contributor Author

Found a problem that I'm not quite sure how to solve:

  1. We want to use the "tail allocated" representation that string literals use, since that's how we avoid allocations
  2. Existing callers of withCString have an inlined check that assumes tail-allocated implies null-terminated.
  3. Unlike the previous inlining problem, they don't call any non-inlined functions in this path, so there's nowhere to insert a followup check

The good news is that withCString is the only callsite that has this problem, and that the only paths we actually create non-terminated strings on are not inlinable. So if we can find a way to detect that the process hasn't been recompiled since before the flag was added, then we could disable creating non-terminated strings, with only a loss of performance.

Another alternative would be to only ever make non-terminated allocated shared strings, which would cost a malloc for the shell object on creation, but avoid this issue completely.

@Catfish-Man Catfish-Man disabled auto-merge March 31, 2025 22:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants