Support arguments in jitted functions#2164
Conversation
| self.values, | ||
| ) | ||
| }; | ||
| let cif_args = values.iter().map(|v| libffi::middle::Arg::new(v)).collect(); |
There was a problem hiding this comment.
If you're going to recollect the vec anyway, you may as well just v.assume_init() in the mapping function and avoid the transmute.
There was a problem hiding this comment.
I can't use assume_init as I need the reference into the values vector, cif_args is effectively a vector of pointers that are passed to libffi. This would be nicer if we had either rust-lang/rust#63291 or rust-lang/rust#63568.
| #[cfg(feature = "jit")] | ||
| use super::objfloat; | ||
| #[cfg(feature = "jit")] | ||
| use super::objint; |
There was a problem hiding this comment.
nit; you could condense this into one #[cfg jit] use super::{objint, objfloat}
| .get_or_try_init(|| { | ||
| rustpython_jit::compile(&self.code.code) | ||
| let arg_types = PyFunction::get_jit_arg_types(&zelf, vm)?; | ||
| rustpython_jit::compile(&zelf.code.code, &arg_types) |
There was a problem hiding this comment.
This is a lot of code in objfunction, maybe there could be a submodule obj/objfunction/jitfunc.rs or something to store all the logic for py<->jit conversion?
| )) | ||
| } | ||
| } else { | ||
| Err(vm.new_runtime_error(format!("argument {} needs annotation", name))) |
| } | ||
| } | ||
|
|
||
| #[derive(Copy, Clone, PartialEq)] |
There was a problem hiding this comment.
The reason I didn't make this Copy is because I was thinking of eventually having composite types, like List(Box<JitType>) or Tuple(Vec<JitType>) or maybe some sort of product or sum type.
| impl<'a> ArgsBuilder<'a> { | ||
| fn new(code: &'a CompiledCode) -> ArgsBuilder<'a> { | ||
| ArgsBuilder { | ||
| values: vec![MaybeUninit::uninit(); code.sig.args.len()], |
There was a problem hiding this comment.
Couldn't this be Vec<Option<UntypedAbiArg>>? and you could like do self.values.iter().map(|val| val.as_ref().map(|val| middle::Abi::new(val)).collect::<Option<_>>()
And you could just store the Vec<Option<>> in the Args struct, since it just matters that it's not dropped
9a15a26 to
bd3c4fc
Compare
|
An example like the following can cause UB, where the function is given incorrect input: def add_two(a: int, b: int) -> int:
return a + b
add_two.__jit__()
result = add_two(2, 3.0) # cpython would return 5.0 as a floatHere, I give a function that should take an I was wondering if we're okay with this sort of undefined behaviour when incorrect input is given to jitted functions? If not, we could either
I'm not sure if |
Another option is to use some sort of multiple dispatch, as Julia does. Which also implies introducing some sort of type inference system and other complex things... Perhaps it would be easier to just throw an error for now, and eventually introduce more complicated machinery. |
|
I think ideally we're trying to make a jitted function transparent -- it should be no different in behavior from a non-jitted function, and it shouldn't error because of a jit limitation (e.g. i64 ints instead of BigInts). So yeah, I think we should definitely type-check and then fall back to non-jit behavior to either error or get whatever dynamic behavior would happen with that. |
|
Doing something similar to Julia's multiple dispatch definitely sounds cool though -- with def add(a, b):
return a + bWe could have like a hashmap of |
|
@ArniDagur Good catch, this PR did previously do a runtime check of the arguments types, and if it didn't match it would fallback to interpreting the bytecode instead, but a subsequent refactoring broke that. @darleybarreto @coolreader18 I'm not familiar with Julia at all, but does sound like an interesting approach. |
|
By looking PyPy practice, it make guards with typecheck and falling back to original code when the jit assumption failed. |
To jit functions that have arguments, the type of the arguments needs to be known when it's compiled. this PR uses the annotations to determine the type of the arguments.