ReprGuard to recursion

This commit is contained in:
Jeong Yunwon committed 2022-04-23 07:56:20 +09:00
1 parent f959ab9159
commit 0294473704
13 files changed
+64 -55

No files matched your search

+2 -1
View File
@@ -16,11 +16,12 @@ use crate::{
},
protocol::{PyIterIter, PyIterReturn, PyMappingMethods, PySequenceMethods},
pyclass::{PyClassDef, PyClassImpl},
recursion::ReprGuard,
types::{
AsMapping, AsSequence, Callable, Comparable, Constructor, Hashable, IterNext,
IterNextIterable, Iterable, PyComparisonOp, Unconstructible, Unhashable,
},
vm::{ReprGuard, VirtualMachine},
vm::VirtualMachine,
AsObject, Py, PyContext, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
};
use rustpython_common::lock::PyMutex;
+2 -1
View File
@@ -8,6 +8,7 @@ use crate::{
function::{FuncArgs, OptionalArg, PyComparisonValue},
protocol::{PyIterReturn, PyMappingMethods, PySequence, PySequenceMethods},
pyclass::PyClassImpl,
recursion::ReprGuard,
sequence::{MutObjectSequenceOp, ObjectSequenceOp, SequenceMutOp, SequenceOp},
sliceable::{saturate_index, SequenceIndex, SliceableSequenceMutOp, SliceableSequenceOp},
types::{
@@ -15,7 +16,7 @@ use crate::{
Iterable, PyComparisonOp, Unconstructible, Unhashable,
},
utils::collection_repr,
vm::{ReprGuard, VirtualMachine},
vm::VirtualMachine,
AsObject, Py, PyContext, PyObject, PyObjectRef, PyPayload, PyRef, PyResult,
};
use std::{borrow::Cow, fmt, ops::DerefMut};
+1 -1
View File
@@ -3,8 +3,8 @@ use crate::{
builtins::PyDict,
function::{FuncArgs, PyComparisonValue},
pyclass::PyClassImpl,
recursion::ReprGuard,
types::{Comparable, Constructor, PyComparisonOp},
vm::ReprGuard,
AsObject, PyContext, PyObject, PyPayload, PyRef, PyResult, VirtualMachine,
};
+2 -1
View File
@@ -11,12 +11,13 @@ use crate::{
function::{ArgIterable, FuncArgs, OptionalArg, PosArgs, PyArithmeticValue, PyComparisonValue},
protocol::{PyIterReturn, PySequenceMethods},
pyclass::PyClassImpl,
recursion::ReprGuard,
types::{
AsSequence, Comparable, Constructor, Hashable, IterNext, IterNextIterable, Iterable,
PyComparisonOp, Unconstructible, Unhashable,
},
utils::collection_repr,
vm::{ReprGuard, VirtualMachine},
vm::VirtualMachine,
AsObject, PyContext, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
};
use std::borrow::Cow;
+2 -1
View File
@@ -5,6 +5,7 @@ use crate::{
function::{OptionalArg, PyArithmeticValue, PyComparisonValue},
protocol::{PyIterReturn, PyMappingMethods, PySequenceMethods},
pyclass::PyClassImpl,
recursion::ReprGuard,
sequence::{ObjectSequenceOp, SequenceOp},
sliceable::{SequenceIndex, SliceableSequenceOp},
stdlib::sys,
@@ -13,7 +14,7 @@ use crate::{
Iterable, PyComparisonOp, Unconstructible,
},
utils::collection_repr,
vm::{ReprGuard, VirtualMachine},
vm::VirtualMachine,
AsObject, PyContext, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
};
use std::{borrow::Cow, fmt, marker::PhantomData};
+1
View File
@@ -67,6 +67,7 @@ pub mod py_io;
pub mod py_serde;
pub mod pyclass;
pub mod readline;
pub mod recursion;
pub mod scope;
pub mod sequence;
pub mod signal;
+30
View File
@@ -0,0 +1,30 @@
use crate::{AsObject, PyObject, VirtualMachine};
pub struct ReprGuard<'vm> {
vm: &'vm VirtualMachine,
id: usize,
}
/// A guard to protect repr methods from recursion into itself,
impl<'vm> ReprGuard<'vm> {
/// Returns None if the guard against 'obj' is still held otherwise returns the guard. The guard
/// which is released if dropped.
pub fn enter(vm: &'vm VirtualMachine, obj: &PyObject) -> Option<Self> {
let mut guards = vm.repr_guards.borrow_mut();
// Should this be a flag on the obj itself? putting it in a global variable for now until it
// decided the form of PyObject. https://github.com/RustPython/RustPython/issues/371
let id = obj.get_id();
if guards.contains(&id) {
return None;
}
guards.insert(id);
Some(ReprGuard { vm, id })
}
}
impl<'vm> Drop for ReprGuard<'vm> {
fn drop(&mut self) {
self.vm.repr_guards.borrow_mut().remove(&self.id);
}
}
+1 -1
View File
@@ -10,6 +10,7 @@ mod _collections {
common::lock::{PyMutex, PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard},
function::{FuncArgs, KwArgs, OptionalArg, PyComparisonValue},
protocol::{PyIterReturn, PySequenceMethods},
recursion::ReprGuard,
sequence::{MutObjectSequenceOp, ObjectSequenceOp},
sliceable,
sliceable::saturate_index,
@@ -18,7 +19,6 @@ mod _collections {
PyComparisonOp, Unhashable,
},
utils::collection_repr,
vm::ReprGuard,
AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
};
use crossbeam_utils::atomic::AtomicCell;
+2 -1
View File
@@ -111,9 +111,10 @@ mod _io {
BufferDescriptor, BufferMethods, BufferResizeGuard, PyBuffer, PyIterReturn, VecBuffer,
},
pyclass::StaticType,
recursion::ReprGuard,
types::{Constructor, Destructor, IterNext, Iterable},
utils::Either,
vm::{ReprGuard, VirtualMachine},
vm::VirtualMachine,
AsObject, PyContext, PyObject, PyObjectRef, PyPayload, PyRef, PyResult,
TryFromBorrowedObject, TryFromObject,
};
+1 -1
View File
@@ -14,12 +14,12 @@ mod _operator {
builtins::{PyInt, PyIntRef, PyStrRef, PyTupleRef, PyTypeRef},
function::{ArgBytesLike, FuncArgs, KwArgs, OptionalArg},
protocol::PyIter,
recursion::ReprGuard,
types::{
Callable, Constructor,
PyComparisonOp::{Eq, Ge, Gt, Le, Lt, Ne},
},
utils::Either,
vm::ReprGuard,
AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
};
+2 -1
View File
@@ -412,10 +412,11 @@ pub(super) mod _os {
crt_fd::{Fd, Offset},
function::{ArgBytesLike, FuncArgs, OptionalArg},
protocol::PyIterReturn,
recursion::ReprGuard,
suppress_iph,
types::{IterNext, IterNextIterable, PyStructSequence},
utils::Either,
vm::{ReprGuard, VirtualMachine},
vm::VirtualMachine,
AsObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
};
use crossbeam_utils::atomic::AtomicCell;
+18 -17
View File
@@ -46,24 +46,25 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static {
let s = value.repr(vm)?;
Ok(format!("{}={}", name, s))
};
let (body, suffix) =
if let Some(_guard) = rustpython_vm::vm::ReprGuard::enter(vm, zelf.as_object()) {
if Self::FIELD_NAMES.len() == 1 {
let value = zelf.as_slice().first().unwrap();
let formatted = format_field((value, Self::FIELD_NAMES[0]))?;
(formatted, ",")
} else {
let fields: PyResult<Vec<_>> = zelf
.as_slice()
.iter()
.zip(Self::FIELD_NAMES.iter().copied())
.map(format_field)
.collect();
(fields?.join(", "), "")
}
let (body, suffix) = if let Some(_guard) =
rustpython_vm::recursion::ReprGuard::enter(vm, zelf.as_object())
{
if Self::FIELD_NAMES.len() == 1 {
let value = zelf.as_slice().first().unwrap();
let formatted = format_field((value, Self::FIELD_NAMES[0]))?;
(formatted, ",")
} else {
(String::new(), "...")
};
let fields: PyResult<Vec<_>> = zelf
.as_slice()
.iter()
.zip(Self::FIELD_NAMES.iter().copied())
.map(format_field)
.collect();
(fields?.join(", "), "")
}
} else {
(String::new(), "...")
};
Ok(format!("{}({}{})", Self::TP_NAME, body, suffix))
}
-29
View File
@@ -750,32 +750,3 @@ impl VirtualMachine {
.map(|code| PyCode::new(self.map_codeobj(code)).into_ref(self))
}
}
pub struct ReprGuard<'vm> {
vm: &'vm VirtualMachine,
id: usize,
}
/// A guard to protect repr methods from recursion into itself,
impl<'vm> ReprGuard<'vm> {
/// Returns None if the guard against 'obj' is still held otherwise returns the guard. The guard
/// which is released if dropped.
pub fn enter(vm: &'vm VirtualMachine, obj: &PyObject) -> Option<Self> {
let mut guards = vm.repr_guards.borrow_mut();
// Should this be a flag on the obj itself? putting it in a global variable for now until it
// decided the form of PyObject. https://github.com/RustPython/RustPython/issues/371
let id = obj.get_id();
if guards.contains(&id) {
return None;
}
guards.insert(id);
Some(ReprGuard { vm, id })
}
}
impl<'vm> Drop for ReprGuard<'vm> {
fn drop(&mut self) {
self.vm.repr_guards.borrow_mut().remove(&self.id);
}
}