optimization with try_from_borrowed_object

This commit is contained in:
Jeong YunWon
2023-03-22 02:26:22 +09:00
parent 12297982c8
commit 80afab57d3
15 changed files with 93 additions and 126 deletions

View File

@@ -45,10 +45,10 @@ mod array {
atomic_func,
builtins::{
PositionIterInternal, PyByteArray, PyBytes, PyBytesRef, PyDictRef, PyFloat, PyInt,
PyIntRef, PyList, PyListRef, PyStr, PyStrRef, PyTupleRef, PyTypeRef,
PyList, PyListRef, PyStr, PyStrRef, PyTupleRef, PyTypeRef,
},
class_or_notimplemented,
convert::{ToPyObject, ToPyResult, TryFromObject},
convert::{ToPyObject, ToPyResult, TryFromBorrowedObject, TryFromObject},
function::{
ArgBytesLike, ArgIntoFloat, ArgIterable, KwArgs, OptionalArg, PyComparisonValue,
},
@@ -829,7 +829,7 @@ mod array {
#[pymethod]
fn fromunicode(zelf: &Py<Self>, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let utf8 = PyStrRef::try_from_object(vm, obj.clone()).map_err(|_| {
let utf8: &str = obj.try_to_value(vm).map_err(|_| {
vm.new_type_error(format!(
"fromunicode() argument must be str, not {}",
obj.class().name()
@@ -841,7 +841,7 @@ mod array {
));
}
let mut w = zelf.try_resizable(vm)?;
let bytes = Self::_unicode_to_wchar_bytes(utf8.as_str(), w.itemsize());
let bytes = Self::_unicode_to_wchar_bytes(utf8, w.itemsize());
w.frombytes_move(bytes);
Ok(())
}
@@ -1490,9 +1490,9 @@ mod array {
}
}
impl TryFromObject for MachineFormatCode {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
PyIntRef::try_from_object(vm, obj.clone())
impl<'a> TryFromBorrowedObject<'a> for MachineFormatCode {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
obj.try_to_ref::<PyInt>(vm)
.map_err(|_| {
vm.new_type_error(format!(
"an integer is required (got type {})",

View File

@@ -4,7 +4,7 @@ pub(crate) use _csv::make_module;
mod _csv {
use crate::common::lock::PyMutex;
use crate::vm::{
builtins::{PyStr, PyStrRef, PyTypeRef},
builtins::{PyStr, PyTypeRef},
function::{ArgIterable, ArgumentError, FromArgs, FuncArgs},
match_class,
protocol::{PyIter, PyIterReturn},
@@ -97,8 +97,8 @@ mod _csv {
impl FromArgs for FormatOptions {
fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result<Self, ArgumentError> {
let delimiter = if let Some(delimiter) = args.kwargs.remove("delimiter") {
PyStrRef::try_from_object(vm, delimiter)?
.as_str()
delimiter
.try_to_value::<&str>(vm)?
.bytes()
.exactly_one()
.map_err(|_| {
@@ -110,8 +110,8 @@ mod _csv {
};
let quotechar = if let Some(quotechar) = args.kwargs.remove("quotechar") {
PyStrRef::try_from_object(vm, quotechar)?
.as_str()
quotechar
.try_to_value::<&str>(vm)?
.bytes()
.exactly_one()
.map_err(|_| {

View File

@@ -1,8 +1,9 @@
use crate::{
builtins::{PyIntRef, PyTupleRef},
builtins::{PyIntRef, PyTuple},
cformat::cformat_string,
convert::TryFromBorrowedObject,
function::OptionalOption,
PyObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine,
Py, PyObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine,
};
use num_traits::{cast::ToPrimitive, sign::Signed};
@@ -213,21 +214,21 @@ pub trait AnyStr {
F: Fn(&Self) -> PyObjectRef;
#[inline]
fn py_startsendswith<T, F>(
fn py_startsendswith<'a, T, F>(
&self,
affix: PyObjectRef,
affix: &'a PyObject,
func_name: &str,
py_type_name: &str,
func: F,
vm: &VirtualMachine,
) -> PyResult<bool>
where
T: TryFromObject,
F: Fn(&Self, &T) -> bool,
T: TryFromBorrowedObject<'a>,
F: Fn(&Self, T) -> bool,
{
single_or_tuple_any(
affix,
&|s: &T| Ok(func(self, s)),
&|s: T| Ok(func(self, s)),
&|o| {
format!(
"{} first arg must be {} or a tuple of {}, not {}",
@@ -448,24 +449,25 @@ pub trait AnyStr {
/// test that any of the values contained within the tuples satisfies the predicate. Type parameter
/// T specifies the type that is expected, if the input value is not of that type or a tuple of
/// values of that type, then a TypeError is raised.
pub fn single_or_tuple_any<T, F, M>(
obj: PyObjectRef,
pub fn single_or_tuple_any<'a, T, F, M>(
obj: &'a PyObject,
predicate: &F,
message: &M,
vm: &VirtualMachine,
) -> PyResult<bool>
where
T: TryFromObject,
F: Fn(&T) -> PyResult<bool>,
T: TryFromBorrowedObject<'a>,
F: Fn(T) -> PyResult<bool>,
M: Fn(&PyObject) -> String,
{
match T::try_from_object(vm, obj.clone()) {
Ok(single) => (predicate)(&single),
match obj.try_to_value::<T>(vm) {
Ok(single) => (predicate)(single),
Err(_) => {
let tuple = PyTupleRef::try_from_object(vm, obj.clone())
.map_err(|_| vm.new_type_error((message)(&obj)))?;
for obj in &tuple {
if single_or_tuple_any(obj.clone(), predicate, message, vm)? {
let tuple: &Py<PyTuple> = obj
.try_to_value(vm)
.map_err(|_| vm.new_type_error((message)(obj)))?;
for obj in tuple {
if single_or_tuple_any(obj, predicate, message, vm)? {
return Ok(true);
}
}

View File

@@ -375,10 +375,10 @@ impl PyByteArray {
None => return Ok(false),
};
substr.py_startsendswith(
affix,
&affix,
"endswith",
"bytes",
|s, x: &PyBytesInner| s.ends_with(x.as_bytes()),
|s, x: PyBytesInner| s.ends_with(x.as_bytes()),
vm,
)
}
@@ -396,10 +396,10 @@ impl PyByteArray {
None => return Ok(false),
};
substr.py_startsendswith(
affix,
&affix,
"startswith",
"bytes",
|s, x: &PyBytesInner| s.starts_with(x.as_bytes()),
|s, x: PyBytesInner| s.starts_with(x.as_bytes()),
vm,
)
}

View File

@@ -300,10 +300,10 @@ impl PyBytes {
None => return Ok(false),
};
substr.py_startsendswith(
affix,
&affix,
"endswith",
"bytes",
|s, x: &PyBytesInner| s.ends_with(x.as_bytes()),
|s, x: PyBytesInner| s.ends_with(x.as_bytes()),
vm,
)
}
@@ -320,10 +320,10 @@ impl PyBytes {
None => return Ok(false),
};
substr.py_startsendswith(
affix,
&affix,
"startswith",
"bytes",
|s, x: &PyBytesInner| s.starts_with(x.as_bytes()),
|s, x: PyBytesInner| s.starts_with(x.as_bytes()),
vm,
)
}

View File

@@ -76,8 +76,8 @@ impl Constructor for PyGenericAlias {
)]
impl PyGenericAlias {
pub fn new(origin: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> Self {
let args: PyTupleRef = if let Ok(tuple) = PyTupleRef::try_from_object(vm, args.clone()) {
tuple
let args = if let Ok(tuple) = args.try_to_ref::<PyTuple>(vm) {
tuple.to_owned()
} else {
PyTuple::new_ref(vec![args], &vm.ctx)
};
@@ -223,21 +223,19 @@ pub(crate) fn is_typevar(obj: &PyObjectRef, vm: &VirtualMachine) -> bool {
.unwrap_or(false)
}
fn make_parameters(args: &PyTupleRef, vm: &VirtualMachine) -> PyTupleRef {
pub(crate) fn make_parameters(args: &Py<PyTuple>, vm: &VirtualMachine) -> PyTupleRef {
let mut parameters: Vec<PyObjectRef> = Vec::with_capacity(args.len());
for arg in args {
if is_typevar(arg, vm) {
if !parameters.iter().any(|param| param.is(arg)) {
parameters.push(arg.clone());
}
} else if let Ok(subparams) = arg
.clone()
.get_attr(identifier!(vm, __parameters__), vm)
.and_then(|obj| PyTupleRef::try_from_object(vm, obj))
{
for sub_param in &subparams {
if !parameters.iter().any(|param| param.is(sub_param)) {
parameters.push(sub_param.clone());
} else if let Ok(obj) = arg.get_attr(identifier!(vm, __parameters__), vm) {
if let Ok(sub_params) = obj.try_to_ref::<PyTuple>(vm) {
for sub_param in sub_params {
if !parameters.iter().any(|param| param.is(sub_param)) {
parameters.push(sub_param.clone());
}
}
}
}
@@ -258,13 +256,12 @@ fn subs_tvars(
argitems: &[PyObjectRef],
vm: &VirtualMachine,
) -> PyResult {
obj.clone()
.get_attr(identifier!(vm, __parameters__), vm)
obj.get_attr(identifier!(vm, __parameters__), vm)
.ok()
.and_then(|sub_params| {
PyTupleRef::try_from_object(vm, sub_params)
.ok()
.map(|sub_params| {
.and_then(|sub_params| {
if sub_params.len() > 0 {
let sub_args = sub_params
.iter()
@@ -283,7 +280,6 @@ fn subs_tvars(
}
})
})
.flatten()
.unwrap_or(Ok(obj))
}
@@ -299,9 +295,9 @@ pub fn subs_parameters<F: Fn(&VirtualMachine) -> PyResult<String>>(
return Err(vm.new_type_error(format!("There are no type variables left in {}", repr(vm)?)));
}
let items = PyTupleRef::try_from_object(vm, needle.clone());
let items = needle.try_to_ref::<PyTuple>(vm);
let arg_items = match items {
Ok(ref tuple) => tuple.as_slice(),
Ok(tuple) => tuple.as_slice(),
Err(_) => std::slice::from_ref(&needle),
};

View File

@@ -647,10 +647,10 @@ impl PyStr {
None => return Ok(false),
};
substr.py_startsendswith(
affix,
&affix,
"endswith",
"str",
|s, x: &PyStrRef| s.ends_with(x.as_str()),
|s, x: &Py<PyStr>| s.ends_with(x.as_str()),
vm,
)
}
@@ -667,10 +667,10 @@ impl PyStr {
None => return Ok(false),
};
substr.py_startsendswith(
affix,
&affix,
"startswith",
"str",
|s, x: &PyStrRef| s.starts_with(x.as_str()),
|s, x: &Py<PyStr>| s.starts_with(x.as_str()),
vm,
)
}

View File

@@ -139,7 +139,7 @@ impl<'a> std::iter::IntoIterator for &'a PyTuple {
}
}
impl<'a> std::iter::IntoIterator for &'a PyTupleRef {
impl<'a> std::iter::IntoIterator for &'a Py<PyTuple> {
type Item = &'a PyObjectRef;
type IntoIter = std::slice::Iter<'a, PyObjectRef>;
@@ -482,7 +482,7 @@ pub struct PyTupleTyped<T: TransmuteFromObject> {
impl<T: TransmuteFromObject> TryFromObject for PyTupleTyped<T> {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
let tuple = PyTupleRef::try_from_object(vm, obj)?;
for elem in &tuple {
for elem in &*tuple {
T::check(vm, elem)?
}
// SAFETY: the contract of TransmuteFromObject upholds the variant on `tuple`

View File

@@ -1198,7 +1198,7 @@ pub(super) fn or_(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) ->
}
let tuple = PyTuple::new_ref(vec![zelf, other], &vm.ctx);
union_::make_union(tuple, vm)
union_::make_union(&tuple, vm)
}
fn take_next_base(bases: &mut [Vec<PyTypeRef>]) -> Option<PyTypeRef> {

View File

@@ -8,8 +8,7 @@ use crate::{
function::PyComparisonValue,
protocol::{PyMappingMethods, PyNumberMethods},
types::{AsMapping, AsNumber, Comparable, GetAttr, Hashable, PyComparisonOp, Representable},
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
VirtualMachine,
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
};
use once_cell::sync::Lazy;
use std::fmt;
@@ -139,33 +138,14 @@ pub fn is_unionable(obj: PyObjectRef, vm: &VirtualMachine) -> bool {
|| obj.class().is(vm.ctx.types.union_type)
}
fn make_parameters(args: &PyTupleRef, vm: &VirtualMachine) -> PyTupleRef {
let mut parameters: Vec<PyObjectRef> = Vec::with_capacity(args.len());
for arg in args {
if genericalias::is_typevar(arg, vm) {
if !parameters.iter().any(|param| param.is(arg)) {
parameters.push(arg.clone());
}
} else if let Ok(sub_params) = arg
.clone()
.get_attr(identifier!(vm, __parameters__), vm)
.and_then(|obj| PyTupleRef::try_from_object(vm, obj))
{
for sub_param in &sub_params {
if !parameters.iter().any(|param| param.is(sub_param)) {
parameters.push(sub_param.clone());
}
}
}
}
parameters.shrink_to_fit();
dedup_and_flatten_args(PyTuple::new_ref(parameters, &vm.ctx), vm)
fn make_parameters(args: &Py<PyTuple>, vm: &VirtualMachine) -> PyTupleRef {
let parameters = genericalias::make_parameters(args, vm);
dedup_and_flatten_args(&parameters, vm)
}
fn flatten_args(args: PyTupleRef, vm: &VirtualMachine) -> PyTupleRef {
fn flatten_args(args: &Py<PyTuple>, vm: &VirtualMachine) -> PyTupleRef {
let mut total_args = 0;
for arg in &args {
for arg in args {
if let Some(pyref) = arg.downcast_ref::<PyUnion>() {
total_args += pyref.args.len();
} else {
@@ -174,7 +154,7 @@ fn flatten_args(args: PyTupleRef, vm: &VirtualMachine) -> PyTupleRef {
}
let mut flattened_args = Vec::with_capacity(total_args);
for arg in &args {
for arg in args {
if let Some(pyref) = arg.downcast_ref::<PyUnion>() {
flattened_args.extend(pyref.args.iter().cloned());
} else if vm.is_none(arg) {
@@ -187,11 +167,11 @@ fn flatten_args(args: PyTupleRef, vm: &VirtualMachine) -> PyTupleRef {
PyTuple::new_ref(flattened_args, &vm.ctx)
}
fn dedup_and_flatten_args(args: PyTupleRef, vm: &VirtualMachine) -> PyTupleRef {
fn dedup_and_flatten_args(args: &Py<PyTuple>, vm: &VirtualMachine) -> PyTupleRef {
let args = flatten_args(args, vm);
let mut new_args: Vec<PyObjectRef> = Vec::with_capacity(args.len());
for arg in &args {
for arg in &*args {
if !new_args.iter().any(|param| {
param
.rich_compare_bool(arg, PyComparisonOp::Eq, vm)
@@ -206,7 +186,7 @@ fn dedup_and_flatten_args(args: PyTupleRef, vm: &VirtualMachine) -> PyTupleRef {
PyTuple::new_ref(new_args, &vm.ctx)
}
pub fn make_union(args: PyTupleRef, vm: &VirtualMachine) -> PyObjectRef {
pub fn make_union(args: &Py<PyTuple>, vm: &VirtualMachine) -> PyObjectRef {
let args = dedup_and_flatten_args(args, vm);
match args.len() {
1 => args.fast_getitem(0),
@@ -225,7 +205,7 @@ impl PyUnion {
)?;
let mut res;
if new_args.len() == 0 {
res = make_union(new_args, vm);
res = make_union(&new_args, vm);
} else {
res = new_args.fast_getitem(0);
for arg in new_args.iter().skip(1) {

View File

@@ -4,7 +4,7 @@
use crate::{
builtins::{
pystr::AsPyStr, PyBytes, PyDict, PyDictRef, PyGenericAlias, PyInt, PyStr, PyStrRef,
PyTupleRef, PyTypeRef,
PyTuple, PyTupleRef, PyType, PyTypeRef,
},
bytesinner::ByteInnerNewOptions,
common::{hash::PyHash, str::to_ascii},
@@ -377,9 +377,7 @@ impl PyObject {
return Ok(true);
}
let bases = derived
.to_owned()
.get_attr(identifier!(vm, __bases__), vm)?;
let bases = derived.get_attr(identifier!(vm, __bases__), vm)?;
let tuple = PyTupleRef::try_from_object(vm, bases)?;
let n = tuple.len();
@@ -409,11 +407,8 @@ impl PyObject {
}
fn recursive_issubclass(&self, cls: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
if let (Ok(obj), Ok(cls)) = (
PyTypeRef::try_from_object(vm, self.to_owned()),
PyTypeRef::try_from_object(vm, cls.to_owned()),
) {
Ok(obj.fast_issubclass(&cls))
if let (Ok(obj), Ok(cls)) = (self.try_to_ref::<PyType>(vm), cls.try_to_ref::<PyType>(vm)) {
Ok(obj.fast_issubclass(cls))
} else {
self.check_cls(self, vm, || {
format!("issubclass() arg 1 must be a class, not {}", self.class())
@@ -438,8 +433,8 @@ impl PyObject {
return self.recursive_issubclass(cls, vm);
}
if let Ok(tuple) = PyTupleRef::try_from_object(vm, cls.to_owned()) {
for typ in &tuple {
if let Ok(tuple) = cls.try_to_value::<&Py<PyTuple>>(vm) {
for typ in tuple {
if vm.with_recursion("in __subclasscheck__", || self.is_subclass(typ, vm))? {
return Ok(true);
}
@@ -460,17 +455,16 @@ impl PyObject {
}
fn abstract_isinstance(&self, cls: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
let r = if let Ok(typ) = PyTypeRef::try_from_object(vm, cls.to_owned()) {
if self.class().fast_issubclass(&typ) {
let r = if let Ok(typ) = cls.try_to_ref::<PyType>(vm) {
if self.class().fast_issubclass(typ) {
true
} else if let Ok(icls) = PyTypeRef::try_from_object(
vm,
self.to_owned().get_attr(identifier!(vm, __class__), vm)?,
) {
} else if let Ok(icls) =
PyTypeRef::try_from_object(vm, self.get_attr(identifier!(vm, __class__), vm)?)
{
if icls.is(self.class()) {
false
} else {
icls.fast_issubclass(&typ)
icls.fast_issubclass(typ)
}
} else {
false
@@ -482,7 +476,7 @@ impl PyObject {
cls.class()
)
})?;
let icls: PyObjectRef = self.to_owned().get_attr(identifier!(vm, __class__), vm)?;
let icls: PyObjectRef = self.get_attr(identifier!(vm, __class__), vm)?;
if vm.is_none(&icls) {
false
} else {
@@ -505,8 +499,8 @@ impl PyObject {
return self.abstract_isinstance(cls, vm);
}
if let Ok(tuple) = PyTupleRef::try_from_object(vm, cls.to_owned()) {
for typ in &tuple {
if let Ok(tuple) = cls.try_to_ref::<PyTuple>(vm) {
for typ in tuple {
if vm.with_recursion("in __instancecheck__", || self.is_instance(typ, vm))? {
return Ok(true);
}

View File

@@ -870,7 +870,7 @@ mod builtins {
let (metaclass, meta_name) = match metaclass {
Ok(mut metaclass) => {
for base in &bases {
for base in bases.iter() {
let base_class = base.class();
if base_class.fast_issubclass(&metaclass) {
metaclass = base.class().to_owned();

View File

@@ -946,7 +946,7 @@ mod decl {
return Err(vm.new_type_error(msg));
}
let cur = &args[0];
if let Ok(cur) = usize::try_from_object(vm, cur.clone()) {
if let Ok(cur) = cur.try_to_value(vm) {
zelf.cur.store(cur);
} else {
return Err(vm.new_type_error(String::from("Argument must be usize.")));

View File

@@ -29,7 +29,7 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyObjectRef {
#[pymodule(name = "posix")]
pub mod module {
use crate::{
builtins::{PyDictRef, PyInt, PyIntRef, PyListRef, PyStrRef, PyTupleRef, PyTypeRef},
builtins::{PyDictRef, PyInt, PyListRef, PyStrRef, PyTupleRef, PyTypeRef},
convert::{IntoPyException, ToPyObject, TryFromObject},
function::{Either, OptionalArg},
stdlib::os::{
@@ -1004,7 +1004,8 @@ pub mod module {
fn try_from_id(vm: &VirtualMachine, obj: PyObjectRef, typ_name: &str) -> PyResult<Option<u32>> {
use std::cmp::Ordering;
let i = PyIntRef::try_from_object(vm, obj.clone())
let i = obj
.try_to_ref::<PyInt>(vm)
.map_err(|_| {
vm.new_type_error(format!(
"an integer is required (got type {})",

View File

@@ -108,17 +108,11 @@ fn get_filter(
for i in 0..filters.borrow_vec().len() {
let tmp_item = if let Some(tmp_item) = filters.borrow_vec().get(i).cloned() {
let tmp_item = PyTupleRef::try_from_object(vm, tmp_item)?;
if tmp_item.len() == 5 {
Some(tmp_item)
} else {
None
}
(tmp_item.len() == 5).then_some(tmp_item)
} else {
None
};
let tmp_item = tmp_item.ok_or_else(|| {
vm.new_value_error(format!("_warnings.filters item {i} isn't a 5-tuple"))
})?;
}
.ok_or_else(|| vm.new_value_error(format!("_warnings.filters item {i} isn't a 5-tuple")))?;
/* Python code: action, msg, cat, mod, ln = item */
let action = if let Some(action) = tmp_item.get(0) {