From b2ba6b20136ccdf205fbcd324219695b78f04c80 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Mon, 27 Jan 2020 13:45:46 +0900 Subject: [PATCH] objtype::class_*_attr into PyClassRef methods --- vm/src/obj/objmappingproxy.rs | 6 +- vm/src/obj/objnone.rs | 14 ++--- vm/src/obj/objobject.rs | 15 +++-- vm/src/obj/objslice.rs | 4 +- vm/src/obj/objtype.rs | 106 +++++++++++++++++----------------- vm/src/stdlib/itertools.rs | 2 +- vm/src/vm.rs | 23 ++++---- 7 files changed, 84 insertions(+), 86 deletions(-) diff --git a/vm/src/obj/objmappingproxy.rs b/vm/src/obj/objmappingproxy.rs index 450a37cea..519c42e5c 100644 --- a/vm/src/obj/objmappingproxy.rs +++ b/vm/src/obj/objmappingproxy.rs @@ -1,7 +1,7 @@ use super::objdict::PyDictRef; use super::objiter; use super::objstr::PyStringRef; -use super::objtype::{self, PyClassRef}; +use super::objtype::PyClassRef; use crate::function::OptionalArg; use crate::pyobject::{ ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, @@ -48,7 +48,7 @@ impl PyMappingProxy { let opt = match &self.mapping { MappingProxyInner::Class(class) => { let key = PyStringRef::try_from_object(vm, key)?; - objtype::class_get_attr(&class, key.as_str()) + class.get_attr(key.as_str()) } MappingProxyInner::Dict(obj) => obj.get_item(&key, vm).ok(), }; @@ -75,7 +75,7 @@ impl PyMappingProxy { match &self.mapping { MappingProxyInner::Class(class) => { let key = PyStringRef::try_from_object(vm, key)?; - Ok(vm.new_bool(objtype::class_has_attr(&class, key.as_str()))) + Ok(vm.new_bool(class.has_attr(key.as_str()))) } MappingProxyInner::Dict(obj) => vm._membership(obj.clone(), key), } diff --git a/vm/src/obj/objnone.rs b/vm/src/obj/objnone.rs index 93f7385bd..57a6fcd8d 100644 --- a/vm/src/obj/objnone.rs +++ b/vm/src/obj/objnone.rs @@ -1,6 +1,6 @@ use super::objproperty::PyPropertyRef; use super::objstr::PyStringRef; -use super::objtype::{class_get_attr, class_has_attr, PyClassRef}; +use super::objtype::PyClassRef; use crate::pyobject::{ IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, @@ -79,10 +79,10 @@ impl PyNone { } } - if let Some(attr) = class_get_attr(&cls, name.as_str()) { + if let Some(attr) = cls.get_attr(name.as_str()) { let attr_class = attr.class(); - if class_has_attr(&attr_class, "__set__") { - if let Some(get_func) = class_get_attr(&attr_class, "__get__") { + if attr_class.has_attr("__set__") { + if let Some(get_func) = attr_class.get_attr("__get__") { return call_descriptor( attr, get_func, @@ -98,14 +98,14 @@ impl PyNone { // if let Some(obj_attr) = zelf.as_object().get_attr(name.as_str()) { // Ok(obj_attr) // } else - if let Some(attr) = class_get_attr(&cls, name.as_str()) { + if let Some(attr) = cls.get_attr(name.as_str()) { let attr_class = attr.class(); - if let Some(get_func) = class_get_attr(&attr_class, "__get__") { + if let Some(get_func) = attr_class.get_attr("__get__") { call_descriptor(attr, get_func, zelf.into_object(), cls.into_object(), vm) } else { Ok(attr) } - } else if let Some(getter) = class_get_attr(&cls, "__getattr__") { + } else if let Some(getter) = cls.get_attr("__getattr__") { vm.invoke(&getter, vec![zelf.into_object(), name.into_object()]) } else { Err(vm.new_attribute_error(format!("{} has no attribute '{}'", zelf.as_object(), name))) diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index e9aaa7622..a7409cba2 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -86,8 +86,8 @@ pub(crate) fn object_setattr( vm_trace!("object.__setattr__({:?}, {}, {:?})", obj, attr_name, value); let cls = obj.class(); - if let Some(attr) = objtype::class_get_attr(&cls, attr_name.as_str()) { - if let Some(descriptor) = objtype::class_get_attr(&attr.class(), "__set__") { + if let Some(attr) = cls.get_attr(attr_name.as_str()) { + if let Some(descriptor) = attr.class().get_attr("__set__") { return vm .invoke(&descriptor, vec![attr, obj.clone(), value]) .map(|_| ()); @@ -109,8 +109,8 @@ pub(crate) fn object_setattr( fn object_delattr(obj: PyObjectRef, attr_name: PyStringRef, vm: &VirtualMachine) -> PyResult<()> { let cls = obj.class(); - if let Some(attr) = objtype::class_get_attr(&cls, attr_name.as_str()) { - if let Some(descriptor) = objtype::class_get_attr(&attr.class(), "__delete__") { + if let Some(attr) = cls.get_attr(attr_name.as_str()) { + if let Some(descriptor) = attr.class().get_attr("__delete__") { return vm.invoke(&descriptor, vec![attr, obj.clone()]).map(|_| ()); } } @@ -140,7 +140,7 @@ fn object_subclasshook(vm: &VirtualMachine, _args: PyFuncArgs) -> PyResult { } pub fn object_dir(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { - let attributes: PyAttributes = objtype::get_attributes(obj.class()); + let attributes: PyAttributes = obj.class().get_attributes(); let dict = PyDictRef::from_attributes(attributes, vm)?; @@ -262,9 +262,8 @@ fn object_reduce(obj: PyObjectRef, proto: OptionalArg, vm: &VirtualMachin fn object_reduce_ex(obj: PyObjectRef, proto: usize, vm: &VirtualMachine) -> PyResult { let cls = obj.class(); - if let Some(reduce) = objtype::class_get_attr(&cls, "__reduce__") { - let object_reduce = - objtype::class_get_attr(&vm.ctx.types.object_type, "__reduce__").unwrap(); + if let Some(reduce) = cls.get_attr("__reduce__") { + let object_reduce = vm.ctx.types.object_type.get_attr("__reduce__").unwrap(); if !reduce.is(&object_reduce) { return vm.invoke(&reduce, vec![]); } diff --git a/vm/src/obj/objslice.rs b/vm/src/obj/objslice.rs index 1eae01850..42e3ba24a 100644 --- a/vm/src/obj/objslice.rs +++ b/vm/src/obj/objslice.rs @@ -1,5 +1,5 @@ use super::objint::PyInt; -use super::objtype::{class_has_attr, PyClassRef}; +use super::objtype::PyClassRef; use crate::function::{OptionalArg, PyFuncArgs}; use crate::pyobject::{ IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryIntoRef, @@ -327,7 +327,7 @@ fn to_index_value(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult() { Ok(Some(val.as_bigint().clone())) diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index 8cf45f250..e7431da9b 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -98,7 +98,7 @@ impl PyClassRef { #[pymethod(magic)] fn dir(self, vm: &VirtualMachine) -> PyList { - let attributes = get_attributes(self); + let attributes = self.get_attributes(); let attributes: Vec = attributes .keys() .map(|k| vm.ctx.new_str(k.to_string())) @@ -156,10 +156,10 @@ impl PyClassRef { vm_trace!("type.__getattribute__({:?}, {:?})", self, name); let mcl = self.class(); - if let Some(attr) = class_get_attr(&mcl, &name) { + if let Some(attr) = mcl.get_attr(&name) { let attr_class = attr.class(); - if class_has_attr(&attr_class, "__set__") { - if let Some(ref descriptor) = class_get_attr(&attr_class, "__get__") { + if attr_class.has_attr("__set__") { + if let Some(ref descriptor) = attr_class.get_attr("__get__") { return vm.invoke( descriptor, vec![attr, self.into_object(), mcl.into_object()], @@ -168,18 +168,18 @@ impl PyClassRef { } } - if let Some(attr) = class_get_attr(&self, &name) { + if let Some(attr) = self.get_attr(&name) { let attr_class = attr.class(); - if let Some(ref descriptor) = class_get_attr(&attr_class, "__get__") { + if let Some(ref descriptor) = attr_class.get_attr("__get__") { return vm.invoke(descriptor, vec![attr, vm.get_none(), self.into_object()]); } } - if let Some(cls_attr) = class_get_attr(&self, &name) { + if let Some(cls_attr) = self.get_attr(&name) { Ok(cls_attr) - } else if let Some(attr) = class_get_attr(&mcl, &name) { + } else if let Some(attr) = mcl.get_attr(&name) { vm.call_get_descriptor(attr, self.into_object()) - } else if let Some(ref getter) = class_get_attr(&self, "__getattr__") { + } else if let Some(ref getter) = self.get_attr("__getattr__") { vm.invoke(getter, vec![mcl.into_object(), name_ref.into_object()]) } else { Err(vm.new_attribute_error(format!("{} has no attribute '{}'", self, name))) @@ -193,8 +193,8 @@ impl PyClassRef { value: PyObjectRef, vm: &VirtualMachine, ) -> PyResult<()> { - if let Some(attr) = class_get_attr(&self.class(), attr_name.as_str()) { - if let Some(ref descriptor) = class_get_attr(&attr.class(), "__set__") { + if let Some(attr) = self.class().get_attr(attr_name.as_str()) { + if let Some(ref descriptor) = attr.class().get_attr("__set__") { vm.invoke(descriptor, vec![attr, self.into_object(), value])?; return Ok(()); } @@ -208,15 +208,15 @@ impl PyClassRef { #[pymethod(magic)] fn delattr(self, attr_name: PyStringRef, vm: &VirtualMachine) -> PyResult<()> { - if let Some(attr) = class_get_attr(&self.class(), attr_name.as_str()) { - if let Some(ref descriptor) = class_get_attr(&attr.class(), "__delete__") { + if let Some(attr) = self.class().get_attr(attr_name.as_str()) { + if let Some(ref descriptor) = attr.class().get_attr("__delete__") { return vm .invoke(descriptor, vec![attr, self.into_object()]) .map(|_| ()); } } - if class_get_attr(&self, attr_name.as_str()).is_some() { + if self.get_attr(attr_name.as_str()).is_some() { self.attributes.borrow_mut().remove(attr_name.as_str()); Ok(()) } else { @@ -397,48 +397,48 @@ fn type_dict_setter( )) } -/// This is the internal get_attr implementation for fast lookup on a class. -pub fn class_get_attr(class: &PyClassRef, attr_name: &str) -> Option { - flame_guard!(format!("class_get_attr({:?})", attr_name)); +impl PyClassRef { + /// This is the internal get_attr implementation for fast lookup on a class. + pub fn get_attr(&self, attr_name: &str) -> Option { + flame_guard!(format!("class_get_attr({:?})", attr_name)); - class - .attributes - .borrow() - .get(attr_name) - .cloned() - .or_else(|| class_get_super_attr(class, attr_name)) -} - -pub fn class_get_super_attr(class: &PyClassRef, attr_name: &str) -> Option { - class - .mro - .iter() - .find_map(|class| class.attributes.borrow().get(attr_name).cloned()) -} - -// This is the internal has_attr implementation for fast lookup on a class. -pub fn class_has_attr(class: &PyClassRef, attr_name: &str) -> bool { - class.attributes.borrow().contains_key(attr_name) - || class - .mro - .iter() - .any(|c| c.attributes.borrow().contains_key(attr_name)) -} - -pub fn get_attributes(cls: PyClassRef) -> PyAttributes { - // Gather all members here: - let mut attributes = PyAttributes::new(); - - let mut base_classes: Vec<&PyClassRef> = cls.iter_mro().collect(); - base_classes.reverse(); - - for bc in base_classes { - for (name, value) in bc.attributes.borrow().iter() { - attributes.insert(name.to_string(), value.clone()); - } + self.attributes + .borrow() + .get(attr_name) + .cloned() + .or_else(|| self.get_super_attr(attr_name)) } - attributes + pub fn get_super_attr(&self, attr_name: &str) -> Option { + self.mro + .iter() + .find_map(|class| class.attributes.borrow().get(attr_name).cloned()) + } + + // This is the internal has_attr implementation for fast lookup on a class. + pub fn has_attr(&self, attr_name: &str) -> bool { + self.attributes.borrow().contains_key(attr_name) + || self + .mro + .iter() + .any(|c| c.attributes.borrow().contains_key(attr_name)) + } + + pub fn get_attributes(self) -> PyAttributes { + // Gather all members here: + let mut attributes = PyAttributes::new(); + + let mut base_classes: Vec<&PyClassRef> = self.iter_mro().collect(); + base_classes.reverse(); + + for bc in base_classes { + for (name, value) in bc.attributes.borrow().iter() { + attributes.insert(name.to_string(), value.clone()); + } + } + + attributes + } } fn take_next_base(mut bases: Vec>) -> Option<(PyClassRef, Vec>)> { diff --git a/vm/src/stdlib/itertools.rs b/vm/src/stdlib/itertools.rs index 00828079b..e2688b063 100644 --- a/vm/src/stdlib/itertools.rs +++ b/vm/src/stdlib/itertools.rs @@ -777,7 +777,7 @@ impl PyItertoolsTee { ) -> PyResult> { let n = n.unwrap_or(2); - let copyable = if objtype::class_has_attr(&iterable.class(), "__copy__") { + let copyable = if iterable.class().has_attr("__copy__") { vm.call_method(&iterable, "__copy__", PyFuncArgs::from(vec![]))? } else { PyItertoolsTee::from_iter(iterable, vm)? diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 856fcc17c..75f862f38 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -624,7 +624,7 @@ impl VirtualMachine { if let Some(descr_get) = slots.borrow().descr_get.as_ref() { let cls = obj.class(); descr_get(self, vec![attr, obj.clone(), cls.into_object()].into()) - } else if let Some(ref descriptor) = objtype::class_get_attr(&attr_class, "__get__") { + } else if let Some(ref descriptor) = attr_class.get_attr("__get__") { let cls = obj.class(); self.invoke(descriptor, vec![attr, obj.clone(), cls.into_object()]) } else { @@ -640,7 +640,7 @@ impl VirtualMachine { // This is only used in the vm for magic methods, which use a greatly simplified attribute lookup. let cls = obj.class(); - match objtype::class_get_attr(&cls, method_name) { + match cls.get_attr(method_name) { Some(func) => { vm_trace!( "vm.call_method {:?} {:?} {:?} -> {:?}", @@ -666,7 +666,7 @@ impl VirtualMachine { let result = slot_call(self, args); self.trace_event(TraceEvent::Return)?; result - } else if objtype::class_has_attr(&class, "__call__") { + } else if class.has_attr("__call__") { let result = self.call_method(&callable, "__call__", args); result } else { @@ -781,7 +781,7 @@ impl VirtualMachine { F: FnOnce() -> String, { let cls = obj.class(); - match objtype::class_get_attr(&cls, method_name) { + match cls.get_attr(method_name) { Some(method) => self.call_get_descriptor(method, obj.clone()), None => Err(self.new_type_error(err_msg())), } @@ -790,7 +790,7 @@ impl VirtualMachine { /// May return exception, if `__get__` descriptor raises one pub fn get_method(&self, obj: PyObjectRef, method_name: &str) -> Option { let cls = obj.class(); - let method = objtype::class_get_attr(&cls, method_name)?; + let method = cls.get_attr(method_name)?; Some(self.call_get_descriptor(method, obj.clone())) } @@ -851,10 +851,10 @@ impl VirtualMachine { let name = name_str.as_str(); let cls = obj.class(); - if let Some(attr) = objtype::class_get_attr(&cls, &name) { + if let Some(attr) = cls.get_attr(&name) { let attr_class = attr.class(); - if objtype::class_has_attr(&attr_class, "__set__") { - if let Some(descriptor) = objtype::class_get_attr(&attr_class, "__get__") { + if attr_class.has_attr("__set__") { + if let Some(descriptor) = attr_class.get_attr("__get__") { return self .invoke(&descriptor, vec![attr, obj, cls.into_object()]) .map(Some); @@ -870,9 +870,9 @@ impl VirtualMachine { if let Some(obj_attr) = attr { Ok(Some(obj_attr)) - } else if let Some(attr) = objtype::class_get_attr(&cls, &name) { + } else if let Some(attr) = cls.get_attr(&name) { self.call_get_descriptor(attr, obj).map(Some) - } else if let Some(getter) = objtype::class_get_attr(&cls, "__getattr__") { + } else if let Some(getter) = cls.get_attr("__getattr__") { self.invoke(&getter, vec![obj, name_str.into_object()]) .map(Some) } else { @@ -881,8 +881,7 @@ impl VirtualMachine { } pub fn is_callable(&self, obj: &PyObjectRef) -> bool { - obj.class().slots.borrow().call.is_some() - || objtype::class_has_attr(&obj.class(), "__call__") + obj.class().slots.borrow().call.is_some() || obj.class().has_attr("__call__") } #[inline]