From 07f898e4f0ddd60f0e6af79fec45ec4b45a0e9b2 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 20 Sep 2020 07:57:57 +0900 Subject: [PATCH] tuple internal to Box<[PyObjectRef]> it will use 16bytes instead of 24bytes --- derive/src/pystructseq.rs | 2 +- vm/src/obj/objtuple.rs | 31 +++++++++++++++++-------------- vm/src/obj/objtype.rs | 2 +- vm/src/pyobject.rs | 5 ++++- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/derive/src/pystructseq.rs b/derive/src/pystructseq.rs index ff624afd7..357c9af36 100644 --- a/derive/src/pystructseq.rs +++ b/derive/src/pystructseq.rs @@ -36,7 +36,7 @@ pub(crate) fn impl_pystruct_sequence( self.#field_names, vm, )),*]; - unsafe { ::rustpython_vm::obj::objtuple::PyTuple::_new(items) } + items.into_boxed_slice().into() } } }; diff --git a/vm/src/obj/objtuple.rs b/vm/src/obj/objtuple.rs index 329b2ab19..7a114d646 100644 --- a/vm/src/obj/objtuple.rs +++ b/vm/src/obj/objtuple.rs @@ -6,9 +6,8 @@ use super::objsequence::get_item; use super::objtype::PyClassRef; use crate::function::OptionalArg; use crate::pyobject::{ - self, BorrowValue, Either, IdProtocol, IntoPyObject, - PyArithmaticValue::{self, *}, - PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, + self, BorrowValue, Either, IdProtocol, IntoPyObject, PyArithmaticValue, PyClassImpl, + PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, }; use crate::sequence::{self, SimpleSeq}; use crate::slots::{Comparable, Hashable, PyComparisonOp}; @@ -21,7 +20,7 @@ use rustpython_common::hash::PyHash; /// If the argument is a tuple, the return value is the same object. #[pyclass(module = false, name = "tuple")] pub struct PyTuple { - elements: Vec, + elements: Box<[PyObjectRef]>, } impl fmt::Debug for PyTuple { @@ -31,6 +30,12 @@ impl fmt::Debug for PyTuple { } } +impl From> for PyTuple { + fn from(elements: Box<[PyObjectRef]>) -> Self { + PyTuple { elements } + } +} + impl<'a> BorrowValue<'a> for PyTuple { type Borrowed = &'a [PyObjectRef]; @@ -64,12 +69,6 @@ impl_intopyobj_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5)); impl_intopyobj_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5), (G, 6)); impl PyTuple { - // this is designed to be only used to skip empty tuple optimization - // not unsafe as meaning of rust, but a warning because this is performance critical - pub(crate) unsafe fn _new(elements: Vec) -> Self { - Self { elements } - } - pub(crate) fn fast_getitem(&self, idx: usize) -> PyObjectRef { self.elements[idx].clone() } @@ -82,6 +81,7 @@ impl PyTupleRef { if elements.is_empty() { ctx.empty_tuple.clone() } else { + let elements = elements.into_boxed_slice(); Self::new_ref(PyTuple { elements }, ctx.types.tuple_type.clone(), None) } } @@ -110,7 +110,8 @@ impl PyTuple { .boxed_iter() .chain(other.borrow_value().boxed_iter()) .cloned() - .collect::>(); + .collect::>() + .into_boxed_slice(); Self { elements }.into_ref(vm) } }); @@ -172,9 +173,10 @@ impl PyTuple { if self.elements.is_empty() || counter == 0 { vm.ctx.empty_tuple.clone() } else { - let elements: Vec<_> = sequence::seq_mul(&self.elements, counter) + let elements = sequence::seq_mul(&self.elements, counter) .cloned() - .collect(); + .collect::>() + .into_boxed_slice(); Self { elements }.into_ref(vm) } } @@ -227,7 +229,8 @@ impl PyTuple { vm.extract_elements(&iterable)? } else { vec![] - }; + } + .into_boxed_slice(); Self { elements }.into_ref_with_type(vm, cls) } diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index abcb159e0..8d1601807 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -184,7 +184,7 @@ impl PyClass { #[pyproperty(name = "__mro__")] fn get_mro(zelf: PyRef) -> PyTuple { let elements: Vec = zelf.iter_mro().map(|x| x.as_object().clone()).collect(); - unsafe { PyTuple::_new(elements) } + elements.into_boxed_slice().into() } #[pyproperty(magic)] diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 2090a90db..16826cddd 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -139,7 +139,10 @@ impl PyContext { 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(unsafe { PyTuple::_new(Vec::new()) }, &types.tuple_type); + let empty_tuple = create_object( + PyTuple::from(Vec::new().into_boxed_slice()), + &types.tuple_type, + ); let tp_new_wrapper = create_object( PyFuncDef::from(objtype::tp_new_wrapper.into_func()).into_function(),