Skip to content

Commit

Permalink
Add Id::writeback
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Oct 6, 2022
1 parent 59c01f8 commit 0ae96b5
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 3 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ resolver = "2"
inherits = "release"
# Enable LTO to allow testing the `unstable-static-sel-inlined` feature
lto = true
# Disable generation of code to handle unwinds.
panic = "abort"
21 changes: 19 additions & 2 deletions objc2/src/rc/id.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use core::fmt;
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use core::mem::{self, ManuallyDrop};
use core::ops::{Deref, DerefMut};
use core::panic::{RefUnwindSafe, UnwindSafe};
use core::ptr::NonNull;
use core::ptr::{self, NonNull};

use super::AutoreleasePool;
use super::{Owned, Ownership, Shared};
Expand Down Expand Up @@ -522,6 +522,23 @@ impl<T: Message, O: Ownership> Id<T, O> {
);
res
}

/// TODO
// https://clang.llvm.org/docs/AutomaticReferenceCounting.html#passing-to-an-out-parameter-by-writeback
#[inline]
pub unsafe fn writeback<R, F>(this: &mut Option<Self>, f: F) -> R
where
F: FnOnce(&mut *mut T) -> R,
{
let mut ptr = match this {
Some(this) => this.ptr.as_ptr(),
None => ptr::null_mut(),
};
let res = f(&mut ptr);
let old = mem::replace(this, unsafe { Self::retain(ptr) });
drop(old);
res
}
}

// TODO: Consider something like this
Expand Down
25 changes: 25 additions & 0 deletions test-assembly/crates/test_out_parameters/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "test_out_parameters"
version = "0.1.0"
edition = "2021"
publish = false

[lib]
path = "lib.rs"

[dependencies]
objc2 = { path = "../../../objc2", default-features = false }

[features]
default = ["apple", "std"]
std = ["objc2/std"]
# Runtime
apple = ["objc2/apple"]
gnustep-1-7 = ["objc2/gnustep-1-7"]
gnustep-1-8 = ["gnustep-1-7", "objc2/gnustep-1-8"]
gnustep-1-9 = ["gnustep-1-8", "objc2/gnustep-1-9"]
gnustep-2-0 = ["gnustep-1-9", "objc2/gnustep-2-0"]
gnustep-2-1 = ["gnustep-2-0", "objc2/gnustep-2-1"]

# Hack
assembly-features = []
82 changes: 82 additions & 0 deletions test-assembly/crates/test_out_parameters/expected/apple-x86_64.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
.section __TEXT,__text,regular,pure_instructions
.intel_syntax noprefix
.globl _null
.p2align 4, 0x90
_null:
push rbp
mov rbp, rsp
push rbx
push rax
mov qword ptr [rbp - 16], 0
lea rdx, [rbp - 16]
call _objc_msgSend
mov rbx, rax
mov rdi, qword ptr [rbp - 16]
call _objc_retain
mov rdx, rax
mov rax, rbx
add rsp, 8
pop rbx
pop rbp
ret

.globl _nonnull
.p2align 4, 0x90
_nonnull:
push rbp
mov rbp, rsp
push r15
push r14
push rbx
push rax
mov rbx, rdx
mov qword ptr [rbp - 32], rdx
lea rdx, [rbp - 32]
call _objc_msgSend
mov r14, rax
mov rdi, qword ptr [rbp - 32]
call _objc_retain
mov r15, rax
mov rdi, rbx
call _objc_release
mov rax, r14
mov rdx, r15
add rsp, 8
pop rbx
pop r14
pop r15
pop rbp
ret

.globl _generic
.p2align 4, 0x90
_generic:
push rbp
mov rbp, rsp
push r15
push r14
push rbx
push rax
mov rbx, rdx
mov qword ptr [rbp - 32], rdx
lea rdx, [rbp - 32]
call _objc_msgSend
mov r14, rax
mov rdi, qword ptr [rbp - 32]
call _objc_retain
mov r15, rax
test rbx, rbx
je LBB2_2
mov rdi, rbx
call _objc_release
LBB2_2:
mov rax, r14
mov rdx, r15
add rsp, 8
pop rbx
pop r14
pop r15
pop rbp
ret

.subsections_via_symbols
35 changes: 35 additions & 0 deletions test-assembly/crates/test_out_parameters/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//! Test that Id::writeback does the correct thing.
//!
//! Note that without `panic = "abort"`, this generates a lot more code to
//! ensure that if the message send panics, the `param` (whether it has been
//! overwritten yet or not) is still released.
use objc2::ffi::NSInteger;
use objc2::rc::{Id, Owned};
use objc2::runtime::{Object, Sel};
use objc2::MessageReceiver;

unsafe fn handle(obj: &Object, sel: Sel, param: &mut *mut Object) -> NSInteger {
MessageReceiver::send_message(obj, sel, (param,))
}

type Res = (NSInteger, Option<Id<Object, Owned>>);

#[no_mangle]
unsafe fn null(obj: &Object, sel: Sel) -> Res {
let mut param = None;
let res = Id::writeback(&mut param, |param| handle(obj, sel, param));
(res, param)
}

#[no_mangle]
unsafe fn nonnull(obj: &Object, sel: Sel, param: Id<Object, Owned>) -> Res {
let mut param = Some(param);
let res = Id::writeback(&mut param, |param| handle(obj, sel, param));
(res, param)
}

#[no_mangle]
unsafe fn generic(obj: &Object, sel: Sel, mut param: Option<Id<Object, Owned>>) -> Res {
let res = Id::writeback(&mut param, |param| handle(obj, sel, param));
(res, param)
}
7 changes: 6 additions & 1 deletion test-assembly/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ fn demangle_assembly(assembly: &str) -> String {
//
// Example: test_msg_send_static_sel[f7bb0e08e35403f3]::handle_with_sel::NAME_DATA
// Becomes: test_msg_send_static_sel[CRATE_ID]::handle_with_sel::NAME_DATA
static ref RE_CRATE_ID: Regex = Regex::new(r"\[.*\]").unwrap();
static ref RE_CRATE_ID: Regex = Regex::new(r"\[.*?\]").unwrap();

// Replace last part of symbol if it looks to be autogenerated
//
Expand Down Expand Up @@ -347,5 +347,10 @@ l_anon.[ID].0:
"#;
let output = demangle_assembly(before);
assert_eq!(output, after, "Got {}", output);

let before = r#"__RINvNtCshB9ITk7tvJd_4core3ptr13drop_in_placeINtNtB4_6option6OptionINtNtNtCsaWDm3USgSkM_5objc22rc2id2IdNtNtB19_7runtime6ObjectNtNtB17_9ownership6SharedEEECs8tAMaYSsbuV_19test_out_parameters:"#;
let after = r#"SYM(core[CRATE_ID]::ptr::drop_in_place::<core[CRATE_ID]::option::Option<objc2[CRATE_ID]::rc::id::Id<objc2[CRATE_ID]::runtime::Object, objc2[CRATE_ID]::rc::ownership::Shared>>>, 0):"#;
let output = demangle_assembly(before);
assert_eq!(output, after, "Got {}", output);
}
}

0 comments on commit 0ae96b5

Please sign in to comment.