Move jit specific functions out of objfunction.rs into a sub module j… · RustPython/RustPython@588facf · GitHub
Skip to content

Commit 588facf

Browse files
committed
Move jit specific functions out of objfunction.rs into a sub module jitfunc.
1 parent 3151d89 commit 588facf

3 files changed

Lines changed: 163 additions & 166 deletions

File tree

jit/src/instructions.rs

Lines changed: 1 addition & 4 deletions

vm/src/obj/objfunction.rs

Lines changed: 8 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1+
#[cfg(feature = "jit")]
2+
mod jitfunc;
3+
14
use super::objcode::PyCodeRef;
25
use super::objdict::PyDictRef;
3-
#[cfg(feature = "jit")]
4-
use super::objfloat;
5-
#[cfg(feature = "jit")]
6-
use super::objint;
76
use super::objstr::PyStringRef;
87
use super::objtuple::PyTupleRef;
98
use super::objtype::PyClassRef;
@@ -13,34 +12,20 @@ use crate::function::{OptionalArg, PyFuncArgs};
1312
use crate::obj::objasyncgenerator::PyAsyncGen;
1413
use crate::obj::objcoroutine::PyCoroutine;
1514
use crate::obj::objgenerator::PyGenerator;
15+
#[cfg(feature = "jit")]
16+
use crate::pyobject::IntoPyObject;
1617
use 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};
2221
use crate::scope::Scope;
2322
use crate::slots::{SlotCall, SlotDescriptor};
2423
use crate::VirtualMachine;
2524
use 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")]
3126
use 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

4530
pub 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

429275
impl 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
})

vm/src/obj/objfunction/jitfunc.rs

Lines changed: 154 additions & 0 deletions

0 commit comments

Comments
 (0)