11//!
22//! See:
33//! - https://github.com/apple/swift-corelibs-libdispatch/tree/main/src/BlocksRuntime
4+ //! - https://github.com/apple/swift-corelibs-foundation/tree/main/Sources/BlocksRuntime
45//! - https://clang.llvm.org/docs/BlockLanguageSpec.html
56//! - https://clang.llvm.org/docs/Block-ABI-Apple.html
67
@@ -14,6 +15,7 @@ extern crate objc2_sys;
1415use core:: cell:: UnsafeCell ;
1516use core:: ffi:: c_void;
1617use core:: marker:: { PhantomData , PhantomPinned } ;
18+ use std:: os:: raw:: { c_char, c_ulong} ;
1719
1820#[ repr( C ) ]
1921pub struct Class {
@@ -28,6 +30,127 @@ pub struct Class {
2830 _opaque : PhantomData < ( UnsafeCell < * const ( ) > , PhantomPinned ) > ,
2931}
3032
33+ /// Block descriptor flags.
34+ /// Values for Block_layout->flags to describe block objects
35+ #[ allow( non_camel_case_types) ]
36+ pub type block_flags = i32 ;
37+
38+ #[ cfg( feature = "apple" ) ]
39+ pub const BLOCK_DEALLOCATING : block_flags = 0x0001 ;
40+
41+ /// Mask for the reference count in byref structure's flags field. The low
42+ /// 3 bytes are reserved for the reference count, the top byte for the flags.
43+ #[ cfg( feature = "gnustep-1-7" ) ]
44+ pub const BLOCK_REFCOUNT_MASK : block_flags = 0x00ffffff ;
45+ #[ cfg( any( feature = "compiler-rt" , feature = "objfw" ) ) ]
46+ pub const BLOCK_REFCOUNT_MASK : block_flags = 0xffff ;
47+ #[ cfg( feature = "apple" ) ]
48+ /// runtime
49+ pub const BLOCK_REFCOUNT_MASK : block_flags = 0xfffe ;
50+
51+ #[ cfg( feature = "apple" ) ]
52+ /// compiler
53+ pub const BLOCK_INLINE_LAYOUT_STRING : block_flags = 1 << 21 ;
54+
55+ #[ cfg( feature = "apple" ) ]
56+ /// compiler
57+ pub const BLOCK_SMALL_DESCRIPTOR : block_flags = 1 << 22 ;
58+
59+ #[ cfg( feature = "apple" ) ] // Part of ABI?
60+ /// compiler
61+ pub const BLOCK_IS_NOESCAPE : block_flags = 1 << 23 ;
62+
63+ #[ cfg( feature = "apple" ) ]
64+ /// runtime
65+ pub const BLOCK_NEEDS_FREE : block_flags = 1 << 24 ;
66+
67+ /// The block descriptor contains copy and dispose helpers.
68+ /// compiler
69+ pub const BLOCK_HAS_COPY_DISPOSE : block_flags = 1 << 25 ;
70+
71+ /// The helpers have C++ code.
72+ /// compiler: helpers have C++ code
73+ pub const BLOCK_HAS_CTOR : block_flags = 1 << 26 ;
74+
75+ #[ cfg( feature = "apple" ) ]
76+ /// compiler
77+ pub const BLOCK_IS_GC : block_flags = 1 << 27 ;
78+
79+ /// Block is stored in global memory and does not need to be copied.
80+ /// compiler
81+ pub const BLOCK_IS_GLOBAL : block_flags = 1 << 28 ;
82+
83+ /// Block function uses a calling convention that returns a structure via a
84+ /// pointer passed in by the caller.
85+ ///
86+ /// match (BLOCK_USE_STRET, BLOCK_HAS_SIGNATURE) {
87+ /// (false, false) => 10.6.ABI, no signature field available
88+ /// (true, false) => 10.6.ABI, no signature field available
89+ /// (false, true) => ABI.2010.3.16, regular calling convention, presence of signature field
90+ /// (true, true) => ABI.2010.3.16, stret calling convention, presence of signature field,
91+ /// }
92+ ///
93+ /// See https://clang.llvm.org/docs/Block-ABI-Apple.html#high-level
94+ #[ doc( alias = "BLOCK_USE_SRET" ) ]
95+ #[ doc( alias = "BLOCK_HAS_DESCRIPTOR" ) ] // compiler-rt || macOS 10.6
96+ pub const BLOCK_USE_STRET : block_flags = 1 << 29 ;
97+
98+ /// Block has an Objective-C type encoding.
99+ /// compiler
100+ pub const BLOCK_HAS_SIGNATURE : block_flags = 1 << 30 ;
101+
102+ #[ cfg( feature = "apple" ) ]
103+ /// compiler
104+ pub const BLOCK_HAS_EXTENDED_LAYOUT : block_flags = 1 << 31 ;
105+
106+ /// Flags used in the final argument to _Block_object_assign() and
107+ /// _Block_object_dispose(). These indicate the type of copy or dispose to
108+ /// perform.
109+ /// Values for _Block_object_assign() and _Block_object_dispose() parameters
110+ ///
111+ /// This is a helper type, in the sources this type does not have a name!
112+ #[ allow( non_camel_case_types) ]
113+ pub type block_assign_dispose_flags = i32 ;
114+
115+ /// The value is of some id-like type, and should be copied as an Objective-C
116+ /// object: i.e. by sending -retain or via the GC assign functions in GC mode
117+ /// (not yet supported).
118+ ///
119+ /// id, NSObject, __attribute__((NSObject)), block, ...
120+ pub const BLOCK_FIELD_IS_OBJECT : block_assign_dispose_flags = 3 ;
121+
122+ /// The field is a block. This must be copied by the block copy functions.
123+ ///
124+ /// a block variable
125+ pub const BLOCK_FIELD_IS_BLOCK : block_assign_dispose_flags = 7 ;
126+
127+ /// The field is an indirect reference to a variable declared with the __block
128+ /// storage qualifier.
129+ ///
130+ /// the on stack structure holding the __block variable
131+ pub const BLOCK_FIELD_IS_BYREF : block_assign_dispose_flags = 8 ;
132+
133+ /// The field is an indirect reference to a variable declared with the __block
134+ /// storage qualifier.
135+ ///
136+ /// declared __weak, only used in byref copy helpers
137+ pub const BLOCK_FIELD_IS_WEAK : block_assign_dispose_flags = 16 ;
138+
139+ /// The field is an indirect reference to a variable declared with the __block
140+ /// storage qualifier.
141+ ///
142+ /// called from __block (byref) copy/dispose support routines.
143+ pub const BLOCK_BYREF_CALLER : block_assign_dispose_flags = 128 ;
144+
145+ #[ cfg( feature = "apple" ) ]
146+ pub const BLOCK_ALL_COPY_DISPOSE_FLAGS : block_assign_dispose_flags = BLOCK_FIELD_IS_OBJECT
147+ | BLOCK_FIELD_IS_BLOCK
148+ | BLOCK_FIELD_IS_BYREF
149+ | BLOCK_FIELD_IS_WEAK
150+ | BLOCK_BYREF_CALLER ;
151+
152+ // TODO: BLOCK_LAYOUT_X
153+
31154extern "C" {
32155 // the raw data space for runtime classes for blocks
33156 // class+meta used for stack, malloc, and collectable based blocks
@@ -41,9 +164,219 @@ extern "C" {
41164
42165 /// Runtime entry point called by compiler when assigning objects inside
43166 /// copy helper routines
44- pub fn _Block_object_assign ( dest_addr : * mut c_void , object : * const c_void , flags : i32 ) ;
167+ pub fn _Block_object_assign (
168+ dest_addr : * mut c_void ,
169+ object : * const c_void ,
170+ flags : block_assign_dispose_flags ,
171+ ) ;
45172
46173 /// runtime entry point called by the compiler when disposing of objects
47174 /// inside dispose helper routine
48- pub fn _Block_object_dispose ( object : * const c_void , flags : i32 ) ;
175+ pub fn _Block_object_dispose ( object : * const c_void , flags : block_assign_dispose_flags ) ;
176+ }
177+
178+ #[ cfg( feature = "apple" ) ]
179+ extern "C" {
180+ // Whether the return value of the block is on the stack.
181+ // macOS 10.7
182+ // pub fn _Block_use_stret(block: *mut c_void) -> bool;
183+
184+ // Returns a string describing the block's GC layout.
185+ // This uses the GC skip/scan encoding.
186+ // May return NULL.
187+ // macOS 10.7
188+ // pub fn _Block_layout(block: *mut c_void) -> *const c_char;
189+
190+ // Returns a string describing the block's layout.
191+ // This uses the "extended layout" form described above.
192+ // May return NULL.
193+ // macOS 10.8
194+ // pub fn _Block_extended_layout(block: *mut c_void) -> *const c_char;
195+
196+ // Callable only from the ARR weak subsystem while in exclusion zone
197+ // macOS 10.7
198+ // pub fn _Block_tryRetain(block: *const c_void) -> bool;
199+
200+ // Callable only from the ARR weak subsystem while in exclusion zone
201+ // macOS 10.7
202+ // pub fn _Block_isDeallocating(block: *const c_void) -> bool;
203+ }
204+
205+ #[ cfg( any( feature = "apple" , feature = "compiler-rt" ) ) ]
206+ extern "C" {
207+ // the raw data space for runtime classes for blocks
208+ // class+meta used for stack, malloc, and collectable based blocks
209+
210+ pub static _NSConcreteAutoBlock: Class ;
211+ pub static _NSConcreteFinalizingBlock: Class ;
212+ pub static _NSConcreteWeakBlockVariable: Class ;
213+
214+ pub fn Block_size ( block : * mut c_void ) -> c_ulong ; // usize
215+ }
216+
217+ #[ cfg( any( feature = "apple" , feature = "gnustep-1-7" ) ) ]
218+ extern "C" {
219+ // indicates whether block was compiled with compiler that sets the ABI
220+ // related metadata bits
221+ // macOS 10.7
222+ // pub fn _Block_has_signature(block: *mut c_void) -> bool;
223+
224+ // Returns a string describing the block's parameter and return types.
225+ // The encoding scheme is the same as Objective-C @encode.
226+ // Returns NULL for blocks compiled with some compilers.
227+ // macOS 10.7
228+ // pub fn _Block_signature(block: *mut c_void) -> *const c_char;
229+ }
230+
231+ #[ repr( C ) ]
232+ pub struct Block_layout {
233+ /// Class pointer. Always initialised to &_NSConcreteStackBlock for blocks
234+ /// that are created on the stack or &_NSConcreteGlobalBlock for blocks
235+ /// that are created in global storage.
236+ pub isa : * mut Class ,
237+ /// Flags.
238+ /// See the `block_flags` enumerated type for possible values.
239+ /// Contains ref count in Apple and ObjFW.
240+ pub flags : block_flags ,
241+ /// Reserved - always initialised to 0 by the compiler (but this is not
242+ /// said in the specification).
243+ ///
244+ /// Used for the reference count in GNUStep and WinObjC.
245+ pub reserved : i32 ,
246+ /// The function that implements the block. The first argument is this
247+ /// structure, the subsequent arguments are the block's explicit
248+ /// parameters. If the BLOCK_USE_SRET & BLOCK_HAS_SIGNATURE flag is set,
249+ /// there is an additional hidden argument, which is a pointer to the
250+ /// space on the stack allocated to hold the return value.
251+ pub invoke : Option < unsafe extern "C" fn ( block : * mut Block_layout , ...) > ,
252+ /// The block's descriptor. The actual type of this is:
253+ /// ```ignore
254+ /// match (BLOCK_HAS_COPY_DISPOSE, BLOCK_HAS_SIGNATURE) {
255+ /// (false, false) => Block_descriptor_header,
256+ /// (true, false) => Block_descriptor,
257+ /// (false, true) => Block_descriptor_basic,
258+ /// (true, true) => Block_descriptor_with_signature,
259+ /// }
260+ /// ```
261+ ///
262+ /// But it is safe to access this through just `Block_descriptor_header`.
263+ pub descriptor : * mut Block_descriptor_header ,
264+ }
265+
266+ #[ repr( C ) ]
267+ pub struct Block_descriptor_header {
268+ /// Reserved for future use. Currently always 0.
269+ pub reserved : c_ulong , // usize
270+ /// Size of the block.
271+ pub size : c_ulong , // usize
272+ }
273+
274+ /// Block descriptor that contains copy and dispose operations.
275+ ///
276+ /// Requires BLOCK_HAS_COPY_DISPOSE
277+ #[ repr( C ) ]
278+ pub struct Block_descriptor {
279+ pub header : Block_descriptor_header ,
280+ /// Copy function, generated by the compiler to help copy the block if it
281+ /// contains nontrivial copy operations.
282+ pub copy : Option < unsafe extern "C" fn ( dst : * mut Block_byref , src : * mut Block_byref ) > ,
283+ /// Dispose function, generated by the compiler to help copy the block if
284+ /// it contains nontrivial destructors.
285+ pub dispose : Option < unsafe extern "C" fn ( src : * mut Block_byref ) > ,
286+ }
287+
288+ /// Extended block descriptor that does not contain copy and dispose helper
289+ /// functions.
290+ ///
291+ /// Requires BLOCK_HAS_SIGNATURE
292+ #[ repr( C ) ]
293+ #[ cfg( not( feature = "objfw" ) ) ]
294+ pub struct Block_descriptor_basic {
295+ pub header : Block_descriptor_header ,
296+
297+ /// Objective-C type encoding of the block.
298+ #[ doc( alias = "signature" ) ]
299+ pub encoding : * const c_char ,
300+ }
301+
302+ /// Requires BLOCK_HAS_COPY_DISPOSE and BLOCK_HAS_SIGNATURE
303+ #[ repr( C ) ]
304+ pub struct Block_descriptor_with_signature {
305+ pub inner : Block_descriptor ,
306+
307+ /// Objective-C type encoding of the block.
308+ #[ doc( alias = "signature" ) ]
309+ pub encoding : * const c_char ,
310+ }
311+
312+ // #[cfg(feature = "apple")]
313+ // pub layout: *const c_char,
314+
315+ // #[repr(C)]
316+ // pub struct Block_descriptor_small {
317+ // pub size: u32,
318+ // pub signature: i32,
319+ // pub layout: i32,
320+ // pub copy: i32,
321+ // pub dispose: i32,
322+ // }
323+
324+ // #[repr(C)]
325+ // pub struct Block_basic {
326+ // pub isa: *mut c_void,
327+ // pub Block_flags: i32,
328+ // pub Block_size: i32,
329+ // pub Block_invoke: Option<unsafe extern "C" fn(block: *mut c_void)>,
330+ // pub Block_copy: Option<unsafe extern "C" fn(dst: *mut c_void, src: *mut c_void)>,
331+ // pub Block_dispose: Option<unsafe extern "C" fn(block: *mut c_void)>,
332+ // }
333+ // Example usage: https://opensource.apple.com/source/libdispatch/libdispatch-84.5/src/once.c.auto.html
334+
335+ /// Structure used for on-stack variables that are referenced by blocks.
336+ #[ repr( C ) ]
337+ #[ doc( alias = "Block_byref_1" ) ]
338+ pub struct Block_byref_header {
339+ /// Class pointer. Currently unused on GNUStep and always NULL. Could be
340+ /// used in the future to support introspection.
341+ pub isa : * mut c_void ,
342+ /// The pointer to the structure that contains the real version of the
343+ /// data. All accesses go via this pointer. If an on-stack byref structure
344+ /// is copied to the heap, then its forwarding pointer should point to the
345+ /// heap version. Otherwise it should point to itself.
346+ pub forwarding : * mut Block_byref_header ,
347+ /// Flags and reference count.
348+ ///
349+ /// TODO: Volatile!
350+ pub flags : block_flags ,
351+ #[ cfg( feature = "apple" ) ]
352+ /// Size of this structure.
353+ pub size : u32 ,
354+ #[ cfg( not( feature = "apple" ) ) ]
355+ /// Size of this structure.
356+ pub size : i32 ,
357+ }
358+
359+ /// Structure used for on-stack variables that are referenced by blocks.
360+ ///
361+ /// requires BLOCK_BYREF_HAS_COPY_DISPOSE
362+ #[ repr( C ) ]
363+ #[ doc( alias = "Block_byref_2" ) ]
364+ pub struct Block_byref {
365+ pub header : Block_byref_header ,
366+ /// Copy function.
367+ pub keep :
368+ Option < unsafe extern "C" fn ( dst : * mut Block_byref_header , src : * mut Block_byref_header ) > ,
369+ /// Dispose function.
370+ pub destroy : Option < unsafe extern "C" fn ( src : * mut Block_byref_header ) > ,
371+ }
372+
373+ #[ cfg( feature = "apple" ) ]
374+ /// Structure used for on-stack variables that are referenced by blocks.
375+ ///
376+ /// requires BLOCK_BYREF_LAYOUT_EXTENDED
377+ #[ repr( C ) ]
378+ #[ doc( alias = "Block_byref_3" ) ]
379+ pub struct Block_byref_extended {
380+ pub inner : Block_byref ,
381+ pub layout : * const c_char ,
49382}
0 commit comments