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 *)©->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