1*7c3d14c8STreehugger Robot /*
2*7c3d14c8STreehugger Robot * runtime.c
3*7c3d14c8STreehugger Robot *
4*7c3d14c8STreehugger Robot * Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,
5*7c3d14c8STreehugger Robot * to any person obtaining a copy of this software and associated documentation
6*7c3d14c8STreehugger Robot * files (the "Software"), to deal in the Software without restriction,
7*7c3d14c8STreehugger Robot * including without limitation the rights to use, copy, modify, merge, publish,
8*7c3d14c8STreehugger Robot * distribute, sublicense, and/or sell copies of the Software, and to permit
9*7c3d14c8STreehugger Robot * persons to whom the Software is furnished to do so, subject to the following
10*7c3d14c8STreehugger Robot * conditions:
11*7c3d14c8STreehugger Robot *
12*7c3d14c8STreehugger Robot * The above copyright notice and this permission notice shall be included in
13*7c3d14c8STreehugger Robot * all copies or substantial portions of the Software.
14*7c3d14c8STreehugger Robot *
15*7c3d14c8STreehugger Robot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*7c3d14c8STreehugger Robot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*7c3d14c8STreehugger Robot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18*7c3d14c8STreehugger Robot * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*7c3d14c8STreehugger Robot * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20*7c3d14c8STreehugger Robot * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21*7c3d14c8STreehugger Robot * SOFTWARE.
22*7c3d14c8STreehugger Robot *
23*7c3d14c8STreehugger Robot */
24*7c3d14c8STreehugger Robot
25*7c3d14c8STreehugger Robot #include "Block_private.h"
26*7c3d14c8STreehugger Robot #include <stdio.h>
27*7c3d14c8STreehugger Robot #include <stdlib.h>
28*7c3d14c8STreehugger Robot #include <string.h>
29*7c3d14c8STreehugger Robot #include <stdint.h>
30*7c3d14c8STreehugger Robot
31*7c3d14c8STreehugger Robot #include "config.h"
32*7c3d14c8STreehugger Robot
33*7c3d14c8STreehugger Robot #ifdef HAVE_AVAILABILITY_MACROS_H
34*7c3d14c8STreehugger Robot #include <AvailabilityMacros.h>
35*7c3d14c8STreehugger Robot #endif /* HAVE_AVAILABILITY_MACROS_H */
36*7c3d14c8STreehugger Robot
37*7c3d14c8STreehugger Robot #ifdef HAVE_TARGET_CONDITIONALS_H
38*7c3d14c8STreehugger Robot #include <TargetConditionals.h>
39*7c3d14c8STreehugger Robot #endif /* HAVE_TARGET_CONDITIONALS_H */
40*7c3d14c8STreehugger Robot
41*7c3d14c8STreehugger Robot #if defined(HAVE_OSATOMIC_COMPARE_AND_SWAP_INT) && defined(HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG)
42*7c3d14c8STreehugger Robot
43*7c3d14c8STreehugger Robot #ifdef HAVE_LIBKERN_OSATOMIC_H
44*7c3d14c8STreehugger Robot #include <libkern/OSAtomic.h>
45*7c3d14c8STreehugger Robot #endif /* HAVE_LIBKERN_OSATOMIC_H */
46*7c3d14c8STreehugger Robot
47*7c3d14c8STreehugger Robot #elif defined(__WIN32__) || defined(_WIN32)
48*7c3d14c8STreehugger Robot #define _CRT_SECURE_NO_WARNINGS 1
49*7c3d14c8STreehugger Robot #include <windows.h>
50*7c3d14c8STreehugger Robot
OSAtomicCompareAndSwapLong(long oldl,long newl,long volatile * dst)51*7c3d14c8STreehugger Robot static __inline bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) {
52*7c3d14c8STreehugger Robot /* fixme barrier is overkill -- see objc-os.h */
53*7c3d14c8STreehugger Robot long original = InterlockedCompareExchange(dst, newl, oldl);
54*7c3d14c8STreehugger Robot return (original == oldl);
55*7c3d14c8STreehugger Robot }
56*7c3d14c8STreehugger Robot
OSAtomicCompareAndSwapInt(int oldi,int newi,int volatile * dst)57*7c3d14c8STreehugger Robot static __inline bool OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile *dst) {
58*7c3d14c8STreehugger Robot /* fixme barrier is overkill -- see objc-os.h */
59*7c3d14c8STreehugger Robot int original = InterlockedCompareExchange(dst, newi, oldi);
60*7c3d14c8STreehugger Robot return (original == oldi);
61*7c3d14c8STreehugger Robot }
62*7c3d14c8STreehugger Robot
63*7c3d14c8STreehugger Robot /*
64*7c3d14c8STreehugger Robot * Check to see if the GCC atomic built-ins are available. If we're on
65*7c3d14c8STreehugger Robot * a 64-bit system, make sure we have an 8-byte atomic function
66*7c3d14c8STreehugger Robot * available.
67*7c3d14c8STreehugger Robot *
68*7c3d14c8STreehugger Robot */
69*7c3d14c8STreehugger Robot
70*7c3d14c8STreehugger Robot #elif defined(HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT) && defined(HAVE_SYNC_BOOL_COMPARE_AND_SWAP_LONG)
71*7c3d14c8STreehugger Robot
OSAtomicCompareAndSwapLong(long oldl,long newl,long volatile * dst)72*7c3d14c8STreehugger Robot static __inline bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) {
73*7c3d14c8STreehugger Robot return __sync_bool_compare_and_swap(dst, oldl, newl);
74*7c3d14c8STreehugger Robot }
75*7c3d14c8STreehugger Robot
OSAtomicCompareAndSwapInt(int oldi,int newi,int volatile * dst)76*7c3d14c8STreehugger Robot static __inline bool OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile *dst) {
77*7c3d14c8STreehugger Robot return __sync_bool_compare_and_swap(dst, oldi, newi);
78*7c3d14c8STreehugger Robot }
79*7c3d14c8STreehugger Robot
80*7c3d14c8STreehugger Robot #else
81*7c3d14c8STreehugger Robot #error unknown atomic compare-and-swap primitive
82*7c3d14c8STreehugger Robot #endif /* HAVE_OSATOMIC_COMPARE_AND_SWAP_INT && HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG */
83*7c3d14c8STreehugger Robot
84*7c3d14c8STreehugger Robot
85*7c3d14c8STreehugger Robot /*
86*7c3d14c8STreehugger Robot * Globals:
87*7c3d14c8STreehugger Robot */
88*7c3d14c8STreehugger Robot
89*7c3d14c8STreehugger Robot static void *_Block_copy_class = _NSConcreteMallocBlock;
90*7c3d14c8STreehugger Robot static void *_Block_copy_finalizing_class = _NSConcreteMallocBlock;
91*7c3d14c8STreehugger Robot static int _Block_copy_flag = BLOCK_NEEDS_FREE;
92*7c3d14c8STreehugger Robot static int _Byref_flag_initial_value = BLOCK_NEEDS_FREE | 2;
93*7c3d14c8STreehugger Robot
94*7c3d14c8STreehugger Robot static const int WANTS_ONE = (1 << 16);
95*7c3d14c8STreehugger Robot
96*7c3d14c8STreehugger Robot static bool isGC = false;
97*7c3d14c8STreehugger Robot
98*7c3d14c8STreehugger Robot /*
99*7c3d14c8STreehugger Robot * Internal Utilities:
100*7c3d14c8STreehugger Robot */
101*7c3d14c8STreehugger Robot
102*7c3d14c8STreehugger Robot #if 0
103*7c3d14c8STreehugger Robot static unsigned long int latching_incr_long(unsigned long int *where) {
104*7c3d14c8STreehugger Robot while (1) {
105*7c3d14c8STreehugger Robot unsigned long int old_value = *(volatile unsigned long int *)where;
106*7c3d14c8STreehugger Robot if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
107*7c3d14c8STreehugger Robot return BLOCK_REFCOUNT_MASK;
108*7c3d14c8STreehugger Robot }
109*7c3d14c8STreehugger Robot if (OSAtomicCompareAndSwapLong(old_value, old_value+1, (volatile long int *)where)) {
110*7c3d14c8STreehugger Robot return old_value+1;
111*7c3d14c8STreehugger Robot }
112*7c3d14c8STreehugger Robot }
113*7c3d14c8STreehugger Robot }
114*7c3d14c8STreehugger Robot #endif /* if 0 */
115*7c3d14c8STreehugger Robot
latching_incr_int(int * where)116*7c3d14c8STreehugger Robot static int latching_incr_int(int *where) {
117*7c3d14c8STreehugger Robot while (1) {
118*7c3d14c8STreehugger Robot int old_value = *(volatile int *)where;
119*7c3d14c8STreehugger Robot if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
120*7c3d14c8STreehugger Robot return BLOCK_REFCOUNT_MASK;
121*7c3d14c8STreehugger Robot }
122*7c3d14c8STreehugger Robot if (OSAtomicCompareAndSwapInt(old_value, old_value+1, (volatile int *)where)) {
123*7c3d14c8STreehugger Robot return old_value+1;
124*7c3d14c8STreehugger Robot }
125*7c3d14c8STreehugger Robot }
126*7c3d14c8STreehugger Robot }
127*7c3d14c8STreehugger Robot
128*7c3d14c8STreehugger Robot #if 0
129*7c3d14c8STreehugger Robot static int latching_decr_long(unsigned long int *where) {
130*7c3d14c8STreehugger Robot while (1) {
131*7c3d14c8STreehugger Robot unsigned long int old_value = *(volatile int *)where;
132*7c3d14c8STreehugger Robot if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
133*7c3d14c8STreehugger Robot return BLOCK_REFCOUNT_MASK;
134*7c3d14c8STreehugger Robot }
135*7c3d14c8STreehugger Robot if ((old_value & BLOCK_REFCOUNT_MASK) == 0) {
136*7c3d14c8STreehugger Robot return 0;
137*7c3d14c8STreehugger Robot }
138*7c3d14c8STreehugger Robot if (OSAtomicCompareAndSwapLong(old_value, old_value-1, (volatile long int *)where)) {
139*7c3d14c8STreehugger Robot return old_value-1;
140*7c3d14c8STreehugger Robot }
141*7c3d14c8STreehugger Robot }
142*7c3d14c8STreehugger Robot }
143*7c3d14c8STreehugger Robot #endif /* if 0 */
144*7c3d14c8STreehugger Robot
latching_decr_int(int * where)145*7c3d14c8STreehugger Robot static int latching_decr_int(int *where) {
146*7c3d14c8STreehugger Robot while (1) {
147*7c3d14c8STreehugger Robot int old_value = *(volatile int *)where;
148*7c3d14c8STreehugger Robot if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
149*7c3d14c8STreehugger Robot return BLOCK_REFCOUNT_MASK;
150*7c3d14c8STreehugger Robot }
151*7c3d14c8STreehugger Robot if ((old_value & BLOCK_REFCOUNT_MASK) == 0) {
152*7c3d14c8STreehugger Robot return 0;
153*7c3d14c8STreehugger Robot }
154*7c3d14c8STreehugger Robot if (OSAtomicCompareAndSwapInt(old_value, old_value-1, (volatile int *)where)) {
155*7c3d14c8STreehugger Robot return old_value-1;
156*7c3d14c8STreehugger Robot }
157*7c3d14c8STreehugger Robot }
158*7c3d14c8STreehugger Robot }
159*7c3d14c8STreehugger Robot
160*7c3d14c8STreehugger Robot
161*7c3d14c8STreehugger Robot /*
162*7c3d14c8STreehugger Robot * GC support stub routines:
163*7c3d14c8STreehugger Robot */
164*7c3d14c8STreehugger Robot #if 0
165*7c3d14c8STreehugger Robot #pragma mark GC Support Routines
166*7c3d14c8STreehugger Robot #endif /* if 0 */
167*7c3d14c8STreehugger Robot
168*7c3d14c8STreehugger Robot
_Block_alloc_default(const unsigned long size,const bool initialCountIsOne,const bool isObject)169*7c3d14c8STreehugger Robot static void *_Block_alloc_default(const unsigned long size, const bool initialCountIsOne, const bool isObject) {
170*7c3d14c8STreehugger Robot return malloc(size);
171*7c3d14c8STreehugger Robot }
172*7c3d14c8STreehugger Robot
_Block_assign_default(void * value,void ** destptr)173*7c3d14c8STreehugger Robot static void _Block_assign_default(void *value, void **destptr) {
174*7c3d14c8STreehugger Robot *destptr = value;
175*7c3d14c8STreehugger Robot }
176*7c3d14c8STreehugger Robot
_Block_setHasRefcount_default(const void * ptr,const bool hasRefcount)177*7c3d14c8STreehugger Robot static void _Block_setHasRefcount_default(const void *ptr, const bool hasRefcount) {
178*7c3d14c8STreehugger Robot }
179*7c3d14c8STreehugger Robot
_Block_do_nothing(const void * aBlock)180*7c3d14c8STreehugger Robot static void _Block_do_nothing(const void *aBlock) { }
181*7c3d14c8STreehugger Robot
_Block_retain_object_default(const void * ptr)182*7c3d14c8STreehugger Robot static void _Block_retain_object_default(const void *ptr) {
183*7c3d14c8STreehugger Robot if (!ptr) return;
184*7c3d14c8STreehugger Robot }
185*7c3d14c8STreehugger Robot
_Block_release_object_default(const void * ptr)186*7c3d14c8STreehugger Robot static void _Block_release_object_default(const void *ptr) {
187*7c3d14c8STreehugger Robot if (!ptr) return;
188*7c3d14c8STreehugger Robot }
189*7c3d14c8STreehugger Robot
_Block_assign_weak_default(const void * ptr,void * dest)190*7c3d14c8STreehugger Robot static void _Block_assign_weak_default(const void *ptr, void *dest) {
191*7c3d14c8STreehugger Robot *(void **)dest = (void *)ptr;
192*7c3d14c8STreehugger Robot }
193*7c3d14c8STreehugger Robot
_Block_memmove_default(void * dst,void * src,unsigned long size)194*7c3d14c8STreehugger Robot static void _Block_memmove_default(void *dst, void *src, unsigned long size) {
195*7c3d14c8STreehugger Robot memmove(dst, src, (size_t)size);
196*7c3d14c8STreehugger Robot }
197*7c3d14c8STreehugger Robot
_Block_memmove_gc_broken(void * dest,void * src,unsigned long size)198*7c3d14c8STreehugger Robot static void _Block_memmove_gc_broken(void *dest, void *src, unsigned long size) {
199*7c3d14c8STreehugger Robot void **destp = (void **)dest;
200*7c3d14c8STreehugger Robot void **srcp = (void **)src;
201*7c3d14c8STreehugger Robot while (size) {
202*7c3d14c8STreehugger Robot _Block_assign_default(*srcp, destp);
203*7c3d14c8STreehugger Robot destp++;
204*7c3d14c8STreehugger Robot srcp++;
205*7c3d14c8STreehugger Robot size -= sizeof(void *);
206*7c3d14c8STreehugger Robot }
207*7c3d14c8STreehugger Robot }
208*7c3d14c8STreehugger Robot
209*7c3d14c8STreehugger Robot /*
210*7c3d14c8STreehugger Robot * GC support callout functions - initially set to stub routines:
211*7c3d14c8STreehugger Robot */
212*7c3d14c8STreehugger Robot
213*7c3d14c8STreehugger Robot static void *(*_Block_allocator)(const unsigned long, const bool isOne, const bool isObject) = _Block_alloc_default;
214*7c3d14c8STreehugger Robot static void (*_Block_deallocator)(const void *) = (void (*)(const void *))free;
215*7c3d14c8STreehugger Robot static void (*_Block_assign)(void *value, void **destptr) = _Block_assign_default;
216*7c3d14c8STreehugger Robot static void (*_Block_setHasRefcount)(const void *ptr, const bool hasRefcount) = _Block_setHasRefcount_default;
217*7c3d14c8STreehugger Robot static void (*_Block_retain_object)(const void *ptr) = _Block_retain_object_default;
218*7c3d14c8STreehugger Robot static void (*_Block_release_object)(const void *ptr) = _Block_release_object_default;
219*7c3d14c8STreehugger Robot static void (*_Block_assign_weak)(const void *dest, void *ptr) = _Block_assign_weak_default;
220*7c3d14c8STreehugger Robot static void (*_Block_memmove)(void *dest, void *src, unsigned long size) = _Block_memmove_default;
221*7c3d14c8STreehugger Robot
222*7c3d14c8STreehugger Robot
223*7c3d14c8STreehugger Robot /*
224*7c3d14c8STreehugger Robot * GC support SPI functions - called from ObjC runtime and CoreFoundation:
225*7c3d14c8STreehugger Robot */
226*7c3d14c8STreehugger Robot
227*7c3d14c8STreehugger Robot /* Public SPI
228*7c3d14c8STreehugger Robot * Called from objc-auto to turn on GC.
229*7c3d14c8STreehugger Robot * version 3, 4 arg, but changed 1st arg
230*7c3d14c8STreehugger Robot */
_Block_use_GC(void * (* alloc)(const unsigned long,const bool isOne,const bool isObject),void (* setHasRefcount)(const void *,const bool),void (* gc_assign)(void *,void **),void (* gc_assign_weak)(const void *,void *),void (* gc_memmove)(void *,void *,unsigned long))231*7c3d14c8STreehugger Robot void _Block_use_GC( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
232*7c3d14c8STreehugger Robot void (*setHasRefcount)(const void *, const bool),
233*7c3d14c8STreehugger Robot void (*gc_assign)(void *, void **),
234*7c3d14c8STreehugger Robot void (*gc_assign_weak)(const void *, void *),
235*7c3d14c8STreehugger Robot void (*gc_memmove)(void *, void *, unsigned long)) {
236*7c3d14c8STreehugger Robot
237*7c3d14c8STreehugger Robot isGC = true;
238*7c3d14c8STreehugger Robot _Block_allocator = alloc;
239*7c3d14c8STreehugger Robot _Block_deallocator = _Block_do_nothing;
240*7c3d14c8STreehugger Robot _Block_assign = gc_assign;
241*7c3d14c8STreehugger Robot _Block_copy_flag = BLOCK_IS_GC;
242*7c3d14c8STreehugger Robot _Block_copy_class = _NSConcreteAutoBlock;
243*7c3d14c8STreehugger Robot /* blocks with ctors & dtors need to have the dtor run from a class with a finalizer */
244*7c3d14c8STreehugger Robot _Block_copy_finalizing_class = _NSConcreteFinalizingBlock;
245*7c3d14c8STreehugger Robot _Block_setHasRefcount = setHasRefcount;
246*7c3d14c8STreehugger Robot _Byref_flag_initial_value = BLOCK_IS_GC; // no refcount
247*7c3d14c8STreehugger Robot _Block_retain_object = _Block_do_nothing;
248*7c3d14c8STreehugger Robot _Block_release_object = _Block_do_nothing;
249*7c3d14c8STreehugger Robot _Block_assign_weak = gc_assign_weak;
250*7c3d14c8STreehugger Robot _Block_memmove = gc_memmove;
251*7c3d14c8STreehugger Robot }
252*7c3d14c8STreehugger Robot
253*7c3d14c8STreehugger Robot /* transitional */
_Block_use_GC5(void * (* alloc)(const unsigned long,const bool isOne,const bool isObject),void (* setHasRefcount)(const void *,const bool),void (* gc_assign)(void *,void **),void (* gc_assign_weak)(const void *,void *))254*7c3d14c8STreehugger Robot void _Block_use_GC5( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
255*7c3d14c8STreehugger Robot void (*setHasRefcount)(const void *, const bool),
256*7c3d14c8STreehugger Robot void (*gc_assign)(void *, void **),
257*7c3d14c8STreehugger Robot void (*gc_assign_weak)(const void *, void *)) {
258*7c3d14c8STreehugger Robot /* until objc calls _Block_use_GC it will call us; supply a broken internal memmove implementation until then */
259*7c3d14c8STreehugger Robot _Block_use_GC(alloc, setHasRefcount, gc_assign, gc_assign_weak, _Block_memmove_gc_broken);
260*7c3d14c8STreehugger Robot }
261*7c3d14c8STreehugger Robot
262*7c3d14c8STreehugger Robot
263*7c3d14c8STreehugger Robot /*
264*7c3d14c8STreehugger Robot * Called from objc-auto to alternatively turn on retain/release.
265*7c3d14c8STreehugger Robot * Prior to this the only "object" support we can provide is for those
266*7c3d14c8STreehugger Robot * super special objects that live in libSystem, namely dispatch queues.
267*7c3d14c8STreehugger Robot * Blocks and Block_byrefs have their own special entry points.
268*7c3d14c8STreehugger Robot *
269*7c3d14c8STreehugger Robot */
_Block_use_RR(void (* retain)(const void *),void (* release)(const void *))270*7c3d14c8STreehugger Robot void _Block_use_RR( void (*retain)(const void *),
271*7c3d14c8STreehugger Robot void (*release)(const void *)) {
272*7c3d14c8STreehugger Robot _Block_retain_object = retain;
273*7c3d14c8STreehugger Robot _Block_release_object = release;
274*7c3d14c8STreehugger Robot }
275*7c3d14c8STreehugger Robot
276*7c3d14c8STreehugger Robot /*
277*7c3d14c8STreehugger Robot * Internal Support routines for copying:
278*7c3d14c8STreehugger Robot */
279*7c3d14c8STreehugger Robot
280*7c3d14c8STreehugger Robot #if 0
281*7c3d14c8STreehugger Robot #pragma mark Copy/Release support
282*7c3d14c8STreehugger Robot #endif /* if 0 */
283*7c3d14c8STreehugger Robot
284*7c3d14c8STreehugger Robot /* Copy, or bump refcount, of a block. If really copying, call the copy helper if present. */
_Block_copy_internal(const void * arg,const int flags)285*7c3d14c8STreehugger Robot static void *_Block_copy_internal(const void *arg, const int flags) {
286*7c3d14c8STreehugger Robot struct Block_layout *aBlock;
287*7c3d14c8STreehugger Robot const bool wantsOne = (WANTS_ONE & flags) == WANTS_ONE;
288*7c3d14c8STreehugger Robot
289*7c3d14c8STreehugger Robot //printf("_Block_copy_internal(%p, %x)\n", arg, flags);
290*7c3d14c8STreehugger Robot if (!arg) return NULL;
291*7c3d14c8STreehugger Robot
292*7c3d14c8STreehugger Robot
293*7c3d14c8STreehugger Robot // The following would be better done as a switch statement
294*7c3d14c8STreehugger Robot aBlock = (struct Block_layout *)arg;
295*7c3d14c8STreehugger Robot if (aBlock->flags & BLOCK_NEEDS_FREE) {
296*7c3d14c8STreehugger Robot // latches on high
297*7c3d14c8STreehugger Robot latching_incr_int(&aBlock->flags);
298*7c3d14c8STreehugger Robot return aBlock;
299*7c3d14c8STreehugger Robot }
300*7c3d14c8STreehugger Robot else if (aBlock->flags & BLOCK_IS_GC) {
301*7c3d14c8STreehugger Robot // GC refcounting is expensive so do most refcounting here.
302*7c3d14c8STreehugger Robot if (wantsOne && ((latching_incr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK) == 1)) {
303*7c3d14c8STreehugger Robot // Tell collector to hang on this - it will bump the GC refcount version
304*7c3d14c8STreehugger Robot _Block_setHasRefcount(aBlock, true);
305*7c3d14c8STreehugger Robot }
306*7c3d14c8STreehugger Robot return aBlock;
307*7c3d14c8STreehugger Robot }
308*7c3d14c8STreehugger Robot else if (aBlock->flags & BLOCK_IS_GLOBAL) {
309*7c3d14c8STreehugger Robot return aBlock;
310*7c3d14c8STreehugger Robot }
311*7c3d14c8STreehugger Robot
312*7c3d14c8STreehugger Robot // Its a stack block. Make a copy.
313*7c3d14c8STreehugger Robot if (!isGC) {
314*7c3d14c8STreehugger Robot struct Block_layout *result = malloc(aBlock->descriptor->size);
315*7c3d14c8STreehugger Robot if (!result) return (void *)0;
316*7c3d14c8STreehugger Robot memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
317*7c3d14c8STreehugger Robot // reset refcount
318*7c3d14c8STreehugger Robot result->flags &= ~(BLOCK_REFCOUNT_MASK); // XXX not needed
319*7c3d14c8STreehugger Robot result->flags |= BLOCK_NEEDS_FREE | 1;
320*7c3d14c8STreehugger Robot result->isa = _NSConcreteMallocBlock;
321*7c3d14c8STreehugger Robot if (result->flags & BLOCK_HAS_COPY_DISPOSE) {
322*7c3d14c8STreehugger Robot //printf("calling block copy helper %p(%p, %p)...\n", aBlock->descriptor->copy, result, aBlock);
323*7c3d14c8STreehugger Robot (*aBlock->descriptor->copy)(result, aBlock); // do fixup
324*7c3d14c8STreehugger Robot }
325*7c3d14c8STreehugger Robot return result;
326*7c3d14c8STreehugger Robot }
327*7c3d14c8STreehugger Robot else {
328*7c3d14c8STreehugger Robot // Under GC want allocation with refcount 1 so we ask for "true" if wantsOne
329*7c3d14c8STreehugger Robot // This allows the copy helper routines to make non-refcounted block copies under GC
330*7c3d14c8STreehugger Robot unsigned long int flags = aBlock->flags;
331*7c3d14c8STreehugger Robot bool hasCTOR = (flags & BLOCK_HAS_CTOR) != 0;
332*7c3d14c8STreehugger Robot struct Block_layout *result = _Block_allocator(aBlock->descriptor->size, wantsOne, hasCTOR);
333*7c3d14c8STreehugger Robot if (!result) return (void *)0;
334*7c3d14c8STreehugger Robot memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
335*7c3d14c8STreehugger Robot // reset refcount
336*7c3d14c8STreehugger Robot // if we copy a malloc block to a GC block then we need to clear NEEDS_FREE.
337*7c3d14c8STreehugger Robot flags &= ~(BLOCK_NEEDS_FREE|BLOCK_REFCOUNT_MASK); // XXX not needed
338*7c3d14c8STreehugger Robot if (wantsOne)
339*7c3d14c8STreehugger Robot flags |= BLOCK_IS_GC | 1;
340*7c3d14c8STreehugger Robot else
341*7c3d14c8STreehugger Robot flags |= BLOCK_IS_GC;
342*7c3d14c8STreehugger Robot result->flags = flags;
343*7c3d14c8STreehugger Robot if (flags & BLOCK_HAS_COPY_DISPOSE) {
344*7c3d14c8STreehugger Robot //printf("calling block copy helper...\n");
345*7c3d14c8STreehugger Robot (*aBlock->descriptor->copy)(result, aBlock); // do fixup
346*7c3d14c8STreehugger Robot }
347*7c3d14c8STreehugger Robot if (hasCTOR) {
348*7c3d14c8STreehugger Robot result->isa = _NSConcreteFinalizingBlock;
349*7c3d14c8STreehugger Robot }
350*7c3d14c8STreehugger Robot else {
351*7c3d14c8STreehugger Robot result->isa = _NSConcreteAutoBlock;
352*7c3d14c8STreehugger Robot }
353*7c3d14c8STreehugger Robot return result;
354*7c3d14c8STreehugger Robot }
355*7c3d14c8STreehugger Robot }
356*7c3d14c8STreehugger Robot
357*7c3d14c8STreehugger Robot
358*7c3d14c8STreehugger Robot /*
359*7c3d14c8STreehugger Robot * Runtime entry points for maintaining the sharing knowledge of byref data blocks.
360*7c3d14c8STreehugger Robot *
361*7c3d14c8STreehugger Robot * A closure has been copied and its fixup routine is asking us to fix up the reference to the shared byref data
362*7c3d14c8STreehugger Robot * Closures that aren't copied must still work, so everyone always accesses variables after dereferencing the forwarding ptr.
363*7c3d14c8STreehugger Robot * We ask if the byref pointer that we know about has already been copied to the heap, and if so, increment it.
364*7c3d14c8STreehugger Robot * Otherwise we need to copy it and update the stack forwarding pointer
365*7c3d14c8STreehugger Robot * XXX We need to account for weak/nonretained read-write barriers.
366*7c3d14c8STreehugger Robot */
367*7c3d14c8STreehugger Robot
_Block_byref_assign_copy(void * dest,const void * arg,const int flags)368*7c3d14c8STreehugger Robot static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) {
369*7c3d14c8STreehugger Robot struct Block_byref **destp = (struct Block_byref **)dest;
370*7c3d14c8STreehugger Robot struct Block_byref *src = (struct Block_byref *)arg;
371*7c3d14c8STreehugger Robot
372*7c3d14c8STreehugger Robot //printf("_Block_byref_assign_copy called, byref destp %p, src %p, flags %x\n", destp, src, flags);
373*7c3d14c8STreehugger Robot //printf("src dump: %s\n", _Block_byref_dump(src));
374*7c3d14c8STreehugger Robot if (src->forwarding->flags & BLOCK_IS_GC) {
375*7c3d14c8STreehugger Robot ; // don't need to do any more work
376*7c3d14c8STreehugger Robot }
377*7c3d14c8STreehugger Robot else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
378*7c3d14c8STreehugger Robot //printf("making copy\n");
379*7c3d14c8STreehugger Robot // src points to stack
380*7c3d14c8STreehugger Robot bool isWeak = ((flags & (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)) == (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK));
381*7c3d14c8STreehugger Robot // if its weak ask for an object (only matters under GC)
382*7c3d14c8STreehugger Robot struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak);
383*7c3d14c8STreehugger Robot copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack
384*7c3d14c8STreehugger Robot copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier)
385*7c3d14c8STreehugger Robot src->forwarding = copy; // patch stack to point to heap copy
386*7c3d14c8STreehugger Robot copy->size = src->size;
387*7c3d14c8STreehugger Robot if (isWeak) {
388*7c3d14c8STreehugger Robot copy->isa = &_NSConcreteWeakBlockVariable; // mark isa field so it gets weak scanning
389*7c3d14c8STreehugger Robot }
390*7c3d14c8STreehugger Robot if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
391*7c3d14c8STreehugger Robot // Trust copy helper to copy everything of interest
392*7c3d14c8STreehugger Robot // If more than one field shows up in a byref block this is wrong XXX
393*7c3d14c8STreehugger Robot copy->byref_keep = src->byref_keep;
394*7c3d14c8STreehugger Robot copy->byref_destroy = src->byref_destroy;
395*7c3d14c8STreehugger Robot (*src->byref_keep)(copy, src);
396*7c3d14c8STreehugger Robot }
397*7c3d14c8STreehugger Robot else {
398*7c3d14c8STreehugger Robot // just bits. Blast 'em using _Block_memmove in case they're __strong
399*7c3d14c8STreehugger Robot _Block_memmove(
400*7c3d14c8STreehugger Robot (void *)©->byref_keep,
401*7c3d14c8STreehugger Robot (void *)&src->byref_keep,
402*7c3d14c8STreehugger Robot src->size - sizeof(struct Block_byref_header));
403*7c3d14c8STreehugger Robot }
404*7c3d14c8STreehugger Robot }
405*7c3d14c8STreehugger Robot // already copied to heap
406*7c3d14c8STreehugger Robot else if ((src->forwarding->flags & BLOCK_NEEDS_FREE) == BLOCK_NEEDS_FREE) {
407*7c3d14c8STreehugger Robot latching_incr_int(&src->forwarding->flags);
408*7c3d14c8STreehugger Robot }
409*7c3d14c8STreehugger Robot // assign byref data block pointer into new Block
410*7c3d14c8STreehugger Robot _Block_assign(src->forwarding, (void **)destp);
411*7c3d14c8STreehugger Robot }
412*7c3d14c8STreehugger Robot
413*7c3d14c8STreehugger Robot // Old compiler SPI
_Block_byref_release(const void * arg)414*7c3d14c8STreehugger Robot static void _Block_byref_release(const void *arg) {
415*7c3d14c8STreehugger Robot struct Block_byref *shared_struct = (struct Block_byref *)arg;
416*7c3d14c8STreehugger Robot int refcount;
417*7c3d14c8STreehugger Robot
418*7c3d14c8STreehugger Robot // dereference the forwarding pointer since the compiler isn't doing this anymore (ever?)
419*7c3d14c8STreehugger Robot shared_struct = shared_struct->forwarding;
420*7c3d14c8STreehugger Robot
421*7c3d14c8STreehugger Robot //printf("_Block_byref_release %p called, flags are %x\n", shared_struct, shared_struct->flags);
422*7c3d14c8STreehugger Robot // To support C++ destructors under GC we arrange for there to be a finalizer for this
423*7c3d14c8STreehugger Robot // by using an isa that directs the code to a finalizer that calls the byref_destroy method.
424*7c3d14c8STreehugger Robot if ((shared_struct->flags & BLOCK_NEEDS_FREE) == 0) {
425*7c3d14c8STreehugger Robot return; // stack or GC or global
426*7c3d14c8STreehugger Robot }
427*7c3d14c8STreehugger Robot refcount = shared_struct->flags & BLOCK_REFCOUNT_MASK;
428*7c3d14c8STreehugger Robot if (refcount <= 0) {
429*7c3d14c8STreehugger Robot printf("_Block_byref_release: Block byref data structure at %p underflowed\n", arg);
430*7c3d14c8STreehugger Robot }
431*7c3d14c8STreehugger Robot else if ((latching_decr_int(&shared_struct->flags) & BLOCK_REFCOUNT_MASK) == 0) {
432*7c3d14c8STreehugger Robot //printf("disposing of heap based byref block\n");
433*7c3d14c8STreehugger Robot if (shared_struct->flags & BLOCK_HAS_COPY_DISPOSE) {
434*7c3d14c8STreehugger Robot //printf("calling out to helper\n");
435*7c3d14c8STreehugger Robot (*shared_struct->byref_destroy)(shared_struct);
436*7c3d14c8STreehugger Robot }
437*7c3d14c8STreehugger Robot _Block_deallocator((struct Block_layout *)shared_struct);
438*7c3d14c8STreehugger Robot }
439*7c3d14c8STreehugger Robot }
440*7c3d14c8STreehugger Robot
441*7c3d14c8STreehugger Robot
442*7c3d14c8STreehugger Robot /*
443*7c3d14c8STreehugger Robot *
444*7c3d14c8STreehugger Robot * API supporting SPI
445*7c3d14c8STreehugger Robot * _Block_copy, _Block_release, and (old) _Block_destroy
446*7c3d14c8STreehugger Robot *
447*7c3d14c8STreehugger Robot */
448*7c3d14c8STreehugger Robot
449*7c3d14c8STreehugger Robot #if 0
450*7c3d14c8STreehugger Robot #pragma mark SPI/API
451*7c3d14c8STreehugger Robot #endif /* if 0 */
452*7c3d14c8STreehugger Robot
_Block_copy(const void * arg)453*7c3d14c8STreehugger Robot void *_Block_copy(const void *arg) {
454*7c3d14c8STreehugger Robot return _Block_copy_internal(arg, WANTS_ONE);
455*7c3d14c8STreehugger Robot }
456*7c3d14c8STreehugger Robot
457*7c3d14c8STreehugger Robot
458*7c3d14c8STreehugger Robot // API entry point to release a copied Block
_Block_release(void * arg)459*7c3d14c8STreehugger Robot void _Block_release(void *arg) {
460*7c3d14c8STreehugger Robot struct Block_layout *aBlock = (struct Block_layout *)arg;
461*7c3d14c8STreehugger Robot int32_t newCount;
462*7c3d14c8STreehugger Robot if (!aBlock) return;
463*7c3d14c8STreehugger Robot newCount = latching_decr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK;
464*7c3d14c8STreehugger Robot if (newCount > 0) return;
465*7c3d14c8STreehugger Robot // Hit zero
466*7c3d14c8STreehugger Robot if (aBlock->flags & BLOCK_IS_GC) {
467*7c3d14c8STreehugger Robot // Tell GC we no longer have our own refcounts. GC will decr its refcount
468*7c3d14c8STreehugger Robot // and unless someone has done a CFRetain or marked it uncollectable it will
469*7c3d14c8STreehugger Robot // now be subject to GC reclamation.
470*7c3d14c8STreehugger Robot _Block_setHasRefcount(aBlock, false);
471*7c3d14c8STreehugger Robot }
472*7c3d14c8STreehugger Robot else if (aBlock->flags & BLOCK_NEEDS_FREE) {
473*7c3d14c8STreehugger Robot if (aBlock->flags & BLOCK_HAS_COPY_DISPOSE)(*aBlock->descriptor->dispose)(aBlock);
474*7c3d14c8STreehugger Robot _Block_deallocator(aBlock);
475*7c3d14c8STreehugger Robot }
476*7c3d14c8STreehugger Robot else if (aBlock->flags & BLOCK_IS_GLOBAL) {
477*7c3d14c8STreehugger Robot ;
478*7c3d14c8STreehugger Robot }
479*7c3d14c8STreehugger Robot else {
480*7c3d14c8STreehugger Robot printf("Block_release called upon a stack Block: %p, ignored\n", (void *)aBlock);
481*7c3d14c8STreehugger Robot }
482*7c3d14c8STreehugger Robot }
483*7c3d14c8STreehugger Robot
484*7c3d14c8STreehugger Robot
485*7c3d14c8STreehugger Robot
486*7c3d14c8STreehugger Robot // Old Compiler SPI point to release a copied Block used by the compiler in dispose helpers
_Block_destroy(const void * arg)487*7c3d14c8STreehugger Robot static void _Block_destroy(const void *arg) {
488*7c3d14c8STreehugger Robot struct Block_layout *aBlock;
489*7c3d14c8STreehugger Robot if (!arg) return;
490*7c3d14c8STreehugger Robot aBlock = (struct Block_layout *)arg;
491*7c3d14c8STreehugger Robot if (aBlock->flags & BLOCK_IS_GC) {
492*7c3d14c8STreehugger Robot // assert(aBlock->Block_flags & BLOCK_HAS_CTOR);
493*7c3d14c8STreehugger Robot return; // ignore, we are being called because of a DTOR
494*7c3d14c8STreehugger Robot }
495*7c3d14c8STreehugger Robot _Block_release(aBlock);
496*7c3d14c8STreehugger Robot }
497*7c3d14c8STreehugger Robot
498*7c3d14c8STreehugger Robot
499*7c3d14c8STreehugger Robot
500*7c3d14c8STreehugger Robot /*
501*7c3d14c8STreehugger Robot *
502*7c3d14c8STreehugger Robot * SPI used by other layers
503*7c3d14c8STreehugger Robot *
504*7c3d14c8STreehugger Robot */
505*7c3d14c8STreehugger Robot
506*7c3d14c8STreehugger Robot // SPI, also internal. Called from NSAutoBlock only under GC
_Block_copy_collectable(const void * aBlock)507*7c3d14c8STreehugger Robot void *_Block_copy_collectable(const void *aBlock) {
508*7c3d14c8STreehugger Robot return _Block_copy_internal(aBlock, 0);
509*7c3d14c8STreehugger Robot }
510*7c3d14c8STreehugger Robot
511*7c3d14c8STreehugger Robot
512*7c3d14c8STreehugger Robot // SPI
Block_size(void * arg)513*7c3d14c8STreehugger Robot unsigned long int Block_size(void *arg) {
514*7c3d14c8STreehugger Robot return ((struct Block_layout *)arg)->descriptor->size;
515*7c3d14c8STreehugger Robot }
516*7c3d14c8STreehugger Robot
517*7c3d14c8STreehugger Robot
518*7c3d14c8STreehugger Robot #if 0
519*7c3d14c8STreehugger Robot #pragma mark Compiler SPI entry points
520*7c3d14c8STreehugger Robot #endif /* if 0 */
521*7c3d14c8STreehugger Robot
522*7c3d14c8STreehugger Robot
523*7c3d14c8STreehugger Robot /*******************************************************
524*7c3d14c8STreehugger Robot
525*7c3d14c8STreehugger Robot Entry points used by the compiler - the real API!
526*7c3d14c8STreehugger Robot
527*7c3d14c8STreehugger Robot
528*7c3d14c8STreehugger Robot A Block can reference four different kinds of things that require help when the Block is copied to the heap.
529*7c3d14c8STreehugger Robot 1) C++ stack based objects
530*7c3d14c8STreehugger Robot 2) References to Objective-C objects
531*7c3d14c8STreehugger Robot 3) Other Blocks
532*7c3d14c8STreehugger Robot 4) __block variables
533*7c3d14c8STreehugger Robot
534*7c3d14c8STreehugger Robot 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.
535*7c3d14c8STreehugger Robot
536*7c3d14c8STreehugger Robot The flags parameter of _Block_object_assign and _Block_object_dispose is set to
537*7c3d14c8STreehugger Robot * BLOCK_FIELD_IS_OBJECT (3), for the case of an Objective-C Object,
538*7c3d14c8STreehugger Robot * BLOCK_FIELD_IS_BLOCK (7), for the case of another Block, and
539*7c3d14c8STreehugger Robot * BLOCK_FIELD_IS_BYREF (8), for the case of a __block variable.
540*7c3d14c8STreehugger Robot If the __block variable is marked weak the compiler also or's in BLOCK_FIELD_IS_WEAK (16).
541*7c3d14c8STreehugger Robot
542*7c3d14c8STreehugger Robot So the Block copy/dispose helpers should only ever generate the four flag values of 3, 7, 8, and 24.
543*7c3d14c8STreehugger Robot
544*7c3d14c8STreehugger Robot 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.
545*7c3d14c8STreehugger Robot
546*7c3d14c8STreehugger Robot 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:
547*7c3d14c8STreehugger Robot __block id 128+3
548*7c3d14c8STreehugger Robot __weak block id 128+3+16
549*7c3d14c8STreehugger Robot __block (^Block) 128+7
550*7c3d14c8STreehugger Robot __weak __block (^Block) 128+7+16
551*7c3d14c8STreehugger Robot
552*7c3d14c8STreehugger Robot The implementation of the two routines would be improved by switch statements enumerating the eight cases.
553*7c3d14c8STreehugger Robot
554*7c3d14c8STreehugger Robot ********************************************************/
555*7c3d14c8STreehugger Robot
556*7c3d14c8STreehugger Robot /*
557*7c3d14c8STreehugger Robot * When Blocks or Block_byrefs hold objects then their copy routine helpers use this entry point
558*7c3d14c8STreehugger Robot * to do the assignment.
559*7c3d14c8STreehugger Robot */
_Block_object_assign(void * destAddr,const void * object,const int flags)560*7c3d14c8STreehugger Robot void _Block_object_assign(void *destAddr, const void *object, const int flags) {
561*7c3d14c8STreehugger Robot //printf("_Block_object_assign(*%p, %p, %x)\n", destAddr, object, flags);
562*7c3d14c8STreehugger Robot if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) {
563*7c3d14c8STreehugger Robot if ((flags & BLOCK_FIELD_IS_WEAK) == BLOCK_FIELD_IS_WEAK) {
564*7c3d14c8STreehugger Robot _Block_assign_weak(object, destAddr);
565*7c3d14c8STreehugger Robot }
566*7c3d14c8STreehugger Robot else {
567*7c3d14c8STreehugger Robot // do *not* retain or *copy* __block variables whatever they are
568*7c3d14c8STreehugger Robot _Block_assign((void *)object, destAddr);
569*7c3d14c8STreehugger Robot }
570*7c3d14c8STreehugger Robot }
571*7c3d14c8STreehugger Robot else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF) {
572*7c3d14c8STreehugger Robot // copying a __block reference from the stack Block to the heap
573*7c3d14c8STreehugger Robot // flags will indicate if it holds a __weak reference and needs a special isa
574*7c3d14c8STreehugger Robot _Block_byref_assign_copy(destAddr, object, flags);
575*7c3d14c8STreehugger Robot }
576*7c3d14c8STreehugger Robot // (this test must be before next one)
577*7c3d14c8STreehugger Robot else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) {
578*7c3d14c8STreehugger Robot // copying a Block declared variable from the stack Block to the heap
579*7c3d14c8STreehugger Robot _Block_assign(_Block_copy_internal(object, flags), destAddr);
580*7c3d14c8STreehugger Robot }
581*7c3d14c8STreehugger Robot // (this test must be after previous one)
582*7c3d14c8STreehugger Robot else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) {
583*7c3d14c8STreehugger Robot //printf("retaining object at %p\n", object);
584*7c3d14c8STreehugger Robot _Block_retain_object(object);
585*7c3d14c8STreehugger Robot //printf("done retaining object at %p\n", object);
586*7c3d14c8STreehugger Robot _Block_assign((void *)object, destAddr);
587*7c3d14c8STreehugger Robot }
588*7c3d14c8STreehugger Robot }
589*7c3d14c8STreehugger Robot
590*7c3d14c8STreehugger Robot // When Blocks or Block_byrefs hold objects their destroy helper routines call this entry point
591*7c3d14c8STreehugger Robot // to help dispose of the contents
592*7c3d14c8STreehugger Robot // Used initially only for __attribute__((NSObject)) marked pointers.
_Block_object_dispose(const void * object,const int flags)593*7c3d14c8STreehugger Robot void _Block_object_dispose(const void *object, const int flags) {
594*7c3d14c8STreehugger Robot //printf("_Block_object_dispose(%p, %x)\n", object, flags);
595*7c3d14c8STreehugger Robot if (flags & BLOCK_FIELD_IS_BYREF) {
596*7c3d14c8STreehugger Robot // get rid of the __block data structure held in a Block
597*7c3d14c8STreehugger Robot _Block_byref_release(object);
598*7c3d14c8STreehugger Robot }
599*7c3d14c8STreehugger Robot else if ((flags & (BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_BLOCK) {
600*7c3d14c8STreehugger Robot // get rid of a referenced Block held by this Block
601*7c3d14c8STreehugger Robot // (ignore __block Block variables, compiler doesn't need to call us)
602*7c3d14c8STreehugger Robot _Block_destroy(object);
603*7c3d14c8STreehugger Robot }
604*7c3d14c8STreehugger Robot else if ((flags & (BLOCK_FIELD_IS_WEAK|BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_OBJECT) {
605*7c3d14c8STreehugger Robot // get rid of a referenced object held by this Block
606*7c3d14c8STreehugger Robot // (ignore __block object variables, compiler doesn't need to call us)
607*7c3d14c8STreehugger Robot _Block_release_object(object);
608*7c3d14c8STreehugger Robot }
609*7c3d14c8STreehugger Robot }
610*7c3d14c8STreehugger Robot
611*7c3d14c8STreehugger Robot
612*7c3d14c8STreehugger Robot /*
613*7c3d14c8STreehugger Robot * Debugging support:
614*7c3d14c8STreehugger Robot */
615*7c3d14c8STreehugger Robot #if 0
616*7c3d14c8STreehugger Robot #pragma mark Debugging
617*7c3d14c8STreehugger Robot #endif /* if 0 */
618*7c3d14c8STreehugger Robot
619*7c3d14c8STreehugger Robot
_Block_dump(const void * block)620*7c3d14c8STreehugger Robot const char *_Block_dump(const void *block) {
621*7c3d14c8STreehugger Robot struct Block_layout *closure = (struct Block_layout *)block;
622*7c3d14c8STreehugger Robot static char buffer[512];
623*7c3d14c8STreehugger Robot char *cp = buffer;
624*7c3d14c8STreehugger Robot if (closure == NULL) {
625*7c3d14c8STreehugger Robot sprintf(cp, "NULL passed to _Block_dump\n");
626*7c3d14c8STreehugger Robot return buffer;
627*7c3d14c8STreehugger Robot }
628*7c3d14c8STreehugger Robot if (! (closure->flags & BLOCK_HAS_DESCRIPTOR)) {
629*7c3d14c8STreehugger Robot printf("Block compiled by obsolete compiler, please recompile source for this Block\n");
630*7c3d14c8STreehugger Robot exit(1);
631*7c3d14c8STreehugger Robot }
632*7c3d14c8STreehugger Robot cp += sprintf(cp, "^%p (new layout) =\n", (void *)closure);
633*7c3d14c8STreehugger Robot if (closure->isa == NULL) {
634*7c3d14c8STreehugger Robot cp += sprintf(cp, "isa: NULL\n");
635*7c3d14c8STreehugger Robot }
636*7c3d14c8STreehugger Robot else if (closure->isa == _NSConcreteStackBlock) {
637*7c3d14c8STreehugger Robot cp += sprintf(cp, "isa: stack Block\n");
638*7c3d14c8STreehugger Robot }
639*7c3d14c8STreehugger Robot else if (closure->isa == _NSConcreteMallocBlock) {
640*7c3d14c8STreehugger Robot cp += sprintf(cp, "isa: malloc heap Block\n");
641*7c3d14c8STreehugger Robot }
642*7c3d14c8STreehugger Robot else if (closure->isa == _NSConcreteAutoBlock) {
643*7c3d14c8STreehugger Robot cp += sprintf(cp, "isa: GC heap Block\n");
644*7c3d14c8STreehugger Robot }
645*7c3d14c8STreehugger Robot else if (closure->isa == _NSConcreteGlobalBlock) {
646*7c3d14c8STreehugger Robot cp += sprintf(cp, "isa: global Block\n");
647*7c3d14c8STreehugger Robot }
648*7c3d14c8STreehugger Robot else if (closure->isa == _NSConcreteFinalizingBlock) {
649*7c3d14c8STreehugger Robot cp += sprintf(cp, "isa: finalizing Block\n");
650*7c3d14c8STreehugger Robot }
651*7c3d14c8STreehugger Robot else {
652*7c3d14c8STreehugger Robot cp += sprintf(cp, "isa?: %p\n", (void *)closure->isa);
653*7c3d14c8STreehugger Robot }
654*7c3d14c8STreehugger Robot cp += sprintf(cp, "flags:");
655*7c3d14c8STreehugger Robot if (closure->flags & BLOCK_HAS_DESCRIPTOR) {
656*7c3d14c8STreehugger Robot cp += sprintf(cp, " HASDESCRIPTOR");
657*7c3d14c8STreehugger Robot }
658*7c3d14c8STreehugger Robot if (closure->flags & BLOCK_NEEDS_FREE) {
659*7c3d14c8STreehugger Robot cp += sprintf(cp, " FREEME");
660*7c3d14c8STreehugger Robot }
661*7c3d14c8STreehugger Robot if (closure->flags & BLOCK_IS_GC) {
662*7c3d14c8STreehugger Robot cp += sprintf(cp, " ISGC");
663*7c3d14c8STreehugger Robot }
664*7c3d14c8STreehugger Robot if (closure->flags & BLOCK_HAS_COPY_DISPOSE) {
665*7c3d14c8STreehugger Robot cp += sprintf(cp, " HASHELP");
666*7c3d14c8STreehugger Robot }
667*7c3d14c8STreehugger Robot if (closure->flags & BLOCK_HAS_CTOR) {
668*7c3d14c8STreehugger Robot cp += sprintf(cp, " HASCTOR");
669*7c3d14c8STreehugger Robot }
670*7c3d14c8STreehugger Robot cp += sprintf(cp, "\nrefcount: %u\n", closure->flags & BLOCK_REFCOUNT_MASK);
671*7c3d14c8STreehugger Robot cp += sprintf(cp, "invoke: %p\n", (void *)(uintptr_t)closure->invoke);
672*7c3d14c8STreehugger Robot {
673*7c3d14c8STreehugger Robot struct Block_descriptor *dp = closure->descriptor;
674*7c3d14c8STreehugger Robot cp += sprintf(cp, "descriptor: %p\n", (void *)dp);
675*7c3d14c8STreehugger Robot cp += sprintf(cp, "descriptor->reserved: %lu\n", dp->reserved);
676*7c3d14c8STreehugger Robot cp += sprintf(cp, "descriptor->size: %lu\n", dp->size);
677*7c3d14c8STreehugger Robot
678*7c3d14c8STreehugger Robot if (closure->flags & BLOCK_HAS_COPY_DISPOSE) {
679*7c3d14c8STreehugger Robot cp += sprintf(cp, "descriptor->copy helper: %p\n", (void *)(uintptr_t)dp->copy);
680*7c3d14c8STreehugger Robot cp += sprintf(cp, "descriptor->dispose helper: %p\n", (void *)(uintptr_t)dp->dispose);
681*7c3d14c8STreehugger Robot }
682*7c3d14c8STreehugger Robot }
683*7c3d14c8STreehugger Robot return buffer;
684*7c3d14c8STreehugger Robot }
685*7c3d14c8STreehugger Robot
686*7c3d14c8STreehugger Robot
_Block_byref_dump(struct Block_byref * src)687*7c3d14c8STreehugger Robot const char *_Block_byref_dump(struct Block_byref *src) {
688*7c3d14c8STreehugger Robot static char buffer[256];
689*7c3d14c8STreehugger Robot char *cp = buffer;
690*7c3d14c8STreehugger Robot cp += sprintf(cp, "byref data block %p contents:\n", (void *)src);
691*7c3d14c8STreehugger Robot cp += sprintf(cp, " forwarding: %p\n", (void *)src->forwarding);
692*7c3d14c8STreehugger Robot cp += sprintf(cp, " flags: 0x%x\n", src->flags);
693*7c3d14c8STreehugger Robot cp += sprintf(cp, " size: %d\n", src->size);
694*7c3d14c8STreehugger Robot if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
695*7c3d14c8STreehugger Robot cp += sprintf(cp, " copy helper: %p\n", (void *)(uintptr_t)src->byref_keep);
696*7c3d14c8STreehugger Robot cp += sprintf(cp, " dispose helper: %p\n", (void *)(uintptr_t)src->byref_destroy);
697*7c3d14c8STreehugger Robot }
698*7c3d14c8STreehugger Robot return buffer;
699*7c3d14c8STreehugger Robot }
700*7c3d14c8STreehugger Robot
701