Merge pull request #4721 from youknowone/opt-getattr

type.__name__ & getattr optimization
This commit is contained in:
Jeong YunWon
2023-03-20 21:01:16 +09:00
committed by GitHub
43 changed files with 553 additions and 495 deletions

View File

@@ -1650,8 +1650,6 @@ class GeneralModuleTests(unittest.TestCase):
f = None
support.gc_collect()
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_name_closed_socketio(self):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
fp = sock.makefile("rb")

View File

@@ -458,6 +458,7 @@ impl ModuleItem for ClassItem {
let set_attr = match py_names.len() {
0 => quote! {
let _ = new_class; // suppress warning
let _ = vm.ctx.intern_str(#class_name);
},
1 => {
let py_name = &py_names[0];

View File

@@ -78,7 +78,8 @@ impl<'vm> ShellHelper<'vm> {
let mut current = self.globals.get_item_opt(first.as_str(), self.vm).ok()??;
for attr in parents {
current = current.get_attr(attr.as_str(), self.vm).ok()?;
let attr = self.vm.ctx.new_str(attr.as_str());
current = current.get_attr(&attr, self.vm).ok()?;
}
let current_iter = str_iter_method(current, identifier!(self.vm, __dir__)).ok()?;

View File

@@ -766,7 +766,7 @@ mod _sqlite {
pub(super) fn setup_module(module: &PyObject, vm: &VirtualMachine) {
for (name, code) in ERROR_CODES {
let name = vm.ctx.new_str(*name);
let name = vm.ctx.intern_str(*name);
let code = vm.new_pyobj(*code);
module.set_attr(name, code, vm).unwrap();
}

View File

@@ -230,7 +230,7 @@ mod _ssl {
/// SSL/TLS connection terminated abruptly.
#[pyattr(name = "SSLEOFError", once)]
fn ssl_eof_error(vm: &VirtualMachine) -> PyTypeRef {
PyType::new_simple_ref("ssl.SSLEOFError", &ssl_error(vm), &vm.ctx).unwrap()
PyType::new_simple_heap("ssl.SSLEOFError", &ssl_error(vm), &vm.ctx).unwrap()
}
type OpensslVersionInfo = (u8, u8, u8, u8, u8);

View File

@@ -259,7 +259,7 @@ impl PyBuiltinMethod {
vm: &VirtualMachine,
) -> (Option<PyObjectRef>, (Option<PyObjectRef>, PyStrRef)) {
let builtins_getattr = vm.builtins.get_attr("getattr", vm).ok();
let classname = vm.builtins.get_attr(self.class.name().to_string(), vm).ok();
let classname = vm.builtins.get_attr(&self.class.__name__(vm), vm).ok();
(builtins_getattr, (classname, self.value.name.clone()))
}
}

View File

@@ -501,10 +501,10 @@ impl Comparable for PyBoundMethod {
}
impl GetAttr for PyBoundMethod {
fn getattro(zelf: &Py<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
fn getattro(zelf: &Py<Self>, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
let class_attr = vm
.ctx
.interned_str(&*name)
.interned_str(name)
.and_then(|attr_name| zelf.get_class_attr(attr_name));
if let Some(obj) = class_attr {
return vm.call_if_get_descriptor(obj, zelf.to_owned().into());

View File

@@ -3,7 +3,7 @@ use once_cell::sync::Lazy;
use super::type_;
use crate::{
atomic_func,
builtins::{PyList, PyStr, PyStrRef, PyTuple, PyTupleRef, PyType, PyTypeRef},
builtins::{PyList, PyStr, PyTuple, PyTupleRef, PyType, PyTypeRef},
class::PyClassImpl,
common::hash,
convert::ToPyObject,
@@ -214,9 +214,9 @@ impl PyGenericAlias {
}
}
fn is_typevar(obj: &PyObjectRef, vm: &VirtualMachine) -> bool {
pub(crate) fn is_typevar(obj: &PyObjectRef, vm: &VirtualMachine) -> bool {
let class = obj.class();
class.slot_name() == "TypeVar"
"TypeVar" == &*class.slot_name()
&& class
.get_attr(identifier!(vm, __module__))
.and_then(|o| o.downcast_ref::<PyStr>().map(|s| s.as_str() == "typing"))
@@ -390,7 +390,7 @@ impl Hashable for PyGenericAlias {
}
impl GetAttr for PyGenericAlias {
fn getattro(zelf: &Py<Self>, attr: PyStrRef, vm: &VirtualMachine) -> PyResult {
fn getattro(zelf: &Py<Self>, attr: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
for exc in ATTR_EXCEPTIONS.iter() {
if *(*exc) == attr.to_string() {
return zelf.as_object().generic_getattr(attr, vm);

View File

@@ -1,7 +1,6 @@
use super::pystr::IntoPyStrRef;
use super::{PyDictRef, PyStr, PyStrRef, PyType, PyTypeRef};
use crate::{
builtins::PyStrInterned,
builtins::{pystr::AsPyStr, PyStrInterned},
class::PyClassImpl,
convert::ToPyObject,
function::FuncArgs,
@@ -26,33 +25,21 @@ pub struct ModuleInitArgs {
doc: Option<PyStrRef>,
}
#[pyclass(with(GetAttr, Initializer, Representable), flags(BASETYPE, HAS_DICT))]
impl PyModule {
// pub(crate) fn new(d: PyDictRef) -> Self {
// PyModule { dict: d.into() }
// }
}
// #[inline]
// pub fn dict(&self) -> PyDictRef {
// self.dict.get()
// }
#[pyslot]
fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
PyModule {}.into_ref_with_type(vm, cls).map(Into::into)
}
fn getattr_inner(zelf: &Py<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
if let Some(attr) = zelf
.as_object()
.generic_getattr_opt(name.clone(), None, vm)?
{
impl Py<PyModule> {
fn getattr_inner(&self, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
if let Some(attr) = self.as_object().generic_getattr_opt(name, None, vm)? {
return Ok(attr);
}
if let Ok(getattr) = zelf.dict().get_item(identifier!(vm, __getattr__), vm) {
return getattr.call((name,), vm);
if let Ok(getattr) = self.dict().get_item(identifier!(vm, __getattr__), vm) {
return getattr.call((name.to_owned(),), vm);
}
let module_name = if let Some(name) = Self::name(zelf.to_owned(), vm) {
let module_name = if let Some(name) = self.name(vm) {
format!(" '{name}'")
} else {
"".to_owned()
@@ -60,26 +47,14 @@ impl PyModule {
Err(vm.new_attribute_error(format!("module{module_name} has no attribute '{name}'")))
}
fn name(zelf: PyRef<Self>, vm: &VirtualMachine) -> Option<PyStrRef> {
let name = zelf
fn name(&self, vm: &VirtualMachine) -> Option<PyStrRef> {
let name = self
.as_object()
.generic_getattr_opt(identifier!(vm, __name__).to_owned(), None, vm)
.generic_getattr_opt(identifier!(vm, __name__), None, vm)
.unwrap_or_default()?;
name.downcast::<PyStr>().ok()
}
#[pymethod(magic)]
fn dir(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
let dict = zelf
.as_object()
.dict()
.ok_or_else(|| vm.new_value_error("module has no dict".to_owned()))?;
let attrs = dict.into_iter().map(|(k, _v)| k).collect();
Ok(attrs)
}
}
impl Py<PyModule> {
// TODO: to be replaced by the commented-out dict method above once dictoffsets land
pub fn dict(&self) -> PyDictRef {
self.as_object().dict().unwrap()
@@ -104,12 +79,13 @@ impl Py<PyModule> {
.expect("Failed to set __spec__ on module");
}
pub fn get_attr(&self, attr_name: impl IntoPyStrRef, vm: &VirtualMachine) -> PyResult {
PyModule::getattr_inner(self, attr_name.into_pystr_ref(vm), vm)
pub fn get_attr<'a>(&self, attr_name: impl AsPyStr<'a>, vm: &VirtualMachine) -> PyResult {
self.getattr_inner(attr_name.as_pystr(&vm.ctx), vm)
}
pub fn set_attr(
pub fn set_attr<'a>(
&self,
attr_name: impl IntoPyStrRef,
attr_name: impl AsPyStr<'a>,
attr_value: impl Into<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<()> {
@@ -117,6 +93,24 @@ impl Py<PyModule> {
}
}
#[pyclass(with(GetAttr, Initializer, Representable), flags(BASETYPE, HAS_DICT))]
impl PyModule {
#[pyslot]
fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
PyModule {}.into_ref_with_type(vm, cls).map(Into::into)
}
#[pymethod(magic)]
fn dir(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
let dict = zelf
.as_object()
.dict()
.ok_or_else(|| vm.new_value_error("module has no dict".to_owned()))?;
let attrs = dict.into_iter().map(|(k, _v)| k).collect();
Ok(attrs)
}
}
impl Initializer for PyModule {
type Args = ModuleInitArgs;
@@ -136,8 +130,8 @@ impl Initializer for PyModule {
}
impl GetAttr for PyModule {
fn getattro(zelf: &Py<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
Self::getattr_inner(zelf, name, vm)
fn getattro(zelf: &Py<Self>, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
zelf.getattr_inner(name, vm)
}
}

View File

@@ -53,7 +53,8 @@ impl Initializer for PyNamespace {
return Err(vm.new_type_error("no positional arguments expected".to_owned()));
}
for (name, value) in args.kwargs.into_iter() {
zelf.as_object().set_attr(name, value, vm)?;
let name = vm.ctx.new_str(name);
zelf.as_object().set_attr(&name, value, vm)?;
}
Ok(())
}
@@ -82,7 +83,7 @@ impl Representable for PyNamespace {
let name = if o.class().is(vm.ctx.types.namespace_type) {
"namespace".to_owned()
} else {
o.class().slot_name()
o.class().slot_name().to_owned()
};
let repr = if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) {

View File

@@ -161,19 +161,19 @@ impl PyBaseObject {
value: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
obj.generic_setattr(name, PySetterValue::Assign(value), vm)
obj.generic_setattr(&name, PySetterValue::Assign(value), vm)
}
/// Implement delattr(self, name).
#[pymethod]
fn __delattr__(obj: PyObjectRef, name: PyStrRef, vm: &VirtualMachine) -> PyResult<()> {
obj.generic_setattr(name, PySetterValue::Delete, vm)
obj.generic_setattr(&name, PySetterValue::Delete, vm)
}
#[pyslot]
fn slot_setattro(
obj: &PyObject,
attr_name: PyStrRef,
attr_name: &Py<PyStr>,
value: PySetterValue,
vm: &VirtualMachine,
) -> PyResult<()> {
@@ -296,14 +296,14 @@ impl PyBaseObject {
/// Return getattr(self, name).
#[pyslot]
pub(crate) fn getattro(obj: &PyObject, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
pub(crate) fn getattro(obj: &PyObject, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
vm_trace!("object.__getattribute__({:?}, {:?})", obj, name);
obj.as_object().generic_getattr(name, vm)
}
#[pymethod(magic)]
fn getattribute(obj: PyObjectRef, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
Self::getattro(&obj, name, vm)
Self::getattro(&obj, &name, vm)
}
#[pymethod(magic)]

View File

@@ -143,49 +143,39 @@ impl fmt::Display for PyStr {
}
}
pub trait IntoPyStrRef {
fn into_pystr_ref(self, vm: &VirtualMachine) -> PyStrRef;
pub trait AsPyStr<'a>
where
Self: 'a,
{
#[allow(clippy::wrong_self_convention)] // to implement on refs
fn as_pystr(self, ctx: &Context) -> &'a Py<PyStr>;
}
impl IntoPyStrRef for PyStrRef {
impl<'a> AsPyStr<'a> for &'a Py<PyStr> {
#[inline]
fn into_pystr_ref(self, _vm: &VirtualMachine) -> PyRef<PyStr> {
fn as_pystr(self, _ctx: &Context) -> &'a Py<PyStr> {
self
}
}
impl IntoPyStrRef for PyStr {
impl<'a> AsPyStr<'a> for &'a PyStrRef {
#[inline]
fn into_pystr_ref(self, vm: &VirtualMachine) -> PyRef<PyStr> {
self.into_ref(vm)
fn as_pystr(self, _ctx: &Context) -> &'a Py<PyStr> {
self
}
}
impl IntoPyStrRef for AsciiString {
impl AsPyStr<'static> for &'static str {
#[inline]
fn into_pystr_ref(self, vm: &VirtualMachine) -> PyRef<PyStr> {
PyStr::from(self).into_ref(vm)
fn as_pystr(self, ctx: &Context) -> &'static Py<PyStr> {
ctx.intern_str(self)
}
}
impl IntoPyStrRef for String {
impl<'a> AsPyStr<'a> for &'a PyStrInterned {
#[inline]
fn into_pystr_ref(self, vm: &VirtualMachine) -> PyRef<PyStr> {
PyStr::from(self).into_ref(vm)
}
}
impl IntoPyStrRef for &str {
#[inline]
fn into_pystr_ref(self, vm: &VirtualMachine) -> PyRef<PyStr> {
PyStr::from(self).into_ref(vm)
}
}
impl IntoPyStrRef for &'static PyStrInterned {
#[inline]
fn into_pystr_ref(self, _vm: &VirtualMachine) -> PyRef<PyStr> {
self.to_owned()
fn as_pystr(self, _ctx: &Context) -> &'a Py<PyStr> {
self
}
}
@@ -619,7 +609,7 @@ impl PyStr {
if s == stripped {
zelf
} else {
stripped.into_pystr_ref(vm)
vm.ctx.new_str(stripped)
}
}
@@ -638,7 +628,7 @@ impl PyStr {
if s == stripped {
zelf
} else {
stripped.into_pystr_ref(vm)
vm.ctx.new_str(stripped)
}
}
@@ -949,7 +939,7 @@ impl PyStr {
}
Err(iter) => zelf.as_str().py_join(iter)?,
};
Ok(joined.into_pystr_ref(vm))
Ok(vm.ctx.new_str(joined))
}
// FIXME: two traversals of str is expensive

View File

@@ -3,7 +3,7 @@
See also [CPython source code.](https://github.com/python/cpython/blob/50b48572d9a90c5bb36e2bef6179548ea927a35a/Objects/typeobject.c#L7663)
*/
use super::{PyStrRef, PyType, PyTypeRef};
use super::{PyStr, PyType, PyTypeRef};
use crate::{
class::PyClassImpl,
function::{IntoFuncArgs, OptionalArg},
@@ -126,7 +126,7 @@ impl PySuper {
}
impl GetAttr for PySuper {
fn getattro(zelf: &Py<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
fn getattro(zelf: &Py<Self>, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
let skip = |zelf: &Py<Self>, name| zelf.as_object().generic_getattr(name, vm);
let (obj, start_type): (PyObjectRef, PyTypeRef) = match zelf.obj.clone() {
Some(o) => o,
@@ -139,7 +139,7 @@ impl GetAttr for PySuper {
return skip(zelf, name);
}
if let Some(name) = vm.ctx.interned_str(&*name) {
if let Some(name) = vm.ctx.interned_str(name) {
// skip the classes in start_type.mro up to and including zelf.typ
let mro: Vec<_> = start_type
.iter_mro()

View File

@@ -22,7 +22,8 @@ use crate::{
identifier,
protocol::{PyIterReturn, PyMappingMethods, PyNumberMethods, PySequenceMethods},
types::{AsNumber, Callable, GetAttr, PyTypeFlags, PyTypeSlots, Representable, SetAttr},
AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
VirtualMachine,
};
use indexmap::{map::Entry, IndexMap};
use itertools::Itertools;
@@ -39,8 +40,8 @@ pub struct PyType {
pub heaptype_ext: Option<Pin<Box<HeapTypeExt>>>,
}
#[derive(Default)]
pub struct HeapTypeExt {
pub name: PyRwLock<PyStrRef>,
pub slots: Option<PyTupleTyped<PyStrRef>>,
pub number_methods: PyNumberMethods,
pub sequence_methods: PySequenceMethods,
@@ -119,12 +120,12 @@ impl PyPayload for PyType {
}
impl PyType {
pub fn new_simple_ref(
pub fn new_simple_heap(
name: &str,
base: &PyTypeRef,
ctx: &Context,
) -> Result<PyRef<Self>, String> {
Self::new_ref(
Self::new_heap(
name,
vec![base.clone()],
Default::default(),
@@ -133,7 +134,7 @@ impl PyType {
ctx,
)
}
pub fn new_ref(
pub fn new_heap(
name: &str,
bases: Vec<PyRef<Self>>,
attrs: PyAttributes,
@@ -141,21 +142,24 @@ impl PyType {
metaclass: PyRef<Self>,
ctx: &Context,
) -> Result<PyRef<Self>, String> {
Self::new_verbose_ref(
name,
bases[0].clone(),
bases,
attrs,
slots,
HeapTypeExt::default(),
metaclass,
ctx,
)
// TODO: ensure clean slot name
// assert_eq!(slots.name.borrow(), "");
let name = ctx.new_str(name);
let heaptype_ext = HeapTypeExt {
name: PyRwLock::new(name),
slots: None,
number_methods: PyNumberMethods::default(),
sequence_methods: PySequenceMethods::default(),
mapping_methods: PyMappingMethods::default(),
};
let base = bases[0].clone();
Self::new_heap_inner(base, bases, attrs, slots, heaptype_ext, metaclass, ctx)
}
#[allow(clippy::too_many_arguments)]
fn new_verbose_ref(
name: &str,
fn new_heap_inner(
base: PyRef<Self>,
bases: Vec<PyRef<Self>>,
attrs: PyAttributes,
@@ -182,8 +186,6 @@ impl PyType {
slots.flags |= PyTypeFlags::HAS_DICT
}
*slots.name.get_mut() = Some(String::from(name));
let new_type = PyRef::new_ref(
PyType {
base: Some(base),
@@ -213,8 +215,7 @@ impl PyType {
Ok(new_type)
}
pub fn new_bare_ref(
name: &str,
pub fn new_static(
base: PyRef<Self>,
attrs: PyAttributes,
mut slots: PyTypeSlots,
@@ -224,8 +225,6 @@ impl PyType {
slots.flags |= PyTypeFlags::HAS_DICT
}
*slots.name.get_mut() = Some(String::from(name));
let bases = vec![base.clone()];
let mro = base.iter_mro().map(|x| x.to_owned()).collect();
@@ -280,10 +279,6 @@ impl PyType {
}
}
pub fn slot_name(&self) -> String {
self.slots.name.read().as_ref().unwrap().to_string()
}
pub fn iter_mro(&self) -> impl Iterator<Item = &PyType> + DoubleEndedIterator {
std::iter::once(self).chain(self.mro.iter().map(|cls| -> &PyType { cls }))
}
@@ -369,16 +364,30 @@ impl PyType {
call_slot_new(zelf, subtype, args, vm)
}
fn name_inner<'a, R: 'a>(
&'a self,
static_f: impl FnOnce(&'static str) -> R,
heap_f: impl FnOnce(&'a HeapTypeExt) -> R,
) -> R {
if !self.slots.flags.has_feature(PyTypeFlags::HEAPTYPE) {
static_f(self.slots.name)
} else {
heap_f(self.heaptype_ext.as_ref().unwrap())
}
}
pub fn slot_name(&self) -> BorrowedValue<str> {
self.name_inner(
|name| name.into(),
|ext| PyRwLockReadGuard::map(ext.name.read(), |name| name.as_str()).into(),
)
}
pub fn name(&self) -> BorrowedValue<str> {
PyRwLockReadGuard::map(self.slots.name.read(), |slot_name| {
let name = slot_name.as_ref().unwrap();
if self.slots.flags.has_feature(PyTypeFlags::HEAPTYPE) {
name.as_str()
} else {
name.rsplit('.').next().unwrap()
}
})
.into()
self.name_inner(
|name| name.rsplit_once('.').map_or(name, |(_, name)| name).into(),
|ext| PyRwLockReadGuard::map(ext.name.read(), |name| name.as_str()).into(),
)
}
}
@@ -425,8 +434,21 @@ impl PyType {
}
#[pygetset]
fn __name__(&self) -> String {
self.name().to_string()
pub fn __name__(&self, vm: &VirtualMachine) -> PyStrRef {
self.name_inner(
|name| {
vm.ctx
.interned_str(name.rsplit_once('.').map_or(name, |(_, name)| name))
.unwrap_or_else(|| {
panic!(
"static type name must be already interned but {} is not",
self.slot_name()
)
})
.to_owned()
},
|ext| ext.name.read().clone(),
)
}
#[pygetset(magic)]
@@ -608,7 +630,7 @@ impl PyType {
let (name, bases, dict, kwargs): (PyStrRef, PyTupleRef, PyDictRef, KwArgs) =
args.clone().bind(vm)?;
if name.as_str().contains(char::from(0)) {
if name.as_str().as_bytes().contains(&0) {
return Err(vm.new_value_error("type name must not contain null characters".to_owned()));
}
@@ -733,17 +755,24 @@ 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 heaptype_ext = HeapTypeExt {
slots: heaptype_slots.to_owned(),
..HeapTypeExt::default()
};
let slots = PyTypeSlots {
member_count,
..PyTypeSlots::from_flags(flags)
let (slots, heaptype_ext) = unsafe {
// # Safety
// `slots.name` live long enough because `heaptype_ext` is alive.
let slots = PyTypeSlots {
member_count,
..PyTypeSlots::new(&*(name.as_str() as *const _), flags)
};
let heaptype_ext = HeapTypeExt {
name: PyRwLock::new(name),
slots: heaptype_slots.to_owned(),
number_methods: PyNumberMethods::default(),
sequence_methods: PySequenceMethods::default(),
mapping_methods: PyMappingMethods::default(),
};
(slots, heaptype_ext)
};
let typ = Self::new_verbose_ref(
name.as_str(),
let typ = Self::new_heap_inner(
base,
bases,
attributes,
@@ -837,26 +866,38 @@ impl PyType {
))
}
#[pygetset(magic, setter)]
fn set_name(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
if !self.slots.flags.has_feature(PyTypeFlags::HEAPTYPE) {
fn check_set_special_type_attr(
&self,
_value: &PyObject,
name: &PyStrInterned,
vm: &VirtualMachine,
) -> PyResult<()> {
if self.slots.flags.has_feature(PyTypeFlags::IMMUTABLETYPE) {
return Err(vm.new_type_error(format!(
"cannot set '{}' attribute of immutable type '{}'",
"__name__",
self.name()
name,
self.slot_name()
)));
}
let name = value.downcast_ref::<PyStr>().ok_or_else(|| {
Ok(())
}
#[pygetset(magic, setter)]
fn set_name(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
self.check_set_special_type_attr(&value, identifier!(vm, __name__), vm)?;
let name = value.downcast::<PyStr>().map_err(|value| {
vm.new_type_error(format!(
"can only assign string to {}.__name__, not '{}'",
self.name(),
value.class().name()
self.slot_name(),
value.class().slot_name(),
))
})?;
if name.as_str().contains(char::from(0)) {
if name.as_str().as_bytes().contains(&0) {
return Err(vm.new_value_error("type name must not contain null characters".to_owned()));
}
*self.slots.name.write() = Some(name.as_str().to_string());
*self.heaptype_ext.as_ref().unwrap().name.write() = name;
Ok(())
}
@@ -932,7 +973,7 @@ pub(crate) fn get_text_signature_from_internal_doc<'a>(
}
impl GetAttr for PyType {
fn getattro(zelf: &Py<Self>, name_str: PyStrRef, vm: &VirtualMachine) -> PyResult {
fn getattro(zelf: &Py<Self>, name_str: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
#[cold]
fn attribute_error(
zelf: &Py<PyType>,
@@ -946,7 +987,7 @@ impl GetAttr for PyType {
))
}
let Some(name) = vm.ctx.interned_str(&*name_str) else {
let Some(name) = vm.ctx.interned_str(name_str) else {
return Err(attribute_error(zelf, name_str.as_str(), vm));
};
vm_trace!("type.__getattribute__({:?}, {:?})", zelf, name);
@@ -989,7 +1030,7 @@ impl GetAttr for PyType {
impl SetAttr for PyType {
fn setattro(
zelf: &Py<Self>,
attr_name: PyStrRef,
attr_name: &Py<PyStr>,
value: PySetterValue,
vm: &VirtualMachine,
) -> PyResult<()> {
@@ -1302,7 +1343,7 @@ mod tests {
let object = context.types.object_type.to_owned();
let type_type = context.types.type_type.to_owned();
let a = PyType::new_ref(
let a = PyType::new_heap(
"A",
vec![object.clone()],
PyAttributes::default(),
@@ -1311,7 +1352,7 @@ mod tests {
context,
)
.unwrap();
let b = PyType::new_ref(
let b = PyType::new_heap(
"B",
vec![object.clone()],
PyAttributes::default(),

View File

@@ -1,7 +1,7 @@
use super::{genericalias, type_};
use crate::{
atomic_func,
builtins::{PyFrozenSet, PyStr, PyStrRef, PyTuple, PyTupleRef, PyType},
builtins::{PyFrozenSet, PyStr, PyTuple, PyTupleRef, PyType},
class::PyClassImpl,
common::hash,
convert::{ToPyObject, ToPyResult},
@@ -139,19 +139,10 @@ pub fn is_unionable(obj: PyObjectRef, vm: &VirtualMachine) -> bool {
|| obj.class().is(vm.ctx.types.union_type)
}
fn is_typevar(obj: &PyObjectRef, vm: &VirtualMachine) -> bool {
let class = obj.class();
class.slot_name() == "TypeVar"
&& class
.get_attr(identifier!(vm, __module__))
.and_then(|o| o.downcast_ref::<PyStr>().map(|s| s.as_str() == "typing"))
.unwrap_or(false)
}
fn make_parameters(args: &PyTupleRef, vm: &VirtualMachine) -> PyTupleRef {
let mut parameters: Vec<PyObjectRef> = Vec::with_capacity(args.len());
for arg in args {
if is_typevar(arg, vm) {
if genericalias::is_typevar(arg, vm) {
if !parameters.iter().any(|param| param.is(arg)) {
parameters.push(arg.clone());
}
@@ -301,7 +292,7 @@ impl Hashable for PyUnion {
}
impl GetAttr for PyUnion {
fn getattro(zelf: &Py<Self>, attr: PyStrRef, vm: &VirtualMachine) -> PyResult {
fn getattro(zelf: &Py<Self>, attr: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
for &exc in CLS_ATTRS {
if *exc == attr.to_string() {
return zelf.as_object().generic_getattr(attr, vm);

View File

@@ -1,6 +1,6 @@
use once_cell::sync::Lazy;
use super::{PyStrRef, PyType, PyTypeRef, PyWeak};
use super::{PyStr, PyStrRef, PyType, PyTypeRef, PyWeak};
use crate::{
atomic_func,
class::PyClassImpl,
@@ -132,7 +132,7 @@ fn new_reference_error(vm: &VirtualMachine) -> PyRef<super::PyBaseException> {
impl GetAttr for PyWeakProxy {
// TODO: callbacks
fn getattro(zelf: &Py<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
fn getattro(zelf: &Py<Self>, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
let obj = zelf.try_upgrade(vm)?;
obj.get_attr(name, vm)
}
@@ -141,7 +141,7 @@ impl GetAttr for PyWeakProxy {
impl SetAttr for PyWeakProxy {
fn setattro(
zelf: &Py<Self>,
attr_name: PyStrRef,
attr_name: &Py<PyStr>,
value: PySetterValue,
vm: &VirtualMachine,
) -> PyResult<()> {

View File

@@ -7,7 +7,7 @@ use crate::{
types::{hash_not_implemented, PyTypeFlags, PyTypeSlots},
vm::Context,
};
use rustpython_common::{lock::PyRwLock, static_cell};
use rustpython_common::static_cell;
pub trait StaticType {
// Ideally, saving PyType is better than PyTypeRef
@@ -29,22 +29,21 @@ pub trait StaticType {
.unwrap_or_else(|_| panic!("double initialization from init_manually"));
cell.get().unwrap()
}
fn init_bare_type() -> &'static Py<PyType>
fn init_builtin_type() -> &'static Py<PyType>
where
Self: PyClassImpl,
{
let typ = Self::create_bare_type();
let typ = Self::create_static_type();
let cell = Self::static_cell();
cell.set(typ)
.unwrap_or_else(|_| panic!("double initialization of {}", Self::NAME));
cell.get().unwrap()
}
fn create_bare_type() -> PyTypeRef
fn create_static_type() -> PyTypeRef
where
Self: PyClassImpl,
{
PyType::new_bare_ref(
Self::NAME,
PyType::new_static(
Self::static_baseclass().to_owned(),
Default::default(),
Self::make_slots(),
@@ -73,6 +72,9 @@ pub trait PyClassImpl: PyClassDef {
{
assert!(class.slots.flags.is_created_with_flags());
}
let _ = ctx.intern_str(Self::NAME); // intern type name
if Self::TP_FLAGS.has_feature(PyTypeFlags::HAS_DICT) {
let __dict__ = identifier!(ctx, __dict__);
class.set_attr(
@@ -113,7 +115,7 @@ pub trait PyClassImpl: PyClassDef {
Self: StaticType,
{
(*Self::static_cell().get_or_init(|| {
let typ = Self::create_bare_type();
let typ = Self::create_static_type();
Self::extend_class(ctx, unsafe {
// typ will be saved in static_cell
let r: &Py<PyType> = &typ;
@@ -129,7 +131,7 @@ pub trait PyClassImpl: PyClassDef {
fn make_slots() -> PyTypeSlots {
let mut slots = PyTypeSlots {
flags: Self::TP_FLAGS,
name: PyRwLock::new(Some(Self::TP_NAME.to_owned())),
name: Self::TP_NAME,
basicsize: Self::BASICSIZE,
doc: Self::DOC,
..Default::default()

View File

@@ -414,7 +414,6 @@ macro_rules! extend_exception {
};
}
#[pyclass(with(Constructor, Initializer), flags(BASETYPE, HAS_DICT))]
impl PyBaseException {
pub(crate) fn new(args: Vec<PyObjectRef>, vm: &VirtualMachine) -> PyBaseException {
PyBaseException {
@@ -429,7 +428,10 @@ impl PyBaseException {
pub fn get_arg(&self, idx: usize) -> Option<PyObjectRef> {
self.args.read().get(idx).cloned()
}
}
#[pyclass(with(Constructor, Initializer), flags(BASETYPE, HAS_DICT))]
impl PyBaseException {
#[pygetset]
pub fn args(&self) -> PyTupleRef {
self.args.read().clone()
@@ -540,92 +542,92 @@ impl ExceptionZoo {
pub(crate) fn init() -> Self {
use self::types::*;
let base_exception_type = PyBaseException::init_bare_type();
let base_exception_type = PyBaseException::init_builtin_type();
// Sorted By Hierarchy then alphabetized.
let base_exception_group = PyBaseExceptionGroup::init_bare_type();
let system_exit = PySystemExit::init_bare_type();
let keyboard_interrupt = PyKeyboardInterrupt::init_bare_type();
let generator_exit = PyGeneratorExit::init_bare_type();
let base_exception_group = PyBaseExceptionGroup::init_builtin_type();
let system_exit = PySystemExit::init_builtin_type();
let keyboard_interrupt = PyKeyboardInterrupt::init_builtin_type();
let generator_exit = PyGeneratorExit::init_builtin_type();
let exception_type = PyException::init_bare_type();
let stop_iteration = PyStopIteration::init_bare_type();
let stop_async_iteration = PyStopAsyncIteration::init_bare_type();
let arithmetic_error = PyArithmeticError::init_bare_type();
let floating_point_error = PyFloatingPointError::init_bare_type();
let overflow_error = PyOverflowError::init_bare_type();
let zero_division_error = PyZeroDivisionError::init_bare_type();
let exception_type = PyException::init_builtin_type();
let stop_iteration = PyStopIteration::init_builtin_type();
let stop_async_iteration = PyStopAsyncIteration::init_builtin_type();
let arithmetic_error = PyArithmeticError::init_builtin_type();
let floating_point_error = PyFloatingPointError::init_builtin_type();
let overflow_error = PyOverflowError::init_builtin_type();
let zero_division_error = PyZeroDivisionError::init_builtin_type();
let assertion_error = PyAssertionError::init_bare_type();
let attribute_error = PyAttributeError::init_bare_type();
let buffer_error = PyBufferError::init_bare_type();
let eof_error = PyEOFError::init_bare_type();
let assertion_error = PyAssertionError::init_builtin_type();
let attribute_error = PyAttributeError::init_builtin_type();
let buffer_error = PyBufferError::init_builtin_type();
let eof_error = PyEOFError::init_builtin_type();
let import_error = PyImportError::init_bare_type();
let module_not_found_error = PyModuleNotFoundError::init_bare_type();
let import_error = PyImportError::init_builtin_type();
let module_not_found_error = PyModuleNotFoundError::init_builtin_type();
let lookup_error = PyLookupError::init_bare_type();
let index_error = PyIndexError::init_bare_type();
let key_error = PyKeyError::init_bare_type();
let lookup_error = PyLookupError::init_builtin_type();
let index_error = PyIndexError::init_builtin_type();
let key_error = PyKeyError::init_builtin_type();
let memory_error = PyMemoryError::init_bare_type();
let memory_error = PyMemoryError::init_builtin_type();
let name_error = PyNameError::init_bare_type();
let unbound_local_error = PyUnboundLocalError::init_bare_type();
let name_error = PyNameError::init_builtin_type();
let unbound_local_error = PyUnboundLocalError::init_builtin_type();
// os errors
let os_error = PyOSError::init_bare_type();
let blocking_io_error = PyBlockingIOError::init_bare_type();
let child_process_error = PyChildProcessError::init_bare_type();
let os_error = PyOSError::init_builtin_type();
let blocking_io_error = PyBlockingIOError::init_builtin_type();
let child_process_error = PyChildProcessError::init_builtin_type();
let connection_error = PyConnectionError::init_bare_type();
let broken_pipe_error = PyBrokenPipeError::init_bare_type();
let connection_aborted_error = PyConnectionAbortedError::init_bare_type();
let connection_refused_error = PyConnectionRefusedError::init_bare_type();
let connection_reset_error = PyConnectionResetError::init_bare_type();
let connection_error = PyConnectionError::init_builtin_type();
let broken_pipe_error = PyBrokenPipeError::init_builtin_type();
let connection_aborted_error = PyConnectionAbortedError::init_builtin_type();
let connection_refused_error = PyConnectionRefusedError::init_builtin_type();
let connection_reset_error = PyConnectionResetError::init_builtin_type();
let file_exists_error = PyFileExistsError::init_bare_type();
let file_not_found_error = PyFileNotFoundError::init_bare_type();
let interrupted_error = PyInterruptedError::init_bare_type();
let is_a_directory_error = PyIsADirectoryError::init_bare_type();
let not_a_directory_error = PyNotADirectoryError::init_bare_type();
let permission_error = PyPermissionError::init_bare_type();
let process_lookup_error = PyProcessLookupError::init_bare_type();
let timeout_error = PyTimeoutError::init_bare_type();
let file_exists_error = PyFileExistsError::init_builtin_type();
let file_not_found_error = PyFileNotFoundError::init_builtin_type();
let interrupted_error = PyInterruptedError::init_builtin_type();
let is_a_directory_error = PyIsADirectoryError::init_builtin_type();
let not_a_directory_error = PyNotADirectoryError::init_builtin_type();
let permission_error = PyPermissionError::init_builtin_type();
let process_lookup_error = PyProcessLookupError::init_builtin_type();
let timeout_error = PyTimeoutError::init_builtin_type();
let reference_error = PyReferenceError::init_bare_type();
let reference_error = PyReferenceError::init_builtin_type();
let runtime_error = PyRuntimeError::init_bare_type();
let not_implemented_error = PyNotImplementedError::init_bare_type();
let recursion_error = PyRecursionError::init_bare_type();
let runtime_error = PyRuntimeError::init_builtin_type();
let not_implemented_error = PyNotImplementedError::init_builtin_type();
let recursion_error = PyRecursionError::init_builtin_type();
let syntax_error = PySyntaxError::init_bare_type();
let indentation_error = PyIndentationError::init_bare_type();
let tab_error = PyTabError::init_bare_type();
let syntax_error = PySyntaxError::init_builtin_type();
let indentation_error = PyIndentationError::init_builtin_type();
let tab_error = PyTabError::init_builtin_type();
let system_error = PySystemError::init_bare_type();
let type_error = PyTypeError::init_bare_type();
let value_error = PyValueError::init_bare_type();
let unicode_error = PyUnicodeError::init_bare_type();
let unicode_decode_error = PyUnicodeDecodeError::init_bare_type();
let unicode_encode_error = PyUnicodeEncodeError::init_bare_type();
let unicode_translate_error = PyUnicodeTranslateError::init_bare_type();
let system_error = PySystemError::init_builtin_type();
let type_error = PyTypeError::init_builtin_type();
let value_error = PyValueError::init_builtin_type();
let unicode_error = PyUnicodeError::init_builtin_type();
let unicode_decode_error = PyUnicodeDecodeError::init_builtin_type();
let unicode_encode_error = PyUnicodeEncodeError::init_builtin_type();
let unicode_translate_error = PyUnicodeTranslateError::init_builtin_type();
#[cfg(feature = "jit")]
let jit_error = PyJitError::init_bare_type();
let jit_error = PyJitError::init_builtin_type();
let warning = PyWarning::init_bare_type();
let deprecation_warning = PyDeprecationWarning::init_bare_type();
let pending_deprecation_warning = PyPendingDeprecationWarning::init_bare_type();
let runtime_warning = PyRuntimeWarning::init_bare_type();
let syntax_warning = PySyntaxWarning::init_bare_type();
let user_warning = PyUserWarning::init_bare_type();
let future_warning = PyFutureWarning::init_bare_type();
let import_warning = PyImportWarning::init_bare_type();
let unicode_warning = PyUnicodeWarning::init_bare_type();
let bytes_warning = PyBytesWarning::init_bare_type();
let resource_warning = PyResourceWarning::init_bare_type();
let encoding_warning = PyEncodingWarning::init_bare_type();
let warning = PyWarning::init_builtin_type();
let deprecation_warning = PyDeprecationWarning::init_builtin_type();
let pending_deprecation_warning = PyPendingDeprecationWarning::init_builtin_type();
let runtime_warning = PyRuntimeWarning::init_builtin_type();
let syntax_warning = PySyntaxWarning::init_builtin_type();
let user_warning = PyUserWarning::init_builtin_type();
let future_warning = PyFutureWarning::init_builtin_type();
let import_warning = PyImportWarning::init_builtin_type();
let unicode_warning = PyUnicodeWarning::init_builtin_type();
let bytes_warning = PyBytesWarning::init_builtin_type();
let resource_warning = PyResourceWarning::init_builtin_type();
let encoding_warning = PyEncodingWarning::init_builtin_type();
Self {
base_exception_type,

View File

@@ -79,7 +79,7 @@ fn format_internal(
for name_part in parts {
match name_part {
FieldNamePart::Attribute(attribute) => {
argument = argument.get_attr(attribute.as_str(), vm)?;
argument = argument.get_attr(&vm.ctx.new_str(attribute), vm)?;
}
FieldNamePart::Index(index) => {
argument = argument.get_item(&index, vm)?;

View File

@@ -516,7 +516,7 @@ impl ExecutingFrame<'_> {
Ok(None)
}
bytecode::Instruction::ImportName { idx } => {
self.import(vm, Some(self.code.names[idx.get(arg) as usize].to_owned()))?;
self.import(vm, Some(self.code.names[idx.get(arg) as usize]))?;
Ok(None)
}
bytecode::Instruction::ImportNameless => {
@@ -1020,7 +1020,7 @@ impl ExecutingFrame<'_> {
bytecode::Instruction::LoadMethod { idx } => {
let obj = self.pop_value();
let method_name = self.code.names[idx.get(arg) as usize];
let method = PyMethod::get(obj, method_name.to_owned(), vm)?;
let method = PyMethod::get(obj, method_name, vm)?;
let (target, is_method, func) = match method {
PyMethod::Function { target, func } => (target, true, func),
PyMethod::Attribute(val) => (vm.ctx.none(), false, val),
@@ -1129,8 +1129,8 @@ impl ExecutingFrame<'_> {
}
#[cfg_attr(feature = "flame-it", flame("Frame"))]
fn import(&mut self, vm: &VirtualMachine, module: Option<PyStrRef>) -> PyResult<()> {
let module = module.unwrap_or_else(|| vm.ctx.empty_str.clone());
fn import(&mut self, vm: &VirtualMachine, module: Option<&Py<PyStr>>) -> PyResult<()> {
let module = module.unwrap_or(&vm.ctx.empty_str);
let from_list = <Option<PyTupleTyped<PyStrRef>>>::try_from_object(vm, self.pop_value())?;
let level = usize::try_from_object(vm, self.pop_value())?;
@@ -1144,7 +1144,7 @@ impl ExecutingFrame<'_> {
fn import_from(&mut self, vm: &VirtualMachine, idx: bytecode::NameIdx) -> PyResult {
let module = self.last_value();
let name = self.code.names[idx as usize];
let err = || vm.new_import_error(format!("cannot import name '{name}'"), name);
let err = || vm.new_import_error(format!("cannot import name '{name}'"), name.to_owned());
// Load attribute, and transform any error into import error.
if let Some(obj) = vm.get_attribute_opt(module.clone(), name)? {
return Ok(obj);

View File

@@ -27,7 +27,7 @@ pub(crate) fn init_importlib_base(vm: &mut VirtualMachine) -> PyResult<PyObjectR
install.call((vm.sys_module.clone(), imp), vm)?;
Ok(bootstrap)
})?;
vm.import_func = importlib.get_attr(identifier!(vm, __import__).to_owned(), vm)?;
vm.import_func = importlib.get_attr(identifier!(vm, __import__), vm)?;
Ok(importlib)
}
@@ -73,10 +73,12 @@ pub(crate) fn init_importlib_package(
}
pub fn make_frozen(vm: &VirtualMachine, name: &str) -> PyResult<PyRef<PyCode>> {
let frozen =
vm.state.frozen.get(name).ok_or_else(|| {
vm.new_import_error(format!("No such frozen object named {name}"), name)
})?;
let frozen = vm.state.frozen.get(name).ok_or_else(|| {
vm.new_import_error(
format!("No such frozen object named {name}"),
vm.ctx.new_str(name),
)
})?;
Ok(vm.ctx.new_code(frozen.code))
}
@@ -92,7 +94,7 @@ pub fn import_builtin(vm: &VirtualMachine, module_name: &str) -> PyResult {
let make_module_func = vm.state.module_inits.get(module_name).ok_or_else(|| {
vm.new_import_error(
format!("Cannot import builtin module {module_name}"),
module_name,
vm.ctx.new_str(module_name),
)
})?;
let module = make_module_func(vm);

View File

@@ -32,7 +32,11 @@ impl Clone for StringPool {
impl StringPool {
#[inline]
pub unsafe fn intern<S: Internable>(&self, s: S, typ: PyTypeRef) -> &'static PyStrInterned {
pub unsafe fn intern<S: InternableString>(
&self,
s: S,
typ: PyTypeRef,
) -> &'static PyStrInterned {
if let Some(found) = self.interned(s.as_ref()) {
return found;
}
@@ -60,7 +64,10 @@ impl StringPool {
}
#[inline]
pub fn interned<S: MaybeInterned + ?Sized>(&self, s: &S) -> Option<&'static PyStrInterned> {
pub fn interned<S: MaybeInternedString + ?Sized>(
&self,
s: &S,
) -> Option<&'static PyStrInterned> {
if let Some(interned) = s.as_interned() {
return Some(interned);
}
@@ -164,6 +171,13 @@ impl<T: PyPayload> std::hash::Hash for PyInterned<T> {
}
}
impl<T: PyPayload> AsRef<Py<T>> for PyInterned<T> {
#[inline(always)]
fn as_ref(&self) -> &Py<T> {
&self.inner
}
}
impl<T: PyPayload> Deref for PyInterned<T> {
type Target = Py<T>;
#[inline(always)]
@@ -214,16 +228,16 @@ mod sealed {
}
/// A sealed marker trait for `DictKey` types that always become an exact instance of `str`
pub trait Internable
pub trait InternableString
where
Self: sealed::SealedInternable + ToPyObject + AsRef<Self::Interned>,
Self::Interned: MaybeInterned,
Self::Interned: MaybeInternedString,
{
type Interned: ?Sized;
fn into_pyref_exact(self, str_type: PyTypeRef) -> PyRefExact<PyStr>;
}
impl Internable for String {
impl InternableString for String {
type Interned = str;
#[inline]
fn into_pyref_exact(self, str_type: PyTypeRef) -> PyRefExact<PyStr> {
@@ -232,7 +246,7 @@ impl Internable for String {
}
}
impl Internable for &str {
impl InternableString for &str {
type Interned = str;
#[inline]
fn into_pyref_exact(self, str_type: PyTypeRef) -> PyRefExact<PyStr> {
@@ -240,7 +254,7 @@ impl Internable for &str {
}
}
impl Internable for PyRefExact<PyStr> {
impl InternableString for PyRefExact<PyStr> {
type Interned = Py<PyStr>;
#[inline]
fn into_pyref_exact(self, _str_type: PyTypeRef) -> PyRefExact<PyStr> {
@@ -248,27 +262,27 @@ impl Internable for PyRefExact<PyStr> {
}
}
pub trait MaybeInterned:
pub trait MaybeInternedString:
AsRef<str> + crate::dictdatatype::DictKey + sealed::SealedMaybeInterned
{
fn as_interned(&self) -> Option<&'static PyStrInterned>;
}
impl MaybeInterned for str {
impl MaybeInternedString for str {
#[inline(always)]
fn as_interned(&self) -> Option<&'static PyStrInterned> {
None
}
}
impl MaybeInterned for PyExact<PyStr> {
impl MaybeInternedString for PyExact<PyStr> {
#[inline(always)]
fn as_interned(&self) -> Option<&'static PyStrInterned> {
None
}
}
impl MaybeInterned for Py<PyStr> {
impl MaybeInternedString for Py<PyStr> {
#[inline(always)]
fn as_interned(&self) -> Option<&'static PyStrInterned> {
if self.as_object().is_interned() {

View File

@@ -17,7 +17,7 @@ macro_rules! py_class {
( $ctx:expr, $class_name:expr, $class_base:expr, $flags:expr, { $($name:tt => $value:expr),* $(,)* }) => {
{
#[allow(unused_mut)]
let mut slots = $crate::types::PyTypeSlots::from_flags($crate::types::PyTypeFlags::DEFAULT | $flags);
let mut slots = $crate::types::PyTypeSlots::new($class_name, $crate::types::PyTypeFlags::DEFAULT | $flags);
$($crate::py_class!(@extract_slots($ctx, &mut slots, $name, $value));)*
let py_class = $ctx.new_class(None, $class_name, $class_base, slots);
$($crate::py_class!(@extract_attrs($ctx, &py_class, $name, $value));)*

View File

@@ -3,7 +3,7 @@
use crate::{
builtins::{
pystr::IntoPyStrRef, PyBytes, PyDict, PyDictRef, PyGenericAlias, PyInt, PyStr, PyStrRef,
pystr::AsPyStr, PyBytes, PyDict, PyDictRef, PyGenericAlias, PyInt, PyStr, PyStrRef,
PyTupleRef, PyTypeRef,
},
bytesinner::ByteInnerNewOptions,
@@ -13,7 +13,7 @@ use crate::{
function::{Either, OptionalArg, PyArithmeticValue, PySetterValue},
protocol::{PyIter, PyMapping, PySequence},
types::{Constructor, PyComparisonOp},
AsObject, PyObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine,
AsObject, Py, PyObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine,
};
// RustPython doesn't need these items
@@ -75,26 +75,26 @@ impl PyObjectRef {
}
impl PyObject {
pub fn has_attr(&self, attr_name: impl IntoPyStrRef, vm: &VirtualMachine) -> PyResult<bool> {
self.get_attr(attr_name, vm).map(|o| vm.is_none(&o))
pub fn has_attr<'a>(&self, attr_name: impl AsPyStr<'a>, vm: &VirtualMachine) -> PyResult<bool> {
self.get_attr(attr_name, vm).map(|o| !vm.is_none(&o))
}
pub fn get_attr(&self, attr_name: impl IntoPyStrRef, vm: &VirtualMachine) -> PyResult {
let attr_name = attr_name.into_pystr_ref(vm);
self._get_attr(attr_name, vm)
pub fn get_attr<'a>(&self, attr_name: impl AsPyStr<'a>, vm: &VirtualMachine) -> PyResult {
let attr_name = attr_name.as_pystr(&vm.ctx);
self.get_attr_inner(attr_name, vm)
}
// get_attribute should be used for full attribute access (usually from user code).
#[cfg_attr(feature = "flame-it", flame("PyObjectRef"))]
#[inline]
fn _get_attr(&self, attr_name: PyStrRef, vm: &VirtualMachine) -> PyResult {
pub(crate) fn get_attr_inner(&self, attr_name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
vm_trace!("object.__getattribute__: {:?} {:?}", self, attr_name);
let getattro = self
.class()
.mro_find_map(|cls| cls.slots.getattro.load())
.unwrap();
getattro(self, attr_name.clone(), vm).map_err(|exc| {
vm.set_attribute_error_context(&exc, self.to_owned(), attr_name);
getattro(self, attr_name, vm).map_err(|exc| {
vm.set_attribute_error_context(&exc, self.to_owned(), attr_name.to_owned());
exc
})
}
@@ -102,7 +102,7 @@ impl PyObject {
pub fn call_set_attr(
&self,
vm: &VirtualMachine,
attr_name: PyStrRef,
attr_name: &Py<PyStr>,
attr_value: PySetterValue,
) -> PyResult<()> {
let setattro = {
@@ -126,13 +126,13 @@ impl PyObject {
setattro(self, attr_name, attr_value, vm)
}
pub fn set_attr(
pub fn set_attr<'a>(
&self,
attr_name: impl IntoPyStrRef,
attr_name: impl AsPyStr<'a>,
attr_value: impl Into<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<()> {
let attr_name = attr_name.into_pystr_ref(vm);
let attr_name = attr_name.as_pystr(&vm.ctx);
self.call_set_attr(vm, attr_name, PySetterValue::Assign(attr_value.into()))
}
@@ -140,14 +140,14 @@ impl PyObject {
#[cfg_attr(feature = "flame-it", flame)]
pub fn generic_setattr(
&self,
attr_name: PyStrRef, // TODO: Py<PyStr>
attr_name: &Py<PyStr>,
value: PySetterValue,
vm: &VirtualMachine,
) -> PyResult<()> {
vm_trace!("object.__setattr__({:?}, {}, {:?})", self, attr_name, value);
if let Some(attr) = vm
.ctx
.interned_str(&*attr_name)
.interned_str(attr_name)
.and_then(|attr_name| self.get_class_attr(attr_name))
{
let descr_set = attr.class().mro_find_map(|cls| cls.slots.descr_set.load());
@@ -158,9 +158,9 @@ impl PyObject {
if let Some(dict) = self.dict() {
if let PySetterValue::Assign(value) = value {
dict.set_item(&*attr_name, value, vm)?;
dict.set_item(attr_name, value, vm)?;
} else {
dict.del_item(&*attr_name, vm).map_err(|e| {
dict.del_item(attr_name, vm).map_err(|e| {
if e.fast_isinstance(vm.ctx.exceptions.key_error) {
vm.new_attribute_error(format!(
"'{}' object has no attribute '{}'",
@@ -182,27 +182,26 @@ impl PyObject {
}
}
pub fn generic_getattr(&self, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
self.generic_getattr_opt(name.clone(), None, vm)?
.ok_or_else(|| {
vm.new_attribute_error(format!(
"'{}' object has no attribute '{}'",
self.class().name(),
name
))
})
pub fn generic_getattr(&self, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
self.generic_getattr_opt(name, None, vm)?.ok_or_else(|| {
vm.new_attribute_error(format!(
"'{}' object has no attribute '{}'",
self.class().name(),
name
))
})
}
/// CPython _PyObject_GenericGetAttrWithDict
pub fn generic_getattr_opt(
&self,
name_str: PyStrRef,
name_str: &Py<PyStr>,
dict: Option<PyDictRef>,
vm: &VirtualMachine,
) -> PyResult<Option<PyObjectRef>> {
let name = name_str.as_str();
let obj_cls = self.class();
let cls_attr_name = vm.ctx.interned_str(&*name_str);
let cls_attr_name = vm.ctx.interned_str(name_str);
let cls_attr = match cls_attr_name.and_then(|name| obj_cls.get_attr(name)) {
Some(descr) => {
let descr_cls = descr.class();
@@ -244,8 +243,8 @@ impl PyObject {
}
}
pub fn del_attr(&self, attr_name: impl IntoPyStrRef, vm: &VirtualMachine) -> PyResult<()> {
let attr_name = attr_name.into_pystr_ref(vm);
pub fn del_attr<'a>(&self, attr_name: impl AsPyStr<'a>, vm: &VirtualMachine) -> PyResult<()> {
let attr_name = attr_name.as_pystr(&vm.ctx);
self.call_set_attr(vm, attr_name, PySetterValue::Delete)
}

View File

@@ -141,7 +141,7 @@ impl Scope {
// impl Sealed for super::PyStrRef {}
// }
// pub trait PyName:
// sealed::Sealed + crate::dictdatatype::DictKey + Clone + ToPyObject + IntoPyStrRef
// sealed::Sealed + crate::dictdatatype::DictKey + Clone + ToPyObject
// {
// }
// impl PyName for str {}

View File

@@ -50,7 +50,7 @@ mod _ast {
)));
}
for (name, arg) in fields.iter().zip(args.args) {
zelf.set_attr(name.clone(), arg, vm)?;
zelf.set_attr(name, arg, vm)?;
}
for (key, value) in args.kwargs {
if let Some(pos) = fields.iter().position(|f| f.as_str() == key) {
@@ -62,7 +62,7 @@ mod _ast {
)));
}
}
zelf.set_attr(key, value, vm)?;
zelf.set_attr(vm.ctx.intern_str(key), value, vm)?;
}
Ok(())
}
@@ -77,7 +77,7 @@ mod _ast {
use super::PY_COMPILE_FLAG_AST_ONLY;
}
fn get_node_field(vm: &VirtualMachine, obj: &PyObject, field: &str, typ: &str) -> PyResult {
fn get_node_field(vm: &VirtualMachine, obj: &PyObject, field: &'static str, typ: &str) -> PyResult {
vm.get_attribute_opt(obj.to_owned(), field)?
.ok_or_else(|| vm.new_type_error(format!("required field \"{field}\" missing from {typ}")))
}
@@ -85,7 +85,7 @@ fn get_node_field(vm: &VirtualMachine, obj: &PyObject, field: &str, typ: &str) -
fn get_node_field_opt(
vm: &VirtualMachine,
obj: &PyObject,
field: &str,
field: &'static str,
) -> PyResult<Option<PyObjectRef>> {
Ok(vm
.get_attribute_opt(obj.to_owned(), field)?

View File

@@ -187,7 +187,7 @@ mod builtins {
#[pyfunction]
fn delattr(obj: PyObjectRef, attr: PyStrRef, vm: &VirtualMachine) -> PyResult<()> {
obj.del_attr(attr, vm)
obj.del_attr(&attr, vm)
}
#[pyfunction]
@@ -326,9 +326,9 @@ mod builtins {
vm: &VirtualMachine,
) -> PyResult {
if let OptionalArg::Present(default) = default {
Ok(vm.get_attribute_opt(obj, attr)?.unwrap_or(default))
Ok(vm.get_attribute_opt(obj, &attr)?.unwrap_or(default))
} else {
obj.get_attr(attr, vm)
obj.get_attr(&attr, vm)
}
}
@@ -339,7 +339,7 @@ mod builtins {
#[pyfunction]
fn hasattr(obj: PyObjectRef, attr: PyStrRef, vm: &VirtualMachine) -> PyResult<bool> {
Ok(vm.get_attribute_opt(obj, attr)?.is_some())
Ok(vm.get_attribute_opt(obj, &attr)?.is_some())
}
#[pyfunction]
@@ -744,7 +744,7 @@ mod builtins {
value: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
obj.set_attr(attr, value, vm)?;
obj.set_attr(&attr, value, vm)?;
Ok(())
}
@@ -803,10 +803,9 @@ mod builtins {
#[pyfunction]
fn vars(obj: OptionalArg, vm: &VirtualMachine) -> PyResult {
if let OptionalArg::Present(obj) = obj {
obj.get_attr(identifier!(vm, __dict__).to_owned(), vm)
.map_err(|_| {
vm.new_type_error("vars() argument must have __dict__ attribute".to_owned())
})
obj.get_attr(identifier!(vm, __dict__), vm).map_err(|_| {
vm.new_type_error("vars() argument must have __dict__ attribute".to_owned())
})
} else {
Ok(vm.current_locals()?.into())
}
@@ -882,7 +881,7 @@ mod builtins {
}
}
let meta_name = metaclass.slot_name();
(metaclass.into(), meta_name)
(metaclass.to_owned().into(), meta_name.to_owned())
}
Err(obj) => (obj, "<metaclass>".to_owned()),
};

View File

@@ -350,7 +350,7 @@ mod _codecs {
#[inline]
fn delegate_pycodecs(
cell: &'static StaticCell<PyObjectRef>,
name: &str,
name: &'static str,
args: FuncArgs,
vm: &VirtualMachine,
) -> PyResult {

View File

@@ -11,9 +11,11 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
"errorcode" => errorcode.clone(),
});
for (name, code) in ERROR_CODES {
let name = vm.ctx.new_str(*name);
let name = vm.ctx.intern_str(*name);
let code = vm.new_pyobj(*code);
errorcode.set_item(&*code, name.clone().into(), vm).unwrap();
errorcode
.set_item(&*code, name.to_owned().into(), vm)
.unwrap();
module.set_attr(name, code, vm).unwrap();
}
module

View File

@@ -69,7 +69,7 @@ impl FrozenError {
Excluded => format!("Excluded frozen object named {mod_name}"),
Invalid => format!("Frozen object named {mod_name} is invalid"),
};
vm.new_import_error(msg, mod_name)
vm.new_import_error(msg, vm.ctx.new_str(mod_name))
}
}

View File

@@ -3637,7 +3637,7 @@ mod _io {
}
pub(super) fn make_unsupportedop(ctx: &Context) -> PyTypeRef {
PyType::new_ref(
PyType::new_heap(
"UnsupportedOperation",
vec![
ctx.exceptions.os_error.to_owned(),

View File

@@ -4,7 +4,7 @@ pub(crate) use _operator::make_module;
mod _operator {
use crate::common::cmp;
use crate::{
builtins::{PyInt, PyIntRef, PyStrRef, PyTupleRef, PyTypeRef},
builtins::{PyInt, PyIntRef, PyStr, PyStrRef, PyTupleRef, PyTypeRef},
function::Either,
function::{ArgBytesLike, FuncArgs, KwArgs, OptionalArg},
identifier,
@@ -383,16 +383,17 @@ mod _operator {
// Go through dotted parts of string and call getattr on whatever is returned.
fn get_single_attr(
obj: PyObjectRef,
attr: &str,
attr: &Py<PyStr>,
vm: &VirtualMachine,
) -> PyResult<PyObjectRef> {
let parts = attr.split('.').collect::<Vec<_>>();
let attr_str = attr.as_str();
let parts = attr_str.split('.').collect::<Vec<_>>();
if parts.len() == 1 {
return obj.get_attr(parts[0], vm);
return obj.get_attr(attr, vm);
}
let mut obj = obj;
for part in parts {
obj = obj.get_attr(part, vm)?;
obj = obj.get_attr(&vm.ctx.new_str(part), vm)?;
}
Ok(obj)
}
@@ -429,12 +430,12 @@ mod _operator {
fn call(zelf: &Py<Self>, obj: Self::Args, vm: &VirtualMachine) -> PyResult {
// Handle case where we only have one attribute.
if zelf.attrs.len() == 1 {
return Self::get_single_attr(obj, zelf.attrs[0].as_str(), vm);
return Self::get_single_attr(obj, &zelf.attrs[0], vm);
}
// Build tuple and call get_single on each element in attrs.
let mut results = Vec::with_capacity(zelf.attrs.len());
for o in &zelf.attrs {
results.push(Self::get_single_attr(obj.clone(), o.as_str(), vm)?);
results.push(Self::get_single_attr(obj.clone(), o, vm)?);
}
Ok(vm.ctx.new_tuple(results).into())
}

View File

@@ -336,27 +336,24 @@ mod sys {
#[pyfunction(name = "__breakpointhook__")]
#[pyfunction]
pub fn breakpointhook(args: FuncArgs, vm: &VirtualMachine) -> PyResult {
let envar = std::env::var("PYTHONBREAKPOINT")
.and_then(|envar| {
if envar.is_empty() {
let env_var = std::env::var("PYTHONBREAKPOINT")
.and_then(|env_var| {
if env_var.is_empty() {
Err(VarError::NotPresent)
} else {
Ok(envar)
Ok(env_var)
}
})
.unwrap_or_else(|_| "pdb.set_trace".to_owned());
if envar.eq("0") {
if env_var.eq("0") {
return Ok(vm.ctx.none());
};
let print_unimportable_module_warn = || {
warn(
vm.ctx.exceptions.runtime_warning,
format!(
"Ignoring unimportable $PYTHONBREAKPOINT: \"{}\"",
envar.to_owned(),
),
format!("Ignoring unimportable $PYTHONBREAKPOINT: \"{env_var}\"",),
0,
vm,
)
@@ -364,30 +361,26 @@ mod sys {
Ok(vm.ctx.none())
};
let last = match envar.split('.').last() {
Some(last) => last,
None => {
return print_unimportable_module_warn();
}
let last = match env_var.rsplit_once('.') {
Some((_, last)) => last,
None if !env_var.is_empty() => env_var.as_str(),
_ => return print_unimportable_module_warn(),
};
let (modulepath, attrname) = if last.eq(&envar) {
("builtins".to_owned(), envar.to_owned())
let (module_path, attr_name) = if last == env_var {
("builtins", env_var.as_str())
} else {
(
envar[..(envar.len() - last.len() - 1)].to_owned(),
last.to_owned(),
)
(&env_var[..(env_var.len() - last.len() - 1)], last)
};
let module = match vm.import(modulepath, None, 0) {
let module = match vm.import(&vm.ctx.new_str(module_path), None, 0) {
Ok(module) => module,
Err(_) => {
return print_unimportable_module_warn();
}
};
match vm.get_attribute_opt(module, attrname) {
match vm.get_attribute_opt(module, &vm.ctx.new_str(attr_name)) {
Ok(Some(hook)) => hook.as_ref().call(args, vm),
_ => print_unimportable_module_warn(),
}

View File

@@ -5,7 +5,7 @@ pub(crate) use _thread::{make_module, RawRMutex};
#[pymodule]
pub(crate) mod _thread {
use crate::{
builtins::{PyDictRef, PyStrRef, PyTupleRef, PyTypeRef},
builtins::{PyDictRef, PyStr, PyTupleRef, PyTypeRef},
convert::ToPyException,
function::{ArgCallable, Either, FuncArgs, KwArgs, OptionalArg, PySetterValue},
types::{Constructor, GetAttr, SetAttr},
@@ -360,13 +360,13 @@ pub(crate) mod _thread {
}
impl GetAttr for Local {
fn getattro(zelf: &Py<Self>, attr: PyStrRef, vm: &VirtualMachine) -> PyResult {
fn getattro(zelf: &Py<Self>, attr: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
let ldict = zelf.ldict(vm);
if attr.as_str() == "__dict__" {
Ok(ldict.into())
} else {
zelf.as_object()
.generic_getattr_opt(attr.clone(), Some(ldict), vm)?
.generic_getattr_opt(attr, Some(ldict), vm)?
.ok_or_else(|| {
vm.new_attribute_error(format!(
"{} has no attribute '{}'",
@@ -381,7 +381,7 @@ pub(crate) mod _thread {
impl SetAttr for Local {
fn setattro(
zelf: &Py<Self>,
attr: PyStrRef,
attr: &Py<PyStr>,
value: PySetterValue,
vm: &VirtualMachine,
) -> PyResult<()> {
@@ -393,9 +393,9 @@ pub(crate) mod _thread {
} else {
let dict = zelf.ldict(vm);
if let PySetterValue::Assign(value) = value {
dict.set_item(&*attr, value, vm)?;
dict.set_item(attr, value, vm)?;
} else {
dict.del_item(&*attr, vm)?;
dict.del_item(attr, vm)?;
}
Ok(())
}

View File

@@ -3,7 +3,7 @@ use crate::{
type_::PointerSlot, PyFloat, PyInt, PyStr, PyStrInterned, PyStrRef, PyType, PyTypeRef,
},
bytecode::ComparisonOperator,
common::{hash::PyHash, lock::PyRwLock},
common::hash::PyHash,
convert::{ToPyObject, ToPyResult},
function::{Either, FromArgs, FuncArgs, OptionalArg, PyComparisonValue, PySetterValue},
identifier,
@@ -30,7 +30,10 @@ macro_rules! atomic_func {
#[derive(Default)]
#[non_exhaustive]
pub struct PyTypeSlots {
pub name: PyRwLock<Option<String>>, // tp_name, not class name
/// # Safety
/// For static types, always safe.
/// For heap types, `__name__` must alive
pub(crate) name: &'static str, // tp_name with <module>.<class> for print, not class name
pub basicsize: usize,
// tp_itemsize
@@ -91,8 +94,9 @@ pub struct PyTypeSlots {
}
impl PyTypeSlots {
pub fn from_flags(flags: PyTypeFlags) -> Self {
pub fn new(name: &'static str, flags: PyTypeFlags) -> Self {
Self {
name,
flags,
..Default::default()
}
@@ -277,9 +281,9 @@ pub(crate) type GenericMethod = fn(&PyObject, FuncArgs, &VirtualMachine) -> PyRe
pub(crate) type HashFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyHash>;
// CallFunc = GenericMethod
pub(crate) type StringifyFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyStrRef>;
pub(crate) type GetattroFunc = fn(&PyObject, PyStrRef, &VirtualMachine) -> PyResult;
pub(crate) type GetattroFunc = fn(&PyObject, &Py<PyStr>, &VirtualMachine) -> PyResult;
pub(crate) type SetattroFunc =
fn(&PyObject, PyStrRef, PySetterValue, &VirtualMachine) -> PyResult<()>;
fn(&PyObject, &Py<PyStr>, PySetterValue, &VirtualMachine) -> PyResult<()>;
pub(crate) type AsBufferFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyBuffer>;
pub(crate) type RichCompareFunc = fn(
&PyObject,
@@ -400,13 +404,13 @@ fn call_wrapper(zelf: &PyObject, args: FuncArgs, vm: &VirtualMachine) -> PyResul
vm.call_special_method(zelf.to_owned(), identifier!(vm, __call__), args)
}
fn getattro_wrapper(zelf: &PyObject, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
fn getattro_wrapper(zelf: &PyObject, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
let __getattribute__ = identifier!(vm, __getattribute__);
let __getattr__ = identifier!(vm, __getattr__);
match vm.call_special_method(zelf.to_owned(), __getattribute__, (name.clone(),)) {
match vm.call_special_method(zelf.to_owned(), __getattribute__, (name.to_owned(),)) {
Ok(r) => Ok(r),
Err(_) if zelf.class().has_attr(__getattr__) => {
vm.call_special_method(zelf.to_owned(), __getattr__, (name,))
vm.call_special_method(zelf.to_owned(), __getattr__, (name.to_owned(),))
}
Err(e) => Err(e),
}
@@ -414,11 +418,12 @@ fn getattro_wrapper(zelf: &PyObject, name: PyStrRef, vm: &VirtualMachine) -> PyR
fn setattro_wrapper(
zelf: &PyObject,
name: PyStrRef,
name: &Py<PyStr>,
value: PySetterValue,
vm: &VirtualMachine,
) -> PyResult<()> {
let zelf = zelf.to_owned();
let name = name.to_owned();
match value {
PySetterValue::Assign(value) => {
vm.call_special_method(zelf, identifier!(vm, __setattr__), (name, value))?;
@@ -1215,19 +1220,19 @@ impl PyComparisonOp {
#[pyclass]
pub trait GetAttr: PyPayload {
#[pyslot]
fn slot_getattro(obj: &PyObject, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
fn slot_getattro(obj: &PyObject, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
let zelf = obj.downcast_ref().ok_or_else(|| {
vm.new_type_error("unexpected payload for __getattribute__".to_owned())
})?;
Self::getattro(zelf, name, vm)
}
fn getattro(zelf: &Py<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult;
fn getattro(zelf: &Py<Self>, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult;
#[inline]
#[pymethod(magic)]
fn getattribute(zelf: PyRef<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
Self::getattro(&zelf, name, vm)
Self::getattro(&zelf, &name, vm)
}
}
@@ -1237,7 +1242,7 @@ pub trait SetAttr: PyPayload {
#[inline]
fn slot_setattro(
obj: &PyObject,
name: PyStrRef,
name: &Py<PyStr>,
value: PySetterValue,
vm: &VirtualMachine,
) -> PyResult<()> {
@@ -1249,7 +1254,7 @@ pub trait SetAttr: PyPayload {
fn setattro(
zelf: &Py<Self>,
name: PyStrRef,
name: &Py<PyStr>,
value: PySetterValue,
vm: &VirtualMachine,
) -> PyResult<()>;
@@ -1262,13 +1267,13 @@ pub trait SetAttr: PyPayload {
value: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
Self::setattro(&zelf, name, PySetterValue::Assign(value), vm)
Self::setattro(&zelf, &name, PySetterValue::Assign(value), vm)
}
#[inline]
#[pymethod(magic)]
fn delattr(zelf: PyRef<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult<()> {
Self::setattro(&zelf, name, PySetterValue::Delete, vm)
Self::setattro(&zelf, &name, PySetterValue::Delete, vm)
}
}

View File

@@ -102,81 +102,82 @@ impl TypeZoo {
type_type: type_::PyType::init_manually(type_type),
object_type: object::PyBaseObject::init_manually(object_type),
weakref_type: weakref::PyWeak::init_manually(weakref_type),
int_type: int::PyInt::init_bare_type(),
int_type: int::PyInt::init_builtin_type(),
// types exposed as builtins
bool_type: bool_::PyBool::init_bare_type(),
bytearray_type: bytearray::PyByteArray::init_bare_type(),
bytes_type: bytes::PyBytes::init_bare_type(),
classmethod_type: classmethod::PyClassMethod::init_bare_type(),
complex_type: complex::PyComplex::init_bare_type(),
dict_type: dict::PyDict::init_bare_type(),
enumerate_type: enumerate::PyEnumerate::init_bare_type(),
float_type: float::PyFloat::init_bare_type(),
frozenset_type: set::PyFrozenSet::init_bare_type(),
filter_type: filter::PyFilter::init_bare_type(),
list_type: list::PyList::init_bare_type(),
map_type: map::PyMap::init_bare_type(),
memoryview_type: memory::PyMemoryView::init_bare_type(),
property_type: property::PyProperty::init_bare_type(),
range_type: range::PyRange::init_bare_type(),
set_type: set::PySet::init_bare_type(),
slice_type: slice::PySlice::init_bare_type(),
staticmethod_type: staticmethod::PyStaticMethod::init_bare_type(),
str_type: pystr::PyStr::init_bare_type(),
super_type: super_::PySuper::init_bare_type(),
tuple_type: tuple::PyTuple::init_bare_type(),
zip_type: zip::PyZip::init_bare_type(),
bool_type: bool_::PyBool::init_builtin_type(),
bytearray_type: bytearray::PyByteArray::init_builtin_type(),
bytes_type: bytes::PyBytes::init_builtin_type(),
classmethod_type: classmethod::PyClassMethod::init_builtin_type(),
complex_type: complex::PyComplex::init_builtin_type(),
dict_type: dict::PyDict::init_builtin_type(),
enumerate_type: enumerate::PyEnumerate::init_builtin_type(),
float_type: float::PyFloat::init_builtin_type(),
frozenset_type: set::PyFrozenSet::init_builtin_type(),
filter_type: filter::PyFilter::init_builtin_type(),
list_type: list::PyList::init_builtin_type(),
map_type: map::PyMap::init_builtin_type(),
memoryview_type: memory::PyMemoryView::init_builtin_type(),
property_type: property::PyProperty::init_builtin_type(),
range_type: range::PyRange::init_builtin_type(),
set_type: set::PySet::init_builtin_type(),
slice_type: slice::PySlice::init_builtin_type(),
staticmethod_type: staticmethod::PyStaticMethod::init_builtin_type(),
str_type: pystr::PyStr::init_builtin_type(),
super_type: super_::PySuper::init_builtin_type(),
tuple_type: tuple::PyTuple::init_builtin_type(),
zip_type: zip::PyZip::init_builtin_type(),
// hidden internal types. is this really need to be cached here?
async_generator: asyncgenerator::PyAsyncGen::init_bare_type(),
async_generator_asend: asyncgenerator::PyAsyncGenASend::init_bare_type(),
async_generator_athrow: asyncgenerator::PyAsyncGenAThrow::init_bare_type(),
async_generator_wrapped_value: asyncgenerator::PyAsyncGenWrappedValue::init_bare_type(),
bound_method_type: function::PyBoundMethod::init_bare_type(),
builtin_function_or_method_type: builtin_func::PyBuiltinFunction::init_bare_type(),
bytearray_iterator_type: bytearray::PyByteArrayIterator::init_bare_type(),
bytes_iterator_type: bytes::PyBytesIterator::init_bare_type(),
callable_iterator: iter::PyCallableIterator::init_bare_type(),
cell_type: function::PyCell::init_bare_type(),
code_type: code::PyCode::init_bare_type(),
coroutine_type: coroutine::PyCoroutine::init_bare_type(),
coroutine_wrapper_type: coroutine::PyCoroutineWrapper::init_bare_type(),
dict_keys_type: dict::PyDictKeys::init_bare_type(),
dict_values_type: dict::PyDictValues::init_bare_type(),
dict_items_type: dict::PyDictItems::init_bare_type(),
dict_keyiterator_type: dict::PyDictKeyIterator::init_bare_type(),
dict_reversekeyiterator_type: dict::PyDictReverseKeyIterator::init_bare_type(),
dict_valueiterator_type: dict::PyDictValueIterator::init_bare_type(),
dict_reversevalueiterator_type: dict::PyDictReverseValueIterator::init_bare_type(),
dict_itemiterator_type: dict::PyDictItemIterator::init_bare_type(),
dict_reverseitemiterator_type: dict::PyDictReverseItemIterator::init_bare_type(),
ellipsis_type: slice::PyEllipsis::init_bare_type(),
frame_type: crate::frame::Frame::init_bare_type(),
function_type: function::PyFunction::init_bare_type(),
generator_type: generator::PyGenerator::init_bare_type(),
getset_type: getset::PyGetSet::init_bare_type(),
iter_type: iter::PySequenceIterator::init_bare_type(),
reverse_iter_type: enumerate::PyReverseSequenceIterator::init_bare_type(),
list_iterator_type: list::PyListIterator::init_bare_type(),
list_reverseiterator_type: list::PyListReverseIterator::init_bare_type(),
mappingproxy_type: mappingproxy::PyMappingProxy::init_bare_type(),
memoryviewiterator_type: memory::PyMemoryViewIterator::init_bare_type(),
module_type: module::PyModule::init_bare_type(),
namespace_type: namespace::PyNamespace::init_bare_type(),
range_iterator_type: range::PyRangeIterator::init_bare_type(),
long_range_iterator_type: range::PyLongRangeIterator::init_bare_type(),
set_iterator_type: set::PySetIterator::init_bare_type(),
str_iterator_type: pystr::PyStrIterator::init_bare_type(),
traceback_type: traceback::PyTraceback::init_bare_type(),
tuple_iterator_type: tuple::PyTupleIterator::init_bare_type(),
weakproxy_type: weakproxy::PyWeakProxy::init_bare_type(),
method_descriptor_type: builtin_func::PyBuiltinMethod::init_bare_type(),
none_type: singletons::PyNone::init_bare_type(),
not_implemented_type: singletons::PyNotImplemented::init_bare_type(),
generic_alias_type: genericalias::PyGenericAlias::init_bare_type(),
union_type: union_::PyUnion::init_bare_type(),
member_descriptor_type: descriptor::MemberDescrObject::init_bare_type(),
async_generator: asyncgenerator::PyAsyncGen::init_builtin_type(),
async_generator_asend: asyncgenerator::PyAsyncGenASend::init_builtin_type(),
async_generator_athrow: asyncgenerator::PyAsyncGenAThrow::init_builtin_type(),
async_generator_wrapped_value:
asyncgenerator::PyAsyncGenWrappedValue::init_builtin_type(),
bound_method_type: function::PyBoundMethod::init_builtin_type(),
builtin_function_or_method_type: builtin_func::PyBuiltinFunction::init_builtin_type(),
bytearray_iterator_type: bytearray::PyByteArrayIterator::init_builtin_type(),
bytes_iterator_type: bytes::PyBytesIterator::init_builtin_type(),
callable_iterator: iter::PyCallableIterator::init_builtin_type(),
cell_type: function::PyCell::init_builtin_type(),
code_type: code::PyCode::init_builtin_type(),
coroutine_type: coroutine::PyCoroutine::init_builtin_type(),
coroutine_wrapper_type: coroutine::PyCoroutineWrapper::init_builtin_type(),
dict_keys_type: dict::PyDictKeys::init_builtin_type(),
dict_values_type: dict::PyDictValues::init_builtin_type(),
dict_items_type: dict::PyDictItems::init_builtin_type(),
dict_keyiterator_type: dict::PyDictKeyIterator::init_builtin_type(),
dict_reversekeyiterator_type: dict::PyDictReverseKeyIterator::init_builtin_type(),
dict_valueiterator_type: dict::PyDictValueIterator::init_builtin_type(),
dict_reversevalueiterator_type: dict::PyDictReverseValueIterator::init_builtin_type(),
dict_itemiterator_type: dict::PyDictItemIterator::init_builtin_type(),
dict_reverseitemiterator_type: dict::PyDictReverseItemIterator::init_builtin_type(),
ellipsis_type: slice::PyEllipsis::init_builtin_type(),
frame_type: crate::frame::Frame::init_builtin_type(),
function_type: function::PyFunction::init_builtin_type(),
generator_type: generator::PyGenerator::init_builtin_type(),
getset_type: getset::PyGetSet::init_builtin_type(),
iter_type: iter::PySequenceIterator::init_builtin_type(),
reverse_iter_type: enumerate::PyReverseSequenceIterator::init_builtin_type(),
list_iterator_type: list::PyListIterator::init_builtin_type(),
list_reverseiterator_type: list::PyListReverseIterator::init_builtin_type(),
mappingproxy_type: mappingproxy::PyMappingProxy::init_builtin_type(),
memoryviewiterator_type: memory::PyMemoryViewIterator::init_builtin_type(),
module_type: module::PyModule::init_builtin_type(),
namespace_type: namespace::PyNamespace::init_builtin_type(),
range_iterator_type: range::PyRangeIterator::init_builtin_type(),
long_range_iterator_type: range::PyLongRangeIterator::init_builtin_type(),
set_iterator_type: set::PySetIterator::init_builtin_type(),
str_iterator_type: pystr::PyStrIterator::init_builtin_type(),
traceback_type: traceback::PyTraceback::init_builtin_type(),
tuple_iterator_type: tuple::PyTupleIterator::init_builtin_type(),
weakproxy_type: weakproxy::PyWeakProxy::init_builtin_type(),
method_descriptor_type: builtin_func::PyBuiltinMethod::init_builtin_type(),
none_type: singletons::PyNone::init_builtin_type(),
not_implemented_type: singletons::PyNotImplemented::init_builtin_type(),
generic_alias_type: genericalias::PyGenericAlias::init_builtin_type(),
union_type: union_::PyUnion::init_builtin_type(),
member_descriptor_type: descriptor::MemberDescrObject::init_builtin_type(),
}
}

View File

@@ -18,7 +18,7 @@ use crate::{
common::rc::PyRc,
exceptions,
function::{IntoPyGetterFunc, IntoPyNativeFunc, IntoPySetterFunc},
intern::{Internable, MaybeInterned, StringPool},
intern::{InternableString, MaybeInternedString, StringPool},
object::{Py, PyObjectPayload, PyObjectRef, PyPayload, PyRef},
types::{PyTypeFlags, PyTypeSlots, TypeZoo},
PyResult, VirtualMachine,
@@ -320,11 +320,14 @@ impl Context {
context
}
pub fn intern_str<S: Internable>(&self, s: S) -> &'static PyStrInterned {
pub fn intern_str<S: InternableString>(&self, s: S) -> &'static PyStrInterned {
unsafe { self.string_pool.intern(s, self.types.str_type.to_owned()) }
}
pub fn interned_str<S: MaybeInterned + ?Sized>(&self, s: &S) -> Option<&'static PyStrInterned> {
pub fn interned_str<S: MaybeInternedString + ?Sized>(
&self,
s: &S,
) -> Option<&'static PyStrInterned> {
self.string_pool.interned(s)
}
@@ -386,6 +389,17 @@ impl Context {
pystr::PyStr::new_ref(s, self)
}
pub fn interned_or_new_str<S, M>(&self, s: S) -> PyRef<PyStr>
where
S: Into<PyStr> + AsRef<M>,
M: MaybeInternedString,
{
match self.interned_str(s.as_ref()) {
Some(s) => s.to_owned(),
None => self.new_str(s),
}
}
#[inline]
pub fn new_bytes(&self, data: Vec<u8>) -> PyRef<bytes::PyBytes> {
bytes::PyBytes::new_ref(data, self)
@@ -427,7 +441,7 @@ impl Context {
if let Some(module) = module {
attrs.insert(identifier!(self, __module__), self.new_str(module).into());
};
PyType::new_ref(
PyType::new_heap(
name,
vec![base],
attrs,
@@ -452,11 +466,15 @@ impl Context {
let mut attrs = PyAttributes::default();
attrs.insert(identifier!(self, __module__), self.new_str(module).into());
PyType::new_ref(
let interned_name = self.intern_str(name);
PyType::new_heap(
name,
bases,
attrs,
PyBaseException::make_slots(),
PyTypeSlots {
name: interned_name.as_str(),
..PyBaseException::make_slots()
},
self.types.type_type.to_owned(),
self,
)

View File

@@ -3,9 +3,9 @@
use super::VirtualMachine;
use crate::{
builtins::{PyBaseObject, PyStrInterned, PyStrRef},
builtins::{PyBaseObject, PyStr, PyStrInterned},
function::IntoFuncArgs,
object::{AsObject, PyObjectRef, PyResult},
object::{AsObject, Py, PyObjectRef, PyResult},
types::PyTypeFlags,
};
@@ -19,14 +19,15 @@ pub enum PyMethod {
}
impl PyMethod {
pub fn get(obj: PyObjectRef, name: PyStrRef, vm: &VirtualMachine) -> PyResult<Self> {
pub fn get(obj: PyObjectRef, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult<Self> {
let cls = obj.class();
let getattro = cls.mro_find_map(|cls| cls.slots.getattro.load()).unwrap();
if getattro as usize != PyBaseObject::getattro as usize {
return obj.get_attr(name, vm).map(Self::Attribute);
}
let interned_name = vm.ctx.interned_str(&*name);
// any correct method name is always interned already.
let interned_name = vm.ctx.interned_str(name);
let mut is_method = false;
let cls_attr = match interned_name.and_then(|name| cls.get_attr(name)) {
@@ -54,7 +55,7 @@ impl PyMethod {
};
if let Some(dict) = obj.dict() {
if let Some(attr) = dict.get_item_opt(&*name, vm)? {
if let Some(attr) = dict.get_item_opt(name, vm)? {
return Ok(Self::Attribute(attr));
}
}
@@ -72,14 +73,14 @@ impl PyMethod {
None => Ok(Self::Attribute(attr)),
}
} else if let Some(getter) = cls.get_attr(identifier!(vm, __getattr__)) {
getter.call((obj, name), vm).map(Self::Attribute)
getter.call((obj, name.to_owned()), vm).map(Self::Attribute)
} else {
let exc = vm.new_attribute_error(format!(
"'{}' object has no attribute '{}'",
cls.name(),
name
));
vm.set_attribute_error_context(&exc, obj.clone(), name);
vm.set_attribute_error_context(&exc, obj.clone(), name.to_owned());
Err(exc)
}
}

View File

@@ -17,9 +17,10 @@ mod vm_ops;
use crate::{
builtins::{
code::PyCode,
pystr::IntoPyStrRef,
pystr::AsPyStr,
tuple::{PyTuple, PyTupleTyped},
PyBaseExceptionRef, PyDictRef, PyInt, PyList, PyModule, PyStrInterned, PyStrRef, PyTypeRef,
PyBaseExceptionRef, PyDictRef, PyInt, PyList, PyModule, PyStr, PyStrInterned, PyStrRef,
PyTypeRef,
},
bytecode::frozen_lib::FrozenModule,
codecs::CodecsRegistry,
@@ -33,7 +34,7 @@ use crate::{
scope::Scope,
signal, stdlib,
warn::WarningsState,
AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult,
AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult,
};
use crossbeam_utils::atomic::AtomicCell;
#[cfg(unix)]
@@ -269,8 +270,9 @@ impl VirtualMachine {
Default::default(),
self,
)?;
let dunder_name = self.ctx.intern_str(format!("__{name}__"));
self.sys_module.set_attr(
format!("__{name}__"), // e.g. __stdin__
dunder_name, // e.g. __stdin__
stdio.clone(),
self,
)?;
@@ -444,7 +446,7 @@ impl VirtualMachine {
Ref::map(frame, |f| &f.globals)
}
pub fn try_class(&self, module: &str, class: &str) -> PyResult<PyTypeRef> {
pub fn try_class(&self, module: &'static str, class: &'static str) -> PyResult<PyTypeRef> {
let class = self
.import(module, None, 0)?
.get_attr(class, self)?
@@ -453,10 +455,11 @@ impl VirtualMachine {
Ok(class)
}
pub fn class(&self, module: &str, class: &str) -> PyTypeRef {
pub fn class(&self, module: &'static str, class: &'static str) -> PyTypeRef {
let module = self
.import(module, None, 0)
.unwrap_or_else(|_| panic!("unable to import {module}"));
let class = module
.get_attr(class, self)
.unwrap_or_else(|_| panic!("module {module:?} has no class {class}"));
@@ -464,18 +467,18 @@ impl VirtualMachine {
}
#[inline]
pub fn import(
pub fn import<'a>(
&self,
module: impl IntoPyStrRef,
module: impl AsPyStr<'a>,
from_list: Option<PyTupleTyped<PyStrRef>>,
level: usize,
) -> PyResult {
self._import_inner(module.into_pystr_ref(self), from_list, level)
self.import_inner(module.as_pystr(&self.ctx), from_list, level)
}
fn _import_inner(
fn import_inner(
&self,
module: PyStrRef,
module: &Py<PyStr>,
from_list: Option<PyTupleTyped<PyStrRef>>,
level: usize,
) -> PyResult {
@@ -489,7 +492,7 @@ impl VirtualMachine {
None
} else {
let sys_modules = self.sys_module.get_attr("modules", self)?;
sys_modules.get_item(&*module, self).ok()
sys_modules.get_item(module, self).ok()
};
match cached_module {
@@ -497,7 +500,7 @@ impl VirtualMachine {
if self.is_none(&cached_module) {
Err(self.new_import_error(
format!("import of {module} halted; None in sys.modules"),
module,
module.to_owned(),
))
} else {
Ok(cached_module)
@@ -509,7 +512,7 @@ impl VirtualMachine {
.clone()
.get_attr(identifier!(self, __import__), self)
.map_err(|_| {
self.new_import_error("__import__ not found".to_owned(), module.clone())
self.new_import_error("__import__ not found".to_owned(), module.to_owned())
})?;
let (locals, globals) = if let Some(frame) = self.current_frame() {
@@ -522,7 +525,7 @@ impl VirtualMachine {
None => self.new_tuple(()).into(),
};
import_func
.call((module, globals, locals, from_list, level), self)
.call((module.to_owned(), globals, locals, from_list, level), self)
.map_err(|exc| import::remove_importlib_frames(self, &exc))
}
}
@@ -606,15 +609,13 @@ impl VirtualMachine {
Ok(results)
}
pub fn get_attribute_opt<T>(
pub fn get_attribute_opt<'a>(
&self,
obj: PyObjectRef,
attr_name: T,
) -> PyResult<Option<PyObjectRef>>
where
T: IntoPyStrRef,
{
match obj.get_attr(attr_name, self) {
attr_name: impl AsPyStr<'a>,
) -> PyResult<Option<PyObjectRef>> {
let attr_name = attr_name.as_pystr(&self.ctx);
match obj.get_attr_inner(attr_name, self) {
Ok(attr) => Ok(Some(attr)),
Err(e) if e.fast_isinstance(self.ctx.exceptions.attribute_error) => Ok(None),
Err(e) => Err(e),
@@ -795,12 +796,12 @@ impl VirtualMachine {
pub fn __module_set_attr(
&self,
module: &PyObject,
attr_name: impl IntoPyStrRef,
attr_name: &str,
attr_value: impl Into<PyObjectRef>,
) -> PyResult<()> {
let val = attr_value.into();
module.generic_setattr(
attr_name.into_pystr_ref(self),
self.ctx.intern_str(attr_name),
PySetterValue::Assign(val),
self,
)

View File

@@ -1,6 +1,5 @@
use crate::{
builtins::{
pystr::IntoPyStrRef,
tuple::{IntoPyTuple, PyTupleRef},
PyBaseException, PyBaseExceptionRef, PyDictRef, PyModule, PyStrRef, PyType, PyTypeRef,
},
@@ -268,12 +267,10 @@ impl VirtualMachine {
syntax_error
}
pub fn new_import_error(&self, msg: String, name: impl IntoPyStrRef) -> PyBaseExceptionRef {
pub fn new_import_error(&self, msg: String, name: PyStrRef) -> PyBaseExceptionRef {
let import_error = self.ctx.exceptions.import_error.to_owned();
let exc = self.new_exception_msg(import_error, msg);
exc.as_object()
.set_attr("name", name.into_pystr_ref(self), self)
.unwrap();
exc.as_object().set_attr("name", name, self).unwrap();
exc
}

View File

@@ -1,9 +1,9 @@
use super::PyMethod;
use crate::{
builtins::{PyBaseExceptionRef, PyList, PyStr, PyStrInterned},
builtins::{pystr::AsPyStr, PyBaseExceptionRef, PyList, PyStrInterned},
function::IntoFuncArgs,
identifier,
object::{AsObject, PyObject, PyObjectRef, PyPayload, PyResult},
object::{AsObject, PyObject, PyObjectRef, PyResult},
vm::VirtualMachine,
};
@@ -104,10 +104,14 @@ impl VirtualMachine {
{
flame_guard!(format!("call_method({:?})", method_name));
let name = self
.ctx
.interned_str(method_name)
.map_or_else(|| PyStr::from(method_name).into_ref(self), |s| s.to_owned());
let dynamic_name;
let name = match self.ctx.interned_str(method_name) {
Some(name) => name.as_pystr(&self.ctx),
None => {
dynamic_name = self.ctx.new_str(method_name);
&dynamic_name
}
};
PyMethod::get(obj.to_owned(), name, self)?.invoke(args, self)
}

View File

@@ -619,7 +619,7 @@ mod _js {
fn js_error(vm: &VirtualMachine) -> PyTypeRef {
let ctx = &vm.ctx;
let js_error = PyRef::leak(
PyType::new_simple_ref("JSError", &vm.ctx.exceptions.exception_type.to_owned(), ctx)
PyType::new_simple_heap("JSError", &vm.ctx.exceptions.exception_type.to_owned(), ctx)
.unwrap(),
);
extend_class!(ctx, js_error, {

View File

@@ -314,7 +314,7 @@ impl WASMVirtualMachine {
let (key, value) = entry?;
let key = Object::from(key).to_string();
extend_module!(vm, py_module, {
String::from(key) => convert::js_to_py(vm, value),
&String::from(key) => convert::js_to_py(vm, value),
});
}