@@ -216,6 +216,9 @@ impl<T: Message, O: Ownership> Id<T, O> {
216216 /// some API, and you would like to ensure that the object stays around
217217 /// so that you can work with it.
218218 ///
219+ /// If said API is a normal Objective-C method, you probably want to use
220+ /// [`Id::retain_autoreleased`] instead.
221+ ///
219222 /// This is rarely used to construct owned [`Id`]s, see [`Id::new`] for
220223 /// that.
221224 ///
@@ -272,29 +275,49 @@ impl<T: Message, O: Ownership> Id<T, O> {
272275 NonNull :: new ( ptr) . map ( |ptr| unsafe { Id :: retain ( ptr) } )
273276 }
274277
275- /// TODO
278+ /// Retains a previously autoreleased object pointer.
279+ ///
280+ /// This is useful when calling Objective-C methods that return
281+ /// autoreleaed objects, see [Cocoa's Memory Management Policy][mmRules].
282+ ///
283+ /// This has exactly the same semantics as [`Id::retain`], except it can
284+ /// sometimes avoid putting the object into the autorelease pool, possibly
285+ /// yielding increased speed and reducing memory pressure.
286+ ///
287+ /// Note: This relies heavily on being inlined right after [`msg_send!`],
288+ /// be careful not accidentally require instructions between these.
289+ ///
290+ /// [mmRules]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
291+ ///
292+ /// # Safety
293+ ///
294+ /// Same as [`Id::retain`].
276295 #[ doc( alias = "objc_retainAutoreleasedReturnValue" ) ]
277- // This relies heavily on being inlined right after `objc_msgSend`.
278296 #[ inline( always) ]
279297 pub unsafe fn retain_autoreleased ( ptr : NonNull < T > ) -> Id < T , O > {
280298 // Add magic nop instruction to participate in the fast autorelease
281299 // scheme.
282300 //
301+ // See `callerAcceptsOptimizedReturn` in `objc-object.h`:
302+ // https://github.com/apple-oss-distributions/objc4/blob/objc4-838/runtime/objc-object.h#L1209-L1377
303+ //
283304 // We will unconditionally emit these instructions, even if they end
284305 // up being unused (for example because we're unlucky with inlining,
285306 // some other work is done between the objc_msgSend and this, or the
286307 // runtime version is too old to support it).
287308 //
288- // See `callerAcceptsOptimizedReturn` in `objc-object.h`:
289- // https://github.com/apple-oss-distributions/objc4/blob/objc4-838/runtime/objc-object.h#L1209-L1377
290- // and this StackOverflow answer for some background on why the design
291- // is like it is: https://stackoverflow.com/a/23765612.
292- //
293309 // It may seem like there should be a better way to do this, but
294310 // emitting raw assembly is exactly what Clang and Swift does:
295311 // swiftc: https://github.com/apple/swift/blob/swift-5.5.3-RELEASE/lib/IRGen/GenObjC.cpp#L148-L173
296312 // Clang: https://github.com/llvm/llvm-project/blob/889317d47b7f046cf0e68746da8f7f264582fb5b/clang/lib/CodeGen/CGObjC.cpp#L2339-L2373
297313 //
314+ // Resources:
315+ // - https://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.html
316+ // - https://www.galloway.me.uk/2012/02/how-does-objc_retainautoreleasedreturnvalue-work/
317+ // - https://github.com/gfx-rs/metal-rs/issues/222
318+ // - https://news.ycombinator.com/item?id=29311736
319+ // - https://stackoverflow.com/a/23765612
320+ //
298321 // SAFETY:
299322 // Based on https://doc.rust-lang.org/stable/reference/inline-assembly.html#rules-for-inline-assembly
300323 //
0 commit comments