Skip to content

Commit 82363ac

Browse files
committed
Replace Box<> with Rc<> for NaN-boxed heap values
1 parent b1be6cd commit 82363ac

File tree

1 file changed

+27
-35
lines changed

1 file changed

+27
-35
lines changed

src/value.rs

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -119,25 +119,26 @@ impl Value {
119119

120120
/// Create a string value
121121
pub fn string(s: &str) -> Value {
122-
let heap = Box::new(HeapObject::String(Rc::from(s)));
122+
let heap = Rc::new(HeapObject::String(Rc::from(s)));
123123
Value::from_heap(heap)
124124
}
125125

126126
/// Create a symbol value
127127
pub fn symbol(s: &str) -> Value {
128-
let heap = Box::new(HeapObject::Symbol(Rc::from(s)));
128+
let heap = Rc::new(HeapObject::Symbol(Rc::from(s)));
129129
Value::from_heap(heap)
130130
}
131131

132132
/// Create a list value
133133
pub fn list(items: Vec<Value>) -> Value {
134-
let heap = Box::new(HeapObject::List(Rc::from(items)));
134+
let heap = Rc::new(HeapObject::List(Rc::from(items)));
135135
Value::from_heap(heap)
136136
}
137137

138-
/// Create a heap-allocated value from a Box<HeapObject>
139-
fn from_heap(heap: Box<HeapObject>) -> Value {
140-
let ptr = Box::into_raw(heap) as u64;
138+
/// Create a heap-allocated value from an Rc<HeapObject>
139+
/// Uses Rc::into_raw to store the pointer - refcount is NOT decremented
140+
fn from_heap(heap: Rc<HeapObject>) -> Value {
141+
let ptr = Rc::into_raw(heap) as u64;
141142
debug_assert!(ptr & TAG_MASK == 0, "Pointer uses more than 48 bits");
142143
Value(TAG_PTR | ptr)
143144
}
@@ -219,21 +220,10 @@ impl Value {
219220
return None;
220221
}
221222
let ptr = (self.0 & PAYLOAD_MASK) as *const HeapObject;
222-
// Safety: we only create these pointers from Box::into_raw
223+
// Safety: we only create these pointers from Rc::into_raw
223224
Some(unsafe { &*ptr })
224225
}
225226

226-
/// Get the heap object mutably (for cloning the inner Rc)
227-
#[inline]
228-
fn as_heap_mut(&self) -> Option<&mut HeapObject> {
229-
if !self.is_ptr() {
230-
return None;
231-
}
232-
let ptr = (self.0 & PAYLOAD_MASK) as *mut HeapObject;
233-
// Safety: we only create these pointers from Box::into_raw
234-
Some(unsafe { &mut *ptr })
235-
}
236-
237227
/// Get as a symbol string, if this is a symbol
238228
pub fn as_symbol(&self) -> Option<&str> {
239229
match self.as_heap() {
@@ -343,50 +333,50 @@ impl Value {
343333

344334
/// Create String (backwards compat) - from Rc<str>
345335
pub fn String(s: Rc<str>) -> Value {
346-
let heap = Box::new(HeapObject::String(s));
336+
let heap = Rc::new(HeapObject::String(s));
347337
Value::from_heap(heap)
348338
}
349339

350340
/// Create Symbol (backwards compat) - from Rc<str>
351341
pub fn Symbol(s: Rc<str>) -> Value {
352-
let heap = Box::new(HeapObject::Symbol(s));
342+
let heap = Rc::new(HeapObject::Symbol(s));
353343
Value::from_heap(heap)
354344
}
355345

356346
/// Create List (backwards compat) - from Rc<[Value]>
357347
pub fn List(items: Rc<[Value]>) -> Value {
358-
let heap = Box::new(HeapObject::List(items));
348+
let heap = Rc::new(HeapObject::List(items));
359349
Value::from_heap(heap)
360350
}
361351

362352
/// Create Function (backwards compat)
363353
pub fn Function(f: Rc<Function>) -> Value {
364-
let heap = Box::new(HeapObject::Function(f));
354+
let heap = Rc::new(HeapObject::Function(f));
365355
Value::from_heap(heap)
366356
}
367357

368358
/// Create NativeFunction (backwards compat)
369359
pub fn NativeFunction(f: Rc<NativeFunction>) -> Value {
370-
let heap = Box::new(HeapObject::NativeFunction(f));
360+
let heap = Rc::new(HeapObject::NativeFunction(f));
371361
Value::from_heap(heap)
372362
}
373363

374364
/// Create CompiledFunction (backwards compat)
375365
pub fn CompiledFunction(c: Rc<Chunk>) -> Value {
376-
let heap = Box::new(HeapObject::CompiledFunction(c));
366+
let heap = Rc::new(HeapObject::CompiledFunction(c));
377367
Value::from_heap(heap)
378368
}
379369
}
380370

381371
impl Drop for Value {
382372
fn drop(&mut self) {
383-
// If this is a heap pointer, we need to drop the HeapObject
373+
// If this is a heap pointer, we need to decrement the Rc refcount
384374
if self.is_ptr() {
385-
let ptr = (self.0 & PAYLOAD_MASK) as *mut HeapObject;
386-
// Safety: we only create these from Box::into_raw, and we set
387-
// the tag to something else after dropping
375+
let ptr = (self.0 & PAYLOAD_MASK) as *const HeapObject;
376+
// Safety: we only create these from Rc::into_raw
377+
// Rc::from_raw will decrement the refcount and free if it hits 0
388378
unsafe {
389-
drop(Box::from_raw(ptr));
379+
drop(Rc::from_raw(ptr));
390380
}
391381
// Mark as nil to prevent double-free
392382
self.0 = TAG_NIL;
@@ -397,13 +387,15 @@ impl Drop for Value {
397387
impl Clone for Value {
398388
fn clone(&self) -> Self {
399389
if self.is_ptr() {
400-
// Clone the heap object (which clones the inner Rc)
401-
if let Some(heap) = self.as_heap() {
402-
let cloned = Box::new(heap.clone());
403-
Value::from_heap(cloned)
404-
} else {
405-
Value::nil()
390+
// Just increment the Rc reference count - no new allocation!
391+
let ptr = (self.0 & PAYLOAD_MASK) as *const HeapObject;
392+
// Safety: we only create these from Rc::into_raw
393+
// increment_strong_count increases refcount without creating an Rc
394+
unsafe {
395+
Rc::increment_strong_count(ptr);
406396
}
397+
// Return a Value with the same pointer (both now own a reference)
398+
Value(self.0)
407399
} else {
408400
// Primitives: just copy the bits
409401
Value(self.0)

0 commit comments

Comments
 (0)