18cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar/*
2b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * runtime.c
3b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar *
4b1c07156bab839c0502789f09654ec5da8d33c39Blaine Garst * Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,
5b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * to any person obtaining a copy of this software and associated documentation
6b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * files (the "Software"), to deal in the Software without restriction,
7b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * including without limitation the rights to use, copy, modify, merge, publish,
8b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * distribute, sublicense, and/or sell copies of the Software, and to permit
9b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * persons to whom the Software is furnished to do so, subject to the following
10b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * conditions:
11b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar *
12b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * The above copyright notice and this permission notice shall be included in
13b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * all copies or substantial portions of the Software.
14b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar *
15b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar * SOFTWARE.
228cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar *
238cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar */
248cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
258cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar#include "Block_private.h"
268cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar#include <stdio.h>
278cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar#include <stdlib.h>
288cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar#include <string.h>
298cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar#include <stdint.h>
308cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
31b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen#include "config.h"
32b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen
33b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen#ifdef HAVE_AVAILABILITY_MACROS_H
34b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen#include <AvailabilityMacros.h>
35962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan#endif /* HAVE_AVAILABILITY_MACROS_H */
36b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen
37b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen#ifdef HAVE_TARGET_CONDITIONALS_H
38b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen#include <TargetConditionals.h>
39962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan#endif /* HAVE_TARGET_CONDITIONALS_H */
40b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen
41b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen#if defined(HAVE_OSATOMIC_COMPARE_AND_SWAP_INT) && defined(HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG)
42962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan
43b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen#ifdef HAVE_LIBKERN_OSATOMIC_H
448cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar#include <libkern/OSAtomic.h>
45962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan#endif /* HAVE_LIBKERN_OSATOMIC_H */
46962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan
47ffd69e7b181a486cbba10deb386558cf3ff5e24aCharles Davis#elif defined(__WIN32__) || defined(_WIN32)
488cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar#define _CRT_SECURE_NO_WARNINGS 1
498cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar#include <windows.h>
50962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan
51962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghanstatic __inline bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) {
52e8ce595140fa3f107db10a6b4d9184f7277e58c0Edward O'Callaghan    /* fixme barrier is overkill -- see objc-os.h */
538cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    long original = InterlockedCompareExchange(dst, newl, oldl);
548cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    return (original == oldl);
558cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
568cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
57962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghanstatic __inline bool OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile *dst) {
58e8ce595140fa3f107db10a6b4d9184f7277e58c0Edward O'Callaghan    /* fixme barrier is overkill -- see objc-os.h */
598cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    int original = InterlockedCompareExchange(dst, newi, oldi);
608cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    return (original == oldi);
618cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
62962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan
63962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/*
64962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * Check to see if the GCC atomic built-ins are available.  If we're on
65e8ce595140fa3f107db10a6b4d9184f7277e58c0Edward O'Callaghan * a 64-bit system, make sure we have an 8-byte atomic function
66e8ce595140fa3f107db10a6b4d9184f7277e58c0Edward O'Callaghan * available.
67962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan *
68e8ce595140fa3f107db10a6b4d9184f7277e58c0Edward O'Callaghan */
69962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan
70b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen#elif defined(HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT) && defined(HAVE_SYNC_BOOL_COMPARE_AND_SWAP_LONG)
71962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan
72962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghanstatic __inline bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) {
73e8ce595140fa3f107db10a6b4d9184f7277e58c0Edward O'Callaghan  return __sync_bool_compare_and_swap(dst, oldl, newl);
74e8ce595140fa3f107db10a6b4d9184f7277e58c0Edward O'Callaghan}
75e8ce595140fa3f107db10a6b4d9184f7277e58c0Edward O'Callaghan
76962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghanstatic __inline bool OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile *dst) {
77e8ce595140fa3f107db10a6b4d9184f7277e58c0Edward O'Callaghan  return __sync_bool_compare_and_swap(dst, oldi, newi);
78e8ce595140fa3f107db10a6b4d9184f7277e58c0Edward O'Callaghan}
79962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan
80b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen#else
81b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen#error unknown atomic compare-and-swap primitive
82962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan#endif /* HAVE_OSATOMIC_COMPARE_AND_SWAP_INT && HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG */
838cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
848cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
85962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/*
86962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * Globals:
87962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan */
888cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
898cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void *_Block_copy_class = _NSConcreteMallocBlock;
908cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void *_Block_copy_finalizing_class = _NSConcreteMallocBlock;
918cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic int _Block_copy_flag = BLOCK_NEEDS_FREE;
928cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic int _Byref_flag_initial_value = BLOCK_NEEDS_FREE | 2;
938cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
948cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic const int WANTS_ONE = (1 << 16);
958cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
968cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic bool isGC = false;
978cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
98962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/*
99962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * Internal Utilities:
100962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan */
1018cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
1028cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar#if 0
1038cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic unsigned long int latching_incr_long(unsigned long int *where) {
1048cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    while (1) {
1058cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        unsigned long int old_value = *(volatile unsigned long int *)where;
1068cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
1078cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            return BLOCK_REFCOUNT_MASK;
1088cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
1098cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (OSAtomicCompareAndSwapLong(old_value, old_value+1, (volatile long int *)where)) {
1108cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            return old_value+1;
1118cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
1128cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
1138cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
114962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan#endif /* if 0 */
1158cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
1168cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic int latching_incr_int(int *where) {
1178cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    while (1) {
1188cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        int old_value = *(volatile int *)where;
1198cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
1208cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            return BLOCK_REFCOUNT_MASK;
1218cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
1228cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (OSAtomicCompareAndSwapInt(old_value, old_value+1, (volatile int *)where)) {
1238cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            return old_value+1;
1248cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
1258cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
1268cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
1278cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
1288cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar#if 0
1298cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic int latching_decr_long(unsigned long int *where) {
1308cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    while (1) {
1318cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        unsigned long int old_value = *(volatile int *)where;
1328cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
1338cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            return BLOCK_REFCOUNT_MASK;
1348cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
1358cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if ((old_value & BLOCK_REFCOUNT_MASK) == 0) {
1368cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            return 0;
1378cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
1388cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (OSAtomicCompareAndSwapLong(old_value, old_value-1, (volatile long int *)where)) {
1398cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            return old_value-1;
1408cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
1418cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
1428cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
143962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan#endif /* if 0 */
1448cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
1458cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic int latching_decr_int(int *where) {
1468cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    while (1) {
1478cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        int old_value = *(volatile int *)where;
1488cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
1498cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            return BLOCK_REFCOUNT_MASK;
1508cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
1518cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if ((old_value & BLOCK_REFCOUNT_MASK) == 0) {
1528cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            return 0;
1538cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
1548cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (OSAtomicCompareAndSwapInt(old_value, old_value-1, (volatile int *)where)) {
1558cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            return old_value-1;
1568cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
1578cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
1588cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
1598cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
1608cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
161962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/*
162962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * GC support stub routines:
163962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan */
164b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen#if 0
1658cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar#pragma mark GC Support Routines
166962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan#endif /* if 0 */
1678cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
1688cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
1698cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void *_Block_alloc_default(const unsigned long size, const bool initialCountIsOne, const bool isObject) {
1708cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    return malloc(size);
1718cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
1728cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
1738cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void _Block_assign_default(void *value, void **destptr) {
1748cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    *destptr = value;
1758cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
1768cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
1778cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void _Block_setHasRefcount_default(const void *ptr, const bool hasRefcount) {
1788cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
1798cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
1808cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void _Block_do_nothing(const void *aBlock) { }
1818cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
1828cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void _Block_retain_object_default(const void *ptr) {
1838cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (!ptr) return;
1848cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
1858cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
1868cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void _Block_release_object_default(const void *ptr) {
1878cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (!ptr) return;
1888cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
1898cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
1908cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void _Block_assign_weak_default(const void *ptr, void *dest) {
1918cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    *(void **)dest = (void *)ptr;
1928cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
1938cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
1948cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void _Block_memmove_default(void *dst, void *src, unsigned long size) {
1958cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    memmove(dst, src, (size_t)size);
1968cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
1978cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
1988cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void _Block_memmove_gc_broken(void *dest, void *src, unsigned long size) {
1998cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    void **destp = (void **)dest;
2008cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    void **srcp = (void **)src;
2018cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    while (size) {
2028cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        _Block_assign_default(*srcp, destp);
2038cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        destp++;
2048cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        srcp++;
2058cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        size -= sizeof(void *);
2068cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
2078cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
2088cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
209962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/*
210962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * GC support callout functions - initially set to stub routines:
211962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan */
2128cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
2138cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void *(*_Block_allocator)(const unsigned long, const bool isOne, const bool isObject) = _Block_alloc_default;
2148cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void (*_Block_deallocator)(const void *) = (void (*)(const void *))free;
2158cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void (*_Block_assign)(void *value, void **destptr) = _Block_assign_default;
2168cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void (*_Block_setHasRefcount)(const void *ptr, const bool hasRefcount) = _Block_setHasRefcount_default;
2178cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void (*_Block_retain_object)(const void *ptr) = _Block_retain_object_default;
2188cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void (*_Block_release_object)(const void *ptr) = _Block_release_object_default;
2198cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void (*_Block_assign_weak)(const void *dest, void *ptr) = _Block_assign_weak_default;
2208cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void (*_Block_memmove)(void *dest, void *src, unsigned long size) = _Block_memmove_default;
2218cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
2228cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
223962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/*
224962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * GC support SPI functions - called from ObjC runtime and CoreFoundation:
225962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan */
2268cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
227962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/* Public SPI
228962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * Called from objc-auto to turn on GC.
229962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * version 3, 4 arg, but changed 1st arg
230962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan */
2318cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarvoid _Block_use_GC( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
2328cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar                    void (*setHasRefcount)(const void *, const bool),
2338cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar                    void (*gc_assign)(void *, void **),
2348cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar                    void (*gc_assign_weak)(const void *, void *),
2358cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar                    void (*gc_memmove)(void *, void *, unsigned long)) {
2368cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
2378cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    isGC = true;
2388cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_allocator = alloc;
2398cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_deallocator = _Block_do_nothing;
2408cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_assign = gc_assign;
2418cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_copy_flag = BLOCK_IS_GC;
2428cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_copy_class = _NSConcreteAutoBlock;
243962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan    /* blocks with ctors & dtors need to have the dtor run from a class with a finalizer */
2448cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_copy_finalizing_class = _NSConcreteFinalizingBlock;
2458cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_setHasRefcount = setHasRefcount;
2468cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Byref_flag_initial_value = BLOCK_IS_GC;   // no refcount
2478cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_retain_object = _Block_do_nothing;
2488cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_release_object = _Block_do_nothing;
2498cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_assign_weak = gc_assign_weak;
2508cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_memmove = gc_memmove;
2518cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
2528cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
253962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/* transitional */
2548cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarvoid _Block_use_GC5( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
2558cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar                    void (*setHasRefcount)(const void *, const bool),
2568cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar                    void (*gc_assign)(void *, void **),
2578cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar                    void (*gc_assign_weak)(const void *, void *)) {
258962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan    /* until objc calls _Block_use_GC it will call us; supply a broken internal memmove implementation until then */
2598cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_use_GC(alloc, setHasRefcount, gc_assign, gc_assign_weak, _Block_memmove_gc_broken);
2608cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
2618cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
2628cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
263962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/*
264962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * Called from objc-auto to alternatively turn on retain/release.
265962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * Prior to this the only "object" support we can provide is for those
266962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * super special objects that live in libSystem, namely dispatch queues.
267962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * Blocks and Block_byrefs have their own special entry points.
268962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan *
269962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan */
2708cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarvoid _Block_use_RR( void (*retain)(const void *),
2718cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar                    void (*release)(const void *)) {
2728cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_retain_object = retain;
2738cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_release_object = release;
2748cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
2758cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
276962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/*
277962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * Internal Support routines for copying:
278962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan */
2798cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
280b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen#if 0
2818cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar#pragma mark Copy/Release support
282962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan#endif /* if 0 */
2838cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
284962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/* Copy, or bump refcount, of a block.  If really copying, call the copy helper if present. */
2858cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void *_Block_copy_internal(const void *arg, const int flags) {
2868cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    struct Block_layout *aBlock;
2878cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    const bool wantsOne = (WANTS_ONE & flags) == WANTS_ONE;
2888cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
2898cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    //printf("_Block_copy_internal(%p, %x)\n", arg, flags);
2908cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (!arg) return NULL;
2918cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
2928cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
2938cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    // The following would be better done as a switch statement
2948cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    aBlock = (struct Block_layout *)arg;
2958cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (aBlock->flags & BLOCK_NEEDS_FREE) {
2968cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // latches on high
2978cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        latching_incr_int(&aBlock->flags);
2988cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        return aBlock;
2998cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
3008cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if (aBlock->flags & BLOCK_IS_GC) {
3018cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // GC refcounting is expensive so do most refcounting here.
3028cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (wantsOne && ((latching_incr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK) == 1)) {
3038cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            // Tell collector to hang on this - it will bump the GC refcount version
3048cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            _Block_setHasRefcount(aBlock, true);
3058cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
3068cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        return aBlock;
3078cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
3088cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if (aBlock->flags & BLOCK_IS_GLOBAL) {
3098cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        return aBlock;
3108cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
3118cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
3128cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    // Its a stack block.  Make a copy.
3138cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (!isGC) {
3148cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        struct Block_layout *result = malloc(aBlock->descriptor->size);
3158cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (!result) return (void *)0;
3168cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
3178cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // reset refcount
3188cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        result->flags &= ~(BLOCK_REFCOUNT_MASK);    // XXX not needed
3198cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        result->flags |= BLOCK_NEEDS_FREE | 1;
3208cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        result->isa = _NSConcreteMallocBlock;
3218cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (result->flags & BLOCK_HAS_COPY_DISPOSE) {
3228cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            //printf("calling block copy helper %p(%p, %p)...\n", aBlock->descriptor->copy, result, aBlock);
3238cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            (*aBlock->descriptor->copy)(result, aBlock); // do fixup
3248cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
3258cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        return result;
3268cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
3278cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else {
3288cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // Under GC want allocation with refcount 1 so we ask for "true" if wantsOne
3298cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // This allows the copy helper routines to make non-refcounted block copies under GC
3308cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        unsigned long int flags = aBlock->flags;
3318cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        bool hasCTOR = (flags & BLOCK_HAS_CTOR) != 0;
3328cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        struct Block_layout *result = _Block_allocator(aBlock->descriptor->size, wantsOne, hasCTOR);
3338cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (!result) return (void *)0;
3348cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
3358cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // reset refcount
3368cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // if we copy a malloc block to a GC block then we need to clear NEEDS_FREE.
3378cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        flags &= ~(BLOCK_NEEDS_FREE|BLOCK_REFCOUNT_MASK);   // XXX not needed
3388cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (wantsOne)
3398cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            flags |= BLOCK_IS_GC | 1;
3408cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        else
3418cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            flags |= BLOCK_IS_GC;
3428cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        result->flags = flags;
3438cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (flags & BLOCK_HAS_COPY_DISPOSE) {
3448cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            //printf("calling block copy helper...\n");
3458cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            (*aBlock->descriptor->copy)(result, aBlock); // do fixup
3468cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
3478cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (hasCTOR) {
3488cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            result->isa = _NSConcreteFinalizingBlock;
3498cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
3508cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        else {
3518cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            result->isa = _NSConcreteAutoBlock;
3528cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
3538cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        return result;
3548cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
3558cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
3568cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
3578cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
358962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/*
359962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * Runtime entry points for maintaining the sharing knowledge of byref data blocks.
360962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan *
361962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * A closure has been copied and its fixup routine is asking us to fix up the reference to the shared byref data
362962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * Closures that aren't copied must still work, so everyone always accesses variables after dereferencing the forwarding ptr.
363962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * We ask if the byref pointer that we know about has already been copied to the heap, and if so, increment it.
364962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * Otherwise we need to copy it and update the stack forwarding pointer
365962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * XXX We need to account for weak/nonretained read-write barriers.
366962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan */
3678cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
3688cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) {
3698cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    struct Block_byref **destp = (struct Block_byref **)dest;
3708cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    struct Block_byref *src = (struct Block_byref *)arg;
3718cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
3728cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    //printf("_Block_byref_assign_copy called, byref destp %p, src %p, flags %x\n", destp, src, flags);
3738cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    //printf("src dump: %s\n", _Block_byref_dump(src));
3748cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (src->forwarding->flags & BLOCK_IS_GC) {
3758cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        ;   // don't need to do any more work
3768cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
3778cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
3788cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        //printf("making copy\n");
3798cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // src points to stack
3808cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        bool isWeak = ((flags & (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)) == (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK));
3818cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // if its weak ask for an object (only matters under GC)
3828cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak);
3838cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack
3848cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier)
3858cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        src->forwarding = copy;  // patch stack to point to heap copy
3868cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        copy->size = src->size;
3878cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (isWeak) {
3888cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            copy->isa = &_NSConcreteWeakBlockVariable;  // mark isa field so it gets weak scanning
3898cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
3908cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
3918cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            // Trust copy helper to copy everything of interest
3928cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            // If more than one field shows up in a byref block this is wrong XXX
3938cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            copy->byref_keep = src->byref_keep;
3948cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            copy->byref_destroy = src->byref_destroy;
3958cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            (*src->byref_keep)(copy, src);
3968cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
3978cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        else {
3988cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            // just bits.  Blast 'em using _Block_memmove in case they're __strong
3998cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            _Block_memmove(
4008cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar                (void *)&copy->byref_keep,
4018cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar                (void *)&src->byref_keep,
4028cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar                src->size - sizeof(struct Block_byref_header));
4038cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
4048cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
4058cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    // already copied to heap
4068cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if ((src->forwarding->flags & BLOCK_NEEDS_FREE) == BLOCK_NEEDS_FREE) {
4078cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        latching_incr_int(&src->forwarding->flags);
4088cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
4098cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    // assign byref data block pointer into new Block
4108cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_assign(src->forwarding, (void **)destp);
4118cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
4128cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
4138cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar// Old compiler SPI
4148cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void _Block_byref_release(const void *arg) {
4158cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    struct Block_byref *shared_struct = (struct Block_byref *)arg;
4168cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    int refcount;
4178cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
4188cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    // dereference the forwarding pointer since the compiler isn't doing this anymore (ever?)
4198cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    shared_struct = shared_struct->forwarding;
4208cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
4218cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    //printf("_Block_byref_release %p called, flags are %x\n", shared_struct, shared_struct->flags);
4228cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    // To support C++ destructors under GC we arrange for there to be a finalizer for this
4238cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    // by using an isa that directs the code to a finalizer that calls the byref_destroy method.
4248cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if ((shared_struct->flags & BLOCK_NEEDS_FREE) == 0) {
4258cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        return; // stack or GC or global
4268cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
4278cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    refcount = shared_struct->flags & BLOCK_REFCOUNT_MASK;
4288cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (refcount <= 0) {
4298cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        printf("_Block_byref_release: Block byref data structure at %p underflowed\n", arg);
4308cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
4318cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if ((latching_decr_int(&shared_struct->flags) & BLOCK_REFCOUNT_MASK) == 0) {
4328cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        //printf("disposing of heap based byref block\n");
4338cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (shared_struct->flags & BLOCK_HAS_COPY_DISPOSE) {
4348cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            //printf("calling out to helper\n");
4358cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            (*shared_struct->byref_destroy)(shared_struct);
4368cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
4378cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        _Block_deallocator((struct Block_layout *)shared_struct);
4388cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
4398cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
4408cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
4418cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
442962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/*
4438cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar *
4448cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar * API supporting SPI
4458cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar * _Block_copy, _Block_release, and (old) _Block_destroy
4468cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar *
447962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan */
4488cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
449b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen#if 0
4508cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar#pragma mark SPI/API
451962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan#endif /* if 0 */
4528cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
4538cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarvoid *_Block_copy(const void *arg) {
4548cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    return _Block_copy_internal(arg, WANTS_ONE);
4558cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
4568cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
4578cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
4588cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar// API entry point to release a copied Block
4598cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarvoid _Block_release(void *arg) {
4608cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    struct Block_layout *aBlock = (struct Block_layout *)arg;
4618cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    int32_t newCount;
4628cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (!aBlock) return;
4638cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    newCount = latching_decr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK;
4648cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (newCount > 0) return;
4658cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    // Hit zero
4668cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (aBlock->flags & BLOCK_IS_GC) {
4678cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // Tell GC we no longer have our own refcounts.  GC will decr its refcount
4688cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // and unless someone has done a CFRetain or marked it uncollectable it will
4698cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // now be subject to GC reclamation.
4708cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        _Block_setHasRefcount(aBlock, false);
4718cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
4728cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if (aBlock->flags & BLOCK_NEEDS_FREE) {
4738cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (aBlock->flags & BLOCK_HAS_COPY_DISPOSE)(*aBlock->descriptor->dispose)(aBlock);
4748cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        _Block_deallocator(aBlock);
4758cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
4768cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if (aBlock->flags & BLOCK_IS_GLOBAL) {
4778cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        ;
4788cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
4798cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else {
480b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen        printf("Block_release called upon a stack Block: %p, ignored\n", (void *)aBlock);
4818cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
4828cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
4838cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
4848cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
4858cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
4868cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar// Old Compiler SPI point to release a copied Block used by the compiler in dispose helpers
4878cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarstatic void _Block_destroy(const void *arg) {
4888cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    struct Block_layout *aBlock;
4898cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (!arg) return;
4908cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    aBlock = (struct Block_layout *)arg;
4918cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (aBlock->flags & BLOCK_IS_GC) {
4928cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // assert(aBlock->Block_flags & BLOCK_HAS_CTOR);
4938cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        return; // ignore, we are being called because of a DTOR
4948cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
4958cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    _Block_release(aBlock);
4968cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
4978cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
4988cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
4998cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
500962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/*
5018cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar *
5028cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar * SPI used by other layers
5038cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar *
504962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan */
5058cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5068cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar// SPI, also internal.  Called from NSAutoBlock only under GC
5078cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarvoid *_Block_copy_collectable(const void *aBlock) {
5088cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    return _Block_copy_internal(aBlock, 0);
5098cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
5108cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5118cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5128cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar// SPI
5138cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarunsigned long int Block_size(void *arg) {
5148cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    return ((struct Block_layout *)arg)->descriptor->size;
5158cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
5168cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5178cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
518b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen#if 0
5198cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar#pragma mark Compiler SPI entry points
520962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan#endif /* if 0 */
5218cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5228cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5238cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar/*******************************************************
5248cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5258cbe163cba77c772621f89ddb33793ac170b1faDaniel DunbarEntry points used by the compiler - the real API!
5268cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5278cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5288cbe163cba77c772621f89ddb33793ac170b1faDaniel DunbarA Block can reference four different kinds of things that require help when the Block is copied to the heap.
5298cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar1) C++ stack based objects
5308cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar2) References to Objective-C objects
5318cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar3) Other Blocks
5328cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar4) __block variables
5338cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5348cbe163cba77c772621f89ddb33793ac170b1faDaniel DunbarIn 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.
5358cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5368cbe163cba77c772621f89ddb33793ac170b1faDaniel DunbarThe flags parameter of _Block_object_assign and _Block_object_dispose is set to
5378cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar	* BLOCK_FIELD_IS_OBJECT (3), for the case of an Objective-C Object,
5388cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar	* BLOCK_FIELD_IS_BLOCK (7), for the case of another Block, and
5398cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar	* BLOCK_FIELD_IS_BYREF (8), for the case of a __block variable.
5408cbe163cba77c772621f89ddb33793ac170b1faDaniel DunbarIf the __block variable is marked weak the compiler also or's in BLOCK_FIELD_IS_WEAK (16).
5418cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5428cbe163cba77c772621f89ddb33793ac170b1faDaniel DunbarSo the Block copy/dispose helpers should only ever generate the four flag values of 3, 7, 8, and 24.
5438cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5448cbe163cba77c772621f89ddb33793ac170b1faDaniel DunbarWhen  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.
5458cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5468cbe163cba77c772621f89ddb33793ac170b1faDaniel DunbarSo 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:
5478cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar	__block id                   128+3
5488cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        __weak block id              128+3+16
5498cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar	__block (^Block)             128+7
5508cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar	__weak __block (^Block)      128+7+16
5518cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5528cbe163cba77c772621f89ddb33793ac170b1faDaniel DunbarThe implementation of the two routines would be improved by switch statements enumerating the eight cases.
5538cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5548cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar********************************************************/
5558cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
556962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/*
557962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * When Blocks or Block_byrefs hold objects then their copy routine helpers use this entry point
558962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * to do the assignment.
559962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan */
5608cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarvoid _Block_object_assign(void *destAddr, const void *object, const int flags) {
5618cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    //printf("_Block_object_assign(*%p, %p, %x)\n", destAddr, object, flags);
5628cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) {
5638cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if ((flags & BLOCK_FIELD_IS_WEAK) == BLOCK_FIELD_IS_WEAK) {
5648cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            _Block_assign_weak(object, destAddr);
5658cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
5668cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        else {
5678cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            // do *not* retain or *copy* __block variables whatever they are
5688cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar            _Block_assign((void *)object, destAddr);
5698cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
5708cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
5718cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF)  {
5728cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // copying a __block reference from the stack Block to the heap
5738cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // flags will indicate if it holds a __weak reference and needs a special isa
5748cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        _Block_byref_assign_copy(destAddr, object, flags);
5758cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
5768cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    // (this test must be before next one)
5778cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) {
5788cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // copying a Block declared variable from the stack Block to the heap
5798cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        _Block_assign(_Block_copy_internal(object, flags), destAddr);
5808cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
5818cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    // (this test must be after previous one)
5828cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) {
5838cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        //printf("retaining object at %p\n", object);
5848cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        _Block_retain_object(object);
5858cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        //printf("done retaining object at %p\n", object);
5868cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        _Block_assign((void *)object, destAddr);
5878cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
5888cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
5898cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
5908cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar// When Blocks or Block_byrefs hold objects their destroy helper routines call this entry point
5918cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar// to help dispose of the contents
5928cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar// Used initially only for __attribute__((NSObject)) marked pointers.
5938cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarvoid _Block_object_dispose(const void *object, const int flags) {
5948cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    //printf("_Block_object_dispose(%p, %x)\n", object, flags);
5958cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (flags & BLOCK_FIELD_IS_BYREF)  {
5968cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // get rid of the __block data structure held in a Block
5978cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        _Block_byref_release(object);
5988cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
5998cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if ((flags & (BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_BLOCK) {
6008cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // get rid of a referenced Block held by this Block
6018cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // (ignore __block Block variables, compiler doesn't need to call us)
6028cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        _Block_destroy(object);
6038cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6048cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if ((flags & (BLOCK_FIELD_IS_WEAK|BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_OBJECT) {
6058cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // get rid of a referenced object held by this Block
6068cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        // (ignore __block object variables, compiler doesn't need to call us)
6078cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        _Block_release_object(object);
6088cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6098cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
6108cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
6118cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
612962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan/*
613962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan * Debugging support:
614962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan */
615b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen#if 0
6168cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar#pragma mark Debugging
617962a63123c07b5fed500390eb83f2f3aa8e5f8cbEdward O'Callaghan#endif /* if 0 */
6188cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
6198cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
6208cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarconst char *_Block_dump(const void *block) {
6218cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    struct Block_layout *closure = (struct Block_layout *)block;
6228cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    static char buffer[512];
6238cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    char *cp = buffer;
6248cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (closure == NULL) {
6258cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        sprintf(cp, "NULL passed to _Block_dump\n");
6268cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        return buffer;
6278cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6288cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (! (closure->flags & BLOCK_HAS_DESCRIPTOR)) {
6298cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        printf("Block compiled by obsolete compiler, please recompile source for this Block\n");
6308cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        exit(1);
6318cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
632b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen    cp += sprintf(cp, "^%p (new layout) =\n", (void *)closure);
6338cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (closure->isa == NULL) {
6348cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        cp += sprintf(cp, "isa: NULL\n");
6358cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6368cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if (closure->isa == _NSConcreteStackBlock) {
6378cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        cp += sprintf(cp, "isa: stack Block\n");
6388cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6398cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if (closure->isa == _NSConcreteMallocBlock) {
6408cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        cp += sprintf(cp, "isa: malloc heap Block\n");
6418cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6428cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if (closure->isa == _NSConcreteAutoBlock) {
6438cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        cp += sprintf(cp, "isa: GC heap Block\n");
6448cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6458cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if (closure->isa == _NSConcreteGlobalBlock) {
6468cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        cp += sprintf(cp, "isa: global Block\n");
6478cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6488cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else if (closure->isa == _NSConcreteFinalizingBlock) {
6498cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        cp += sprintf(cp, "isa: finalizing Block\n");
6508cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6518cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    else {
652b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen        cp += sprintf(cp, "isa?: %p\n", (void *)closure->isa);
6538cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6548cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    cp += sprintf(cp, "flags:");
6558cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (closure->flags & BLOCK_HAS_DESCRIPTOR) {
6568cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        cp += sprintf(cp, " HASDESCRIPTOR");
6578cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6588cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (closure->flags & BLOCK_NEEDS_FREE) {
6598cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        cp += sprintf(cp, " FREEME");
6608cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6618cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (closure->flags & BLOCK_IS_GC) {
6628cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        cp += sprintf(cp, " ISGC");
6638cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6648cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (closure->flags & BLOCK_HAS_COPY_DISPOSE) {
6658cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        cp += sprintf(cp, " HASHELP");
6668cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6678cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (closure->flags & BLOCK_HAS_CTOR) {
6688cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        cp += sprintf(cp, " HASCTOR");
6698cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6708cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    cp += sprintf(cp, "\nrefcount: %u\n", closure->flags & BLOCK_REFCOUNT_MASK);
6713f55c61a5d7428eb18e65393e2b9e91ea9444fdbShantonu Sen    cp += sprintf(cp, "invoke: %p\n", (void *)(uintptr_t)closure->invoke);
6728cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    {
6738cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        struct Block_descriptor *dp = closure->descriptor;
674b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen        cp += sprintf(cp, "descriptor: %p\n", (void *)dp);
6758cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        cp += sprintf(cp, "descriptor->reserved: %lu\n", dp->reserved);
6768cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        cp += sprintf(cp, "descriptor->size: %lu\n", dp->size);
6778cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
6788cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        if (closure->flags & BLOCK_HAS_COPY_DISPOSE) {
6793f55c61a5d7428eb18e65393e2b9e91ea9444fdbShantonu Sen            cp += sprintf(cp, "descriptor->copy helper: %p\n", (void *)(uintptr_t)dp->copy);
6803f55c61a5d7428eb18e65393e2b9e91ea9444fdbShantonu Sen            cp += sprintf(cp, "descriptor->dispose helper: %p\n", (void *)(uintptr_t)dp->dispose);
6818cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar        }
6828cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6838cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    return buffer;
6848cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
6858cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
6868cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
6878cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbarconst char *_Block_byref_dump(struct Block_byref *src) {
6888cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    static char buffer[256];
6898cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    char *cp = buffer;
690b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen    cp += sprintf(cp, "byref data block %p contents:\n", (void *)src);
691b4c3b6f8a2d3481bac6b0e9b4240fa0c99412d10Shantonu Sen    cp += sprintf(cp, "  forwarding: %p\n", (void *)src->forwarding);
6928cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    cp += sprintf(cp, "  flags: 0x%x\n", src->flags);
6938cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    cp += sprintf(cp, "  size: %d\n", src->size);
6948cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
6953f55c61a5d7428eb18e65393e2b9e91ea9444fdbShantonu Sen        cp += sprintf(cp, "  copy helper: %p\n", (void *)(uintptr_t)src->byref_keep);
6963f55c61a5d7428eb18e65393e2b9e91ea9444fdbShantonu Sen        cp += sprintf(cp, "  dispose helper: %p\n", (void *)(uintptr_t)src->byref_destroy);
6978cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    }
6988cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar    return buffer;
6998cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar}
7008cbe163cba77c772621f89ddb33793ac170b1faDaniel Dunbar
701