Skip to content
This repository was archived by the owner on Jun 8, 2021. It is now read-only.

Don't store subclass impl/private data in an Option<T> #589

Merged
merged 3 commits into from
Feb 13, 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
11 changes: 11 additions & 0 deletions src/subclass/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,17 @@ mod test {
assert!(weak.upgrade().is_none());
}

#[test]
fn test_create_child_object() {
let type_ = ChildObject::get_type();
let obj = Object::new(type_, &[]).unwrap();

// ChildObject is a zero-sized type and we map that to the same pointer as the object
// itself. No private/impl data is allocated for zero-sized types.
let imp = ChildObject::from_instance(&obj);
assert_eq!(imp as *const _ as *const (), obj.as_ptr() as *const _);
}

#[test]
fn test_set_properties() {
let obj = Object::new(SimpleObject::get_type(), &[]).unwrap();
Expand Down
37 changes: 24 additions & 13 deletions src/subclass/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ pub unsafe trait InstanceStruct: Sized + 'static {
let private_offset = data.as_ref().private_offset;
let ptr: *const u8 = self as *const _ as *const u8;
let priv_ptr = ptr.offset(private_offset);
let imp = priv_ptr as *const Option<Self::Type>;
let imp = priv_ptr as *const Self::Type;

(*imp).as_ref().expect("No private struct")
&*imp
}
}

Expand Down Expand Up @@ -377,7 +377,7 @@ unsafe extern "C" fn class_init<T: ObjectSubclass>(

// We have to update the private struct offset once the class is actually
// being initialized.
{
if mem::size_of::<T>() != 0 {
let mut private_offset = data.as_ref().private_offset as i32;
gobject_sys::g_type_class_adjust_private_offset(klass, &mut private_offset);
(*data.as_mut()).private_offset = private_offset as isize;
Expand Down Expand Up @@ -417,26 +417,23 @@ unsafe extern "C" fn instance_init<T: ObjectSubclass>(
let private_offset = (*data.as_mut()).private_offset;
let ptr: *mut u8 = obj as *mut _ as *mut u8;
let priv_ptr = ptr.offset(private_offset);
let imp_storage = priv_ptr as *mut Option<T>;
let imp_storage = priv_ptr as *mut T;

let klass = &*(klass as *const T::Class);

let imp = T::new_with_class(klass);

ptr::write(imp_storage, Some(imp));
ptr::write(imp_storage, imp);
}

unsafe extern "C" fn finalize<T: ObjectSubclass>(obj: *mut gobject_sys::GObject) {
// Retrieve the private struct, take it out of its storage and
// drop it for freeing all associated memory.
// Retrieve the private struct and drop it for freeing all associated memory.
let mut data = T::type_data();
let private_offset = (*data.as_mut()).private_offset;
let ptr: *mut u8 = obj as *mut _ as *mut u8;
let priv_ptr = ptr.offset(private_offset);
let imp_storage = priv_ptr as *mut Option<T>;

let imp = (*imp_storage).take().expect("No private struct");
drop(imp);
let imp_storage = priv_ptr as *mut T;
ptr::drop_in_place(imp_storage);

// Chain up to the parent class' finalize implementation, if any.
let parent_class = &*(data.as_ref().get_parent_class() as *const gobject_sys::GObjectClass);
Expand All @@ -457,6 +454,16 @@ pub fn register_type<T: ObjectSubclass>() -> Type
where
<<T as ObjectSubclass>::ParentType as ObjectType>::RustClassType: IsSubclassable<T>,
{
// GLib aligns the type private data to two gsizes so we can't safely store any type there that
// requires a bigger alignment.
if mem::align_of::<T>() > 2 * mem::size_of::<usize>() {
panic!(
"Alignment {} of type not supported, bigger than {}",
mem::align_of::<T>(),
2 * mem::size_of::<usize>(),
);
}

unsafe {
use std::ffi::CString;

Expand Down Expand Up @@ -494,8 +501,12 @@ where

let mut data = T::type_data();
(*data.as_mut()).type_ = type_;
let private_offset =
gobject_sys::g_type_add_instance_private(type_.to_glib(), mem::size_of::<Option<T>>());

let private_offset = if mem::size_of::<T>() == 0 {
0
} else {
gobject_sys::g_type_add_instance_private(type_.to_glib(), mem::size_of::<T>())
};
(*data.as_mut()).private_offset = private_offset as isize;

T::type_init(&mut InitializingType::<T>(type_, marker::PhantomData));
Expand Down