@@ -43,22 +43,54 @@ pub fn create_math_lib() -> LibraryModule {
4343 module
4444}
4545
46+ /// OPTIMIZED: Get number without allocating error message on success path
47+ #[ inline( always) ]
48+ fn get_number_fast ( vm : & LuaVM , idx : usize ) -> Option < f64 > {
49+ let frame = vm. current_frame ( ) ;
50+ let base_ptr = frame. base_ptr as usize ;
51+ let top = frame. top as usize ;
52+
53+ if idx < top {
54+ let value = vm. register_stack [ base_ptr + idx] ;
55+ value. as_number ( )
56+ } else {
57+ None
58+ }
59+ }
60+
4661fn get_number ( vm : & mut LuaVM , idx : usize , func_name : & str ) -> LuaResult < f64 > {
47- let value = require_arg ( vm, idx, func_name) ?;
48- if let Some ( value) = value. as_number ( ) {
49- Ok ( value)
62+ if let Some ( n) = get_number_fast ( vm, idx) {
63+ Ok ( n)
5064 } else {
5165 Err ( vm. error ( format ! (
5266 "bad argument #{} to '{}' (number expected)" ,
53- idx + 1 ,
67+ idx,
5468 func_name
5569 ) ) )
5670 }
5771}
5872
5973fn math_abs ( vm : & mut LuaVM ) -> LuaResult < MultiValue > {
60- let x = get_number ( vm, 1 , "math.abs" ) ?;
61- Ok ( MultiValue :: single ( LuaValue :: float ( x. abs ( ) ) ) )
74+ let frame = vm. current_frame ( ) ;
75+ let base_ptr = frame. base_ptr as usize ;
76+ let top = frame. top as usize ;
77+
78+ if top <= 1 {
79+ return Err ( vm. error ( "bad argument #1 to 'abs' (number expected)" . to_string ( ) ) ) ;
80+ }
81+
82+ let value = vm. register_stack [ base_ptr + 1 ] ;
83+
84+ // Fast path: preserve integer type
85+ if let Some ( i) = value. as_integer ( ) {
86+ return Ok ( MultiValue :: single ( LuaValue :: integer ( i. abs ( ) ) ) ) ;
87+ }
88+
89+ if let Some ( f) = value. as_float ( ) {
90+ return Ok ( MultiValue :: single ( LuaValue :: float ( f. abs ( ) ) ) ) ;
91+ }
92+
93+ Err ( vm. error ( "bad argument #1 to 'abs' (number expected)" . to_string ( ) ) )
6294}
6395
6496fn math_acos ( vm : & mut LuaVM ) -> LuaResult < MultiValue > {
@@ -78,8 +110,26 @@ fn math_atan(vm: &mut LuaVM) -> LuaResult<MultiValue> {
78110}
79111
80112fn math_ceil ( vm : & mut LuaVM ) -> LuaResult < MultiValue > {
81- let x = get_number ( vm, 1 , "math.ceil" ) ?;
82- Ok ( MultiValue :: single ( LuaValue :: float ( x. ceil ( ) ) ) )
113+ let frame = vm. current_frame ( ) ;
114+ let base_ptr = frame. base_ptr as usize ;
115+ let top = frame. top as usize ;
116+
117+ if top <= 1 {
118+ return Err ( vm. error ( "bad argument #1 to 'ceil' (number expected)" . to_string ( ) ) ) ;
119+ }
120+
121+ let value = vm. register_stack [ base_ptr + 1 ] ;
122+
123+ // Fast path: integers are already ceil'd
124+ if let Some ( i) = value. as_integer ( ) {
125+ return Ok ( MultiValue :: single ( LuaValue :: integer ( i) ) ) ;
126+ }
127+
128+ if let Some ( f) = value. as_float ( ) {
129+ return Ok ( MultiValue :: single ( LuaValue :: integer ( f. ceil ( ) as i64 ) ) ) ;
130+ }
131+
132+ Err ( vm. error ( "bad argument #1 to 'ceil' (number expected)" . to_string ( ) ) )
83133}
84134
85135fn math_cos ( vm : & mut LuaVM ) -> LuaResult < MultiValue > {
@@ -98,8 +148,26 @@ fn math_exp(vm: &mut LuaVM) -> LuaResult<MultiValue> {
98148}
99149
100150fn math_floor ( vm : & mut LuaVM ) -> LuaResult < MultiValue > {
101- let x = get_number ( vm, 1 , "math.floor" ) ?;
102- Ok ( MultiValue :: single ( LuaValue :: integer ( x. floor ( ) as i64 ) ) )
151+ let frame = vm. current_frame ( ) ;
152+ let base_ptr = frame. base_ptr as usize ;
153+ let top = frame. top as usize ;
154+
155+ if top <= 1 {
156+ return Err ( vm. error ( "bad argument #1 to 'floor' (number expected)" . to_string ( ) ) ) ;
157+ }
158+
159+ let value = vm. register_stack [ base_ptr + 1 ] ;
160+
161+ // Fast path: integers are already floor'd
162+ if let Some ( i) = value. as_integer ( ) {
163+ return Ok ( MultiValue :: single ( LuaValue :: integer ( i) ) ) ;
164+ }
165+
166+ if let Some ( f) = value. as_float ( ) {
167+ return Ok ( MultiValue :: single ( LuaValue :: integer ( f. floor ( ) as i64 ) ) ) ;
168+ }
169+
170+ Err ( vm. error ( "bad argument #1 to 'floor' (number expected)" . to_string ( ) ) )
103171}
104172
105173fn math_fmod ( vm : & mut LuaVM ) -> LuaResult < MultiValue > {
@@ -117,62 +185,66 @@ fn math_log(vm: &mut LuaVM) -> LuaResult<MultiValue> {
117185 Ok ( MultiValue :: single ( LuaValue :: float ( result) ) )
118186}
119187
188+ /// OPTIMIZED: Direct stack access without get_arg overhead
120189fn math_max ( vm : & mut LuaVM ) -> LuaResult < MultiValue > {
121- use crate :: lib_registry:: { arg_count, get_arg} ;
190+ let frame = vm. current_frame ( ) ;
191+ let base_ptr = frame. base_ptr as usize ;
192+ let top = frame. top as usize ;
193+ let argc = top. saturating_sub ( 1 ) ;
122194
123- let argc = arg_count ( vm) ;
124195 if argc == 0 {
125196 return Err ( vm. error ( "bad argument to 'math.max' (value expected)" . to_string ( ) ) ) ;
126197 }
127198
128- // Get first argument
129- let first = get_arg ( vm , 1 ) . unwrap ( ) ;
199+ // Get first argument directly
200+ let first = vm . register_stack [ base_ptr + 1 ] ;
130201 let mut max_val = first
131202 . as_number ( )
132203 . ok_or_else ( || vm. error ( "bad argument to 'math.max' (number expected)" . to_string ( ) ) ) ?;
133204 let mut max_arg = first;
134205
135- // Compare with rest
206+ // Compare with rest - direct stack access
136207 for i in 2 ..=argc {
137- if let Some ( arg) = get_arg ( vm, i) {
138- let val = arg. as_number ( ) . ok_or_else ( || {
139- vm. error ( "bad argument to 'math.max' (number expected)" . to_string ( ) )
140- } ) ?;
141- if val > max_val {
142- max_val = val;
143- max_arg = arg;
144- }
208+ let arg = vm. register_stack [ base_ptr + i] ;
209+ let val = arg. as_number ( ) . ok_or_else ( || {
210+ vm. error ( "bad argument to 'math.max' (number expected)" . to_string ( ) )
211+ } ) ?;
212+ if val > max_val {
213+ max_val = val;
214+ max_arg = arg;
145215 }
146216 }
147217
148218 Ok ( MultiValue :: single ( max_arg) )
149219}
150220
221+ /// OPTIMIZED: Direct stack access without get_arg overhead
151222fn math_min ( vm : & mut LuaVM ) -> LuaResult < MultiValue > {
152- use crate :: lib_registry:: { arg_count, get_arg} ;
223+ let frame = vm. current_frame ( ) ;
224+ let base_ptr = frame. base_ptr as usize ;
225+ let top = frame. top as usize ;
226+ let argc = top. saturating_sub ( 1 ) ;
153227
154- let argc = arg_count ( vm) ;
155228 if argc == 0 {
156229 return Err ( vm. error ( "bad argument to 'math.min' (value expected)" . to_string ( ) ) ) ;
157230 }
158231
159- // Get first argument
160- let first = get_arg ( vm , 1 ) . unwrap ( ) ;
232+ // Get first argument directly
233+ let first = vm . register_stack [ base_ptr + 1 ] ;
161234 let mut min_val = first
162235 . as_number ( )
163236 . ok_or_else ( || vm. error ( "bad argument to 'math.min' (number expected)" . to_string ( ) ) ) ?;
164237 let mut min_arg = first;
165238
166- // Compare with rest
239+ // Compare with rest - direct stack access
167240 for i in 2 ..=argc {
168- if let Some ( arg) = get_arg ( vm, i) {
169- let val = arg. as_number ( ) . ok_or_else ( || {
170- vm. error ( "bad argument to 'math.min' (number expected)" . to_string ( ) )
171- } ) ?;
172- if val < min_val {
173- min_val = val;
174- min_arg = arg;
175- }
241+ let arg = vm. register_stack [ base_ptr + i] ;
242+ let val = arg. as_number ( ) . ok_or_else ( || {
243+ vm. error ( "bad argument to 'math.min' (number expected)" . to_string ( ) )
244+ } ) ?;
245+ if val < min_val {
246+ min_val = val;
247+ min_arg = arg;
176248 }
177249 }
178250
@@ -195,28 +267,51 @@ fn math_rad(vm: &mut LuaVM) -> LuaResult<MultiValue> {
195267 Ok ( MultiValue :: single ( LuaValue :: float ( x. to_radians ( ) ) ) )
196268}
197269
198- fn math_random ( vm : & mut LuaVM ) -> LuaResult < MultiValue > {
199- use std:: collections:: hash_map:: RandomState ;
200- use std:: hash:: { BuildHasher , Hash , Hasher } ;
270+ /// Thread-local random state using xorshift64 algorithm
271+ /// Much faster than creating new RandomState each call
272+ use std:: cell:: Cell ;
273+ thread_local ! {
274+ static RANDOM_STATE : Cell <u64 > = Cell :: new( 0x853c49e6748fea9b_u64 ) ;
275+ }
201276
202- let argc = crate :: lib_registry:: arg_count ( vm) ;
277+ /// Fast xorshift64 random number generator
278+ #[ inline( always) ]
279+ fn xorshift64 ( ) -> u64 {
280+ RANDOM_STATE . with ( |state| {
281+ let mut x = state. get ( ) ;
282+ x ^= x << 13 ;
283+ x ^= x >> 7 ;
284+ x ^= x << 17 ;
285+ state. set ( x) ;
286+ x
287+ } )
288+ }
203289
204- // Simple pseudo-random using hash
205- let mut hasher = RandomState :: new ( ) . build_hasher ( ) ;
206- std:: time:: SystemTime :: now ( ) . hash ( & mut hasher) ;
207- let hash = hasher. finish ( ) ;
208- let random = ( hash % 1000000 ) as f64 / 1000000.0 ;
290+ fn math_random ( vm : & mut LuaVM ) -> LuaResult < MultiValue > {
291+ let frame = vm. current_frame ( ) ;
292+ let top = frame. top as usize ;
293+ let argc = top. saturating_sub ( 1 ) ;
294+
295+ // Generate random u64 and convert to [0, 1) float
296+ let rand_u64 = xorshift64 ( ) ;
297+ let random = ( rand_u64 >> 11 ) as f64 / ( 1u64 << 53 ) as f64 ;
209298
210299 match argc {
211300 0 => Ok ( MultiValue :: single ( LuaValue :: float ( random) ) ) ,
212301 1 => {
213302 let m = get_number ( vm, 1 , "math.random" ) ? as i64 ;
303+ if m < 1 {
304+ return Err ( vm. error ( "bad argument #1 to 'random' (interval is empty)" . to_string ( ) ) ) ;
305+ }
214306 let result = ( random * m as f64 ) . floor ( ) as i64 + 1 ;
215307 Ok ( MultiValue :: single ( LuaValue :: integer ( result) ) )
216308 }
217309 _ => {
218310 let m = get_number ( vm, 1 , "math.random" ) ? as i64 ;
219311 let n = get_number ( vm, 2 , "math.random" ) ? as i64 ;
312+ if m > n {
313+ return Err ( vm. error ( "bad argument #1 to 'random' (interval is empty)" . to_string ( ) ) ) ;
314+ }
220315 let range = ( n - m + 1 ) as f64 ;
221316 let result = m + ( random * range) . floor ( ) as i64 ;
222317 Ok ( MultiValue :: single ( LuaValue :: integer ( result) ) )
@@ -225,8 +320,13 @@ fn math_random(vm: &mut LuaVM) -> LuaResult<MultiValue> {
225320}
226321
227322fn math_randomseed ( vm : & mut LuaVM ) -> LuaResult < MultiValue > {
228- // Seed is ignored in our simple implementation
229- let _x = get_number ( vm, 1 , "math.randomseed" ) ?;
323+ let x = get_number ( vm, 1 , "math.randomseed" ) ? as u64 ;
324+ // Seed the random state
325+ RANDOM_STATE . with ( |state| {
326+ // Ensure seed is non-zero for xorshift
327+ let seed = if x == 0 { 0x853c49e6748fea9b_u64 } else { x } ;
328+ state. set ( seed) ;
329+ } ) ;
230330 Ok ( MultiValue :: empty ( ) )
231331}
232332
0 commit comments