Skip to content

perf(apple): lend Swift method results to C++ instead of boxing them - #1992

Open
mrousavy wants to merge 2 commits into
mrousavy/v1-swift-result-consumerfrom
mrousavy/v1-lend-swift-method-results
Open

mrousavy wants to merge 2 commits into
mrousavy/v1-swift-result-consumerfrom
mrousavy/v1-lend-swift-method-results

Conversation

@mrousavy

Copy link
Copy Markdown
Member

Stacked on #1991.

Throwing Swift methods that return a Swift value now lend it to a SwiftResultConsumer while Swift still owns it. Before, Swift wrote the value into storage that C++ read back through tryMakeSwiftValue<T>(), which returned a swift::Optional<T>, and C++ allocated and freed a box for it on every successful call.

// Before
auto __result = withSwiftResult<::NitroTest::NamedVariant_cxx>([&](void* __outResult) {
  return _swiftPart.bounceVariant(variant, __outResult);
});
// After
auto __result = receiveSwiftResult<::NitroTest::NamedVariant_cxx>([&](const void* __onResult) {
  return _swiftPart.bounceVariant(variant, __onResult);
});
let value = try __implementation.bounceVariant(variant: variant.value)
withUnsafePointer(to: NamedVariant_cxx(value)) { pointer in
  margelo.nitro.SwiftResultConsumer.consume(__onResult, UnsafeRawPointer(pointer))
}
return bridge.Result_void.withValue()

Methods returning void, primitives, classes or imported C++ values keep their current bridges, and so do non-throwing methods and Swift callbacks. SwiftResultConsumerType is a SwiftPointerType, like the other pointer adapters.

Before the rebase onto current v1, I measured this in a local Release Hermes harness on the iOS simulator. Concatenating "hello" and "world" went from 151 ns to 97 ns per call, and two 32-character strings from 303 ns to 247 ns. The harness lives outside the repo, and I haven't run the benchmark app.

The standalone iOS suite passes. Android is unaffected because only Apple bridge code changed.

🤖 Generated with Claude Code

Throwing Swift methods that return Swift values, such as strings, arrays and
structs, now pass the successful value to a SwiftResultConsumer while Swift
still owns it. Before, C++ called tryMakeSwiftValue(), which returned T?, and
C++ allocated a box for that swift::Optional<T> on every successful call.
@vercel

vercel Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
nitro-docs Ready Ready Preview Oct 23, 2026 6:01pm UTC

Request Review

This branch was successfully deployed

1 active deployment
Preview — cb0c6bb2 Deployed Oct 23, 2026 by vercel[bot]
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