Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: Mark all types that are used only in std::shared_ptr<T> as SWIFT_NONCOPYABLE #435

Merged
merged 4 commits into from
Dec 20, 2024

Conversation

mrousavy
Copy link
Owner

@mrousavy mrousavy commented Dec 19, 2024

Summary

This PR avoids copying a few C++ types when using them in Swift, effectively speeding up the codebase by a few factors depending on how heavy the types were to copy. 🔥

Problem

Swift imports all C++ types as value types, so every time you get, use, or pass a C++ type around in Swift, it will make a copy.

Not only is this slow, but sometimes it isn't even expected and might destroy internal state if the C++ class has unsafe pointers inside that are not ref-counted! ⚠️

std::shared_ptr<T> is one of these cases - if you use shared_ptr.pointee, it will actually return the pointer this shared_ptr wraps by value - so it will copy T!! ❌

func someSwiftFunc(shared: std.shared_ptr<T>) {
  shared.pointee.doFirst()
  shared.pointee.doSecond()
  shared.pointee.doThird()
  // 3x copy, 3x destructors!! ❌ ❌ ❌ 
}

Solution

So this PR changes this - every type we use inside of a std::shared_ptr is now marked as a SWIFT_NONCOPYABLE, meaning Swift will not copy this type. It is like SWIFT_IMMORTAL_REFERENCE, but a bit more explicit on the usage.

Right now, the following types are affected and have been improved with this PR;

  • Promise<T>
  • ArrayBuffer
  • Callbacks / std::function

Future

Every type that is not expected to be copied directly should have SWIFT_NONCOPYABLE on it, so that's;

  • Extrusively reference-counted types (aka every type in a shared_ptr<T>, unique_ptr<T> or weak_ptr<T>)
  • const & types
  • Unsafe pointers

Then Swift can use borrowing magic.

Also, I guess an even better solution would be to have a borrowing T accessor instead of just T on the Swift shared_ptr type. I created a feature request for this here: swiftlang/swift#78296

Copy link

vercel bot commented Dec 19, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
nitro-docs ⬜️ Skipped (Inspect) Dec 19, 2024 8:38pm

@mrousavy
Copy link
Owner Author

mrousavy commented Dec 19, 2024

Shit SWIFT_UNSAFE_REFERENCE requires iOS 16.4+...

@mrousavy mrousavy changed the title fix: Mark all types that are used only in std::shared_ptr<T> as SWIFT_UNSAFE_REFERENCE fix: Mark all types that are used only in std::shared_ptr<T> as SWIFT_NONCOPYABLE Dec 19, 2024
@mrousavy
Copy link
Owner Author

omg SWIFT_NONCOPYABLE WORKS!!! 🥳

@mrousavy mrousavy changed the title fix: Mark all types that are used only in std::shared_ptr<T> as SWIFT_NONCOPYABLE perf: Mark all types that are used only in std::shared_ptr<T> as SWIFT_NONCOPYABLE Dec 19, 2024
@mrousavy mrousavy merged commit 196fc9d into main Dec 20, 2024
16 checks passed
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.

1 participant