mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
optimize descr_get
This commit is contained in:
@@ -342,20 +342,22 @@ where
|
||||
let into_func = quote_spanned! {ident.span() =>
|
||||
#transform(Self::#ident)
|
||||
};
|
||||
if slot_name == "call" {
|
||||
quote! {
|
||||
slots.#slot_ident.store(
|
||||
Some(
|
||||
|vm: &::rustpython_vm::VirtualMachine, args: ::rustpython_vm::function::PyFuncArgs| -> ::rustpython_vm::pyobject::PyResult {
|
||||
::rustpython_vm::function::IntoPyNativeFunc::call(&Self::#ident, vm, args)
|
||||
} as _
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
match slot_name.as_str() {
|
||||
"call" => quote! {
|
||||
slots.#slot_ident.store(Some(
|
||||
|vm: &::rustpython_vm::VirtualMachine, args: ::rustpython_vm::function::PyFuncArgs| -> ::rustpython_vm::pyobject::PyResult {
|
||||
::rustpython_vm::function::IntoPyNativeFunc::call(&Self::#ident, vm, args)
|
||||
} as _
|
||||
));
|
||||
},
|
||||
"descr_get" => quote! {
|
||||
slots.#slot_ident.store(Some(
|
||||
Self::#ident as _
|
||||
))
|
||||
},
|
||||
_ => quote! {
|
||||
slots.#slot_ident = Some(#into_func);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -9,3 +9,10 @@ class Callable():
|
||||
c = Callable()
|
||||
assert 1 == c()
|
||||
assert 2 == c()
|
||||
|
||||
class Inherited(Callable):
|
||||
pass
|
||||
|
||||
i = Inherited()
|
||||
|
||||
assert 1 == i()
|
||||
|
||||
@@ -210,24 +210,25 @@ impl PyClass {
|
||||
if let Some(attr) = mcl.get_attr(&name) {
|
||||
let attr_class = attr.lease_class();
|
||||
if attr_class.has_attr("__set__") {
|
||||
if let Some(ref descriptor) = attr_class.get_attr("__get__") {
|
||||
drop(attr_class);
|
||||
if let Some(ref descr_get) =
|
||||
PyLease::into_pyref(attr_class).first_in_mro(|cls| cls.slots.descr_get.load())
|
||||
{
|
||||
let mcl = PyLease::into_pyref(mcl).into_object();
|
||||
return vm.invoke(descriptor, vec![attr, zelf.into_object(), mcl]);
|
||||
return descr_get(
|
||||
vm,
|
||||
attr,
|
||||
Some(zelf.into_object()),
|
||||
OptionalArg::Present(mcl),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(attr) = zelf.get_attr(&name) {
|
||||
let attr_class = attr.class();
|
||||
let slots = &attr_class.slots;
|
||||
if let Some(ref descr_get) = slots.descr_get {
|
||||
if let Some(ref descr_get) = attr_class.first_in_mro(|cls| cls.slots.descr_get.load()) {
|
||||
drop(mcl);
|
||||
return descr_get(vm, attr, None, OptionalArg::Present(zelf.into_object()));
|
||||
} else if let Some(ref descriptor) = attr_class.get_attr("__get__") {
|
||||
drop(mcl);
|
||||
// TODO: is this nessessary?
|
||||
return vm.invoke(descriptor, vec![attr, vm.ctx.none(), zelf.into_object()]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -706,11 +707,12 @@ pub fn new(
|
||||
if base.slots.flags.has_feature(PyTpFlags::HAS_DICT) {
|
||||
slots.flags |= PyTpFlags::HAS_DICT
|
||||
}
|
||||
for slot_name in ["__call__"].iter() {
|
||||
for slot_name in ["__call__", "__get__"].iter() {
|
||||
if attrs.contains_key(*slot_name) {
|
||||
slots.update_slot_func(*slot_name);
|
||||
}
|
||||
}
|
||||
|
||||
let new_type = PyRef::new_ref(
|
||||
PyClass {
|
||||
name: String::from(name),
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::common::hash::PyHash;
|
||||
use crate::function::{IntoPyNativeFunc, OptionalArg, PyFuncArgs, PyNativeFunc};
|
||||
use crate::pyobject::{
|
||||
IdProtocol, PyComparisonValue, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
|
||||
TypeProtocol,
|
||||
};
|
||||
use crate::VirtualMachine;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
@@ -40,18 +41,22 @@ impl Default for PyTpFlags {
|
||||
}
|
||||
}
|
||||
|
||||
type GenericFunc = fn(&VirtualMachine, PyFuncArgs) -> PyResult;
|
||||
type DescrGetFunc =
|
||||
fn(&VirtualMachine, PyObjectRef, Option<PyObjectRef>, OptionalArg<PyObjectRef>) -> PyResult;
|
||||
type HashFunc = Box<py_dyn_fn!(dyn Fn(PyObjectRef, &VirtualMachine) -> PyResult<PyHash>)>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PyClassSlots {
|
||||
pub flags: PyTpFlags,
|
||||
pub name: PyRwLock<Option<String>>, // tp_name, not class name
|
||||
pub new: Option<PyNativeFunc>,
|
||||
pub call: AtomicCell<Option<fn(&VirtualMachine, PyFuncArgs) -> PyResult>>,
|
||||
pub descr_get: Option<PyDescrGetFunc>,
|
||||
pub call: AtomicCell<Option<GenericFunc>>,
|
||||
pub descr_get: AtomicCell<Option<DescrGetFunc>>,
|
||||
pub hash: Option<HashFunc>,
|
||||
pub cmp: Option<CmpFunc>,
|
||||
}
|
||||
|
||||
type HashFunc = Box<py_dyn_fn!(dyn Fn(PyObjectRef, &VirtualMachine) -> PyResult<PyHash>)>;
|
||||
type CmpFunc = Box<
|
||||
py_dyn_fn!(
|
||||
dyn Fn(
|
||||
@@ -75,10 +80,14 @@ impl PyClassSlots {
|
||||
pub(crate) fn update_slot_func(&self, name: &str) {
|
||||
match name {
|
||||
"__call__" => {
|
||||
self.call
|
||||
.store(Some(|vm: &VirtualMachine, args: PyFuncArgs| -> PyResult {
|
||||
IntoPyNativeFunc::call(&call_magic_call, vm, args)
|
||||
} as _))
|
||||
let func: GenericFunc =
|
||||
|vm, args| { IntoPyNativeFunc::call(&call_magic_call, vm, args) } as _;
|
||||
self.call.store(Some(func))
|
||||
}
|
||||
"__get__" => {
|
||||
let func: DescrGetFunc =
|
||||
|vm, zelf, obj, cls| { call_magic_descr_get(vm, zelf, obj, cls) } as _;
|
||||
self.descr_get.store(Some(func))
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
@@ -98,17 +107,37 @@ pub trait SlotCall: PyValue {
|
||||
fn call(zelf: PyRef<Self>, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_class_magic(zelf: &PyObjectRef, name: &str) -> PyObjectRef {
|
||||
zelf.get_class_attr(name).unwrap()
|
||||
// let cls = zelf.lease_class();
|
||||
// let attrs = cls.attributes.read();
|
||||
// let attr = attrs.get(name);
|
||||
// attr.unwrap().clone()
|
||||
}
|
||||
|
||||
fn call_magic_call(zelf: PyObjectRef, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
use crate::obj::objstr::PyString;
|
||||
use crate::pyobject::IntoPyRef;
|
||||
let magic = get_class_magic(&zelf, "__call__");
|
||||
let magic = vm.call_if_get_descriptor(magic, zelf.clone())?;
|
||||
args.insert(zelf);
|
||||
vm.invoke(&magic, args)
|
||||
}
|
||||
|
||||
let magic_call = vm.generic_getattribute(zelf, PyString::from("__call__").into_pyref(vm))?;
|
||||
vm.invoke(&magic_call, args)
|
||||
|
||||
// use crate::pyobject::TypeProtocol;
|
||||
// let magic_call = zelf.get_class_attr("__call__").unwrap();
|
||||
// args.insert( zelf);
|
||||
// vm.invoke(&magic_call, args)
|
||||
fn call_magic_descr_get(
|
||||
vm: &VirtualMachine,
|
||||
zelf: PyObjectRef,
|
||||
obj: Option<PyObjectRef>,
|
||||
cls: OptionalArg<PyObjectRef>,
|
||||
) -> PyResult {
|
||||
let magic = get_class_magic(&zelf, "__get__");
|
||||
vm.invoke(
|
||||
&magic,
|
||||
vec![
|
||||
zelf,
|
||||
vm.unwrap_or_none(obj),
|
||||
vm.unwrap_or_none(cls.into_option()),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
pub type PyDescrGetFunc = Box<
|
||||
|
||||
16
vm/src/vm.rs
16
vm/src/vm.rs
@@ -841,18 +841,10 @@ impl VirtualMachine {
|
||||
obj: Option<PyObjectRef>,
|
||||
cls: Option<PyObjectRef>,
|
||||
) -> Option<PyResult> {
|
||||
let descr_class = descr.class();
|
||||
let slots = &descr_class.slots;
|
||||
if let Some(descr_get) = slots.descr_get.as_ref() {
|
||||
Some(descr_get(self, descr, obj, OptionalArg::from_option(cls)))
|
||||
} else if let Some(ref descriptor) = descr_class.get_attr("__get__") {
|
||||
Some(self.invoke(
|
||||
descriptor,
|
||||
vec![descr, self.unwrap_or_none(obj), self.unwrap_or_none(cls)],
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
descr
|
||||
.class()
|
||||
.first_in_mro(|cls| cls.slots.descr_get.load())
|
||||
.map(|descr_get| descr_get(self, descr, obj, OptionalArg::from_option(cls)))
|
||||
}
|
||||
|
||||
pub fn call_get_descriptor(&self, descr: PyObjectRef, obj: PyObjectRef) -> Option<PyResult> {
|
||||
|
||||
Reference in New Issue
Block a user