-
-
Notifications
You must be signed in to change notification settings - Fork 431
Replace NanBoxing's Box with a refcount and improve clone/drop performance #4219
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
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR updates the memory management for nan boxed values by replacing Box with Arc.
- The tagging functions now accept Arc instead of Box for JsBigInt, JsObject, JsSymbol, and JsString.
- The clone and drop implementations are updated to manually increment and decrement the Arc reference count.
Comments suppressed due to low confidence (2)
core/engine/src/value/inner/nan_boxed.rs:461
- [nitpick] Consider refactoring the clone implementation to use Arc::clone() directly instead of manually calling Arc::increment_strong_count(), as this would simplify the code and reduce the risk of mismatches in the reference count.
if self.is_object() {
core/engine/src/value/inner/nan_boxed.rs:730
- [nitpick] Using Arc::decrement_strong_count() manually in the drop implementation is error-prone; consider using Arc::from_raw() to properly handle deallocation once the reference count drops to zero, ensuring correct memory management.
if self.is_object() {
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4219 +/- ##
==========================================
+ Coverage 47.24% 52.67% +5.43%
==========================================
Files 476 487 +11
Lines 46892 51966 +5074
==========================================
+ Hits 22154 27375 +5221
+ Misses 24738 24591 -147 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
e3e94e3
to
62138f3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR aims to improve the pointer handling in NanBoxedValue by replacing the Box-based management with reference counting. Key changes include:
- Switching from Box to Rc for various value types (JsBigInt, JsObject, JsSymbol, and JsString)
- Modifying clone and drop implementations to use unsafe Rc reference count manipulation
@@ -296,8 +321,8 @@ mod bits { | |||
/// by calling `[Self::drop_pointer]`. | |||
#[inline(always)] | |||
#[allow(clippy::identity_op)] | |||
pub(super) unsafe fn tag_bigint(value: Box<JsBigInt>) -> u64 { | |||
let value = Box::into_raw(value) as u64; | |||
pub(super) unsafe fn tag_bigint(value: Rc<JsBigInt>) -> u64 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Maybe we should pass JsBigInt
as value directly since it's wrapped in an Rc<RawBigInt>
already internally, and add methods for into_raw()
/from_raw()
to JsBigInt
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This cannot work unless I change the interface of the JsValue to return Rc<...>
(or similar) instead of references. To return a &'a JsBigInt
with your suggested change I'd need to reconstruct it on the stack, and I cannot return a reference to that. Unless I'm missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, sorry I missed that 😅 , we could get around this by using a bit of safe "unsafe" code by adding #[repr(transparent)]
on JsBigInt
and transmute
-ing &'a Rc<RawBigInt>
into &'a JsBigInt
JsBigInt.
For more info see: https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kind of tried that. I need to spend more time on it, but I was still getting segfaults accessing freed or invalid memory.
Essentially what I'm doing here is instead of using a
Box
as the container for theJsValue
's inner NaN-boxed pointer, I use an RC. When cloning the value, that RC will the increment (and decrement on drop) instead of allocating a newBox
on the heap. This should make clones ofJsValue
simply increment an integer in memory.So given the following:
The refcount of the
JsObject
itself will be: 1 at line 1, 2 at line 2, still 2 at line 3 as the clone of theJsValue
itself increment the internal counter, 2 at line 4, 1 at line 5 (a
will drop, but theJsValue
itself will still have an innerJsObject
), then finally 0 and dropped at line 6.