Objective-C Interop Extensions

Nicholas Wilson iamthewilsonator at hotmail.com
Sat Nov 16 22:47:09 UTC 2024


On Saturday, 16 November 2024 at 22:29:36 UTC, Luna wrote:
> ## Proposal
>
> Currently DLang has, in some compilers, support for ObjectiveC 
> types being declared. However, modern Objective-C code is 
> strongly dependent on autorelease and auto release pools.
> Without them Objective-C code leaks memory (see: 
> https://developer.apple.com/documentation/quartzcore/cametallayer?language=objc).
>
> To alleviate this, clang implements the concept of an 
> `@autoreleasepool` block, this block frees all Objective-C 
> classes which have called `autorelease`. In the case of Metal, 
> for example, a lot of internal data uses autorelease calls.
>
> The `@autoreleasepool` blocks in clang are implemented via 2 
> helper functions declared in the objective-c runtime 
> `libobjc.dylib` or the like in alternate runtime 
> implementations.
> ```d
> extern(C) extern void* objc_autoreleasePoolPush();
> extern(C) extern void  objc_autoreleasePoolPop(void*);
> ```
>
> My proposal is to add 2 new hooks to the D runtime emitted by 
> the compiler as well as a new keyword, `autoreleasepool`. This 
> keyword should be followed by a block.
>
> The runtime hooks should have a default implementation which do 
> nothing.
> ```d
> void* _d_pool_enter() { return null; }
> void  _d_pool_leave(void*) { }
> ```
>
> Whenever an `autoreleasepool` block is encountered by the 
> compiler, the following code should be emitted.
> ```d
> // Note: __ctx_ptr is just a placeholder, the name of the 
> variable should be unique.
> void* __ctx_ptr = _d_pool_enter();
>
> // Code goes here
>
> _d_pool_leave(__ctx_ptr);
> ```
>
> autorelease pools should additionally, on macOS, automatically 
> be generated in the runtime entry point and wrap the user D 
> main function, and threads created in D should also include 
> pool enter and leave calls.
>
> If the D compiler links to a library defining 
> `objc_autoreleasePoolPush` and `objc_autoreleasePoolPop`, the D 
> runtime hooks should link against those, instead.
>
> ## Why not use NSAutoreleasePool?
>
> The `Foundation` library includes a class called 
> NSAutoreleasePool, however i've found that if Objective-C's 
> runtime is compiled with ARC (Automatic Reference Counting) 
> support, then NSAutoreleasePool becomes no-op in some 
> instances, which in turn causes memory leaks.

This would be easy to do, synchronised works in pretty much the 
exact same way, but why does this need to be a compiler thing? 
i.e. what does it offer that

     ```d
     struct AutoreleasePool
     {
         private void* __p;
         static AutoreleasePool opCall()
         {
             AutoreleasePool ret;
             ret.__p = objc_autoreleasePoolPush();
             return ret;
         }
         ~this () { objc_autoreleasePoolPop(__p); }
     }

     void main()
     {
         auto x = AutoreleasePool();
     }
     ```
does not?

I think I saw some of your code that used a scope delegate as 
`autorelease((){ ... });` why is that not sufficient?

Given how niche this is, there had better be a very good reason 
for adding it, e.g. generality with regular D code, not just 
Obj-C.


More information about the dip.ideas mailing list