@@ -8,9 +8,10 @@ use num_traits::ToPrimitive;
88use rustpython_compiler_core:: {
99 OneIndexed , SourceLocation ,
1010 bytecode:: {
11- AnyInstruction , Arg , CodeFlags , CodeObject , CodeUnit , CodeUnits , ConstantData ,
12- ExceptionTableEntry , InstrDisplayContext , Instruction , InstructionMetadata , Label , OpArg ,
13- PseudoInstruction , PyCodeLocationInfoKind , encode_exception_table, oparg,
11+ AnyInstruction , Arg , CO_FAST_CELL , CO_FAST_FREE , CO_FAST_LOCAL , CodeFlags , CodeObject ,
12+ CodeUnit , CodeUnits , ConstantData , ExceptionTableEntry , InstrDisplayContext , Instruction ,
13+ InstructionMetadata , Label , OpArg , PseudoInstruction , PyCodeLocationInfoKind ,
14+ encode_exception_table, oparg,
1415 } ,
1516 varint:: { write_signed_varint, write_varint} ,
1617} ;
@@ -255,6 +256,8 @@ impl CodeInfo {
255256
256257 // Convert pseudo ops and remove resulting NOPs (keep line-marker NOPs)
257258 convert_pseudo_ops ( & mut blocks, varname_cache. len ( ) as u32 ) ;
259+ // Fixup DEREF opargs: cell-relative → localsplus indices
260+ fixup_deref_opargs ( & mut blocks, varname_cache. len ( ) as u32 ) ;
258261 // Remove redundant NOPs, keeping line-marker NOPs only when
259262 // they are needed to preserve tracing.
260263 let mut block_order = Vec :: new ( ) ;
@@ -488,6 +491,15 @@ impl CodeInfo {
488491 // Generate exception table before moving source_path
489492 let exceptiontable = generate_exception_table ( & blocks, & block_to_index) ;
490493
494+ // Build localspluskinds: per-slot kind flags
495+ let nlocals = varname_cache. len ( ) ;
496+ let ncells = cellvar_cache. len ( ) ;
497+ let nfrees = freevar_cache. len ( ) ;
498+ let mut localspluskinds = Vec :: with_capacity ( nlocals + ncells + nfrees) ;
499+ localspluskinds. extend ( core:: iter:: repeat_n ( CO_FAST_LOCAL , nlocals) ) ;
500+ localspluskinds. extend ( core:: iter:: repeat_n ( CO_FAST_CELL , ncells) ) ;
501+ localspluskinds. extend ( core:: iter:: repeat_n ( CO_FAST_FREE , nfrees) ) ;
502+
491503 Ok ( CodeObject {
492504 flags,
493505 posonlyarg_count,
@@ -507,6 +519,7 @@ impl CodeInfo {
507519 cellvars : cellvar_cache. into_iter ( ) . collect ( ) ,
508520 freevars : freevar_cache. into_iter ( ) . collect ( ) ,
509521 cell2arg,
522+ localspluskinds : localspluskinds. into_boxed_slice ( ) ,
510523 linetable,
511524 exceptiontable,
512525 } )
@@ -1113,12 +1126,19 @@ impl InstrDisplayContext for CodeInfo {
11131126 self . metadata . varnames [ var_num. as_usize ( ) ] . as_ref ( )
11141127 }
11151128
1116- fn get_cell_name ( & self , i : usize ) -> & str {
1117- self . metadata
1118- . cellvars
1119- . get_index ( i)
1120- . unwrap_or_else ( || & self . metadata . freevars [ i - self . metadata . cellvars . len ( ) ] )
1121- . as_ref ( )
1129+ fn get_localsplus_name ( & self , var_num : oparg:: VarNum ) -> & str {
1130+ let idx = var_num. as_usize ( ) ;
1131+ let nlocals = self . metadata . varnames . len ( ) ;
1132+ if idx < nlocals {
1133+ self . metadata . varnames [ idx] . as_ref ( )
1134+ } else {
1135+ let cell_idx = idx - nlocals;
1136+ self . metadata
1137+ . cellvars
1138+ . get_index ( cell_idx)
1139+ . unwrap_or_else ( || & self . metadata . freevars [ cell_idx - self . metadata . cellvars . len ( ) ] )
1140+ . as_ref ( )
1141+ }
11221142 }
11231143}
11241144
@@ -1814,3 +1834,28 @@ pub(crate) fn convert_pseudo_ops(blocks: &mut [Block], varnames_len: u32) {
18141834 }
18151835 }
18161836}
1837+
1838+ /// Convert DEREF instruction opargs from cell-relative indices to localsplus indices.
1839+ /// Cell-relative index = cellvar_idx for cells, ncells + freevar_idx for frees.
1840+ /// Localsplus index = nlocals + cell_relative_idx.
1841+ pub ( crate ) fn fixup_deref_opargs ( blocks : & mut [ Block ] , nlocals : u32 ) {
1842+ for block in blocks. iter_mut ( ) {
1843+ for info in & mut block. instructions {
1844+ let Some ( instr) = info. instr . real ( ) else {
1845+ continue ;
1846+ } ;
1847+ let needs_fixup = matches ! (
1848+ instr,
1849+ Instruction :: LoadDeref { .. }
1850+ | Instruction :: StoreDeref { .. }
1851+ | Instruction :: DeleteDeref { .. }
1852+ | Instruction :: LoadFromDictOrDeref { .. }
1853+ | Instruction :: MakeCell { .. }
1854+ | Instruction :: RestoreCell { .. }
1855+ ) ;
1856+ if needs_fixup {
1857+ info. arg = OpArg :: new ( nlocals + u32:: from ( info. arg ) ) ;
1858+ }
1859+ }
1860+ }
1861+ }
0 commit comments