A declaration for an ÒwrapperÓ callback looks like this: foreign import ccall safe "wrapper" mkDelegate :: IO () -> IO (FunPtr (IO ())) To implement these, GHC normally generates a small piece of executable code at runtime, called an ÒadjustorÓ. The purpose of these ÒwrapperÓ declarations is to generate a C-callable function pointer that executes a Haskell closure. Apple has a code-signing policy, that says that all code that runs on the iPhone must be signed by Apple. GHC wants to generate code at runtime, and this can't be signed by Apple. This is enforced by the iPhone's kernel, so GHC's standard implementation is impossible. This iPhone port solves the problem by pre-compiling a pool of functions, and allocating from it. If the pool is too small for a given application, you can increase it by using a {-# POOLSIZE x #-} pragma, which must appear after the "wrapper" token. e.g. foreign import ccall safe "wrapper" {-# POOLSIZE 100 #-} mkDelegate :: IO () -> IO (FunPtr (IO ())) ================== Changes to the runtime system to achieve the above See also 05-adjustor-pool-compiler-changes.patch --- ghc-6.10.2.orig/rts/Adjustor.c 2009-03-31 06:13:15.000000000 +1300 +++ ghc-6.10.2/rts/Adjustor.c 2009-06-18 15:54:37.000000000 +1200 @@ -42,7 +42,108 @@ #include "RtsUtils.h" #include -#if defined(USE_LIBFFI_FOR_ADJUSTORS) +#if defined(darwin_HOST_OS) + +#include "Hash.h" + +/* iPhone, iPhone, iPhone, tsk, tsk... + * + * The iPhone doesn't allow self-modifying code, so instead we allocate out of + * a pool of pre-compiled functions. + */ + +struct iPhoneAdjustor; + +struct iPhoneAdjustorEntry { + void* func; + struct iPhoneAdjustor* adjustor; +}; + +struct iPhoneAdjustor +{ + struct iPhoneAdjustorEntry* poolEntry; + StgStablePtr hptr; + StgFunPtr wptr; +}; + +#if defined(THREADED_RTS) +static Mutex iPhoneAdjustorMutex; +#endif + +static HashTable* allocatedAdjustors; +void iPhoneAdjustorInit(void); +void* iPhoneCreateAdjustor(int cconv, + StgStablePtr hptr, + StgFunPtr wptr, + char *typeString, + char* descr, + struct iPhoneAdjustorEntry* pool); + +void +iPhoneAdjustorInit() +{ +#if defined(THREADED_RTS) + initMutex(&iPhoneAdjustorMutex); +#endif + allocatedAdjustors = allocHashTable(); +} + +void* +iPhoneCreateAdjustor(int cconv, + StgStablePtr hptr, + StgFunPtr wptr, + char *typeString, + char* descr, + struct iPhoneAdjustorEntry* pool) +{ + int i; + + ACQUIRE_LOCK(&iPhoneAdjustorMutex); + /* Look for a free slot in the function pool. */ + for (i = 0; pool[i].func != NULL; i ++) { + if (pool[i].adjustor == NULL) { + struct iPhoneAdjustor* adj = stgMallocBytes(sizeof(struct iPhoneAdjustor), + "iPhoneAdjustor"); + pool[i].adjustor = adj; + insertHashTable(allocatedAdjustors, (StgWord)pool[i].func, adj); + RELEASE_LOCK(&iPhoneAdjustorMutex); + adj->poolEntry = pool + i; + adj->hptr = hptr; + adj->wptr = wptr; + return pool[i].func; + } + } + RELEASE_LOCK(&iPhoneAdjustorMutex); + barf("iPhoneCreateAdjustor - adjustor pool '%s' is empty (capacity %d)", descr, i); +} + +StgStablePtr iPhoneLookupAdjustor(void* entry_) +{ + struct iPhoneAdjustorEntry* entry = (struct iPhoneAdjustorEntry*) entry_; + return entry->adjustor->hptr; +} + +void +freeHaskellFunctionPtr(void* ptr) +{ + struct iPhoneAdjustor* adj; + + ACQUIRE_LOCK(&iPhoneAdjustorMutex); + adj = lookupHashTable(allocatedAdjustors, (StgWord)ptr); + if (adj != NULL) { + removeHashTable(allocatedAdjustors, (StgWord)ptr, adj); + adj->poolEntry->adjustor = NULL; + RELEASE_LOCK(&iPhoneAdjustorMutex); + + freeStablePtr(adj->hptr); + stgFree(adj); + } + else { + RELEASE_LOCK(&iPhoneAdjustorMutex); + } +} + +#elif defined(USE_LIBFFI_FOR_ADJUSTORS) #include "ffi.h" #include --- ghc-6.10.2.orig/rts/RtsStartup.c 2009-03-31 06:13:16.000000000 +1300 +++ ghc-6.10.2/rts/RtsStartup.c 2009-06-18 15:54:37.000000000 +1200 @@ -130,6 +130,10 @@ } #endif +#if defined(darwin_HOST_OS) + void iPhoneAdjustorInit(void); +#endif + /* ----------------------------------------------------------------------------- Starting up the RTS -------------------------------------------------------------------------- */ @@ -281,6 +285,10 @@ x86_init_fpu(); #endif +#if defined(darwin_HOST_OS) + iPhoneAdjustorInit(); +#endif + /* Record initialization times */ stat_endInit(); }