From b27e2deec1cfa9a6e2732d2baf03af71dfa18815 Mon Sep 17 00:00:00 2001 From: snowapril Date: Sun, 16 Jun 2024 15:21:02 +0900 Subject: [PATCH 1/4] Add DISALLOW_INSTANTIATION for TypeFlags Signed-off-by: snowapril --- vm/src/types/slot.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 2d8c825817..3714d246e0 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -122,6 +122,7 @@ bitflags! { #[derive(Copy, Clone, Debug, PartialEq)] #[non_exhaustive] pub struct PyTypeFlags: u64 { + const DISALLOW_INSTANTIATION = 1 << 7; const IMMUTABLETYPE = 1 << 8; const HEAPTYPE = 1 << 9; const BASETYPE = 1 << 10; From e26485817cf6aace21b7836081ff2d97bb7fd5fe Mon Sep 17 00:00:00 2001 From: snowapril Date: Sun, 16 Jun 2024 15:30:38 +0900 Subject: [PATCH 2/4] Set tp_new slot when build heap/static type Signed-off-by: snowapril --- vm/src/builtins/type.rs | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 776c777cb3..b6ad8cf895 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -283,6 +283,8 @@ impl PyType { None, ); + Self::set_new(&new_type.slots, &new_type.base); + let weakref_type = super::PyWeak::static_type(); for base in new_type.bases.read().iter() { base.subclasses.write().push( @@ -302,9 +304,6 @@ impl PyType { for cls in self.mro.read().iter() { for &name in cls.attributes.read().keys() { - if name == identifier!(ctx, __new__) { - continue; - } if name.as_str().starts_with("__") && name.as_str().ends_with("__") { slot_name_set.insert(name); } @@ -318,6 +317,31 @@ impl PyType { for attr_name in slot_name_set { self.update_slot::(attr_name, ctx); } + + Self::set_new(&self.slots, &self.base); + } + + fn set_new(slots: &PyTypeSlots, base: &Option) { + // if self.slots.new.load().is_none() + // && self + // .base + // .as_ref() + // .map(|base| base.class().is(ctx.types.object_type)) + // .unwrap_or(false) + // && self.slots.flags.contains(PyTypeFlags::HEAPTYPE) + // { + // self.slots.flags |= PyTypeFlags::DISALLOW_INSTANTIATION; + // } + + if slots.flags.contains(PyTypeFlags::DISALLOW_INSTANTIATION) { + slots.new.store(None) + } else if slots.new.load().is_none() { + slots.new.store( + base.as_ref() + .map(|base| base.slots.new.load()) + .unwrap_or(None), + ) + } } // This is used for class initialisation where the vm is not yet available. From d992c2bdf783d3eb48daec18ce5f1ae23caf0745 Mon Sep 17 00:00:00 2001 From: snowapril Date: Sun, 16 Jun 2024 15:31:04 +0900 Subject: [PATCH 3/4] Improve type tp_call impl to check tp_new existence and error if not exist Signed-off-by: snowapril --- vm/src/builtins/type.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index b6ad8cf895..9a3c862da6 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -1221,15 +1221,28 @@ impl Callable for PyType { type Args = FuncArgs; fn call(zelf: &Py, args: FuncArgs, vm: &VirtualMachine) -> PyResult { vm_trace!("type_call: {:?}", zelf); - let obj = call_slot_new(zelf.to_owned(), zelf.to_owned(), args.clone(), vm)?; - if (zelf.is(vm.ctx.types.type_type) && args.kwargs.is_empty()) || !obj.fast_isinstance(zelf) - { + if zelf.is(vm.ctx.types.type_type) { + let num_args = args.args.len(); + if num_args == 1 && args.kwargs.is_empty() { + return Ok(args.args[0].obj_type()); + } + if num_args != 3 { + return Err(vm.new_type_error("type() takes 1 or 3 arguments".to_owned())); + } + } + + let obj = if let Some(slot_new) = zelf.slots.new.load() { + slot_new(zelf.to_owned(), args.clone(), vm)? + } else { + return Err(vm.new_type_error(format!("cannot create '{}' instances", zelf.slots.name))); + }; + + if !obj.class().fast_issubclass(zelf) { return Ok(obj); } - let init = obj.class().mro_find_map(|cls| cls.slots.init.load()); - if let Some(init_method) = init { + if let Some(init_method) = obj.class().slots.init.load() { init_method(obj.clone(), args, vm)?; } Ok(obj) From db9f140f2f28ec1069aa388bc1208ad9f1b9d7d6 Mon Sep 17 00:00:00 2001 From: snowapril Date: Sun, 16 Jun 2024 15:33:50 +0900 Subject: [PATCH 4/4] Set DISALLOW_INSTANTIATION flag on several types according to cpython impl Signed-off-by: snowapril --- stdlib/src/array.rs | 2 +- stdlib/src/csv.rs | 4 ++-- stdlib/src/pystruct.rs | 2 +- stdlib/src/unicodedata.rs | 2 +- stdlib/src/zlib.rs | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/stdlib/src/array.rs b/stdlib/src/array.rs index fd83f0a5ad..3c945c9f90 100644 --- a/stdlib/src/array.rs +++ b/stdlib/src/array.rs @@ -1392,7 +1392,7 @@ mod array { internal: PyMutex>, } - #[pyclass(with(IterNext, Iterable), flags(HAS_DICT))] + #[pyclass(with(IterNext, Iterable), flags(HAS_DICT, DISALLOW_INSTANTIATION))] impl PyArrayIter { #[pymethod(magic)] fn setstate(&self, state: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { diff --git a/stdlib/src/csv.rs b/stdlib/src/csv.rs index 214209ab9e..83a0b78be4 100644 --- a/stdlib/src/csv.rs +++ b/stdlib/src/csv.rs @@ -915,7 +915,7 @@ mod _csv { } } - #[pyclass(with(IterNext, Iterable))] + #[pyclass(with(IterNext, Iterable), flags(DISALLOW_INSTANTIATION))] impl Reader { #[pygetset] fn line_num(&self) -> u64 { @@ -1069,7 +1069,7 @@ mod _csv { } } - #[pyclass] + #[pyclass(flags(DISALLOW_INSTANTIATION))] impl Writer { #[pygetset(name = "dialect")] fn get_dialect(&self, _vm: &VirtualMachine) -> PyDialect { diff --git a/stdlib/src/pystruct.rs b/stdlib/src/pystruct.rs index 2c7aa1ebf7..cbcb686869 100644 --- a/stdlib/src/pystruct.rs +++ b/stdlib/src/pystruct.rs @@ -191,7 +191,7 @@ pub(crate) mod _struct { } } - #[pyclass(with(IterNext, Iterable))] + #[pyclass(with(IterNext, Iterable), flags(DISALLOW_INSTANTIATION))] impl UnpackIterator { #[pymethod(magic)] fn length_hint(&self) -> usize { diff --git a/stdlib/src/unicodedata.rs b/stdlib/src/unicodedata.rs index 9af921d360..8eb3da6b46 100644 --- a/stdlib/src/unicodedata.rs +++ b/stdlib/src/unicodedata.rs @@ -107,7 +107,7 @@ mod unicodedata { } } - #[pyclass] + #[pyclass(flags(DISALLOW_INSTANTIATION))] impl Ucd { #[pymethod] fn category(&self, character: PyStrRef, vm: &VirtualMachine) -> PyResult { diff --git a/stdlib/src/zlib.rs b/stdlib/src/zlib.rs index 19ed659bbb..e23a78f69e 100644 --- a/stdlib/src/zlib.rs +++ b/stdlib/src/zlib.rs @@ -343,7 +343,7 @@ mod zlib { inner: PyMutex, } - #[pyclass] + #[pyclass(flags(DISALLOW_INSTANTIATION))] impl PyDecompress { #[pygetset] fn eof(&self) -> bool { @@ -497,7 +497,7 @@ mod zlib { inner: PyMutex, } - #[pyclass] + #[pyclass(flags(DISALLOW_INSTANTIATION))] impl PyCompress { #[pymethod] fn compress(&self, data: ArgBytesLike, vm: &VirtualMachine) -> PyResult> {