From 0ebd4e0719796e9a8ea5a012d5e18cbfdaa6d876 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Thu, 23 Jun 2022 21:55:42 +0200 Subject: [PATCH 01/11] refactor number methods as atomic function --- vm/src/builtins/float.rs | 62 +++++++--- vm/src/builtins/int.rs | 72 +++++++---- vm/src/protocol/number.rs | 243 +++++++++++++++++--------------------- 3 files changed, 200 insertions(+), 177 deletions(-) diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index 9758f56dc..d006688dc 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -16,6 +16,7 @@ use crate::{ AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject, TryFromObject, VirtualMachine, }; +use crossbeam_utils::atomic::AtomicCell; use num_bigint::{BigInt, ToBigInt}; use num_complex::Complex64; use num_rational::Ratio; @@ -552,34 +553,57 @@ impl Hashable for PyFloat { } } +macro_rules! atomic_func { + ($x:expr) => { + AtomicCell::new(Some($x)) + }; +} + impl AsNumber for PyFloat { const AS_NUMBER: PyNumberMethods = PyNumberMethods { - add: Some(|number, other, vm| Self::number_float_op(number, other, |a, b| a + b, vm)), - subtract: Some(|number, other, vm| Self::number_float_op(number, other, |a, b| a - b, vm)), - multiply: Some(|number, other, vm| Self::number_float_op(number, other, |a, b| a * b, vm)), - remainder: Some(|number, other, vm| Self::number_general_op(number, other, inner_mod, vm)), - divmod: Some(|number, other, vm| Self::number_general_op(number, other, inner_divmod, vm)), - power: Some(|number, other, vm| Self::number_general_op(number, other, float_pow, vm)), - negative: Some(|number, vm| { - let value = Self::number_downcast(number).value; + add: atomic_func!(|num, other, vm| Self::number_float_op(num, other, |a, b| a + b, vm)), + subtract: atomic_func!(|num, other, vm| Self::number_float_op( + num, + other, + |a, b| a - b, + vm + )), + multiply: atomic_func!(|num, other, vm| Self::number_float_op( + num, + other, + |a, b| a * b, + vm + )), + remainder: atomic_func!(|num, other, vm| Self::number_general_op( + num, other, inner_mod, vm + )), + divmod: atomic_func!(|num, other, vm| Self::number_general_op( + num, + other, + inner_divmod, + vm + )), + power: atomic_func!(|num, other, vm| Self::number_general_op(num, other, float_pow, vm)), + negative: atomic_func!(|num, vm| { + let value = Self::number_downcast(num).value; (-value).to_pyresult(vm) }), - positive: Some(|number, vm| Self::number_float(number, vm).to_pyresult(vm)), - absolute: Some(|number, vm| { - let value = Self::number_downcast(number).value; + positive: atomic_func!(|num, vm| Self::number_float(num, vm).to_pyresult(vm)), + absolute: atomic_func!(|num, vm| { + let value = Self::number_downcast(num).value; value.abs().to_pyresult(vm) }), - boolean: Some(|number, _vm| Ok(Self::number_downcast(number).value.is_zero())), - int: Some(|number, vm| { - let value = Self::number_downcast(number).value; + boolean: atomic_func!(|num, _vm| Ok(Self::number_downcast(num).value.is_zero())), + int: atomic_func!(|num, vm| { + let value = Self::number_downcast(num).value; try_to_bigint(value, vm).map(|x| vm.ctx.new_int(x)) }), - float: Some(|number, vm| Ok(Self::number_float(number, vm))), - floor_divide: Some(|number, other, vm| { - Self::number_general_op(number, other, inner_floordiv, vm) + float: atomic_func!(|num, vm| Ok(Self::number_float(num, vm))), + floor_divide: atomic_func!(|num, other, vm| { + Self::number_general_op(num, other, inner_floordiv, vm) }), - true_divide: Some(|number, other, vm| { - Self::number_general_op(number, other, inner_div, vm) + true_divide: atomic_func!(|num, other, vm| { + Self::number_general_op(num, other, inner_div, vm) }), ..PyNumberMethods::NOT_IMPLEMENTED }; diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 3d64af457..dc8695f3d 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -15,6 +15,7 @@ use crate::{ TryFromBorrowedObject, VirtualMachine, }; use bstr::ByteSlice; +use crossbeam_utils::atomic::AtomicCell; use num_bigint::{BigInt, BigUint, Sign}; use num_integer::Integer; use num_traits::{One, Pow, PrimInt, Signed, ToPrimitive, Zero}; @@ -755,36 +756,59 @@ impl Hashable for PyInt { } } +macro_rules! atomic_func { + ($x:expr) => { + AtomicCell::new(Some($x)) + }; +} + impl AsNumber for PyInt { const AS_NUMBER: PyNumberMethods = PyNumberMethods { - add: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a + b, vm)), - subtract: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a - b, vm)), - multiply: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a * b, vm)), - remainder: Some(|number, other, vm| Self::number_general_op(number, other, inner_mod, vm)), - divmod: Some(|number, other, vm| Self::number_general_op(number, other, inner_divmod, vm)), - power: Some(|number, other, vm| Self::number_general_op(number, other, inner_pow, vm)), - negative: Some(|number, vm| (&Self::number_downcast(number).value).neg().to_pyresult(vm)), - positive: Some(|number, vm| Ok(Self::number_int(number, vm).into())), - absolute: Some(|number, vm| Self::number_downcast(number).value.abs().to_pyresult(vm)), - boolean: Some(|number, _vm| Ok(Self::number_downcast(number).value.is_zero())), - invert: Some(|number, vm| (&Self::number_downcast(number).value).not().to_pyresult(vm)), - lshift: Some(|number, other, vm| Self::number_general_op(number, other, inner_lshift, vm)), - rshift: Some(|number, other, vm| Self::number_general_op(number, other, inner_rshift, vm)), - and: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a & b, vm)), - xor: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a ^ b, vm)), - or: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a | b, vm)), - int: Some(|number, other| Ok(Self::number_int(number, other))), - float: Some(|number, vm| { - let zelf = Self::number_downcast(number); + add: atomic_func!(|num, other, vm| Self::number_int_op(num, other, |a, b| a + b, vm)), + subtract: atomic_func!(|num, other, vm| Self::number_int_op(num, other, |a, b| a - b, vm)), + multiply: atomic_func!(|num, other, vm| Self::number_int_op(num, other, |a, b| a * b, vm)), + remainder: atomic_func!(|num, other, vm| Self::number_general_op( + num, other, inner_mod, vm + )), + divmod: atomic_func!(|num, other, vm| Self::number_general_op( + num, + other, + inner_divmod, + vm + )), + power: atomic_func!(|num, other, vm| Self::number_general_op(num, other, inner_pow, vm)), + negative: atomic_func!(|num, vm| (&Self::number_downcast(num).value).neg().to_pyresult(vm)), + positive: atomic_func!(|num, vm| Ok(Self::number_int(num, vm).into())), + absolute: atomic_func!(|num, vm| Self::number_downcast(num).value.abs().to_pyresult(vm)), + boolean: atomic_func!(|num, _vm| Ok(Self::number_downcast(num).value.is_zero())), + invert: atomic_func!(|num, vm| (&Self::number_downcast(num).value).not().to_pyresult(vm)), + lshift: atomic_func!(|num, other, vm| Self::number_general_op( + num, + other, + inner_lshift, + vm + )), + rshift: atomic_func!(|num, other, vm| Self::number_general_op( + num, + other, + inner_rshift, + vm + )), + and: atomic_func!(|num, other, vm| Self::number_int_op(num, other, |a, b| a & b, vm)), + xor: atomic_func!(|num, other, vm| Self::number_int_op(num, other, |a, b| a ^ b, vm)), + or: atomic_func!(|num, other, vm| Self::number_int_op(num, other, |a, b| a | b, vm)), + int: atomic_func!(|num, other| Ok(Self::number_int(num, other))), + float: atomic_func!(|num, vm| { + let zelf = Self::number_downcast(num); try_to_float(&zelf.value, vm).map(|x| vm.ctx.new_float(x)) }), - floor_divide: Some(|number, other, vm| { - Self::number_general_op(number, other, inner_floordiv, vm) + floor_divide: atomic_func!(|num, other, vm| { + Self::number_general_op(num, other, inner_floordiv, vm) }), - true_divide: Some(|number, other, vm| { - Self::number_general_op(number, other, inner_truediv, vm) + true_divide: atomic_func!(|num, other, vm| { + Self::number_general_op(num, other, inner_truediv, vm) }), - index: Some(|number, vm| Ok(Self::number_int(number, vm))), + index: atomic_func!(|num, vm| Ok(Self::number_int(num, vm))), ..PyNumberMethods::NOT_IMPLEMENTED }; } diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index e8f1e9041..944126f54 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -1,148 +1,123 @@ +use crossbeam_utils::atomic::AtomicCell; + use crate::{ builtins::{int, PyByteArray, PyBytes, PyComplex, PyFloat, PyInt, PyIntRef, PyStr}, function::ArgBytesLike, stdlib::warnings, - AsObject, PyObject, PyPayload, PyRef, PyResult, TryFromBorrowedObject, VirtualMachine, + AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject, + VirtualMachine, }; -#[allow(clippy::type_complexity)] -#[derive(Clone)] +type UnaryFunc = AtomicCell PyResult>>; +type BinaryFunc = + AtomicCell PyResult>>; + pub struct PyNumberMethods { /* Number implementations must check *both* arguments for proper type and implement the necessary conversions in the slot functions themselves. */ - pub add: Option PyResult>, - pub subtract: Option PyResult>, - pub multiply: Option PyResult>, - pub remainder: Option PyResult>, - pub divmod: Option PyResult>, - pub power: Option PyResult>, - pub negative: Option PyResult>, - pub positive: Option PyResult>, - pub absolute: Option PyResult>, - pub boolean: Option PyResult>, - pub invert: Option PyResult>, - pub lshift: Option PyResult>, - pub rshift: Option PyResult>, - pub and: Option PyResult>, - pub xor: Option PyResult>, - pub or: Option PyResult>, - pub int: Option PyResult>, - pub float: Option PyResult>>, + pub add: BinaryFunc, + pub subtract: BinaryFunc, + pub multiply: BinaryFunc, + pub remainder: BinaryFunc, + pub divmod: BinaryFunc, + pub power: BinaryFunc, + pub negative: UnaryFunc, + pub positive: UnaryFunc, + pub absolute: UnaryFunc, + pub boolean: UnaryFunc, + pub invert: UnaryFunc, + pub lshift: BinaryFunc, + pub rshift: BinaryFunc, + pub and: BinaryFunc, + pub xor: BinaryFunc, + pub or: BinaryFunc, + pub int: UnaryFunc>, + pub float: UnaryFunc>, - pub inplace_add: Option PyResult>, - pub inplace_subtract: Option PyResult>, - pub inplace_multiply: Option PyResult>, - pub inplace_remainder: Option PyResult>, - pub inplace_divmod: Option PyResult>, - pub inplace_power: Option PyResult>, - pub inplace_lshift: Option PyResult>, - pub inplace_rshift: Option PyResult>, - pub inplace_and: Option PyResult>, - pub inplace_xor: Option PyResult>, - pub inplace_or: Option PyResult>, + pub inplace_add: BinaryFunc, + pub inplace_subtract: BinaryFunc, + pub inplace_multiply: BinaryFunc, + pub inplace_remainder: BinaryFunc, + pub inplace_divmod: BinaryFunc, + pub inplace_power: BinaryFunc, + pub inplace_lshift: BinaryFunc, + pub inplace_rshift: BinaryFunc, + pub inplace_and: BinaryFunc, + pub inplace_xor: BinaryFunc, + pub inplace_or: BinaryFunc, - pub floor_divide: Option PyResult>, - pub true_divide: Option PyResult>, - pub inplace_floor_divide: Option PyResult>, - pub inplace_true_divide: Option PyResult>, + pub floor_divide: BinaryFunc, + pub true_divide: BinaryFunc, + pub inplace_floor_divide: BinaryFunc, + pub inplace_true_divide: BinaryFunc, - pub index: Option PyResult>, + pub index: UnaryFunc>, - pub matrix_multiply: Option PyResult>, - pub inplace_matrix_multiply: Option PyResult>, + pub matrix_multiply: BinaryFunc, + pub inplace_matrix_multiply: BinaryFunc, } impl PyNumberMethods { pub const NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods { - add: None, - subtract: None, - multiply: None, - remainder: None, - divmod: None, - power: None, - negative: None, - positive: None, - absolute: None, - boolean: None, - invert: None, - lshift: None, - rshift: None, - and: None, - xor: None, - or: None, - int: None, - float: None, - inplace_add: None, - inplace_subtract: None, - inplace_multiply: None, - inplace_remainder: None, - inplace_divmod: None, - inplace_power: None, - inplace_lshift: None, - inplace_rshift: None, - inplace_and: None, - inplace_xor: None, - inplace_or: None, - floor_divide: None, - true_divide: None, - inplace_floor_divide: None, - inplace_true_divide: None, - index: None, - matrix_multiply: None, - inplace_matrix_multiply: None, + add: AtomicCell::new(None), + subtract: AtomicCell::new(None), + multiply: AtomicCell::new(None), + remainder: AtomicCell::new(None), + divmod: AtomicCell::new(None), + power: AtomicCell::new(None), + negative: AtomicCell::new(None), + positive: AtomicCell::new(None), + absolute: AtomicCell::new(None), + boolean: AtomicCell::new(None), + invert: AtomicCell::new(None), + lshift: AtomicCell::new(None), + rshift: AtomicCell::new(None), + and: AtomicCell::new(None), + xor: AtomicCell::new(None), + or: AtomicCell::new(None), + int: AtomicCell::new(None), + float: AtomicCell::new(None), + inplace_add: AtomicCell::new(None), + inplace_subtract: AtomicCell::new(None), + inplace_multiply: AtomicCell::new(None), + inplace_remainder: AtomicCell::new(None), + inplace_divmod: AtomicCell::new(None), + inplace_power: AtomicCell::new(None), + inplace_lshift: AtomicCell::new(None), + inplace_rshift: AtomicCell::new(None), + inplace_and: AtomicCell::new(None), + inplace_xor: AtomicCell::new(None), + inplace_or: AtomicCell::new(None), + floor_divide: AtomicCell::new(None), + true_divide: AtomicCell::new(None), + inplace_floor_divide: AtomicCell::new(None), + inplace_true_divide: AtomicCell::new(None), + index: AtomicCell::new(None), + matrix_multiply: AtomicCell::new(None), + inplace_matrix_multiply: AtomicCell::new(None), }; - pub(crate) fn generic( - has_int: bool, - has_float: bool, - has_index: bool, - ) -> &'static PyNumberMethods { - static METHODS: &[PyNumberMethods] = &[ - new_generic(false, false, false), - new_generic(true, false, false), - new_generic(false, true, false), - new_generic(true, true, false), - new_generic(false, false, true), - new_generic(true, false, true), - new_generic(false, true, true), - new_generic(true, true, true), - ]; - - fn int(num: &PyNumber, vm: &VirtualMachine) -> PyResult> { - let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __int__), ())?; - ret.downcast::().map_err(|obj| { - vm.new_type_error(format!("__int__ returned non-int (type {})", obj.class())) - }) - } - fn float(num: &PyNumber, vm: &VirtualMachine) -> PyResult> { - let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __float__), ())?; - ret.downcast::().map_err(|obj| { - vm.new_type_error(format!( - "__float__ returned non-float (type {})", - obj.class() - )) - }) - } - fn index(num: &PyNumber, vm: &VirtualMachine) -> PyResult> { - let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __index__), ())?; - ret.downcast::().map_err(|obj| { - vm.new_type_error(format!("__index__ returned non-int (type {})", obj.class())) - }) - } - - const fn new_generic(has_int: bool, has_float: bool, has_index: bool) -> PyNumberMethods { - PyNumberMethods { - int: if has_int { Some(int) } else { None }, - float: if has_float { Some(float) } else { None }, - index: if has_index { Some(index) } else { None }, - ..PyNumberMethods::NOT_IMPLEMENTED - } - } - - let key = (has_int as usize) | ((has_float as usize) << 1) | ((has_index as usize) << 2); - - &METHODS[key] + fn int(num: &PyNumber, vm: &VirtualMachine) -> PyResult> { + let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __int__), ())?; + ret.downcast::().map_err(|obj| { + vm.new_type_error(format!("__int__ returned non-int (type {})", obj.class())) + }) + } + fn float(num: &PyNumber, vm: &VirtualMachine) -> PyResult> { + let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __float__), ())?; + ret.downcast::().map_err(|obj| { + vm.new_type_error(format!( + "__float__ returned non-float (type {})", + obj.class() + )) + }) + } + fn index(num: &PyNumber, vm: &VirtualMachine) -> PyResult> { + let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __index__), ())?; + ret.downcast::().map_err(|obj| { + vm.new_type_error(format!("__index__ returned non-int (type {})", obj.class())) + }) } } @@ -174,16 +149,16 @@ impl PyNumber<'_> { // PyNumber_Check pub fn check(obj: &PyObject, vm: &VirtualMachine) -> bool { Self::find_methods(obj, vm).map_or(false, |methods| { - methods.int.is_some() - || methods.index.is_some() - || methods.float.is_some() + methods.int.load().is_some() + || methods.index.load().is_some() + || methods.float.load().is_some() || obj.payload_is::() }) } // PyIndex_Check pub fn is_index(&self) -> bool { - self.methods().index.is_some() + self.methods().index.load().is_some() } pub fn int(&self, vm: &VirtualMachine) -> PyResult { @@ -201,7 +176,7 @@ impl PyNumber<'_> { if let Some(i) = self.obj.downcast_ref_if_exact::(vm) { Ok(i.to_owned()) - } else if let Some(f) = self.methods().int { + } else if let Some(f) = self.methods().int.load() { let ret = f(self, vm)?; if !ret.class().is(PyInt::class(vm)) { warnings::warn( @@ -219,7 +194,7 @@ impl PyNumber<'_> { } else { Ok(ret) } - } else if self.methods().index.is_some() { + } else if self.methods().index.load().is_some() { self.index(vm) } else if let Ok(Ok(f)) = vm.get_special_method(self.obj.to_owned(), identifier!(vm, __trunc__)) @@ -260,7 +235,7 @@ impl PyNumber<'_> { Ok(Some(i.to_owned())) } else if let Some(i) = self.obj.payload::() { Ok(Some(vm.ctx.new_bigint(i.as_bigint()))) - } else if let Some(f) = self.methods().index { + } else if let Some(f) = self.methods().index.load() { let ret = f(self, vm)?; if !ret.class().is(PyInt::class(vm)) { warnings::warn( @@ -295,7 +270,7 @@ impl PyNumber<'_> { pub fn float_opt(&self, vm: &VirtualMachine) -> PyResult>> { if let Some(float) = self.obj.downcast_ref_if_exact::(vm) { Ok(Some(float.to_owned())) - } else if let Some(f) = self.methods().float { + } else if let Some(f) = self.methods().float.load() { let ret = f(self, vm)?; if !ret.class().is(PyFloat::class(vm)) { warnings::warn( @@ -313,7 +288,7 @@ impl PyNumber<'_> { } else { Ok(Some(ret)) } - } else if self.methods().index.is_some() { + } else if self.methods().index.load().is_some() { let i = self.index(vm)?; let value = int::try_to_float(i.as_bigint(), vm)?; Ok(Some(vm.ctx.new_float(value))) From c24457521d6815d0d5d43ece2d94d5c54e521f40 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Fri, 24 Jun 2022 22:31:52 +0200 Subject: [PATCH 02/11] proto heaptypeext --- derive/src/pyclass.rs | 5 +++++ vm/src/builtins/float.rs | 4 ++-- vm/src/builtins/int.rs | 2 +- vm/src/builtins/type.rs | 29 ++++++++++++++++++++++------ vm/src/function/number.rs | 2 +- vm/src/object/core.rs | 3 +++ vm/src/protocol/number.rs | 40 ++++++++++++++++++++++----------------- vm/src/types/slot.rs | 17 ++++------------- vm/src/vm/vm_ops.rs | 6 ++---- 9 files changed, 64 insertions(+), 44 deletions(-) diff --git a/derive/src/pyclass.rs b/derive/src/pyclass.rs index a8e266cde..1a3701a84 100644 --- a/derive/src/pyclass.rs +++ b/derive/src/pyclass.rs @@ -564,10 +564,15 @@ where let slot_name = slot_ident.to_string(); let tokens = { const NON_ATOMIC_SLOTS: &[&str] = &["as_buffer"]; + const POINTER_SLOTS: &[&str] = &["as_number"]; if NON_ATOMIC_SLOTS.contains(&slot_name.as_str()) { quote_spanned! { span => slots.#slot_ident = Some(Self::#ident as _); } + } else if POINTER_SLOTS.contains(&slot_name.as_str()) { + quote_spanned! { span => + slots.#slot_ident.store(Some(NonNull::from(Self::#ident()))); + } } else { quote_spanned! { span => slots.#slot_ident.store(Some(Self::#ident as _)); diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index d006688dc..e796efb47 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -60,11 +60,11 @@ impl From for PyFloat { impl PyObject { pub fn try_float_opt(&self, vm: &VirtualMachine) -> PyResult>> { - PyNumber::new(self, vm).float_opt(vm) + PyNumber::from(self).float_opt(vm) } pub fn try_float(&self, vm: &VirtualMachine) -> PyResult> { - PyNumber::new(self, vm).float(vm) + PyNumber::from(self).float(vm) } } diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index dc8695f3d..5cecce848 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -266,7 +266,7 @@ impl Constructor for PyInt { val }; - PyNumber::new(val.as_ref(), vm) + PyNumber::from(val.as_ref()) .int(vm) .map(|x| x.as_bigint().clone()) } diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 6647cdba7..37cc0aeaa 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -2,11 +2,6 @@ use super::{ mappingproxy::PyMappingProxy, object, union_, PyClassMethod, PyDictRef, PyList, PyStaticMethod, PyStr, PyStrInterned, PyStrRef, PyTuple, PyTupleRef, PyWeak, }; -use crate::common::{ - ascii, - borrow::BorrowedValue, - lock::{PyRwLock, PyRwLockReadGuard}, -}; use crate::{ builtins::PyBaseExceptionRef, class::{PyClassImpl, StaticType}, @@ -15,9 +10,17 @@ use crate::{ types::{Callable, GetAttr, PyTypeFlags, PyTypeSlots, SetAttr}, AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; +use crate::{ + common::{ + ascii, + borrow::BorrowedValue, + lock::{PyRwLock, PyRwLockReadGuard}, + }, + protocol::PyNumberMethods, +}; use indexmap::{map::Entry, IndexMap}; use itertools::Itertools; -use std::{borrow::Borrow, collections::HashSet, fmt, ops::Deref}; +use std::{borrow::Borrow, collections::HashSet, fmt, ops::Deref, pin::Pin}; /// type(object_or_name, bases, dict) /// type(object) -> the object's type @@ -30,10 +33,23 @@ pub struct PyType { pub subclasses: PyRwLock>>, pub attributes: PyRwLock, pub slots: PyTypeSlots, + pub heaptype_ext: Option>>, +} + +#[derive(Default)] +pub struct HeapTypeExt { + pub number_methods: PyNumberMethods, } pub type PyTypeRef = PyRef; +cfg_if::cfg_if! { + if #[cfg(feature = "threading")] { + unsafe impl Send for PyType {} + unsafe impl Sync for PyType {} + } +} + /// For attributes we do not use a dict, but an IndexMap, which is an Hash Table /// that maintains order and is compatible with the standard HashMap This is probably /// faster and only supports strings as keys. @@ -112,6 +128,7 @@ impl PyType { subclasses: PyRwLock::default(), attributes: PyRwLock::new(attrs), slots, + heaptype_ext: Some(Pin::new(Box::new(HeapTypeExt::default()))), }, metaclass, None, diff --git a/vm/src/function/number.rs b/vm/src/function/number.rs index 6c6eac2de..28badb15b 100644 --- a/vm/src/function/number.rs +++ b/vm/src/function/number.rs @@ -82,7 +82,7 @@ impl Deref for ArgIntoFloat { impl TryFromObject for ArgIntoFloat { // Equivalent to PyFloat_AsDouble. fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { - let value = PyNumber::new(obj.as_ref(), vm).float(vm)?.to_f64(); + let value = PyNumber::from(obj.as_ref()).float(vm)?.to_f64(); Ok(ArgIntoFloat { value }) } } diff --git a/vm/src/object/core.rs b/vm/src/object/core.rs index c3a67ccfc..8868a68e9 100644 --- a/vm/src/object/core.rs +++ b/vm/src/object/core.rs @@ -1105,6 +1105,7 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef, PyTypeRef) { subclasses: PyRwLock::default(), attributes: PyRwLock::new(Default::default()), slots: PyType::make_slots(), + heaptype_ext: None, }; let object_payload = PyType { base: None, @@ -1113,6 +1114,7 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef, PyTypeRef) { subclasses: PyRwLock::default(), attributes: PyRwLock::new(Default::default()), slots: object::PyBaseObject::make_slots(), + heaptype_ext: None, }; let type_type_ptr = Box::into_raw(Box::new(partially_init!( PyInner:: { @@ -1173,6 +1175,7 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef, PyTypeRef) { subclasses: PyRwLock::default(), attributes: PyRwLock::default(), slots: PyWeak::make_slots(), + heaptype_ext: None, }; let weakref_type = PyRef::new_ref(weakref_type, type_type.clone(), None); diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index 944126f54..86a13f268 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -1,4 +1,7 @@ +use std::ptr::NonNull; + use crossbeam_utils::atomic::AtomicCell; +use once_cell::sync::OnceCell; use crate::{ builtins::{int, PyByteArray, PyBytes, PyComplex, PyFloat, PyInt, PyIntRef, PyStr}, @@ -12,6 +15,7 @@ type UnaryFunc = AtomicCell = AtomicCell PyResult>>; +#[derive(Default)] pub struct PyNumberMethods { /* Number implementations must check *both* arguments for proper type and implement the necessary conversions @@ -124,36 +128,38 @@ impl PyNumberMethods { pub struct PyNumber<'a> { pub obj: &'a PyObject, // some fast path do not need methods, so we do lazy initialize - pub methods: Option<&'static PyNumberMethods>, + methods: OnceCell>, } -impl<'a> PyNumber<'a> { - pub fn new(obj: &'a PyObject, vm: &VirtualMachine) -> Self { +impl<'a> From<&'a PyObject> for PyNumber<'a> { + fn from(obj: &'a PyObject) -> Self { Self { obj, - methods: Self::find_methods(obj, vm), + methods: OnceCell::new(), } } } impl PyNumber<'_> { - pub fn find_methods(obj: &PyObject, vm: &VirtualMachine) -> Option<&'static PyNumberMethods> { - let as_number = obj.class().mro_find_map(|x| x.slots.as_number.load()); - as_number.map(|f| f(obj, vm)) + pub fn methods(&self) -> &PyNumberMethods { + let as_number = self.methods.get_or_init(|| { + Self::find_methods(self.obj).unwrap_or(NonNull::from(&PyNumberMethods::NOT_IMPLEMENTED)) + }); + unsafe { as_number.as_ref() } } - pub fn methods(&self) -> &'static PyNumberMethods { - self.methods.unwrap_or(&PyNumberMethods::NOT_IMPLEMENTED) + fn find_methods<'a>(obj: &'a PyObject) -> Option> { + obj.class().mro_find_map(|x| x.slots.as_number.load()) } // PyNumber_Check - pub fn check(obj: &PyObject, vm: &VirtualMachine) -> bool { - Self::find_methods(obj, vm).map_or(false, |methods| { - methods.int.load().is_some() - || methods.index.load().is_some() - || methods.float.load().is_some() - || obj.payload_is::() - }) + pub fn check<'a>(obj: &'a PyObject, vm: &VirtualMachine) -> bool { + let num = PyNumber::from(obj); + let methods = num.methods(); + methods.int.load().is_some() + || methods.index.load().is_some() + || methods.float.load().is_some() + || obj.payload_is::() } // PyIndex_Check @@ -207,7 +213,7 @@ impl PyNumber<'_> { // vm, // )?; let ret = f.invoke((), vm)?; - PyNumber::new(ret.as_ref(), vm).index(vm).map_err(|_| { + PyNumber::from(ret.as_ref()).index(vm).map_err(|_| { vm.new_type_error(format!( "__trunc__ returned non-Integral (type {})", ret.class() diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index f05483886..85df5b485 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -15,6 +15,7 @@ use crate::{ }; use crossbeam_utils::atomic::AtomicCell; use num_traits::{Signed, ToPrimitive}; +use std::ptr::NonNull; use std::{borrow::Borrow, cmp::Ordering}; // The corresponding field in CPython is `tp_` prefixed. @@ -30,7 +31,7 @@ pub struct PyTypeSlots { // Methods to implement standard operations // Method suites for standard classes - pub as_number: AtomicCell>, + pub as_number: AtomicCell>>, pub as_sequence: AtomicCell>, pub as_mapping: AtomicCell>, @@ -139,7 +140,6 @@ impl Default for PyTypeFlags { pub(crate) type GenericMethod = fn(&PyObject, FuncArgs, &VirtualMachine) -> PyResult; pub(crate) type AsMappingFunc = fn(&PyObject, &VirtualMachine) -> &'static PyMappingMethods; -pub(crate) type AsNumberFunc = fn(&PyObject, &VirtualMachine) -> &'static PyNumberMethods; pub(crate) type HashFunc = fn(&PyObject, &VirtualMachine) -> PyResult; // CallFunc = GenericMethod pub(crate) type GetattroFunc = fn(&PyObject, PyStrRef, &VirtualMachine) -> PyResult; @@ -205,15 +205,6 @@ fn slot_as_sequence(zelf: &PyObject, vm: &VirtualMachine) -> &'static PySequence PySequenceMethods::generic(has_length, has_ass_item) } -fn slot_as_number(zelf: &PyObject, vm: &VirtualMachine) -> &'static PyNumberMethods { - let (has_int, has_float, has_index) = ( - zelf.class().has_attr(identifier!(vm, __int__)), - zelf.class().has_attr(identifier!(vm, __float__)), - zelf.class().has_attr(identifier!(vm, __index__)), - ); - PyNumberMethods::generic(has_int, has_float, has_index) -} - fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult { let hash_obj = vm.call_special_method(zelf.to_owned(), identifier!(vm, __hash__), ())?; match hash_obj.payload_if_subclass::(vm) { @@ -374,7 +365,7 @@ impl PyType { update_slot!(del, del_wrapper); } "__int__" | "__index__" | "__float__" => { - update_slot!(as_number, slot_as_number); + // update_slot!(as_number, slot_as_number); } _ => {} } @@ -884,7 +875,7 @@ pub trait AsNumber: PyPayload { #[inline] #[pyslot] - fn as_number(_zelf: &PyObject, _vm: &VirtualMachine) -> &'static PyNumberMethods { + fn as_number() -> &'static PyNumberMethods { &Self::AS_NUMBER } diff --git a/vm/src/vm/vm_ops.rs b/vm/src/vm/vm_ops.rs index f8af60b7a..1c325595c 100644 --- a/vm/src/vm/vm_ops.rs +++ b/vm/src/vm/vm_ops.rs @@ -10,13 +10,11 @@ use crate::{ /// Collection of operators impl VirtualMachine { pub fn to_index_opt(&self, obj: PyObjectRef) -> Option> { - PyNumber::new(obj.as_ref(), self) - .index_opt(self) - .transpose() + PyNumber::from(obj.as_ref()).index_opt(self).transpose() } pub fn to_index(&self, obj: &PyObject) -> PyResult { - PyNumber::new(obj, self).index(self) + PyNumber::from(obj).index(self) } #[inline] From 44daeef9c898d49e9bb809094dc2c04bb5f430e5 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Sat, 25 Jun 2022 09:42:06 +0200 Subject: [PATCH 03/11] fix static lifetime --- vm/src/builtins/float.rs | 81 ++++++++++++++++----------------------- vm/src/builtins/int.rs | 83 +++++++++++++++++----------------------- vm/src/types/slot.rs | 12 +++--- 3 files changed, 76 insertions(+), 100 deletions(-) diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index e796efb47..29b8af28e 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -560,55 +560,42 @@ macro_rules! atomic_func { } impl AsNumber for PyFloat { - const AS_NUMBER: PyNumberMethods = PyNumberMethods { - add: atomic_func!(|num, other, vm| Self::number_float_op(num, other, |a, b| a + b, vm)), - subtract: atomic_func!(|num, other, vm| Self::number_float_op( - num, - other, - |a, b| a - b, - vm - )), - multiply: atomic_func!(|num, other, vm| Self::number_float_op( - num, - other, - |a, b| a * b, - vm - )), - remainder: atomic_func!(|num, other, vm| Self::number_general_op( - num, other, inner_mod, vm - )), - divmod: atomic_func!(|num, other, vm| Self::number_general_op( - num, - other, - inner_divmod, - vm - )), - power: atomic_func!(|num, other, vm| Self::number_general_op(num, other, float_pow, vm)), - negative: atomic_func!(|num, vm| { - let value = Self::number_downcast(num).value; - (-value).to_pyresult(vm) - }), - positive: atomic_func!(|num, vm| Self::number_float(num, vm).to_pyresult(vm)), - absolute: atomic_func!(|num, vm| { - let value = Self::number_downcast(num).value; - value.abs().to_pyresult(vm) - }), - boolean: atomic_func!(|num, _vm| Ok(Self::number_downcast(num).value.is_zero())), - int: atomic_func!(|num, vm| { - let value = Self::number_downcast(num).value; - try_to_bigint(value, vm).map(|x| vm.ctx.new_int(x)) - }), - float: atomic_func!(|num, vm| Ok(Self::number_float(num, vm))), - floor_divide: atomic_func!(|num, other, vm| { - Self::number_general_op(num, other, inner_floordiv, vm) - }), - true_divide: atomic_func!(|num, other, vm| { - Self::number_general_op(num, other, inner_div, vm) - }), - ..PyNumberMethods::NOT_IMPLEMENTED - }; + fn as_number() -> &'static PyNumberMethods { + &AS_NUMBER + } } +static AS_NUMBER: PyNumberMethods = PyNumberMethods { + add: atomic_func!(|num, other, vm| PyFloat::number_float_op(num, other, |a, b| a + b, vm)), + subtract: atomic_func!(|num, other, vm| PyFloat::number_float_op(num, other, |a, b| a - b, vm)), + multiply: atomic_func!(|num, other, vm| PyFloat::number_float_op(num, other, |a, b| a * b, vm)), + remainder: atomic_func!(|num, other, vm| PyFloat::number_general_op(num, other, inner_mod, vm)), + divmod: atomic_func!(|num, other, vm| PyFloat::number_general_op(num, other, inner_divmod, vm)), + power: atomic_func!(|num, other, vm| PyFloat::number_general_op(num, other, float_pow, vm)), + negative: atomic_func!(|num, vm| { + let value = PyFloat::number_downcast(num).value; + (-value).to_pyresult(vm) + }), + positive: atomic_func!(|num, vm| PyFloat::number_float(num, vm).to_pyresult(vm)), + absolute: atomic_func!(|num, vm| { + let value = PyFloat::number_downcast(num).value; + value.abs().to_pyresult(vm) + }), + boolean: atomic_func!(|num, _vm| Ok(PyFloat::number_downcast(num).value.is_zero())), + int: atomic_func!(|num, vm| { + let value = PyFloat::number_downcast(num).value; + try_to_bigint(value, vm).map(|x| vm.ctx.new_int(x)) + }), + float: atomic_func!(|num, vm| Ok(PyFloat::number_float(num, vm))), + floor_divide: atomic_func!(|num, other, vm| { + PyFloat::number_general_op(num, other, inner_floordiv, vm) + }), + true_divide: atomic_func!(|num, other, vm| { + PyFloat::number_general_op(num, other, inner_div, vm) + }), + ..PyNumberMethods::NOT_IMPLEMENTED +}; + impl PyFloat { fn number_general_op( number: &PyNumber, diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 5cecce848..2b98155e4 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -763,56 +763,43 @@ macro_rules! atomic_func { } impl AsNumber for PyInt { - const AS_NUMBER: PyNumberMethods = PyNumberMethods { - add: atomic_func!(|num, other, vm| Self::number_int_op(num, other, |a, b| a + b, vm)), - subtract: atomic_func!(|num, other, vm| Self::number_int_op(num, other, |a, b| a - b, vm)), - multiply: atomic_func!(|num, other, vm| Self::number_int_op(num, other, |a, b| a * b, vm)), - remainder: atomic_func!(|num, other, vm| Self::number_general_op( - num, other, inner_mod, vm - )), - divmod: atomic_func!(|num, other, vm| Self::number_general_op( - num, - other, - inner_divmod, - vm - )), - power: atomic_func!(|num, other, vm| Self::number_general_op(num, other, inner_pow, vm)), - negative: atomic_func!(|num, vm| (&Self::number_downcast(num).value).neg().to_pyresult(vm)), - positive: atomic_func!(|num, vm| Ok(Self::number_int(num, vm).into())), - absolute: atomic_func!(|num, vm| Self::number_downcast(num).value.abs().to_pyresult(vm)), - boolean: atomic_func!(|num, _vm| Ok(Self::number_downcast(num).value.is_zero())), - invert: atomic_func!(|num, vm| (&Self::number_downcast(num).value).not().to_pyresult(vm)), - lshift: atomic_func!(|num, other, vm| Self::number_general_op( - num, - other, - inner_lshift, - vm - )), - rshift: atomic_func!(|num, other, vm| Self::number_general_op( - num, - other, - inner_rshift, - vm - )), - and: atomic_func!(|num, other, vm| Self::number_int_op(num, other, |a, b| a & b, vm)), - xor: atomic_func!(|num, other, vm| Self::number_int_op(num, other, |a, b| a ^ b, vm)), - or: atomic_func!(|num, other, vm| Self::number_int_op(num, other, |a, b| a | b, vm)), - int: atomic_func!(|num, other| Ok(Self::number_int(num, other))), - float: atomic_func!(|num, vm| { - let zelf = Self::number_downcast(num); - try_to_float(&zelf.value, vm).map(|x| vm.ctx.new_float(x)) - }), - floor_divide: atomic_func!(|num, other, vm| { - Self::number_general_op(num, other, inner_floordiv, vm) - }), - true_divide: atomic_func!(|num, other, vm| { - Self::number_general_op(num, other, inner_truediv, vm) - }), - index: atomic_func!(|num, vm| Ok(Self::number_int(num, vm))), - ..PyNumberMethods::NOT_IMPLEMENTED - }; + fn as_number() -> &'static PyNumberMethods { + &AS_NUMBER + } } +static AS_NUMBER: PyNumberMethods = PyNumberMethods { + add: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a + b, vm)), + subtract: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a - b, vm)), + multiply: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a * b, vm)), + remainder: atomic_func!(|num, other, vm| PyInt::number_general_op(num, other, inner_mod, vm)), + divmod: atomic_func!(|num, other, vm| PyInt::number_general_op(num, other, inner_divmod, vm)), + power: atomic_func!(|num, other, vm| PyInt::number_general_op(num, other, inner_pow, vm)), + negative: atomic_func!(|num, vm| (&PyInt::number_downcast(num).value).neg().to_pyresult(vm)), + positive: atomic_func!(|num, vm| Ok(PyInt::number_int(num, vm).into())), + absolute: atomic_func!(|num, vm| PyInt::number_downcast(num).value.abs().to_pyresult(vm)), + boolean: atomic_func!(|num, _vm| Ok(PyInt::number_downcast(num).value.is_zero())), + invert: atomic_func!(|num, vm| (&PyInt::number_downcast(num).value).not().to_pyresult(vm)), + lshift: atomic_func!(|num, other, vm| PyInt::number_general_op(num, other, inner_lshift, vm)), + rshift: atomic_func!(|num, other, vm| PyInt::number_general_op(num, other, inner_rshift, vm)), + and: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a & b, vm)), + xor: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a ^ b, vm)), + or: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a | b, vm)), + int: atomic_func!(|num, other| Ok(PyInt::number_int(num, other))), + float: atomic_func!(|num, vm| { + let zelf = PyInt::number_downcast(num); + try_to_float(&zelf.value, vm).map(|x| vm.ctx.new_float(x)) + }), + floor_divide: atomic_func!(|num, other, vm| { + PyInt::number_general_op(num, other, inner_floordiv, vm) + }), + true_divide: atomic_func!(|num, other, vm| { + PyInt::number_general_op(num, other, inner_truediv, vm) + }), + index: atomic_func!(|num, vm| Ok(PyInt::number_int(num, vm))), + ..PyNumberMethods::NOT_IMPLEMENTED +}; + impl PyInt { fn number_general_op( number: &PyNumber, diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 85df5b485..8a0c31b89 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -871,13 +871,15 @@ pub trait AsSequence: PyPayload { #[pyimpl] pub trait AsNumber: PyPayload { - const AS_NUMBER: PyNumberMethods; + // const AS_NUMBER: PyNumberMethods; - #[inline] #[pyslot] - fn as_number() -> &'static PyNumberMethods { - &Self::AS_NUMBER - } + fn as_number() -> &'static PyNumberMethods; + // #[inline] + // #[pyslot] + // fn as_number() -> &'static PyNumberMethods { + // &Self::AS_NUMBER + // } fn number_downcast<'a>(number: &'a PyNumber) -> &'a Py { unsafe { number.obj.downcast_unchecked_ref() } From 2895c8124a2673403297ffe162fec2cdc09a7513 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Sat, 25 Jun 2022 14:00:51 +0200 Subject: [PATCH 04/11] use heaptypeext for number protocol --- vm/src/protocol/number.rs | 32 +++---------- vm/src/types/slot.rs | 95 +++++++++++++++++++++++++++++++-------- 2 files changed, 83 insertions(+), 44 deletions(-) diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index 86a13f268..36999a227 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -63,6 +63,9 @@ pub struct PyNumberMethods { } impl PyNumberMethods { + /// this is NOT a global variable + // TODO: weak order read for performance + #[allow(clippy::declare_interior_mutable_const)] pub const NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods { add: AtomicCell::new(None), subtract: AtomicCell::new(None), @@ -101,28 +104,6 @@ impl PyNumberMethods { matrix_multiply: AtomicCell::new(None), inplace_matrix_multiply: AtomicCell::new(None), }; - - fn int(num: &PyNumber, vm: &VirtualMachine) -> PyResult> { - let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __int__), ())?; - ret.downcast::().map_err(|obj| { - vm.new_type_error(format!("__int__ returned non-int (type {})", obj.class())) - }) - } - fn float(num: &PyNumber, vm: &VirtualMachine) -> PyResult> { - let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __float__), ())?; - ret.downcast::().map_err(|obj| { - vm.new_type_error(format!( - "__float__ returned non-float (type {})", - obj.class() - )) - }) - } - fn index(num: &PyNumber, vm: &VirtualMachine) -> PyResult> { - let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __index__), ())?; - ret.downcast::().map_err(|obj| { - vm.new_type_error(format!("__index__ returned non-int (type {})", obj.class())) - }) - } } pub struct PyNumber<'a> { @@ -142,18 +123,19 @@ impl<'a> From<&'a PyObject> for PyNumber<'a> { impl PyNumber<'_> { pub fn methods(&self) -> &PyNumberMethods { + static GLOBAL_NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods::NOT_IMPLEMENTED; let as_number = self.methods.get_or_init(|| { - Self::find_methods(self.obj).unwrap_or(NonNull::from(&PyNumberMethods::NOT_IMPLEMENTED)) + Self::find_methods(self.obj).unwrap_or_else(|| NonNull::from(&GLOBAL_NOT_IMPLEMENTED)) }); unsafe { as_number.as_ref() } } - fn find_methods<'a>(obj: &'a PyObject) -> Option> { + fn find_methods(obj: &PyObject) -> Option> { obj.class().mro_find_map(|x| x.slots.as_number.load()) } // PyNumber_Check - pub fn check<'a>(obj: &'a PyObject, vm: &VirtualMachine) -> bool { + pub fn check(obj: &PyObject) -> bool { let num = PyNumber::from(obj); let methods = num.methods(); methods.int.load().is_some() diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 8a0c31b89..8fea8053a 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -1,6 +1,6 @@ use crate::common::{hash::PyHash, lock::PyRwLock}; use crate::{ - builtins::{PyInt, PyStrInterned, PyStrRef, PyType, PyTypeRef}, + builtins::{PyFloat, PyInt, PyStrInterned, PyStrRef, PyType, PyTypeRef}, bytecode::ComparisonOperator, convert::ToPyResult, function::Either, @@ -205,6 +205,30 @@ fn slot_as_sequence(zelf: &PyObject, vm: &VirtualMachine) -> &'static PySequence PySequenceMethods::generic(has_length, has_ass_item) } +fn int_wrapper(num: &PyNumber, vm: &VirtualMachine) -> PyResult> { + let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __int__), ())?; + ret.downcast::().map_err(|obj| { + vm.new_type_error(format!("__int__ returned non-int (type {})", obj.class())) + }) +} + +fn index_wrapper(num: &PyNumber, vm: &VirtualMachine) -> PyResult> { + let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __index__), ())?; + ret.downcast::().map_err(|obj| { + vm.new_type_error(format!("__index__ returned non-int (type {})", obj.class())) + }) +} + +fn float_wrapper(num: &PyNumber, vm: &VirtualMachine) -> PyResult> { + let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __float__), ())?; + ret.downcast::().map_err(|obj| { + vm.new_type_error(format!( + "__float__ returned non-float (type {})", + obj.class() + )) + }) +} + fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult { let hash_obj = vm.call_special_method(zelf.to_owned(), identifier!(vm, __hash__), ())?; match hash_obj.payload_if_subclass::(vm) { @@ -318,21 +342,37 @@ impl PyType { debug_assert!(name.as_str().starts_with("__")); debug_assert!(name.as_str().ends_with("__")); - macro_rules! update_slot { + macro_rules! toggle_slot { ($name:ident, $func:expr) => {{ self.slots.$name.store(if add { Some($func) } else { None }); }}; } + + macro_rules! update_slot { + ($name:ident, $func:expr) => {{ + self.slots.$name.store(Some($func)); + }}; + } + + macro_rules! update_pointer_slot { + ($name:ident, $pointed:ident) => {{ + self.slots.$name.store( + self.heaptype_ext + .as_ref() + .map(|ext| NonNull::from(&ext.$pointed)), + ); + }}; + } match name.as_str() { "__len__" | "__getitem__" | "__setitem__" | "__delitem__" => { update_slot!(as_mapping, slot_as_mapping); update_slot!(as_sequence, slot_as_sequence); } "__hash__" => { - update_slot!(hash, hash_wrapper); + toggle_slot!(hash, hash_wrapper); } "__call__" => { - update_slot!(call, call_wrapper); + toggle_slot!(call, call_wrapper); } "__getattr__" | "__getattribute__" => { update_slot!(getattro, getattro_wrapper); @@ -344,28 +384,52 @@ impl PyType { update_slot!(richcompare, richcompare_wrapper); } "__iter__" => { - update_slot!(iter, iter_wrapper); + toggle_slot!(iter, iter_wrapper); } "__next__" => { - update_slot!(iternext, iternext_wrapper); + toggle_slot!(iternext, iternext_wrapper); } "__get__" => { - update_slot!(descr_get, descr_get_wrapper); + toggle_slot!(descr_get, descr_get_wrapper); } "__set__" | "__delete__" => { update_slot!(descr_set, descr_set_wrapper); } "__init__" => { - update_slot!(init, init_wrapper); + toggle_slot!(init, init_wrapper); } "__new__" => { - update_slot!(new, new_wrapper); + toggle_slot!(new, new_wrapper); } "__del__" => { - update_slot!(del, del_wrapper); + toggle_slot!(del, del_wrapper); } - "__int__" | "__index__" | "__float__" => { - // update_slot!(as_number, slot_as_number); + "__int__" => { + self.heaptype_ext + .as_ref() + .unwrap() + .number_methods + .int + .store(Some(int_wrapper)); + update_pointer_slot!(as_number, number_methods); + } + "__index__" => { + self.heaptype_ext + .as_ref() + .unwrap() + .number_methods + .index + .store(Some(index_wrapper)); + update_pointer_slot!(as_number, number_methods); + } + "__float__" => { + self.heaptype_ext + .as_ref() + .unwrap() + .number_methods + .float + .store(Some(float_wrapper)); + update_pointer_slot!(as_number, number_methods); } _ => {} } @@ -871,15 +935,8 @@ pub trait AsSequence: PyPayload { #[pyimpl] pub trait AsNumber: PyPayload { - // const AS_NUMBER: PyNumberMethods; - #[pyslot] fn as_number() -> &'static PyNumberMethods; - // #[inline] - // #[pyslot] - // fn as_number() -> &'static PyNumberMethods { - // &Self::AS_NUMBER - // } fn number_downcast<'a>(number: &'a PyNumber) -> &'a Py { unsafe { number.obj.downcast_unchecked_ref() } From 069c6c9a1e31c6af7d0a89b1cc88ba42ea1edeef Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Sat, 25 Jun 2022 21:40:52 +0200 Subject: [PATCH 05/11] refactor replace nonnull with pointerslot --- derive/src/pyclass.rs | 2 +- vm/src/builtins/type.rs | 35 ++++++++++++++++++++++++++++++++++- vm/src/protocol/number.rs | 21 ++++++++++++--------- vm/src/types/slot.rs | 13 +++++-------- 4 files changed, 52 insertions(+), 19 deletions(-) diff --git a/derive/src/pyclass.rs b/derive/src/pyclass.rs index 1a3701a84..8aed20c34 100644 --- a/derive/src/pyclass.rs +++ b/derive/src/pyclass.rs @@ -571,7 +571,7 @@ where } } else if POINTER_SLOTS.contains(&slot_name.as_str()) { quote_spanned! { span => - slots.#slot_ident.store(Some(NonNull::from(Self::#ident()))); + slots.#slot_ident.store(Some(PointerSlot::from(Self::#ident()))); } } else { quote_spanned! { span => diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 37cc0aeaa..8c2c34854 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -20,7 +20,7 @@ use crate::{ }; use indexmap::{map::Entry, IndexMap}; use itertools::Itertools; -use std::{borrow::Borrow, collections::HashSet, fmt, ops::Deref, pin::Pin}; +use std::{borrow::Borrow, collections::HashSet, fmt, ops::Deref, pin::Pin, ptr::NonNull}; /// type(object_or_name, bases, dict) /// type(object) -> the object's type @@ -41,6 +41,39 @@ pub struct HeapTypeExt { pub number_methods: PyNumberMethods, } +pub struct PointerSlot(NonNull); + +impl Clone for PointerSlot { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for PointerSlot {} + +impl From<&'static T> for PointerSlot { + fn from(x: &'static T) -> Self { + Self(NonNull::from(x)) + } +} + +impl AsRef for PointerSlot { + fn as_ref(&self) -> &T { + unsafe { self.0.as_ref() } + } +} + +impl PointerSlot { + pub unsafe fn from_heaptype(typ: &PyType, f: F) -> Option + where + F: FnOnce(&HeapTypeExt) -> &T, + { + typ.heaptype_ext + .as_ref() + .map(|ext| Self(NonNull::from(f(ext)))) + } +} + pub type PyTypeRef = PyRef; cfg_if::cfg_if! { diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index 36999a227..9aca23951 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -1,10 +1,10 @@ -use std::ptr::NonNull; - use crossbeam_utils::atomic::AtomicCell; use once_cell::sync::OnceCell; use crate::{ - builtins::{int, PyByteArray, PyBytes, PyComplex, PyFloat, PyInt, PyIntRef, PyStr}, + builtins::{ + int, type_::PointerSlot, PyByteArray, PyBytes, PyComplex, PyFloat, PyInt, PyIntRef, PyStr, + }, function::ArgBytesLike, stdlib::warnings, AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject, @@ -109,7 +109,7 @@ impl PyNumberMethods { pub struct PyNumber<'a> { pub obj: &'a PyObject, // some fast path do not need methods, so we do lazy initialize - methods: OnceCell>, + methods: OnceCell>, } impl<'a> From<&'a PyObject> for PyNumber<'a> { @@ -124,13 +124,16 @@ impl<'a> From<&'a PyObject> for PyNumber<'a> { impl PyNumber<'_> { pub fn methods(&self) -> &PyNumberMethods { static GLOBAL_NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods::NOT_IMPLEMENTED; - let as_number = self.methods.get_or_init(|| { - Self::find_methods(self.obj).unwrap_or_else(|| NonNull::from(&GLOBAL_NOT_IMPLEMENTED)) - }); - unsafe { as_number.as_ref() } + + self.methods + .get_or_init(|| { + Self::find_methods(self.obj) + .unwrap_or_else(|| PointerSlot::from(&GLOBAL_NOT_IMPLEMENTED)) + }) + .as_ref() } - fn find_methods(obj: &PyObject) -> Option> { + fn find_methods(obj: &PyObject) -> Option> { obj.class().mro_find_map(|x| x.slots.as_number.load()) } diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 8fea8053a..5551e0fcb 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -1,6 +1,6 @@ use crate::common::{hash::PyHash, lock::PyRwLock}; use crate::{ - builtins::{PyFloat, PyInt, PyStrInterned, PyStrRef, PyType, PyTypeRef}, + builtins::{type_::PointerSlot, PyFloat, PyInt, PyStrInterned, PyStrRef, PyType, PyTypeRef}, bytecode::ComparisonOperator, convert::ToPyResult, function::Either, @@ -15,7 +15,6 @@ use crate::{ }; use crossbeam_utils::atomic::AtomicCell; use num_traits::{Signed, ToPrimitive}; -use std::ptr::NonNull; use std::{borrow::Borrow, cmp::Ordering}; // The corresponding field in CPython is `tp_` prefixed. @@ -31,7 +30,7 @@ pub struct PyTypeSlots { // Methods to implement standard operations // Method suites for standard classes - pub as_number: AtomicCell>>, + pub as_number: AtomicCell>>, pub as_sequence: AtomicCell>, pub as_mapping: AtomicCell>, @@ -356,11 +355,9 @@ impl PyType { macro_rules! update_pointer_slot { ($name:ident, $pointed:ident) => {{ - self.slots.$name.store( - self.heaptype_ext - .as_ref() - .map(|ext| NonNull::from(&ext.$pointed)), - ); + self.slots + .$name + .store(unsafe { PointerSlot::from_heaptype(self, |ext| &ext.$pointed) }); }}; } match name.as_str() { From e871a53227eb7ac28d6710ebe69e2777e93b1e38 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sat, 23 Jul 2022 16:12:26 +0900 Subject: [PATCH 06/11] resolve conflict --- vm/src/builtins/bytes.rs | 20 +++--- vm/src/builtins/complex.rs | 63 ++++++++++++------- vm/src/builtins/float.rs | 93 +++++++++++++++------------ vm/src/builtins/int.rs | 107 ++++++++++++++++++++------------ vm/src/builtins/mappingproxy.rs | 18 ++++-- vm/src/builtins/singletons.rs | 12 ++-- vm/src/builtins/type.rs | 14 ++--- vm/src/protocol/number.rs | 5 +- vm/src/stdlib/itertools.rs | 2 +- vm/src/types/slot.rs | 7 +++ 10 files changed, 211 insertions(+), 130 deletions(-) diff --git a/vm/src/builtins/bytes.rs b/vm/src/builtins/bytes.rs index 733504dc2..ff1d3d7b7 100644 --- a/vm/src/builtins/bytes.rs +++ b/vm/src/builtins/bytes.rs @@ -3,6 +3,7 @@ use super::{ }; use crate::{ anystr::{self, AnyStr}, + atomic_func, bytesinner::{ bytes_decode, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions, ByteInnerSplitOptions, ByteInnerTranslateOptions, DecodeArgs, PyBytesInner, @@ -608,14 +609,17 @@ impl AsSequence for PyBytes { } impl AsNumber for PyBytes { - const AS_NUMBER: PyNumberMethods = PyNumberMethods { - remainder: Some(|number, other, vm| { - Self::number_downcast(number) - .mod_(other.to_owned(), vm) - .to_pyresult(vm) - }), - ..PyNumberMethods::NOT_IMPLEMENTED - }; + fn as_number() -> &'static PyNumberMethods { + static AS_NUMBER: PyNumberMethods = PyNumberMethods { + remainder: atomic_func!(|number, other, vm| { + PyBytes::number_downcast(number) + .mod_(other.to_owned(), vm) + .to_pyresult(vm) + }), + ..PyNumberMethods::NOT_IMPLEMENTED + }; + &AS_NUMBER + } } impl Hashable for PyBytes { diff --git a/vm/src/builtins/complex.rs b/vm/src/builtins/complex.rs index 8805c6247..333269e4d 100644 --- a/vm/src/builtins/complex.rs +++ b/vm/src/builtins/complex.rs @@ -1,5 +1,6 @@ use super::{float, PyStr, PyType, PyTypeRef}; use crate::{ + atomic_func, class::PyClassImpl, convert::{ToPyObject, ToPyResult}, function::{ @@ -421,30 +422,44 @@ impl Hashable for PyComplex { } impl AsNumber for PyComplex { - const AS_NUMBER: PyNumberMethods = PyNumberMethods { - add: Some(|number, other, vm| Self::number_complex_op(number, other, |a, b| a + b, vm)), - subtract: Some(|number, other, vm| { - Self::number_complex_op(number, other, |a, b| a - b, vm) - }), - multiply: Some(|number, other, vm| { - Self::number_complex_op(number, other, |a, b| a * b, vm) - }), - power: Some(|number, other, vm| Self::number_general_op(number, other, inner_pow, vm)), - negative: Some(|number, vm| { - let value = Self::number_downcast(number).value; - (-value).to_pyresult(vm) - }), - positive: Some(|number, vm| Self::number_complex(number, vm).to_pyresult(vm)), - absolute: Some(|number, vm| { - let value = Self::number_downcast(number).value; - value.norm().to_pyresult(vm) - }), - boolean: Some(|number, _vm| Ok(Self::number_downcast(number).value.is_zero())), - true_divide: Some(|number, other, vm| { - Self::number_general_op(number, other, inner_div, vm) - }), - ..PyNumberMethods::NOT_IMPLEMENTED - }; + fn as_number() -> &'static PyNumberMethods { + static AS_NUMBER: PyNumberMethods = PyNumberMethods { + add: atomic_func!(|number, other, vm| PyComplex::number_complex_op( + number, + other, + |a, b| a + b, + vm + )), + subtract: atomic_func!(|number, other, vm| { + PyComplex::number_complex_op(number, other, |a, b| a - b, vm) + }), + multiply: atomic_func!(|number, other, vm| { + PyComplex::number_complex_op(number, other, |a, b| a * b, vm) + }), + power: atomic_func!(|number, other, vm| PyComplex::number_general_op( + number, other, inner_pow, vm + )), + negative: atomic_func!(|number, vm| { + let value = PyComplex::number_downcast(number).value; + (-value).to_pyresult(vm) + }), + positive: atomic_func!( + |number, vm| PyComplex::number_complex(number, vm).to_pyresult(vm) + ), + absolute: atomic_func!(|number, vm| { + let value = PyComplex::number_downcast(number).value; + value.norm().to_pyresult(vm) + }), + boolean: atomic_func!(|number, _vm| Ok(PyComplex::number_downcast(number) + .value + .is_zero())), + true_divide: atomic_func!(|number, other, vm| { + PyComplex::number_general_op(number, other, inner_div, vm) + }), + ..PyNumberMethods::NOT_IMPLEMENTED + }; + &AS_NUMBER + } } impl PyComplex { diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index 29b8af28e..c4b15193d 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -2,6 +2,7 @@ use super::{ try_bigint_to_f64, PyByteArray, PyBytes, PyInt, PyIntRef, PyStr, PyStrRef, PyType, PyTypeRef, }; use crate::{ + atomic_func, class::PyClassImpl, common::{float_ops, hash}, convert::{ToPyObject, ToPyResult}, @@ -16,7 +17,6 @@ use crate::{ AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject, TryFromObject, VirtualMachine, }; -use crossbeam_utils::atomic::AtomicCell; use num_bigint::{BigInt, ToBigInt}; use num_complex::Complex64; use num_rational::Ratio; @@ -553,49 +553,66 @@ impl Hashable for PyFloat { } } -macro_rules! atomic_func { - ($x:expr) => { - AtomicCell::new(Some($x)) - }; -} - impl AsNumber for PyFloat { fn as_number() -> &'static PyNumberMethods { + static AS_NUMBER: PyNumberMethods = PyNumberMethods { + add: atomic_func!(|num, other, vm| PyFloat::number_float_op( + num, + other, + |a, b| a + b, + vm + )), + subtract: atomic_func!(|num, other, vm| PyFloat::number_float_op( + num, + other, + |a, b| a - b, + vm + )), + multiply: atomic_func!(|num, other, vm| PyFloat::number_float_op( + num, + other, + |a, b| a * b, + vm + )), + remainder: atomic_func!(|num, other, vm| PyFloat::number_general_op( + num, other, inner_mod, vm + )), + divmod: atomic_func!(|num, other, vm| PyFloat::number_general_op( + num, + other, + inner_divmod, + vm + )), + power: atomic_func!(|num, other, vm| PyFloat::number_general_op( + num, other, float_pow, vm + )), + negative: atomic_func!(|num, vm| { + let value = PyFloat::number_downcast(num).value; + (-value).to_pyresult(vm) + }), + positive: atomic_func!(|num, vm| PyFloat::number_float(num, vm).to_pyresult(vm)), + absolute: atomic_func!(|num, vm| { + let value = PyFloat::number_downcast(num).value; + value.abs().to_pyresult(vm) + }), + boolean: atomic_func!(|num, _vm| Ok(PyFloat::number_downcast(num).value.is_zero())), + int: atomic_func!(|num, vm| { + let value = PyFloat::number_downcast(num).value; + try_to_bigint(value, vm).map(|x| vm.ctx.new_int(x)) + }), + float: atomic_func!(|num, vm| Ok(PyFloat::number_float(num, vm))), + floor_divide: atomic_func!(|num, other, vm| { + PyFloat::number_general_op(num, other, inner_floordiv, vm) + }), + true_divide: atomic_func!(|num, other, vm| { + PyFloat::number_general_op(num, other, inner_div, vm) + }), + ..PyNumberMethods::NOT_IMPLEMENTED + }; &AS_NUMBER } } -static AS_NUMBER: PyNumberMethods = PyNumberMethods { - add: atomic_func!(|num, other, vm| PyFloat::number_float_op(num, other, |a, b| a + b, vm)), - subtract: atomic_func!(|num, other, vm| PyFloat::number_float_op(num, other, |a, b| a - b, vm)), - multiply: atomic_func!(|num, other, vm| PyFloat::number_float_op(num, other, |a, b| a * b, vm)), - remainder: atomic_func!(|num, other, vm| PyFloat::number_general_op(num, other, inner_mod, vm)), - divmod: atomic_func!(|num, other, vm| PyFloat::number_general_op(num, other, inner_divmod, vm)), - power: atomic_func!(|num, other, vm| PyFloat::number_general_op(num, other, float_pow, vm)), - negative: atomic_func!(|num, vm| { - let value = PyFloat::number_downcast(num).value; - (-value).to_pyresult(vm) - }), - positive: atomic_func!(|num, vm| PyFloat::number_float(num, vm).to_pyresult(vm)), - absolute: atomic_func!(|num, vm| { - let value = PyFloat::number_downcast(num).value; - value.abs().to_pyresult(vm) - }), - boolean: atomic_func!(|num, _vm| Ok(PyFloat::number_downcast(num).value.is_zero())), - int: atomic_func!(|num, vm| { - let value = PyFloat::number_downcast(num).value; - try_to_bigint(value, vm).map(|x| vm.ctx.new_int(x)) - }), - float: atomic_func!(|num, vm| Ok(PyFloat::number_float(num, vm))), - floor_divide: atomic_func!(|num, other, vm| { - PyFloat::number_general_op(num, other, inner_floordiv, vm) - }), - true_divide: atomic_func!(|num, other, vm| { - PyFloat::number_general_op(num, other, inner_div, vm) - }), - ..PyNumberMethods::NOT_IMPLEMENTED -}; - impl PyFloat { fn number_general_op( number: &PyNumber, diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 2b98155e4..d6d73e7b3 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -1,5 +1,6 @@ use super::{float, PyByteArray, PyBytes, PyStr, PyStrRef, PyType, PyTypeRef}; use crate::{ + atomic_func, bytesinner::PyBytesInner, class::PyClassImpl, common::hash, @@ -15,7 +16,6 @@ use crate::{ TryFromBorrowedObject, VirtualMachine, }; use bstr::ByteSlice; -use crossbeam_utils::atomic::AtomicCell; use num_bigint::{BigInt, BigUint, Sign}; use num_integer::Integer; use num_traits::{One, Pow, PrimInt, Signed, ToPrimitive, Zero}; @@ -756,50 +756,79 @@ impl Hashable for PyInt { } } -macro_rules! atomic_func { - ($x:expr) => { - AtomicCell::new(Some($x)) - }; -} - impl AsNumber for PyInt { fn as_number() -> &'static PyNumberMethods { + static AS_NUMBER: PyNumberMethods = PyNumberMethods { + add: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a + b, vm)), + subtract: atomic_func!(|num, other, vm| PyInt::number_int_op( + num, + other, + |a, b| a - b, + vm + )), + multiply: atomic_func!(|num, other, vm| PyInt::number_int_op( + num, + other, + |a, b| a * b, + vm + )), + remainder: atomic_func!(|num, other, vm| PyInt::number_general_op( + num, other, inner_mod, vm + )), + divmod: atomic_func!(|num, other, vm| PyInt::number_general_op( + num, + other, + inner_divmod, + vm + )), + power: atomic_func!(|num, other, vm| PyInt::number_general_op( + num, other, inner_pow, vm + )), + negative: atomic_func!(|num, vm| (&PyInt::number_downcast(num).value) + .neg() + .to_pyresult(vm)), + positive: atomic_func!(|num, vm| Ok(PyInt::number_int(num, vm).into())), + absolute: atomic_func!(|num, vm| PyInt::number_downcast(num) + .value + .abs() + .to_pyresult(vm)), + boolean: atomic_func!(|num, _vm| Ok(PyInt::number_downcast(num).value.is_zero())), + invert: atomic_func!(|num, vm| (&PyInt::number_downcast(num).value) + .not() + .to_pyresult(vm)), + lshift: atomic_func!(|num, other, vm| PyInt::number_general_op( + num, + other, + inner_lshift, + vm + )), + rshift: atomic_func!(|num, other, vm| PyInt::number_general_op( + num, + other, + inner_rshift, + vm + )), + and: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a & b, vm)), + xor: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a ^ b, vm)), + or: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a | b, vm)), + int: atomic_func!(|num, other| Ok(PyInt::number_int(num, other))), + float: atomic_func!(|num, vm| { + let zelf = PyInt::number_downcast(num); + try_to_float(&zelf.value, vm).map(|x| vm.ctx.new_float(x)) + }), + floor_divide: atomic_func!(|num, other, vm| { + PyInt::number_general_op(num, other, inner_floordiv, vm) + }), + true_divide: atomic_func!(|num, other, vm| { + PyInt::number_general_op(num, other, inner_truediv, vm) + }), + index: atomic_func!(|num, vm| Ok(PyInt::number_int(num, vm))), + ..PyNumberMethods::NOT_IMPLEMENTED + }; &AS_NUMBER } } -static AS_NUMBER: PyNumberMethods = PyNumberMethods { - add: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a + b, vm)), - subtract: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a - b, vm)), - multiply: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a * b, vm)), - remainder: atomic_func!(|num, other, vm| PyInt::number_general_op(num, other, inner_mod, vm)), - divmod: atomic_func!(|num, other, vm| PyInt::number_general_op(num, other, inner_divmod, vm)), - power: atomic_func!(|num, other, vm| PyInt::number_general_op(num, other, inner_pow, vm)), - negative: atomic_func!(|num, vm| (&PyInt::number_downcast(num).value).neg().to_pyresult(vm)), - positive: atomic_func!(|num, vm| Ok(PyInt::number_int(num, vm).into())), - absolute: atomic_func!(|num, vm| PyInt::number_downcast(num).value.abs().to_pyresult(vm)), - boolean: atomic_func!(|num, _vm| Ok(PyInt::number_downcast(num).value.is_zero())), - invert: atomic_func!(|num, vm| (&PyInt::number_downcast(num).value).not().to_pyresult(vm)), - lshift: atomic_func!(|num, other, vm| PyInt::number_general_op(num, other, inner_lshift, vm)), - rshift: atomic_func!(|num, other, vm| PyInt::number_general_op(num, other, inner_rshift, vm)), - and: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a & b, vm)), - xor: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a ^ b, vm)), - or: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a | b, vm)), - int: atomic_func!(|num, other| Ok(PyInt::number_int(num, other))), - float: atomic_func!(|num, vm| { - let zelf = PyInt::number_downcast(num); - try_to_float(&zelf.value, vm).map(|x| vm.ctx.new_float(x)) - }), - floor_divide: atomic_func!(|num, other, vm| { - PyInt::number_general_op(num, other, inner_floordiv, vm) - }), - true_divide: atomic_func!(|num, other, vm| { - PyInt::number_general_op(num, other, inner_truediv, vm) - }), - index: atomic_func!(|num, vm| Ok(PyInt::number_int(num, vm))), - ..PyNumberMethods::NOT_IMPLEMENTED -}; - impl PyInt { fn number_general_op( number: &PyNumber, diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index 788d100aa..173650169 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -1,5 +1,6 @@ use super::{PyDict, PyDictRef, PyGenericAlias, PyList, PyTuple, PyType, PyTypeRef}; use crate::{ + atomic_func, class::PyClassImpl, convert::ToPyObject, function::{ArgMapping, OptionalArg, PyComparisonValue}, @@ -217,11 +218,18 @@ impl AsSequence for PyMappingProxy { } impl AsNumber for PyMappingProxy { - const AS_NUMBER: PyNumberMethods = PyNumberMethods { - or: Some(|num, args, vm| Self::number_downcast(num).or(args.to_pyobject(vm), vm)), - inplace_or: Some(|num, args, vm| Self::number_downcast(num).ior(args.to_pyobject(vm), vm)), - ..PyNumberMethods::NOT_IMPLEMENTED - }; + fn as_number() -> &'static PyNumberMethods { + static AS_NUMBER: PyNumberMethods = PyNumberMethods { + or: atomic_func!(|num, args, vm| { + PyMappingProxy::number_downcast(num).or(args.to_pyobject(vm), vm) + }), + inplace_or: atomic_func!(|num, args, vm| { + PyMappingProxy::number_downcast(num).ior(args.to_pyobject(vm), vm) + }), + ..PyNumberMethods::NOT_IMPLEMENTED + }; + &AS_NUMBER + } } impl Iterable for PyMappingProxy { diff --git a/vm/src/builtins/singletons.rs b/vm/src/builtins/singletons.rs index f67ca2b85..3f510bed8 100644 --- a/vm/src/builtins/singletons.rs +++ b/vm/src/builtins/singletons.rs @@ -1,5 +1,6 @@ use super::{PyType, PyTypeRef}; use crate::{ + atomic_func, class::PyClassImpl, convert::ToPyObject, protocol::PyNumberMethods, @@ -56,10 +57,13 @@ impl PyNone { } impl AsNumber for PyNone { - const AS_NUMBER: PyNumberMethods = PyNumberMethods { - boolean: Some(|_number, _vm| Ok(false)), - ..PyNumberMethods::NOT_IMPLEMENTED - }; + fn as_number() -> &'static PyNumberMethods { + static AS_NUMBER: PyNumberMethods = PyNumberMethods { + boolean: atomic_func!(|_number, _vm| Ok(false)), + ..PyNumberMethods::NOT_IMPLEMENTED + }; + &AS_NUMBER + } } #[pyclass(module = false, name = "NotImplementedType")] diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 8c2c34854..7acfde88d 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -2,22 +2,20 @@ use super::{ mappingproxy::PyMappingProxy, object, union_, PyClassMethod, PyDictRef, PyList, PyStaticMethod, PyStr, PyStrInterned, PyStrRef, PyTuple, PyTupleRef, PyWeak, }; +use crate::common::{ + ascii, + borrow::BorrowedValue, + lock::{PyRwLock, PyRwLockReadGuard}, +}; use crate::{ builtins::PyBaseExceptionRef, class::{PyClassImpl, StaticType}, function::{FuncArgs, KwArgs, OptionalArg}, identifier, + protocol::PyNumberMethods, types::{Callable, GetAttr, PyTypeFlags, PyTypeSlots, SetAttr}, AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; -use crate::{ - common::{ - ascii, - borrow::BorrowedValue, - lock::{PyRwLock, PyRwLockReadGuard}, - }, - protocol::PyNumberMethods, -}; use indexmap::{map::Entry, IndexMap}; use itertools::Itertools; use std::{borrow::Borrow, collections::HashSet, fmt, ops::Deref, pin::Pin, ptr::NonNull}; diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index 9aca23951..798c0305f 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -1,6 +1,3 @@ -use crossbeam_utils::atomic::AtomicCell; -use once_cell::sync::OnceCell; - use crate::{ builtins::{ int, type_::PointerSlot, PyByteArray, PyBytes, PyComplex, PyFloat, PyInt, PyIntRef, PyStr, @@ -10,6 +7,8 @@ use crate::{ AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject, VirtualMachine, }; +use crossbeam_utils::atomic::AtomicCell; +use once_cell::sync::OnceCell; type UnaryFunc = AtomicCell PyResult>>; type BinaryFunc = diff --git a/vm/src/stdlib/itertools.rs b/vm/src/stdlib/itertools.rs index a90ac5d71..3366bc21e 100644 --- a/vm/src/stdlib/itertools.rs +++ b/vm/src/stdlib/itertools.rs @@ -196,7 +196,7 @@ mod decl { ) -> PyResult { let start = start.into_option().unwrap_or_else(|| vm.new_pyobj(0)); let step = step.into_option().unwrap_or_else(|| vm.new_pyobj(1)); - if !PyNumber::check(&start, vm) || !PyNumber::check(&step, vm) { + if !PyNumber::check(&start) || !PyNumber::check(&step) { return Err(vm.new_type_error("a number is required".to_owned())); } diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 5551e0fcb..b9c021e1f 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -17,6 +17,13 @@ use crossbeam_utils::atomic::AtomicCell; use num_traits::{Signed, ToPrimitive}; use std::{borrow::Borrow, cmp::Ordering}; +#[macro_export] +macro_rules! atomic_func { + ($x:expr) => { + crossbeam_utils::atomic::AtomicCell::new(Some($x)) + }; +} + // The corresponding field in CPython is `tp_` prefixed. // e.g. name -> tp_name #[derive(Default)] From a05712fd9b10f625de0231b1b58c53edb1c40ae0 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sat, 23 Jul 2022 17:47:17 +0900 Subject: [PATCH 07/11] no once cell --- stdlib/src/math.rs | 4 ++-- vm/src/builtins/complex.rs | 2 +- vm/src/builtins/float.rs | 12 +----------- vm/src/builtins/int.rs | 2 +- vm/src/builtins/type.rs | 6 ++++++ vm/src/function/number.rs | 4 ++-- vm/src/protocol/number.rs | 40 +++++++++++++++++++++----------------- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/stdlib/src/math.rs b/stdlib/src/math.rs index 08f450323..a1bf2cb57 100644 --- a/stdlib/src/math.rs +++ b/stdlib/src/math.rs @@ -454,7 +454,7 @@ mod math { fn ceil(x: PyObjectRef, vm: &VirtualMachine) -> PyResult { let result_or_err = try_magic_method(identifier!(vm, __ceil__), vm, &x); if result_or_err.is_err() { - if let Ok(Some(v)) = x.try_float_opt(vm) { + if let Ok(Some(v)) = x.to_number().float_opt(vm) { let v = try_f64_to_bigint(v.to_f64().ceil(), vm)?; return Ok(vm.ctx.new_int(v).into()); } @@ -466,7 +466,7 @@ mod math { fn floor(x: PyObjectRef, vm: &VirtualMachine) -> PyResult { let result_or_err = try_magic_method(identifier!(vm, __floor__), vm, &x); if result_or_err.is_err() { - if let Ok(Some(v)) = x.try_float_opt(vm) { + if let Ok(Some(v)) = x.to_number().float_opt(vm) { let v = try_f64_to_bigint(v.to_f64().floor(), vm)?; return Ok(vm.ctx.new_int(v).into()); } diff --git a/vm/src/builtins/complex.rs b/vm/src/builtins/complex.rs index 333269e4d..f48080f0d 100644 --- a/vm/src/builtins/complex.rs +++ b/vm/src/builtins/complex.rs @@ -67,7 +67,7 @@ impl PyObjectRef { if let Some(complex) = self.payload_if_subclass::(vm) { return Ok(Some((complex.value, true))); } - if let Some(float) = self.try_float_opt(vm)? { + if let Some(float) = self.to_number().float_opt(vm)? { return Ok(Some((Complex64::new(float.to_f64(), 0.0), false))); } Ok(None) diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index c4b15193d..d152dcb11 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -58,16 +58,6 @@ impl From for PyFloat { } } -impl PyObject { - pub fn try_float_opt(&self, vm: &VirtualMachine) -> PyResult>> { - PyNumber::from(self).float_opt(vm) - } - - pub fn try_float(&self, vm: &VirtualMachine) -> PyResult> { - PyNumber::from(self).float(vm) - } -} - pub(crate) fn to_op_float(obj: &PyObject, vm: &VirtualMachine) -> PyResult> { let v = if let Some(float) = obj.payload_if_subclass::(vm) { Some(float.value) @@ -152,7 +142,7 @@ impl Constructor for PyFloat { let float_val = match arg { OptionalArg::Missing => 0.0, OptionalArg::Present(val) => { - if let Some(f) = val.try_float_opt(vm)? { + if let Some(f) = val.to_number().float_opt(vm)? { f.value } else { float_from_string(val, vm)? diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index d6d73e7b3..e185a346c 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -266,7 +266,7 @@ impl Constructor for PyInt { val }; - PyNumber::from(val.as_ref()) + val.to_number() .int(vm) .map(|x| x.as_bigint().clone()) } diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 7acfde88d..4bc294171 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -41,6 +41,12 @@ pub struct HeapTypeExt { pub struct PointerSlot(NonNull); +impl PointerSlot { + pub unsafe fn borrow_static(&self) -> &'static T { + self.0.as_ref() + } +} + impl Clone for PointerSlot { fn clone(&self) -> Self { *self diff --git a/vm/src/function/number.rs b/vm/src/function/number.rs index 28badb15b..2c7790691 100644 --- a/vm/src/function/number.rs +++ b/vm/src/function/number.rs @@ -1,4 +1,4 @@ -use crate::{protocol::PyNumber, AsObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine}; +use crate::{AsObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine}; use num_complex::Complex64; use std::ops::Deref; @@ -82,7 +82,7 @@ impl Deref for ArgIntoFloat { impl TryFromObject for ArgIntoFloat { // Equivalent to PyFloat_AsDouble. fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { - let value = PyNumber::from(obj.as_ref()).float(vm)?.to_f64(); + let value = obj.to_number().float(vm)?.to_f64(); Ok(ArgIntoFloat { value }) } } diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index 798c0305f..8faa156b1 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -8,12 +8,19 @@ use crate::{ VirtualMachine, }; use crossbeam_utils::atomic::AtomicCell; -use once_cell::sync::OnceCell; type UnaryFunc = AtomicCell PyResult>>; type BinaryFunc = AtomicCell PyResult>>; + +impl PyObject { + #[inline] + pub fn to_number(&self) -> PyNumber<'_> { + PyNumber::from(self) + } +} + #[derive(Default)] pub struct PyNumberMethods { /* Number implementations must check *both* @@ -107,39 +114,36 @@ impl PyNumberMethods { pub struct PyNumber<'a> { pub obj: &'a PyObject, - // some fast path do not need methods, so we do lazy initialize - methods: OnceCell>, + methods: &'a PyNumberMethods, } impl<'a> From<&'a PyObject> for PyNumber<'a> { fn from(obj: &'a PyObject) -> Self { + static GLOBAL_NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods::NOT_IMPLEMENTED; Self { obj, - methods: OnceCell::new(), + methods: Self::find_methods(obj).map_or(&GLOBAL_NOT_IMPLEMENTED, |m| unsafe { m.borrow_static() }), } } } impl PyNumber<'_> { - pub fn methods(&self) -> &PyNumberMethods { - static GLOBAL_NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods::NOT_IMPLEMENTED; - - self.methods - .get_or_init(|| { - Self::find_methods(self.obj) - .unwrap_or_else(|| PointerSlot::from(&GLOBAL_NOT_IMPLEMENTED)) - }) - .as_ref() - } - fn find_methods(obj: &PyObject) -> Option> { obj.class().mro_find_map(|x| x.slots.as_number.load()) } + pub fn methods(&self) -> &PyNumberMethods { + self.methods + } + // PyNumber_Check pub fn check(obj: &PyObject) -> bool { - let num = PyNumber::from(obj); - let methods = num.methods(); + let methods = if let Some(m) = Self::find_methods(obj) { + m + } else { + return false; + }; + let methods = methods.as_ref(); methods.int.load().is_some() || methods.index.load().is_some() || methods.float.load().is_some() @@ -197,7 +201,7 @@ impl PyNumber<'_> { // vm, // )?; let ret = f.invoke((), vm)?; - PyNumber::from(ret.as_ref()).index(vm).map_err(|_| { + ret.to_number().index(vm).map_err(|_| { vm.new_type_error(format!( "__trunc__ returned non-Integral (type {})", ret.class() From 2d1158b27176451d2596045270ee81e0b0fe1327 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 24 Jul 2022 06:30:24 +0900 Subject: [PATCH 08/11] remove vm.try_index --- stdlib/src/bisect.rs | 2 +- stdlib/src/math.rs | 2 +- stdlib/src/select.rs | 2 +- stdlib/src/socket.rs | 6 +++--- vm/src/buffer.rs | 14 +++++++------- vm/src/builtins/int.rs | 6 +++--- vm/src/builtins/memory.rs | 2 +- vm/src/builtins/range.rs | 2 +- vm/src/byte.rs | 2 +- vm/src/convert/try_from.rs | 2 +- vm/src/dictdatatype.rs | 2 +- vm/src/protocol/number.rs | 26 +++++++++++++++++++++++++- vm/src/sliceable.rs | 4 ++-- vm/src/stdlib/builtins.rs | 2 +- vm/src/stdlib/io.rs | 2 +- vm/src/stdlib/operator.rs | 2 +- vm/src/stdlib/os.rs | 6 +++--- vm/src/stdlib/sre.rs | 2 +- vm/src/vm/vm_ops.rs | 10 +--------- 19 files changed, 56 insertions(+), 40 deletions(-) diff --git a/stdlib/src/bisect.rs b/stdlib/src/bisect.rs index 66084c068..0caab7c1d 100644 --- a/stdlib/src/bisect.rs +++ b/stdlib/src/bisect.rs @@ -25,7 +25,7 @@ mod _bisect { vm: &VirtualMachine, ) -> PyResult> { arg.into_option() - .map(|v| vm.to_index(&v)?.try_to_primitive(vm)) + .map(|v| v.try_index(vm)?.try_to_primitive(vm)) .transpose() } diff --git a/stdlib/src/math.rs b/stdlib/src/math.rs index a1bf2cb57..d0604ea69 100644 --- a/stdlib/src/math.rs +++ b/stdlib/src/math.rs @@ -199,7 +199,7 @@ mod math { #[pyfunction] fn isqrt(x: PyObjectRef, vm: &VirtualMachine) -> PyResult { - let index = vm.to_index(&x)?; + let index = x.try_index(vm)?; let value = index.as_bigint(); if value.is_negative() { diff --git a/stdlib/src/select.rs b/stdlib/src/select.rs index 29a053832..1c72c7fd9 100644 --- a/stdlib/src/select.rs +++ b/stdlib/src/select.rs @@ -347,7 +347,7 @@ mod decl { Some(ms) => { let ms = if let Some(float) = ms.payload::() { float.to_f64().to_i32() - } else if let Some(int) = vm.to_index_opt(ms.clone()) { + } else if let Some(int) = ms.try_index_opt(vm) { int?.as_bigint().to_i32() } else { return Err(vm.new_type_error(format!( diff --git a/stdlib/src/socket.rs b/stdlib/src/socket.rs index 729363d2b..313c55ca0 100644 --- a/stdlib/src/socket.rs +++ b/stdlib/src/socket.rs @@ -734,8 +734,8 @@ mod _socket { if obj.fast_isinstance(vm.ctx.types.float_type) { return Err(vm.new_type_error("integer argument expected, got float".to_owned())); } - let int = vm - .to_index_opt(obj) + let int = obj + .try_index_opt(vm) .unwrap_or_else(|| Err(vm.new_type_error("an integer is required".to_owned())))?; int.try_to_primitive::(vm) .map(|sock| sock as RawSocket) @@ -1382,7 +1382,7 @@ mod _socket { let (flags, address) = match arg3 { OptionalArg::Present(arg3) => { // should just be i32::try_from_obj but tests check for error message - let int = vm.to_index_opt(arg2).unwrap_or_else(|| { + let int = arg2.try_index_opt(vm).unwrap_or_else(|| { Err(vm.new_type_error("an integer is required".to_owned())) })?; let flags = int.try_to_primitive::(vm)?; diff --git a/vm/src/buffer.rs b/vm/src/buffer.rs index f2e05e828..f053c510c 100644 --- a/vm/src/buffer.rs +++ b/vm/src/buffer.rs @@ -491,15 +491,15 @@ fn get_int_or_index(vm: &VirtualMachine, arg: PyObjectRef) -> PyResult where T: PrimInt + for<'a> TryFrom<&'a BigInt>, { - match vm.to_index_opt(arg) { - Some(index) => index? - .try_to_primitive(vm) - .map_err(|_| new_struct_error(vm, "argument out of range".to_owned())), - None => Err(new_struct_error( + let index = arg.try_index_opt(vm).unwrap_or_else(|| { + Err(new_struct_error( vm, "required argument is not an integer".to_owned(), - )), - } + )) + })?; + index + .try_to_primitive(vm) + .map_err(|_| new_struct_error(vm, "argument out of range".to_owned())) } make_pack_primint!(i8); diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index e185a346c..360d20113 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -69,7 +69,7 @@ impl PyPayload for PyInt { } fn special_retrieve(vm: &VirtualMachine, obj: &PyObject) -> Option>> { - Some(vm.to_index(obj)) + Some(obj.try_index(vm)) } } @@ -245,8 +245,8 @@ impl Constructor for PyInt { fn py_new(cls: PyTypeRef, options: Self::Args, vm: &VirtualMachine) -> PyResult { let value = if let OptionalArg::Present(val) = options.val_options { if let OptionalArg::Present(base) = options.base { - let base = vm - .to_index(&base)? + let base = base + .try_index(vm)? .as_bigint() .to_u32() .filter(|&v| v == 0 || (2..=36).contains(&v)) diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs index 58f6decd1..4549285d9 100644 --- a/vm/src/builtins/memory.rs +++ b/vm/src/builtins/memory.rs @@ -904,7 +904,7 @@ impl TryFromObject for SubscriptNeedle { Ok(Self::Index(i.try_to_primitive(vm)?)) } else if obj.payload_is::() { Ok(Self::Slice(unsafe { obj.downcast_unchecked::() })) - } else if let Ok(i) = vm.to_index(&obj) { + } else if let Ok(i) = obj.try_index(vm) { Ok(Self::Index(i.try_to_primitive(vm)?)) } else { if let Some(tuple) = obj.payload::() { diff --git a/vm/src/builtins/range.rs b/vm/src/builtins/range.rs index f71f98a1b..6275f4d21 100644 --- a/vm/src/builtins/range.rs +++ b/vm/src/builtins/range.rs @@ -682,7 +682,7 @@ impl TryFromObject for RangeIndex { i @ PyInt => Ok(RangeIndex::Int(i)), s @ PySlice => Ok(RangeIndex::Slice(s)), obj => { - let val = vm.to_index(&obj).map_err(|_| vm.new_type_error(format!( + let val = obj.try_index(vm).map_err(|_| vm.new_type_error(format!( "sequence indices be integers or slices or classes that override __index__ operator, not '{}'", obj.class().name() )))?; diff --git a/vm/src/byte.rs b/vm/src/byte.rs index 4933b2b3a..42455bd27 100644 --- a/vm/src/byte.rs +++ b/vm/src/byte.rs @@ -20,7 +20,7 @@ pub fn bytes_from_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult PyResult { - vm.to_index(obj)? + obj.try_index(vm)? .as_bigint() .to_u8() .ok_or_else(|| vm.new_value_error("byte must be in range(0, 256)".to_owned())) diff --git a/vm/src/convert/try_from.rs b/vm/src/convert/try_from.rs index cd1489695..1319cabe5 100644 --- a/vm/src/convert/try_from.rs +++ b/vm/src/convert/try_from.rs @@ -108,7 +108,7 @@ impl TryFromObject for std::time::Duration { use std::time::Duration; if let Some(float) = obj.payload::() { Ok(Duration::from_secs_f64(float.to_f64())) - } else if let Some(int) = vm.to_index_opt(obj.clone()) { + } else if let Some(int) = obj.try_index_opt(vm) { let sec = int? .as_bigint() .to_u64() diff --git a/vm/src/dictdatatype.rs b/vm/src/dictdatatype.rs index d9f68a797..d7a5c054d 100644 --- a/vm/src/dictdatatype.rs +++ b/vm/src/dictdatatype.rs @@ -717,7 +717,7 @@ impl DictKey for PyObject { } #[inline] fn key_as_isize(&self, vm: &VirtualMachine) -> PyResult { - vm.to_index(self)?.try_to_primitive(vm) + self.try_index(vm)?.try_to_primitive(vm) } } diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index 8faa156b1..86e648fca 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -19,6 +19,29 @@ impl PyObject { pub fn to_number(&self) -> PyNumber<'_> { PyNumber::from(self) } + + pub fn try_index_opt(&self, vm: &VirtualMachine) -> Option> { + self.to_number().index_opt(vm).transpose() + // Some(if let Some(i) = self.downcast_ref_if_exact::(vm) { + // Ok(i.to_owned()) + // } else if let Some(i) = self.payload::() { + // Ok(vm.ctx.new_bigint(i.as_bigint())) + // } else if let Some(result) = self.to_number().index(vm).transpose() { + // result + // } else { + // return None; + // }) + } + + pub fn try_index(&self, vm: &VirtualMachine) -> PyResult { + self.to_number().index(vm) + // self.try_index_opt(vm).transpose()?.ok_or_else(|| { + // vm.new_type_error(format!( + // "'{}' object cannot be interpreted as an integer", + // self.class() + // )) + // }) + } } #[derive(Default)] @@ -122,7 +145,8 @@ impl<'a> From<&'a PyObject> for PyNumber<'a> { static GLOBAL_NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods::NOT_IMPLEMENTED; Self { obj, - methods: Self::find_methods(obj).map_or(&GLOBAL_NOT_IMPLEMENTED, |m| unsafe { m.borrow_static() }), + methods: Self::find_methods(obj) + .map_or(&GLOBAL_NOT_IMPLEMENTED, |m| unsafe { m.borrow_static() }), } } } diff --git a/vm/src/sliceable.rs b/vm/src/sliceable.rs index 6f62e76f3..26c7c4ac0 100644 --- a/vm/src/sliceable.rs +++ b/vm/src/sliceable.rs @@ -275,7 +275,7 @@ impl SequenceIndex { .map(Self::Int) } else if let Some(slice) = obj.payload::() { slice.to_saturated(vm).map(Self::Slice) - } else if let Some(i) = vm.to_index_opt(obj.to_owned()) { + } else if let Some(i) = obj.try_index_opt(vm) { // TODO: __index__ for indices is no more supported? i?.try_to_primitive(vm) .map_err(|_| { @@ -465,7 +465,7 @@ fn to_isize_index(vm: &VirtualMachine, obj: &PyObject) -> PyResult if vm.is_none(obj) { return Ok(None); } - let result = vm.to_index_opt(obj.to_owned()).unwrap_or_else(|| { + let result = obj.try_index_opt(vm).unwrap_or_else(|| { Err(vm.new_type_error( "slice indices must be integers or None or have an __index__ method".to_owned(), )) diff --git a/vm/src/stdlib/builtins.rs b/vm/src/stdlib/builtins.rs index 67d402b86..8f3d99e47 100644 --- a/vm/src/stdlib/builtins.rs +++ b/vm/src/stdlib/builtins.rs @@ -719,7 +719,7 @@ mod builtins { })?; match ndigits.flatten() { Some(obj) => { - let ndigits = vm.to_index(&obj)?; + let ndigits = obj.try_index(vm)?; meth.invoke((ndigits,), vm) } None => { diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index fd154fa5f..2942031ca 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -1330,7 +1330,7 @@ mod _io { } pub fn get_offset(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { - let int = vm.to_index(&obj)?; + let int = obj.try_index(vm)?; int.as_bigint().try_into().map_err(|_| { vm.new_value_error(format!( "cannot fit '{}' into an offset-sized integer", diff --git a/vm/src/stdlib/operator.rs b/vm/src/stdlib/operator.rs index 2ee0a516a..fdfe04587 100644 --- a/vm/src/stdlib/operator.rs +++ b/vm/src/stdlib/operator.rs @@ -110,7 +110,7 @@ mod _operator { /// Return a converted to an integer. Equivalent to a.__index__(). #[pyfunction] fn index(a: PyObjectRef, vm: &VirtualMachine) -> PyResult { - vm.to_index(&a) + a.try_index(vm) } /// Return the bitwise inverse of the number obj. This is equivalent to ~obj. diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index ed4049a8d..c2bfe1743 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -349,7 +349,7 @@ impl FromArgs for DirFd { Some(o) if vm.is_none(&o) => DEFAULT_DIR_FD, None => DEFAULT_DIR_FD, Some(o) => { - let fd = vm.to_index_opt(o.clone()).unwrap_or_else(|| { + let fd = o.try_index_opt(vm).unwrap_or_else(|| { Err(vm.new_type_error(format!( "argument should be integer or None, not {}", o.class().name() @@ -1364,8 +1364,8 @@ pub(super) mod _os { divmod.class().name() )) })?; - let secs = vm.to_index(&div)?.try_to_primitive(vm)?; - let ns = vm.to_index(&rem)?.try_to_primitive(vm)?; + let secs = div.try_index(vm)?.try_to_primitive(vm)?; + let ns = rem.try_index(vm)?.try_to_primitive(vm)?; Ok(Duration::new(secs, ns)) }; // TODO: do validation to make sure this doesn't.. underflow? diff --git a/vm/src/stdlib/sre.rs b/vm/src/stdlib/sre.rs index 2b6b88d9f..a4bb7b01a 100644 --- a/vm/src/stdlib/sre.rs +++ b/vm/src/stdlib/sre.rs @@ -745,7 +745,7 @@ mod _sre { } fn get_index(&self, group: PyObjectRef, vm: &VirtualMachine) -> Option { - let i = if let Ok(i) = vm.to_index(&group) { + let i = if let Ok(i) = group.try_index(vm) { i } else { self.pattern diff --git a/vm/src/vm/vm_ops.rs b/vm/src/vm/vm_ops.rs index 1c325595c..12f940fb0 100644 --- a/vm/src/vm/vm_ops.rs +++ b/vm/src/vm/vm_ops.rs @@ -3,20 +3,12 @@ use crate::{ builtins::{PyInt, PyIntRef, PyStrInterned}, function::PyArithmeticValue, object::{AsObject, PyObject, PyObjectRef, PyResult}, - protocol::{PyIterReturn, PyNumber}, + protocol::PyIterReturn, types::PyComparisonOp, }; /// Collection of operators impl VirtualMachine { - pub fn to_index_opt(&self, obj: PyObjectRef) -> Option> { - PyNumber::from(obj.as_ref()).index_opt(self).transpose() - } - - pub fn to_index(&self, obj: &PyObject) -> PyResult { - PyNumber::from(obj).index(self) - } - #[inline] pub fn bool_eq(&self, a: &PyObject, b: &PyObject) -> PyResult { a.rich_compare_bool(b, PyComparisonOp::Eq, self) From 7a43a2ed3f95c72cd64fb271f506202fec45952d Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 24 Jul 2022 06:44:25 +0900 Subject: [PATCH 09/11] PyObject::try_index --- vm/src/builtins/int.rs | 4 +-- vm/src/protocol/number.rs | 61 +++++++++++++++------------------------ 2 files changed, 25 insertions(+), 40 deletions(-) diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 360d20113..232568ff2 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -266,9 +266,7 @@ impl Constructor for PyInt { val }; - val.to_number() - .int(vm) - .map(|x| x.as_bigint().clone()) + val.to_number().int(vm).map(|x| x.as_bigint().clone()) } } else if let OptionalArg::Present(_) = options.base { Err(vm.new_type_error("int() missing string argument".to_owned())) diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index 86e648fca..b5c0b644a 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -13,7 +13,6 @@ type UnaryFunc = AtomicCell = AtomicCell PyResult>>; - impl PyObject { #[inline] pub fn to_number(&self) -> PyNumber<'_> { @@ -21,29 +20,29 @@ impl PyObject { } pub fn try_index_opt(&self, vm: &VirtualMachine) -> Option> { - self.to_number().index_opt(vm).transpose() - // Some(if let Some(i) = self.downcast_ref_if_exact::(vm) { - // Ok(i.to_owned()) - // } else if let Some(i) = self.payload::() { - // Ok(vm.ctx.new_bigint(i.as_bigint())) - // } else if let Some(result) = self.to_number().index(vm).transpose() { - // result - // } else { - // return None; - // }) + #[allow(clippy::question_mark)] + Some(if let Some(i) = self.downcast_ref_if_exact::(vm) { + Ok(i.to_owned()) + } else if let Some(i) = self.payload::() { + Ok(vm.ctx.new_bigint(i.as_bigint())) + } else if let Some(i) = self.to_number().index(vm).transpose() { + i + } else { + return None; + }) } + #[inline] pub fn try_index(&self, vm: &VirtualMachine) -> PyResult { - self.to_number().index(vm) - // self.try_index_opt(vm).transpose()?.ok_or_else(|| { - // vm.new_type_error(format!( - // "'{}' object cannot be interpreted as an integer", - // self.class() - // )) - // }) + self.try_index_opt(vm).transpose()?.ok_or_else(|| { + vm.new_type_error(format!( + "'{}' object cannot be interpreted as an integer", + self.class() + )) + }) } } - + #[derive(Default)] pub struct PyNumberMethods { /* Number implementations must check *both* @@ -213,7 +212,7 @@ impl PyNumber<'_> { Ok(ret) } } else if self.methods().index.load().is_some() { - self.index(vm) + self.obj.try_index(vm) } else if let Ok(Ok(f)) = vm.get_special_method(self.obj.to_owned(), identifier!(vm, __trunc__)) { @@ -225,7 +224,7 @@ impl PyNumber<'_> { // vm, // )?; let ret = f.invoke((), vm)?; - ret.to_number().index(vm).map_err(|_| { + ret.try_index(vm).map_err(|_| { vm.new_type_error(format!( "__trunc__ returned non-Integral (type {})", ret.class() @@ -248,12 +247,9 @@ impl PyNumber<'_> { } } - pub fn index_opt(&self, vm: &VirtualMachine) -> PyResult> { - if let Some(i) = self.obj.downcast_ref_if_exact::(vm) { - Ok(Some(i.to_owned())) - } else if let Some(i) = self.obj.payload::() { - Ok(Some(vm.ctx.new_bigint(i.as_bigint()))) - } else if let Some(f) = self.methods().index.load() { + #[inline] + pub fn index(&self, vm: &VirtualMachine) -> PyResult> { + if let Some(f) = self.methods().index.load() { let ret = f(self, vm)?; if !ret.class().is(PyInt::class(vm)) { warnings::warn( @@ -276,15 +272,6 @@ impl PyNumber<'_> { } } - pub fn index(&self, vm: &VirtualMachine) -> PyResult { - self.index_opt(vm)?.ok_or_else(|| { - vm.new_type_error(format!( - "'{}' object cannot be interpreted as an integer", - self.obj.class() - )) - }) - } - pub fn float_opt(&self, vm: &VirtualMachine) -> PyResult>> { if let Some(float) = self.obj.downcast_ref_if_exact::(vm) { Ok(Some(float.to_owned())) @@ -307,7 +294,7 @@ impl PyNumber<'_> { Ok(Some(ret)) } } else if self.methods().index.load().is_some() { - let i = self.index(vm)?; + let i = self.obj.try_index(vm)?; let value = int::try_to_float(i.as_bigint(), vm)?; Ok(Some(vm.ctx.new_float(value))) } else if let Some(value) = self.obj.downcast_ref::() { From b96dddfed14868331a6a4b2caa0b9bb23ed2ed38 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 24 Jul 2022 07:18:03 +0900 Subject: [PATCH 10/11] PyObject::try_int --- vm/src/builtins/int.rs | 2 +- vm/src/protocol/number.rs | 116 +++++++++++++++++++++----------------- 2 files changed, 65 insertions(+), 53 deletions(-) diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 232568ff2..991b3d7ed 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -266,7 +266,7 @@ impl Constructor for PyInt { val }; - val.to_number().int(vm).map(|x| x.as_bigint().clone()) + val.try_int(vm).map(|x| x.as_bigint().clone()) } } else if let OptionalArg::Present(_) = options.base { Err(vm.new_type_error("int() missing string argument".to_owned())) diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index b5c0b644a..da963b6ed 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -41,6 +41,62 @@ impl PyObject { )) }) } + + pub fn try_int(&self, vm: &VirtualMachine) -> PyResult { + fn try_convert(obj: &PyObject, lit: &[u8], vm: &VirtualMachine) -> PyResult { + let base = 10; + match int::bytes_to_int(lit, base) { + Some(i) => Ok(PyInt::from(i).into_ref(vm)), + None => Err(vm.new_value_error(format!( + "invalid literal for int() with base {}: {}", + base, + obj.repr(vm)?, + ))), + } + } + + if let Some(i) = self.downcast_ref_if_exact::(vm) { + Ok(i.to_owned()) + } else { + let number = self.to_number(); + if let Some(i) = number.int(vm)? { + Ok(i) + } else if let Some(i) = self.try_index_opt(vm) { + i + } else if let Ok(Ok(f)) = + vm.get_special_method(self.to_owned(), identifier!(vm, __trunc__)) + { + // TODO: Deprecate in 3.11 + // warnings::warn( + // vm.ctx.exceptions.deprecation_warning.clone(), + // "The delegation of int() to __trunc__ is deprecated.".to_owned(), + // 1, + // vm, + // )?; + let ret = f.invoke((), vm)?; + ret.try_index(vm).map_err(|_| { + vm.new_type_error(format!( + "__trunc__ returned non-Integral (type {})", + ret.class() + )) + }) + } else if let Some(s) = self.payload::() { + try_convert(self, s.as_str().as_bytes(), vm) + } else if let Some(bytes) = self.payload::() { + try_convert(self, bytes, vm) + } else if let Some(bytearray) = self.payload::() { + try_convert(self, &bytearray.borrow_buf(), vm) + } else if let Ok(buffer) = ArgBytesLike::try_from_borrowed_object(vm, self) { + // TODO: replace to PyBuffer + try_convert(self, &buffer.borrow_buf(), vm) + } else { + Err(vm.new_type_error(format!( + "int() argument must be a string, a bytes-like object or a real number, not '{}'", + self.class() + ))) + } + } + } } #[derive(Default)] @@ -178,24 +234,11 @@ impl PyNumber<'_> { self.methods().index.load().is_some() } - pub fn int(&self, vm: &VirtualMachine) -> PyResult { - fn try_convert(obj: &PyObject, lit: &[u8], vm: &VirtualMachine) -> PyResult { - let base = 10; - match int::bytes_to_int(lit, base) { - Some(i) => Ok(PyInt::from(i).into_ref(vm)), - None => Err(vm.new_value_error(format!( - "invalid literal for int() with base {}: {}", - base, - obj.repr(vm)?, - ))), - } - } - - if let Some(i) = self.obj.downcast_ref_if_exact::(vm) { - Ok(i.to_owned()) - } else if let Some(f) = self.methods().int.load() { + #[inline] + pub fn int(&self, vm: &VirtualMachine) -> PyResult> { + Ok(if let Some(f) = self.methods().int.load() { let ret = f(self, vm)?; - if !ret.class().is(PyInt::class(vm)) { + Some(if !ret.class().is(PyInt::class(vm)) { warnings::warn( vm.ctx.exceptions.deprecation_warning, format!( @@ -207,44 +250,13 @@ impl PyNumber<'_> { 1, vm, )?; - Ok(vm.ctx.new_bigint(ret.as_bigint())) + vm.ctx.new_bigint(ret.as_bigint()) } else { - Ok(ret) - } - } else if self.methods().index.load().is_some() { - self.obj.try_index(vm) - } else if let Ok(Ok(f)) = - vm.get_special_method(self.obj.to_owned(), identifier!(vm, __trunc__)) - { - // TODO: Deprecate in 3.11 - // warnings::warn( - // vm.ctx.exceptions.deprecation_warning.clone(), - // "The delegation of int() to __trunc__ is deprecated.".to_owned(), - // 1, - // vm, - // )?; - let ret = f.invoke((), vm)?; - ret.try_index(vm).map_err(|_| { - vm.new_type_error(format!( - "__trunc__ returned non-Integral (type {})", - ret.class() - )) + ret }) - } else if let Some(s) = self.obj.payload::() { - try_convert(self.obj, s.as_str().as_bytes(), vm) - } else if let Some(bytes) = self.obj.payload::() { - try_convert(self.obj, bytes, vm) - } else if let Some(bytearray) = self.obj.payload::() { - try_convert(self.obj, &bytearray.borrow_buf(), vm) - } else if let Ok(buffer) = ArgBytesLike::try_from_borrowed_object(vm, self.obj) { - // TODO: replace to PyBuffer - try_convert(self.obj, &buffer.borrow_buf(), vm) } else { - Err(vm.new_type_error(format!( - "int() argument must be a string, a bytes-like object or a real number, not '{}'", - self.obj.class() - ))) - } + None + }) } #[inline] From 370c4f7f605b67d4c41499aff80c108c1d00d3b6 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 24 Jul 2022 07:34:43 +0900 Subject: [PATCH 11/11] PyObject::try_float --- stdlib/src/math.rs | 4 +-- vm/src/builtins/complex.rs | 2 +- vm/src/builtins/float.rs | 2 +- vm/src/function/number.rs | 2 +- vm/src/protocol/number.rs | 55 +++++++++++++++++++++++--------------- 5 files changed, 39 insertions(+), 26 deletions(-) diff --git a/stdlib/src/math.rs b/stdlib/src/math.rs index d0604ea69..d4ad0f55c 100644 --- a/stdlib/src/math.rs +++ b/stdlib/src/math.rs @@ -454,7 +454,7 @@ mod math { fn ceil(x: PyObjectRef, vm: &VirtualMachine) -> PyResult { let result_or_err = try_magic_method(identifier!(vm, __ceil__), vm, &x); if result_or_err.is_err() { - if let Ok(Some(v)) = x.to_number().float_opt(vm) { + if let Ok(Some(v)) = x.try_float_opt(vm) { let v = try_f64_to_bigint(v.to_f64().ceil(), vm)?; return Ok(vm.ctx.new_int(v).into()); } @@ -466,7 +466,7 @@ mod math { fn floor(x: PyObjectRef, vm: &VirtualMachine) -> PyResult { let result_or_err = try_magic_method(identifier!(vm, __floor__), vm, &x); if result_or_err.is_err() { - if let Ok(Some(v)) = x.to_number().float_opt(vm) { + if let Ok(Some(v)) = x.try_float_opt(vm) { let v = try_f64_to_bigint(v.to_f64().floor(), vm)?; return Ok(vm.ctx.new_int(v).into()); } diff --git a/vm/src/builtins/complex.rs b/vm/src/builtins/complex.rs index f48080f0d..333269e4d 100644 --- a/vm/src/builtins/complex.rs +++ b/vm/src/builtins/complex.rs @@ -67,7 +67,7 @@ impl PyObjectRef { if let Some(complex) = self.payload_if_subclass::(vm) { return Ok(Some((complex.value, true))); } - if let Some(float) = self.to_number().float_opt(vm)? { + if let Some(float) = self.try_float_opt(vm)? { return Ok(Some((Complex64::new(float.to_f64(), 0.0), false))); } Ok(None) diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index d152dcb11..ee4837090 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -142,7 +142,7 @@ impl Constructor for PyFloat { let float_val = match arg { OptionalArg::Missing => 0.0, OptionalArg::Present(val) => { - if let Some(f) = val.to_number().float_opt(vm)? { + if let Some(f) = val.try_float_opt(vm)? { f.value } else { float_from_string(val, vm)? diff --git a/vm/src/function/number.rs b/vm/src/function/number.rs index 2c7790691..12f6d70cc 100644 --- a/vm/src/function/number.rs +++ b/vm/src/function/number.rs @@ -82,7 +82,7 @@ impl Deref for ArgIntoFloat { impl TryFromObject for ArgIntoFloat { // Equivalent to PyFloat_AsDouble. fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { - let value = obj.to_number().float(vm)?.to_f64(); + let value = obj.try_float(vm)?.to_f64(); Ok(ArgIntoFloat { value }) } } diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index da963b6ed..da144dfae 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -97,6 +97,32 @@ impl PyObject { } } } + + pub fn try_float_opt(&self, vm: &VirtualMachine) -> PyResult>> { + let value = if let Some(float) = self.downcast_ref_if_exact::(vm) { + Some(float.to_owned()) + } else { + let number = self.to_number(); + #[allow(clippy::manual_map)] + if let Some(f) = number.float(vm)? { + Some(f) + } else if let Some(i) = self.try_index_opt(vm) { + let value = int::try_to_float(i?.as_bigint(), vm)?; + Some(vm.ctx.new_float(value)) + } else if let Some(value) = self.downcast_ref::() { + Some(vm.ctx.new_float(value.to_f64())) + } else { + None + } + }; + Ok(value) + } + + #[inline] + pub fn try_float(&self, vm: &VirtualMachine) -> PyResult> { + self.try_float_opt(vm)? + .ok_or_else(|| vm.new_type_error(format!("must be real number, not {}", self.class()))) + } } #[derive(Default)] @@ -284,12 +310,11 @@ impl PyNumber<'_> { } } - pub fn float_opt(&self, vm: &VirtualMachine) -> PyResult>> { - if let Some(float) = self.obj.downcast_ref_if_exact::(vm) { - Ok(Some(float.to_owned())) - } else if let Some(f) = self.methods().float.load() { + #[inline] + pub fn float(&self, vm: &VirtualMachine) -> PyResult>> { + Ok(if let Some(f) = self.methods().float.load() { let ret = f(self, vm)?; - if !ret.class().is(PyFloat::class(vm)) { + Some(if !ret.class().is(PyFloat::class(vm)) { warnings::warn( vm.ctx.exceptions.deprecation_warning, format!( @@ -301,24 +326,12 @@ impl PyNumber<'_> { 1, vm, )?; - Ok(Some(vm.ctx.new_float(ret.to_f64()))) + vm.ctx.new_float(ret.to_f64()) } else { - Ok(Some(ret)) - } - } else if self.methods().index.load().is_some() { - let i = self.obj.try_index(vm)?; - let value = int::try_to_float(i.as_bigint(), vm)?; - Ok(Some(vm.ctx.new_float(value))) - } else if let Some(value) = self.obj.downcast_ref::() { - Ok(Some(vm.ctx.new_float(value.to_f64()))) + ret + }) } else { - Ok(None) - } - } - - pub fn float(&self, vm: &VirtualMachine) -> PyResult> { - self.float_opt(vm)?.ok_or_else(|| { - vm.new_type_error(format!("must be real number, not {}", self.obj.class())) + None }) } }