2020
2121use crate :: {
2222 CallInfo , Instruction , LUA_MASKCALL , LUA_MASKCOUNT , LUA_MASKLINE , LUA_MASKRET , LuaResult ,
23- LuaState , LuaValue , OpCode ,
23+ LuaState , LuaValue , OpCode , TablePtr ,
2424 lua_value:: LUA_VNUMINT ,
2525 lua_vm:: {
2626 LuaError , TmKind ,
@@ -32,22 +32,50 @@ use crate::{
3232 helper:: {
3333 bin_tm_fallback, eq_fallback, error_div_by_zero, error_global, error_mod_by_zero,
3434 finishget_fallback, finishset_fallback, finishset_fallback_known_miss,
35- float_for_loop, fltvalue, forprep, handle_pending_ops , ivalue , lua_fmod , lua_idiv ,
36- lua_imod , lua_shiftl , lua_shiftr , luai_numpow , objlen , order_tm_fallback ,
37- pfltvalue , pivalue , psetfltvalue , psetivalue , ptonumberns , pttisfloat ,
38- pttisinteger , return0_with_hook , return1_with_hook , self_shortstr_index_chain_fast ,
39- setbfvalue , setbtvalue , setfltvalue , setivalue , setnilvalue , setobj2s , setobjs2s ,
40- tointeger , tointegerns , tonumberns , ttisfloat , ttisinteger , ttisstring ,
41- unary_tm_fallback,
35+ float_for_loop, fltvalue, forprep, get_metamethod_from_meta_ptr ,
36+ handle_pending_ops , ivalue , lua_fmod , lua_idiv , lua_imod , lua_shiftl , lua_shiftr ,
37+ luai_numpow , objlen , order_tm_fallback , pfltvalue , pivalue , psetfltvalue ,
38+ psetivalue , ptonumberns , pttisfloat , pttisinteger , return0_with_hook ,
39+ return1_with_hook , self_shortstr_index_chain_fast , setbfvalue , setbtvalue ,
40+ setfltvalue , setivalue , setnilvalue , setobj2s , setobjs2s , tointeger , tointegerns ,
41+ tonumberns , ttisfloat , ttisinteger , ttisstring , unary_tm_fallback,
4242 } ,
4343 hook:: { hook_check_instruction, hook_on_call} ,
44+ metamethod:: call_tm,
4445 number:: { le_num, lt_num} ,
4546 vararg:: { exec_varargprep, get_vararg, get_varargs} ,
4647 } ,
4748 lua_limits:: EXTRA_STACK ,
4849 } ,
4950} ;
5051
52+ #[ inline( always) ]
53+ fn call_newindex_tm_fast (
54+ lua_state : & mut LuaState ,
55+ ci : & mut CallInfo ,
56+ obj : LuaValue ,
57+ meta : TablePtr ,
58+ key : LuaValue ,
59+ value : LuaValue ,
60+ ) -> LuaResult < bool > {
61+ let Some ( tm) = get_metamethod_from_meta_ptr ( lua_state, meta, TmKind :: NewIndex ) else {
62+ return Ok ( false ) ;
63+ } ;
64+ if !tm. is_function ( ) {
65+ return Ok ( false ) ;
66+ }
67+
68+ match call_tm ( lua_state, tm, obj, key, value) {
69+ Ok ( ( ) ) => Ok ( true ) ,
70+ Err ( LuaError :: Yield ) => {
71+ ci. set_pending_finish_get ( -2 ) ;
72+ ci. call_status |= CIST_PENDING_FINISH ;
73+ Err ( LuaError :: Yield )
74+ }
75+ Err ( e) => Err ( e) ,
76+ }
77+ }
78+
5179/// Execute until call depth reaches target_depth
5280/// Used for protected calls (pcall) to execute only the called function
5381/// without affecting caller frames
@@ -462,11 +490,12 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<(
462490 "GetTabUp key must be short string for fast path"
463491 ) ;
464492 let mut known_newindex_miss = false ;
493+ let mut meta = TablePtr :: null ( ) ;
465494 if upval_value. is_table ( ) {
466495 let table = upval_value. hvalue_mut ( ) ;
467496 let table_ptr = unsafe { upval_value. as_table_ptr_unchecked ( ) } ;
468497 let gc_ptr = unsafe { upval_value. as_gc_ptr_table_unchecked ( ) } ;
469- let meta = table. meta_ptr ( ) ;
498+ meta = table. meta_ptr ( ) ;
470499 if meta. is_null ( ) || meta. as_mut_ref ( ) . data . no_tm ( TmKind :: NewIndex . into ( ) ) {
471500 let ( new_key, delta, rc_tt) = if instr. get_k ( ) {
472501 let rc = * k_val ! ( c) ;
@@ -538,6 +567,10 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<(
538567 } ;
539568 savestate ! ( ) ;
540569 if known_newindex_miss {
570+ if call_newindex_tm_fast ( lua_state, ci, upval_value, meta, * key, rc) ? {
571+ updatetrap ! ( ) ;
572+ continue ;
573+ }
541574 finishset_fallback_known_miss ( lua_state, ci, & upval_value, key, rc) ?;
542575 } else {
543576 finishset_fallback ( lua_state, ci, & upval_value, key, rc) ?;
@@ -635,6 +668,10 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<(
635668 * stack_val ! ( c)
636669 } ;
637670 savestate ! ( ) ;
671+ if call_newindex_tm_fast ( lua_state, ci, ra, meta, rb, rc) ? {
672+ updatetrap ! ( ) ;
673+ continue ;
674+ }
638675 finishset_fallback_known_miss ( lua_state, ci, & ra, & rb, rc) ?;
639676 updatetrap ! ( ) ;
640677 continue ;
@@ -702,6 +739,10 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<(
702739 continue ;
703740 }
704741 savestate ! ( ) ;
742+ if call_newindex_tm_fast ( lua_state, ci, ra, meta, rb, rc) ? {
743+ updatetrap ! ( ) ;
744+ continue ;
745+ }
705746 finishset_fallback_known_miss ( lua_state, ci, & ra, & rb, rc) ?;
706747 updatetrap ! ( ) ;
707748 continue ;
@@ -781,6 +822,10 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<(
781822 let ra = * ra;
782823 let rb = LuaValue :: integer ( b) ;
783824 savestate ! ( ) ;
825+ if call_newindex_tm_fast ( lua_state, ci, ra, meta, rb, rc) ? {
826+ updatetrap ! ( ) ;
827+ continue ;
828+ }
784829 finishset_fallback_known_miss ( lua_state, ci, & ra, & rb, rc) ?;
785830 updatetrap ! ( ) ;
786831 continue ;
@@ -809,9 +854,10 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<(
809854 "SetField key must be short string for fast path"
810855 ) ;
811856 let mut known_newindex_miss = false ;
857+ let mut meta = TablePtr :: null ( ) ;
812858 if unsafe { ( * ra_ptr) . is_table ( ) } {
813859 let table = unsafe { ( * ra_ptr) . hvalue_mut ( ) } ;
814- let meta = table. meta_ptr ( ) ;
860+ meta = table. meta_ptr ( ) ;
815861 if meta. is_null ( ) || meta. as_mut_ref ( ) . data . no_tm ( TmKind :: NewIndex . into ( ) ) {
816862 let ( new_key, delta, rc_tt) = if instr. get_k ( ) {
817863 let rc = * k_val ! ( c) ;
@@ -894,6 +940,10 @@ pub fn lua_execute(lua_state: &mut LuaState, target_depth: usize) -> LuaResult<(
894940 let rb = * key;
895941 savestate ! ( ) ;
896942 if known_newindex_miss {
943+ if call_newindex_tm_fast ( lua_state, ci, ra, meta, rb, rc) ? {
944+ updatetrap ! ( ) ;
945+ continue ;
946+ }
897947 finishset_fallback_known_miss ( lua_state, ci, & ra, & rb, rc) ?;
898948 } else {
899949 finishset_fallback ( lua_state, ci, & ra, & rb, rc) ?;
0 commit comments