Skip to content

Commit

Permalink
WIP: Work on magic nop instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Mar 1, 2022
1 parent 8a3542f commit 608d251
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 2 deletions.
1 change: 1 addition & 0 deletions objc2/benches/autorelease.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ macro_rules! main_with_warmup {
)+
}

// Needed to get DYLD to resolve the stubs
fn warmup() {
$(
warmup_fns::$f();
Expand Down
74 changes: 72 additions & 2 deletions objc2/src/rc/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,12 +274,82 @@ impl<T: Message, O: Ownership> Id<T, O> {

/// TODO
#[doc(alias = "objc_retainAutoreleasedReturnValue")]
// This relies heavily on being inlined right after `objc_msgSend`.
#[inline(always)]
pub unsafe fn retain_autoreleased(ptr: NonNull<T>) -> Id<T, O> {
// SAFETY: Same as `retain`, `objc_retainAutoreleasedReturnValue` is
// just an optimization.
// Not supported on TARGET_OS_WIN32
#[cfg(all(apple, not(target_os = "windows")))]
{
// Add magic nop instruction to participate in the fast
// autorelease scheme.
//
// We will unconditionally emit these instructions, even if they
// end up being unused (for example because we're unlucky with
// inlining, some other work is done between the objc_msgSend and
// this, or the runtime version is too old to support it).
//
// See `callerAcceptsOptimizedReturn` in `objc-object.h`:
// https://github.com/apple-oss-distributions/objc4/blob/objc4-838/runtime/objc-object.h#L1209-L1377
// and this StackOverflow answer for some background on why the
// design is like it is: https://stackoverflow.com/a/23765612.
//
// It may seem like there should be a better way to do this, but
// emitting raw assembly is exactly what Clang and Swift does:
// swiftc: https://github.com/apple/swift/blob/swift-5.5.3-RELEASE/lib/IRGen/GenObjC.cpp#L148-L173
// Clang: https://github.com/llvm/llvm-project/blob/889317d47b7f046cf0e68746da8f7f264582fb5b/clang/lib/CodeGen/CGObjC.cpp#L2339-L2373
//
// SAFETY:
// Based on https://doc.rust-lang.org/stable/reference/inline-assembly.html#rules-for-inline-assembly
//
// We don't care about the value of the register (so it's okay to
// be undefined), and its value is preserved.
//
// nomem: No reads or writes to memory are performed (this `mov`
// operates entirely on registers).
// preserves_flags: `mov` doesn't modify any flags.
// nostack: We don't touch the stack.

// Supported since macOS 10.7.
#[cfg(target_arch = "x86_64")]
{} // x86_64 looks at the next call instruction

// Supported since macOS 10.8.
#[cfg(target_arch = "arm")]
unsafe {
core::arch::asm!("mov r7, r7", options(nomem, preserves_flags, nostack))
};

// Supported since macOS 10.10.
#[cfg(target_arch = "aarch64")]
unsafe {
core::arch::asm!("mov fp, fp", options(nomem, preserves_flags, nostack))
};

// Supported since macOS 10.12.
#[cfg(target_arch = "x86")]
unsafe {
core::arch::asm!("mov ebp, ebp", options(nomem, preserves_flags, nostack))
};
}

let ptr = ptr.as_ptr() as *mut objc_sys::objc_object;

// objc_autoreleaseReturnValue / objc_retainAutoreleasedReturnValue:

// #![feature(asm_sym)]
// #[cfg(target_arch = "x86_64")]
// unsafe {
// core::arch::asm!(
// "mov rdi, rax",
// "call {}",
// sym objc2::ffi::objc_retainAutoreleasedReturnValue,
// inout("rax") obj,
// clobber_abi("C"),
// );
// }

// SAFETY: Same as `retain`, `objc_retainAutoreleasedReturnValue` is
// just an optimization.
let res = unsafe { objc_sys::objc_retainAutoreleasedReturnValue(ptr) };
debug_assert_eq!(
res, ptr,
Expand Down

0 comments on commit 608d251

Please sign in to comment.