1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LLVM_LICENSE_HEADER@ 5 */ 6 7/* 8 * import_byref.c 9 * Examples 10 * 11 * Created by Blaine Garst on 2/1/08. 12 * Copyright 2008 __MyCompanyName__. All rights reserved. 13 * 14 */ 15 16 17#include "driver.h" 18 19// 20// Example closure code generated for specific Blocks 21// 22 23// 24// Fully bound computation on const imported locals 25// 26 27#if __BLOCKS__ 28int import_byref_real(int verbose) { 29 int x = rand(); 30 int y = 15; 31 void (^myClosure)(void) = ^ (void) { | y | setGlobalInt(x+y); ++y;}; 32 x++; 33 callVoidVoid(myClosure); 34 35 int globalValue = getGlobalInt(); 36 int desiredValue = x + y - 2; 37 if (error_found("import byref", globalValue, desiredValue, verbose)) return 1; 38 39#if FULL_CLOSURES 40// not yet 41 void (^myClosureCopy)(void) = Block_copy(myClosure); 42 callVoidVoid(myClosureCopy, NULL); 43 44 globalValue = getGlobalInt(); 45 if (error_found("import byref copy", globalValue, desiredValue, verbose)) return 1; 46 47 Block_release(myClosureCopy); 48#endif 49 return 0; 50} 51 52#endif __BLOCKS__ 53 54// the closure data structure sythesized for the import_byref 55struct import_byref_shared_struct { 56 struct Block_byref base; 57 int y; 58}; 59 60 61struct import_byref_struct { 62 struct Block_basic base; 63 const int x; 64 struct import_byref_shared_struct *shared_struct; 65}; 66 67void print_byref_struct(struct import_byref_shared_struct *ibs) { 68 printf("byref structure @ %p:\n", ibs); 69 printf("forwarding: %p\nrefcount: %d\nsize: %d\n", ibs->base.forwarding, ibs->base.flags, ibs->base.size); 70 printf("y: %d\n\n", ibs->y); 71} 72 73// the "thunks" compiled for the invoke entry point of the import_byref 74 75void invoke_import_byref(struct import_byref_struct *aBlock) { 76 // no return value so just a void invoke 77 // the compound statement rewritten to reference locals via the const copies. 78 { 79 setGlobalInt(aBlock->x + aBlock->shared_struct->y); 80 ++aBlock->shared_struct->y; 81 } 82} 83 84// fix up the just copied closure 85void copy_import_byref(struct import_byref_struct *dst, struct import_byref_struct *src) { 86 87 // do closure specific work 88 // the new closure can't reference the stack, so update it's pointer. 89 // _Block_byref_assign_copy will either copy it to the heap or bump the heap refcount 90 //print_byref_struct(aBlock->shared_struct); 91 _Block_byref_assign_copy(&dst->shared_struct, src->shared_struct); 92 //print_byref_struct(aBlock->shared_struct); 93 94} 95 96// the closure 'destructor' 97// Only called when destroying a heap based closure 98void destroy_import_byref(struct import_byref_struct *aBlock) { 99 // do closure specific unwork 100 // lose the heap based closure's reference to the shared struct 101 // The lexical scope will also have this call synthesized 102 Block_release_byref(aBlock->shared_struct); 103} 104 105// The rewritten version of the code above 106 107int import_byref(int verbose) { 108 int x = rand(); 109 // XXX move this into support routine 110 struct import_byref_shared_struct shared_struct; 111 shared_struct.base.flags = 0;//BLOCK_HAS_COPY_DISPOSE; 112 shared_struct.base.forwarding = &shared_struct; 113 shared_struct.base.size = sizeof(struct import_byref_shared_struct); 114 115 // this byref does not contain 116 // 1) another closure 117 // 2) an id 118 // 3) a C++ stack object 119 // and so, there is nothing for it to do on preserve/destroy 120 shared_struct.base.byref_destroy = NULL; 121 shared_struct.base.byref_keep = NULL; 122 123 shared_struct.y = 15; 124 struct import_byref_struct myClosure = { 125 { 0, BLOCK_HAS_COPY_DISPOSE, sizeof(struct import_byref_struct), 126 (void (*)(void *))invoke_import_byref, 127 (void (*)(void *, void *))copy_import_byref, 128 (void (*)(void *))destroy_import_byref 129 }, 130 x, // capture x 131 &shared_struct // capture y 132 }; 133 x++; 134 callVoidVoid(&myClosure.base); 135 136 int globalValue = getGlobalInt(); 137 int desiredValue = x + ((struct import_byref_shared_struct *)(shared_struct.base.forwarding))->y - 2; 138 if (error_found("import byref", globalValue, desiredValue, verbose)) return 1; 139 140 struct import_byref_struct *myClosureCopy = Block_copy(&myClosure); 141 callVoidVoid(&myClosureCopy->base); 142 143 globalValue = getGlobalInt(); 144 ++desiredValue; // y was incr'ed after first invocation 145 if (error_found("import byref copy", globalValue, desiredValue, verbose)) return 1; 146 147 Block_release(myClosureCopy); 148 149 // the following is synthesized sometime after the last use of all shared variables 150 // the first time any closure that uses shared_struct is copied, an extra refcount on that new 151 // copy is provided for this stack frame's use. This stack frame needs to relinquish that code. 152 153 // XXX if shared_struct.base.forwarding != &shared_struct) ... 154 Block_release_byref(shared_struct.base.forwarding); 155 156 return 0; 157} 158