Skip to content

Commit e644e2b

Browse files
committed
update
1 parent cd4469d commit e644e2b

File tree

4 files changed

+175
-144
lines changed

4 files changed

+175
-144
lines changed

crates/luars/src/gc/object_pool.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,12 @@ pub struct ObjectPool {
396396
pub tm_shr: StringId, // "__shr"
397397
pub tm_concat: StringId, // "__concat"
398398
pub tm_metatable: StringId, // "__metatable"
399+
400+
// Pre-cached coroutine status strings for fast coroutine.status
401+
pub str_suspended: StringId, // "suspended"
402+
pub str_running: StringId, // "running"
403+
pub str_normal: StringId, // "normal"
404+
pub str_dead: StringId, // "dead"
399405
}
400406

401407
// ============ Lua-style String Interning Table ============
@@ -623,6 +629,10 @@ impl ObjectPool {
623629
tm_shr: StringId(0),
624630
tm_concat: StringId(0),
625631
tm_metatable: StringId(0),
632+
str_suspended: StringId(0),
633+
str_running: StringId(0),
634+
str_normal: StringId(0),
635+
str_dead: StringId(0),
626636
};
627637

628638
// Pre-create all metamethod name strings (like Lua's luaT_init)
@@ -657,6 +667,12 @@ impl ObjectPool {
657667
pool.tm_shr = pool.create_string("__shr");
658668
pool.tm_concat = pool.create_string("__concat");
659669
pool.tm_metatable = pool.create_string("__metatable");
670+
671+
// Pre-create coroutine status strings
672+
pool.str_suspended = pool.create_string("suspended");
673+
pool.str_running = pool.create_string("running");
674+
pool.str_normal = pool.create_string("normal");
675+
pool.str_dead = pool.create_string("dead");
660676

661677
// Fix all metamethod name strings - they should never be collected
662678
// (like Lua's luaC_fix in luaT_init)
@@ -690,6 +706,10 @@ impl ObjectPool {
690706
pool.fix_string(pool.tm_shr);
691707
pool.fix_string(pool.tm_concat);
692708
pool.fix_string(pool.tm_metatable);
709+
pool.fix_string(pool.str_suspended);
710+
pool.fix_string(pool.str_running);
711+
pool.fix_string(pool.str_normal);
712+
pool.fix_string(pool.str_dead);
693713

694714
pool
695715
}

crates/luars/src/lua_vm/execute/control_instructions.rs

Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -905,46 +905,57 @@ pub fn exec_call(
905905
return Ok(());
906906
}
907907

908-
// Slow path: Check for __call metamethod
909-
if func.kind() == LuaValueKind::Table {
910-
let metatable_opt = func.as_table_id().and_then(|table_id| {
911-
vm.object_pool
912-
.get_table(table_id)
913-
.and_then(|t| t.get_metatable())
914-
});
915-
916-
if let Some(metatable) = metatable_opt {
917-
// Use pre-cached __call StringId
918-
let call_key = LuaValue::string(vm.object_pool.tm_call);
919-
if let Some(call_func) = vm.table_get_with_meta(&metatable, &call_key) {
920-
if call_func.is_callable() {
921-
if call_func.is_cfunction() {
922-
exec_call_cfunction(
923-
vm,
924-
call_func,
925-
a,
926-
b,
927-
c,
928-
base,
929-
true,
930-
func,
931-
frame_ptr_ptr,
932-
)?;
933-
return Ok(());
934-
} else {
935-
exec_call_lua_function(
936-
vm,
937-
call_func,
938-
a,
939-
b,
940-
c,
941-
base,
942-
true,
943-
func,
944-
frame_ptr_ptr,
945-
)?;
946-
return Ok(());
947-
}
908+
// Slow path: Check for __call metamethod (for Table and Userdata)
909+
let metatable_opt = match func.kind() {
910+
LuaValueKind::Table => {
911+
func.as_table_id().and_then(|table_id| {
912+
vm.object_pool
913+
.get_table(table_id)
914+
.and_then(|t| t.get_metatable())
915+
})
916+
}
917+
LuaValueKind::Userdata => {
918+
func.as_userdata_id().and_then(|ud_id| {
919+
vm.object_pool
920+
.get_userdata(ud_id)
921+
.map(|ud| ud.get_metatable())
922+
.filter(|mt| !mt.is_nil())
923+
})
924+
}
925+
_ => None,
926+
};
927+
928+
if let Some(metatable) = metatable_opt {
929+
// Use pre-cached __call StringId
930+
let call_key = LuaValue::string(vm.object_pool.tm_call);
931+
if let Some(call_func) = vm.table_get_with_meta(&metatable, &call_key) {
932+
if call_func.is_callable() {
933+
if call_func.is_cfunction() {
934+
exec_call_cfunction(
935+
vm,
936+
call_func,
937+
a,
938+
b,
939+
c,
940+
base,
941+
true,
942+
func,
943+
frame_ptr_ptr,
944+
)?;
945+
return Ok(());
946+
} else {
947+
exec_call_lua_function(
948+
vm,
949+
call_func,
950+
a,
951+
b,
952+
c,
953+
base,
954+
true,
955+
func,
956+
frame_ptr_ptr,
957+
)?;
958+
return Ok(());
948959
}
949960
}
950961
}

crates/luars/src/lua_vm/mod.rs

Lines changed: 53 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -638,78 +638,68 @@ impl LuaVM {
638638
return Err(self.error("invalid thread".to_string()));
639639
};
640640

641-
// Check thread status first
642-
let status = {
643-
let Some(thread) = self.object_pool.get_thread(thread_id) else {
641+
// OPTIMIZED: Single lookup for status check and state modification
642+
let (is_first_resume, func_for_upvalues) = {
643+
let Some(thread) = self.object_pool.get_thread_mut(thread_id) else {
644644
return Err(self.error("invalid thread".to_string()));
645645
};
646-
thread.status
647-
};
648646

649-
match status {
650-
CoroutineStatus::Dead => {
651-
return Ok((
652-
false,
653-
vec![self.create_string("cannot resume dead coroutine")],
654-
));
655-
}
656-
CoroutineStatus::Running => {
657-
return Ok((
658-
false,
659-
vec![self.create_string("cannot resume running coroutine")],
660-
));
647+
match thread.status {
648+
CoroutineStatus::Dead => {
649+
return Ok((
650+
false,
651+
vec![self.create_string("cannot resume dead coroutine")],
652+
));
653+
}
654+
CoroutineStatus::Running => {
655+
return Ok((
656+
false,
657+
vec![self.create_string("cannot resume running coroutine")],
658+
));
659+
}
660+
_ => {}
661661
}
662-
_ => {}
663-
}
664-
665-
// OPTIMIZED: Use swap to exchange state with thread
666-
// This avoids allocation/deallocation overhead of take
667-
let is_first_resume;
668-
{
669-
let Some(thread) = self.object_pool.get_thread_mut(thread_id) else {
670-
return Err(self.error("invalid thread".to_string()));
671-
};
672662

673-
is_first_resume = thread.frame_count == 0;
663+
let is_first = thread.frame_count == 0;
674664
thread.status = CoroutineStatus::Running;
675-
}
665+
666+
// Get function for upvalue closing if first resume
667+
let func = if is_first {
668+
thread.register_stack.get(0).cloned()
669+
} else {
670+
None
671+
};
672+
673+
(is_first, func)
674+
};
676675

677676
// CRITICAL FIX: Before first resume, close all open upvalues in the coroutine function
678-
// This is necessary because open upvalues point to stack positions in the MAIN thread.
679-
// After swap, the coroutine has its own stack, so open upvalues would point to wrong locations.
680-
// By closing them BEFORE swap, we capture their current values from the main stack.
681677
if is_first_resume {
682-
let func = {
683-
let Some(thread) = self.object_pool.get_thread(thread_id) else {
684-
return Err(self.error("invalid thread".to_string()));
685-
};
686-
thread.register_stack.get(0).cloned().unwrap_or(LuaValue::nil())
687-
};
688-
689-
// If the function has upvalues, close them before swap
690-
if let Some(func_id) = func.as_function_id() {
691-
// Get upvalue IDs from the function
692-
let upvalue_ids: Vec<UpvalueId> = {
693-
if let Some(func_ref) = self.object_pool.get_function(func_id) {
694-
func_ref.upvalues.clone()
695-
} else {
696-
Vec::new()
697-
}
698-
};
699-
700-
// Close each open upvalue by reading from current (main) stack
701-
for uv_id in upvalue_ids {
702-
if let Some(uv) = self.object_pool.get_upvalue(uv_id) {
703-
if let Some(stack_idx) = uv.get_stack_index() {
704-
// Read current value from main stack
705-
let value = if stack_idx < self.register_stack.len() {
706-
self.register_stack[stack_idx]
707-
} else {
708-
LuaValue::nil()
709-
};
710-
// Close the upvalue with this value
711-
if let Some(uv_mut) = self.object_pool.get_upvalue_mut(uv_id) {
712-
uv_mut.close(value);
678+
if let Some(func) = func_for_upvalues {
679+
if let Some(func_id) = func.as_function_id() {
680+
// Get upvalue IDs from the function
681+
let upvalue_ids: Vec<UpvalueId> = {
682+
if let Some(func_ref) = self.object_pool.get_function(func_id) {
683+
func_ref.upvalues.clone()
684+
} else {
685+
Vec::new()
686+
}
687+
};
688+
689+
// Close each open upvalue by reading from current (main) stack
690+
for uv_id in upvalue_ids {
691+
if let Some(uv) = self.object_pool.get_upvalue(uv_id) {
692+
if let Some(stack_idx) = uv.get_stack_index() {
693+
// Read current value from main stack
694+
let value = if stack_idx < self.register_stack.len() {
695+
self.register_stack[stack_idx]
696+
} else {
697+
LuaValue::nil()
698+
};
699+
// Close the upvalue with this value
700+
if let Some(uv_mut) = self.object_pool.get_upvalue_mut(uv_id) {
701+
uv_mut.close(value);
702+
}
713703
}
714704
}
715705
}

0 commit comments

Comments
 (0)