@@ -2,7 +2,8 @@ use std::cell::RefCell;
22use std:: collections:: HashMap ;
33use std:: fmt;
44use std:: rc:: Rc ;
5- use std:: sync:: Arc ;
5+ use std:: sync:: { Arc , Mutex } ;
6+ use std:: thread:: JoinHandle ;
67
78use crate :: bytecode:: Chunk ;
89
@@ -260,6 +261,9 @@ pub enum HeapObject {
260261 NativeFunction ( NativeFunction ) ,
261262 /// Compiled function - keeps Rc<Chunk> for sharing in tail calls
262263 CompiledFunction ( Rc < Chunk > ) ,
264+ /// Thread handle for spawned threads - wrapped in Mutex because JoinHandle can only be joined once
265+ /// The Option allows us to take the handle when joining (join consumes the handle)
266+ ThreadHandle ( Arc < Mutex < Option < JoinHandle < Result < SharedValue , String > > > > > ) ,
263267}
264268
265269impl Clone for HeapObject {
@@ -272,6 +276,7 @@ impl Clone for HeapObject {
272276 HeapObject :: Function ( f) => HeapObject :: Function ( f. clone ( ) ) ,
273277 HeapObject :: NativeFunction ( f) => HeapObject :: NativeFunction ( f. clone ( ) ) ,
274278 HeapObject :: CompiledFunction ( c) => HeapObject :: CompiledFunction ( c. clone ( ) ) ,
279+ HeapObject :: ThreadHandle ( h) => HeapObject :: ThreadHandle ( h. clone ( ) ) ,
275280 }
276281 }
277282}
@@ -297,6 +302,8 @@ pub struct SharedConsCell {
297302
298303/// Thread-safe heap objects using Arc instead of Rc
299304/// Mirrors HeapObject but is safe to send across threads
305+ /// Note: Functions are NOT included because closures capture environments with Rc
306+ /// and cannot be shared across threads. Use compiled functions or native functions instead.
300307#[ derive( Debug , Clone ) ]
301308pub enum SharedHeapObject {
302309 /// String data
@@ -307,10 +314,6 @@ pub enum SharedHeapObject {
307314 List ( Box < [ SharedValue ] > ) ,
308315 /// Cons cell with shared values
309316 Cons ( SharedConsCell ) ,
310- /// Functions cannot be shared across threads (closures capture environment)
311- /// Use channels or other communication primitives instead
312- /// We keep this variant for completeness but it will error if attempted
313- Function ( Box < Function > ) ,
314317 /// Native functions are just function pointers, safe to share
315318 NativeFunction ( NativeFunction ) ,
316319 /// Compiled functions share their chunk via Arc
@@ -374,7 +377,6 @@ impl fmt::Display for SharedValue {
374377 }
375378 write ! ( f, ")" )
376379 }
377- SharedHeapObject :: Function ( _) => write ! ( f, "<function>" ) ,
378380 SharedHeapObject :: NativeFunction ( nf) => write ! ( f, "<native fn {}>" , nf. name) ,
379381 SharedHeapObject :: CompiledFunction ( _) => write ! ( f, "<function>" ) ,
380382 }
@@ -496,7 +498,7 @@ impl Value {
496498
497499 /// Create a heap-allocated value from an Rc<HeapObject>
498500 /// Uses Rc::into_raw to store the pointer - refcount is NOT decremented
499- fn from_heap ( heap : Rc < HeapObject > ) -> Value {
501+ pub fn from_heap ( heap : Rc < HeapObject > ) -> Value {
500502 let ptr = Rc :: into_raw ( heap) as u64 ;
501503 debug_assert ! ( ptr & TAG_MASK == 0 , "Pointer uses more than 48 bits" ) ;
502504 Value ( TAG_PTR | ptr)
@@ -597,7 +599,7 @@ impl Value {
597599
598600 /// Get the heap object if this is a heap pointer (Rc or arena)
599601 #[ inline]
600- fn as_heap ( & self ) -> Option < & HeapObject > {
602+ pub fn as_heap ( & self ) -> Option < & HeapObject > {
601603 if self . is_ptr ( ) {
602604 let ptr = ( self . 0 & PAYLOAD_MASK ) as * const HeapObject ;
603605 // Safety: we only create these pointers from Rc::into_raw
@@ -776,6 +778,7 @@ impl Value {
776778 HeapObject :: Function ( _) => "function" ,
777779 HeapObject :: NativeFunction ( _) => "native-function" ,
778780 HeapObject :: CompiledFunction ( _) => "function" ,
781+ HeapObject :: ThreadHandle ( _) => "thread-handle" ,
779782 }
780783 } else {
781784 "unknown"
@@ -959,6 +962,11 @@ impl Value {
959962 Some ( HeapObject :: CompiledFunction ( c) ) => {
960963 Value :: CompiledFunction ( c. clone ( ) )
961964 }
965+ Some ( HeapObject :: ThreadHandle ( h) ) => {
966+ // ThreadHandles are already Arc-based, just clone the Value
967+ let heap = Rc :: new ( HeapObject :: ThreadHandle ( h. clone ( ) ) ) ;
968+ Value :: from_heap ( heap)
969+ }
962970 None => Value :: nil ( ) ,
963971 }
964972 } else if self . is_ptr ( ) {
@@ -1073,6 +1081,9 @@ impl Value {
10731081 inner : Arc :: new ( SharedHeapObject :: CompiledFunction ( arc_chunk) ) ,
10741082 } )
10751083 }
1084+ Some ( HeapObject :: ThreadHandle ( _) ) => {
1085+ Err ( "Thread handles cannot be shared across threads" . to_string ( ) )
1086+ }
10761087 None => Err ( "Cannot convert unknown value to SharedValue" . to_string ( ) ) ,
10771088 }
10781089 }
@@ -1122,7 +1133,6 @@ impl Value {
11221133 let cdr = Value :: from_shared ( & cons. cdr ) ;
11231134 Value :: cons_rc ( car, cdr)
11241135 }
1125- SharedHeapObject :: Function ( f) => Value :: function ( ( * * f) . clone ( ) ) ,
11261136 SharedHeapObject :: NativeFunction ( nf) => {
11271137 Value :: native_function ( & nf. name , nf. func )
11281138 }
@@ -1212,6 +1222,7 @@ impl fmt::Display for Value {
12121222 HeapObject :: Function ( _) => write ! ( f, "<function>" ) ,
12131223 HeapObject :: NativeFunction ( nf) => write ! ( f, "<native fn {}>" , nf. name) ,
12141224 HeapObject :: CompiledFunction ( _) => write ! ( f, "<function>" ) ,
1225+ HeapObject :: ThreadHandle ( _) => write ! ( f, "<thread-handle>" ) ,
12151226 }
12161227 } else {
12171228 write ! ( f, "<unknown>" )
0 commit comments