@@ -19,9 +19,9 @@ pub struct VM {
1919 registers : Vec < Value > ,
2020 frames : Vec < CallFrame > ,
2121 globals : Rc < RefCell < HashMap < String , Value > > > ,
22- // Cache for global lookups: (chunk_ptr, const_idx) -> Value
23- // This avoids repeated HashMap lookups for recursive function calls
24- global_cache : HashMap < ( usize , u16 ) , Value > ,
22+ // Cache for global lookups: name -> Value
23+ // Keyed by name to allow targeted invalidation when a specific global changes
24+ global_cache : HashMap < String , Value > ,
2525}
2626
2727impl VM {
@@ -44,9 +44,21 @@ impl VM {
4444 }
4545
4646 pub fn define_global ( & mut self , name : & str , value : Value ) {
47- self . globals . borrow_mut ( ) . insert ( name. to_string ( ) , value) ;
48- // Invalidate cache when globals change
49- self . global_cache . clear ( ) ;
47+ // Avoid String allocation if key already exists
48+ {
49+ let mut globals = self . globals . borrow_mut ( ) ;
50+ if let Some ( existing) = globals. get_mut ( name) {
51+ * existing = value. clone ( ) ;
52+ } else {
53+ globals. insert ( name. to_string ( ) , value. clone ( ) ) ;
54+ }
55+ }
56+ // Update cache (same optimization)
57+ if let Some ( existing) = self . global_cache . get_mut ( name) {
58+ * existing = value;
59+ } else {
60+ self . global_cache . insert ( name. to_string ( ) , value) ;
61+ }
5062 }
5163
5264 pub fn run ( & mut self , chunk : Chunk ) -> Result < Value , String > {
@@ -103,22 +115,20 @@ impl VM {
103115 }
104116
105117 Op :: GetGlobal ( dest, name_idx) => {
106- // Use chunk pointer as part of cache key for uniqueness
118+ // Get name from constant pool
107119 let chunk = & self . frames . last ( ) . unwrap ( ) . chunk ;
108- let chunk_ptr = Rc :: as_ptr ( chunk) as usize ;
109- let cache_key = ( chunk_ptr , name_idx ) ;
120+ let name = chunk. constants [ name_idx as usize ] . as_symbol ( )
121+ . ok_or ( "GetGlobal: expected symbol" ) ? ;
110122
111- let value = if let Some ( cached) = self . global_cache . get ( & cache_key ) {
112- // Cache hit - avoid HashMap lookup entirely
123+ let value = if let Some ( cached) = self . global_cache . get ( name ) {
124+ // Cache hit - avoid globals HashMap lookup
113125 cached. clone ( )
114126 } else {
115- // Cache miss - do the lookup (using &str to avoid String allocation)
116- let name = chunk. constants [ name_idx as usize ] . as_symbol ( )
117- . ok_or ( "GetGlobal: expected symbol" ) ?;
127+ // Cache miss - look up in globals
118128 let v = self . globals . borrow ( ) . get ( name) . cloned ( )
119129 . ok_or_else ( || format ! ( "Undefined variable: {}" , name) ) ?;
120130 // Cache for future lookups
121- self . global_cache . insert ( cache_key , v. clone ( ) ) ;
131+ self . global_cache . insert ( name . to_string ( ) , v. clone ( ) ) ;
122132 v
123133 } ;
124134 self . registers [ base + dest as usize ] = value;
@@ -129,9 +139,21 @@ impl VM {
129139 let name = chunk. constants [ name_idx as usize ] . as_symbol ( )
130140 . ok_or ( "SetGlobal: expected symbol" ) ?;
131141 let value = self . registers [ base + src as usize ] . clone ( ) ;
132- self . globals . borrow_mut ( ) . insert ( name. to_string ( ) , value) ;
133- // Invalidate cache - global was modified
134- self . global_cache . clear ( ) ;
142+ // Avoid String allocation if key already exists
143+ {
144+ let mut globals = self . globals . borrow_mut ( ) ;
145+ if let Some ( existing) = globals. get_mut ( name) {
146+ * existing = value. clone ( ) ;
147+ } else {
148+ globals. insert ( name. to_string ( ) , value. clone ( ) ) ;
149+ }
150+ }
151+ // Update cache (same optimization)
152+ if let Some ( existing) = self . global_cache . get_mut ( name) {
153+ * existing = value;
154+ } else {
155+ self . global_cache . insert ( name. to_string ( ) , value) ;
156+ }
135157 }
136158
137159 Op :: Closure ( dest, proto_idx) => {
@@ -258,19 +280,17 @@ impl VM {
258280 Op :: CallGlobal ( dest, name_idx, nargs) => {
259281 // Optimized: look up global and call directly without intermediate register
260282 let chunk = & self . frames . last ( ) . unwrap ( ) . chunk ;
261- let chunk_ptr = Rc :: as_ptr ( chunk) as usize ;
262- let cache_key = ( chunk_ptr , name_idx ) ;
283+ let name = chunk. constants [ name_idx as usize ] . as_symbol ( )
284+ . ok_or ( "CallGlobal: expected symbol" ) ? ;
263285
264286 // Get function from cache or globals
265- let func_value = if let Some ( cached) = self . global_cache . get ( & cache_key ) {
287+ let func_value = if let Some ( cached) = self . global_cache . get ( name ) {
266288 cached
267289 } else {
268- let name = chunk. constants [ name_idx as usize ] . as_symbol ( )
269- . ok_or ( "CallGlobal: expected symbol" ) ?;
270290 let v = self . globals . borrow ( ) . get ( name) . cloned ( )
271291 . ok_or_else ( || format ! ( "Undefined function: {}" , name) ) ?;
272- self . global_cache . insert ( cache_key , v) ;
273- self . global_cache . get ( & cache_key ) . unwrap ( )
292+ self . global_cache . insert ( name . to_string ( ) , v) ;
293+ self . global_cache . get ( name ) . unwrap ( )
274294 } ;
275295
276296 if let Some ( cf) = func_value. as_compiled_function ( ) {
@@ -316,19 +336,17 @@ impl VM {
316336 Op :: TailCallGlobal ( name_idx, arg_start, nargs) => {
317337 // Optimized: look up global and tail-call directly
318338 let chunk = & self . frames . last ( ) . unwrap ( ) . chunk ;
319- let chunk_ptr = Rc :: as_ptr ( chunk) as usize ;
320- let cache_key = ( chunk_ptr , name_idx ) ;
339+ let name = chunk. constants [ name_idx as usize ] . as_symbol ( )
340+ . ok_or ( "TailCallGlobal: expected symbol" ) ? ;
321341
322342 // Get function from cache or globals
323- let func_value = if let Some ( cached) = self . global_cache . get ( & cache_key ) {
343+ let func_value = if let Some ( cached) = self . global_cache . get ( name ) {
324344 cached
325345 } else {
326- let name = chunk. constants [ name_idx as usize ] . as_symbol ( )
327- . ok_or ( "TailCallGlobal: expected symbol" ) ?;
328346 let v = self . globals . borrow ( ) . get ( name) . cloned ( )
329347 . ok_or_else ( || format ! ( "Undefined function: {}" , name) ) ?;
330- self . global_cache . insert ( cache_key , v) ;
331- self . global_cache . get ( & cache_key ) . unwrap ( )
348+ self . global_cache . insert ( name . to_string ( ) , v) ;
349+ self . global_cache . get ( name ) . unwrap ( )
332350 } ;
333351
334352 if let Some ( cf) = func_value. as_compiled_function ( ) {
0 commit comments