/* * When Blocks or Block_byrefs hold objects then their copy routine helpers use this entry point * to do the assignment. */ void _Block_object_assign(void *destAddr, const void *object, const int flags) { //printf("_Block_object_assign(*%p, %p, %x)\n", destAddr, object, flags); if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) { if ((flags & BLOCK_FIELD_IS_WEAK) == BLOCK_FIELD_IS_WEAK) { _Block_assign_weak(object, destAddr); } else { // do *not* retain or *copy* __block variables whatever they are _Block_assign((void *)object, destAddr); } } else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF) { // copying a __block reference from the stack Block to the heap // flags will indicate if it holds a __weak reference and needs a special isa _Block_byref_assign_copy(destAddr, object, flags); } // (this test must be before next one) else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) { // copying a Block declared variable from the stack Block to the heap _Block_assign(_Block_copy_internal(object, flags), destAddr); } // (this test must be after previous one) else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) { //printf("retaining object at %p\n", object); _Block_retain_object(object); //printf("done retaining object at %p\n", object); _Block_assign((void *)object, destAddr); } }
// A closure has been copied and its fixup routine is asking us to fix up the reference to the shared byref data // Closures that aren't copied must still work, so everyone always accesses variables after dereferencing the forwarding ptr. // We ask if the byref pointer that we know about has already been copied to the heap, and if so, increment it. // Otherwise we need to copy it and update the stack forwarding pointer static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) { struct Block_byref **destp = (struct Block_byref **)dest; struct Block_byref *src = (struct Block_byref *)arg; if (src->forwarding->flags & BLOCK_BYREF_IS_GC) { ; // don't need to do any more work } else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) { // src points to stack bool isWeak = ((flags & (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)) == (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)); // if its weak ask for an object (only matters under GC) struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak); copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier) src->forwarding = copy; // patch stack to point to heap copy copy->size = src->size; if (isWeak) { copy->isa = &_NSConcreteWeakBlockVariable; // mark isa field so it gets weak scanning } if (src->flags & BLOCK_BYREF_HAS_COPY_DISPOSE) { // Trust copy helper to copy everything of interest // If more than one field shows up in a byref block this is wrong XXX struct Block_byref_2 *src2 = (struct Block_byref_2 *)(src+1); struct Block_byref_2 *copy2 = (struct Block_byref_2 *)(copy+1); copy2->byref_keep = src2->byref_keep; copy2->byref_destroy = src2->byref_destroy; if (src->flags & BLOCK_BYREF_LAYOUT_EXTENDED) { struct Block_byref_3 *src3 = (struct Block_byref_3 *)(src2+1); struct Block_byref_3 *copy3 = (struct Block_byref_3*)(copy2+1); copy3->layout = src3->layout; } (*src2->byref_keep)(copy, src); } else { // just bits. Blast 'em using _Block_memmove in case they're __strong // This copy includes Block_byref_3, if any. _Block_memmove(copy+1, src+1, src->size - sizeof(struct Block_byref)); } } // already copied to heap else if ((src->forwarding->flags & BLOCK_BYREF_NEEDS_FREE) == BLOCK_BYREF_NEEDS_FREE) { latching_incr_int(&src->forwarding->flags); } // assign byref data block pointer into new Block _Block_assign(src->forwarding, (void **)destp); }
static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) { struct Block_byref **destp = (struct Block_byref **)dest; struct Block_byref *src = (struct Block_byref *)arg; //printf("_Block_byref_assign_copy called, byref destp %p, src %p, flags %x\n", destp, src, flags); //printf("src dump: %s\n", _Block_byref_dump(src)); if (src->forwarding->flags & BLOCK_IS_GC) { ; // don't need to do any more work } else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) { //printf("making copy\n"); // src points to stack bool isWeak = ((flags & (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)) == (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)); // if its weak ask for an object (only matters under GC) struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak); copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier) src->forwarding = copy; // patch stack to point to heap copy copy->size = src->size; if (isWeak) { copy->isa = &_NSConcreteWeakBlockVariable; // mark isa field so it gets weak scanning } if (src->flags & BLOCK_HAS_COPY_DISPOSE) { // Trust copy helper to copy everything of interest // If more than one field shows up in a byref block this is wrong XXX copy->byref_keep = src->byref_keep; copy->byref_destroy = src->byref_destroy; (*src->byref_keep)(copy, src); } else { // just bits. Blast 'em using _Block_memmove in case they're __strong _Block_memmove( (void *)©->byref_keep, (void *)&src->byref_keep, src->size - sizeof(struct Block_byref_header)); } } // already copied to heap else if ((src->forwarding->flags & BLOCK_NEEDS_FREE) == BLOCK_NEEDS_FREE) { latching_incr_int(&src->forwarding->flags); } // assign byref data block pointer into new Block _Block_assign(src->forwarding, (void **)destp); }
// // When Blocks or Block_byrefs hold objects then their copy routine helpers use this entry point // to do the assignment. // void _Block_object_assign(void *destAddr, const void *object, const int flags) { switch (osx_assumes(flags & BLOCK_ALL_COPY_DISPOSE_FLAGS)) { case BLOCK_FIELD_IS_OBJECT: /******* id object = ...; [^{ object; } copy]; ********/ _Block_retain_object(object); _Block_assign((void *)object, destAddr); break; case BLOCK_FIELD_IS_BLOCK: /******* void (^object)(void) = ...; [^{ object; } copy]; ********/ _Block_assign(_Block_copy_internal(object, false), destAddr); break; case BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK: case BLOCK_FIELD_IS_BYREF: /******* // copy the onstack __block container to the heap __block ... x; __weak __block ... x; [^{ x; } copy]; ********/ _Block_byref_assign_copy(destAddr, object, flags); break; case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT: case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK: /******* // copy the actual field held in the __block container __block id object; __block void (^object)(void); [^{ object; } copy]; ********/ // under manual retain release __block object/block variables are dangling _Block_assign((void *)object, destAddr); break; case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK: case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK | BLOCK_FIELD_IS_WEAK: /******* // copy the actual field held in the __block container __weak __block id object; __weak __block void (^object)(void); [^{ object; } copy]; ********/ _Block_assign_weak(object, destAddr); break; default: break; } }