Skip to content

Commit 09f7d92

Browse files
committed
Relocate generic_getattr/opt from vm to object protocol
According to cpython docs, generic_getattr/opt is object protocol. It is more appropriate to locate in protocol/object.rs than vm Signed-off-by: snowapril <sinjihng@gmail.com>
1 parent 3b7bb5c commit 09f7d92

File tree

8 files changed

+76
-73
lines changed

8 files changed

+76
-73
lines changed

vm/src/builtins/genericalias.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ impl GetAttr for PyGenericAlias {
369369
fn getattro(zelf: PyRef<Self>, attr: PyStrRef, vm: &VirtualMachine) -> PyResult {
370370
for exc in &ATTR_EXCEPTIONS {
371371
if *(*exc) == attr.to_string() {
372-
return vm.generic_getattribute(zelf.as_object().to_owned(), attr);
372+
return zelf.as_object().generic_getattr(attr, vm);
373373
}
374374
}
375375
zelf.origin().get_attr(attr, vm)

vm/src/builtins/module.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ impl PyModule {
4949
}
5050

5151
fn getattr_inner(zelf: &Py<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
52-
if let Some(attr) =
53-
vm.generic_getattribute_opt(zelf.to_owned().into(), name.clone(), None)?
52+
if let Some(attr) = zelf
53+
.as_object()
54+
.generic_getattr_opt(name.clone(), None, vm)?
5455
{
5556
return Ok(attr);
5657
}
@@ -66,7 +67,8 @@ impl PyModule {
6667
}
6768

6869
fn name(zelf: PyRef<Self>, vm: &VirtualMachine) -> Option<PyStrRef> {
69-
vm.generic_getattribute_opt(zelf.into(), PyStr::from("__name__").into_ref(vm), None)
70+
zelf.as_object()
71+
.generic_getattr_opt(PyStr::from("__name__").into_ref(vm), None, vm)
7072
.unwrap_or(None)
7173
.and_then(|obj| obj.downcast::<PyStr>().ok())
7274
}

vm/src/builtins/object.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ impl PyBaseObject {
288288
#[pyslot]
289289
pub(crate) fn getattro(obj: PyObjectRef, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
290290
vm_trace!("object.__getattribute__({:?}, {:?})", obj, name);
291-
vm.generic_getattribute(obj, name)
291+
obj.as_object().generic_getattr(name, vm)
292292
}
293293

294294
#[pymethod(magic)]
@@ -331,7 +331,7 @@ pub fn object_set_dict(obj: PyObjectRef, dict: PyDictRef, vm: &VirtualMachine) -
331331
}
332332

333333
pub fn generic_getattr(obj: PyObjectRef, attr_name: PyStrRef, vm: &VirtualMachine) -> PyResult {
334-
vm.generic_getattribute(obj, attr_name)
334+
obj.as_object().generic_getattr(attr_name, vm)
335335
}
336336

337337
pub fn init(ctx: &Context) {

vm/src/builtins/super.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl PySuper {
126126

127127
impl GetAttr for PySuper {
128128
fn getattro(zelf: PyRef<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
129-
let skip = |zelf: PyRef<Self>, name| vm.generic_getattribute(zelf.into(), name);
129+
let skip = |zelf: PyRef<Self>, name| zelf.as_object().generic_getattr(name, vm);
130130
let (obj, start_type): (PyObjectRef, PyTypeRef) = match zelf.obj.clone() {
131131
Some(o) => o,
132132
None => return skip(zelf, name),

vm/src/builtins/union.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ impl GetAttr for PyUnion {
266266
fn getattro(zelf: PyRef<Self>, attr: PyStrRef, vm: &VirtualMachine) -> PyResult {
267267
for &exc in CLS_ATTRS {
268268
if *exc == attr.to_string() {
269-
return vm.generic_getattribute(zelf.as_object().to_owned(), attr);
269+
return zelf.as_object().generic_getattr(attr, vm);
270270
}
271271
}
272272
zelf.as_object().to_pyobject(vm).get_attr(attr, vm)

vm/src/protocol/object.rs

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
44
use crate::{
55
builtins::{
6-
pystr::IntoPyStrRef, PyBytes, PyDict, PyGenericAlias, PyInt, PyStrRef, PyTupleRef,
7-
PyTypeRef,
6+
pystr::IntoPyStrRef, PyBytes, PyDict, PyDictRef, PyGenericAlias, PyInt, PyStrRef,
7+
PyTupleRef, PyTypeRef,
88
},
99
bytesinner::ByteInnerNewOptions,
1010
common::{hash::PyHash, str::to_ascii},
@@ -118,8 +118,6 @@ impl PyObject {
118118
setattro(self, attr_name, attr_value, vm)
119119
}
120120

121-
// PyObject *PyObject_GenericGetAttr(PyObject *o, PyObject *name)
122-
123121
pub fn set_attr(
124122
&self,
125123
attr_name: impl IntoPyStrRef,
@@ -173,6 +171,68 @@ impl PyObject {
173171
}
174172
}
175173

174+
pub fn generic_getattr(&self, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
175+
self.generic_getattr_opt(name.clone(), None, vm)?
176+
.ok_or_else(|| vm.new_attribute_error(format!("{} has no attribute '{}'", self, name)))
177+
}
178+
179+
/// CPython _PyObject_GenericGetAttrWithDict
180+
pub fn generic_getattr_opt(
181+
&self,
182+
name_str: PyStrRef,
183+
dict: Option<PyDictRef>,
184+
vm: &VirtualMachine,
185+
) -> PyResult<Option<PyObjectRef>> {
186+
let name = name_str.as_str();
187+
let obj_cls = self.class();
188+
let cls_attr = match obj_cls.get_attr(name) {
189+
Some(descr) => {
190+
let descr_cls = descr.class();
191+
let descr_get = descr_cls.mro_find_map(|cls| cls.slots.descr_get.load());
192+
if let Some(descr_get) = descr_get {
193+
if descr_cls
194+
.mro_find_map(|cls| cls.slots.descr_set.load())
195+
.is_some()
196+
{
197+
drop(descr_cls);
198+
let cls = obj_cls.into_owned().into();
199+
return descr_get(descr, Some(self.to_pyobject(vm)), Some(cls), vm)
200+
.map(Some);
201+
}
202+
}
203+
drop(descr_cls);
204+
Some((descr, descr_get))
205+
}
206+
None => None,
207+
};
208+
209+
let dict = dict.or_else(|| self.dict());
210+
211+
let attr = if let Some(dict) = dict {
212+
dict.get_item_opt(name, vm)?
213+
} else {
214+
None
215+
};
216+
217+
if let Some(obj_attr) = attr {
218+
Ok(Some(obj_attr))
219+
} else if let Some((attr, descr_get)) = cls_attr {
220+
match descr_get {
221+
Some(descr_get) => {
222+
let cls = obj_cls.into_owned().into();
223+
descr_get(attr, Some(self.to_pyobject(vm)), Some(cls), vm).map(Some)
224+
}
225+
None => Ok(Some(attr)),
226+
}
227+
} else if let Some(getter) = obj_cls.get_attr("__getattr__") {
228+
drop(obj_cls);
229+
vm.invoke(&getter, (self.to_pyobject(vm), name_str))
230+
.map(Some)
231+
} else {
232+
Ok(None)
233+
}
234+
}
235+
176236
pub fn del_attr(&self, attr_name: impl IntoPyStrRef, vm: &VirtualMachine) -> PyResult<()> {
177237
let attr_name = attr_name.into_pystr_ref(vm);
178238
self.call_set_attr(vm, attr_name, None)

vm/src/stdlib/thread.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,8 @@ pub(crate) mod _thread {
326326
if attr.as_str() == "__dict__" {
327327
Ok(ldict.into())
328328
} else {
329-
vm.generic_getattribute_opt(zelf.clone().into(), attr.clone(), Some(ldict))?
329+
zelf.as_object()
330+
.generic_getattr_opt(attr.clone(), Some(ldict), vm)?
330331
.ok_or_else(|| {
331332
vm.new_attribute_error(format!(
332333
"{} has no attribute '{}'",

vm/src/vm/mod.rs

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -593,66 +593,6 @@ impl VirtualMachine {
593593
Some(self.call_if_get_descriptor(method, obj))
594594
}
595595

596-
pub fn generic_getattribute(&self, obj: PyObjectRef, name: PyStrRef) -> PyResult {
597-
self.generic_getattribute_opt(obj.clone(), name.clone(), None)?
598-
.ok_or_else(|| self.new_attribute_error(format!("{} has no attribute '{}'", obj, name)))
599-
}
600-
601-
/// CPython _PyObject_GenericGetAttrWithDict
602-
pub fn generic_getattribute_opt(
603-
&self,
604-
obj: PyObjectRef,
605-
name_str: PyStrRef,
606-
dict: Option<PyDictRef>,
607-
) -> PyResult<Option<PyObjectRef>> {
608-
let name = name_str.as_str();
609-
let obj_cls = obj.class();
610-
let cls_attr = match obj_cls.get_attr(name) {
611-
Some(descr) => {
612-
let descr_cls = descr.class();
613-
let descr_get = descr_cls.mro_find_map(|cls| cls.slots.descr_get.load());
614-
if let Some(descr_get) = descr_get {
615-
if descr_cls
616-
.mro_find_map(|cls| cls.slots.descr_set.load())
617-
.is_some()
618-
{
619-
drop(descr_cls);
620-
let cls = obj_cls.into_owned().into();
621-
return descr_get(descr, Some(obj), Some(cls), self).map(Some);
622-
}
623-
}
624-
drop(descr_cls);
625-
Some((descr, descr_get))
626-
}
627-
None => None,
628-
};
629-
630-
let dict = dict.or_else(|| obj.dict());
631-
632-
let attr = if let Some(dict) = dict {
633-
dict.get_item_opt(name, self)?
634-
} else {
635-
None
636-
};
637-
638-
if let Some(obj_attr) = attr {
639-
Ok(Some(obj_attr))
640-
} else if let Some((attr, descr_get)) = cls_attr {
641-
match descr_get {
642-
Some(descr_get) => {
643-
let cls = obj_cls.into_owned().into();
644-
descr_get(attr, Some(obj), Some(cls), self).map(Some)
645-
}
646-
None => Ok(Some(attr)),
647-
}
648-
} else if let Some(getter) = obj_cls.get_attr("__getattr__") {
649-
drop(obj_cls);
650-
self.invoke(&getter, (obj, name_str)).map(Some)
651-
} else {
652-
Ok(None)
653-
}
654-
}
655-
656596
pub fn is_callable(&self, obj: &PyObject) -> bool {
657597
obj.class()
658598
.mro_find_map(|cls| cls.slots.call.load())

0 commit comments

Comments
 (0)