/* * Copyright (c) 2008 - 2010 * Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE included in * the packaging of this file. */ #include "config.h" #include #include #include #import "OFBlock.h" #import "OFExceptions.h" #import "atomic.h" /// \cond internal @protocol RetainRelease - retain; - (void)release; @end /// \endcond #if defined(OF_GNU_RUNTIME) || defined(OF_OBJFW_RUNTIME) struct objc_abi_class { struct objc_abi_metaclass *metaclass; const char *superclass, *name; unsigned long version, info, instance_size; void *ivars, *methodlist, *dtable, *subclass_list, *sibling_class; void *protocols, *gc_object_type; long abi_version; void *ivar_offsets, *properties; }; struct objc_abi_metaclass { const char *metaclass, *superclass, *name; unsigned long version, info, instance_size; void *ivars, *methodlist, *dtable, *subclass_list, *sibling_class; void *protocols, *gc_object_type; long abi_version; void *ivar_offsets, *properties; }; enum objc_abi_class_info { OBJC_CLASS_INFO_CLASS = 0x01, OBJC_CLASS_INFO_METACLASS = 0x02 }; extern void __objc_exec_class(void*); /* Begin of ObjC module */ static struct objc_abi_metaclass _NSConcreteStackBlock_metaclass = { "OFBlock", "OFBlock", "OFStackBlock", 8, OBJC_CLASS_INFO_METACLASS, sizeof(struct objc_class), NULL, NULL }; struct objc_abi_class _NSConcreteStackBlock = { &_NSConcreteStackBlock_metaclass, "OFBlock", "OFStackBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), NULL, NULL }; static struct objc_abi_metaclass _NSConcreteGlobalBlock_metaclass = { "OFBlock", "OFBlock", "OFGlobalBlock", 8, OBJC_CLASS_INFO_METACLASS, sizeof(struct objc_class), NULL, NULL }; struct objc_abi_class _NSConcreteGlobalBlock = { &_NSConcreteGlobalBlock_metaclass, "OFBlock", "OFGlobalBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), NULL, NULL }; static struct objc_abi_metaclass _NSConcreteMallocBlock_metaclass = { "OFBlock", "OFBlock", "OFMallocBlock", 8, OBJC_CLASS_INFO_METACLASS, sizeof(struct objc_class), NULL, NULL }; struct objc_abi_class _NSConcreteMallocBlock = { &_NSConcreteMallocBlock_metaclass, "OFBlock", "OFMallocBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), NULL, NULL }; static struct { unsigned int unknown; struct objc_abi_selector *sel_refs; uint16_t cls_def_cnt, cat_def_cnt; void *defs[4]; } symtab = { 0, NULL, 3, 0, { &_NSConcreteStackBlock, &_NSConcreteGlobalBlock, &_NSConcreteMallocBlock, NULL }}; static struct { unsigned long version, size; const char *name; void *symtab; } module = { 8, sizeof(module), NULL, &symtab }; static void __attribute__((constructor)) constructor() { __objc_exec_class(&module); } /* End of ObjC module */ #else extern void *_NSConcreteStackBlock; extern void *_NSConcreteGlobalBlock; extern void *_NSConcreteMallocBlock; #endif #ifndef HAVE_BLOCK_COPY static struct { Class isa; } alloc_failed_exception; void* _Block_copy(const void *block_) { of_block_literal_t *block = (of_block_literal_t*)block_; if (block->isa == (Class)&_NSConcreteStackBlock) { of_block_literal_t *copy; if ((copy = malloc(block->descriptor->size)) == NULL) { alloc_failed_exception.isa = [OFAllocFailedException class]; @throw (OFAllocFailedException*)&alloc_failed_exception; } memcpy(copy, block, block->descriptor->size); copy->isa = (Class)&_NSConcreteMallocBlock; copy->reserved++; if (block->flags & OF_BLOCK_HAS_COPY_DISPOSE) block->descriptor->copy_helper(copy, block); return copy; } if (block->isa == (Class)&_NSConcreteMallocBlock) of_atomic_inc_int(&block->reserved); return block; } void _Block_release(const void *block_) { of_block_literal_t *block = (of_block_literal_t*)block_; if (block->isa != (Class)&_NSConcreteMallocBlock) return; if (of_atomic_dec_int(&block->reserved) == 0) { if (block->flags & OF_BLOCK_HAS_COPY_DISPOSE) block->descriptor->dispose_helper(block); free(block); } } void _Block_object_assign(void *dst_, const void *src_, const int flags_) { int flags = flags_ & (OF_BLOCK_FIELD_IS_BLOCK | OF_BLOCK_FIELD_IS_OBJECT | OF_BLOCK_FIELD_IS_BYREF); switch (flags) { case OF_BLOCK_FIELD_IS_BLOCK: *(of_block_literal_t**)dst_ = _Block_copy(src_); break; case OF_BLOCK_FIELD_IS_OBJECT: *(id*)dst_ = [(id)src_ retain]; break; case OF_BLOCK_FIELD_IS_BYREF:; of_block_byref_t *src = (of_block_byref_t*)src_; of_block_byref_t **dst = (of_block_byref_t**)dst_; if ((src->flags & ~OF_BLOCK_HAS_COPY_DISPOSE) == 0) { if ((*dst = malloc(src->size)) == NULL) { alloc_failed_exception.isa = [OFAllocFailedException class]; @throw (OFAllocFailedException*) &alloc_failed_exception; } if (src->forwarding == src) src->forwarding = *dst; memcpy(*dst, src, src->size); if (src->size >= sizeof(of_block_byref_t)) src->byref_keep(*dst, src); } else *dst = src; (*dst)->flags++; break; } } void _Block_object_dispose(const void *obj_, const int flags_) { const int flags = flags_ & (OF_BLOCK_FIELD_IS_BLOCK | OF_BLOCK_FIELD_IS_OBJECT | OF_BLOCK_FIELD_IS_BYREF); switch (flags) { case OF_BLOCK_FIELD_IS_BLOCK: _Block_release(obj_); break; case OF_BLOCK_FIELD_IS_OBJECT: [(id)obj_ release]; break; case OF_BLOCK_FIELD_IS_BYREF:; of_block_byref_t *obj = (of_block_byref_t*)obj_; if ((--obj->flags & ~OF_BLOCK_HAS_COPY_DISPOSE) == 0) { if (obj->size >= sizeof(of_block_byref_t)) obj->byref_dispose(obj); free(obj); } break; } } #endif /// \cond internal @implementation OFBlock + (void)initialize { } + (Class)class { return self; } - copy { return Block_copy(self); } - (void)release { Block_release(self); } @end #if !defined(OF_GNU_RUNTIME) && !defined(OF_OBJFW_RUNTIME) @implementation OFStackBlock @end @implementation OFGlobalBlock @end @implementation OFMallocBlock @end #endif /// \endcond