Don't allocate for PyNativeFunc when it's just a fn pointer

This commit is contained in:
Noah committed 2020-04-02 13:57:08 -05:00
1 parent c1c9631798
commit e2d7ab30aa
7 files changed
+40 -14

No files matched your search

Generated
+7
View File
@@ -1645,6 +1645,7 @@ dependencies = [
"sha-1",
"sha2",
"sha3",
"smallbox",
"socket2",
"statrs",
"subprocess",
@@ -1818,6 +1819,12 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
[[package]]
name = "smallbox"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa0eec6425219a55511a35afac416a2eecc62f5fa1bec14f9b97de0caa7daebe"
[[package]]
name = "smallvec"
version = "1.2.0"
+1 -1
View File
@@ -458,7 +458,7 @@ fn extract_impl_items(mut items: Vec<ItemSig>) -> Result<TokenStream2, Diagnosti
let transform = if vec!["new", "call"].contains(&slot_ident.to_string().as_str()) {
quote! { ::rustpython_vm::function::IntoPyNativeFunc::into_func }
} else {
quote! { Box::new }
quote! { ::rustpython_vm::__exports::smallbox! }
};
let into_func = quote_spanned! {item_ident.span()=>
#transform(Self::#item_ident)
+1
View File
@@ -72,6 +72,7 @@ is-macro = "0.1"
result-like = "^0.2.1"
foreign-types = "0.3"
num_enum = "0.4"
smallbox = "0.8"
flame = { version = "0.2", optional = true }
flamer = { version = "0.3", optional = true }
+20 -4
View File
@@ -4,6 +4,7 @@ use std::ops::RangeInclusive;
use indexmap::IndexMap;
use result_like::impl_option_like;
use smallbox::{smallbox, space::S1, SmallBox};
use crate::exceptions::PyBaseExceptionRef;
use crate::obj::objtuple::PyTuple;
@@ -453,8 +454,11 @@ tuple_from_py_func_args!(A, B, C, D);
tuple_from_py_func_args!(A, B, C, D, E);
tuple_from_py_func_args!(A, B, C, D, E, F);
/// A container that can hold a `dyn Fn*` trait object, but doesn't allocate if it's only a fn() pointer
pub type FunctionBox<T> = SmallBox<T, S1>;
/// A built-in Python function.
pub type PyNativeFunc = Box<dyn Fn(&VirtualMachine, PyFuncArgs) -> PyResult + 'static>;
pub type PyNativeFunc = FunctionBox<dyn Fn(&VirtualMachine, PyFuncArgs) -> PyResult + 'static>;
/// Implemented by types that are or can generate built-in functions.
///
@@ -479,7 +483,7 @@ where
F: Fn(&VirtualMachine, PyFuncArgs) -> PyResult + 'static,
{
fn into_func(self) -> PyNativeFunc {
Box::new(self)
smallbox!(self)
}
}
@@ -499,7 +503,7 @@ macro_rules! into_py_native_func_tuple {
R: IntoPyObject,
{
fn into_func(self) -> PyNativeFunc {
Box::new(move |vm, args| {
smallbox!(move |vm: &VirtualMachine, args: PyFuncArgs| {
let ($($n,)*) = args.bind::<($($T,)*)>(vm)?;
(self)($($n,)* vm).into_pyobject(vm)
@@ -515,7 +519,7 @@ macro_rules! into_py_native_func_tuple {
R: IntoPyObject,
{
fn into_func(self) -> PyNativeFunc {
Box::new(move |vm, args| {
smallbox!(move |vm: &VirtualMachine, args: PyFuncArgs| {
let (zelf, $($n,)*) = args.bind::<(PyRef<S>, $($T,)*)>(vm)?;
(self)(&zelf, $($n,)* vm).into_pyobject(vm)
@@ -597,3 +601,15 @@ pub fn single_or_tuple_any<T: PyValue, F: Fn(PyRef<T>) -> PyResult<bool>>(
};
checker.check(obj)
}
#[cfg(test)]
mod tests {
#[test]
fn test_functionbox_noalloc() {
fn py_func(_b: bool, _vm: &crate::VirtualMachine) -> i32 {
1
}
let f = super::IntoPyNativeFunc::into_func(py_func);
assert!(!f.is_heap());
}
}
+1
View File
@@ -88,4 +88,5 @@ pub use rustpython_bytecode::*;
#[doc(hidden)]
pub mod __exports {
pub use maplit::hashmap;
pub use smallbox::smallbox;
}
+8 -7
View File
@@ -2,7 +2,7 @@
*/
use super::objtype::PyClassRef;
use crate::function::{OptionalArg, OwnedParam, RefParam};
use crate::function::{FunctionBox, OptionalArg, OwnedParam, RefParam};
use crate::pyobject::{
IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
TypeProtocol,
@@ -10,8 +10,9 @@ use crate::pyobject::{
use crate::slots::SlotDescriptor;
use crate::vm::VirtualMachine;
pub type PyGetterFunc = Box<dyn Fn(&VirtualMachine, PyObjectRef) -> PyResult>;
pub type PySetterFunc = Box<dyn Fn(&VirtualMachine, PyObjectRef, PyObjectRef) -> PyResult<()>>;
pub type PyGetterFunc = FunctionBox<dyn Fn(&VirtualMachine, PyObjectRef) -> PyResult>;
pub type PySetterFunc =
FunctionBox<dyn Fn(&VirtualMachine, PyObjectRef, PyObjectRef) -> PyResult<()>>;
pub trait IntoPyGetterFunc<T> {
fn into_getter(self) -> PyGetterFunc;
@@ -24,7 +25,7 @@ where
R: IntoPyObject,
{
fn into_getter(self) -> PyGetterFunc {
Box::new(move |vm, obj| {
smallbox::smallbox!(move |vm: &VirtualMachine, obj| {
let obj = T::try_from_object(vm, obj)?;
(self)(obj, vm).into_pyobject(vm)
})
@@ -38,7 +39,7 @@ where
R: IntoPyObject,
{
fn into_getter(self) -> PyGetterFunc {
Box::new(move |vm, obj| {
smallbox::smallbox!(move |vm: &VirtualMachine, obj| {
let zelf = PyRef::<S>::try_from_object(vm, obj)?;
(self)(&zelf, vm).into_pyobject(vm)
})
@@ -95,7 +96,7 @@ where
R: IntoPyNoResult,
{
fn into_setter(self) -> PySetterFunc {
Box::new(move |vm, obj, value| {
smallbox::smallbox!(move |vm: &VirtualMachine, obj, value| {
let obj = T::try_from_object(vm, obj)?;
let value = V::try_from_object(vm, value)?;
(self)(obj, value, vm).into_noresult()
@@ -111,7 +112,7 @@ where
R: IntoPyNoResult,
{
fn into_setter(self) -> PySetterFunc {
Box::new(move |vm, obj, value| {
smallbox::smallbox!(move |vm: &VirtualMachine, obj, value| {
let zelf = PyRef::<S>::try_from_object(vm, obj)?;
let value = V::try_from_object(vm, value)?;
(self)(&zelf, value, vm).into_noresult()
+2 -2
View File
@@ -1,4 +1,4 @@
use crate::function::{OptionalArg, PyFuncArgs, PyNativeFunc};
use crate::function::{FunctionBox, OptionalArg, PyFuncArgs, PyNativeFunc};
use crate::pyobject::{IdProtocol, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject};
use crate::VirtualMachine;
@@ -44,7 +44,7 @@ pub trait SlotCall: PyValue {
fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult;
}
pub type PyDescrGetFunc = Box<
pub type PyDescrGetFunc = FunctionBox<
dyn Fn(&VirtualMachine, PyObjectRef, Option<PyObjectRef>, OptionalArg<PyObjectRef>) -> PyResult,
>;