177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/*
277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * runtime.c
377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao *
477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * Copyright 2008-2009 Apple, Inc. Permission is hereby granted, free of charge,
577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * to any person obtaining a copy of this software and associated documentation
677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * files (the "Software"), to deal in the Software without restriction,
777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * including without limitation the rights to use, copy, modify, merge, publish,
877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * distribute, sublicense, and/or sell copies of the Software, and to permit
977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * persons to whom the Software is furnished to do so, subject to the following
1077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * conditions:
1177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao *
1277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * The above copyright notice and this permission notice shall be included in
1377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * all copies or substantial portions of the Software.
1477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao *
1577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * SOFTWARE.
2277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao *
2377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao */
2477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
2577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#include "Block_private.h"
2677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#include <stdio.h>
2777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#include <stdlib.h>
2877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#include <string.h>
2977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#include <stdint.h>
3077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#include <stdbool.h>
3177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
3277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#include "config.h"
3377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
3477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#ifdef HAVE_AVAILABILITY_MACROS_H
3577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#include <AvailabilityMacros.h>
3677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#endif /* HAVE_AVAILABILITY_MACROS_H */
3777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
3877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#ifdef HAVE_TARGET_CONDITIONALS_H
3977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#include <TargetConditionals.h>
4077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#endif /* HAVE_TARGET_CONDITIONALS_H */
4177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
4277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#if defined(HAVE_OSATOMIC_COMPARE_AND_SWAP_INT) && defined(HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG)
4377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
4477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#ifdef HAVE_LIBKERN_OSATOMIC_H
4577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#include <libkern/OSAtomic.h>
4677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#endif /* HAVE_LIBKERN_OSATOMIC_H */
4777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
4877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#elif defined(__WIN32__)
4977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#define _CRT_SECURE_NO_WARNINGS 1
5077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#include <windows.h>
5177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
5277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic __inline bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) {
5377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    /* fixme barrier is overkill -- see objc-os.h */
5477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    long original = InterlockedCompareExchange(dst, newl, oldl);
5577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    return (original == oldl);
5677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
5777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
5877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic __inline bool OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile *dst) {
5977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    /* fixme barrier is overkill -- see objc-os.h */
6077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    int original = InterlockedCompareExchange(dst, newi, oldi);
6177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    return (original == oldi);
6277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
6377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
6477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/*
6577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * Check to see if the GCC atomic built-ins are available.  If we're on
6677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * a 64-bit system, make sure we have an 8-byte atomic function
6777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * available.
6877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao *
6977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao */
7077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
7177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#elif defined(HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT) && defined(HAVE_SYNC_BOOL_COMPARE_AND_SWAP_LONG)
7277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
7377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic __inline bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) {
7477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao  return __sync_bool_compare_and_swap(dst, oldl, newl);
7577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
7677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
7777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic __inline bool OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile *dst) {
7877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao  return __sync_bool_compare_and_swap(dst, oldi, newi);
7977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
8077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
8177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#else
8277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#error unknown atomic compare-and-swap primitive
8377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#endif /* HAVE_OSATOMIC_COMPARE_AND_SWAP_INT && HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG */
8477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
8577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
8677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/*
8777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * Globals:
8877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao */
8977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
9077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void *_Block_copy_class = _NSConcreteMallocBlock;
9177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void *_Block_copy_finalizing_class = _NSConcreteMallocBlock;
9277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic int _Block_copy_flag = BLOCK_NEEDS_FREE;
9377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic int _Byref_flag_initial_value = BLOCK_NEEDS_FREE | 2;
9477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
9577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic const int WANTS_ONE = (1 << 16);
9677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
9777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic bool isGC = false;
9877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
9977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/*
10077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * Internal Utilities:
10177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao */
10277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
10377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#if 0
10477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic unsigned long int latching_incr_long(unsigned long int *where) {
10577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    while (1) {
10677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        unsigned long int old_value = *(volatile unsigned long int *)where;
10777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
10877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            return BLOCK_REFCOUNT_MASK;
10977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
11077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (OSAtomicCompareAndSwapLong(old_value, old_value+1, (volatile long int *)where)) {
11177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            return old_value+1;
11277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
11377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
11477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
11577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#endif /* if 0 */
11677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
11777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic int latching_incr_int(int *where) {
11877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    while (1) {
11977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        int old_value = *(volatile int *)where;
12077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
12177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            return BLOCK_REFCOUNT_MASK;
12277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
12377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (OSAtomicCompareAndSwapInt(old_value, old_value+1, (volatile int *)where)) {
12477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            return old_value+1;
12577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
12677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
12777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
12877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
12977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#if 0
13077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic int latching_decr_long(unsigned long int *where) {
13177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    while (1) {
13277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        unsigned long int old_value = *(volatile int *)where;
13377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
13477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            return BLOCK_REFCOUNT_MASK;
13577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
13677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if ((old_value & BLOCK_REFCOUNT_MASK) == 0) {
13777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            return 0;
13877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
13977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (OSAtomicCompareAndSwapLong(old_value, old_value-1, (volatile long int *)where)) {
14077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            return old_value-1;
14177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
14277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
14377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
14477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#endif /* if 0 */
14577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
14677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic int latching_decr_int(int *where) {
14777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    while (1) {
14877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        int old_value = *(volatile int *)where;
14977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
15077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            return BLOCK_REFCOUNT_MASK;
15177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
15277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if ((old_value & BLOCK_REFCOUNT_MASK) == 0) {
15377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            return 0;
15477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
15577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (OSAtomicCompareAndSwapInt(old_value, old_value-1, (volatile int *)where)) {
15677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            return old_value-1;
15777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
15877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
15977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
16077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
16177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
16277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/*
16377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * GC support stub routines:
16477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao */
16577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#if 0
16677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#pragma mark GC Support Routines
16777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#endif /* if 0 */
16877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
16977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
17077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void *_Block_alloc_default(const unsigned long size, const bool initialCountIsOne, const bool isObject) {
17177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    return malloc(size);
17277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
17377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
17477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void _Block_assign_default(void *value, void **destptr) {
17577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    *destptr = value;
17677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
17777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
17877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void _Block_setHasRefcount_default(const void *ptr, const bool hasRefcount) {
17977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
18077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
18177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void _Block_do_nothing(const void *aBlock) { }
18277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
18377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void _Block_retain_object_default(const void *ptr) {
18477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (!ptr) return;
18577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
18677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
18777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void _Block_release_object_default(const void *ptr) {
18877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (!ptr) return;
18977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
19077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
19177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void _Block_assign_weak_default(const void *ptr, void *dest) {
19277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    *(void **)dest = (void *)ptr;
19377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
19477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
19577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void _Block_memmove_default(void *dst, void *src, unsigned long size) {
19677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    memmove(dst, src, (size_t)size);
19777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
19877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
19977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void _Block_memmove_gc_broken(void *dest, void *src, unsigned long size) {
20077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    void **destp = (void **)dest;
20177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    void **srcp = (void **)src;
20277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    while (size) {
20377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        _Block_assign_default(*srcp, destp);
20477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        destp++;
20577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        srcp++;
20677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        size -= sizeof(void *);
20777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
20877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
20977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
21077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/*
21177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * GC support callout functions - initially set to stub routines:
21277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao */
21377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
21477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void *(*_Block_allocator)(const unsigned long, const bool isOne, const bool isObject) = _Block_alloc_default;
21577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void (*_Block_deallocator)(const void *) = (void (*)(const void *))free;
21677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void (*_Block_assign)(void *value, void **destptr) = _Block_assign_default;
21777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void (*_Block_setHasRefcount)(const void *ptr, const bool hasRefcount) = _Block_setHasRefcount_default;
21877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void (*_Block_retain_object)(const void *ptr) = _Block_retain_object_default;
21977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void (*_Block_release_object)(const void *ptr) = _Block_release_object_default;
22077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void (*_Block_assign_weak)(const void *dest, void *ptr) = _Block_assign_weak_default;
22177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void (*_Block_memmove)(void *dest, void *src, unsigned long size) = _Block_memmove_default;
22277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
22377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
22477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/*
22577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * GC support SPI functions - called from ObjC runtime and CoreFoundation:
22677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao */
22777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
22877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/* Public SPI
22977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * Called from objc-auto to turn on GC.
23077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * version 3, 4 arg, but changed 1st arg
23177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao */
23277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaovoid _Block_use_GC( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
23377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao                    void (*setHasRefcount)(const void *, const bool),
23477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao                    void (*gc_assign)(void *, void **),
23577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao                    void (*gc_assign_weak)(const void *, void *),
23677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao                    void (*gc_memmove)(void *, void *, unsigned long)) {
23777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
23877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    isGC = true;
23977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_allocator = alloc;
24077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_deallocator = _Block_do_nothing;
24177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_assign = gc_assign;
24277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_copy_flag = BLOCK_IS_GC;
24377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_copy_class = _NSConcreteAutoBlock;
24477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    /* blocks with ctors & dtors need to have the dtor run from a class with a finalizer */
24577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_copy_finalizing_class = _NSConcreteFinalizingBlock;
24677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_setHasRefcount = setHasRefcount;
24777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Byref_flag_initial_value = BLOCK_IS_GC;   // no refcount
24877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_retain_object = _Block_do_nothing;
24977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_release_object = _Block_do_nothing;
25077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_assign_weak = gc_assign_weak;
25177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_memmove = gc_memmove;
25277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
25377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
25477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/* transitional */
25577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaovoid _Block_use_GC5( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
25677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao                    void (*setHasRefcount)(const void *, const bool),
25777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao                    void (*gc_assign)(void *, void **),
25877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao                    void (*gc_assign_weak)(const void *, void *)) {
25977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    /* until objc calls _Block_use_GC it will call us; supply a broken internal memmove implementation until then */
26077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_use_GC(alloc, setHasRefcount, gc_assign, gc_assign_weak, _Block_memmove_gc_broken);
26177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
26277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
26377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
26477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/*
26577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * Called from objc-auto to alternatively turn on retain/release.
26677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * Prior to this the only "object" support we can provide is for those
26777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * super special objects that live in libSystem, namely dispatch queues.
26877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * Blocks and Block_byrefs have their own special entry points.
26977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao *
27077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao */
27177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaovoid _Block_use_RR( void (*retain)(const void *),
27277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao                    void (*release)(const void *)) {
27377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_retain_object = retain;
27477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_release_object = release;
27577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
27677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
27777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/*
27877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * Internal Support routines for copying:
27977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao */
28077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
28177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#if 0
28277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#pragma mark Copy/Release support
28377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#endif /* if 0 */
28477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
28577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/* Copy, or bump refcount, of a block.  If really copying, call the copy helper if present. */
28677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void *_Block_copy_internal(const void *arg, const int flags) {
28777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    struct Block_layout *aBlock;
28877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    const bool wantsOne = (WANTS_ONE & flags) == WANTS_ONE;
28977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
29077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    //printf("_Block_copy_internal(%p, %x)\n", arg, flags);
29177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (!arg) return NULL;
29277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
29377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
29477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    // The following would be better done as a switch statement
29577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    aBlock = (struct Block_layout *)arg;
29677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (aBlock->flags & BLOCK_NEEDS_FREE) {
29777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // latches on high
29877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        latching_incr_int(&aBlock->flags);
29977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        return aBlock;
30077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
30177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if (aBlock->flags & BLOCK_IS_GC) {
30277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // GC refcounting is expensive so do most refcounting here.
30377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (wantsOne && ((latching_incr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK) == 1)) {
30477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            // Tell collector to hang on this - it will bump the GC refcount version
30577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            _Block_setHasRefcount(aBlock, true);
30677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
30777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        return aBlock;
30877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
30977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if (aBlock->flags & BLOCK_IS_GLOBAL) {
31077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        return aBlock;
31177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
31277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
31377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    // Its a stack block.  Make a copy.
31477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (!isGC) {
31577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        struct Block_layout *result = malloc(aBlock->descriptor->size);
31677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (!result) return (void *)0;
31777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
31877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // reset refcount
31977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        result->flags &= ~(BLOCK_REFCOUNT_MASK);    // XXX not needed
32077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        result->flags |= BLOCK_NEEDS_FREE | 1;
32177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        result->isa = _NSConcreteMallocBlock;
32277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (result->flags & BLOCK_HAS_COPY_DISPOSE) {
32377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            //printf("calling block copy helper %p(%p, %p)...\n", aBlock->descriptor->copy, result, aBlock);
32477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            (*aBlock->descriptor->copy)(result, aBlock); // do fixup
32577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
32677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        return result;
32777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
32877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else {
32977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // Under GC want allocation with refcount 1 so we ask for "true" if wantsOne
33077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // This allows the copy helper routines to make non-refcounted block copies under GC
33177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        unsigned long int flags = aBlock->flags;
33277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        bool hasCTOR = (flags & BLOCK_HAS_CTOR) != 0;
33377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        struct Block_layout *result = _Block_allocator(aBlock->descriptor->size, wantsOne, hasCTOR);
33477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (!result) return (void *)0;
33577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
33677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // reset refcount
33777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // if we copy a malloc block to a GC block then we need to clear NEEDS_FREE.
33877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        flags &= ~(BLOCK_NEEDS_FREE|BLOCK_REFCOUNT_MASK);   // XXX not needed
33977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (wantsOne)
34077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            flags |= BLOCK_IS_GC | 1;
34177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        else
34277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            flags |= BLOCK_IS_GC;
34377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        result->flags = flags;
34477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (flags & BLOCK_HAS_COPY_DISPOSE) {
34577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            //printf("calling block copy helper...\n");
34677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            (*aBlock->descriptor->copy)(result, aBlock); // do fixup
34777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
34877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (hasCTOR) {
34977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            result->isa = _NSConcreteFinalizingBlock;
35077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
35177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        else {
35277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            result->isa = _NSConcreteAutoBlock;
35377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
35477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        return result;
35577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
35677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
35777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
35877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
35977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/*
36077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * Runtime entry points for maintaining the sharing knowledge of byref data blocks.
36177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao *
36277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * A closure has been copied and its fixup routine is asking us to fix up the reference to the shared byref data
36377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * Closures that aren't copied must still work, so everyone always accesses variables after dereferencing the forwarding ptr.
36477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * We ask if the byref pointer that we know about has already been copied to the heap, and if so, increment it.
36577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * Otherwise we need to copy it and update the stack forwarding pointer
36677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * XXX We need to account for weak/nonretained read-write barriers.
36777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao */
36877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
36977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) {
37077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    struct Block_byref **destp = (struct Block_byref **)dest;
37177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    struct Block_byref *src = (struct Block_byref *)arg;
37277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
37377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    //printf("_Block_byref_assign_copy called, byref destp %p, src %p, flags %x\n", destp, src, flags);
37477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    //printf("src dump: %s\n", _Block_byref_dump(src));
37577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (src->forwarding->flags & BLOCK_IS_GC) {
37677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        ;   // don't need to do any more work
37777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
37877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
37977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        //printf("making copy\n");
38077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // src points to stack
38177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        bool isWeak = ((flags & (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)) == (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK));
38277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // if its weak ask for an object (only matters under GC)
38377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak);
38477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack
38577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier)
38677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        src->forwarding = copy;  // patch stack to point to heap copy
38777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        copy->size = src->size;
38877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (isWeak) {
38977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            copy->isa = &_NSConcreteWeakBlockVariable;  // mark isa field so it gets weak scanning
39077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
39177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
39277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            // Trust copy helper to copy everything of interest
39377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            // If more than one field shows up in a byref block this is wrong XXX
39477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            copy->byref_keep = src->byref_keep;
39577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            copy->byref_destroy = src->byref_destroy;
39677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            (*src->byref_keep)(copy, src);
39777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
39877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        else {
39977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            // just bits.  Blast 'em using _Block_memmove in case they're __strong
40077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            _Block_memmove(
40177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao                (void *)&copy->byref_keep,
40277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao                (void *)&src->byref_keep,
40377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao                src->size - sizeof(struct Block_byref_header));
40477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
40577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
40677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    // already copied to heap
40777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if ((src->forwarding->flags & BLOCK_NEEDS_FREE) == BLOCK_NEEDS_FREE) {
40877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        latching_incr_int(&src->forwarding->flags);
40977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
41077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    // assign byref data block pointer into new Block
41177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_assign(src->forwarding, (void **)destp);
41277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
41377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
41477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao// Old compiler SPI
41577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void _Block_byref_release(const void *arg) {
41677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    struct Block_byref *shared_struct = (struct Block_byref *)arg;
41777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    int refcount;
41877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
41977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    // dereference the forwarding pointer since the compiler isn't doing this anymore (ever?)
42077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    shared_struct = shared_struct->forwarding;
42177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
42277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    //printf("_Block_byref_release %p called, flags are %x\n", shared_struct, shared_struct->flags);
42377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    // To support C++ destructors under GC we arrange for there to be a finalizer for this
42477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    // by using an isa that directs the code to a finalizer that calls the byref_destroy method.
42577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if ((shared_struct->flags & BLOCK_NEEDS_FREE) == 0) {
42677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        return; // stack or GC or global
42777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
42877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    refcount = shared_struct->flags & BLOCK_REFCOUNT_MASK;
42977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (refcount <= 0) {
43077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        printf("_Block_byref_release: Block byref data structure at %p underflowed\n", arg);
43177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
43277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if ((latching_decr_int(&shared_struct->flags) & BLOCK_REFCOUNT_MASK) == 0) {
43377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        //printf("disposing of heap based byref block\n");
43477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (shared_struct->flags & BLOCK_HAS_COPY_DISPOSE) {
43577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            //printf("calling out to helper\n");
43677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            (*shared_struct->byref_destroy)(shared_struct);
43777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
43877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        _Block_deallocator((struct Block_layout *)shared_struct);
43977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
44077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
44177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
44277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
44377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/*
44477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao *
44577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * API supporting SPI
44677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * _Block_copy, _Block_release, and (old) _Block_destroy
44777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao *
44877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao */
44977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
45077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#if 0
45177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#pragma mark SPI/API
45277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#endif /* if 0 */
45377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
45477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaovoid *_Block_copy(const void *arg) {
45577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    return _Block_copy_internal(arg, WANTS_ONE);
45677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
45777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
45877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
45977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao// API entry point to release a copied Block
46077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaovoid _Block_release(void *arg) {
46177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    struct Block_layout *aBlock = (struct Block_layout *)arg;
46277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    int32_t newCount;
46377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (!aBlock) return;
46477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    newCount = latching_decr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK;
46577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (newCount > 0) return;
46677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    // Hit zero
46777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (aBlock->flags & BLOCK_IS_GC) {
46877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // Tell GC we no longer have our own refcounts.  GC will decr its refcount
46977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // and unless someone has done a CFRetain or marked it uncollectable it will
47077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // now be subject to GC reclamation.
47177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        _Block_setHasRefcount(aBlock, false);
47277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
47377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if (aBlock->flags & BLOCK_NEEDS_FREE) {
47477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (aBlock->flags & BLOCK_HAS_COPY_DISPOSE)(*aBlock->descriptor->dispose)(aBlock);
47577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        _Block_deallocator(aBlock);
47677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
47777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if (aBlock->flags & BLOCK_IS_GLOBAL) {
47877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        ;
47977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
48077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else {
48177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        printf("Block_release called upon a stack Block: %p, ignored\n", (void *)aBlock);
48277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
48377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
48477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
48577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
48677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
48777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao// Old Compiler SPI point to release a copied Block used by the compiler in dispose helpers
48877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaostatic void _Block_destroy(const void *arg) {
48977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    struct Block_layout *aBlock;
49077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (!arg) return;
49177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    aBlock = (struct Block_layout *)arg;
49277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (aBlock->flags & BLOCK_IS_GC) {
493bbcef8ad069ee33c3bfc52dcd1bd6e1a7633e1f9Stephen Hines        // bccAssert(aBlock->Block_flags & BLOCK_HAS_CTOR);
49477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        return; // ignore, we are being called because of a DTOR
49577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
49677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    _Block_release(aBlock);
49777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
49877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
49977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
50077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
50177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/*
50277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao *
50377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * SPI used by other layers
50477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao *
50577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao */
50677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
50777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao// SPI, also internal.  Called from NSAutoBlock only under GC
50877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaovoid *_Block_copy_collectable(const void *aBlock) {
50977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    return _Block_copy_internal(aBlock, 0);
51077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
51177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
51277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
51377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao// SPI
51477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaounsigned long int Block_size(void *arg) {
51577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    return ((struct Block_layout *)arg)->descriptor->size;
51677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
51777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
51877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
51977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#if 0
52077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#pragma mark Compiler SPI entry points
52177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#endif /* if 0 */
52277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
52377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
52477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/*******************************************************
52577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
52677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei LiaoEntry points used by the compiler - the real API!
52777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
52877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
52977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei LiaoA Block can reference four different kinds of things that require help when the Block is copied to the heap.
53077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao1) C++ stack based objects
53177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao2) References to Objective-C objects
53277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao3) Other Blocks
53377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao4) __block variables
53477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
53577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei LiaoIn 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.
53677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
53777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei LiaoThe flags parameter of _Block_object_assign and _Block_object_dispose is set to
53877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao	* BLOCK_FIELD_IS_OBJECT (3), for the case of an Objective-C Object,
53977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao	* BLOCK_FIELD_IS_BLOCK (7), for the case of another Block, and
54077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao	* BLOCK_FIELD_IS_BYREF (8), for the case of a __block variable.
54177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei LiaoIf the __block variable is marked weak the compiler also or's in BLOCK_FIELD_IS_WEAK (16).
54277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
54377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei LiaoSo the Block copy/dispose helpers should only ever generate the four flag values of 3, 7, 8, and 24.
54477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
54577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei LiaoWhen  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.
54677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
54777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei LiaoSo 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:
54877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao	__block id                   128+3
54977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        __weak block id              128+3+16
55077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao	__block (^Block)             128+7
55177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao	__weak __block (^Block)      128+7+16
55277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
55377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei LiaoThe implementation of the two routines would be improved by switch statements enumerating the eight cases.
55477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
55577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao********************************************************/
55677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
55777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/*
55877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * When Blocks or Block_byrefs hold objects then their copy routine helpers use this entry point
55977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * to do the assignment.
56077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao */
56177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaovoid _Block_object_assign(void *destAddr, const void *object, const int flags) {
56277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    //printf("_Block_object_assign(*%p, %p, %x)\n", destAddr, object, flags);
56377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) {
56477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if ((flags & BLOCK_FIELD_IS_WEAK) == BLOCK_FIELD_IS_WEAK) {
56577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            _Block_assign_weak(object, destAddr);
56677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
56777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        else {
56877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            // do *not* retain or *copy* __block variables whatever they are
56977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            _Block_assign((void *)object, destAddr);
57077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
57177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
57277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF)  {
57377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // copying a __block reference from the stack Block to the heap
57477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // flags will indicate if it holds a __weak reference and needs a special isa
57577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        _Block_byref_assign_copy(destAddr, object, flags);
57677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
57777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    // (this test must be before next one)
57877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) {
57977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // copying a Block declared variable from the stack Block to the heap
58077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        _Block_assign(_Block_copy_internal(object, flags), destAddr);
58177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
58277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    // (this test must be after previous one)
58377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) {
58477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        //printf("retaining object at %p\n", object);
58577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        _Block_retain_object(object);
58677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        //printf("done retaining object at %p\n", object);
58777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        _Block_assign((void *)object, destAddr);
58877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
58977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
59077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
59177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao// When Blocks or Block_byrefs hold objects their destroy helper routines call this entry point
59277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao// to help dispose of the contents
59377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao// Used initially only for __attribute__((NSObject)) marked pointers.
59477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaovoid _Block_object_dispose(const void *object, const int flags) {
59577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    //printf("_Block_object_dispose(%p, %x)\n", object, flags);
59677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (flags & BLOCK_FIELD_IS_BYREF)  {
59777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // get rid of the __block data structure held in a Block
59877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        _Block_byref_release(object);
59977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
60077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if ((flags & (BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_BLOCK) {
60177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // get rid of a referenced Block held by this Block
60277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // (ignore __block Block variables, compiler doesn't need to call us)
60377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        _Block_destroy(object);
60477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
60577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if ((flags & (BLOCK_FIELD_IS_WEAK|BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_OBJECT) {
60677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // get rid of a referenced object held by this Block
60777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        // (ignore __block object variables, compiler doesn't need to call us)
60877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        _Block_release_object(object);
60977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
61077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
61177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
61277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
61377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao/*
61477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao * Debugging support:
61577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao */
61677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#if 0
61777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#pragma mark Debugging
61877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao#endif /* if 0 */
61977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
62077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
62177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaoconst char *_Block_dump(const void *block) {
62277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    struct Block_layout *closure = (struct Block_layout *)block;
62377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    static char buffer[512];
62477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    char *cp = buffer;
62577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (closure == NULL) {
62677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        sprintf(cp, "NULL passed to _Block_dump\n");
62777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        return buffer;
62877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
62977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (! (closure->flags & BLOCK_HAS_DESCRIPTOR)) {
63077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        printf("Block compiled by obsolete compiler, please recompile source for this Block\n");
63177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        exit(1);
63277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
63377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    cp += sprintf(cp, "^%p (new layout) =\n", (void *)closure);
63477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (closure->isa == NULL) {
63577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, "isa: NULL\n");
63677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
63777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if (closure->isa == _NSConcreteStackBlock) {
63877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, "isa: stack Block\n");
63977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
64077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if (closure->isa == _NSConcreteMallocBlock) {
64177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, "isa: malloc heap Block\n");
64277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
64377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if (closure->isa == _NSConcreteAutoBlock) {
64477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, "isa: GC heap Block\n");
64577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
64677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if (closure->isa == _NSConcreteGlobalBlock) {
64777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, "isa: global Block\n");
64877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
64977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else if (closure->isa == _NSConcreteFinalizingBlock) {
65077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, "isa: finalizing Block\n");
65177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
65277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    else {
65377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, "isa?: %p\n", (void *)closure->isa);
65477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
65577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    cp += sprintf(cp, "flags:");
65677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (closure->flags & BLOCK_HAS_DESCRIPTOR) {
65777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, " HASDESCRIPTOR");
65877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
65977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (closure->flags & BLOCK_NEEDS_FREE) {
66077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, " FREEME");
66177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
66277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (closure->flags & BLOCK_IS_GC) {
66377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, " ISGC");
66477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
66577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (closure->flags & BLOCK_HAS_COPY_DISPOSE) {
66677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, " HASHELP");
66777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
66877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (closure->flags & BLOCK_HAS_CTOR) {
66977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, " HASCTOR");
67077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
67177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    cp += sprintf(cp, "\nrefcount: %u\n", closure->flags & BLOCK_REFCOUNT_MASK);
67277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    cp += sprintf(cp, "invoke: %p\n", (void *)(uintptr_t)closure->invoke);
67377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    {
67477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        struct Block_descriptor *dp = closure->descriptor;
67577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, "descriptor: %p\n", (void *)dp);
67677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, "descriptor->reserved: %lu\n", dp->reserved);
67777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, "descriptor->size: %lu\n", dp->size);
67877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
67977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        if (closure->flags & BLOCK_HAS_COPY_DISPOSE) {
68077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            cp += sprintf(cp, "descriptor->copy helper: %p\n", (void *)(uintptr_t)dp->copy);
68177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao            cp += sprintf(cp, "descriptor->dispose helper: %p\n", (void *)(uintptr_t)dp->dispose);
68277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        }
68377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
68477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    return buffer;
68577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
68677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
68777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
68877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liaoconst char *_Block_byref_dump(struct Block_byref *src) {
68977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    static char buffer[256];
69077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    char *cp = buffer;
69177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    cp += sprintf(cp, "byref data block %p contents:\n", (void *)src);
69277ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    cp += sprintf(cp, "  forwarding: %p\n", (void *)src->forwarding);
69377ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    cp += sprintf(cp, "  flags: 0x%x\n", src->flags);
69477ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    cp += sprintf(cp, "  size: %d\n", src->size);
69577ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
69677ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, "  copy helper: %p\n", (void *)(uintptr_t)src->byref_keep);
69777ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao        cp += sprintf(cp, "  dispose helper: %p\n", (void *)(uintptr_t)src->byref_destroy);
69877ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    }
69977ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao    return buffer;
70077ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao}
70177ed6142daed1e068fbda64405d0de9845e40e1Shih-wei Liao
702