@@ -19,15 +19,18 @@ pub struct HostImport {
1919pub struct Program {
2020 pub constants : Vec < Value > ,
2121 pub code : Vec < u8 > ,
22+ pub local_count : usize ,
2223 pub imports : Vec < HostImport > ,
2324 pub debug : Option < crate :: debug_info:: DebugInfo > ,
2425}
2526
2627impl Program {
2728 pub fn new ( constants : Vec < Value > , code : Vec < u8 > ) -> Self {
29+ let local_count = infer_local_count_from_code ( & code) ;
2830 Self {
2931 constants,
3032 code,
33+ local_count,
3134 imports : Vec :: new ( ) ,
3235 debug : None ,
3336 }
@@ -38,9 +41,11 @@ impl Program {
3841 code : Vec < u8 > ,
3942 debug : Option < crate :: debug_info:: DebugInfo > ,
4043 ) -> Self {
44+ let local_count = infer_local_count_from_code ( & code) ;
4145 Self {
4246 constants,
4347 code,
48+ local_count,
4449 imports : Vec :: new ( ) ,
4550 debug,
4651 }
@@ -52,13 +57,72 @@ impl Program {
5257 imports : Vec < HostImport > ,
5358 debug : Option < crate :: debug_info:: DebugInfo > ,
5459 ) -> Self {
60+ let local_count = infer_local_count_from_code ( & code) ;
5561 Self {
5662 constants,
5763 code,
64+ local_count,
5865 imports,
5966 debug,
6067 }
6168 }
69+
70+ pub fn with_local_count ( mut self , local_count : usize ) -> Self {
71+ self . local_count = local_count;
72+ self
73+ }
74+ }
75+
76+ fn infer_local_count_from_code ( code : & [ u8 ] ) -> usize {
77+ let mut ip = 0usize ;
78+ let mut max_local_index: Option < u8 > = None ;
79+
80+ while let Some ( & opcode) = code. get ( ip) {
81+ ip += 1 ;
82+ match opcode {
83+ x if x == OpCode :: Nop as u8
84+ || x == OpCode :: Ret as u8
85+ || x == OpCode :: Add as u8
86+ || x == OpCode :: Sub as u8
87+ || x == OpCode :: Mul as u8
88+ || x == OpCode :: Div as u8
89+ || x == OpCode :: Neg as u8
90+ || x == OpCode :: Ceq as u8
91+ || x == OpCode :: Clt as u8
92+ || x == OpCode :: Cgt as u8
93+ || x == OpCode :: Pop as u8
94+ || x == OpCode :: Dup as u8
95+ || x == OpCode :: Shl as u8
96+ || x == OpCode :: Shr as u8
97+ || x == OpCode :: Mod as u8
98+ || x == OpCode :: And as u8
99+ || x == OpCode :: Or as u8 => { }
100+ x if x == OpCode :: Ldc as u8
101+ || x == OpCode :: Br as u8
102+ || x == OpCode :: Brfalse as u8 => {
103+ if ip + 4 > code. len ( ) {
104+ break ;
105+ }
106+ ip += 4 ;
107+ }
108+ x if x == OpCode :: Ldloc as u8 || x == OpCode :: Stloc as u8 => {
109+ let Some ( & index) = code. get ( ip) else {
110+ break ;
111+ } ;
112+ ip += 1 ;
113+ max_local_index = Some ( max_local_index. map_or ( index, |prev| prev. max ( index) ) ) ;
114+ }
115+ x if x == OpCode :: Call as u8 => {
116+ if ip + 3 > code. len ( ) {
117+ break ;
118+ }
119+ ip += 3 ;
120+ }
121+ _ => break ,
122+ }
123+ }
124+
125+ max_local_index. map_or ( 0 , |index| index as usize + 1 )
62126}
63127
64128#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
0 commit comments