optimize tp_hash

This commit is contained in:
Jeong YunWon committed 2020-09-24 01:55:05 +09:00
1 parent 5e69141884
commit 09ebd19857
4 files changed
+52 -38

No files matched your search

+26 -21
View File
@@ -334,32 +334,37 @@ where
let slot_ident = item_meta.slot_name()?;
let slot_name = slot_ident.to_string();
let tokens = {
let transform = if ["new", "call"].contains(&slot_name.as_str()) {
quote! { ::rustpython_vm::function::IntoPyNativeFunc::into_func }
if slot_name == "new" {
let into_func = quote_spanned! {ident.span() =>
::rustpython_vm::function::IntoPyNativeFunc::into_func(Self::#ident)
};
quote! {
slots.#slot_ident = Some(#into_func);
}
} else if slot_name == "cmp" {
let into_func = quote_spanned! {ident.span() =>
::std::boxed::Box::new(Self::#ident)
};
quote! {
slots.#slot_ident = Some(#into_func);
}
} else {
quote! { ::std::boxed::Box::new }
};
let into_func = quote_spanned! {ident.span() =>
#transform(Self::#ident)
};
match slot_name.as_str() {
"call" => quote! {
slots.#slot_ident.store(Some(
let into_func = if slot_name == "call" {
quote_spanned! {ident.span() =>
|zelf: ::rustpython_vm::pyobject::PyObjectRef, args: ::rustpython_vm::function::PyFuncArgs, vm: &::rustpython_vm::VirtualMachine| -> ::rustpython_vm::pyobject::PyResult {
use ::rustpython_vm::pyobject::TryFromObject;
let zelf = PyRef::<Self>::try_from_object(vm, zelf)?;
Self::#ident(zelf, args, vm)
} as _
));
},
"descr_get" => quote! {
slots.#slot_ident.store(Some(
Self::#ident as _
))
},
_ => quote! {
slots.#slot_ident = Some(#into_func);
},
}
}
} else {
quote_spanned! {ident.span() =>
Self::#ident
}
};
quote! {
slots.#slot_ident.store(Some(#into_func as _))
}
}
};
+1 -1
View File
@@ -702,7 +702,7 @@ pub fn new(
if base.slots.flags.has_feature(PyTpFlags::HAS_DICT) {
slots.flags |= PyTpFlags::HAS_DICT
}
for slot_name in ["__call__", "__get__"].iter() {
for slot_name in ["__call__", "__get__", "__hash__"].iter() {
if attrs.contains_key(*slot_name) {
slots.update_slot_func(*slot_name);
}
+19 -4
View File
@@ -3,9 +3,10 @@ use std::cmp::Ordering;
use crate::common::cell::PyRwLock;
use crate::common::hash::PyHash;
use crate::function::{OptionalArg, PyFuncArgs, PyNativeFunc};
use crate::obj::objint::PyInt;
use crate::pyobject::{
IdProtocol, PyComparisonValue, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
TypeProtocol,
BorrowValue, IdProtocol, PyComparisonValue, PyObjectRef, PyRef, PyResult, PyValue,
TryFromObject, TypeProtocol,
};
use crate::VirtualMachine;
use crossbeam_utils::atomic::AtomicCell;
@@ -44,7 +45,7 @@ impl Default for PyTpFlags {
type GenericMethod = fn(PyObjectRef, PyFuncArgs, &VirtualMachine) -> PyResult;
type DescrGetFunc =
fn(PyObjectRef, Option<PyObjectRef>, Option<PyObjectRef>, &VirtualMachine) -> PyResult;
type HashFunc = Box<py_dyn_fn!(dyn Fn(PyObjectRef, &VirtualMachine) -> PyResult<PyHash>)>;
type HashFunc = fn(PyObjectRef, &VirtualMachine) -> PyResult<PyHash>;
#[derive(Default)]
pub struct PyClassSlots {
@@ -53,7 +54,7 @@ pub struct PyClassSlots {
pub new: Option<PyNativeFunc>,
pub call: AtomicCell<Option<GenericMethod>>,
pub descr_get: AtomicCell<Option<DescrGetFunc>>,
pub hash: Option<HashFunc>,
pub hash: AtomicCell<Option<HashFunc>>,
pub cmp: Option<CmpFunc>,
}
@@ -97,6 +98,20 @@ impl PyClassSlots {
} as _;
self.descr_get.store(Some(func))
}
"__hash__" => {
let func: HashFunc = |zelf, vm| {
let magic = get_class_magic(&zelf, "__hash__");
let hash_obj = vm.invoke(&magic, vec![zelf])?;
match hash_obj.payload_if_subclass::<PyInt>(vm) {
Some(py_int) => {
Ok(rustpython_common::hash::hash_bigint(py_int.borrow_value()))
}
None => Err(vm
.new_type_error("__hash__ method should return an integer".to_owned())),
}
} as _;
self.hash.store(Some(func));
}
_ => (),
}
}
+6 -12
View File
@@ -28,7 +28,7 @@ use crate::import;
use crate::obj::objbool;
use crate::obj::objcode::{PyCode, PyCodeRef};
use crate::obj::objdict::PyDictRef;
use crate::obj::objint::{PyInt, PyIntRef};
use crate::obj::objint::PyIntRef;
use crate::obj::objiter;
use crate::obj::objlist::PyList;
use crate::obj::objmodule::{self, PyModule};
@@ -1453,17 +1453,11 @@ impl VirtualMachine {
}
pub fn _hash(&self, obj: &PyObjectRef) -> PyResult<rustpython_common::hash::PyHash> {
if let Some(ref hash) = obj.lease_class().slots.hash {
hash(obj.clone(), self)
} else {
let hash_obj = self.call_method(obj, "__hash__", vec![])?;
match hash_obj.payload_if_subclass::<PyInt>(self) {
Some(py_int) => Ok(rustpython_common::hash::hash_bigint(py_int.borrow_value())),
None => {
Err(self.new_type_error("__hash__ method should return an integer".to_owned()))
}
}
}
let hash = obj
.class()
.first_in_mro(|cls| cls.slots.hash.load())
.unwrap(); // hash always exist
hash(obj.clone(), self)
}
// https://docs.python.org/3/reference/expressions.html#membership-test-operations