1+ #[ cfg( feature = "jit" ) ]
2+ mod jitfunc;
3+
14use super :: objcode:: PyCodeRef ;
25use super :: objdict:: PyDictRef ;
3- #[ cfg( feature = "jit" ) ]
4- use super :: objfloat;
5- #[ cfg( feature = "jit" ) ]
6- use super :: objint;
76use super :: objstr:: PyStringRef ;
87use super :: objtuple:: PyTupleRef ;
98use super :: objtype:: PyClassRef ;
@@ -13,34 +12,20 @@ use crate::function::{OptionalArg, PyFuncArgs};
1312use crate :: obj:: objasyncgenerator:: PyAsyncGen ;
1413use crate :: obj:: objcoroutine:: PyCoroutine ;
1514use crate :: obj:: objgenerator:: PyGenerator ;
15+ #[ cfg( feature = "jit" ) ]
16+ use crate :: pyobject:: IntoPyObject ;
1617use crate :: pyobject:: {
1718 BorrowValue , IdProtocol , ItemProtocol , PyClassImpl , PyContext , PyObjectRef , PyRef , PyResult ,
1819 PyValue , TypeProtocol ,
1920} ;
20- #[ cfg( feature = "jit" ) ]
21- use crate :: pyobject:: { IntoPyObject , TryFromObject } ;
2221use crate :: scope:: Scope ;
2322use crate :: slots:: { SlotCall , SlotDescriptor } ;
2423use crate :: VirtualMachine ;
2524use itertools:: Itertools ;
2625#[ cfg( feature = "jit" ) ]
27- use num_traits:: ToPrimitive ;
28- #[ cfg( feature = "jit" ) ]
29- use rustpython_bytecode:: bytecode:: CodeFlags ;
30- #[ cfg( feature = "jit" ) ]
3126use rustpython_common:: cell:: OnceCell ;
3227#[ cfg( feature = "jit" ) ]
33- use rustpython_jit:: { AbiValue , Args , CompiledCode , JitType } ;
34-
35- #[ cfg( feature = "jit" ) ]
36- impl IntoPyObject for AbiValue {
37- fn into_pyobject ( self , vm : & VirtualMachine ) -> PyObjectRef {
38- match self {
39- AbiValue :: Int ( i) => i. into_pyobject ( vm) ,
40- AbiValue :: Float ( f) => f. into_pyobject ( vm) ,
41- }
42- }
43- }
28+ use rustpython_jit:: CompiledCode ;
4429
4530pub type PyFunctionRef = PyRef < PyFunction > ;
4631
@@ -253,7 +238,7 @@ impl PyFunction {
253238 ) -> PyResult {
254239 #[ cfg( feature = "jit" ) ]
255240 if let Some ( jitted_code) = self . jitted_code . get ( ) {
256- if let Some ( args) = self . get_jit_args ( & func_args, jitted_code, vm) {
241+ if let Some ( args) = jitfunc :: get_jit_args ( self , & func_args, jitted_code, vm) {
257242 return Ok ( jitted_code. invoke ( & args) . into_pyobject ( vm) ) ;
258243 }
259244 }
@@ -285,145 +270,6 @@ impl PyFunction {
285270 pub fn invoke ( & self , func_args : PyFuncArgs , vm : & VirtualMachine ) -> PyResult {
286271 self . invoke_with_scope ( func_args, & self . scope , vm)
287272 }
288-
289- #[ cfg( feature = "jit" ) ]
290- fn get_jit_arg_type ( dict : & PyDictRef , name : & str , vm : & VirtualMachine ) -> PyResult < JitType > {
291- if let Some ( value) = dict. get_item_option ( name, vm) ? {
292- if value. is ( & vm. ctx . types . int_type ) {
293- Ok ( JitType :: Int )
294- } else if value. is ( & vm. ctx . types . float_type ) {
295- Ok ( JitType :: Float )
296- } else {
297- Err ( vm. new_runtime_error (
298- "Jit requires argument to be either int or float" . to_owned ( ) ,
299- ) )
300- }
301- } else {
302- Err ( vm. new_runtime_error ( format ! ( "argument {} needs annotation" , name) ) )
303- }
304- }
305-
306- #[ cfg( feature = "jit" ) ]
307- fn get_jit_arg_types ( zelf : & PyRef < Self > , vm : & VirtualMachine ) -> PyResult < Vec < JitType > > {
308- if zelf
309- . code
310- . flags
311- . intersects ( CodeFlags :: HAS_VARARGS | CodeFlags :: HAS_VARKEYWORDS )
312- {
313- return Err ( vm. new_runtime_error (
314- "Can't jit functions with variable number of arguments" . to_owned ( ) ,
315- ) ) ;
316- }
317-
318- if zelf. code . arg_names . is_empty ( ) && zelf. code . kwonlyarg_names . is_empty ( ) {
319- return Ok ( Vec :: new ( ) ) ;
320- }
321-
322- let annotations = vm. get_attribute ( zelf. clone ( ) . into_object ( ) , "__annotations__" ) ?;
323- if vm. is_none ( & annotations) {
324- Err ( vm. new_runtime_error (
325- "Jitting function requires arguments to have annotations" . to_owned ( ) ,
326- ) )
327- } else if let Ok ( dict) = PyDictRef :: try_from_object ( vm, annotations) {
328- let mut arg_types = Vec :: new ( ) ;
329-
330- for arg in & zelf. code . arg_names {
331- arg_types. push ( Self :: get_jit_arg_type ( & dict, arg, vm) ?) ;
332- }
333-
334- for arg in & zelf. code . kwonlyarg_names {
335- arg_types. push ( Self :: get_jit_arg_type ( & dict, arg, vm) ?) ;
336- }
337-
338- Ok ( arg_types)
339- } else {
340- Err ( vm. new_type_error ( "Function annotations aren't a dict" . to_owned ( ) ) )
341- }
342- }
343-
344- #[ cfg( feature = "jit" ) ]
345- fn get_jit_value ( vm : & VirtualMachine , obj : & PyObjectRef ) -> Option < AbiValue > {
346- // This does exact type checks as subclasses of int/float can't be passed to jitted functions
347- let cls = obj. lease_class ( ) ;
348- if cls. is ( & vm. ctx . types . int_type ) {
349- objint:: get_value ( & obj) . to_i64 ( ) . map ( AbiValue :: Int )
350- } else if cls. is ( & vm. ctx . types . float_type ) {
351- Some ( AbiValue :: Float ( objfloat:: get_value ( & obj) ) )
352- } else {
353- None
354- }
355- }
356-
357- /// Like `fill_locals_from_args` but to populate arguments for calling a jit function.
358- /// This also doesn't do full error handling but instead return None if anything is wrong. In
359- /// that case it falls back to the executing the bytecode version which will call
360- /// `fill_locals_from_args` which will raise the actual exception if needed.
361- #[ cfg( feature = "jit" ) ]
362- fn get_jit_args < ' a > (
363- & self ,
364- func_args : & PyFuncArgs ,
365- jitted_code : & ' a CompiledCode ,
366- vm : & VirtualMachine ,
367- ) -> Option < Args < ' a > > {
368- let mut jit_args = jitted_code. args_builder ( ) ;
369- let nargs = func_args. args . len ( ) ;
370-
371- if nargs > self . code . arg_names . len ( ) || nargs < self . code . posonlyarg_count {
372- return None ;
373- }
374-
375- // Add positional arguments
376- for i in 0 ..nargs {
377- jit_args. set ( i, Self :: get_jit_value ( vm, & func_args. args [ i] ) ?) ;
378- }
379-
380- // Handle keyword arguments
381- for ( name, value) in & func_args. kwargs {
382- if let Some ( arg_idx) = self . code . arg_names . iter ( ) . position ( |arg| arg == name) {
383- if jit_args. is_set ( arg_idx) {
384- return None ;
385- }
386- jit_args. set ( arg_idx, Self :: get_jit_value ( vm, & value) ?) ;
387- } else if let Some ( kwarg_idx) =
388- self . code . kwonlyarg_names . iter ( ) . position ( |arg| arg == name)
389- {
390- let arg_idx = kwarg_idx + self . code . arg_names . len ( ) ;
391- if jit_args. is_set ( arg_idx) {
392- return None ;
393- }
394- jit_args. set ( arg_idx, Self :: get_jit_value ( vm, & value) ?) ;
395- } else {
396- return None ;
397- }
398- }
399-
400- // fill in positional defaults
401- if let Some ( defaults) = & self . defaults {
402- let defaults = defaults. borrow_value ( ) ;
403- for ( i, default) in defaults. iter ( ) . enumerate ( ) {
404- let arg_idx = i + self . code . arg_names . len ( ) - defaults. len ( ) ;
405- if !jit_args. is_set ( arg_idx) {
406- jit_args. set ( arg_idx, Self :: get_jit_value ( vm, default) ?) ;
407- }
408- }
409- }
410-
411- // fill in keyword only defaults
412- if let Some ( kw_only_defaults) = & self . kw_only_defaults {
413- for ( i, name) in self . code . kwonlyarg_names . iter ( ) . enumerate ( ) {
414- let arg_idx = i + self . code . arg_names . len ( ) ;
415- if !jit_args. is_set ( arg_idx) {
416- let default = kw_only_defaults
417- . get_item ( name. as_str ( ) , vm)
418- . ok ( )
419- . and_then ( |obj| Self :: get_jit_value ( vm, & obj) ) ?;
420- jit_args. set ( arg_idx, default) ;
421- }
422- }
423- }
424-
425- jit_args. into_args ( )
426- }
427273}
428274
429275impl PyValue for PyFunction {
@@ -465,7 +311,7 @@ impl PyFunction {
465311 fn jit ( zelf : PyRef < Self > , vm : & VirtualMachine ) -> PyResult < ( ) > {
466312 zelf. jitted_code
467313 . get_or_try_init ( || {
468- let arg_types = PyFunction :: get_jit_arg_types ( & zelf, vm) ?;
314+ let arg_types = jitfunc :: get_jit_arg_types ( & zelf, vm) ?;
469315 rustpython_jit:: compile ( & zelf. code . code , & arg_types)
470316 . map_err ( |err| vm. new_runtime_error ( err. to_string ( ) ) )
471317 } )
0 commit comments