1cc9a6355SApple OSS Distributions /*
2cc9a6355SApple OSS Distributions * runtime.c
3cc9a6355SApple OSS Distributions * libclosure
4cc9a6355SApple OSS Distributions *
5cc9a6355SApple OSS Distributions * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
6cc9a6355SApple OSS Distributions *
7cc9a6355SApple OSS Distributions * @APPLE_LLVM_LICENSE_HEADER@
8cc9a6355SApple OSS Distributions */
9cc9a6355SApple OSS Distributions
10cc9a6355SApple OSS Distributions
11cc9a6355SApple OSS Distributions #ifndef KERNEL
12cc9a6355SApple OSS Distributions
13cc9a6355SApple OSS Distributions #include "Block_private.h"
14cc9a6355SApple OSS Distributions #include <stdio.h>
15cc9a6355SApple OSS Distributions #include <stdlib.h>
16cc9a6355SApple OSS Distributions #include <dlfcn.h>
17cc9a6355SApple OSS Distributions #include <os/assumes.h>
18e6231be0SApple OSS Distributions #include <TargetConditionals.h>
19cc9a6355SApple OSS Distributions
20cc9a6355SApple OSS Distributions #else /* !KERNEL */
21bb611c8fSApple OSS Distributions #define TARGET_OS_WIN32 0
22cc9a6355SApple OSS Distributions
23cc9a6355SApple OSS Distributions #include <libkern/Block_private.h>
24bb611c8fSApple OSS Distributions __BEGIN_DECLS
25bb611c8fSApple OSS Distributions #include <kern/kalloc.h>
26bb611c8fSApple OSS Distributions __END_DECLS
27cc9a6355SApple OSS Distributions
28*aca3beaaSApple OSS Distributions /* void * is a bit of a lie, but that will have to do */
29*aca3beaaSApple OSS Distributions KALLOC_TYPE_VAR_DEFINE(KT_BLOCK_LAYOUT, struct Block_layout, void *, KT_DEFAULT);
30*aca3beaaSApple OSS Distributions KALLOC_TYPE_VAR_DEFINE(KT_BLOCK_BYREF, struct Block_byref, void *, KT_DEFAULT);
315c2921b0SApple OSS Distributions
32*aca3beaaSApple OSS Distributions static inline struct Block_layout *
block_layout_alloc(size_t size)33*aca3beaaSApple OSS Distributions block_layout_alloc(size_t size)
34bb611c8fSApple OSS Distributions {
35*aca3beaaSApple OSS Distributions return (struct Block_layout *)kalloc_type_var_impl(KT_BLOCK_LAYOUT,
36*aca3beaaSApple OSS Distributions size, Z_WAITOK_ZERO_NOFAIL, NULL);
37bb611c8fSApple OSS Distributions }
38bb611c8fSApple OSS Distributions
39bb611c8fSApple OSS Distributions static inline void
block_layout_free(Block_layout * ptr,size_t size)40*aca3beaaSApple OSS Distributions block_layout_free(Block_layout *ptr, size_t size)
41bb611c8fSApple OSS Distributions {
42*aca3beaaSApple OSS Distributions kfree_type_var_impl(KT_BLOCK_LAYOUT, ptr, size);
43bb611c8fSApple OSS Distributions }
44cc9a6355SApple OSS Distributions
45*aca3beaaSApple OSS Distributions static inline struct Block_byref *
block_byref_alloc(size_t size)46*aca3beaaSApple OSS Distributions block_byref_alloc(size_t size)
47*aca3beaaSApple OSS Distributions {
48*aca3beaaSApple OSS Distributions return (struct Block_byref *)kalloc_type_var_impl(KT_BLOCK_BYREF,
49*aca3beaaSApple OSS Distributions size, Z_WAITOK_ZERO_NOFAIL, NULL);
50*aca3beaaSApple OSS Distributions }
51*aca3beaaSApple OSS Distributions
52*aca3beaaSApple OSS Distributions static inline void
block_byref_free(Block_byref * ptr,size_t size)53*aca3beaaSApple OSS Distributions block_byref_free(Block_byref *ptr, size_t size)
54*aca3beaaSApple OSS Distributions {
55*aca3beaaSApple OSS Distributions kfree_type_var_impl(KT_BLOCK_BYREF, ptr, size);
56*aca3beaaSApple OSS Distributions }
575c2921b0SApple OSS Distributions
58cc9a6355SApple OSS Distributions #endif /* KERNEL */
59cc9a6355SApple OSS Distributions
60a5e72196SApple OSS Distributions #include <machine/atomic.h>
61cc9a6355SApple OSS Distributions #include <string.h>
62cc9a6355SApple OSS Distributions #include <stdint.h>
63cc9a6355SApple OSS Distributions #ifndef os_assumes
64cc9a6355SApple OSS Distributions #define os_assumes(_x) (_x)
65cc9a6355SApple OSS Distributions #endif
66cc9a6355SApple OSS Distributions #ifndef os_assert
67cc9a6355SApple OSS Distributions #define os_assert(_x) assert(_x)
68cc9a6355SApple OSS Distributions #endif
69cc9a6355SApple OSS Distributions
70cc9a6355SApple OSS Distributions #if TARGET_OS_WIN32
71cc9a6355SApple OSS Distributions #define _CRT_SECURE_NO_WARNINGS 1
72cc9a6355SApple OSS Distributions #include <windows.h>
73a5e72196SApple OSS Distributions static __inline bool
OSAtomicCompareAndSwapLong(long oldl,long newl,long volatile * dst)74a5e72196SApple OSS Distributions OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst)
75cc9a6355SApple OSS Distributions {
76cc9a6355SApple OSS Distributions // fixme barrier is overkill -- see objc-os.h
77cc9a6355SApple OSS Distributions long original = InterlockedCompareExchange(dst, newl, oldl);
78a5e72196SApple OSS Distributions return original == oldl;
79cc9a6355SApple OSS Distributions }
80cc9a6355SApple OSS Distributions
81a5e72196SApple OSS Distributions static __inline bool
OSAtomicCompareAndSwapInt(int oldi,int newi,int volatile * dst)82a5e72196SApple OSS Distributions OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile *dst)
83cc9a6355SApple OSS Distributions {
84cc9a6355SApple OSS Distributions // fixme barrier is overkill -- see objc-os.h
85cc9a6355SApple OSS Distributions int original = InterlockedCompareExchange(dst, newi, oldi);
86a5e72196SApple OSS Distributions return original == oldi;
87cc9a6355SApple OSS Distributions }
88cc9a6355SApple OSS Distributions #else
89a5e72196SApple OSS Distributions #define OSAtomicCompareAndSwapLong(_Old, _New, _Ptr) os_atomic_cmpxchg(_Ptr, _Old, _New, relaxed)
90a5e72196SApple OSS Distributions #define OSAtomicCompareAndSwapInt(_Old, _New, _Ptr) os_atomic_cmpxchg(_Ptr, _Old, _New, relaxed)
91cc9a6355SApple OSS Distributions #endif
92cc9a6355SApple OSS Distributions
93cc9a6355SApple OSS Distributions
94cc9a6355SApple OSS Distributions /*******************************************************************************
95a5e72196SApple OSS Distributions * Internal Utilities
96cc9a6355SApple OSS Distributions ********************************************************************************/
97cc9a6355SApple OSS Distributions
98a5e72196SApple OSS Distributions static int32_t
latching_incr_int(volatile int32_t * where)99a5e72196SApple OSS Distributions latching_incr_int(volatile int32_t *where)
100a5e72196SApple OSS Distributions {
101cc9a6355SApple OSS Distributions while (1) {
102cc9a6355SApple OSS Distributions int32_t old_value = *where;
103cc9a6355SApple OSS Distributions if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
104cc9a6355SApple OSS Distributions return BLOCK_REFCOUNT_MASK;
105cc9a6355SApple OSS Distributions }
106cc9a6355SApple OSS Distributions if (OSAtomicCompareAndSwapInt(old_value, old_value + 2, where)) {
107cc9a6355SApple OSS Distributions return old_value + 2;
108cc9a6355SApple OSS Distributions }
109cc9a6355SApple OSS Distributions }
110cc9a6355SApple OSS Distributions }
111cc9a6355SApple OSS Distributions
112a5e72196SApple OSS Distributions static bool
latching_incr_int_not_deallocating(volatile int32_t * where)113a5e72196SApple OSS Distributions latching_incr_int_not_deallocating(volatile int32_t *where)
114a5e72196SApple OSS Distributions {
115cc9a6355SApple OSS Distributions while (1) {
116cc9a6355SApple OSS Distributions int32_t old_value = *where;
117cc9a6355SApple OSS Distributions if (old_value & BLOCK_DEALLOCATING) {
118cc9a6355SApple OSS Distributions // if deallocating we can't do this
119cc9a6355SApple OSS Distributions return false;
120cc9a6355SApple OSS Distributions }
121cc9a6355SApple OSS Distributions if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
122cc9a6355SApple OSS Distributions // if latched, we're leaking this block, and we succeed
123cc9a6355SApple OSS Distributions return true;
124cc9a6355SApple OSS Distributions }
125cc9a6355SApple OSS Distributions if (OSAtomicCompareAndSwapInt(old_value, old_value + 2, where)) {
126cc9a6355SApple OSS Distributions // otherwise, we must store a new retained value without the deallocating bit set
127cc9a6355SApple OSS Distributions return true;
128cc9a6355SApple OSS Distributions }
129cc9a6355SApple OSS Distributions }
130cc9a6355SApple OSS Distributions }
131cc9a6355SApple OSS Distributions
132cc9a6355SApple OSS Distributions
133cc9a6355SApple OSS Distributions // return should_deallocate?
134a5e72196SApple OSS Distributions static bool
latching_decr_int_should_deallocate(volatile int32_t * where)135a5e72196SApple OSS Distributions latching_decr_int_should_deallocate(volatile int32_t *where)
136a5e72196SApple OSS Distributions {
137cc9a6355SApple OSS Distributions while (1) {
138cc9a6355SApple OSS Distributions int32_t old_value = *where;
139cc9a6355SApple OSS Distributions if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
140cc9a6355SApple OSS Distributions return false; // latched high
141cc9a6355SApple OSS Distributions }
142cc9a6355SApple OSS Distributions if ((old_value & BLOCK_REFCOUNT_MASK) == 0) {
143cc9a6355SApple OSS Distributions return false; // underflow, latch low
144cc9a6355SApple OSS Distributions }
145cc9a6355SApple OSS Distributions int32_t new_value = old_value - 2;
146cc9a6355SApple OSS Distributions bool result = false;
147cc9a6355SApple OSS Distributions if ((old_value & (BLOCK_REFCOUNT_MASK | BLOCK_DEALLOCATING)) == 2) {
148cc9a6355SApple OSS Distributions new_value = old_value - 1;
149cc9a6355SApple OSS Distributions result = true;
150cc9a6355SApple OSS Distributions }
151cc9a6355SApple OSS Distributions if (OSAtomicCompareAndSwapInt(old_value, new_value, where)) {
152cc9a6355SApple OSS Distributions return result;
153cc9a6355SApple OSS Distributions }
154cc9a6355SApple OSS Distributions }
155cc9a6355SApple OSS Distributions }
156cc9a6355SApple OSS Distributions
157cc9a6355SApple OSS Distributions
158cc9a6355SApple OSS Distributions /**************************************************************************
159a5e72196SApple OSS Distributions * Framework callback functions and their default implementations.
160cc9a6355SApple OSS Distributions ***************************************************************************/
161cc9a6355SApple OSS Distributions #if !TARGET_OS_WIN32
162cc9a6355SApple OSS Distributions #pragma mark Framework Callback Routines
163cc9a6355SApple OSS Distributions #endif
164bb611c8fSApple OSS Distributions #if KERNEL
165bb611c8fSApple OSS Distributions static inline void
_Block_retain_object(const void * ptr __unused)166bb611c8fSApple OSS Distributions _Block_retain_object(const void *ptr __unused)
167bb611c8fSApple OSS Distributions {
168bb611c8fSApple OSS Distributions }
169bb611c8fSApple OSS Distributions
170bb611c8fSApple OSS Distributions static inline void
_Block_release_object(const void * ptr __unused)171bb611c8fSApple OSS Distributions _Block_release_object(const void *ptr __unused)
172bb611c8fSApple OSS Distributions {
173bb611c8fSApple OSS Distributions }
174bb611c8fSApple OSS Distributions
175bb611c8fSApple OSS Distributions static inline void
_Block_destructInstance(const void * aBlock __unused)176bb611c8fSApple OSS Distributions _Block_destructInstance(const void *aBlock __unused)
177bb611c8fSApple OSS Distributions {
178bb611c8fSApple OSS Distributions }
179bb611c8fSApple OSS Distributions
180bb611c8fSApple OSS Distributions #else
181cc9a6355SApple OSS Distributions
182a5e72196SApple OSS Distributions static void
_Block_retain_object_default(const void * ptr __unused)183a5e72196SApple OSS Distributions _Block_retain_object_default(const void *ptr __unused)
184a5e72196SApple OSS Distributions {
185a5e72196SApple OSS Distributions }
186cc9a6355SApple OSS Distributions
187a5e72196SApple OSS Distributions static void
_Block_release_object_default(const void * ptr __unused)188a5e72196SApple OSS Distributions _Block_release_object_default(const void *ptr __unused)
189a5e72196SApple OSS Distributions {
190a5e72196SApple OSS Distributions }
191cc9a6355SApple OSS Distributions
192a5e72196SApple OSS Distributions static void
_Block_destructInstance_default(const void * aBlock __unused)193a5e72196SApple OSS Distributions _Block_destructInstance_default(const void *aBlock __unused)
194a5e72196SApple OSS Distributions {
195a5e72196SApple OSS Distributions }
196cc9a6355SApple OSS Distributions
197cc9a6355SApple OSS Distributions static void (*_Block_retain_object)(const void *ptr) = _Block_retain_object_default;
198cc9a6355SApple OSS Distributions static void (*_Block_release_object)(const void *ptr) = _Block_release_object_default;
199cc9a6355SApple OSS Distributions static void (*_Block_destructInstance) (const void *aBlock) = _Block_destructInstance_default;
200cc9a6355SApple OSS Distributions
201cc9a6355SApple OSS Distributions
202cc9a6355SApple OSS Distributions /**************************************************************************
203a5e72196SApple OSS Distributions * Callback registration from ObjC runtime and CoreFoundation
204cc9a6355SApple OSS Distributions ***************************************************************************/
205cc9a6355SApple OSS Distributions
206a5e72196SApple OSS Distributions void
_Block_use_RR2(const Block_callbacks_RR * callbacks)207a5e72196SApple OSS Distributions _Block_use_RR2(const Block_callbacks_RR *callbacks)
208a5e72196SApple OSS Distributions {
209cc9a6355SApple OSS Distributions _Block_retain_object = callbacks->retain;
210cc9a6355SApple OSS Distributions _Block_release_object = callbacks->release;
211cc9a6355SApple OSS Distributions _Block_destructInstance = callbacks->destructInstance;
212cc9a6355SApple OSS Distributions }
213bb611c8fSApple OSS Distributions #endif // !KERNEL
214cc9a6355SApple OSS Distributions
215cc9a6355SApple OSS Distributions /****************************************************************************
216a5e72196SApple OSS Distributions * Accessors for block descriptor fields
217cc9a6355SApple OSS Distributions *****************************************************************************/
218cc9a6355SApple OSS Distributions
2195c2921b0SApple OSS Distributions #if BLOCK_SMALL_DESCRIPTOR_SUPPORTED
220bb611c8fSApple OSS Distributions template <class T>
221bb611c8fSApple OSS Distributions static T *
unwrap_relative_pointer(int32_t & offset)222bb611c8fSApple OSS Distributions unwrap_relative_pointer(int32_t &offset)
223bb611c8fSApple OSS Distributions {
224bb611c8fSApple OSS Distributions if (offset == 0) {
225bb611c8fSApple OSS Distributions return nullptr;
226bb611c8fSApple OSS Distributions }
227bb611c8fSApple OSS Distributions
228bb611c8fSApple OSS Distributions uintptr_t base = (uintptr_t)&offset;
229bb611c8fSApple OSS Distributions uintptr_t extendedOffset = (uintptr_t)(intptr_t)offset;
230bb611c8fSApple OSS Distributions uintptr_t pointer = base + extendedOffset;
231bb611c8fSApple OSS Distributions return (T *)pointer;
232bb611c8fSApple OSS Distributions }
2335c2921b0SApple OSS Distributions #endif
234bb611c8fSApple OSS Distributions
235bb611c8fSApple OSS Distributions #if 0
236a5e72196SApple OSS Distributions static struct Block_descriptor_2 *
237a5e72196SApple OSS Distributions _Block_descriptor_2(struct Block_layout *aBlock)
238cc9a6355SApple OSS Distributions {
239bb611c8fSApple OSS Distributions uint8_t *desc = (uint8_t *)_Block_get_descriptor(aBlock);
240cc9a6355SApple OSS Distributions desc += sizeof(struct Block_descriptor_1);
241cc9a6355SApple OSS Distributions return __IGNORE_WCASTALIGN((struct Block_descriptor_2 *)desc);
242cc9a6355SApple OSS Distributions }
243bb611c8fSApple OSS Distributions #endif
244cc9a6355SApple OSS Distributions
245a5e72196SApple OSS Distributions static struct Block_descriptor_3 *
_Block_descriptor_3(struct Block_layout * aBlock)246a5e72196SApple OSS Distributions _Block_descriptor_3(struct Block_layout *aBlock)
247cc9a6355SApple OSS Distributions {
248bb611c8fSApple OSS Distributions uint8_t *desc = (uint8_t *)_Block_get_descriptor(aBlock);
249cc9a6355SApple OSS Distributions desc += sizeof(struct Block_descriptor_1);
250cc9a6355SApple OSS Distributions if (aBlock->flags & BLOCK_HAS_COPY_DISPOSE) {
251cc9a6355SApple OSS Distributions desc += sizeof(struct Block_descriptor_2);
252cc9a6355SApple OSS Distributions }
253cc9a6355SApple OSS Distributions return __IGNORE_WCASTALIGN((struct Block_descriptor_3 *)desc);
254cc9a6355SApple OSS Distributions }
255cc9a6355SApple OSS Distributions
256a5e72196SApple OSS Distributions static void
_Block_call_copy_helper(void * result,struct Block_layout * aBlock)257a5e72196SApple OSS Distributions _Block_call_copy_helper(void *result, struct Block_layout *aBlock)
258cc9a6355SApple OSS Distributions {
259bb611c8fSApple OSS Distributions if (auto *pFn = _Block_get_copy_function(aBlock)) {
260bb611c8fSApple OSS Distributions pFn(result, aBlock);
261a5e72196SApple OSS Distributions }
262cc9a6355SApple OSS Distributions }
263cc9a6355SApple OSS Distributions
264a5e72196SApple OSS Distributions static void
_Block_call_dispose_helper(struct Block_layout * aBlock)265a5e72196SApple OSS Distributions _Block_call_dispose_helper(struct Block_layout *aBlock)
266cc9a6355SApple OSS Distributions {
267bb611c8fSApple OSS Distributions if (auto *pFn = _Block_get_dispose_function(aBlock)) {
268bb611c8fSApple OSS Distributions pFn(aBlock);
269a5e72196SApple OSS Distributions }
270cc9a6355SApple OSS Distributions }
271cc9a6355SApple OSS Distributions
272cc9a6355SApple OSS Distributions /*******************************************************************************
273a5e72196SApple OSS Distributions * Internal Support routines for copying
274cc9a6355SApple OSS Distributions ********************************************************************************/
275cc9a6355SApple OSS Distributions
276cc9a6355SApple OSS Distributions #if !TARGET_OS_WIN32
277cc9a6355SApple OSS Distributions #pragma mark Copy/Release support
278cc9a6355SApple OSS Distributions #endif
279cc9a6355SApple OSS Distributions
280cc9a6355SApple OSS Distributions // Copy, or bump refcount, of a block. If really copying, call the copy helper if present.
281a5e72196SApple OSS Distributions void *
_Block_copy(const void * arg)282a5e72196SApple OSS Distributions _Block_copy(const void *arg)
283a5e72196SApple OSS Distributions {
284cc9a6355SApple OSS Distributions struct Block_layout *aBlock;
285cc9a6355SApple OSS Distributions
286a5e72196SApple OSS Distributions if (!arg) {
287a5e72196SApple OSS Distributions return NULL;
288a5e72196SApple OSS Distributions }
289cc9a6355SApple OSS Distributions
290cc9a6355SApple OSS Distributions // The following would be better done as a switch statement
291cc9a6355SApple OSS Distributions aBlock = (struct Block_layout *)arg;
292cc9a6355SApple OSS Distributions if (aBlock->flags & BLOCK_NEEDS_FREE) {
293cc9a6355SApple OSS Distributions // latches on high
294cc9a6355SApple OSS Distributions latching_incr_int(&aBlock->flags);
295cc9a6355SApple OSS Distributions return aBlock;
296a5e72196SApple OSS Distributions } else if (aBlock->flags & BLOCK_IS_GLOBAL) {
297cc9a6355SApple OSS Distributions return aBlock;
298a5e72196SApple OSS Distributions } else {
299cc9a6355SApple OSS Distributions // Its a stack block. Make a copy.
300bb611c8fSApple OSS Distributions size_t size = Block_size(aBlock);
301*aca3beaaSApple OSS Distributions struct Block_layout *result = block_layout_alloc(size);
302bb611c8fSApple OSS Distributions memmove(result, aBlock, size); // bitcopy first
303cc9a6355SApple OSS Distributions #if __has_feature(ptrauth_calls)
304cc9a6355SApple OSS Distributions // Resign the invoke pointer as it uses address authentication.
305cc9a6355SApple OSS Distributions result->invoke = aBlock->invoke;
306bb611c8fSApple OSS Distributions
307bb611c8fSApple OSS Distributions #if __has_feature(ptrauth_signed_block_descriptors)
308bb611c8fSApple OSS Distributions uintptr_t oldDesc =
309bb611c8fSApple OSS Distributions ptrauth_blend_discriminator(
310bb611c8fSApple OSS Distributions &aBlock->descriptor, _Block_descriptor_ptrauth_discriminator);
311bb611c8fSApple OSS Distributions uintptr_t newDesc =
312bb611c8fSApple OSS Distributions ptrauth_blend_discriminator(
313bb611c8fSApple OSS Distributions &result->descriptor, _Block_descriptor_ptrauth_discriminator);
314bb611c8fSApple OSS Distributions
315bb611c8fSApple OSS Distributions result->descriptor =
316bb611c8fSApple OSS Distributions ptrauth_auth_and_resign(aBlock->descriptor, ptrauth_key_asda, oldDesc,
317bb611c8fSApple OSS Distributions ptrauth_key_asda, newDesc);
318cc9a6355SApple OSS Distributions #endif
319bb611c8fSApple OSS Distributions #endif
320bb611c8fSApple OSS Distributions
321cc9a6355SApple OSS Distributions // reset refcount
322cc9a6355SApple OSS Distributions result->flags &= ~(BLOCK_REFCOUNT_MASK | BLOCK_DEALLOCATING); // XXX not needed
323cc9a6355SApple OSS Distributions result->flags |= BLOCK_NEEDS_FREE | 2; // logical refcount 1
324cc9a6355SApple OSS Distributions _Block_call_copy_helper(result, aBlock);
325cc9a6355SApple OSS Distributions // Set isa last so memory analysis tools see a fully-initialized object.
326cc9a6355SApple OSS Distributions result->isa = _NSConcreteMallocBlock;
327cc9a6355SApple OSS Distributions return result;
328cc9a6355SApple OSS Distributions }
329cc9a6355SApple OSS Distributions }
330cc9a6355SApple OSS Distributions
331cc9a6355SApple OSS Distributions
332cc9a6355SApple OSS Distributions // Runtime entry points for maintaining the sharing knowledge of byref data blocks.
333cc9a6355SApple OSS Distributions
334cc9a6355SApple OSS Distributions // A closure has been copied and its fixup routine is asking us to fix up the reference to the shared byref data
335cc9a6355SApple OSS Distributions // Closures that aren't copied must still work, so everyone always accesses variables after dereferencing the forwarding ptr.
336cc9a6355SApple OSS Distributions // We ask if the byref pointer that we know about has already been copied to the heap, and if so, increment and return it.
337cc9a6355SApple OSS Distributions // Otherwise we need to copy it and update the stack forwarding pointer
338a5e72196SApple OSS Distributions static struct Block_byref *
_Block_byref_copy(const void * arg)339a5e72196SApple OSS Distributions _Block_byref_copy(const void *arg)
340a5e72196SApple OSS Distributions {
341cc9a6355SApple OSS Distributions struct Block_byref *src = (struct Block_byref *)arg;
342cc9a6355SApple OSS Distributions
343cc9a6355SApple OSS Distributions if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
344cc9a6355SApple OSS Distributions // src points to stack
345*aca3beaaSApple OSS Distributions struct Block_byref *copy = block_byref_alloc(src->size);
346cc9a6355SApple OSS Distributions copy->isa = NULL;
347cc9a6355SApple OSS Distributions // byref value 4 is logical refcount of 2: one for caller, one for stack
348cc9a6355SApple OSS Distributions copy->flags = src->flags | BLOCK_BYREF_NEEDS_FREE | 4;
349cc9a6355SApple OSS Distributions copy->forwarding = copy; // patch heap copy to point to itself
350cc9a6355SApple OSS Distributions src->forwarding = copy; // patch stack to point to heap copy
351cc9a6355SApple OSS Distributions copy->size = src->size;
352cc9a6355SApple OSS Distributions
353cc9a6355SApple OSS Distributions if (src->flags & BLOCK_BYREF_HAS_COPY_DISPOSE) {
354cc9a6355SApple OSS Distributions // Trust copy helper to copy everything of interest
355cc9a6355SApple OSS Distributions // If more than one field shows up in a byref block this is wrong XXX
356cc9a6355SApple OSS Distributions struct Block_byref_2 *src2 = (struct Block_byref_2 *)(src + 1);
357cc9a6355SApple OSS Distributions struct Block_byref_2 *copy2 = (struct Block_byref_2 *)(copy + 1);
358cc9a6355SApple OSS Distributions copy2->byref_keep = src2->byref_keep;
359cc9a6355SApple OSS Distributions copy2->byref_destroy = src2->byref_destroy;
360cc9a6355SApple OSS Distributions
361cc9a6355SApple OSS Distributions if (src->flags & BLOCK_BYREF_LAYOUT_EXTENDED) {
362cc9a6355SApple OSS Distributions struct Block_byref_3 *src3 = (struct Block_byref_3 *)(src2 + 1);
363cc9a6355SApple OSS Distributions struct Block_byref_3 *copy3 = (struct Block_byref_3*)(copy2 + 1);
364cc9a6355SApple OSS Distributions copy3->layout = src3->layout;
365cc9a6355SApple OSS Distributions }
366cc9a6355SApple OSS Distributions
367cc9a6355SApple OSS Distributions (*src2->byref_keep)(copy, src);
368a5e72196SApple OSS Distributions } else {
369cc9a6355SApple OSS Distributions // Bitwise copy.
370cc9a6355SApple OSS Distributions // This copy includes Block_byref_3, if any.
371cc9a6355SApple OSS Distributions memmove(copy + 1, src + 1, src->size - sizeof(*src));
372cc9a6355SApple OSS Distributions }
373cc9a6355SApple OSS Distributions }
374cc9a6355SApple OSS Distributions // already copied to heap
375cc9a6355SApple OSS Distributions else if ((src->forwarding->flags & BLOCK_BYREF_NEEDS_FREE) == BLOCK_BYREF_NEEDS_FREE) {
376cc9a6355SApple OSS Distributions latching_incr_int(&src->forwarding->flags);
377cc9a6355SApple OSS Distributions }
378cc9a6355SApple OSS Distributions
379cc9a6355SApple OSS Distributions return src->forwarding;
380cc9a6355SApple OSS Distributions }
381cc9a6355SApple OSS Distributions
382a5e72196SApple OSS Distributions static void
_Block_byref_release(const void * arg)383a5e72196SApple OSS Distributions _Block_byref_release(const void *arg)
384a5e72196SApple OSS Distributions {
385cc9a6355SApple OSS Distributions struct Block_byref *byref = (struct Block_byref *)arg;
386cc9a6355SApple OSS Distributions
387cc9a6355SApple OSS Distributions // dereference the forwarding pointer since the compiler isn't doing this anymore (ever?)
388cc9a6355SApple OSS Distributions byref = byref->forwarding;
389cc9a6355SApple OSS Distributions
390cc9a6355SApple OSS Distributions if (byref->flags & BLOCK_BYREF_NEEDS_FREE) {
391cc9a6355SApple OSS Distributions __assert_only int32_t refcount = byref->flags & BLOCK_REFCOUNT_MASK;
392cc9a6355SApple OSS Distributions os_assert(refcount);
393cc9a6355SApple OSS Distributions if (latching_decr_int_should_deallocate(&byref->flags)) {
394cc9a6355SApple OSS Distributions if (byref->flags & BLOCK_BYREF_HAS_COPY_DISPOSE) {
395cc9a6355SApple OSS Distributions struct Block_byref_2 *byref2 = (struct Block_byref_2 *)(byref + 1);
396cc9a6355SApple OSS Distributions (*byref2->byref_destroy)(byref);
397cc9a6355SApple OSS Distributions }
398*aca3beaaSApple OSS Distributions block_byref_free(byref, byref->size);
399cc9a6355SApple OSS Distributions }
400cc9a6355SApple OSS Distributions }
401cc9a6355SApple OSS Distributions }
402cc9a6355SApple OSS Distributions
403cc9a6355SApple OSS Distributions
404cc9a6355SApple OSS Distributions /************************************************************
405cc9a6355SApple OSS Distributions *
406cc9a6355SApple OSS Distributions * API supporting SPI
407cc9a6355SApple OSS Distributions * _Block_copy, _Block_release, and (old) _Block_destroy
408cc9a6355SApple OSS Distributions *
409cc9a6355SApple OSS Distributions ***********************************************************/
410cc9a6355SApple OSS Distributions
411cc9a6355SApple OSS Distributions #if !TARGET_OS_WIN32
412cc9a6355SApple OSS Distributions #pragma mark SPI/API
413cc9a6355SApple OSS Distributions #endif
414cc9a6355SApple OSS Distributions
415cc9a6355SApple OSS Distributions
416cc9a6355SApple OSS Distributions // API entry point to release a copied Block
417a5e72196SApple OSS Distributions void
_Block_release(const void * arg)418a5e72196SApple OSS Distributions _Block_release(const void *arg)
419a5e72196SApple OSS Distributions {
420cc9a6355SApple OSS Distributions struct Block_layout *aBlock = (struct Block_layout *)arg;
421a5e72196SApple OSS Distributions if (!aBlock) {
422a5e72196SApple OSS Distributions return;
423a5e72196SApple OSS Distributions }
424a5e72196SApple OSS Distributions if (aBlock->flags & BLOCK_IS_GLOBAL) {
425a5e72196SApple OSS Distributions return;
426a5e72196SApple OSS Distributions }
427a5e72196SApple OSS Distributions if (!(aBlock->flags & BLOCK_NEEDS_FREE)) {
428a5e72196SApple OSS Distributions return;
429a5e72196SApple OSS Distributions }
430cc9a6355SApple OSS Distributions
431cc9a6355SApple OSS Distributions if (latching_decr_int_should_deallocate(&aBlock->flags)) {
432cc9a6355SApple OSS Distributions _Block_call_dispose_helper(aBlock);
433cc9a6355SApple OSS Distributions _Block_destructInstance(aBlock);
434*aca3beaaSApple OSS Distributions block_layout_free(aBlock, Block_size(aBlock));
435cc9a6355SApple OSS Distributions }
436cc9a6355SApple OSS Distributions }
437cc9a6355SApple OSS Distributions
438a5e72196SApple OSS Distributions bool
_Block_tryRetain(const void * arg)439a5e72196SApple OSS Distributions _Block_tryRetain(const void *arg)
440a5e72196SApple OSS Distributions {
441cc9a6355SApple OSS Distributions struct Block_layout *aBlock = (struct Block_layout *)arg;
442cc9a6355SApple OSS Distributions return latching_incr_int_not_deallocating(&aBlock->flags);
443cc9a6355SApple OSS Distributions }
444cc9a6355SApple OSS Distributions
445a5e72196SApple OSS Distributions bool
_Block_isDeallocating(const void * arg)446a5e72196SApple OSS Distributions _Block_isDeallocating(const void *arg)
447a5e72196SApple OSS Distributions {
448cc9a6355SApple OSS Distributions struct Block_layout *aBlock = (struct Block_layout *)arg;
449cc9a6355SApple OSS Distributions return (aBlock->flags & BLOCK_DEALLOCATING) != 0;
450cc9a6355SApple OSS Distributions }
451cc9a6355SApple OSS Distributions
452cc9a6355SApple OSS Distributions
453cc9a6355SApple OSS Distributions /************************************************************
454cc9a6355SApple OSS Distributions *
455cc9a6355SApple OSS Distributions * SPI used by other layers
456cc9a6355SApple OSS Distributions *
457cc9a6355SApple OSS Distributions ***********************************************************/
458cc9a6355SApple OSS Distributions
459a5e72196SApple OSS Distributions size_t
Block_size(void * aBlock)460a5e72196SApple OSS Distributions Block_size(void *aBlock)
461a5e72196SApple OSS Distributions {
462bb611c8fSApple OSS Distributions auto *layout = (Block_layout *)aBlock;
463bb611c8fSApple OSS Distributions void *desc = _Block_get_descriptor(layout);
4645c2921b0SApple OSS Distributions #if BLOCK_SMALL_DESCRIPTOR_SUPPORTED
465bb611c8fSApple OSS Distributions if (layout->flags & BLOCK_SMALL_DESCRIPTOR) {
466bb611c8fSApple OSS Distributions return ((Block_descriptor_small *)desc)->size;
467bb611c8fSApple OSS Distributions }
4685c2921b0SApple OSS Distributions #endif
469bb611c8fSApple OSS Distributions return ((Block_descriptor_1 *)desc)->size;
470cc9a6355SApple OSS Distributions }
471cc9a6355SApple OSS Distributions
472a5e72196SApple OSS Distributions bool
_Block_use_stret(void * aBlock)473a5e72196SApple OSS Distributions _Block_use_stret(void *aBlock)
474a5e72196SApple OSS Distributions {
475cc9a6355SApple OSS Distributions struct Block_layout *layout = (struct Block_layout *)aBlock;
476cc9a6355SApple OSS Distributions
477cc9a6355SApple OSS Distributions int requiredFlags = BLOCK_HAS_SIGNATURE | BLOCK_USE_STRET;
478cc9a6355SApple OSS Distributions return (layout->flags & requiredFlags) == requiredFlags;
479cc9a6355SApple OSS Distributions }
480cc9a6355SApple OSS Distributions
481cc9a6355SApple OSS Distributions // Checks for a valid signature, not merely the BLOCK_HAS_SIGNATURE bit.
482a5e72196SApple OSS Distributions bool
_Block_has_signature(void * aBlock)483a5e72196SApple OSS Distributions _Block_has_signature(void *aBlock)
484a5e72196SApple OSS Distributions {
485cc9a6355SApple OSS Distributions return _Block_signature(aBlock) ? true : false;
486cc9a6355SApple OSS Distributions }
487cc9a6355SApple OSS Distributions
488a5e72196SApple OSS Distributions const char *
_Block_signature(void * aBlock)489a5e72196SApple OSS Distributions _Block_signature(void *aBlock)
490cc9a6355SApple OSS Distributions {
491bb611c8fSApple OSS Distributions struct Block_layout *layout = (struct Block_layout *)aBlock;
492bb611c8fSApple OSS Distributions if (!(layout->flags & BLOCK_HAS_SIGNATURE)) {
493bb611c8fSApple OSS Distributions return nullptr;
494a5e72196SApple OSS Distributions }
495cc9a6355SApple OSS Distributions
4965c2921b0SApple OSS Distributions #if BLOCK_SMALL_DESCRIPTOR_SUPPORTED
497bb611c8fSApple OSS Distributions if (layout->flags & BLOCK_SMALL_DESCRIPTOR) {
498bb611c8fSApple OSS Distributions auto *bds = (Block_descriptor_small *)_Block_get_descriptor(layout);
499bb611c8fSApple OSS Distributions return unwrap_relative_pointer<const char>(bds->signature);
500bb611c8fSApple OSS Distributions }
5015c2921b0SApple OSS Distributions #endif
502bb611c8fSApple OSS Distributions
503bb611c8fSApple OSS Distributions struct Block_descriptor_3 *desc3 = _Block_descriptor_3(layout);
504cc9a6355SApple OSS Distributions return desc3->signature;
505cc9a6355SApple OSS Distributions }
506cc9a6355SApple OSS Distributions
507a5e72196SApple OSS Distributions const char *
_Block_layout(void * aBlock)508a5e72196SApple OSS Distributions _Block_layout(void *aBlock)
509cc9a6355SApple OSS Distributions {
510cc9a6355SApple OSS Distributions // Don't return extended layout to callers expecting old GC layout
511bb611c8fSApple OSS Distributions Block_layout *layout = (Block_layout *)aBlock;
512bb611c8fSApple OSS Distributions if ((layout->flags & BLOCK_HAS_EXTENDED_LAYOUT) ||
513bb611c8fSApple OSS Distributions !(layout->flags & BLOCK_HAS_SIGNATURE)) {
514bb611c8fSApple OSS Distributions return nullptr;
515a5e72196SApple OSS Distributions }
516cc9a6355SApple OSS Distributions
5175c2921b0SApple OSS Distributions #if BLOCK_SMALL_DESCRIPTOR_SUPPORTED
518bb611c8fSApple OSS Distributions if (layout->flags & BLOCK_SMALL_DESCRIPTOR) {
519bb611c8fSApple OSS Distributions auto *bds = (Block_descriptor_small *)_Block_get_descriptor(layout);
520bb611c8fSApple OSS Distributions return unwrap_relative_pointer<const char>(bds->layout);
521a5e72196SApple OSS Distributions }
5225c2921b0SApple OSS Distributions #endif
523cc9a6355SApple OSS Distributions
524bb611c8fSApple OSS Distributions Block_descriptor_3 *desc = _Block_descriptor_3(layout);
525bb611c8fSApple OSS Distributions return desc->layout;
526cc9a6355SApple OSS Distributions }
527cc9a6355SApple OSS Distributions
528a5e72196SApple OSS Distributions const char *
_Block_extended_layout(void * aBlock)529a5e72196SApple OSS Distributions _Block_extended_layout(void *aBlock)
530cc9a6355SApple OSS Distributions {
531cc9a6355SApple OSS Distributions // Don't return old GC layout to callers expecting extended layout
532bb611c8fSApple OSS Distributions Block_layout *layout = (Block_layout *)aBlock;
533bb611c8fSApple OSS Distributions if (!(layout->flags & BLOCK_HAS_EXTENDED_LAYOUT) ||
534bb611c8fSApple OSS Distributions !(layout->flags & BLOCK_HAS_SIGNATURE)) {
535bb611c8fSApple OSS Distributions return nullptr;
536a5e72196SApple OSS Distributions }
537cc9a6355SApple OSS Distributions
538bb611c8fSApple OSS Distributions const char *extLayout;
5395c2921b0SApple OSS Distributions #if BLOCK_SMALL_DESCRIPTOR_SUPPORTED
540bb611c8fSApple OSS Distributions if (layout->flags & BLOCK_SMALL_DESCRIPTOR) {
541bb611c8fSApple OSS Distributions auto *bds = (Block_descriptor_small *)_Block_get_descriptor(layout);
542bb611c8fSApple OSS Distributions if (layout->flags & BLOCK_INLINE_LAYOUT_STRING) {
543bb611c8fSApple OSS Distributions extLayout = (const char *)(uintptr_t)bds->layout;
544bb611c8fSApple OSS Distributions } else {
545bb611c8fSApple OSS Distributions extLayout = unwrap_relative_pointer<const char>(bds->layout);
546bb611c8fSApple OSS Distributions }
5475c2921b0SApple OSS Distributions } else
5485c2921b0SApple OSS Distributions #endif
5495c2921b0SApple OSS Distributions {
550bb611c8fSApple OSS Distributions Block_descriptor_3 *desc3 = _Block_descriptor_3(layout);
551bb611c8fSApple OSS Distributions extLayout = desc3->layout;
552a5e72196SApple OSS Distributions }
553cc9a6355SApple OSS Distributions
554cc9a6355SApple OSS Distributions // Return empty string (all non-object bytes) instead of NULL
555cc9a6355SApple OSS Distributions // so callers can distinguish "empty layout" from "no layout".
556bb611c8fSApple OSS Distributions if (!extLayout) {
557bb611c8fSApple OSS Distributions extLayout = "";
558a5e72196SApple OSS Distributions }
559bb611c8fSApple OSS Distributions return extLayout;
560cc9a6355SApple OSS Distributions }
561cc9a6355SApple OSS Distributions
562cc9a6355SApple OSS Distributions #if !TARGET_OS_WIN32
563cc9a6355SApple OSS Distributions #pragma mark Compiler SPI entry points
564cc9a6355SApple OSS Distributions #endif
565cc9a6355SApple OSS Distributions
566cc9a6355SApple OSS Distributions
567cc9a6355SApple OSS Distributions /*******************************************************
568a5e72196SApple OSS Distributions *
569a5e72196SApple OSS Distributions * Entry points used by the compiler - the real API!
570a5e72196SApple OSS Distributions *
571a5e72196SApple OSS Distributions *
572a5e72196SApple OSS Distributions * A Block can reference four different kinds of things that require help when the Block is copied to the heap.
573a5e72196SApple OSS Distributions * 1) C++ stack based objects
574a5e72196SApple OSS Distributions * 2) References to Objective-C objects
575a5e72196SApple OSS Distributions * 3) Other Blocks
576a5e72196SApple OSS Distributions * 4) __block variables
577a5e72196SApple OSS Distributions *
578a5e72196SApple OSS Distributions * In these cases helper functions are synthesized by the compiler for use in Block_copy and Block_release, called the copy and dispose helpers. The copy helper emits a call to the C++ const copy constructor for C++ stack based objects and for the rest calls into the runtime support function _Block_object_assign. The dispose helper has a call to the C++ destructor for case 1 and a call into _Block_object_dispose for the rest.
579a5e72196SApple OSS Distributions *
580a5e72196SApple OSS Distributions * The flags parameter of _Block_object_assign and _Block_object_dispose is set to
581cc9a6355SApple OSS Distributions * BLOCK_FIELD_IS_OBJECT (3), for the case of an Objective-C Object,
582cc9a6355SApple OSS Distributions * BLOCK_FIELD_IS_BLOCK (7), for the case of another Block, and
583cc9a6355SApple OSS Distributions * BLOCK_FIELD_IS_BYREF (8), for the case of a __block variable.
584a5e72196SApple OSS Distributions * If the __block variable is marked weak the compiler also or's in BLOCK_FIELD_IS_WEAK (16)
585a5e72196SApple OSS Distributions *
586a5e72196SApple OSS Distributions * So the Block copy/dispose helpers should only ever generate the four flag values of 3, 7, 8, and 24.
587a5e72196SApple OSS Distributions *
588a5e72196SApple OSS Distributions * When a __block variable is either a C++ object, an Objective-C object, or another Block then the compiler also generates copy/dispose helper functions. Similarly to the Block copy helper, the "__block" copy helper (formerly and still a.k.a. "byref" copy helper) will do a C++ copy constructor (not a const one though!) and the dispose helper will do the destructor. And similarly the helpers will call into the same two support functions with the same values for objects and Blocks with the additional BLOCK_BYREF_CALLER (128) bit of information supplied.
589a5e72196SApple OSS Distributions *
590a5e72196SApple OSS Distributions * So the __block copy/dispose helpers will generate flag values of 3 or 7 for objects and Blocks respectively, with BLOCK_FIELD_IS_WEAK (16) or'ed as appropriate and always 128 or'd in, for the following set of possibilities:
591a5e72196SApple OSS Distributions * __block id 128+3 (0x83)
592a5e72196SApple OSS Distributions * __block (^Block) 128+7 (0x87)
593a5e72196SApple OSS Distributions * __weak __block id 128+3+16 (0x93)
594a5e72196SApple OSS Distributions * __weak __block (^Block) 128+7+16 (0x97)
595a5e72196SApple OSS Distributions *
596a5e72196SApple OSS Distributions *
597cc9a6355SApple OSS Distributions ********************************************************/
598cc9a6355SApple OSS Distributions
599cc9a6355SApple OSS Distributions //
600cc9a6355SApple OSS Distributions // When Blocks or Block_byrefs hold objects then their copy routine helpers use this entry point
601cc9a6355SApple OSS Distributions // to do the assignment.
602cc9a6355SApple OSS Distributions //
603a5e72196SApple OSS Distributions void
_Block_object_assign(void * destArg,const void * object,const int flags)604a5e72196SApple OSS Distributions _Block_object_assign(void *destArg, const void *object, const int flags)
605a5e72196SApple OSS Distributions {
606cc9a6355SApple OSS Distributions const void **dest = (const void **)destArg;
607cc9a6355SApple OSS Distributions switch (os_assumes(flags & BLOCK_ALL_COPY_DISPOSE_FLAGS)) {
608cc9a6355SApple OSS Distributions case BLOCK_FIELD_IS_OBJECT:
609cc9a6355SApple OSS Distributions /*******
610a5e72196SApple OSS Distributions * id object = ...;
611a5e72196SApple OSS Distributions * [^{ object; } copy];
612cc9a6355SApple OSS Distributions ********/
613cc9a6355SApple OSS Distributions
614cc9a6355SApple OSS Distributions _Block_retain_object(object);
615cc9a6355SApple OSS Distributions *dest = object;
616cc9a6355SApple OSS Distributions break;
617cc9a6355SApple OSS Distributions
618cc9a6355SApple OSS Distributions case BLOCK_FIELD_IS_BLOCK:
619cc9a6355SApple OSS Distributions /*******
620a5e72196SApple OSS Distributions * void (^object)(void) = ...;
621a5e72196SApple OSS Distributions * [^{ object; } copy];
622cc9a6355SApple OSS Distributions ********/
623cc9a6355SApple OSS Distributions
624cc9a6355SApple OSS Distributions *dest = _Block_copy(object);
625cc9a6355SApple OSS Distributions break;
626cc9a6355SApple OSS Distributions
627cc9a6355SApple OSS Distributions case BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK:
628cc9a6355SApple OSS Distributions case BLOCK_FIELD_IS_BYREF:
629cc9a6355SApple OSS Distributions /*******
630a5e72196SApple OSS Distributions * // copy the onstack __block container to the heap
631a5e72196SApple OSS Distributions * // Note this __weak is old GC-weak/MRC-unretained.
632a5e72196SApple OSS Distributions * // ARC-style __weak is handled by the copy helper directly.
633a5e72196SApple OSS Distributions * __block ... x;
634a5e72196SApple OSS Distributions * __weak __block ... x;
635a5e72196SApple OSS Distributions * [^{ x; } copy];
636cc9a6355SApple OSS Distributions ********/
637cc9a6355SApple OSS Distributions
638cc9a6355SApple OSS Distributions *dest = _Block_byref_copy(object);
639cc9a6355SApple OSS Distributions break;
640cc9a6355SApple OSS Distributions
641cc9a6355SApple OSS Distributions case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT:
642cc9a6355SApple OSS Distributions case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK:
643cc9a6355SApple OSS Distributions /*******
644a5e72196SApple OSS Distributions * // copy the actual field held in the __block container
645a5e72196SApple OSS Distributions * // Note this is MRC unretained __block only.
646a5e72196SApple OSS Distributions * // ARC retained __block is handled by the copy helper directly.
647a5e72196SApple OSS Distributions * __block id object;
648a5e72196SApple OSS Distributions * __block void (^object)(void);
649a5e72196SApple OSS Distributions * [^{ object; } copy];
650cc9a6355SApple OSS Distributions ********/
651cc9a6355SApple OSS Distributions
652cc9a6355SApple OSS Distributions *dest = object;
653cc9a6355SApple OSS Distributions break;
654cc9a6355SApple OSS Distributions
655cc9a6355SApple OSS Distributions case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK:
656cc9a6355SApple OSS Distributions case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK | BLOCK_FIELD_IS_WEAK:
657cc9a6355SApple OSS Distributions /*******
658a5e72196SApple OSS Distributions * // copy the actual field held in the __block container
659a5e72196SApple OSS Distributions * // Note this __weak is old GC-weak/MRC-unretained.
660a5e72196SApple OSS Distributions * // ARC-style __weak is handled by the copy helper directly.
661a5e72196SApple OSS Distributions * __weak __block id object;
662a5e72196SApple OSS Distributions * __weak __block void (^object)(void);
663a5e72196SApple OSS Distributions * [^{ object; } copy];
664cc9a6355SApple OSS Distributions ********/
665cc9a6355SApple OSS Distributions
666cc9a6355SApple OSS Distributions *dest = object;
667cc9a6355SApple OSS Distributions break;
668cc9a6355SApple OSS Distributions
669cc9a6355SApple OSS Distributions default:
670cc9a6355SApple OSS Distributions break;
671cc9a6355SApple OSS Distributions }
672cc9a6355SApple OSS Distributions }
673cc9a6355SApple OSS Distributions
674cc9a6355SApple OSS Distributions // When Blocks or Block_byrefs hold objects their destroy helper routines call this entry point
675cc9a6355SApple OSS Distributions // to help dispose of the contents
676a5e72196SApple OSS Distributions void
_Block_object_dispose(const void * object,const int flags)677a5e72196SApple OSS Distributions _Block_object_dispose(const void *object, const int flags)
678a5e72196SApple OSS Distributions {
679cc9a6355SApple OSS Distributions switch (os_assumes(flags & BLOCK_ALL_COPY_DISPOSE_FLAGS)) {
680cc9a6355SApple OSS Distributions case BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK:
681cc9a6355SApple OSS Distributions case BLOCK_FIELD_IS_BYREF:
682cc9a6355SApple OSS Distributions // get rid of the __block data structure held in a Block
683cc9a6355SApple OSS Distributions _Block_byref_release(object);
684cc9a6355SApple OSS Distributions break;
685cc9a6355SApple OSS Distributions case BLOCK_FIELD_IS_BLOCK:
686cc9a6355SApple OSS Distributions _Block_release(object);
687cc9a6355SApple OSS Distributions break;
688cc9a6355SApple OSS Distributions case BLOCK_FIELD_IS_OBJECT:
689cc9a6355SApple OSS Distributions _Block_release_object(object);
690cc9a6355SApple OSS Distributions break;
691cc9a6355SApple OSS Distributions case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT:
692cc9a6355SApple OSS Distributions case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK:
693cc9a6355SApple OSS Distributions case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK:
694cc9a6355SApple OSS Distributions case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK | BLOCK_FIELD_IS_WEAK:
695cc9a6355SApple OSS Distributions break;
696cc9a6355SApple OSS Distributions default:
697cc9a6355SApple OSS Distributions break;
698cc9a6355SApple OSS Distributions }
699cc9a6355SApple OSS Distributions }
700cc9a6355SApple OSS Distributions
701cc9a6355SApple OSS Distributions
702cc9a6355SApple OSS Distributions // Workaround for <rdar://26015603> dylib with no __DATA segment fails to rebase
703cc9a6355SApple OSS Distributions __attribute__((used))
704cc9a6355SApple OSS Distributions static int let_there_be_data = 42;
705