From bbc31364bbfcf2d5ca525a622f47d908d1e8790b Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Wed, 18 May 2022 11:40:09 +0900 Subject: [PATCH] PyInterned --- stdlib/src/array.rs | 2 +- vm/src/builtins/bool.rs | 1 - vm/src/builtins/code.rs | 2 +- vm/src/builtins/str.rs | 2 +- vm/src/intern.rs | 154 ++++++++++++++++++++++------------------ vm/src/stdlib/sys.rs | 4 +- vm/src/vm/context.rs | 5 +- 7 files changed, 93 insertions(+), 77 deletions(-) diff --git a/stdlib/src/array.rs b/stdlib/src/array.rs index 6ceef4f20..937dfb2b2 100644 --- a/stdlib/src/array.rs +++ b/stdlib/src/array.rs @@ -683,7 +683,7 @@ mod array { fn typecode(&self, vm: &VirtualMachine) -> PyStrRef { vm.ctx .intern_str(self.read().typecode().to_string()) - .to_str() + .to_owned() } #[pyproperty] diff --git a/vm/src/builtins/bool.rs b/vm/src/builtins/bool.rs index fab3e9cfe..38b20d31b 100644 --- a/vm/src/builtins/bool.rs +++ b/vm/src/builtins/bool.rs @@ -117,7 +117,6 @@ impl PyBool { vm.ctx.false_str } .to_owned() - .into_pyref() } #[pymethod(magic)] diff --git a/vm/src/builtins/code.rs b/vm/src/builtins/code.rs index c0f216f13..d9205982e 100644 --- a/vm/src/builtins/code.rs +++ b/vm/src/builtins/code.rs @@ -104,7 +104,7 @@ impl ConstantBag for PyObjBag<'_> { } fn make_name(&self, name: &str) -> PyStrRef { - self.0.intern_str(name).to_str() + self.0.intern_str(name).to_owned() } } diff --git a/vm/src/builtins/str.rs b/vm/src/builtins/str.rs index 40f610c45..151a1f1d3 100644 --- a/vm/src/builtins/str.rs +++ b/vm/src/builtins/str.rs @@ -230,7 +230,7 @@ impl IntoPyStrRef for &str { impl IntoPyStrRef for &'static crate::intern::PyStrInterned { #[inline] fn into_pystr_ref(self, _vm: &VirtualMachine) -> PyRef { - self.to_str() + self.to_owned() } } diff --git a/vm/src/intern.rs b/vm/src/intern.rs index 74c192cf6..817871a19 100644 --- a/vm/src/intern.rs +++ b/vm/src/intern.rs @@ -2,7 +2,7 @@ use crate::{ builtins::{PyStr, PyTypeRef}, common::lock::PyRwLock, convert::ToPyObject, - AsObject, Py, PyExact, PyObject, PyObjectRef, PyRef, PyRefExact, + AsObject, Py, PyExact, PyObject, PyObjectRef, PyPayload, PyRef, PyRefExact, VirtualMachine, }; use std::{ borrow::{Borrow, ToOwned}, @@ -113,11 +113,84 @@ impl CachedPyStrRef { } } +pub struct PyInterned +where + T: PyPayload, +{ + inner: Py, +} + +impl PyInterned { + #[inline] + pub fn leak(cache: PyRef) -> &'static Self { + unsafe { std::mem::transmute(cache) } + } + + #[inline] + fn as_ptr(&self) -> *const Py { + self as *const _ as *const _ + } + + #[inline] + pub fn to_owned(&'static self) -> PyRef { + unsafe { (*(&self as *const _ as *const PyRef)).clone() } + } + + #[inline] + pub fn to_object(&'static self) -> PyObjectRef { + self.to_owned().into() + } +} + +impl Borrow for PyInterned { + #[inline(always)] + fn borrow(&self) -> &PyObject { + self.inner.borrow() + } +} + +// NOTE: std::hash::Hash of Self and Self::Borrowed *must* be the same +// This is ok only because PyObject doesn't implement Hash +impl std::hash::Hash for PyInterned { + #[inline(always)] + fn hash(&self, state: &mut H) { + self.get_id().hash(state) + } +} + +impl Deref for PyInterned { + type Target = Py; + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl PartialEq for PyInterned { + #[inline(always)] + fn eq(&self, other: &Self) -> bool { + std::ptr::eq(self, other) + } +} + +impl Eq for PyInterned {} + +impl std::fmt::Debug for PyInterned { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Debug::fmt(&**self, f)?; + write!(f, "@{:p}", self.as_ptr()) + } +} + +impl ToPyObject for &'static PyInterned { + fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef { + self.to_owned().into() + } +} + /// The unique reference of interned PyStr /// Always intended to be used as a static reference -pub struct PyStrInterned { - inner: Py, -} +pub type PyStrInterned = PyInterned; impl PyStrInterned { /// # Safety @@ -128,70 +201,8 @@ impl PyStrInterned { } #[inline] - fn as_ptr(&self) -> *const Py { - self as *const _ as *const _ - } - - #[inline] - pub fn to_owned(&'static self) -> PyRefExact { - unsafe { (*(&self as *const _ as *const PyRefExact)).clone() } - } - - #[inline] - pub fn to_str(&'static self) -> PyRef { - self.to_owned().into_pyref() - } - - #[inline] - pub fn to_object(&'static self) -> PyObjectRef { - self.to_str().into() - } -} - -impl Borrow for PyStrInterned { - #[inline(always)] - fn borrow(&self) -> &PyObject { - self.inner.borrow() - } -} - -// NOTE: std::hash::Hash of Self and Self::Borrowed *must* be the same -// This is ok only because PyObject doesn't implement Hash -impl std::hash::Hash for PyStrInterned { - #[inline(always)] - fn hash(&self, state: &mut H) { - self.get_id().hash(state) - } -} - -impl Deref for PyStrInterned { - type Target = Py; - #[inline(always)] - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl PartialEq for PyStrInterned { - #[inline(always)] - fn eq(&self, other: &Self) -> bool { - std::ptr::eq(self, other) - } -} - -impl Eq for PyStrInterned {} - -impl AsRef for PyStrInterned { - #[inline(always)] - fn as_ref(&self) -> &str { - self.as_str() - } -} - -impl std::fmt::Debug for PyStrInterned { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Debug::fmt(self.as_str(), f)?; - write!(f, "@{:p}", self.as_ptr()) + pub fn to_exact(&'static self) -> PyRefExact { + unsafe { PyRefExact::new_unchecked(self.to_owned()) } } } @@ -201,6 +212,13 @@ impl std::fmt::Display for PyStrInterned { } } +impl AsRef for PyStrInterned { + #[inline(always)] + fn as_ref(&self) -> &str { + self.as_str() + } +} + mod sealed { use crate::{ builtins::PyStr, diff --git a/vm/src/stdlib/sys.rs b/vm/src/stdlib/sys.rs index c94df5e68..d21229dfe 100644 --- a/vm/src/stdlib/sys.rs +++ b/vm/src/stdlib/sys.rs @@ -132,7 +132,7 @@ mod sys { } else { "unknown" }) - .to_str() + .to_owned() } #[pyattr] @@ -513,7 +513,7 @@ mod sys { #[pyfunction] fn intern(s: PyRefExact, vm: &VirtualMachine) -> PyRefExact { - vm.ctx.intern_str(s).to_owned() + vm.ctx.intern_str(s).to_exact() } #[pyattr] diff --git a/vm/src/vm/context.rs b/vm/src/vm/context.rs index 747a8fa57..c4ec499a4 100644 --- a/vm/src/vm/context.rs +++ b/vm/src/vm/context.rs @@ -80,15 +80,14 @@ impl Context { 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.to_owned().into_pyref()) - .into_function(), + PyNativeFuncDef::new(PyType::__new__.into_func(), new_str.to_owned()).into_function(), &types.builtin_function_or_method_type, ) .into(); let true_str = unsafe { string_pool.intern("True", types.str_type.clone()) }; let false_str = unsafe { string_pool.intern("False", types.str_type.clone()) }; - let empty_str = unsafe { string_pool.intern("", types.str_type.clone()) }.to_str(); + let empty_str = unsafe { string_pool.intern("", types.str_type.clone()) }.to_owned(); let context = Context { true_value,