22// Represents a single thread/coroutine execution context
33// Multiple LuaStates can share the same LuaVM (global_State)
44
5- use std:: collections:: HashMap ;
65use std:: rc:: Rc ;
76
87use crate :: lua_value:: { LuaUserdata , LuaValue , LuaValueKind , LuaValuePtr , UpvalueStore } ;
@@ -45,9 +44,9 @@ pub struct LuaState {
4544 call_depth : usize ,
4645
4746 /// Open upvalues - upvalues pointing to stack locations
48- /// Uses HashMap for O(1) lookup by stack index (unlike Lua's sorted linked list)
49- /// Also maintains a sorted Vec(higher indices first) for efficient traversal during close operations
50- open_upvalues_map : HashMap < usize , UpvaluePtr > ,
47+ /// Sorted Vec (higher stack indices first) for efficient lookup and close traversal.
48+ /// Linear scan is faster than HashMap for typical 0-5 open upvalues due to
49+ /// no hashing overhead and better cache locality. Matches C Lua's sorted list design.
5150 open_upvalues_list : Vec < UpvaluePtr > ,
5251
5352 /// Error message storage (lightweight error handling)
@@ -109,7 +108,6 @@ impl LuaState {
109108 stack_top : 0 , // Start with empty stack (Lua's L->top.p = L->stack)
110109 call_stack : Vec :: with_capacity ( call_stack_size) ,
111110 call_depth : 0 ,
112- open_upvalues_map : HashMap :: new ( ) ,
113111 open_upvalues_list : Vec :: new ( ) ,
114112 error_msg : String :: new ( ) ,
115113 error_object : LuaValue :: nil ( ) ,
@@ -862,16 +860,12 @@ impl LuaState {
862860
863861 if count > 0 {
864862 // Process upvalues to close in-place, then drain.
865- // First pass: close each upvalue and remove from map.
866863 for i in 0 ..count {
867864 let upval_ptr = self . open_upvalues_list [ i] ;
868865 let data = & upval_ptr. as_ref ( ) . data ;
869866 if data. is_open ( ) {
870867 let stack_idx = data. get_stack_index ( ) ;
871868
872- // Remove from map (maintain consistency)
873- self . open_upvalues_map . remove ( & stack_idx) ;
874-
875869 // Capture value from stack
876870 let value = self
877871 . stack
@@ -1288,13 +1282,20 @@ impl LuaState {
12881282 result
12891283 }
12901284
1291- /// Find or create an open upvalue for the given stack index
1292- /// Uses HashMap for O(1) lookup instead of O(n) linear search
1293- /// This is a major optimization over the naive linked list approach
1285+ /// Find or create an open upvalue for the given stack index.
1286+ /// Uses linear scan on sorted Vec — faster than HashMap for typical 0-5 open upvalues.
12941287 pub fn find_or_create_upvalue ( & mut self , stack_index : usize ) -> LuaResult < UpvaluePtr > {
1295- // O(1) lookup in HashMap
1296- if let Some ( & upval_ptr) = self . open_upvalues_map . get ( & stack_index) {
1297- return Ok ( upval_ptr) ;
1288+ // Linear scan on sorted list (descending by stack index).
1289+ // For 0-5 elements, this is faster than HashMap (no hash computation).
1290+ for & upval_ptr in & self . open_upvalues_list {
1291+ let idx = upval_ptr. as_ref ( ) . data . get_stack_index ( ) ;
1292+ if idx == stack_index {
1293+ return Ok ( upval_ptr) ;
1294+ }
1295+ if idx < stack_index {
1296+ // Passed the insertion point — not found (list is sorted descending)
1297+ break ;
1298+ }
12981299 }
12991300
13001301 // Not found, create a new one
@@ -1306,17 +1307,12 @@ impl LuaState {
13061307 vm. create_upvalue_open ( stack_index, ptr) ?
13071308 } ;
13081309
1309- // Add to HashMap for O(1) future lookups
1310- self . open_upvalues_map . insert ( stack_index, upval_ptr) ;
1311-
1312- // Also add to sorted list for traversal (insert in sorted position, higher indices first)
1313- // Collect existing upvalue IDs and their stack indices
1314- let insert_pos = {
1315- self . open_upvalues_list
1316- . iter ( )
1317- . position ( |& ptr| ptr. as_ref ( ) . data . get_stack_index ( ) < stack_index)
1318- . unwrap_or ( self . open_upvalues_list . len ( ) )
1319- } ;
1310+ // Insert in sorted position (higher indices first)
1311+ let insert_pos = self
1312+ . open_upvalues_list
1313+ . iter ( )
1314+ . position ( |& ptr| ptr. as_ref ( ) . data . get_stack_index ( ) < stack_index)
1315+ . unwrap_or ( self . open_upvalues_list . len ( ) ) ;
13201316
13211317 self . open_upvalues_list . insert ( insert_pos, upval_ptr) ;
13221318
0 commit comments