From e5186004d42d0715e7f88868d290f1dbe2270ba8 Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Fri, 25 Sep 2020 12:13:53 -0500 Subject: [PATCH] Some more getattr related tweaks/optimizations --- bytecode/src/bytecode.rs | 2 +- vm/src/frame.rs | 37 ++++++++++++++++--------------------- vm/src/obj/objdict.rs | 17 +++++++++-------- vm/src/obj/objframe.rs | 2 +- vm/src/pyobject.rs | 6 +++--- vm/src/scope.rs | 6 +++--- vm/src/vm.rs | 4 ++-- 7 files changed, 35 insertions(+), 39 deletions(-) diff --git a/bytecode/src/bytecode.rs b/bytecode/src/bytecode.rs index 74c8a0356..7223d9efc 100644 --- a/bytecode/src/bytecode.rs +++ b/bytecode/src/bytecode.rs @@ -91,7 +91,7 @@ impl Label { } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] /// An indication where the name must be accessed. pub enum NameScope { /// The name will be in the local scope. diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 8b95c7886..563d920bc 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -10,19 +10,17 @@ use crate::common::cell::PyMutex; use crate::exceptions::{self, ExceptionCtor, PyBaseExceptionRef}; use crate::function::PyFuncArgs; use crate::obj::objasyncgenerator::PyAsyncGenWrappedValue; -use crate::obj::objbool; use crate::obj::objcode::PyCodeRef; use crate::obj::objcoroinner::Coro; use crate::obj::objcoroutine::PyCoroutine; use crate::obj::objdict::{PyDict, PyDictRef}; use crate::obj::objgenerator::PyGenerator; -use crate::obj::objiter; -use crate::obj::objlist; use crate::obj::objslice::PySlice; use crate::obj::objstr::{self, PyStr, PyStrRef}; use crate::obj::objtraceback::PyTraceback; use crate::obj::objtuple::PyTuple; use crate::obj::objtype::{self, PyTypeRef}; +use crate::obj::{objbool, objiter, objlist, objset}; use crate::pyobject::{ BorrowValue, IdProtocol, ItemProtocol, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, @@ -177,6 +175,7 @@ impl Frame { } impl FrameRef { + #[inline] fn with_exec(&self, f: impl FnOnce(ExecutingFrame) -> R) -> R { let mut state = self.state.lock(); let exec = ExecutingFrame { @@ -350,14 +349,10 @@ impl ExecutingFrame<'_> { } => self.import(vm, name, symbols, *level), bytecode::Instruction::ImportStar => self.import_star(vm), bytecode::Instruction::ImportFrom { ref name } => self.import_from(vm, name), - bytecode::Instruction::LoadName { - ref name, - ref scope, - } => self.load_name(vm, name, scope), - bytecode::Instruction::StoreName { - ref name, - ref scope, - } => self.store_name(vm, name, scope), + bytecode::Instruction::LoadName { ref name, scope } => self.load_name(vm, name, *scope), + bytecode::Instruction::StoreName { ref name, scope } => { + self.store_name(vm, name, *scope) + } bytecode::Instruction::DeleteName { ref name } => self.delete_name(vm, name), bytecode::Instruction::Subscript => self.execute_subscript(vm), bytecode::Instruction::StoreSubscript => self.execute_store_subscript(vm), @@ -393,11 +388,11 @@ impl ExecutingFrame<'_> { } bytecode::Instruction::BuildSet { size, unpack } => { let elements = self.get_elements(vm, *size, *unpack)?; - let py_obj = vm.ctx.new_set(); + let set = vm.ctx.new_set(); for item in elements { - vm.call_method(&py_obj, "add", vec![item])?; + set.add(item, vm)?; } - self.push_value(py_obj); + self.push_value(set.into_object()); Ok(None) } bytecode::Instruction::BuildTuple { size, unpack } => { @@ -421,14 +416,14 @@ impl ExecutingFrame<'_> { bytecode::Instruction::SetAdd { i } => { let set_obj = self.nth_value(*i); let item = self.pop_value(); - vm.call_method(&set_obj, "add", vec![item])?; + objset::PySetRef::try_from_object(vm, set_obj)?.add(item, vm)?; Ok(None) } bytecode::Instruction::MapAdd { i } => { let dict_obj = self.nth_value(*i + 1); let key = self.pop_value(); let value = self.pop_value(); - vm.call_method(&dict_obj, "__setitem__", vec![key, value])?; + PyDictRef::try_from_object(vm, dict_obj)?.set_item(key, value, vm)?; Ok(None) } bytecode::Instruction::MapAddRev { i } => { @@ -436,7 +431,7 @@ impl ExecutingFrame<'_> { let dict_obj = self.nth_value(*i + 1); let value = self.pop_value(); let key = self.pop_value(); - vm.call_method(&dict_obj, "__setitem__", vec![key, value])?; + PyDictRef::try_from_object(vm, dict_obj)?.set_item(key, value, vm)?; Ok(None) } bytecode::Instruction::BinaryOperation { ref op, inplace } => { @@ -882,7 +877,7 @@ impl ExecutingFrame<'_> { &mut self, vm: &VirtualMachine, name: &str, - name_scope: &bytecode::NameScope, + name_scope: bytecode::NameScope, ) -> FrameResult { let obj = self.pop_value(); match name_scope { @@ -910,11 +905,12 @@ impl ExecutingFrame<'_> { } #[cfg_attr(feature = "flame-it", flame("Frame"))] + #[inline] fn load_name( &mut self, vm: &VirtualMachine, name: &str, - name_scope: &bytecode::NameScope, + name_scope: bytecode::NameScope, ) -> FrameResult { let optional_value = match name_scope { bytecode::NameScope::Global => self.scope.load_global(vm, name), @@ -1210,8 +1206,7 @@ impl ExecutingFrame<'_> { fn jump(&mut self, label: bytecode::Label) { let target_pc = self.code.label_map[&label]; - #[cfg(feature = "vm-tracing-logging")] - trace!("jump from {:?} to {:?}", self.lasti(), target_pc); + vm_trace!("jump from {:?} to {:?}", self.lasti(), target_pc); self.lasti.store(target_pc, Ordering::Relaxed); } diff --git a/vm/src/obj/objdict.rs b/vm/src/obj/objdict.rs index b8f7b8816..3739b7893 100644 --- a/vm/src/obj/objdict.rs +++ b/vm/src/obj/objdict.rs @@ -388,7 +388,7 @@ impl PyDict { Ok(PyDict { entries: dict }) } - pub fn contains_key(&self, key: T, vm: &VirtualMachine) -> bool { + pub fn contains_key(&self, key: K, vm: &VirtualMachine) -> bool { let key = key.into_pyobject(vm); self.entries.contains(vm, &key).unwrap() } @@ -421,6 +421,7 @@ impl Unhashable for PyDict {} impl PyDictRef { /// Return an optional inner item, or an error (can be key error as well) + #[inline] fn inner_getitem_option( &self, key: K, @@ -453,9 +454,9 @@ impl PyDictRef { /// python value, or None. /// Note that we can pass any type which implements the DictKey /// trait. Notable examples are String and PyObjectRef. - pub fn get_item_option( + pub fn get_item_option( &self, - key: T, + key: K, vm: &VirtualMachine, ) -> PyResult> { // Test if this object is a true dict, or mabye a subclass? @@ -492,15 +493,15 @@ impl PyDictRef { } } -impl ItemProtocol for PyDictRef +impl ItemProtocol for PyDictRef where - T: DictKey, + K: DictKey, { - fn get_item(&self, key: T, vm: &VirtualMachine) -> PyResult { + fn get_item(&self, key: K, vm: &VirtualMachine) -> PyResult { self.as_object().get_item(key, vm) } - fn set_item(&self, key: T, value: PyObjectRef, vm: &VirtualMachine) -> PyResult { + fn set_item(&self, key: K, value: PyObjectRef, vm: &VirtualMachine) -> PyResult { if self.lease_class().is(&vm.ctx.types.dict_type) { self.inner_setitem_fast(key, value, vm) .map(|_| vm.ctx.none()) @@ -510,7 +511,7 @@ where } } - fn del_item(&self, key: T, vm: &VirtualMachine) -> PyResult { + fn del_item(&self, key: K, vm: &VirtualMachine) -> PyResult { if self.lease_class().is(&vm.ctx.types.dict_type) { self.entries.delete(vm, key).map(|_| vm.ctx.none()) } else { diff --git a/vm/src/obj/objframe.rs b/vm/src/obj/objframe.rs index 4e92fbc52..014125d58 100644 --- a/vm/src/obj/objframe.rs +++ b/vm/src/obj/objframe.rs @@ -46,7 +46,7 @@ impl FrameRef { #[pyproperty] fn f_locals(self) -> PyDictRef { - self.scope.get_locals() + self.scope.get_locals().clone() } #[pyproperty] diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 9c7189764..07c93ac99 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -27,7 +27,7 @@ use crate::obj::objiter; use crate::obj::objlist::PyList; use crate::obj::objnamespace::PyNamespace; use crate::obj::objobject; -use crate::obj::objset::PySet; +use crate::obj::objset; use crate::obj::objsingletons::{PyNone, PyNoneRef, PyNotImplemented, PyNotImplementedRef}; use crate::obj::objslice::PyEllipsis; use crate::obj::objstaticmethod::PyStaticMethod; @@ -256,10 +256,10 @@ impl PyContext { PyObject::new(PyList::from(elements), self.types.list_type.clone(), None) } - pub fn new_set(&self) -> PyObjectRef { + pub fn new_set(&self) -> objset::PySetRef { // Initialized empty, as calling __hash__ is required for adding each object to the set // which requires a VM context - this is done in the objset code itself. - PyObject::new(PySet::default(), self.types.set_type.clone(), None) + PyRef::new_ref(objset::PySet::default(), self.types.set_type.clone(), None) } pub fn new_dict(&self) -> PyDictRef { diff --git a/vm/src/scope.rs b/vm/src/scope.rs index d71b51050..e7f6811b5 100644 --- a/vm/src/scope.rs +++ b/vm/src/scope.rs @@ -45,10 +45,10 @@ impl Scope { Scope::new(locals, globals, vm) } - pub fn get_locals(&self) -> PyDictRef { + pub fn get_locals(&self) -> &PyDictRef { match self.locals.first() { - Some(dict) => dict.clone(), - None => self.globals.clone(), + Some(dict) => dict, + None => &self.globals, } } diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 456216bb2..e312ca4e5 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -700,7 +700,7 @@ impl VirtualMachine { } pub fn get_locals(&self) -> PyDictRef { - self.current_scope().get_locals() + self.current_scope().get_locals().clone() } // Container of the virtual machine state: @@ -783,7 +783,7 @@ impl VirtualMachine { let (locals, globals) = if let Some(frame) = self.current_frame() { ( - frame.scope.get_locals().into_object(), + frame.scope.get_locals().clone().into_object(), frame.scope.globals.clone().into_object(), ) } else {