1818
1919use crate :: {
2020 Instruction , LuaResult , LuaValue , OpCode ,
21- gc:: TablePtr ,
2221 lua_vm:: {
2322 LuaState , StkId , TmKind ,
2423 call_info:: CallInfo ,
@@ -253,6 +252,8 @@ pub(crate) fn op_get_field(
253252// ── SET operations ──────────────────────────────────────────────
254253
255254/// SetTabUp: UpValue[A][K[B]:shortstring] := RK(C)
255+ ///
256+ /// Lua 5.5 style: fast set first, metatable deferred to fallback.
256257#[ inline]
257258pub ( crate ) fn op_set_tabup (
258259 lua_state : & mut LuaState ,
@@ -269,79 +270,78 @@ pub(crate) fn op_set_tabup(
269270 let upvalue_ptr = unsafe { * ci. upvalue_ptrs . add ( a as usize ) } ;
270271 let upval_value = upvalue_ptr. as_ref ( ) . data . get_value_ref ( ) ;
271272 let key = k_val ( constants, b) ;
272- debug_assert ! (
273- key. is_short_string( ) ,
274- "GetTabUp key must be short string for fast path"
275- ) ;
276- let mut known_newindex_miss = false ;
277- let mut meta = TablePtr :: null ( ) ;
273+ debug_assert ! ( key. is_short_string( ) , "SetTabUp key must be short string" ) ;
274+
275+ // Unified value extraction (RKC in C)
276+ let ( rc_ref, rc_is_collectable) = if instr. get_k ( ) {
277+ let v = k_val ( constants, c) ;
278+ ( v, v. is_collectable ( ) )
279+ } else {
280+ let stk = ( * base_stk) . offset ( c as usize ) ;
281+ ( stk. get_ref ( ) , stk. is_collectable ( ) )
282+ } ;
283+
284+ // luaV_fastset: fast set first, no metatable check
278285 if upval_value. is_table ( ) {
279286 let table = upval_value. hvalue_mut ( ) ;
280287 let table_ptr = upval_value. table_ptr_raw ( ) ;
281288 let gc_ptr = upval_value. as_gc_ptr_unchecked ( ) ;
282- meta = table. meta_ptr ( ) ;
289+ let pset_result = table. impl_table . pset_shortstr ( key, rc_ref) ;
290+
291+ // HOK: existing key, value written
292+ if pset_result. is_hok ( ) {
293+ if rc_is_collectable {
294+ lua_state. gc_barrier_back ( gc_ptr) ;
295+ }
296+ return Ok ( ( ) ) ;
297+ }
298+
299+ // Fallback: check metatable
300+ let meta = table. meta_ptr ( ) ;
283301 if meta. is_null ( ) || meta. as_mut_ref ( ) . data . no_tm ( TmKind :: NewIndex . into ( ) ) {
284- let ( new_key, delta, is_collectable) = if instr. get_k ( ) {
285- let rc_value = k_val ( constants, c) ;
286- let pset_result = table. impl_table . pset_shortstr ( key, rc_value) ;
287- let ( new_key, delta) =
288- table
289- . impl_table
290- . finish_shortstr_set ( key, rc_value, pset_result) ;
291- ( new_key, delta, rc_value. is_collectable ( ) )
292- } else {
293- let rc = ( * base_stk) . offset ( c as usize ) ;
294- let pset_result = table. impl_table . pset_shortstr ( key, rc. get_ref ( ) ) ;
295- let ( new_key, delta) =
296- table
297- . impl_table
298- . finish_shortstr_set ( key, rc. get_ref ( ) , pset_result) ;
299- ( new_key, delta, rc. is_collectable ( ) )
300- } ;
302+ let ( new_key, delta) = table
303+ . impl_table
304+ . finish_shortstr_set ( key, rc_ref, pset_result) ;
301305 if new_key {
302306 table. invalidate_tm_cache ( ) ;
303307 }
304308 if delta != 0 {
305309 lua_state. gc_track_table_resize ( table_ptr, delta) ;
306310 }
307- if is_collectable {
311+ if rc_is_collectable {
308312 lua_state. gc_barrier_back ( gc_ptr) ;
309313 }
310314 return Ok ( ( ) ) ;
311- } else {
312- let rc_value = if instr. get_k ( ) {
313- k_val ( constants, c)
314- } else {
315- ( * base_stk) . offset ( c as usize ) . get_ref ( )
316- } ;
317- if table. impl_table . set_existing_shortstr ( key, rc_value) {
318- if rc_value. is_collectable ( ) {
319- lua_state. gc_barrier_back ( gc_ptr) ;
320- }
321- return Ok ( ( ) ) ;
322- }
323- known_newindex_miss = true ;
324315 }
325- }
326316
327- let upval_value = * upval_value;
328- let rc = if instr. get_k ( ) {
329- * k_val ( constants, c)
330- } else {
331- ( * base_stk) . offset ( c as usize ) . get ( )
332- } ;
333- ci. save_pc ( pc) ;
334- lua_state. set_top_raw ( ci. top as usize ) ;
335- if known_newindex_miss {
336- if call_newindex_tm_fast ( lua_state, ci, upval_value, meta, * key, rc) ? {
317+ // Has __newindex
318+ if table. impl_table . set_existing_shortstr ( key, rc_ref) {
319+ if rc_is_collectable {
320+ lua_state. gc_barrier_back ( gc_ptr) ;
321+ }
322+ return Ok ( ( ) ) ;
323+ }
324+ let upval = * upval_value;
325+ let rc = * rc_ref;
326+ ci. save_pc ( pc) ;
327+ lua_state. set_top_raw ( ci. top as usize ) ;
328+ if call_newindex_tm_fast ( lua_state, ci, upval, meta, * key, rc) ? {
337329 * base_stk = ci. base_stk ;
338330 updatetrap ! ( trap, lua_state) ;
339331 return Ok ( ( ) ) ;
340332 }
341- finishset_fallback ( lua_state, ci, & upval_value, key, rc, true ) ?;
342- } else {
343- finishset_fallback ( lua_state, ci, & upval_value, key, rc, false ) ?;
333+ finishset_fallback ( lua_state, ci, & upval, key, rc, true ) ?;
334+ * base_stk = ci. base_stk ;
335+ updatetrap ! ( trap, lua_state) ;
336+ return Ok ( ( ) ) ;
344337 }
338+
339+ // Not a table
340+ let upval = * upval_value;
341+ let rc = * rc_ref;
342+ ci. save_pc ( pc) ;
343+ lua_state. set_top_raw ( ci. top as usize ) ;
344+ finishset_fallback ( lua_state, ci, & upval, key, rc, false ) ?;
345345 * base_stk = ci. base_stk ;
346346 updatetrap ! ( trap, lua_state) ;
347347 Ok ( ( ) )
@@ -549,45 +549,31 @@ pub(crate) fn op_set_i(
549549 let b = instr. get_b ( ) as i64 ;
550550 let c = instr. get_c ( ) ;
551551
552- // Hot path: table with no __newindex metamethod, key in array range
553552 if ra. is_table ( ) {
554553 let table = ra. hvalue_mut ( ) ;
555554 let table_ptr = ra. as_table_ptr ( ) ;
556555 let gc_ptr = ra. as_gc_ptr ( ) ;
557556 let meta = table. meta_ptr ( ) ;
558557 if meta. is_null ( ) || meta. as_mut_ref ( ) . data . no_tm ( TmKind :: NewIndex . into ( ) ) {
559- if !instr. get_k ( ) {
560- let rc = base. offset ( c as usize ) ;
561- if table. impl_table . fast_seti ( b, rc. get ( ) ) {
562- if rc. is_collectable ( ) {
563- lua_state. gc_barrier_back ( gc_ptr) ;
564- }
565- return Ok ( ( ) ) ;
566- }
567-
568- let delta = table. impl_table . set_int_slow ( b, rc. get ( ) ) ;
569- if delta != 0 {
570- lua_state. gc_track_table_resize ( table_ptr, delta) ;
571- }
572- if rc. is_collectable ( ) {
573- lua_state. gc_barrier_back ( gc_ptr) ;
574- }
575- return Ok ( ( ) ) ;
576- }
558+ let ( rc_val, rc_is_collectable) = if instr. get_k ( ) {
559+ let v = * k_val ( constants, c) ;
560+ ( v, v. is_collectable ( ) )
561+ } else {
562+ let stk = base. offset ( c as usize ) ;
563+ ( stk. get ( ) , stk. is_collectable ( ) )
564+ } ;
577565
578- let rc = * k_val ( constants, c) ;
579- if table. impl_table . fast_seti ( b, rc) {
580- if rc. is_collectable ( ) {
566+ if table. impl_table . fast_seti ( b, rc_val) {
567+ if rc_is_collectable {
581568 lua_state. gc_barrier_back ( gc_ptr) ;
582569 }
583570 return Ok ( ( ) ) ;
584571 }
585-
586- let delta = table. impl_table . set_int_slow ( b, rc) ;
572+ let delta = table. impl_table . set_int_slow ( b, rc_val) ;
587573 if delta != 0 {
588574 lua_state. gc_track_table_resize ( table_ptr, delta) ;
589575 }
590- if rc . is_collectable ( ) {
576+ if rc_is_collectable {
591577 lua_state. gc_barrier_back ( gc_ptr) ;
592578 }
593579 return Ok ( ( ) ) ;
@@ -603,7 +589,6 @@ pub(crate) fn op_set_i(
603589 }
604590 return Ok ( ( ) ) ;
605591 }
606- // Fall through to finishset fallback (known miss)
607592 let rb = LuaValue :: integer ( b) ;
608593 ci. save_pc ( pc) ;
609594 lua_state. set_top_raw ( ci. top as usize ) ;
0 commit comments