Skip to content

Make PyObject.typ a Rc<PyObject<PyClass>> #1811

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions vm/src/obj/objmemory.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::borrow::Borrow;

use super::objbyteinner::try_as_byte;
use super::objtype::{issubclass, PyClassRef};
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
use crate::pyobject::{
PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
};
use crate::stdlib::array::PyArray;
use crate::vm::VirtualMachine;

Expand All @@ -26,12 +26,12 @@ impl PyMemoryView {
bytes_object: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyMemoryViewRef> {
let object_type = bytes_object.typ.borrow();
let object_type = bytes_object.class();

if issubclass(object_type, &vm.ctx.types.memoryview_type)
|| issubclass(object_type, &vm.ctx.types.bytes_type)
|| issubclass(object_type, &vm.ctx.types.bytearray_type)
|| issubclass(object_type, &PyArray::class(vm))
if issubclass(&object_type, &vm.ctx.types.memoryview_type)
|| issubclass(&object_type, &vm.ctx.types.bytes_type)
|| issubclass(&object_type, &vm.ctx.types.bytearray_type)
|| issubclass(&object_type, &PyArray::class(vm))
{
PyMemoryView {
obj_ref: bytes_object.clone(),
Expand Down
2 changes: 1 addition & 1 deletion vm/src/obj/objtype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ pub fn new(
slots: RefCell::default(),
},
dict: None,
typ,
typ: typ.into_typed_pyobj(),
}
.into_ref();

Expand Down
37 changes: 32 additions & 5 deletions vm/src/pyobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ impl PyContext {

pub fn new_base_object(&self, class: PyClassRef, dict: Option<PyDictRef>) -> PyObjectRef {
PyObject {
typ: class,
typ: class.into_typed_pyobj(),
dict: dict.map(RefCell::new),
payload: objobject::PyBaseObject,
}
Expand Down Expand Up @@ -628,7 +628,7 @@ pub struct PyObject<T>
where
T: ?Sized + PyObjectPayload,
{
pub typ: PyClassRef,
pub typ: Rc<PyObject<PyClass>>,
pub dict: Option<RefCell<PyDictRef>>, // __dict__ member
pub payload: T,
}
Expand All @@ -648,6 +648,21 @@ impl PyObject<dyn PyObjectPayload> {
Err(self)
}
}

/// Downcast this PyObjectRef to an `Rc<PyObject<T>>`. The [`downcast`](#method.downcast) method
/// is generally preferred, as the `PyRef<T>` it returns implements `Deref<Target=T>`, and
/// therefore can be used similarly to an `&T`.
pub fn downcast_generic<T: PyObjectPayload>(
self: Rc<Self>,
) -> Result<Rc<PyObject<T>>, PyObjectRef> {
if self.payload_is::<T>() {
let ptr = Rc::into_raw(self) as *const PyObject<T>;
let ret = unsafe { Rc::from_raw(ptr) };
Ok(ret)
} else {
Err(self)
}
}
}

/// A reference to a Python object.
Expand All @@ -660,6 +675,7 @@ impl PyObject<dyn PyObjectPayload> {
/// situations (such as when implementing in-place methods such as `__iadd__`)
/// where a reference to the same object must be returned.
#[derive(Debug)]
#[repr(transparent)]
pub struct PyRef<T> {
// invariant: this obj must always have payload of type T
obj: PyObjectRef,
Expand Down Expand Up @@ -705,6 +721,10 @@ impl<T: PyValue> PyRef<T> {
pub fn typ(&self) -> PyClassRef {
self.obj.class()
}

pub fn into_typed_pyobj(self) -> Rc<PyObject<T>> {
self.into_object().downcast_generic().unwrap()
}
}

impl<T> Deref for PyRef<T>
Expand Down Expand Up @@ -838,13 +858,13 @@ where
T: ?Sized + PyObjectPayload,
{
fn class(&self) -> PyClassRef {
self.typ.clone()
self.typ.clone().into_pyref()
}
}

impl<T> TypeProtocol for PyRef<T> {
fn class(&self) -> PyClassRef {
self.obj.typ.clone()
self.obj.class()
}
}

Expand Down Expand Up @@ -1103,7 +1123,7 @@ where
#[allow(clippy::new_ret_no_self)]
pub fn new(payload: T, typ: PyClassRef, dict: Option<PyDictRef>) -> PyObjectRef {
PyObject {
typ,
typ: typ.into_typed_pyobj(),
dict: dict.map(RefCell::new),
payload,
}
Expand All @@ -1114,6 +1134,13 @@ where
pub fn into_ref(self) -> PyObjectRef {
Rc::new(self)
}

pub fn into_pyref(self: Rc<Self>) -> PyRef<T>
where
T: PyValue,
{
PyRef::new_ref_unchecked(self as PyObjectRef)
}
}

impl PyObject<dyn PyObjectPayload> {
Expand Down
47 changes: 10 additions & 37 deletions vm/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ use crate::obj::objtype::{self, PyClass, PyClassRef};
use crate::obj::objweakproxy;
use crate::obj::objweakref;
use crate::obj::objzip;
use crate::pyobject::{PyAttributes, PyContext, PyObject, PyObjectPayload};
use crate::pyobject::{PyAttributes, PyContext, PyObject};
use std::cell::RefCell;
use std::mem::{self, MaybeUninit};
use std::mem::MaybeUninit;
use std::ptr;
use std::rc::Rc;

Expand Down Expand Up @@ -312,41 +312,14 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
let type_type_ptr =
Rc::into_raw(type_type.clone()) as *mut MaybeUninit<PyClassObj> as *mut PyClassObj;

// same as std::raw::TraitObject (which is unstable, but accurate)
#[repr(C)]
struct TraitObject {
data: *mut (),
vtable: *mut (),
}

let pyclass_vptr = {
// dummy PyClass
let cls = PyClass {
name: Default::default(),
bases: Default::default(),
mro: Default::default(),
subclasses: Default::default(),
attributes: Default::default(),
slots: Default::default(),
};
// so that we can get the vtable ptr of PyClass for PyObjectPayload
mem::transmute::<_, TraitObject>(&cls as &dyn PyObjectPayload).vtable
};

let write_typ_ptr = |ptr: *mut PyClassObj, type_type: UninitRef<PyClassObj>| {
// turn type_type into a trait object, using the vtable for PyClass we got earlier
let type_type = mem::transmute(TraitObject {
data: mem::transmute(type_type),
vtable: pyclass_vptr,
});
ptr::write(
&mut (*ptr).typ as *mut PyClassRef as *mut MaybeUninit<PyClassRef>,
type_type,
);
};

write_typ_ptr(object_type_ptr, type_type.clone());
write_typ_ptr(type_type_ptr, type_type);
ptr::write(
&mut (*object_type_ptr).typ as *mut Rc<PyClassObj> as *mut UninitRef<PyClassObj>,
type_type.clone(),
);
ptr::write(
&mut (*type_type_ptr).typ as *mut Rc<PyClassObj> as *mut UninitRef<PyClassObj>,
type_type,
);

let type_type = PyClassRef::new_ref_unchecked(Rc::from_raw(type_type_ptr));
let object_type = PyClassRef::new_ref_unchecked(Rc::from_raw(object_type_ptr));
Expand Down