From 946fc93170c3152411eeeca1f1e6debda664f729 Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Sat, 23 Apr 2022 06:59:52 +0900 Subject: [PATCH] vm::PyContext --- vm/src/lib.rs | 5 +- vm/src/pyclass.rs | 3 +- vm/src/pyobject.rs | 320 +------------------------------------- vm/src/types/structseq.rs | 2 +- vm/src/types/zoo.rs | 2 +- vm/src/vm/context.rs | 316 +++++++++++++++++++++++++++++++++++++ vm/src/vm/mod.rs | 4 +- 7 files changed, 329 insertions(+), 323 deletions(-) create mode 100644 vm/src/vm/context.rs diff --git a/vm/src/lib.rs b/vm/src/lib.rs index 1a65bacbd..e5df719a3 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -84,14 +84,13 @@ mod pyobject { pub use super::_pyobjectrc::*; } -// pub use self::Executor; pub use self::convert::{TryFromBorrowedObject, TryFromObject}; // pyobject items -pub use self::pyobject::{AsObject, PyContext, PyMethod, PyPayload, PyRefExact, PyResult}; +pub use self::pyobject::{AsObject, PyMethod, PyPayload, PyRefExact, PyResult}; // pyobjectrc items pub use self::pyobject::{Py, PyObject, PyObjectRef, PyRef, PyWeakRef}; pub use self::types::PyStructSequence; -pub use self::vm::{InitParameter, Interpreter, PySettings, VirtualMachine}; +pub use self::vm::{InitParameter, Interpreter, PyContext, PySettings, VirtualMachine}; pub use rustpython_bytecode as bytecode; pub use rustpython_common as common; diff --git a/vm/src/pyclass.rs b/vm/src/pyclass.rs index bf06ba50c..f8e0ef634 100644 --- a/vm/src/pyclass.rs +++ b/vm/src/pyclass.rs @@ -2,8 +2,9 @@ use crate::{ builtins::{PyBaseObject, PyBoundMethod, PyType, PyTypeRef}, - pyobject::{PyContext, PyObjectPayload, PyObjectRef, PyRef}, + pyobject::{PyObjectPayload, PyObjectRef, PyRef}, types::{PyTypeFlags, PyTypeSlots}, + vm::PyContext, }; use rustpython_common::{lock::PyRwLock, static_cell}; diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 3200ac6b6..cfd773529 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -1,27 +1,12 @@ use crate::common::lock::PyRwLockReadGuard; use crate::{ - builtins::{ - builtinfunc::{PyBuiltinFunction, PyBuiltinMethod, PyNativeFuncDef}, - bytes, - getset::{IntoPyGetterFunc, IntoPySetterFunc, PyGetSet}, - object, pystr, - pytype::PyAttributes, - PyBaseException, PyBaseExceptionRef, PyDict, PyDictRef, PyEllipsis, PyFloat, PyFrozenSet, - PyInt, PyIntRef, PyList, PyListRef, PyNone, PyNotImplemented, PyStr, PyTuple, PyTupleRef, - PyType, PyTypeRef, - }, - convert::TryFromObject, - convert::{ToPyObject, ToPyResult}, - exceptions, - function::{IntoFuncArgs, IntoPyNativeFunc}, - intern::{Internable, StringPool}, - pyclass::{PyClassImpl, StaticType}, - types::{PyTypeFlags, PyTypeSlots, TypeZoo}, + builtins::{object, pystr, PyBaseExceptionRef, PyType, PyTypeRef}, + convert::{ToPyObject, ToPyResult, TryFromObject}, + function::IntoFuncArgs, + types::PyTypeFlags, VirtualMachine, _pyobjectrc::{Py, PyObject, PyObjectRef, PyRef}, }; -use num_bigint::BigInt; -use num_traits::ToPrimitive; use std::{any::Any, borrow::Borrow, fmt, ops::Deref}; /* Python objects and references. @@ -55,303 +40,6 @@ impl fmt::Display for PyObject { } } -#[derive(Debug, Clone)] -pub struct PyContext { - pub true_value: PyIntRef, - pub false_value: PyIntRef, - pub none: PyRef, - pub empty_tuple: PyTupleRef, - pub empty_frozenset: PyRef, - pub ellipsis: PyRef, - pub not_implemented: PyRef, - - pub(crate) true_str: PyRef, - pub(crate) false_str: PyRef, - - pub types: TypeZoo, - pub exceptions: exceptions::ExceptionZoo, - pub int_cache_pool: Vec, - // there should only be exact objects of str in here, no non-strs and no subclasses - pub(crate) string_pool: StringPool, - pub(super) slot_new_wrapper: PyObjectRef, -} - -// Basic objects: -impl PyContext { - pub const INT_CACHE_POOL_MIN: i32 = -5; - pub const INT_CACHE_POOL_MAX: i32 = 256; - - fn init() -> Self { - flame_guard!("init PyContext"); - let types = TypeZoo::init(); - let exceptions = exceptions::ExceptionZoo::init(); - - #[inline] - fn create_object(payload: T, cls: &PyTypeRef) -> PyRef { - PyRef::new_ref(payload, cls.clone(), None) - } - - let none = create_object(PyNone, PyNone::static_type()); - let ellipsis = create_object(PyEllipsis, PyEllipsis::static_type()); - let not_implemented = create_object(PyNotImplemented, PyNotImplemented::static_type()); - - let int_cache_pool = (Self::INT_CACHE_POOL_MIN..=Self::INT_CACHE_POOL_MAX) - .map(|v| PyRef::new_ref(PyInt::from(BigInt::from(v)), types.int_type.clone(), None)) - .collect(); - - let true_value = create_object(PyInt::from(1), &types.bool_type); - let false_value = create_object(PyInt::from(0), &types.bool_type); - - let empty_tuple = create_object( - PyTuple::new_unchecked(Vec::new().into_boxed_slice()), - &types.tuple_type, - ); - let empty_frozenset = - PyRef::new_ref(PyFrozenSet::default(), types.frozenset_type.clone(), None); - - let string_pool = StringPool::default(); - - let new_str = unsafe { string_pool.intern("__new__", types.str_type.clone()) }; - let slot_new_wrapper = create_object( - PyNativeFuncDef::new(PyType::__new__.into_func(), new_str.into_pyref()).into_function(), - &types.builtin_function_or_method_type, - ) - .into(); - - let true_str = unsafe { string_pool.intern("True", types.str_type.clone()) }.into_pyref(); - let false_str = unsafe { string_pool.intern("False", types.str_type.clone()) }.into_pyref(); - - let context = PyContext { - true_value, - false_value, - none, - empty_tuple, - empty_frozenset, - ellipsis, - not_implemented, - - true_str, - false_str, - - types, - exceptions, - int_cache_pool, - string_pool, - slot_new_wrapper, - }; - TypeZoo::extend(&context); - exceptions::ExceptionZoo::extend(&context); - context - } - - pub fn intern_string(&self, s: S) -> PyRefExact { - unsafe { self.string_pool.intern(s, self.types.str_type.clone()) } - } - - #[inline(always)] - pub fn none(&self) -> PyObjectRef { - self.none.clone().into() - } - - #[inline(always)] - pub fn ellipsis(&self) -> PyObjectRef { - self.ellipsis.clone().into() - } - - #[inline(always)] - pub fn not_implemented(&self) -> PyObjectRef { - self.not_implemented.clone().into() - } - - // shortcuts for common type - - #[inline] - pub fn new_int + ToPrimitive>(&self, i: T) -> PyIntRef { - if let Some(i) = i.to_i32() { - if i >= Self::INT_CACHE_POOL_MIN && i <= Self::INT_CACHE_POOL_MAX { - let inner_idx = (i - Self::INT_CACHE_POOL_MIN) as usize; - return self.int_cache_pool[inner_idx].clone(); - } - } - PyRef::new_ref(PyInt::from(i), self.types.int_type.clone(), None) - } - - #[inline] - pub fn new_bigint(&self, i: &BigInt) -> PyIntRef { - if let Some(i) = i.to_i32() { - if i >= Self::INT_CACHE_POOL_MIN && i <= Self::INT_CACHE_POOL_MAX { - let inner_idx = (i - Self::INT_CACHE_POOL_MIN) as usize; - return self.int_cache_pool[inner_idx].clone(); - } - } - PyRef::new_ref(PyInt::from(i.clone()), self.types.int_type.clone(), None) - } - - #[inline] - pub fn new_float(&self, value: f64) -> PyRef { - PyRef::new_ref(PyFloat::from(value), self.types.float_type.clone(), None) - } - - #[inline] - pub fn new_str(&self, s: impl Into) -> PyRef { - pystr::PyStr::new_ref(s, self) - } - - #[inline] - pub fn new_bytes(&self, data: Vec) -> PyRef { - bytes::PyBytes::new_ref(data, self) - } - - #[inline(always)] - pub fn new_bool(&self, b: bool) -> PyIntRef { - let value = if b { - &self.true_value - } else { - &self.false_value - }; - value.clone() - } - - #[inline(always)] - pub fn new_tuple(&self, elements: Vec) -> PyTupleRef { - PyTuple::new_ref(elements, self) - } - - #[inline(always)] - pub fn new_list(&self, elements: Vec) -> PyListRef { - PyList::new_ref(elements, self) - } - - #[inline(always)] - pub fn new_dict(&self) -> PyDictRef { - PyDict::new_ref(self) - } - - pub fn new_class( - &self, - module: Option<&str>, - name: &str, - base: &PyTypeRef, - slots: PyTypeSlots, - ) -> PyTypeRef { - let mut attrs = PyAttributes::default(); - if let Some(module) = module { - attrs.insert("__module__".to_string(), self.new_str(module).into()); - }; - PyType::new_ref( - name, - vec![base.clone()], - attrs, - slots, - self.types.type_type.clone(), - ) - .unwrap() - } - - pub fn new_exception_type( - &self, - module: &str, - name: &str, - bases: Option>, - ) -> PyTypeRef { - let bases = if let Some(bases) = bases { - bases - } else { - vec![self.exceptions.exception_type.clone()] - }; - let mut attrs = PyAttributes::default(); - attrs.insert("__module__".to_owned(), self.new_str(module).into()); - - PyType::new_ref( - name, - bases, - attrs, - PyBaseException::make_slots(), - self.types.type_type.clone(), - ) - .unwrap() - } - - #[inline] - pub fn make_funcdef(&self, name: impl Into, f: F) -> PyNativeFuncDef - where - F: IntoPyNativeFunc, - { - PyNativeFuncDef::new(f.into_func(), PyStr::new_ref(name, self)) - } - - // #[deprecated] - pub fn new_function(&self, name: impl Into, f: F) -> PyRef - where - F: IntoPyNativeFunc, - { - self.make_funcdef(name, f).build_function(self) - } - - pub fn new_method( - &self, - name: impl Into, - class: PyTypeRef, - f: F, - ) -> PyRef - where - F: IntoPyNativeFunc, - { - PyBuiltinMethod::new_ref(name, class, f, self) - } - - pub fn new_readonly_getset( - &self, - name: impl Into, - class: PyTypeRef, - f: F, - ) -> PyRef - where - F: IntoPyGetterFunc, - { - PyRef::new_ref( - PyGetSet::new(name.into(), class).with_get(f), - self.types.getset_type.clone(), - None, - ) - } - - pub fn new_getset( - &self, - name: impl Into, - class: PyTypeRef, - g: G, - s: S, - ) -> PyRef - where - G: IntoPyGetterFunc, - S: IntoPySetterFunc, - { - PyRef::new_ref( - PyGetSet::new(name.into(), class).with_get(g).with_set(s), - self.types.getset_type.clone(), - None, - ) - } - - pub fn new_base_object(&self, class: PyTypeRef, dict: Option) -> PyObjectRef { - debug_assert_eq!( - class.slots.flags.contains(PyTypeFlags::HAS_DICT), - dict.is_some() - ); - PyRef::new_ref(object::PyBaseObject, class, dict).into() - } -} - -impl Default for PyContext { - fn default() -> Self { - rustpython_common::static_cell! { - static CONTEXT: PyContext; - } - CONTEXT.get_or_init(Self::init).clone() - } -} - impl fmt::Display for PyRef where T: PyObjectPayload + fmt::Display, diff --git a/vm/src/types/structseq.rs b/vm/src/types/structseq.rs index 375eb27d3..a0f51eb0d 100644 --- a/vm/src/types/structseq.rs +++ b/vm/src/types/structseq.rs @@ -1,7 +1,7 @@ use crate::{ builtins::{PyTuple, PyTupleRef, PyTypeRef}, pyclass::{PyClassImpl, StaticType}, - pyobject::PyContext, + vm::PyContext, AsObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; diff --git a/vm/src/types/zoo.rs b/vm/src/types/zoo.rs index 5ea301470..0431dfb0d 100644 --- a/vm/src/types/zoo.rs +++ b/vm/src/types/zoo.rs @@ -9,7 +9,7 @@ use crate::{ zip, }, pyclass::StaticType, - pyobject::PyContext, + vm::PyContext, }; /// Holder of references to builtin types. diff --git a/vm/src/vm/context.rs b/vm/src/vm/context.rs new file mode 100644 index 000000000..f381292bf --- /dev/null +++ b/vm/src/vm/context.rs @@ -0,0 +1,316 @@ +use crate::{ + builtins::{ + builtinfunc::{PyBuiltinFunction, PyBuiltinMethod, PyNativeFuncDef}, + bytes, + getset::{IntoPyGetterFunc, IntoPySetterFunc, PyGetSet}, + object, pystr, + pytype::PyAttributes, + PyBaseException, PyDict, PyDictRef, PyEllipsis, PyFloat, PyFrozenSet, PyInt, PyIntRef, + PyList, PyListRef, PyNone, PyNotImplemented, PyStr, PyTuple, PyTupleRef, PyType, PyTypeRef, + }, + exceptions, + function::IntoPyNativeFunc, + intern::{Internable, StringPool}, + pyclass::{PyClassImpl, StaticType}, + pyobject::{PyObjectPayload, PyObjectRef, PyPayload, PyRef, PyRefExact}, + types::{PyTypeFlags, PyTypeSlots, TypeZoo}, +}; +use num_bigint::BigInt; +use num_traits::ToPrimitive; + +#[derive(Debug, Clone)] +pub struct PyContext { + pub true_value: PyIntRef, + pub false_value: PyIntRef, + pub none: PyRef, + pub empty_tuple: PyTupleRef, + pub empty_frozenset: PyRef, + pub ellipsis: PyRef, + pub not_implemented: PyRef, + + pub(crate) true_str: PyRef, + pub(crate) false_str: PyRef, + + pub types: TypeZoo, + pub exceptions: exceptions::ExceptionZoo, + pub int_cache_pool: Vec, + // there should only be exact objects of str in here, no non-strs and no subclasses + pub(crate) string_pool: StringPool, + pub(crate) slot_new_wrapper: PyObjectRef, +} + +// Basic objects: +impl PyContext { + pub const INT_CACHE_POOL_MIN: i32 = -5; + pub const INT_CACHE_POOL_MAX: i32 = 256; + + fn init() -> Self { + flame_guard!("init PyContext"); + let types = TypeZoo::init(); + let exceptions = exceptions::ExceptionZoo::init(); + + #[inline] + fn create_object(payload: T, cls: &PyTypeRef) -> PyRef { + PyRef::new_ref(payload, cls.clone(), None) + } + + let none = create_object(PyNone, PyNone::static_type()); + let ellipsis = create_object(PyEllipsis, PyEllipsis::static_type()); + let not_implemented = create_object(PyNotImplemented, PyNotImplemented::static_type()); + + let int_cache_pool = (Self::INT_CACHE_POOL_MIN..=Self::INT_CACHE_POOL_MAX) + .map(|v| PyRef::new_ref(PyInt::from(BigInt::from(v)), types.int_type.clone(), None)) + .collect(); + + let true_value = create_object(PyInt::from(1), &types.bool_type); + let false_value = create_object(PyInt::from(0), &types.bool_type); + + let empty_tuple = create_object( + PyTuple::new_unchecked(Vec::new().into_boxed_slice()), + &types.tuple_type, + ); + let empty_frozenset = + PyRef::new_ref(PyFrozenSet::default(), types.frozenset_type.clone(), None); + + let string_pool = StringPool::default(); + + let new_str = unsafe { string_pool.intern("__new__", types.str_type.clone()) }; + let slot_new_wrapper = create_object( + PyNativeFuncDef::new(PyType::__new__.into_func(), new_str.into_pyref()).into_function(), + &types.builtin_function_or_method_type, + ) + .into(); + + let true_str = unsafe { string_pool.intern("True", types.str_type.clone()) }.into_pyref(); + let false_str = unsafe { string_pool.intern("False", types.str_type.clone()) }.into_pyref(); + + let context = PyContext { + true_value, + false_value, + none, + empty_tuple, + empty_frozenset, + ellipsis, + not_implemented, + + true_str, + false_str, + + types, + exceptions, + int_cache_pool, + string_pool, + slot_new_wrapper, + }; + TypeZoo::extend(&context); + exceptions::ExceptionZoo::extend(&context); + context + } + + pub fn intern_string(&self, s: S) -> PyRefExact { + unsafe { self.string_pool.intern(s, self.types.str_type.clone()) } + } + + #[inline(always)] + pub fn none(&self) -> PyObjectRef { + self.none.clone().into() + } + + #[inline(always)] + pub fn ellipsis(&self) -> PyObjectRef { + self.ellipsis.clone().into() + } + + #[inline(always)] + pub fn not_implemented(&self) -> PyObjectRef { + self.not_implemented.clone().into() + } + + // shortcuts for common type + + #[inline] + pub fn new_int + ToPrimitive>(&self, i: T) -> PyIntRef { + if let Some(i) = i.to_i32() { + if i >= Self::INT_CACHE_POOL_MIN && i <= Self::INT_CACHE_POOL_MAX { + let inner_idx = (i - Self::INT_CACHE_POOL_MIN) as usize; + return self.int_cache_pool[inner_idx].clone(); + } + } + PyRef::new_ref(PyInt::from(i), self.types.int_type.clone(), None) + } + + #[inline] + pub fn new_bigint(&self, i: &BigInt) -> PyIntRef { + if let Some(i) = i.to_i32() { + if i >= Self::INT_CACHE_POOL_MIN && i <= Self::INT_CACHE_POOL_MAX { + let inner_idx = (i - Self::INT_CACHE_POOL_MIN) as usize; + return self.int_cache_pool[inner_idx].clone(); + } + } + PyRef::new_ref(PyInt::from(i.clone()), self.types.int_type.clone(), None) + } + + #[inline] + pub fn new_float(&self, value: f64) -> PyRef { + PyRef::new_ref(PyFloat::from(value), self.types.float_type.clone(), None) + } + + #[inline] + pub fn new_str(&self, s: impl Into) -> PyRef { + pystr::PyStr::new_ref(s, self) + } + + #[inline] + pub fn new_bytes(&self, data: Vec) -> PyRef { + bytes::PyBytes::new_ref(data, self) + } + + #[inline(always)] + pub fn new_bool(&self, b: bool) -> PyIntRef { + let value = if b { + &self.true_value + } else { + &self.false_value + }; + value.clone() + } + + #[inline(always)] + pub fn new_tuple(&self, elements: Vec) -> PyTupleRef { + PyTuple::new_ref(elements, self) + } + + #[inline(always)] + pub fn new_list(&self, elements: Vec) -> PyListRef { + PyList::new_ref(elements, self) + } + + #[inline(always)] + pub fn new_dict(&self) -> PyDictRef { + PyDict::new_ref(self) + } + + pub fn new_class( + &self, + module: Option<&str>, + name: &str, + base: &PyTypeRef, + slots: PyTypeSlots, + ) -> PyTypeRef { + let mut attrs = PyAttributes::default(); + if let Some(module) = module { + attrs.insert("__module__".to_string(), self.new_str(module).into()); + }; + PyType::new_ref( + name, + vec![base.clone()], + attrs, + slots, + self.types.type_type.clone(), + ) + .unwrap() + } + + pub fn new_exception_type( + &self, + module: &str, + name: &str, + bases: Option>, + ) -> PyTypeRef { + let bases = if let Some(bases) = bases { + bases + } else { + vec![self.exceptions.exception_type.clone()] + }; + let mut attrs = PyAttributes::default(); + attrs.insert("__module__".to_owned(), self.new_str(module).into()); + + PyType::new_ref( + name, + bases, + attrs, + PyBaseException::make_slots(), + self.types.type_type.clone(), + ) + .unwrap() + } + + #[inline] + pub fn make_funcdef(&self, name: impl Into, f: F) -> PyNativeFuncDef + where + F: IntoPyNativeFunc, + { + PyNativeFuncDef::new(f.into_func(), PyStr::new_ref(name, self)) + } + + // #[deprecated] + pub fn new_function(&self, name: impl Into, f: F) -> PyRef + where + F: IntoPyNativeFunc, + { + self.make_funcdef(name, f).build_function(self) + } + + pub fn new_method( + &self, + name: impl Into, + class: PyTypeRef, + f: F, + ) -> PyRef + where + F: IntoPyNativeFunc, + { + PyBuiltinMethod::new_ref(name, class, f, self) + } + + pub fn new_readonly_getset( + &self, + name: impl Into, + class: PyTypeRef, + f: F, + ) -> PyRef + where + F: IntoPyGetterFunc, + { + PyRef::new_ref( + PyGetSet::new(name.into(), class).with_get(f), + self.types.getset_type.clone(), + None, + ) + } + + pub fn new_getset( + &self, + name: impl Into, + class: PyTypeRef, + g: G, + s: S, + ) -> PyRef + where + G: IntoPyGetterFunc, + S: IntoPySetterFunc, + { + PyRef::new_ref( + PyGetSet::new(name.into(), class).with_get(g).with_set(s), + self.types.getset_type.clone(), + None, + ) + } + + pub fn new_base_object(&self, class: PyTypeRef, dict: Option) -> PyObjectRef { + debug_assert_eq!( + class.slots.flags.contains(PyTypeFlags::HAS_DICT), + dict.is_some() + ); + PyRef::new_ref(object::PyBaseObject, class, dict).into() + } +} + +impl Default for PyContext { + fn default() -> Self { + rustpython_common::static_cell! { + static CONTEXT: PyContext; + } + CONTEXT.get_or_init(Self::init).clone() + } +} diff --git a/vm/src/vm/mod.rs b/vm/src/vm/mod.rs index 42a6b74c9..28353e374 100644 --- a/vm/src/vm/mod.rs +++ b/vm/src/vm/mod.rs @@ -5,6 +5,7 @@ #[cfg(feature = "rustpython-compiler")] mod compile; +mod context; mod interpreter; mod setting; pub mod thread; @@ -30,7 +31,7 @@ use crate::{ import, protocol::PyIterIter, scope::Scope, - signal, stdlib, AsObject, PyContext, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, + signal, stdlib, AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, }; use crossbeam_utils::atomic::AtomicCell; use std::{ @@ -39,6 +40,7 @@ use std::{ collections::{HashMap, HashSet}, }; +pub use context::PyContext; pub use interpreter::Interpreter; pub use setting::PySettings;