From a3565d02e3931552bc5e3e77f5654884b316bba2 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Wed, 15 Mar 2023 20:14:22 +0200 Subject: [PATCH 01/16] move PyNumberSlots to protocol::number --- vm/src/protocol/mod.rs | 3 +- vm/src/protocol/number.rs | 124 ++++++++++++++++++++++++++++++++++++++ vm/src/types/slot.rs | 123 +------------------------------------ 3 files changed, 127 insertions(+), 123 deletions(-) diff --git a/vm/src/protocol/mod.rs b/vm/src/protocol/mod.rs index a41d843e9b..dbbb39fbce 100644 --- a/vm/src/protocol/mod.rs +++ b/vm/src/protocol/mod.rs @@ -11,6 +11,7 @@ pub use callable::PyCallable; pub use iter::{PyIter, PyIterIter, PyIterReturn}; pub use mapping::{PyMapping, PyMappingMethods}; pub use number::{ - PyNumber, PyNumberBinaryFunc, PyNumberBinaryOp, PyNumberMethods, PyNumberUnaryFunc, + PyNumber, PyNumberBinaryFunc, PyNumberBinaryOp, PyNumberMethods, PyNumberSlots, + PyNumberUnaryFunc, }; pub use sequence::{PySequence, PySequenceMethods}; diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index 12bc10e7ba..2b0376537d 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -1,3 +1,5 @@ +use crossbeam_utils::atomic::AtomicCell; + use crate::{ builtins::{ int, type_::PointerSlot, PyByteArray, PyBytes, PyComplex, PyFloat, PyInt, PyIntRef, PyStr, @@ -263,6 +265,128 @@ pub enum PyNumberBinaryOp { InplaceMatrixMultiply, } +#[derive(Default)] +pub struct PyNumberSlots { + pub add: AtomicCell>, + pub subtract: AtomicCell>, + pub multiply: AtomicCell>, + pub remainder: AtomicCell>, + pub divmod: AtomicCell>, + pub power: AtomicCell>, + pub negative: AtomicCell>, + pub positive: AtomicCell>, + pub absolute: AtomicCell>, + pub boolean: AtomicCell>>, + pub invert: AtomicCell>, + pub lshift: AtomicCell>, + pub rshift: AtomicCell>, + pub and: AtomicCell>, + pub xor: AtomicCell>, + pub or: AtomicCell>, + pub int: AtomicCell>>>, + pub float: AtomicCell>>>, + + pub right_add: AtomicCell>, + pub right_subtract: AtomicCell>, + pub right_multiply: AtomicCell>, + pub right_remainder: AtomicCell>, + pub right_divmod: AtomicCell>, + pub right_power: AtomicCell>, + pub right_lshift: AtomicCell>, + pub right_rshift: AtomicCell>, + pub right_and: AtomicCell>, + pub right_xor: AtomicCell>, + pub right_or: AtomicCell>, + + pub inplace_add: AtomicCell>, + pub inplace_subtract: AtomicCell>, + pub inplace_multiply: AtomicCell>, + pub inplace_remainder: AtomicCell>, + pub inplace_power: AtomicCell>, + pub inplace_lshift: AtomicCell>, + pub inplace_rshift: AtomicCell>, + pub inplace_and: AtomicCell>, + pub inplace_xor: AtomicCell>, + pub inplace_or: AtomicCell>, + + pub floor_divide: AtomicCell>, + pub true_divide: AtomicCell>, + pub right_floor_divide: AtomicCell>, + pub right_true_divide: AtomicCell>, + pub inplace_floor_divide: AtomicCell>, + pub inplace_true_divide: AtomicCell>, + + pub index: AtomicCell>>>, + + pub matrix_multiply: AtomicCell>, + pub right_matrix_multiply: AtomicCell>, + pub inplace_matrix_multiply: AtomicCell>, +} + +impl PyNumberSlots { + pub fn left_binary_op( + &self, + op_slot: PyNumberBinaryOp, + ) -> PyResult> { + use PyNumberBinaryOp::*; + let binary_op = match op_slot { + Add => self.add.load(), + Subtract => self.subtract.load(), + Multiply => self.multiply.load(), + Remainder => self.remainder.load(), + Divmod => self.divmod.load(), + Power => self.power.load(), + Lshift => self.lshift.load(), + Rshift => self.rshift.load(), + And => self.and.load(), + Xor => self.xor.load(), + Or => self.or.load(), + InplaceAdd => self.inplace_add.load(), + InplaceSubtract => self.inplace_subtract.load(), + InplaceMultiply => self.inplace_multiply.load(), + InplaceRemainder => self.inplace_remainder.load(), + InplacePower => self.inplace_power.load(), + InplaceLshift => self.inplace_lshift.load(), + InplaceRshift => self.inplace_rshift.load(), + InplaceAnd => self.inplace_and.load(), + InplaceXor => self.inplace_xor.load(), + InplaceOr => self.inplace_or.load(), + FloorDivide => self.floor_divide.load(), + TrueDivide => self.true_divide.load(), + InplaceFloorDivide => self.inplace_floor_divide.load(), + InplaceTrueDivide => self.inplace_true_divide.load(), + MatrixMultiply => self.matrix_multiply.load(), + InplaceMatrixMultiply => self.inplace_matrix_multiply.load(), + }; + Ok(binary_op) + } + + pub fn right_binary_op( + &self, + op_slot: PyNumberBinaryOp, + ) -> PyResult> { + use PyNumberBinaryOp::*; + let binary_op = match op_slot { + Add => self.right_add.load(), + Subtract => self.right_subtract.load(), + Multiply => self.right_multiply.load(), + Remainder => self.right_remainder.load(), + Divmod => self.right_divmod.load(), + Power => self.right_power.load(), + Lshift => self.right_lshift.load(), + Rshift => self.right_rshift.load(), + And => self.right_and.load(), + Xor => self.right_xor.load(), + Or => self.right_or.load(), + FloorDivide => self.right_floor_divide.load(), + TrueDivide => self.right_true_divide.load(), + MatrixMultiply => self.right_matrix_multiply.load(), + _ => None, + }; + Ok(binary_op) + } +} + #[derive(Copy, Clone)] pub struct PyNumber<'a> { pub obj: &'a PyObject, diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index d1b304d2c6..80e77cd2cf 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -9,7 +9,7 @@ use crate::{ identifier, protocol::{ PyBuffer, PyIterReturn, PyMapping, PyMappingMethods, PyNumber, PyNumberBinaryFunc, - PyNumberBinaryOp, PyNumberMethods, PyNumberUnaryFunc, PySequence, PySequenceMethods, + PyNumberBinaryOp, PyNumberMethods, PyNumberUnaryFunc, PySequence, PySequenceMethods, PyNumberSlots, }, vm::Context, AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, @@ -109,127 +109,6 @@ impl std::fmt::Debug for PyTypeSlots { } } -#[derive(Default)] -pub struct PyNumberSlots { - pub add: AtomicCell>, - pub subtract: AtomicCell>, - pub multiply: AtomicCell>, - pub remainder: AtomicCell>, - pub divmod: AtomicCell>, - pub power: AtomicCell>, - pub negative: AtomicCell>, - pub positive: AtomicCell>, - pub absolute: AtomicCell>, - pub boolean: AtomicCell>>, - pub invert: AtomicCell>, - pub lshift: AtomicCell>, - pub rshift: AtomicCell>, - pub and: AtomicCell>, - pub xor: AtomicCell>, - pub or: AtomicCell>, - pub int: AtomicCell>>>, - pub float: AtomicCell>>>, - - pub right_add: AtomicCell>, - pub right_subtract: AtomicCell>, - pub right_multiply: AtomicCell>, - pub right_remainder: AtomicCell>, - pub right_divmod: AtomicCell>, - pub right_power: AtomicCell>, - pub right_lshift: AtomicCell>, - pub right_rshift: AtomicCell>, - pub right_and: AtomicCell>, - pub right_xor: AtomicCell>, - pub right_or: AtomicCell>, - - pub inplace_add: AtomicCell>, - pub inplace_subtract: AtomicCell>, - pub inplace_multiply: AtomicCell>, - pub inplace_remainder: AtomicCell>, - pub inplace_power: AtomicCell>, - pub inplace_lshift: AtomicCell>, - pub inplace_rshift: AtomicCell>, - pub inplace_and: AtomicCell>, - pub inplace_xor: AtomicCell>, - pub inplace_or: AtomicCell>, - - pub floor_divide: AtomicCell>, - pub true_divide: AtomicCell>, - pub right_floor_divide: AtomicCell>, - pub right_true_divide: AtomicCell>, - pub inplace_floor_divide: AtomicCell>, - pub inplace_true_divide: AtomicCell>, - - pub index: AtomicCell>>>, - - pub matrix_multiply: AtomicCell>, - pub right_matrix_multiply: AtomicCell>, - pub inplace_matrix_multiply: AtomicCell>, -} - -impl PyNumberSlots { - pub fn left_binary_op( - &self, - op_slot: PyNumberBinaryOp, - ) -> PyResult> { - use PyNumberBinaryOp::*; - let binary_op = match op_slot { - Add => self.add.load(), - Subtract => self.subtract.load(), - Multiply => self.multiply.load(), - Remainder => self.remainder.load(), - Divmod => self.divmod.load(), - Power => self.power.load(), - Lshift => self.lshift.load(), - Rshift => self.rshift.load(), - And => self.and.load(), - Xor => self.xor.load(), - Or => self.or.load(), - InplaceAdd => self.inplace_add.load(), - InplaceSubtract => self.inplace_subtract.load(), - InplaceMultiply => self.inplace_multiply.load(), - InplaceRemainder => self.inplace_remainder.load(), - InplacePower => self.inplace_power.load(), - InplaceLshift => self.inplace_lshift.load(), - InplaceRshift => self.inplace_rshift.load(), - InplaceAnd => self.inplace_and.load(), - InplaceXor => self.inplace_xor.load(), - InplaceOr => self.inplace_or.load(), - FloorDivide => self.floor_divide.load(), - TrueDivide => self.true_divide.load(), - InplaceFloorDivide => self.inplace_floor_divide.load(), - InplaceTrueDivide => self.inplace_true_divide.load(), - MatrixMultiply => self.matrix_multiply.load(), - InplaceMatrixMultiply => self.inplace_matrix_multiply.load(), - }; - Ok(binary_op) - } - - pub fn right_binary_op( - &self, - op_slot: PyNumberBinaryOp, - ) -> PyResult> { - use PyNumberBinaryOp::*; - let binary_op = match op_slot { - Add => self.right_add.load(), - Subtract => self.right_subtract.load(), - Multiply => self.right_multiply.load(), - Remainder => self.right_remainder.load(), - Divmod => self.right_divmod.load(), - Power => self.right_power.load(), - Lshift => self.right_lshift.load(), - Rshift => self.right_rshift.load(), - And => self.right_and.load(), - Xor => self.right_xor.load(), - Or => self.right_or.load(), - FloorDivide => self.right_floor_divide.load(), - TrueDivide => self.right_true_divide.load(), - MatrixMultiply => self.right_matrix_multiply.load(), - _ => None, - }; - Ok(binary_op) - } -} bitflags! { #[non_exhaustive] From 044c0ba9f2d21723cf6ef460d5922277286e3286 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Wed, 15 Mar 2023 21:18:29 +0200 Subject: [PATCH 02/16] refactor PyNumberBinaryFunc --- vm/src/builtins/bool.rs | 12 +-- vm/src/builtins/bytearray.rs | 6 +- vm/src/builtins/bytes.rs | 6 +- vm/src/builtins/complex.rs | 18 ++--- vm/src/builtins/dict.rs | 138 ++++++++++---------------------- vm/src/builtins/float.rs | 38 ++++----- vm/src/builtins/int.rs | 32 ++++---- vm/src/builtins/mappingproxy.rs | 12 +-- vm/src/builtins/set.rs | 96 +++++++++------------- vm/src/builtins/str.rs | 6 +- vm/src/builtins/type.rs | 4 +- vm/src/builtins/union.rs | 4 +- vm/src/protocol/number.rs | 15 +++- vm/src/types/slot.rs | 4 +- vm/src/vm/vm_ops.rs | 8 +- 15 files changed, 171 insertions(+), 228 deletions(-) diff --git a/vm/src/builtins/bool.rs b/vm/src/builtins/bool.rs index e8d5068273..2c11d66caf 100644 --- a/vm/src/builtins/bool.rs +++ b/vm/src/builtins/bool.rs @@ -164,14 +164,14 @@ impl PyBool { impl AsNumber for PyBool { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - and: Some(|number, other, vm| { - PyBool::and(number.obj.to_owned(), other.to_owned(), vm).to_pyresult(vm) + and: Some(|a, b, vm| { + PyBool::and(a.to_owned(), b.to_owned(), vm).to_pyresult(vm) }), - xor: Some(|number, other, vm| { - PyBool::xor(number.obj.to_owned(), other.to_owned(), vm).to_pyresult(vm) + xor: Some(|a, b, vm| { + PyBool::xor(a.to_owned(), b.to_owned(), vm).to_pyresult(vm) }), - or: Some(|number, other, vm| { - PyBool::or(number.obj.to_owned(), other.to_owned(), vm).to_pyresult(vm) + or: Some(|a, b, vm| { + PyBool::or(a.to_owned(), b.to_owned(), vm).to_pyresult(vm) }), ..PyInt::AS_NUMBER }; diff --git a/vm/src/builtins/bytearray.rs b/vm/src/builtins/bytearray.rs index a835d7a763..c7d78ff476 100644 --- a/vm/src/builtins/bytearray.rs +++ b/vm/src/builtins/bytearray.rs @@ -843,9 +843,9 @@ impl AsSequence for PyByteArray { impl AsNumber for PyByteArray { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - remainder: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.mod_(other.to_owned(), vm).to_pyresult(vm) + remainder: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.mod_(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } diff --git a/vm/src/builtins/bytes.rs b/vm/src/builtins/bytes.rs index 5715d3f3bb..b649c0ae06 100644 --- a/vm/src/builtins/bytes.rs +++ b/vm/src/builtins/bytes.rs @@ -615,9 +615,9 @@ impl AsSequence for PyBytes { impl AsNumber for PyBytes { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - remainder: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.mod_(other.to_owned(), vm).to_pyresult(vm) + remainder: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.mod_(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } diff --git a/vm/src/builtins/complex.rs b/vm/src/builtins/complex.rs index 04d433c307..f10f3c0466 100644 --- a/vm/src/builtins/complex.rs +++ b/vm/src/builtins/complex.rs @@ -418,16 +418,16 @@ impl Hashable for PyComplex { impl AsNumber for PyComplex { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - add: Some(|number, other, vm| { - PyComplex::number_op(number, other, |a, b, _vm| a + b, vm) + add: Some(|a, b, vm| { + PyComplex::number_op(a, b, |a, b, _vm| a + b, vm) }), - subtract: Some(|number, other, vm| { - PyComplex::number_op(number, other, |a, b, _vm| a - b, vm) + subtract: Some(|a, b, vm| { + PyComplex::number_op(a, b, |a, b, _vm| a - b, vm) }), - multiply: Some(|number, other, vm| { - PyComplex::number_op(number, other, |a, b, _vm| a * b, vm) + multiply: Some(|a, b, vm| { + PyComplex::number_op(a, b, |a, b, _vm| a * b, vm) }), - power: Some(|number, other, vm| PyComplex::number_op(number, other, inner_pow, vm)), + power: Some(|a, b, vm| PyComplex::number_op(a, b, inner_pow, vm)), negative: Some(|number, vm| { let value = PyComplex::number_downcast(number).value; (-value).to_pyresult(vm) @@ -494,12 +494,12 @@ impl Representable for PyComplex { } impl PyComplex { - fn number_op(number: PyNumber, other: &PyObject, op: F, vm: &VirtualMachine) -> PyResult + fn number_op(a: &PyObject, b: &PyObject, op: F, vm: &VirtualMachine) -> PyResult where F: FnOnce(Complex64, Complex64, &VirtualMachine) -> R, R: ToPyResult, { - if let (Some(a), Some(b)) = (to_op_complex(number.obj, vm)?, to_op_complex(other, vm)?) { + if let (Some(a), Some(b)) = (to_op_complex(a, vm)?, to_op_complex(b, vm)?) { op(a, b, vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index 74d71ddac1..dbf058cb15 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -472,16 +472,16 @@ impl AsSequence for PyDict { impl AsNumber for PyDict { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - or: Some(|num, args, vm| { - if let Some(num) = num.obj.downcast_ref::() { - PyDict::or(num, args.to_pyobject(vm), vm) + or: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + PyDict::or(a, b.to_pyobject(vm), vm) } else { Ok(vm.ctx.not_implemented()) } }), - inplace_or: Some(|num, args, vm| { - if let Some(num) = num.obj.downcast_ref::() { - PyDict::ior(num.to_owned(), args.to_pyobject(vm), vm).map(|d| d.into()) + inplace_or: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + PyDict::ior(a.to_owned(), b.to_pyobject(vm), vm).map(|d| d.into()) } else { Ok(vm.ctx.not_implemented()) } @@ -1169,51 +1169,10 @@ impl AsSequence for PyDictKeys { impl AsNumber for PyDictKeys { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - subtract: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num - .difference(ArgIterable::try_from_object(vm, args.to_owned())?, vm)?, - } - .into_pyobject(vm)) - }), - and: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num - .intersection(ArgIterable::try_from_object(vm, args.to_owned())?, vm)?, - } - .into_pyobject(vm)) - }), - xor: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num.symmetric_difference( - ArgIterable::try_from_object(vm, args.to_owned())?, - vm, - )?, - } - .into_pyobject(vm)) - }), - or: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num.union(ArgIterable::try_from_object(vm, args.to_owned())?, vm)?, - } - .into_pyobject(vm)) - }), + subtract: Some(inner_set_number_subtract), + add: Some(inner_set_number_add), + xor: Some(inner_set_number_xor), + or: Some(inner_set_number_or), ..PyNumberMethods::NOT_IMPLEMENTED }; &AS_NUMBER @@ -1288,51 +1247,10 @@ impl AsSequence for PyDictItems { impl AsNumber for PyDictItems { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - subtract: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num - .difference(ArgIterable::try_from_object(vm, args.to_owned())?, vm)?, - } - .into_pyobject(vm)) - }), - and: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num - .intersection(ArgIterable::try_from_object(vm, args.to_owned())?, vm)?, - } - .into_pyobject(vm)) - }), - xor: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num.symmetric_difference( - ArgIterable::try_from_object(vm, args.to_owned())?, - vm, - )?, - } - .into_pyobject(vm)) - }), - or: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num.union(ArgIterable::try_from_object(vm, args.to_owned())?, vm)?, - } - .into_pyobject(vm)) - }), + subtract: Some(inner_set_number_subtract), + and: Some(inner_set_number_add), + xor: Some(inner_set_number_xor), + or: Some(inner_set_number_or), ..PyNumberMethods::NOT_IMPLEMENTED }; &AS_NUMBER @@ -1358,6 +1276,34 @@ impl AsSequence for PyDictValues { } } +fn inner_set_number_op(a: &PyObject, b: &PyObject, f: F, vm: &VirtualMachine) -> PyResult +where + F: FnOnce(PySetInner, ArgIterable) -> PyResult, +{ + let a = PySetInner::from_iter( + ArgIterable::try_from_object(vm, a.to_owned())?.iter(vm)?, + vm, + )?; + let b = ArgIterable::try_from_object(vm, b.to_owned())?; + Ok(PySet { inner: f(a, b)? }.into_pyobject(vm)) +} + +fn inner_set_number_subtract(a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult { + inner_set_number_op(a, b, |a, b| a.difference(b, vm), vm) +} + +fn inner_set_number_add(a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult { + inner_set_number_op(a, b, |a, b| a.intersection(b, vm), vm) +} + +fn inner_set_number_xor(a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult { + inner_set_number_op(a, b, |a, b| a.symmetric_difference(b, vm), vm) +} + +fn inner_set_number_or(a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult { + inner_set_number_op(a, b, |a, b| a.union(b, vm), vm) +} + pub(crate) fn init(context: &Context) { PyDict::extend_class(context, context.types.dict_type); PyDictKeys::extend_class(context, context.types.dict_keys_type); diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index e97082eed0..08640fa863 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -544,29 +544,29 @@ impl Hashable for PyFloat { impl AsNumber for PyFloat { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - add: Some(|num, other, vm| PyFloat::number_op(num, other, |a, b, _vm| a + b, vm)), - subtract: Some(|num, other, vm| PyFloat::number_op(num, other, |a, b, _vm| a - b, vm)), - multiply: Some(|num, other, vm| PyFloat::number_op(num, other, |a, b, _vm| a * b, vm)), - remainder: Some(|num, other, vm| PyFloat::number_op(num, other, inner_mod, vm)), - divmod: Some(|num, other, vm| PyFloat::number_op(num, other, inner_divmod, vm)), - power: Some(|num, other, vm| PyFloat::number_op(num, other, float_pow, vm)), - negative: Some(|num, vm| { - let value = PyFloat::number_downcast(num).value; + add: Some(|a, b, vm| PyFloat::number_op(a, b, |a, b, _vm| a + b, vm)), + subtract: Some(|a, b, vm| PyFloat::number_op(a, b, |a, b, _vm| a - b, vm)), + multiply: Some(|a, b, vm| PyFloat::number_op(a, b, |a, b, _vm| a * b, vm)), + remainder: Some(|a, b, vm| PyFloat::number_op(a, b, inner_mod, vm)), + divmod: Some(|a, b, vm| PyFloat::number_op(a, b, inner_divmod, vm)), + power: Some(|a, b, vm| PyFloat::number_op(a, b, float_pow, vm)), + negative: Some(|a, vm| { + let value = PyFloat::number_downcast(a).value; (-value).to_pyresult(vm) }), - positive: Some(|num, vm| PyFloat::number_downcast_exact(num, vm).to_pyresult(vm)), - absolute: Some(|num, vm| { - let value = PyFloat::number_downcast(num).value; + positive: Some(|a, vm| PyFloat::number_downcast_exact(a, vm).to_pyresult(vm)), + absolute: Some(|a, vm| { + let value = PyFloat::number_downcast(a).value; value.abs().to_pyresult(vm) }), - boolean: Some(|num, _vm| Ok(PyFloat::number_downcast(num).value.is_zero())), - int: Some(|num, vm| { - let value = PyFloat::number_downcast(num).value; + boolean: Some(|a, _vm| Ok(PyFloat::number_downcast(a).value.is_zero())), + int: Some(|a, vm| { + let value = PyFloat::number_downcast(a).value; try_to_bigint(value, vm).map(|x| vm.ctx.new_int(x)) }), - float: Some(|num, vm| Ok(PyFloat::number_downcast_exact(num, vm))), - floor_divide: Some(|num, other, vm| PyFloat::number_op(num, other, inner_floordiv, vm)), - true_divide: Some(|num, other, vm| PyFloat::number_op(num, other, inner_div, vm)), + float: Some(|a, vm| Ok(PyFloat::number_downcast_exact(a, vm))), + floor_divide: Some(|a, b, vm| PyFloat::number_op(a, b, inner_floordiv, vm)), + true_divide: Some(|a, b, vm| PyFloat::number_op(a, b, inner_div, vm)), ..PyNumberMethods::NOT_IMPLEMENTED }; &AS_NUMBER @@ -586,12 +586,12 @@ impl Representable for PyFloat { } impl PyFloat { - fn number_op(number: PyNumber, other: &PyObject, op: F, vm: &VirtualMachine) -> PyResult + fn number_op(a: &PyObject, b: &PyObject, op: F, vm: &VirtualMachine) -> PyResult where F: FnOnce(f64, f64, &VirtualMachine) -> R, R: ToPyResult, { - if let (Some(a), Some(b)) = (to_op_float(number.obj, vm)?, to_op_float(other, vm)?) { + if let (Some(a), Some(b)) = (to_op_float(a, vm)?, to_op_float(b, vm)?) { op(a, b, vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 46b81de56b..db63c07831 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -743,39 +743,39 @@ impl AsNumber for PyInt { impl PyInt { pub(super) const AS_NUMBER: PyNumberMethods = PyNumberMethods { - add: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a + b, vm)), - subtract: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a - b, vm)), - multiply: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a * b, vm)), - remainder: Some(|num, other, vm| PyInt::number_op(num, other, inner_mod, vm)), - divmod: Some(|num, other, vm| PyInt::number_op(num, other, inner_divmod, vm)), - power: Some(|num, other, vm| PyInt::number_op(num, other, inner_pow, vm)), + add: Some(|a, b, vm| PyInt::number_op(a, b, |a, b, _vm| a + b, vm)), + subtract: Some(|a, b, vm| PyInt::number_op(a, b, |a, b, _vm| a - b, vm)), + multiply: Some(|a, b, vm| PyInt::number_op(a, b, |a, b, _vm| a * b, vm)), + remainder: Some(|a, b, vm| PyInt::number_op(a, b, inner_mod, vm)), + divmod: Some(|a, b, vm| PyInt::number_op(a, b, inner_divmod, vm)), + power: Some(|a, b, vm| PyInt::number_op(a, b, inner_pow, vm)), negative: Some(|num, vm| (&PyInt::number_downcast(num).value).neg().to_pyresult(vm)), positive: Some(|num, vm| Ok(PyInt::number_downcast_exact(num, vm).into())), absolute: Some(|num, vm| PyInt::number_downcast(num).value.abs().to_pyresult(vm)), boolean: Some(|num, _vm| Ok(PyInt::number_downcast(num).value.is_zero())), invert: Some(|num, vm| (&PyInt::number_downcast(num).value).not().to_pyresult(vm)), - lshift: Some(|num, other, vm| PyInt::number_op(num, other, inner_lshift, vm)), - rshift: Some(|num, other, vm| PyInt::number_op(num, other, inner_rshift, vm)), - and: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a & b, vm)), - xor: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a ^ b, vm)), - or: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a | b, vm)), - int: Some(|num, vm| Ok(PyInt::number_downcast_exact(num, vm))), + lshift: Some(|a, b, vm| PyInt::number_op(a, b, inner_lshift, vm)), + rshift: Some(|a, b, vm| PyInt::number_op(a, b, inner_rshift, vm)), + and: Some(|a, b, vm| PyInt::number_op(a, b, |a, b, _vm| a & b, vm)), + xor: Some(|a, b, vm| PyInt::number_op(a, b, |a, b, _vm| a ^ b, vm)), + or: Some(|a, b, vm| PyInt::number_op(a, b, |a, b, _vm| a | b, vm)), + int: Some(|a, vm| Ok(PyInt::number_downcast_exact(a, vm))), float: Some(|num, vm| { let zelf = PyInt::number_downcast(num); try_to_float(&zelf.value, vm).map(|x| vm.ctx.new_float(x)) }), - floor_divide: Some(|num, other, vm| PyInt::number_op(num, other, inner_floordiv, vm)), - true_divide: Some(|num, other, vm| PyInt::number_op(num, other, inner_truediv, vm)), + floor_divide: Some(|a, b, vm| PyInt::number_op(a, b, inner_floordiv, vm)), + true_divide: Some(|a, b, vm| PyInt::number_op(a, b, inner_truediv, vm)), index: Some(|num, vm| Ok(PyInt::number_downcast_exact(num, vm))), ..PyNumberMethods::NOT_IMPLEMENTED }; - fn number_op(number: PyNumber, other: &PyObject, op: F, vm: &VirtualMachine) -> PyResult + fn number_op(a: &PyObject, b: &PyObject, op: F, vm: &VirtualMachine) -> PyResult where F: FnOnce(&BigInt, &BigInt, &VirtualMachine) -> R, R: ToPyResult, { - if let (Some(a), Some(b)) = (number.obj.payload::(), other.payload::()) { + if let (Some(a), Some(b)) = (a.payload::(), b.payload::()) { op(&a.value, &b.value, vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index 6414b9b03c..06a032aa2b 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -238,16 +238,16 @@ impl AsSequence for PyMappingProxy { impl AsNumber for PyMappingProxy { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - or: Some(|num, args, vm| { - if let Some(num) = num.obj.downcast_ref::() { - num.or(args.to_pyobject(vm), vm) + or: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.or(b.to_pyobject(vm), vm) } else { Ok(vm.ctx.not_implemented()) } }), - inplace_or: Some(|num, args, vm| { - if let Some(num) = num.obj.downcast_ref::() { - num.ior(args.to_pyobject(vm), vm) + inplace_or: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.ior(b.to_pyobject(vm), vm) } else { Ok(vm.ctx.not_implemented()) } diff --git a/vm/src/builtins/set.rs b/vm/src/builtins/set.rs index a19296b203..514e2a5f98 100644 --- a/vm/src/builtins/set.rs +++ b/vm/src/builtins/set.rs @@ -794,78 +794,62 @@ impl Iterable for PySet { impl AsNumber for PySet { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - subtract: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.sub(other.to_owned(), vm).to_pyresult(vm) + subtract: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.sub(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - and: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.and(other.to_owned(), vm).to_pyresult(vm) + and: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.and(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - xor: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.xor(other.to_owned(), vm).to_pyresult(vm) + xor: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.xor(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - or: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.or(other.to_owned(), vm).to_pyresult(vm) + or: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.or(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - inplace_subtract: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - PySet::isub( - number.to_owned(), - AnySet::try_from_object(vm, other.to_owned())?, - vm, - ) - .to_pyresult(vm) + inplace_subtract: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + PySet::isub(a.to_owned(), AnySet::try_from_object(vm, b.to_owned())?, vm) + .to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - inplace_and: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - PySet::iand( - number.to_owned(), - AnySet::try_from_object(vm, other.to_owned())?, - vm, - ) - .to_pyresult(vm) + inplace_and: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + PySet::iand(a.to_owned(), AnySet::try_from_object(vm, b.to_owned())?, vm) + .to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - inplace_xor: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - PySet::ixor( - number.to_owned(), - AnySet::try_from_object(vm, other.to_owned())?, - vm, - ) - .to_pyresult(vm) + inplace_xor: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + PySet::ixor(a.to_owned(), AnySet::try_from_object(vm, b.to_owned())?, vm) + .to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - inplace_or: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - PySet::ior( - number.to_owned(), - AnySet::try_from_object(vm, other.to_owned())?, - vm, - ) - .to_pyresult(vm) + inplace_or: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + PySet::ior(a.to_owned(), AnySet::try_from_object(vm, b.to_owned())?, vm) + .to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } @@ -1133,30 +1117,30 @@ impl Iterable for PyFrozenSet { impl AsNumber for PyFrozenSet { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - subtract: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.sub(other.to_owned(), vm).to_pyresult(vm) + subtract: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.sub(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - and: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.and(other.to_owned(), vm).to_pyresult(vm) + and: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.and(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - xor: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.xor(other.to_owned(), vm).to_pyresult(vm) + xor: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.xor(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - or: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.or(other.to_owned(), vm).to_pyresult(vm) + or: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.or(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } diff --git a/vm/src/builtins/str.rs b/vm/src/builtins/str.rs index cc5a659120..a8efa69ee0 100644 --- a/vm/src/builtins/str.rs +++ b/vm/src/builtins/str.rs @@ -1337,9 +1337,9 @@ impl AsMapping for PyStr { impl AsNumber for PyStr { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - remainder: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.modulo(other.to_owned(), vm).to_pyresult(vm) + remainder: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.modulo(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index bc7d3891e4..91f88cda19 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -1088,8 +1088,8 @@ impl Callable for PyType { impl AsNumber for PyType { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - or: Some(|num, other, vm| { - or_(num.obj.to_owned(), other.to_owned(), vm).to_pyresult(vm) + or: Some(|a, b, vm| { + or_(a.to_owned(), b.to_owned(), vm).to_pyresult(vm) }), ..PyNumberMethods::NOT_IMPLEMENTED }; diff --git a/vm/src/builtins/union.rs b/vm/src/builtins/union.rs index 347836e10c..aad29496f5 100644 --- a/vm/src/builtins/union.rs +++ b/vm/src/builtins/union.rs @@ -252,8 +252,8 @@ impl AsMapping for PyUnion { impl AsNumber for PyUnion { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - or: Some(|num, other, vm| { - PyUnion::or(num.obj.to_owned(), other.to_owned(), vm).to_pyresult(vm) + or: Some(|a, b, vm| { + PyUnion::or(a.to_owned(), b.to_owned(), vm).to_pyresult(vm) }), ..PyNumberMethods::NOT_IMPLEMENTED }; diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index 2b0376537d..7c459b3c21 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -12,7 +12,7 @@ use crate::{ }; pub type PyNumberUnaryFunc = fn(PyNumber, &VirtualMachine) -> PyResult; -pub type PyNumberBinaryFunc = fn(PyNumber, &PyObject, &VirtualMachine) -> PyResult; +pub type PyNumberBinaryFunc = fn(&PyObject, &PyObject, &VirtualMachine) -> PyResult; impl PyObject { #[inline] @@ -265,6 +265,19 @@ pub enum PyNumberBinaryOp { InplaceMatrixMultiply, } +pub trait PyNumberOps { + fn add(&self, a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult; +} + +impl PyNumberOps for PyNumberMethods { + fn add(&self, a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult { + let Some(f) = self.add else { + return Ok(vm.ctx.not_implemented()); + }; + f(a, b, vm) + } +} + #[derive(Default)] pub struct PyNumberSlots { pub add: AtomicCell>, diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 80e77cd2cf..b6c07df48a 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -227,7 +227,7 @@ macro_rules! number_binary_op_wrapper { ($name:ident) => { |num, other, vm| { vm.call_special_method( - num.obj.to_owned(), + num.to_owned(), identifier!(vm, $name), (other.to_owned(),), ) @@ -1200,7 +1200,7 @@ macro_rules! extend_number_slot { $slots.number.$right_method.store(Some(|num, other, vm| { num.methods.binary_op(PyNumberBinaryOp::$op_slot).unwrap()( other.to_number(), - num.obj, + num, vm, ) })); diff --git a/vm/src/vm/vm_ops.rs b/vm/src/vm/vm_ops.rs index ccc77b4409..ed44f4d961 100644 --- a/vm/src/vm/vm_ops.rs +++ b/vm/src/vm/vm_ops.rs @@ -149,21 +149,21 @@ impl VirtualMachine { if let Some(slot_a) = slot_a { if let Some(slot_bb) = slot_b { if b.fast_isinstance(a.class()) { - let x = slot_bb(b.to_number(), a, self)?; + let x = slot_bb(b, a, self)?; if !x.is(&self.ctx.not_implemented) { return Ok(x); } slot_b = None; } } - let x = slot_a(a.to_number(), b, self)?; + let x = slot_a(a, b, self)?; if !x.is(&self.ctx.not_implemented) { return Ok(x); } } if let Some(slot_b) = slot_b { - let x = slot_b(b.to_number(), a, self)?; + let x = slot_b(b, a, self)?; if !x.is(&self.ctx.not_implemented) { return Ok(x); } @@ -207,7 +207,7 @@ impl VirtualMachine { op_slot: PyNumberBinaryOp, ) -> PyResult { if let Some(slot) = a.class().slots.number.left_binary_op(iop_slot)? { - let x = slot(a.to_number(), b, self)?; + let x = slot(a, b, self)?; if !x.is(&self.ctx.not_implemented) { return Ok(x); } From 674975d9ae37bc6b5046bdb73681bfbc8e69beb0 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Sat, 18 Mar 2023 22:22:00 +0200 Subject: [PATCH 03/16] replace PyNumber with PyObject::pynumber methods --- vm/src/builtins/type.rs | 6 +- vm/src/protocol/number.rs | 308 +++++++++++++++++++++----------------- vm/src/types/slot.rs | 3 +- 3 files changed, 170 insertions(+), 147 deletions(-) diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 91f88cda19..230b54b47d 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -43,7 +43,7 @@ pub struct PyType { pub struct HeapTypeExt { pub name: PyRwLock, pub slots: Option>, - pub number_methods: PyNumberMethods, + pub number_slots: PyNumberSlots, pub sequence_methods: PySequenceMethods, pub mapping_methods: PyMappingMethods, } @@ -1088,9 +1088,7 @@ impl Callable for PyType { impl AsNumber for PyType { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - or: Some(|a, b, vm| { - or_(a.to_owned(), b.to_owned(), vm).to_pyresult(vm) - }), + or: Some(|a, b, vm| or_(a.to_owned(), b.to_owned(), vm).to_pyresult(vm)), ..PyNumberMethods::NOT_IMPLEMENTED }; &AS_NUMBER diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index 7c459b3c21..ceff5338ac 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -11,13 +11,110 @@ use crate::{ VirtualMachine, }; -pub type PyNumberUnaryFunc = fn(PyNumber, &VirtualMachine) -> PyResult; +pub type PyNumberUnaryFunc = fn(&PyObject, &VirtualMachine) -> PyResult; pub type PyNumberBinaryFunc = fn(&PyObject, &PyObject, &VirtualMachine) -> PyResult; +macro_rules! load_pynumber_method { + ($cls:expr, $x:ident) => {{ + let class = $cls; + if let Some(ext) = class.heaptype_ext { + ext.number_slots.$x.load() + } else if let Some(methods) = class.slots.as_number { + methods.$x + } else { + None + } + }}; +} + impl PyObject { + pub fn pynumber_check(&self) -> bool { + let class = self.class(); + if let Some(ext) = class.heaptype_ext { + ext.number_slots.int.load().is_some() + || ext.number_slots.index.load().is_some() + || ext.number_slots.float.load().is_some() + } else if let Some(methods) = class.slots.as_number { + methods.int.is_some() || methods.index.is_some() || methods.float.is_some() + } else { + self.payload_is::() + } + } + + pub fn is_index(&self) -> bool { + load_pynumber_method!(self.class(), index).is_some() + } + + #[inline] + pub fn pynumber_int(&self, vm: &VirtualMachine) -> Option> { + load_pynumber_method!(self.class(), int).map(|f| { + let ret = f(self, vm)?; + let value = if !ret.class().is(PyInt::class(vm)) { + warnings::warn( + vm.ctx.exceptions.deprecation_warning, + format!( + "__int__ returned non-int (type {}). \ + The ability to return an instance of a strict subclass of int \ + is deprecated, and may be removed in a future version of Python.", + ret.class() + ), + 1, + vm, + )?; + vm.ctx.new_bigint(ret.as_bigint()) + } else { + ret + }; + Ok(value) + }) + } + + #[inline] + pub fn pynumber_index(&self, vm: &VirtualMachine) -> Option> { + load_pynumber_method!(self.class(), index).map(|f| { + let ret = f(self, vm)?; + let value = if !ret.class().is(PyInt::class(vm)) { + warnings::warn( + vm.ctx.exceptions.deprecation_warning, + format!( + "__index__ returned non-int (type {}). \ + The ability to return an instance of a strict subclass of int \ + is deprecated, and may be removed in a future version of Python.", + ret.class() + ), + 1, + vm, + )?; + vm.ctx.new_bigint(ret.as_bigint()) + } else { + ret + }; + Ok(value) + }) + } + #[inline] - pub fn to_number(&self) -> PyNumber<'_> { - PyNumber::from(self) + pub fn pynumber_float(&self, vm: &VirtualMachine) -> Option>> { + load_pynumber_method!(self.class(), float).map(|f| { + let ret = f(self, vm)?; + let value = if !ret.class().is(PyFloat::class(vm)) { + warnings::warn( + vm.ctx.exceptions.deprecation_warning, + format!( + "__float__ returned non-float (type {}). \ + The ability to return an instance of a strict subclass of float \ + is deprecated, and may be removed in a future version of Python.", + ret.class() + ), + 1, + vm, + )?; + vm.ctx.new_float(ret.to_f64()) + } else { + ret + }; + Ok(value) + }) } pub fn try_index_opt(&self, vm: &VirtualMachine) -> Option> { @@ -26,7 +123,7 @@ impl PyObject { } else if let Some(i) = self.payload::() { Some(Ok(vm.ctx.new_bigint(i.as_bigint()))) } else { - self.to_number().index(vm) + self.pynumber_index(vm) } } @@ -58,7 +155,7 @@ impl PyObject { if let Some(i) = self.downcast_ref_if_exact::(vm) { Ok(i.to_owned()) - } else if let Some(i) = self.to_number().int(vm).or_else(|| self.try_index_opt(vm)) { + } else if let Some(i) = self.pynumber_int(vm).or_else(|| self.try_index_opt(vm)) { i } else if let Ok(Ok(f)) = vm.get_special_method(self.to_owned(), identifier!(vm, __trunc__)) { @@ -96,7 +193,7 @@ impl PyObject { pub fn try_float_opt(&self, vm: &VirtualMachine) -> Option>> { if let Some(float) = self.downcast_ref_if_exact::(vm) { Some(Ok(float.to_owned())) - } else if let Some(f) = self.to_number().float(vm) { + } else if let Some(f) = self.pynumber_float(vm) { Some(f) } else { self.try_index_opt(vm) @@ -265,19 +362,6 @@ pub enum PyNumberBinaryOp { InplaceMatrixMultiply, } -pub trait PyNumberOps { - fn add(&self, a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult; -} - -impl PyNumberOps for PyNumberMethods { - fn add(&self, a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult { - let Some(f) = self.add else { - return Ok(vm.ctx.not_implemented()); - }; - f(a, b, vm) - } -} - #[derive(Default)] pub struct PyNumberSlots { pub add: AtomicCell>, @@ -336,13 +420,69 @@ pub struct PyNumberSlots { pub inplace_matrix_multiply: AtomicCell>, } +impl From<&PyNumberMethods> for PyNumberSlots { + fn from(value: &PyNumberMethods) -> Self { + // right_* functions will use the same left function as PyNumberMethods garrentee to + // support both f(self, other) and f(other, self) + // the caller will have to reverse direction when calling right_* functions + Self { + add: AtomicCell::new(value.add), + subtract: AtomicCell::new(value.subtract), + multiply: AtomicCell::new(value.multiply), + remainder: AtomicCell::new(value.remainder), + divmod: AtomicCell::new(value.divmod), + power: AtomicCell::new(value.power), + negative: AtomicCell::new(value.negative), + positive: AtomicCell::new(value.positive), + absolute: AtomicCell::new(value.absolute), + boolean: AtomicCell::new(value.boolean), + invert: AtomicCell::new(value.invert), + lshift: AtomicCell::new(value.lshift), + rshift: AtomicCell::new(value.rshift), + and: AtomicCell::new(value.and), + xor: AtomicCell::new(value.xor), + or: AtomicCell::new(value.or), + int: AtomicCell::new(value.int), + float: AtomicCell::new(value.float), + right_add: AtomicCell::new(value.add), + right_subtract: AtomicCell::new(value.subtract), + right_multiply: AtomicCell::new(value.multiply), + right_remainder: AtomicCell::new(value.remainder), + right_divmod: AtomicCell::new(value.divmod), + right_power: AtomicCell::new(value.power), + right_lshift: AtomicCell::new(value.lshift), + right_rshift: AtomicCell::new(value.rshift), + right_and: AtomicCell::new(value.and), + right_xor: AtomicCell::new(value.xor), + right_or: AtomicCell::new(value.or), + inplace_add: AtomicCell::new(value.inplace_add), + inplace_subtract: AtomicCell::new(value.inplace_subtract), + inplace_multiply: AtomicCell::new(value.inplace_multiply), + inplace_remainder: AtomicCell::new(value.inplace_remainder), + inplace_power: AtomicCell::new(value.inplace_power), + inplace_lshift: AtomicCell::new(value.inplace_lshift), + inplace_rshift: AtomicCell::new(value.inplace_rshift), + inplace_and: AtomicCell::new(value.inplace_and), + inplace_xor: AtomicCell::new(value.inplace_xor), + inplace_or: AtomicCell::new(value.inplace_or), + floor_divide: AtomicCell::new(value.floor_divide), + true_divide: AtomicCell::new(value.true_divide), + right_floor_divide: AtomicCell::new(value.floor_divide), + right_true_divide: AtomicCell::new(value.true_divide), + inplace_floor_divide: AtomicCell::new(value.inplace_floor_divide), + inplace_true_divide: AtomicCell::new(value.inplace_true_divide), + index: AtomicCell::new(value.index), + matrix_multiply: AtomicCell::new(value.matrix_multiply), + right_matrix_multiply: AtomicCell::new(value.matrix_multiply), + inplace_matrix_multiply: AtomicCell::new(value.inplace_matrix_multiply), + } + } +} + impl PyNumberSlots { - pub fn left_binary_op( - &self, - op_slot: PyNumberBinaryOp, - ) -> PyResult> { + pub fn left_binary_op(&self, op_slot: PyNumberBinaryOp) -> Option { use PyNumberBinaryOp::*; - let binary_op = match op_slot { + match op_slot { Add => self.add.load(), Subtract => self.subtract.load(), Multiply => self.multiply.load(), @@ -370,16 +510,12 @@ impl PyNumberSlots { InplaceTrueDivide => self.inplace_true_divide.load(), MatrixMultiply => self.matrix_multiply.load(), InplaceMatrixMultiply => self.inplace_matrix_multiply.load(), - }; - Ok(binary_op) + } } - pub fn right_binary_op( - &self, - op_slot: PyNumberBinaryOp, - ) -> PyResult> { + pub fn right_binary_op(&self, op_slot: PyNumberBinaryOp) -> Option { use PyNumberBinaryOp::*; - let binary_op = match op_slot { + match op_slot { Add => self.right_add.load(), Subtract => self.right_subtract.load(), Multiply => self.right_multiply.load(), @@ -395,116 +531,6 @@ impl PyNumberSlots { TrueDivide => self.right_true_divide.load(), MatrixMultiply => self.right_matrix_multiply.load(), _ => None, - }; - Ok(binary_op) - } -} - -#[derive(Copy, Clone)] -pub struct PyNumber<'a> { - pub obj: &'a PyObject, - pub(crate) 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: Self::find_methods(obj) - .map_or(&GLOBAL_NOT_IMPLEMENTED, |m| unsafe { m.borrow_static() }), } } } - -impl PyNumber<'_> { - fn find_methods(obj: &PyObject) -> Option> { - obj.class().mro_find_map(|x| x.slots.as_number.load()) - } - - // PyNumber_Check - pub fn check(obj: &PyObject) -> bool { - let methods = &obj.class().slots.number; - 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.obj.class().slots.number.index.load().is_some() - } - - #[inline] - pub fn int(self, vm: &VirtualMachine) -> Option> { - self.obj.class().slots.number.int.load().map(|f| { - let ret = f(self, vm)?; - let value = if !ret.class().is(PyInt::class(vm)) { - warnings::warn( - vm.ctx.exceptions.deprecation_warning, - format!( - "__int__ returned non-int (type {}). \ - The ability to return an instance of a strict subclass of int \ - is deprecated, and may be removed in a future version of Python.", - ret.class() - ), - 1, - vm, - )?; - vm.ctx.new_bigint(ret.as_bigint()) - } else { - ret - }; - Ok(value) - }) - } - - #[inline] - pub fn index(self, vm: &VirtualMachine) -> Option> { - self.obj.class().slots.number.index.load().map(|f| { - let ret = f(self, vm)?; - let value = if !ret.class().is(PyInt::class(vm)) { - warnings::warn( - vm.ctx.exceptions.deprecation_warning, - format!( - "__index__ returned non-int (type {}). \ - The ability to return an instance of a strict subclass of int \ - is deprecated, and may be removed in a future version of Python.", - ret.class() - ), - 1, - vm, - )?; - vm.ctx.new_bigint(ret.as_bigint()) - } else { - ret - }; - Ok(value) - }) - } - - #[inline] - pub fn float(self, vm: &VirtualMachine) -> Option>> { - self.obj.class().slots.number.float.load().map(|f| { - let ret = f(self, vm)?; - let value = if !ret.class().is(PyFloat::class(vm)) { - warnings::warn( - vm.ctx.exceptions.deprecation_warning, - format!( - "__float__ returned non-float (type {}). \ - The ability to return an instance of a strict subclass of float \ - is deprecated, and may be removed in a future version of Python.", - ret.class() - ), - 1, - vm, - )?; - vm.ctx.new_float(ret.to_f64()) - } else { - ret - }; - Ok(value) - }) - } -} diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index b6c07df48a..a1ad686b3c 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -41,7 +41,7 @@ pub struct PyTypeSlots { // Methods to implement standard operations // Method suites for standard classes - pub as_number: AtomicCell>>, + pub as_number: Option<&'static PyNumberMethods>, pub as_sequence: AtomicCell>>, pub as_mapping: AtomicCell>>, @@ -90,7 +90,6 @@ pub struct PyTypeSlots { // The count of tp_members. pub member_count: usize, - pub number: PyNumberSlots, } impl PyTypeSlots { From 19d6293a3b9791b61c201e462e3bae200a0da1cd Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Sat, 18 Mar 2023 22:51:42 +0200 Subject: [PATCH 04/16] refactor binary_op* --- vm/src/protocol/number.rs | 153 +++++++++++++++----------------------- vm/src/vm/vm_ops.rs | 27 ++++--- 2 files changed, 74 insertions(+), 106 deletions(-) diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index ceff5338ac..c96f2db66e 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -15,16 +15,19 @@ pub type PyNumberUnaryFunc = fn(&PyObject, &VirtualMachine) -> pub type PyNumberBinaryFunc = fn(&PyObject, &PyObject, &VirtualMachine) -> PyResult; macro_rules! load_pynumber_method { - ($cls:expr, $x:ident) => {{ + ($cls:expr, $x:ident, $y:ident) => {{ let class = $cls; if let Some(ext) = class.heaptype_ext { - ext.number_slots.$x.load() + ext.number_slots.$y.load() } else if let Some(methods) = class.slots.as_number { methods.$x } else { None } }}; + ($cls:expr, $x:ident) => {{ + load_pynumber_method!($cls, $x, $x) + }}; } impl PyObject { @@ -258,7 +261,6 @@ 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: None, subtract: None, @@ -296,39 +298,6 @@ impl PyNumberMethods { matrix_multiply: None, inplace_matrix_multiply: None, }; - - pub fn binary_op(&self, op_slot: PyNumberBinaryOp) -> Option { - use PyNumberBinaryOp::*; - match op_slot { - Add => self.add, - Subtract => self.subtract, - Multiply => self.multiply, - Remainder => self.remainder, - Divmod => self.divmod, - Power => self.power, - Lshift => self.lshift, - Rshift => self.rshift, - And => self.and, - Xor => self.xor, - Or => self.or, - InplaceAdd => self.inplace_add, - InplaceSubtract => self.inplace_subtract, - InplaceMultiply => self.inplace_multiply, - InplaceRemainder => self.inplace_remainder, - InplacePower => self.inplace_power, - InplaceLshift => self.inplace_lshift, - InplaceRshift => self.inplace_rshift, - InplaceAnd => self.inplace_and, - InplaceXor => self.inplace_xor, - InplaceOr => self.inplace_or, - FloorDivide => self.floor_divide, - TrueDivide => self.true_divide, - InplaceFloorDivide => self.inplace_floor_divide, - InplaceTrueDivide => self.inplace_true_divide, - MatrixMultiply => self.matrix_multiply, - InplaceMatrixMultiply => self.inplace_matrix_multiply, - } - } } #[derive(Copy, Clone)] @@ -362,6 +331,62 @@ pub enum PyNumberBinaryOp { InplaceMatrixMultiply, } +impl PyNumberBinaryOp { + pub fn left(self, cls: &PyType) -> Option { + use PyNumberBinaryOp::*; + match self { + Add => load_pynumber_method!(cls, add), + Subtract => load_pynumber_method!(cls, subtract), + Multiply => load_pynumber_method!(cls, multiply), + Remainder => load_pynumber_method!(cls, remainder), + Divmod => load_pynumber_method!(cls, divmod), + Power => load_pynumber_method!(cls, power), + Lshift => load_pynumber_method!(cls, lshift), + Rshift => load_pynumber_method!(cls, rshift), + And => load_pynumber_method!(cls, and), + Xor => load_pynumber_method!(cls, xor), + Or => load_pynumber_method!(cls, or), + InplaceAdd => load_pynumber_method!(cls, inplace_add), + InplaceSubtract => load_pynumber_method!(cls, inplace_subtract), + InplaceMultiply => load_pynumber_method!(cls, inplace_multiply), + InplaceRemainder => load_pynumber_method!(cls, inplace_remainder), + InplacePower => load_pynumber_method!(cls, inplace_power), + InplaceLshift => load_pynumber_method!(cls, inplace_lshift), + InplaceRshift => load_pynumber_method!(cls, inplace_rshift), + InplaceAnd => load_pynumber_method!(cls, inplace_and), + InplaceXor => load_pynumber_method!(cls, inplace_xor), + InplaceOr => load_pynumber_method!(cls, inplace_or), + FloorDivide => load_pynumber_method!(cls, floor_divide), + TrueDivide => load_pynumber_method!(cls, true_divide), + InplaceFloorDivide => load_pynumber_method!(cls, inplace_floor_divide), + InplaceTrueDivide => load_pynumber_method!(cls, inplace_true_divide), + MatrixMultiply => load_pynumber_method!(cls, matrix_multiply), + InplaceMatrixMultiply => load_pynumber_method!(cls, inplace_matrix_multiply), + } + } + + pub fn right(self, cls: &PyType) -> Option { + use PyNumberBinaryOp::*; + match self { + Add => load_pynumber_method!(cls, add, right_add), + Subtract => load_pynumber_method!(cls, subtract, right_subtract), + Multiply => load_pynumber_method!(cls, multiply, right_multiply), + Remainder => load_pynumber_method!(cls, remainder, right_remainder), + Divmod => load_pynumber_method!(cls, divmod, right_divmod), + Power => load_pynumber_method!(cls, power, right_power), + Lshift => load_pynumber_method!(cls, lshift, right_lshift), + Rshift => load_pynumber_method!(cls, rshift, right_rshift), + And => load_pynumber_method!(cls, and, right_and), + Xor => load_pynumber_method!(cls, xor, right_xor), + Or => load_pynumber_method!(cls, or, right_or), + FloorDivide => load_pynumber_method!(cls, floor_divide, right_floor_divide), + TrueDivide => load_pynumber_method!(cls, true_divide, right_true_divide), + MatrixMultiply => load_pynumber_method!(cls, matrix_multiply, right_matrix_multiply), + _ => None, + } + } +} + #[derive(Default)] pub struct PyNumberSlots { pub add: AtomicCell>, @@ -478,59 +503,3 @@ impl From<&PyNumberMethods> for PyNumberSlots { } } } - -impl PyNumberSlots { - pub fn left_binary_op(&self, op_slot: PyNumberBinaryOp) -> Option { - use PyNumberBinaryOp::*; - match op_slot { - Add => self.add.load(), - Subtract => self.subtract.load(), - Multiply => self.multiply.load(), - Remainder => self.remainder.load(), - Divmod => self.divmod.load(), - Power => self.power.load(), - Lshift => self.lshift.load(), - Rshift => self.rshift.load(), - And => self.and.load(), - Xor => self.xor.load(), - Or => self.or.load(), - InplaceAdd => self.inplace_add.load(), - InplaceSubtract => self.inplace_subtract.load(), - InplaceMultiply => self.inplace_multiply.load(), - InplaceRemainder => self.inplace_remainder.load(), - InplacePower => self.inplace_power.load(), - InplaceLshift => self.inplace_lshift.load(), - InplaceRshift => self.inplace_rshift.load(), - InplaceAnd => self.inplace_and.load(), - InplaceXor => self.inplace_xor.load(), - InplaceOr => self.inplace_or.load(), - FloorDivide => self.floor_divide.load(), - TrueDivide => self.true_divide.load(), - InplaceFloorDivide => self.inplace_floor_divide.load(), - InplaceTrueDivide => self.inplace_true_divide.load(), - MatrixMultiply => self.matrix_multiply.load(), - InplaceMatrixMultiply => self.inplace_matrix_multiply.load(), - } - } - - pub fn right_binary_op(&self, op_slot: PyNumberBinaryOp) -> Option { - use PyNumberBinaryOp::*; - match op_slot { - Add => self.right_add.load(), - Subtract => self.right_subtract.load(), - Multiply => self.right_multiply.load(), - Remainder => self.right_remainder.load(), - Divmod => self.right_divmod.load(), - Power => self.right_power.load(), - Lshift => self.right_lshift.load(), - Rshift => self.right_rshift.load(), - And => self.right_and.load(), - Xor => self.right_xor.load(), - Or => self.right_or.load(), - FloorDivide => self.right_floor_divide.load(), - TrueDivide => self.right_true_divide.load(), - MatrixMultiply => self.right_matrix_multiply.load(), - _ => None, - } - } -} diff --git a/vm/src/vm/vm_ops.rs b/vm/src/vm/vm_ops.rs index ed44f4d961..8a8e2e2e9e 100644 --- a/vm/src/vm/vm_ops.rs +++ b/vm/src/vm/vm_ops.rs @@ -132,23 +132,22 @@ impl VirtualMachine { /// /// [*] only when Py_TYPE(a) != Py_TYPE(b) && Py_TYPE(b) is a subclass of Py_TYPE(a) pub fn binary_op1(&self, a: &PyObject, b: &PyObject, op_slot: PyNumberBinaryOp) -> PyResult { - let slot_a = a.class().slots.number.left_binary_op(op_slot)?; - let mut slot_b = if b.class().is(a.class()) { - None - } else { - match b.class().slots.number.right_binary_op(op_slot)? { - Some(slot_b) - if slot_b as usize == slot_a.map(|s| s as usize).unwrap_or_default() => - { - None - } - slot_b => slot_b, + let class_a = a.class(); + let class_b = b.class(); + + let slot_a = op_slot.left(class_a); + let mut slot_b = None; + + if !class_b.is(class_a) { + let slot_bb = op_slot.right(class_b); + if slot_bb.map(|x| x as usize) != slot_a.map(|x| x as usize) { + slot_b = slot_bb; } - }; + } if let Some(slot_a) = slot_a { if let Some(slot_bb) = slot_b { - if b.fast_isinstance(a.class()) { + if class_b.fast_isinstance(class_a) { let x = slot_bb(b, a, self)?; if !x.is(&self.ctx.not_implemented) { return Ok(x); @@ -206,7 +205,7 @@ impl VirtualMachine { iop_slot: PyNumberBinaryOp, op_slot: PyNumberBinaryOp, ) -> PyResult { - if let Some(slot) = a.class().slots.number.left_binary_op(iop_slot)? { + if let Some(slot) = iop_slot.left(a.class()) { let x = slot(a, b, self)?; if !x.is(&self.ctx.not_implemented) { return Ok(x); From d456f4ab54f4f31d3b80ded239d27dab470eae2d Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Sat, 18 Mar 2023 23:02:52 +0200 Subject: [PATCH 05/16] change as_number to NON_ATOMIC_SLOTS --- derive-impl/src/pyclass.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/derive-impl/src/pyclass.rs b/derive-impl/src/pyclass.rs index 182286e5b3..df88eaeffd 100644 --- a/derive-impl/src/pyclass.rs +++ b/derive-impl/src/pyclass.rs @@ -701,8 +701,8 @@ where let slot_ident = Ident::new(&slot_ident.to_string().to_lowercase(), slot_ident.span()); let slot_name = slot_ident.to_string(); let tokens = { - const NON_ATOMIC_SLOTS: &[&str] = &["as_buffer"]; - const POINTER_SLOTS: &[&str] = &["as_number", "as_sequence", "as_mapping"]; + const NON_ATOMIC_SLOTS: &[&str] = &["as_buffer", "as_number"]; + const POINTER_SLOTS: &[&str] = &["as_sequence", "as_mapping"]; if NON_ATOMIC_SLOTS.contains(&slot_name.as_str()) { quote_spanned! { span => slots.#slot_ident = Some(Self::#ident as _); From a71c6c95a5d11b91eeea42410c271d7d4344fb22 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Sun, 19 Mar 2023 20:09:35 +0200 Subject: [PATCH 06/16] fix update_slots --- vm/src/builtins/bool.rs | 3 +- vm/src/builtins/type.rs | 2 +- vm/src/protocol/number.rs | 47 ++++--- vm/src/types/slot.rs | 264 +++++++++++++++++--------------------- 4 files changed, 151 insertions(+), 165 deletions(-) diff --git a/vm/src/builtins/bool.rs b/vm/src/builtins/bool.rs index 2c11d66caf..275294f0ca 100644 --- a/vm/src/builtins/bool.rs +++ b/vm/src/builtins/bool.rs @@ -173,7 +173,8 @@ impl AsNumber for PyBool { or: Some(|a, b, vm| { PyBool::or(a.to_owned(), b.to_owned(), vm).to_pyresult(vm) }), - ..PyInt::AS_NUMBER + // ..PyInt::AS_NUMBER + ..*PyInt::as_number() }; &AS_NUMBER } diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 230b54b47d..65e9ac99c4 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -20,7 +20,7 @@ use crate::{ convert::{ToPyObject, ToPyResult}, function::{FuncArgs, KwArgs, OptionalArg, PySetterValue}, identifier, - protocol::{PyIterReturn, PyMappingMethods, PyNumberMethods, PySequenceMethods}, + protocol::{PyIterReturn, PyMappingMethods, PyNumberMethods, PyNumberSlots, PySequenceMethods}, types::{AsNumber, Callable, GetAttr, PyTypeFlags, PyTypeSlots, Representable, SetAttr}, AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine, diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index c96f2db66e..acdaef5c2a 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -1,9 +1,9 @@ +use std::ops::Deref; + use crossbeam_utils::atomic::AtomicCell; use crate::{ - builtins::{ - int, type_::PointerSlot, PyByteArray, PyBytes, PyComplex, PyFloat, PyInt, PyIntRef, PyStr, - }, + builtins::{int, PyByteArray, PyBytes, PyComplex, PyFloat, PyInt, PyIntRef, PyStr, PyType}, common::int::bytes_to_int, function::ArgBytesLike, stdlib::warnings, @@ -11,9 +11,20 @@ use crate::{ VirtualMachine, }; -pub type PyNumberUnaryFunc = fn(&PyObject, &VirtualMachine) -> PyResult; +pub type PyNumberUnaryFunc = fn(PyNumber, &VirtualMachine) -> PyResult; pub type PyNumberBinaryFunc = fn(&PyObject, &PyObject, &VirtualMachine) -> PyResult; +#[derive(Copy, Clone)] +pub struct PyNumber<'a>(&'a PyObject); + +impl Deref for PyNumber<'_> { + type Target = PyObject; + + fn deref(&self) -> &Self::Target { + self.0 + } +} + macro_rules! load_pynumber_method { ($cls:expr, $x:ident, $y:ident) => {{ let class = $cls; @@ -30,9 +41,9 @@ macro_rules! load_pynumber_method { }}; } -impl PyObject { - pub fn pynumber_check(&self) -> bool { - let class = self.class(); +impl PyNumber<'_> { + pub fn check(obj: &PyObject) -> bool { + let class = obj.class(); if let Some(ext) = class.heaptype_ext { ext.number_slots.int.load().is_some() || ext.number_slots.index.load().is_some() @@ -40,16 +51,16 @@ impl PyObject { } else if let Some(methods) = class.slots.as_number { methods.int.is_some() || methods.index.is_some() || methods.float.is_some() } else { - self.payload_is::() + obj.payload_is::() } } - pub fn is_index(&self) -> bool { + pub fn is_index(self) -> bool { load_pynumber_method!(self.class(), index).is_some() } #[inline] - pub fn pynumber_int(&self, vm: &VirtualMachine) -> Option> { + pub fn int(self, vm: &VirtualMachine) -> Option> { load_pynumber_method!(self.class(), int).map(|f| { let ret = f(self, vm)?; let value = if !ret.class().is(PyInt::class(vm)) { @@ -73,7 +84,7 @@ impl PyObject { } #[inline] - pub fn pynumber_index(&self, vm: &VirtualMachine) -> Option> { + pub fn index(self, vm: &VirtualMachine) -> Option> { load_pynumber_method!(self.class(), index).map(|f| { let ret = f(self, vm)?; let value = if !ret.class().is(PyInt::class(vm)) { @@ -97,7 +108,7 @@ impl PyObject { } #[inline] - pub fn pynumber_float(&self, vm: &VirtualMachine) -> Option>> { + pub fn float(self, vm: &VirtualMachine) -> Option>> { load_pynumber_method!(self.class(), float).map(|f| { let ret = f(self, vm)?; let value = if !ret.class().is(PyFloat::class(vm)) { @@ -119,6 +130,12 @@ impl PyObject { Ok(value) }) } +} + +impl PyObject { + pub fn to_number(&self) -> PyNumber { + PyNumber(self) + } pub fn try_index_opt(&self, vm: &VirtualMachine) -> Option> { if let Some(i) = self.downcast_ref_if_exact::(vm) { @@ -126,7 +143,7 @@ impl PyObject { } else if let Some(i) = self.payload::() { Some(Ok(vm.ctx.new_bigint(i.as_bigint()))) } else { - self.pynumber_index(vm) + self.to_number().index(vm) } } @@ -158,7 +175,7 @@ impl PyObject { if let Some(i) = self.downcast_ref_if_exact::(vm) { Ok(i.to_owned()) - } else if let Some(i) = self.pynumber_int(vm).or_else(|| self.try_index_opt(vm)) { + } else if let Some(i) = self.to_number().int(vm).or_else(|| self.try_index_opt(vm)) { i } else if let Ok(Ok(f)) = vm.get_special_method(self.to_owned(), identifier!(vm, __trunc__)) { @@ -196,7 +213,7 @@ impl PyObject { pub fn try_float_opt(&self, vm: &VirtualMachine) -> Option>> { if let Some(float) = self.downcast_ref_if_exact::(vm) { Some(Ok(float.to_owned())) - } else if let Some(f) = self.pynumber_float(vm) { + } else if let Some(f) = self.to_number().float(vm) { Some(f) } else { self.try_index_opt(vm) diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index a1ad686b3c..53adc44dd6 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -9,7 +9,8 @@ use crate::{ identifier, protocol::{ PyBuffer, PyIterReturn, PyMapping, PyMappingMethods, PyNumber, PyNumberBinaryFunc, - PyNumberBinaryOp, PyNumberMethods, PyNumberUnaryFunc, PySequence, PySequenceMethods, PyNumberSlots, + PyNumberBinaryOp, PyNumberMethods, PyNumberSlots, PyNumberUnaryFunc, PySequence, + PySequenceMethods, }, vm::Context, AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, @@ -108,7 +109,6 @@ impl std::fmt::Debug for PyTypeSlots { } } - bitflags! { #[non_exhaustive] pub struct PyTypeFlags: u64 { @@ -225,11 +225,7 @@ fn float_wrapper(num: PyNumber, vm: &VirtualMachine) -> PyResult> macro_rules! number_binary_op_wrapper { ($name:ident) => { |num, other, vm| { - vm.call_special_method( - num.to_owned(), - identifier!(vm, $name), - (other.to_owned(),), - ) + vm.call_special_method(num.to_owned(), identifier!(vm, $name), (other.to_owned(),)) } }; } @@ -516,185 +512,233 @@ impl PyType { toggle_slot!(del, del_wrapper); } _ if name == identifier!(ctx, __int__) => { - toggle_subslot!(number, int, int_wrapper); + toggle_ext_func!(number_slots, int, int_wrapper); } _ if name == identifier!(ctx, __index__) => { - toggle_subslot!(number, index, index_wrapper); + toggle_ext_func!(number_slots, index, index_wrapper); } _ if name == identifier!(ctx, __float__) => { - toggle_subslot!(number, float, float_wrapper); + toggle_ext_func!(number_slots, float, float_wrapper); } _ if name == identifier!(ctx, __add__) => { - toggle_subslot!(number, add, number_binary_op_wrapper!(__add__)); + toggle_ext_func!(number_slots, add, number_binary_op_wrapper!(__add__)); } _ if name == identifier!(ctx, __radd__) => { - toggle_subslot!(number, right_add, number_binary_op_wrapper!(__radd__)); + toggle_ext_func!(number_slots, right_add, number_binary_op_wrapper!(__radd__)); } _ if name == identifier!(ctx, __iadd__) => { - toggle_subslot!(number, inplace_add, number_binary_op_wrapper!(__iadd__)); + toggle_ext_func!( + number_slots, + inplace_add, + number_binary_op_wrapper!(__iadd__) + ); } _ if name == identifier!(ctx, __sub__) => { - toggle_subslot!(number, subtract, number_binary_op_wrapper!(__sub__)); + toggle_ext_func!(number_slots, subtract, number_binary_op_wrapper!(__sub__)); } _ if name == identifier!(ctx, __rsub__) => { - toggle_subslot!(number, right_subtract, number_binary_op_wrapper!(__rsub__)); + toggle_ext_func!( + number_slots, + right_subtract, + number_binary_op_wrapper!(__rsub__) + ); } _ if name == identifier!(ctx, __isub__) => { - toggle_subslot!( - number, + toggle_ext_func!( + number_slots, inplace_subtract, number_binary_op_wrapper!(__isub__) ); } _ if name == identifier!(ctx, __mul__) => { - toggle_subslot!(number, multiply, number_binary_op_wrapper!(__mul__)); + toggle_ext_func!(number_slots, multiply, number_binary_op_wrapper!(__mul__)); } _ if name == identifier!(ctx, __rmul__) => { - toggle_subslot!(number, right_multiply, number_binary_op_wrapper!(__rmul__)); + toggle_ext_func!( + number_slots, + right_multiply, + number_binary_op_wrapper!(__rmul__) + ); } _ if name == identifier!(ctx, __imul__) => { - toggle_subslot!( - number, + toggle_ext_func!( + number_slots, inplace_multiply, number_binary_op_wrapper!(__imul__) ); } _ if name == identifier!(ctx, __mod__) => { - toggle_subslot!(number, remainder, number_binary_op_wrapper!(__mod__)); + toggle_ext_func!(number_slots, remainder, number_binary_op_wrapper!(__mod__)); } _ if name == identifier!(ctx, __rmod__) => { - toggle_subslot!(number, right_remainder, number_binary_op_wrapper!(__rmod__)); + toggle_ext_func!( + number_slots, + right_remainder, + number_binary_op_wrapper!(__rmod__) + ); } _ if name == identifier!(ctx, __imod__) => { - toggle_subslot!( - number, + toggle_ext_func!( + number_slots, inplace_remainder, number_binary_op_wrapper!(__imod__) ); } _ if name == identifier!(ctx, __divmod__) => { - toggle_subslot!(number, divmod, number_binary_op_wrapper!(__divmod__)); + toggle_ext_func!(number_slots, divmod, number_binary_op_wrapper!(__divmod__)); } _ if name == identifier!(ctx, __rdivmod__) => { - toggle_subslot!(number, right_divmod, number_binary_op_wrapper!(__rdivmod__)); + toggle_ext_func!( + number_slots, + right_divmod, + number_binary_op_wrapper!(__rdivmod__) + ); } _ if name == identifier!(ctx, __pow__) => { - toggle_subslot!(number, power, number_binary_op_wrapper!(__pow__)); + toggle_ext_func!(number_slots, power, number_binary_op_wrapper!(__pow__)); } _ if name == identifier!(ctx, __rpow__) => { - toggle_subslot!(number, right_power, number_binary_op_wrapper!(__rpow__)); + toggle_ext_func!( + number_slots, + right_power, + number_binary_op_wrapper!(__rpow__) + ); } _ if name == identifier!(ctx, __ipow__) => { - toggle_subslot!(number, inplace_power, number_binary_op_wrapper!(__ipow__)); + toggle_ext_func!( + number_slots, + inplace_power, + number_binary_op_wrapper!(__ipow__) + ); } _ if name == identifier!(ctx, __lshift__) => { - toggle_subslot!(number, lshift, number_binary_op_wrapper!(__lshift__)); + toggle_ext_func!(number_slots, lshift, number_binary_op_wrapper!(__lshift__)); } _ if name == identifier!(ctx, __rlshift__) => { - toggle_subslot!(number, right_lshift, number_binary_op_wrapper!(__rlshift__)); + toggle_ext_func!( + number_slots, + right_lshift, + number_binary_op_wrapper!(__rlshift__) + ); } _ if name == identifier!(ctx, __ilshift__) => { - toggle_subslot!( - number, + toggle_ext_func!( + number_slots, inplace_lshift, number_binary_op_wrapper!(__ilshift__) ); } _ if name == identifier!(ctx, __rshift__) => { - toggle_subslot!(number, rshift, number_binary_op_wrapper!(__rshift__)); + toggle_ext_func!(number_slots, rshift, number_binary_op_wrapper!(__rshift__)); } _ if name == identifier!(ctx, __rrshift__) => { - toggle_subslot!(number, right_rshift, number_binary_op_wrapper!(__rrshift__)); + toggle_ext_func!( + number_slots, + right_rshift, + number_binary_op_wrapper!(__rrshift__) + ); } _ if name == identifier!(ctx, __irshift__) => { - toggle_subslot!( - number, + toggle_ext_func!( + number_slots, inplace_rshift, number_binary_op_wrapper!(__irshift__) ); } _ if name == identifier!(ctx, __and__) => { - toggle_subslot!(number, and, number_binary_op_wrapper!(__and__)); + toggle_ext_func!(number_slots, and, number_binary_op_wrapper!(__and__)); } _ if name == identifier!(ctx, __rand__) => { - toggle_subslot!(number, right_and, number_binary_op_wrapper!(__rand__)); + toggle_ext_func!(number_slots, right_and, number_binary_op_wrapper!(__rand__)); } _ if name == identifier!(ctx, __iand__) => { - toggle_subslot!(number, inplace_and, number_binary_op_wrapper!(__iand__)); + toggle_ext_func!( + number_slots, + inplace_and, + number_binary_op_wrapper!(__iand__) + ); } _ if name == identifier!(ctx, __xor__) => { - toggle_subslot!(number, xor, number_binary_op_wrapper!(__xor__)); + toggle_ext_func!(number_slots, xor, number_binary_op_wrapper!(__xor__)); } _ if name == identifier!(ctx, __rxor__) => { - toggle_subslot!(number, right_xor, number_binary_op_wrapper!(__rxor__)); + toggle_ext_func!(number_slots, right_xor, number_binary_op_wrapper!(__rxor__)); } _ if name == identifier!(ctx, __ixor__) => { - toggle_subslot!(number, inplace_xor, number_binary_op_wrapper!(__ixor__)); + toggle_ext_func!( + number_slots, + inplace_xor, + number_binary_op_wrapper!(__ixor__) + ); } _ if name == identifier!(ctx, __or__) => { - toggle_subslot!(number, or, number_binary_op_wrapper!(__or__)); + toggle_ext_func!(number_slots, or, number_binary_op_wrapper!(__or__)); } _ if name == identifier!(ctx, __ror__) => { - toggle_subslot!(number, right_or, number_binary_op_wrapper!(__ror__)); + toggle_ext_func!(number_slots, right_or, number_binary_op_wrapper!(__ror__)); } _ if name == identifier!(ctx, __ior__) => { - toggle_subslot!(number, inplace_or, number_binary_op_wrapper!(__ior__)); + toggle_ext_func!(number_slots, inplace_or, number_binary_op_wrapper!(__ior__)); } _ if name == identifier!(ctx, __floordiv__) => { - toggle_subslot!( - number, + toggle_ext_func!( + number_slots, floor_divide, number_binary_op_wrapper!(__floordiv__) ); } _ if name == identifier!(ctx, __rfloordiv__) => { - toggle_subslot!( - number, + toggle_ext_func!( + number_slots, right_floor_divide, number_binary_op_wrapper!(__rfloordiv__) ); } _ if name == identifier!(ctx, __ifloordiv__) => { - toggle_subslot!( - number, + toggle_ext_func!( + number_slots, inplace_floor_divide, number_binary_op_wrapper!(__ifloordiv__) ); } _ if name == identifier!(ctx, __truediv__) => { - toggle_subslot!(number, true_divide, number_binary_op_wrapper!(__truediv__)); + toggle_ext_func!( + number_slots, + true_divide, + number_binary_op_wrapper!(__truediv__) + ); } _ if name == identifier!(ctx, __rtruediv__) => { - toggle_subslot!( - number, + toggle_ext_func!( + number_slots, right_true_divide, number_binary_op_wrapper!(__rtruediv__) ); } _ if name == identifier!(ctx, __itruediv__) => { - toggle_subslot!( - number, + toggle_ext_func!( + number_slots, inplace_true_divide, number_binary_op_wrapper!(__itruediv__) ); } _ if name == identifier!(ctx, __matmul__) => { - toggle_subslot!( - number, + toggle_ext_func!( + number_slots, matrix_multiply, number_binary_op_wrapper!(__matmul__) ); } _ if name == identifier!(ctx, __rmatmul__) => { - toggle_subslot!( - number, + toggle_ext_func!( + number_slots, right_matrix_multiply, number_binary_op_wrapper!(__rmatmul__) ); } _ if name == identifier!(ctx, __imatmul__) => { - toggle_subslot!( - number, + toggle_ext_func!( + number_slots, inplace_matrix_multiply, number_binary_op_wrapper!(__imatmul__) ); @@ -1192,102 +1236,26 @@ pub trait AsSequence: PyPayload { } } -macro_rules! extend_number_slot { - ($slots:ident, $methods:ident, $method:ident, $right_method:ident, $op_slot:ident) => { - if $methods.$method.is_some() { - $slots.number.$method.store($methods.$method); - $slots.number.$right_method.store(Some(|num, other, vm| { - num.methods.binary_op(PyNumberBinaryOp::$op_slot).unwrap()( - other.to_number(), - num, - vm, - ) - })); - } - }; - ($slots:ident, $methods:ident, $method:ident) => { - if $methods.$method.is_some() { - $slots.number.$method.store($methods.$method); - } - }; -} - #[pyclass] pub trait AsNumber: PyPayload { #[pyslot] fn as_number() -> &'static PyNumberMethods; - fn clone_exact(_zelf: &Py, _vm: &VirtualMachine) -> PyRef { - // not all AsNumber requires this implementation. - unimplemented!() + fn number_downcast(zelf: PyNumber) -> &Py { + zelf.downcast_ref().unwrap() } - #[inline] - fn number_downcast(num: PyNumber) -> &Py { - unsafe { num.obj.downcast_unchecked_ref() } - } - - #[inline] - fn number_downcast_exact(number: PyNumber, vm: &VirtualMachine) -> PyRef { - if let Some(zelf) = number.obj.downcast_ref_if_exact::(vm) { + fn number_downcast_exact(zelf: PyNumber, vm: &VirtualMachine) -> PyRef { + if let Some(zelf) = zelf.downcast_ref_if_exact(vm) { zelf.to_owned() } else { - Self::clone_exact(Self::number_downcast(number), vm) + Self::clone_exact(Self::number_downcast(zelf), vm) } } - fn extend_slots(slots: &mut PyTypeSlots) { - let methods = Self::as_number(); - - extend_number_slot!(slots, methods, add, right_add, Add); - extend_number_slot!(slots, methods, subtract, right_subtract, Subtract); - extend_number_slot!(slots, methods, multiply, right_multiply, Multiply); - extend_number_slot!(slots, methods, remainder, right_remainder, Remainder); - extend_number_slot!(slots, methods, divmod, right_divmod, Divmod); - extend_number_slot!(slots, methods, power, right_power, Power); - extend_number_slot!(slots, methods, lshift, right_lshift, Lshift); - extend_number_slot!(slots, methods, rshift, right_rshift, Rshift); - extend_number_slot!(slots, methods, and, right_and, And); - extend_number_slot!(slots, methods, xor, right_xor, Xor); - extend_number_slot!(slots, methods, or, right_or, Or); - extend_number_slot!( - slots, - methods, - floor_divide, - right_floor_divide, - FloorDivide - ); - extend_number_slot!(slots, methods, true_divide, right_true_divide, TrueDivide); - extend_number_slot!( - slots, - methods, - matrix_multiply, - right_matrix_multiply, - MatrixMultiply - ); - - extend_number_slot!(slots, methods, negative); - extend_number_slot!(slots, methods, positive); - extend_number_slot!(slots, methods, absolute); - extend_number_slot!(slots, methods, boolean); - extend_number_slot!(slots, methods, invert); - extend_number_slot!(slots, methods, int); - extend_number_slot!(slots, methods, float); - extend_number_slot!(slots, methods, index); - - extend_number_slot!(slots, methods, inplace_add); - extend_number_slot!(slots, methods, inplace_subtract); - extend_number_slot!(slots, methods, inplace_multiply); - extend_number_slot!(slots, methods, inplace_remainder); - extend_number_slot!(slots, methods, inplace_power); - extend_number_slot!(slots, methods, inplace_lshift); - extend_number_slot!(slots, methods, inplace_rshift); - extend_number_slot!(slots, methods, inplace_and); - extend_number_slot!(slots, methods, inplace_xor); - extend_number_slot!(slots, methods, inplace_or); - extend_number_slot!(slots, methods, inplace_floor_divide); - extend_number_slot!(slots, methods, inplace_true_divide); - extend_number_slot!(slots, methods, inplace_matrix_multiply); + fn clone_exact(_zelf: &Py, _vm: &VirtualMachine) -> PyRef { + // not all AsNumber requires this implementation. + unimplemented!() } } From 521da91ecfc1b281b10886b7f0b0c97e2aed6891 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Sun, 19 Mar 2023 21:20:28 +0200 Subject: [PATCH 07/16] pass compile --- derive-impl/src/pyclass.rs | 7 ++++++- vm/src/builtins/bool.rs | 3 +-- vm/src/protocol/number.rs | 12 +++++++++--- vm/src/types/slot.rs | 12 ++++++------ 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/derive-impl/src/pyclass.rs b/derive-impl/src/pyclass.rs index df88eaeffd..e1c7d8b0e0 100644 --- a/derive-impl/src/pyclass.rs +++ b/derive-impl/src/pyclass.rs @@ -701,8 +701,9 @@ where let slot_ident = Ident::new(&slot_ident.to_string().to_lowercase(), slot_ident.span()); let slot_name = slot_ident.to_string(); let tokens = { - const NON_ATOMIC_SLOTS: &[&str] = &["as_buffer", "as_number"]; + const NON_ATOMIC_SLOTS: &[&str] = &["as_buffer"]; const POINTER_SLOTS: &[&str] = &["as_sequence", "as_mapping"]; + const STATIC_SLOTS: &[&str] = &["as_number"]; if NON_ATOMIC_SLOTS.contains(&slot_name.as_str()) { quote_spanned! { span => slots.#slot_ident = Some(Self::#ident as _); @@ -711,6 +712,10 @@ where quote_spanned! { span => slots.#slot_ident.store(Some(PointerSlot::from(Self::#ident()))); } + } else if STATIC_SLOTS.contains(&slot_name.as_str()) { + quote_spanned! { span => + slots.#slot_ident = Some(Self::#ident()); + } } else { quote_spanned! { span => slots.#slot_ident.store(Some(Self::#ident as _)); diff --git a/vm/src/builtins/bool.rs b/vm/src/builtins/bool.rs index 275294f0ca..2c11d66caf 100644 --- a/vm/src/builtins/bool.rs +++ b/vm/src/builtins/bool.rs @@ -173,8 +173,7 @@ impl AsNumber for PyBool { or: Some(|a, b, vm| { PyBool::or(a.to_owned(), b.to_owned(), vm).to_pyresult(vm) }), - // ..PyInt::AS_NUMBER - ..*PyInt::as_number() + ..PyInt::AS_NUMBER }; &AS_NUMBER } diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index acdaef5c2a..620bc468c8 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -17,7 +17,7 @@ pub type PyNumberBinaryFunc = fn(&PyObject, &PyObject, &VirtualMachine) -> PyRes #[derive(Copy, Clone)] pub struct PyNumber<'a>(&'a PyObject); -impl Deref for PyNumber<'_> { +impl<'a> Deref for PyNumber<'a> { type Target = PyObject; fn deref(&self) -> &Self::Target { @@ -25,10 +25,16 @@ impl Deref for PyNumber<'_> { } } +impl<'a> PyNumber<'a> { + pub(crate) fn obj(self) -> &'a PyObject { + self.0 + } +} + macro_rules! load_pynumber_method { ($cls:expr, $x:ident, $y:ident) => {{ let class = $cls; - if let Some(ext) = class.heaptype_ext { + if let Some(ext) = class.heaptype_ext.as_ref() { ext.number_slots.$y.load() } else if let Some(methods) = class.slots.as_number { methods.$x @@ -44,7 +50,7 @@ macro_rules! load_pynumber_method { impl PyNumber<'_> { pub fn check(obj: &PyObject) -> bool { let class = obj.class(); - if let Some(ext) = class.heaptype_ext { + if let Some(ext) = class.heaptype_ext.as_ref() { ext.number_slots.int.load().is_some() || ext.number_slots.index.load().is_some() || ext.number_slots.float.load().is_some() diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 53adc44dd6..0f7ca51eff 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -17,7 +17,7 @@ use crate::{ }; use crossbeam_utils::atomic::AtomicCell; use num_traits::{Signed, ToPrimitive}; -use std::{borrow::Borrow, cmp::Ordering}; +use std::{borrow::Borrow, cmp::Ordering, ops::Deref}; #[macro_export] macro_rules! atomic_func { @@ -199,21 +199,21 @@ pub(crate) fn len_wrapper(obj: &PyObject, vm: &VirtualMachine) -> PyResult PyResult> { - let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __int__), ())?; + let ret = vm.call_special_method(num.deref().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__), ())?; + let ret = vm.call_special_method(num.deref().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__), ())?; + let ret = vm.call_special_method(num.deref().to_owned(), identifier!(vm, __float__), ())?; ret.downcast::().map_err(|obj| { vm.new_type_error(format!( "__float__ returned non-float (type {})", @@ -1242,11 +1242,11 @@ pub trait AsNumber: PyPayload { fn as_number() -> &'static PyNumberMethods; fn number_downcast(zelf: PyNumber) -> &Py { - zelf.downcast_ref().unwrap() + unsafe { zelf.obj().downcast_unchecked_ref() } } fn number_downcast_exact(zelf: PyNumber, vm: &VirtualMachine) -> PyRef { - if let Some(zelf) = zelf.downcast_ref_if_exact(vm) { + if let Some(zelf) = zelf.downcast_ref_if_exact::(vm) { zelf.to_owned() } else { Self::clone_exact(Self::number_downcast(zelf), vm) From 7f2a1976d1ff1a4b946568d48a039a84012c591a Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Mon, 20 Mar 2023 10:06:28 +0200 Subject: [PATCH 08/16] fill number_slots when creating type --- stdlib/src/array.rs | 2 +- vm/src/builtins/type.rs | 127 +++++++++++++++++++------------------- vm/src/stdlib/builtins.rs | 10 +-- 3 files changed, 71 insertions(+), 68 deletions(-) diff --git a/stdlib/src/array.rs b/stdlib/src/array.rs index 5becd160df..8f40d80a6f 100644 --- a/stdlib/src/array.rs +++ b/stdlib/src/array.rs @@ -8,7 +8,7 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyObjectRef { let array = module .get_attr("array", vm) .expect("Expect array has array type."); - array.init_builtin_number_slots(&vm.ctx); + // array.init_builtin_number_slots(&vm.ctx); let collections_abc = vm .import("collections.abc", None, 0) diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 65e9ac99c4..e14e1c64d4 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -149,7 +149,7 @@ impl PyType { let heaptype_ext = HeapTypeExt { name: PyRwLock::new(name), slots: None, - number_methods: PyNumberMethods::default(), + number_slots: PyNumberSlots::default(), sequence_methods: PySequenceMethods::default(), mapping_methods: PyMappingMethods::default(), }; @@ -755,6 +755,9 @@ impl PyType { base.slots.member_count + heaptype_slots.as_ref().map(|x| x.len()).unwrap_or(0); let flags = PyTypeFlags::heap_type_flags() | PyTypeFlags::HAS_DICT; + + let number_slots = base.slots.as_number.map(|x| x.into()).unwrap_or_default(); + let (slots, heaptype_ext) = unsafe { // # Safety // `slots.name` live long enough because `heaptype_ext` is alive. @@ -765,7 +768,7 @@ impl PyType { let heaptype_ext = HeapTypeExt { name: PyRwLock::new(name), slots: heaptype_slots.to_owned(), - number_methods: PyNumberMethods::default(), + number_slots, sequence_methods: PySequenceMethods::default(), mapping_methods: PyMappingMethods::default(), }; @@ -1377,63 +1380,63 @@ mod tests { } } -impl crate::PyObject { - // temporary tool to fill missing number protocols for builtin types - pub fn init_builtin_number_slots(&self, ctx: &Context) { - let typ = self - .downcast_ref::() - .expect("not called from a type"); - macro_rules! call_update_slot { - ($name:ident) => { - let id = identifier!(ctx, $name); - if typ.has_attr(id) { - typ.update_slot::(identifier!(ctx, $name), ctx); - } - }; - } - call_update_slot!(__add__); - call_update_slot!(__radd__); - call_update_slot!(__iadd__); - call_update_slot!(__sub__); - call_update_slot!(__rsub__); - call_update_slot!(__isub__); - call_update_slot!(__mul__); - call_update_slot!(__rmul__); - call_update_slot!(__imul__); - call_update_slot!(__mod__); - call_update_slot!(__rmod__); - call_update_slot!(__imod__); - call_update_slot!(__div__); - call_update_slot!(__rdiv__); - call_update_slot!(__idiv__); - call_update_slot!(__divmod__); - call_update_slot!(__rdivmod__); - call_update_slot!(__pow__); - call_update_slot!(__rpow__); - call_update_slot!(__ipow__); - call_update_slot!(__lshift__); - call_update_slot!(__rlshift__); - call_update_slot!(__ilshift__); - call_update_slot!(__rshift__); - call_update_slot!(__rrshift__); - call_update_slot!(__irshift__); - call_update_slot!(__and__); - call_update_slot!(__rand__); - call_update_slot!(__iand__); - call_update_slot!(__xor__); - call_update_slot!(__rxor__); - call_update_slot!(__ixor__); - call_update_slot!(__or__); - call_update_slot!(__ror__); - call_update_slot!(__ior__); - call_update_slot!(__floordiv__); - call_update_slot!(__rfloordiv__); - call_update_slot!(__ifloordiv__); - call_update_slot!(__truediv__); - call_update_slot!(__rtruediv__); - call_update_slot!(__itruediv__); - call_update_slot!(__matmul__); - call_update_slot!(__rmatmul__); - call_update_slot!(__imatmul__); - } -} +// impl crate::PyObject { +// // temporary tool to fill missing number protocols for builtin types +// pub fn init_builtin_number_slots(&self, ctx: &Context) { +// let typ = self +// .downcast_ref::() +// .expect("not called from a type"); +// macro_rules! call_update_slot { +// ($name:ident) => { +// let id = identifier!(ctx, $name); +// if typ.has_attr(id) { +// typ.update_slot::(identifier!(ctx, $name), ctx); +// } +// }; +// } +// call_update_slot!(__add__); +// call_update_slot!(__radd__); +// call_update_slot!(__iadd__); +// call_update_slot!(__sub__); +// call_update_slot!(__rsub__); +// call_update_slot!(__isub__); +// call_update_slot!(__mul__); +// call_update_slot!(__rmul__); +// call_update_slot!(__imul__); +// call_update_slot!(__mod__); +// call_update_slot!(__rmod__); +// call_update_slot!(__imod__); +// call_update_slot!(__div__); +// call_update_slot!(__rdiv__); +// call_update_slot!(__idiv__); +// call_update_slot!(__divmod__); +// call_update_slot!(__rdivmod__); +// call_update_slot!(__pow__); +// call_update_slot!(__rpow__); +// call_update_slot!(__ipow__); +// call_update_slot!(__lshift__); +// call_update_slot!(__rlshift__); +// call_update_slot!(__ilshift__); +// call_update_slot!(__rshift__); +// call_update_slot!(__rrshift__); +// call_update_slot!(__irshift__); +// call_update_slot!(__and__); +// call_update_slot!(__rand__); +// call_update_slot!(__iand__); +// call_update_slot!(__xor__); +// call_update_slot!(__rxor__); +// call_update_slot!(__ixor__); +// call_update_slot!(__or__); +// call_update_slot!(__ror__); +// call_update_slot!(__ior__); +// call_update_slot!(__floordiv__); +// call_update_slot!(__rfloordiv__); +// call_update_slot!(__ifloordiv__); +// call_update_slot!(__truediv__); +// call_update_slot!(__rtruediv__); +// call_update_slot!(__itruediv__); +// call_update_slot!(__matmul__); +// call_update_slot!(__rmatmul__); +// call_update_slot!(__imatmul__); +// } +// } diff --git a/vm/src/stdlib/builtins.rs b/vm/src/stdlib/builtins.rs index 00be9a31eb..f1c96d1c8f 100644 --- a/vm/src/stdlib/builtins.rs +++ b/vm/src/stdlib/builtins.rs @@ -946,11 +946,11 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef) { crate::protocol::VecBuffer::make_class(&vm.ctx); builtins::extend_module(vm, &module); - use crate::AsObject; - ctx.types - .generic_alias_type - .as_object() - .init_builtin_number_slots(&vm.ctx); + // use crate::AsObject; + // ctx.types + // .generic_alias_type + // .as_object() + // .init_builtin_number_slots(&vm.ctx); let debug_mode: bool = vm.state.settings.optimize == 0; extend_module!(vm, module, { From 0ca8d0d899d375363bde80ddfa66e99504ba7a11 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Mon, 20 Mar 2023 10:34:44 +0200 Subject: [PATCH 09/16] fix array not implement with AsSequence --- stdlib/src/array.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/src/array.rs b/stdlib/src/array.rs index 8f40d80a6f..454f8836a4 100644 --- a/stdlib/src/array.rs +++ b/stdlib/src/array.rs @@ -722,7 +722,7 @@ mod array { #[pyclass( flags(BASETYPE), - with(Comparable, AsBuffer, AsMapping, Iterable, Constructor) + with(Comparable, AsBuffer, AsMapping, AsSequence, Iterable, Constructor) )] impl PyArray { fn read(&self) -> PyRwLockReadGuard<'_, ArrayContentType> { From be09ec90d324cc38a31c89168c0d8158071e54b1 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Mon, 20 Mar 2023 10:45:22 +0200 Subject: [PATCH 10/16] impl number_or for genericalias --- vm/src/builtins/genericalias.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/vm/src/builtins/genericalias.rs b/vm/src/builtins/genericalias.rs index 857c45430e..a4bad3d00e 100644 --- a/vm/src/builtins/genericalias.rs +++ b/vm/src/builtins/genericalias.rs @@ -8,9 +8,9 @@ use crate::{ common::hash, convert::ToPyObject, function::{FuncArgs, PyComparisonValue}, - protocol::PyMappingMethods, + protocol::{PyMappingMethods, PyNumberMethods}, types::{ - AsMapping, Callable, Comparable, Constructor, GetAttr, Hashable, PyComparisonOp, + AsMapping, AsNumber, Callable, Comparable, Constructor, GetAttr, Hashable, PyComparisonOp, Representable, }, AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, @@ -65,6 +65,7 @@ impl Constructor for PyGenericAlias { #[pyclass( with( AsMapping, + AsNumber, Callable, Comparable, Constructor, @@ -342,6 +343,16 @@ impl AsMapping for PyGenericAlias { } } +impl AsNumber for PyGenericAlias { + fn as_number() -> &'static PyNumberMethods { + static AS_NUMBER: PyNumberMethods = PyNumberMethods { + or: Some(|a, b, vm| Ok(PyGenericAlias::or(a.to_owned(), b.to_owned(), vm))), + ..PyNumberMethods::NOT_IMPLEMENTED + }; + &AS_NUMBER + } +} + impl Callable for PyGenericAlias { type Args = FuncArgs; fn call(zelf: &Py, args: FuncArgs, vm: &VirtualMachine) -> PyResult { From ffd0f43c58ffc5f50f4c5c36249c33dd54a54466 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Mon, 20 Mar 2023 11:51:54 +0200 Subject: [PATCH 11/16] fixup --- vm/src/builtins/dict.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index dbf058cb15..4399328632 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -1170,7 +1170,7 @@ impl AsNumber for PyDictKeys { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { subtract: Some(inner_set_number_subtract), - add: Some(inner_set_number_add), + and: Some(inner_set_number_and), xor: Some(inner_set_number_xor), or: Some(inner_set_number_or), ..PyNumberMethods::NOT_IMPLEMENTED @@ -1248,7 +1248,7 @@ impl AsNumber for PyDictItems { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { subtract: Some(inner_set_number_subtract), - and: Some(inner_set_number_add), + and: Some(inner_set_number_and), xor: Some(inner_set_number_xor), or: Some(inner_set_number_or), ..PyNumberMethods::NOT_IMPLEMENTED @@ -1292,7 +1292,7 @@ fn inner_set_number_subtract(a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> inner_set_number_op(a, b, |a, b| a.difference(b, vm), vm) } -fn inner_set_number_add(a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult { +fn inner_set_number_and(a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult { inner_set_number_op(a, b, |a, b| a.intersection(b, vm), vm) } From c7c44e9625f33f3835122d8ea59ae40cb28cff82 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Mon, 20 Mar 2023 20:14:33 +0200 Subject: [PATCH 12/16] fix right_op_wrapper --- vm/src/protocol/number.rs | 16 ++-- vm/src/types/slot.rs | 157 ++++++++++++++++++++------------------ vm/src/vm/vm_ops.rs | 4 +- 3 files changed, 96 insertions(+), 81 deletions(-) diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index 620bc468c8..feeb877ea8 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -51,14 +51,19 @@ impl PyNumber<'_> { pub fn check(obj: &PyObject) -> bool { let class = obj.class(); if let Some(ext) = class.heaptype_ext.as_ref() { - ext.number_slots.int.load().is_some() + if ext.number_slots.int.load().is_some() || ext.number_slots.index.load().is_some() || ext.number_slots.float.load().is_some() - } else if let Some(methods) = class.slots.as_number { - methods.int.is_some() || methods.index.is_some() || methods.float.is_some() - } else { - obj.payload_is::() + { + return true; + } + } + if let Some(methods) = class.slots.as_number { + if methods.int.is_some() || methods.index.is_some() || methods.float.is_some() { + return true; + } } + obj.payload_is::() } pub fn is_index(self) -> bool { @@ -472,7 +477,6 @@ impl From<&PyNumberMethods> for PyNumberSlots { fn from(value: &PyNumberMethods) -> Self { // right_* functions will use the same left function as PyNumberMethods garrentee to // support both f(self, other) and f(other, self) - // the caller will have to reverse direction when calling right_* functions Self { add: AtomicCell::new(value.add), subtract: AtomicCell::new(value.subtract), diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 0f7ca51eff..f8ef14bc59 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -224,9 +224,13 @@ fn float_wrapper(num: PyNumber, vm: &VirtualMachine) -> PyResult> macro_rules! number_binary_op_wrapper { ($name:ident) => { - |num, other, vm| { - vm.call_special_method(num.to_owned(), identifier!(vm, $name), (other.to_owned(),)) - } + |a, b, vm| vm.call_special_method(a.to_owned(), identifier!(vm, $name), (b.to_owned(),)) + }; +} + +macro_rules! number_binary_right_op_wrapper { + ($name:ident) => { + |a, b, vm| vm.call_special_method(b.to_owned(), identifier!(vm, $name), (a.to_owned(),)) }; } @@ -388,15 +392,6 @@ impl PyType { }}; } - macro_rules! toggle_subslot { - ($group:ident, $name:ident, $func:expr) => { - self.slots - .$group - .$name - .store(if ADD { Some($func) } else { None }); - }; - } - macro_rules! update_slot { ($name:ident, $func:expr) => {{ self.slots.$name.store(Some($func)); @@ -411,7 +406,7 @@ impl PyType { }}; } - macro_rules! toggle_ext_func { + macro_rules! toggle_ext_slot { ($n1:ident, $n2:ident, $func:expr) => {{ self.heaptype_ext.as_ref().unwrap().$n1.$n2.store(if ADD { Some($func) @@ -424,9 +419,9 @@ impl PyType { match name { _ if name == identifier!(ctx, __len__) => { // update_slot!(as_mapping, slot_as_mapping); - toggle_ext_func!(sequence_methods, length, |seq, vm| len_wrapper(seq.obj, vm)); + toggle_ext_slot!(sequence_methods, length, |seq, vm| len_wrapper(seq.obj, vm)); update_pointer_slot!(as_sequence, sequence_methods); - toggle_ext_func!(mapping_methods, length, |mapping, vm| len_wrapper( + toggle_ext_slot!(mapping_methods, length, |mapping, vm| len_wrapper( mapping.obj, vm )); @@ -434,22 +429,22 @@ impl PyType { } _ if name == identifier!(ctx, __getitem__) => { // update_slot!(as_mapping, slot_as_mapping); - toggle_ext_func!(sequence_methods, item, |seq, i, vm| getitem_wrapper( + toggle_ext_slot!(sequence_methods, item, |seq, i, vm| getitem_wrapper( seq.obj, i, vm )); update_pointer_slot!(as_sequence, sequence_methods); - toggle_ext_func!(mapping_methods, subscript, |mapping, key, vm| { + toggle_ext_slot!(mapping_methods, subscript, |mapping, key, vm| { getitem_wrapper(mapping.obj, key, vm) }); update_pointer_slot!(as_mapping, mapping_methods); } _ if name == identifier!(ctx, __setitem__) || name == identifier!(ctx, __delitem__) => { // update_slot!(as_mapping, slot_as_mapping); - toggle_ext_func!(sequence_methods, ass_item, |seq, i, value, vm| { + toggle_ext_slot!(sequence_methods, ass_item, |seq, i, value, vm| { setitem_wrapper(seq.obj, i, value, vm) }); update_pointer_slot!(as_sequence, sequence_methods); - toggle_ext_func!(mapping_methods, ass_subscript, |mapping, key, value, vm| { + toggle_ext_slot!(mapping_methods, ass_subscript, |mapping, key, value, vm| { setitem_wrapper(mapping.obj, key, value, vm) }); update_pointer_slot!(as_mapping, mapping_methods); @@ -512,232 +507,248 @@ impl PyType { toggle_slot!(del, del_wrapper); } _ if name == identifier!(ctx, __int__) => { - toggle_ext_func!(number_slots, int, int_wrapper); + toggle_ext_slot!(number_slots, int, int_wrapper); } _ if name == identifier!(ctx, __index__) => { - toggle_ext_func!(number_slots, index, index_wrapper); + toggle_ext_slot!(number_slots, index, index_wrapper); } _ if name == identifier!(ctx, __float__) => { - toggle_ext_func!(number_slots, float, float_wrapper); + toggle_ext_slot!(number_slots, float, float_wrapper); } _ if name == identifier!(ctx, __add__) => { - toggle_ext_func!(number_slots, add, number_binary_op_wrapper!(__add__)); + toggle_ext_slot!(number_slots, add, number_binary_op_wrapper!(__add__)); } _ if name == identifier!(ctx, __radd__) => { - toggle_ext_func!(number_slots, right_add, number_binary_op_wrapper!(__radd__)); + toggle_ext_slot!( + number_slots, + right_add, + number_binary_right_op_wrapper!(__radd__) + ); } _ if name == identifier!(ctx, __iadd__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, inplace_add, number_binary_op_wrapper!(__iadd__) ); } _ if name == identifier!(ctx, __sub__) => { - toggle_ext_func!(number_slots, subtract, number_binary_op_wrapper!(__sub__)); + toggle_ext_slot!(number_slots, subtract, number_binary_op_wrapper!(__sub__)); } _ if name == identifier!(ctx, __rsub__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, right_subtract, - number_binary_op_wrapper!(__rsub__) + number_binary_right_op_wrapper!(__rsub__) ); } _ if name == identifier!(ctx, __isub__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, inplace_subtract, number_binary_op_wrapper!(__isub__) ); } _ if name == identifier!(ctx, __mul__) => { - toggle_ext_func!(number_slots, multiply, number_binary_op_wrapper!(__mul__)); + toggle_ext_slot!(number_slots, multiply, number_binary_op_wrapper!(__mul__)); } _ if name == identifier!(ctx, __rmul__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, right_multiply, - number_binary_op_wrapper!(__rmul__) + number_binary_right_op_wrapper!(__rmul__) ); } _ if name == identifier!(ctx, __imul__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, inplace_multiply, number_binary_op_wrapper!(__imul__) ); } _ if name == identifier!(ctx, __mod__) => { - toggle_ext_func!(number_slots, remainder, number_binary_op_wrapper!(__mod__)); + toggle_ext_slot!(number_slots, remainder, number_binary_op_wrapper!(__mod__)); } _ if name == identifier!(ctx, __rmod__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, right_remainder, - number_binary_op_wrapper!(__rmod__) + number_binary_right_op_wrapper!(__rmod__) ); } _ if name == identifier!(ctx, __imod__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, inplace_remainder, number_binary_op_wrapper!(__imod__) ); } _ if name == identifier!(ctx, __divmod__) => { - toggle_ext_func!(number_slots, divmod, number_binary_op_wrapper!(__divmod__)); + toggle_ext_slot!(number_slots, divmod, number_binary_op_wrapper!(__divmod__)); } _ if name == identifier!(ctx, __rdivmod__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, right_divmod, - number_binary_op_wrapper!(__rdivmod__) + number_binary_right_op_wrapper!(__rdivmod__) ); } _ if name == identifier!(ctx, __pow__) => { - toggle_ext_func!(number_slots, power, number_binary_op_wrapper!(__pow__)); + toggle_ext_slot!(number_slots, power, number_binary_op_wrapper!(__pow__)); } _ if name == identifier!(ctx, __rpow__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, right_power, - number_binary_op_wrapper!(__rpow__) + number_binary_right_op_wrapper!(__rpow__) ); } _ if name == identifier!(ctx, __ipow__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, inplace_power, number_binary_op_wrapper!(__ipow__) ); } _ if name == identifier!(ctx, __lshift__) => { - toggle_ext_func!(number_slots, lshift, number_binary_op_wrapper!(__lshift__)); + toggle_ext_slot!(number_slots, lshift, number_binary_op_wrapper!(__lshift__)); } _ if name == identifier!(ctx, __rlshift__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, right_lshift, - number_binary_op_wrapper!(__rlshift__) + number_binary_right_op_wrapper!(__rlshift__) ); } _ if name == identifier!(ctx, __ilshift__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, inplace_lshift, number_binary_op_wrapper!(__ilshift__) ); } _ if name == identifier!(ctx, __rshift__) => { - toggle_ext_func!(number_slots, rshift, number_binary_op_wrapper!(__rshift__)); + toggle_ext_slot!(number_slots, rshift, number_binary_op_wrapper!(__rshift__)); } _ if name == identifier!(ctx, __rrshift__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, right_rshift, - number_binary_op_wrapper!(__rrshift__) + number_binary_right_op_wrapper!(__rrshift__) ); } _ if name == identifier!(ctx, __irshift__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, inplace_rshift, number_binary_op_wrapper!(__irshift__) ); } _ if name == identifier!(ctx, __and__) => { - toggle_ext_func!(number_slots, and, number_binary_op_wrapper!(__and__)); + toggle_ext_slot!(number_slots, and, number_binary_op_wrapper!(__and__)); } _ if name == identifier!(ctx, __rand__) => { - toggle_ext_func!(number_slots, right_and, number_binary_op_wrapper!(__rand__)); + toggle_ext_slot!( + number_slots, + right_and, + number_binary_right_op_wrapper!(__rand__) + ); } _ if name == identifier!(ctx, __iand__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, inplace_and, number_binary_op_wrapper!(__iand__) ); } _ if name == identifier!(ctx, __xor__) => { - toggle_ext_func!(number_slots, xor, number_binary_op_wrapper!(__xor__)); + toggle_ext_slot!(number_slots, xor, number_binary_op_wrapper!(__xor__)); } _ if name == identifier!(ctx, __rxor__) => { - toggle_ext_func!(number_slots, right_xor, number_binary_op_wrapper!(__rxor__)); + toggle_ext_slot!( + number_slots, + right_xor, + number_binary_right_op_wrapper!(__rxor__) + ); } _ if name == identifier!(ctx, __ixor__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, inplace_xor, number_binary_op_wrapper!(__ixor__) ); } _ if name == identifier!(ctx, __or__) => { - toggle_ext_func!(number_slots, or, number_binary_op_wrapper!(__or__)); + toggle_ext_slot!(number_slots, or, number_binary_op_wrapper!(__or__)); } _ if name == identifier!(ctx, __ror__) => { - toggle_ext_func!(number_slots, right_or, number_binary_op_wrapper!(__ror__)); + toggle_ext_slot!( + number_slots, + right_or, + number_binary_right_op_wrapper!(__ror__) + ); } _ if name == identifier!(ctx, __ior__) => { - toggle_ext_func!(number_slots, inplace_or, number_binary_op_wrapper!(__ior__)); + toggle_ext_slot!(number_slots, inplace_or, number_binary_op_wrapper!(__ior__)); } _ if name == identifier!(ctx, __floordiv__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, floor_divide, number_binary_op_wrapper!(__floordiv__) ); } _ if name == identifier!(ctx, __rfloordiv__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, right_floor_divide, - number_binary_op_wrapper!(__rfloordiv__) + number_binary_right_op_wrapper!(__rfloordiv__) ); } _ if name == identifier!(ctx, __ifloordiv__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, inplace_floor_divide, number_binary_op_wrapper!(__ifloordiv__) ); } _ if name == identifier!(ctx, __truediv__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, true_divide, number_binary_op_wrapper!(__truediv__) ); } _ if name == identifier!(ctx, __rtruediv__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, right_true_divide, - number_binary_op_wrapper!(__rtruediv__) + number_binary_right_op_wrapper!(__rtruediv__) ); } _ if name == identifier!(ctx, __itruediv__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, inplace_true_divide, number_binary_op_wrapper!(__itruediv__) ); } _ if name == identifier!(ctx, __matmul__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, matrix_multiply, number_binary_op_wrapper!(__matmul__) ); } _ if name == identifier!(ctx, __rmatmul__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, right_matrix_multiply, - number_binary_op_wrapper!(__rmatmul__) + number_binary_right_op_wrapper!(__rmatmul__) ); } _ if name == identifier!(ctx, __imatmul__) => { - toggle_ext_func!( + toggle_ext_slot!( number_slots, inplace_matrix_multiply, number_binary_op_wrapper!(__imatmul__) diff --git a/vm/src/vm/vm_ops.rs b/vm/src/vm/vm_ops.rs index 8a8e2e2e9e..60ee1a5479 100644 --- a/vm/src/vm/vm_ops.rs +++ b/vm/src/vm/vm_ops.rs @@ -148,7 +148,7 @@ impl VirtualMachine { if let Some(slot_a) = slot_a { if let Some(slot_bb) = slot_b { if class_b.fast_isinstance(class_a) { - let x = slot_bb(b, a, self)?; + let x = slot_bb(a, b, self)?; if !x.is(&self.ctx.not_implemented) { return Ok(x); } @@ -162,7 +162,7 @@ impl VirtualMachine { } if let Some(slot_b) = slot_b { - let x = slot_b(b, a, self)?; + let x = slot_b(a, b, self)?; if !x.is(&self.ctx.not_implemented) { return Ok(x); } From 34077cf758d63dee9bd20a23b16ad7342bf407ea Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Mon, 20 Mar 2023 20:28:53 +0200 Subject: [PATCH 13/16] fix binary_op1 subclass check --- vm/src/protocol/number.rs | 4 ++-- vm/src/vm/vm_ops.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index feeb877ea8..574802bf56 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -475,8 +475,8 @@ pub struct PyNumberSlots { impl From<&PyNumberMethods> for PyNumberSlots { fn from(value: &PyNumberMethods) -> Self { - // right_* functions will use the same left function as PyNumberMethods garrentee to - // support both f(self, other) and f(other, self) + // right_* functions will use the same left function as PyNumberMethods + // allows both f(self, other) and f(other, self) Self { add: AtomicCell::new(value.add), subtract: AtomicCell::new(value.subtract), diff --git a/vm/src/vm/vm_ops.rs b/vm/src/vm/vm_ops.rs index 60ee1a5479..7fcf1c74cb 100644 --- a/vm/src/vm/vm_ops.rs +++ b/vm/src/vm/vm_ops.rs @@ -147,7 +147,7 @@ impl VirtualMachine { if let Some(slot_a) = slot_a { if let Some(slot_bb) = slot_b { - if class_b.fast_isinstance(class_a) { + if class_b.fast_issubclass(class_a) { let x = slot_bb(a, b, self)?; if !x.is(&self.ctx.not_implemented) { return Ok(x); From b6df5379c4d4426740d43065fc264999be63cd60 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Mon, 20 Mar 2023 20:39:58 +0200 Subject: [PATCH 14/16] clippy & fmt --- vm/src/builtins/bool.rs | 12 +++--------- vm/src/builtins/complex.rs | 14 ++++---------- vm/src/builtins/float.rs | 2 +- vm/src/builtins/int.rs | 2 +- vm/src/builtins/union.rs | 4 +--- vm/src/types/slot.rs | 3 +-- 6 files changed, 11 insertions(+), 26 deletions(-) diff --git a/vm/src/builtins/bool.rs b/vm/src/builtins/bool.rs index 2c11d66caf..2b246d2c52 100644 --- a/vm/src/builtins/bool.rs +++ b/vm/src/builtins/bool.rs @@ -164,15 +164,9 @@ impl PyBool { impl AsNumber for PyBool { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - and: Some(|a, b, vm| { - PyBool::and(a.to_owned(), b.to_owned(), vm).to_pyresult(vm) - }), - xor: Some(|a, b, vm| { - PyBool::xor(a.to_owned(), b.to_owned(), vm).to_pyresult(vm) - }), - or: Some(|a, b, vm| { - PyBool::or(a.to_owned(), b.to_owned(), vm).to_pyresult(vm) - }), + and: Some(|a, b, vm| PyBool::and(a.to_owned(), b.to_owned(), vm).to_pyresult(vm)), + xor: Some(|a, b, vm| PyBool::xor(a.to_owned(), b.to_owned(), vm).to_pyresult(vm)), + or: Some(|a, b, vm| PyBool::or(a.to_owned(), b.to_owned(), vm).to_pyresult(vm)), ..PyInt::AS_NUMBER }; &AS_NUMBER diff --git a/vm/src/builtins/complex.rs b/vm/src/builtins/complex.rs index f10f3c0466..d5ca733314 100644 --- a/vm/src/builtins/complex.rs +++ b/vm/src/builtins/complex.rs @@ -8,7 +8,7 @@ use crate::{ PyComparisonValue, }, identifier, - protocol::{PyNumber, PyNumberMethods}, + protocol::PyNumberMethods, types::{AsNumber, Comparable, Constructor, Hashable, PyComparisonOp, Representable}, AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; @@ -418,15 +418,9 @@ impl Hashable for PyComplex { impl AsNumber for PyComplex { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - add: Some(|a, b, vm| { - PyComplex::number_op(a, b, |a, b, _vm| a + b, vm) - }), - subtract: Some(|a, b, vm| { - PyComplex::number_op(a, b, |a, b, _vm| a - b, vm) - }), - multiply: Some(|a, b, vm| { - PyComplex::number_op(a, b, |a, b, _vm| a * b, vm) - }), + add: Some(|a, b, vm| PyComplex::number_op(a, b, |a, b, _vm| a + b, vm)), + subtract: Some(|a, b, vm| PyComplex::number_op(a, b, |a, b, _vm| a - b, vm)), + multiply: Some(|a, b, vm| PyComplex::number_op(a, b, |a, b, _vm| a * b, vm)), power: Some(|a, b, vm| PyComplex::number_op(a, b, inner_pow, vm)), negative: Some(|number, vm| { let value = PyComplex::number_downcast(number).value; diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index 08640fa863..ac37b9089a 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -13,7 +13,7 @@ use crate::{ PyArithmeticValue::{self, *}, PyComparisonValue, }, - protocol::{PyNumber, PyNumberMethods}, + protocol::PyNumberMethods, types::{AsNumber, Callable, Comparable, Constructor, Hashable, PyComparisonOp, Representable}, AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject, TryFromObject, VirtualMachine, diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index db63c07831..f2cce3efcb 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -13,7 +13,7 @@ use crate::{ ArgByteOrder, ArgIntoBool, OptionalArg, OptionalOption, PyArithmeticValue, PyComparisonValue, }, - protocol::{PyNumber, PyNumberMethods}, + protocol::PyNumberMethods, types::{AsNumber, Comparable, Constructor, Hashable, PyComparisonOp, Representable}, AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject, VirtualMachine, diff --git a/vm/src/builtins/union.rs b/vm/src/builtins/union.rs index aad29496f5..9cea279451 100644 --- a/vm/src/builtins/union.rs +++ b/vm/src/builtins/union.rs @@ -252,9 +252,7 @@ impl AsMapping for PyUnion { impl AsNumber for PyUnion { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - or: Some(|a, b, vm| { - PyUnion::or(a.to_owned(), b.to_owned(), vm).to_pyresult(vm) - }), + or: Some(|a, b, vm| PyUnion::or(a.to_owned(), b.to_owned(), vm).to_pyresult(vm)), ..PyNumberMethods::NOT_IMPLEMENTED }; &AS_NUMBER diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index f8ef14bc59..8883a5f51e 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -8,8 +8,7 @@ use crate::{ function::{Either, FromArgs, FuncArgs, OptionalArg, PyComparisonValue, PySetterValue}, identifier, protocol::{ - PyBuffer, PyIterReturn, PyMapping, PyMappingMethods, PyNumber, PyNumberBinaryFunc, - PyNumberBinaryOp, PyNumberMethods, PyNumberSlots, PyNumberUnaryFunc, PySequence, + PyBuffer, PyIterReturn, PyMapping, PyMappingMethods, PyNumber, PyNumberMethods, PySequence, PySequenceMethods, }, vm::Context, From 130ef1d59f05cf2c6f03255ad5fa9c7eca9e54ed Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Mon, 20 Mar 2023 21:22:30 +0200 Subject: [PATCH 15/16] clearup --- stdlib/src/array.rs | 1 - vm/src/builtins/type.rs | 61 --------------------------------------- vm/src/protocol/number.rs | 13 ++++----- vm/src/stdlib/builtins.rs | 5 ---- 4 files changed, 5 insertions(+), 75 deletions(-) diff --git a/stdlib/src/array.rs b/stdlib/src/array.rs index 454f8836a4..646180db1c 100644 --- a/stdlib/src/array.rs +++ b/stdlib/src/array.rs @@ -8,7 +8,6 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyObjectRef { let array = module .get_attr("array", vm) .expect("Expect array has array type."); - // array.init_builtin_number_slots(&vm.ctx); let collections_abc = vm .import("collections.abc", None, 0) diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index e14e1c64d4..f0dc87b398 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -1379,64 +1379,3 @@ mod tests { ); } } - -// impl crate::PyObject { -// // temporary tool to fill missing number protocols for builtin types -// pub fn init_builtin_number_slots(&self, ctx: &Context) { -// let typ = self -// .downcast_ref::() -// .expect("not called from a type"); -// macro_rules! call_update_slot { -// ($name:ident) => { -// let id = identifier!(ctx, $name); -// if typ.has_attr(id) { -// typ.update_slot::(identifier!(ctx, $name), ctx); -// } -// }; -// } -// call_update_slot!(__add__); -// call_update_slot!(__radd__); -// call_update_slot!(__iadd__); -// call_update_slot!(__sub__); -// call_update_slot!(__rsub__); -// call_update_slot!(__isub__); -// call_update_slot!(__mul__); -// call_update_slot!(__rmul__); -// call_update_slot!(__imul__); -// call_update_slot!(__mod__); -// call_update_slot!(__rmod__); -// call_update_slot!(__imod__); -// call_update_slot!(__div__); -// call_update_slot!(__rdiv__); -// call_update_slot!(__idiv__); -// call_update_slot!(__divmod__); -// call_update_slot!(__rdivmod__); -// call_update_slot!(__pow__); -// call_update_slot!(__rpow__); -// call_update_slot!(__ipow__); -// call_update_slot!(__lshift__); -// call_update_slot!(__rlshift__); -// call_update_slot!(__ilshift__); -// call_update_slot!(__rshift__); -// call_update_slot!(__rrshift__); -// call_update_slot!(__irshift__); -// call_update_slot!(__and__); -// call_update_slot!(__rand__); -// call_update_slot!(__iand__); -// call_update_slot!(__xor__); -// call_update_slot!(__rxor__); -// call_update_slot!(__ixor__); -// call_update_slot!(__or__); -// call_update_slot!(__ror__); -// call_update_slot!(__ior__); -// call_update_slot!(__floordiv__); -// call_update_slot!(__rfloordiv__); -// call_update_slot!(__ifloordiv__); -// call_update_slot!(__truediv__); -// call_update_slot!(__rtruediv__); -// call_update_slot!(__itruediv__); -// call_update_slot!(__matmul__); -// call_update_slot!(__rmatmul__); -// call_update_slot!(__imatmul__); -// } -// } diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index 574802bf56..230b02fed2 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -25,12 +25,6 @@ impl<'a> Deref for PyNumber<'a> { } } -impl<'a> PyNumber<'a> { - pub(crate) fn obj(self) -> &'a PyObject { - self.0 - } -} - macro_rules! load_pynumber_method { ($cls:expr, $x:ident, $y:ident) => {{ let class = $cls; @@ -47,7 +41,11 @@ macro_rules! load_pynumber_method { }}; } -impl PyNumber<'_> { +impl<'a> PyNumber<'a> { + pub(crate) fn obj(self) -> &'a PyObject { + self.0 + } + pub fn check(obj: &PyObject) -> bool { let class = obj.class(); if let Some(ext) = class.heaptype_ext.as_ref() { @@ -288,7 +286,6 @@ pub struct PyNumberMethods { impl PyNumberMethods { /// this is NOT a global variable - // TODO: weak order read for performance pub const NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods { add: None, subtract: None, diff --git a/vm/src/stdlib/builtins.rs b/vm/src/stdlib/builtins.rs index f1c96d1c8f..9b939657b5 100644 --- a/vm/src/stdlib/builtins.rs +++ b/vm/src/stdlib/builtins.rs @@ -946,11 +946,6 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef) { crate::protocol::VecBuffer::make_class(&vm.ctx); builtins::extend_module(vm, &module); - // use crate::AsObject; - // ctx.types - // .generic_alias_type - // .as_object() - // .init_builtin_number_slots(&vm.ctx); let debug_mode: bool = vm.state.settings.optimize == 0; extend_module!(vm, module, { From feb7deb3705b7262e723e5b8ace96a796436add9 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Tue, 21 Mar 2023 15:54:07 +0200 Subject: [PATCH 16/16] remove Option wrap for as_number --- derive-impl/src/pyclass.rs | 2 +- vm/src/builtins/type.rs | 2 +- vm/src/protocol/number.rs | 16 +++++++++------- vm/src/types/slot.rs | 32 ++++++++++++++++++++++++++++++-- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/derive-impl/src/pyclass.rs b/derive-impl/src/pyclass.rs index e1c7d8b0e0..eee341f6bf 100644 --- a/derive-impl/src/pyclass.rs +++ b/derive-impl/src/pyclass.rs @@ -714,7 +714,7 @@ where } } else if STATIC_SLOTS.contains(&slot_name.as_str()) { quote_spanned! { span => - slots.#slot_ident = Some(Self::#ident()); + slots.#slot_ident = Self::#ident(); } } else { quote_spanned! { span => diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index f0dc87b398..dd148453d9 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -756,7 +756,7 @@ impl PyType { let flags = PyTypeFlags::heap_type_flags() | PyTypeFlags::HAS_DICT; - let number_slots = base.slots.as_number.map(|x| x.into()).unwrap_or_default(); + let number_slots = base.slots.as_number.into(); let (slots, heaptype_ext) = unsafe { // # Safety diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index 230b02fed2..4f2cd9e919 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -30,10 +30,8 @@ macro_rules! load_pynumber_method { let class = $cls; if let Some(ext) = class.heaptype_ext.as_ref() { ext.number_slots.$y.load() - } else if let Some(methods) = class.slots.as_number { - methods.$x } else { - None + class.slots.as_number.$x } }}; ($cls:expr, $x:ident) => {{ @@ -56,10 +54,9 @@ impl<'a> PyNumber<'a> { return true; } } - if let Some(methods) = class.slots.as_number { - if methods.int.is_some() || methods.index.is_some() || methods.float.is_some() { - return true; - } + let methods = class.slots.as_number; + if methods.int.is_some() || methods.index.is_some() || methods.float.is_some() { + return true; } obj.payload_is::() } @@ -323,6 +320,11 @@ impl PyNumberMethods { matrix_multiply: None, inplace_matrix_multiply: None, }; + + pub fn not_implemented() -> &'static Self { + static GLOBAL_NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods::NOT_IMPLEMENTED; + &GLOBAL_NOT_IMPLEMENTED + } } #[derive(Copy, Clone)] diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 8883a5f51e..046f914cd7 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -27,7 +27,6 @@ macro_rules! atomic_func { // The corresponding field in CPython is `tp_` prefixed. // e.g. name -> tp_name -#[derive(Default)] #[non_exhaustive] pub struct PyTypeSlots { /// # Safety @@ -41,7 +40,7 @@ pub struct PyTypeSlots { // Methods to implement standard operations // Method suites for standard classes - pub as_number: Option<&'static PyNumberMethods>, + pub as_number: &'static PyNumberMethods, pub as_sequence: AtomicCell>>, pub as_mapping: AtomicCell>>, @@ -92,6 +91,35 @@ pub struct PyTypeSlots { pub member_count: usize, } +impl Default for PyTypeSlots { + fn default() -> Self { + Self { + name: Default::default(), + basicsize: Default::default(), + as_number: PyNumberMethods::not_implemented(), + as_sequence: Default::default(), + as_mapping: Default::default(), + hash: Default::default(), + call: Default::default(), + repr: Default::default(), + getattro: Default::default(), + setattro: Default::default(), + as_buffer: Default::default(), + richcompare: Default::default(), + iter: Default::default(), + iternext: Default::default(), + flags: Default::default(), + doc: Default::default(), + descr_get: Default::default(), + descr_set: Default::default(), + init: Default::default(), + new: Default::default(), + del: Default::default(), + member_count: Default::default(), + } + } +} + impl PyTypeSlots { pub fn new(name: &'static str, flags: PyTypeFlags) -> Self { Self {