Skip to content

Keep the onAborted callback in an internal field of res - #1330

Merged
uNetworkingAB merged 1 commit into
uNetworking:masterfrom
nigrosimone:onaborted-internal-field
Sep 28, 2026
Merged

uNetworkingAB merged 1 commit into
uNetworking:masterfrom
nigrosimone:onaborted-internal-field

Conversation

@nigrosimone

Copy link
Copy Markdown
Contributor

Next small part of #1300, only the onAborted change.

onAborted makes two global handles on every call, one for the callback and one for res, and most frameworks call it on every request.

Now the callback is kept in a second internal field of res, so there is one global handle per request instead of two. The lambda already keeps res alive, and the callback lives as long as res.

Measured on Node 26 win-x64, min of 7 alternating runs: res.onAborted from 91 ns to 80 ns per call. Same behaviour on both builds: only the last callback fires, res throws after the abort, the callback survives a gc, and 2000 of 2000 res objects are collected after end.

@uNetworkingAB

Copy link
Copy Markdown
Contributor

Isn't this really just because of the UniquePersistent bug that you fixed in V8?

@nigrosimone

Copy link
Copy Markdown
Contributor Author

No, the two add up. I measured this PR without the V8 fix: 91 to 80 ns comes only from one global handle less.

The V8 fix alone does not help onAborted: its lambda captures two handles plus the isolate, 24 bytes, too big for the inline storage even with a noexcept move (with the wrapper of #1325 onAborted did not move). With this PR the capture is 16 bytes, so once V8 has the fix it also stays inline: with both it was 81 to 44 ns.

@nigrosimone
nigrosimone marked this pull request as ready for review September 28, 2026 17:40
@uNetworkingAB
uNetworkingAB merged commit a8a801c into uNetworking:master Sep 28, 2026
1 check failed
@uNetworkingAB

Copy link
Copy Markdown
Contributor

This comment:

/* This thing perfectly fits in with unique_function, and will Reset on destructor */

Is so old that it dates back to when std::unique_function was the proposed name for std::move_only_function and by that time I'm pretty sure it was 8 bytes per UniquePersistent and both fit inside the short size optimized storage.

The MoveOnlyFunction is just a placeholder for the std::move_only_function maybe time to drop it and go with the C++23 standard

@nigrosimone

Copy link
Copy Markdown
Contributor Author

Thanks, that explains the comment.

Abaut std::move_only_function: libc++ does not have it yet (llvm/llvm-project#105157 is still open, it is not even on main), so the macOS build would breaks. And the standard one has the same rule as MoveOnlyFunction: MSVC and libstdc++ keep the callable inline only when its move is noexcept, so NoexceptPersistent is still needed.

Now that #1325 is in, onAborted can capture a NoexceptPersistent too and its 16 bytes stay inline: on master it goes from 80 to 45 ns per call. I will open it.

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.

2 participants