--- /dev/null
+#define _GNU_SOURCE
+
+#include <substrate.h>
+#include "cycript.hpp"
+
+#include <cstdio>
+#include <sstream>
+
+#include <setjmp.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include <sys/mman.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "Cycript.tab.hh"
+
+static jmp_buf ctrlc_;
+
+void sigint(int) {
+    longjmp(ctrlc_, 1);
+}
+
+void Run(const char *code, FILE *fout) {
+    JSStringRef script(JSStringCreateWithUTF8CString(code));
+
+    JSContextRef context(CYGetJSContext());
+
+    JSValueRef exception(NULL);
+    JSValueRef result(JSEvaluateScript(context, script, NULL, NULL, 0, &exception));
+    JSStringRelease(script);
+
+    if (exception != NULL)
+        result = exception;
+
+    if (!JSValueIsUndefined(context, result)) {
+        CYPool pool;
+        const char *json;
+
+        json = CYPoolJSONString(pool, context, result);
+
+        if (fout != NULL) {
+            fputs(json, fout);
+            fputs("\n", fout);
+            fflush(fout);
+        }
+    }
+}
+
+void Console() {
+    bool bypass(false);
+    bool debug(false);
+
+    FILE *fout(stdout);
+
+    rl_bind_key('\t', rl_insert);
+
+    struct sigaction action;
+    sigemptyset(&action.sa_mask);
+    action.sa_handler = &sigint;
+    action.sa_flags = 0;
+    sigaction(SIGINT, &action, NULL);
+
+    restart: for (;;) {
+        std::string command;
+        std::vector<std::string> lines;
+
+        bool extra(false);
+        const char *prompt("cy# ");
+
+        if (setjmp(ctrlc_) != 0) {
+            fputs("\n", fout);
+            fflush(fout);
+            goto restart;
+        }
+
+      read:
+        char *line(readline(prompt));
+        if (line == NULL)
+            break;
+
+        if (!extra) {
+            extra = true;
+            if (line[0] == '\\') {
+                std::string data(line + 1);
+                if (data == "bypass") {
+                    bypass = !bypass;
+                    fprintf(fout, "bypass == %s\n", bypass ? "true" : "false");
+                    fflush(fout);
+                } else if (data == "debug") {
+                    debug = !debug;
+                    fprintf(fout, "debug == %s\n", debug ? "true" : "false");
+                    fflush(fout);
+                }
+                add_history(line);
+                goto restart;
+            }
+        }
+
+        lines.push_back(line);
+        command += line;
+        free(line);
+
+        std::string code;
+
+        if (bypass)
+            code = command;
+        else {
+            CYDriver driver("");
+            cy::parser parser(driver);
+
+            driver.data_ = command.c_str();
+            driver.size_ = command.size();
+
+            if (parser.parse() != 0 || !driver.errors_.empty()) {
+                for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i) {
+                    cy::position begin(i->location_.begin);
+                    if (begin.line != lines.size() || begin.column - 1 != lines.back().size()) {
+                        std::cerr << i->message_ << std::endl;
+                        add_history(command.c_str());
+                        goto restart;
+                    }
+                }
+
+                driver.errors_.clear();
+
+                command += '\n';
+                prompt = "cy> ";
+                goto read;
+            }
+
+            if (driver.source_ == NULL)
+                goto restart;
+
+            std::ostringstream str;
+            driver.source_->Show(str);
+            code = str.str();
+        }
+
+        add_history(command.c_str());
+
+        if (debug)
+            std::cout << code << std::endl;
+
+        Run(code.c_str(), fout);
+    }
+
+    fputs("\n", fout);
+    fflush(fout);
+}
+
+void *Map(const char *path, size_t *psize) {
+    int fd;
+    _syscall(fd = open(path, O_RDONLY));
+
+    struct stat stat;
+    _syscall(fstat(fd, &stat));
+    size_t size(stat.st_size);
+
+    *psize = size;
+
+    void *base;
+    _syscall(base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0));
+
+    _syscall(close(fd));
+    return base;
+}
+
+int main(int argc, const char *argv[]) {
+    const char *script;
+
+    if (argc == 1)
+        script = NULL;
+    else {
+        CYSetArgs(argc - 1, argv + 1);
+        script = argv[1];
+    }
+
+    if (script == NULL || strcmp(script, "-") == 0)
+        Console();
+    else {
+        CYDriver driver(script);
+        cy::parser parser(driver);
+
+        size_t size;
+        char *start(reinterpret_cast<char *>(Map(script, &size)));
+        char *end(start + size);
+
+        if (size >= 2 && start[0] == '#' && start[1] == '!') {
+            start += 2;
+            while (start != end && *start++ != '\n');
+        }
+
+        driver.data_ = start;
+        driver.size_ = end - start;
+
+        if (parser.parse() != 0 || !driver.errors_.empty()) {
+            for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i)
+                std::cerr << i->location_.begin << ": " << i->message_ << std::endl;
+        } else if (driver.source_ != NULL) {
+            std::ostringstream str;
+            driver.source_->Show(str);
+            std::string code(str.str());
+            std::cout << code << std::endl;
+            Run(code.c_str(), stdout);
+        }
+    }
+
+    return 0;
+}
 
+++ /dev/null
-#define _GNU_SOURCE
-
-#include <substrate.h>
-#include "cycript.hpp"
-
-#include <cstdio>
-#include <sstream>
-
-#include <setjmp.h>
-
-#include <readline/readline.h>
-#include <readline/history.h>
-
-#include <sys/mman.h>
-
-#include <errno.h>
-#include <unistd.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "Cycript.tab.hh"
-
-static jmp_buf ctrlc_;
-
-void sigint(int) {
-    longjmp(ctrlc_, 1);
-}
-
-void Run(const char *code, FILE *fout) { _pooled
-    JSStringRef script(JSStringCreateWithUTF8CString(code));
-
-    JSContextRef context(CYGetJSContext());
-
-    JSValueRef exception(NULL);
-    JSValueRef result(JSEvaluateScript(context, script, NULL, NULL, 0, &exception));
-    JSStringRelease(script);
-
-    if (exception != NULL)
-        result = exception;
-
-    if (!JSValueIsUndefined(context, result)) {
-        CFStringRef json;
-
-        @try { json:
-            json = CYCopyJSONString(context, result);
-        } @catch (id error) {
-            CYThrow(context, error, &result);
-            goto json;
-        }
-
-        if (fout != NULL) {
-            fputs([reinterpret_cast<const NSString *>(json) UTF8String], fout);
-            fputs("\n", fout);
-            fflush(fout);
-        }
-
-        CFRelease(json);
-    }
-}
-
-void Console() {
-    bool bypass(false);
-    bool debug(false);
-
-    FILE *fout(stdout);
-
-    rl_bind_key('\t', rl_insert);
-
-    struct sigaction action;
-    sigemptyset(&action.sa_mask);
-    action.sa_handler = &sigint;
-    action.sa_flags = 0;
-    sigaction(SIGINT, &action, NULL);
-
-    restart: for (;;) {
-        std::string command;
-        std::vector<std::string> lines;
-
-        bool extra(false);
-        const char *prompt("cy# ");
-
-        if (setjmp(ctrlc_) != 0) {
-            fputs("\n", fout);
-            fflush(fout);
-            goto restart;
-        }
-
-      read:
-        char *line(readline(prompt));
-        if (line == NULL)
-            break;
-
-        if (!extra) {
-            extra = true;
-            if (line[0] == '\\') {
-                std::string data(line + 1);
-                if (data == "bypass") {
-                    bypass = !bypass;
-                    fprintf(fout, "bypass == %s\n", bypass ? "true" : "false");
-                    fflush(fout);
-                } else if (data == "debug") {
-                    debug = !debug;
-                    fprintf(fout, "debug == %s\n", debug ? "true" : "false");
-                    fflush(fout);
-                }
-                add_history(line);
-                goto restart;
-            }
-        }
-
-        lines.push_back(line);
-        command += line;
-        free(line);
-
-        std::string code;
-
-        if (bypass)
-            code = command;
-        else {
-            CYDriver driver("");
-            cy::parser parser(driver);
-
-            driver.data_ = command.c_str();
-            driver.size_ = command.size();
-
-            if (parser.parse() != 0 || !driver.errors_.empty()) {
-                for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i) {
-                    cy::position begin(i->location_.begin);
-                    if (begin.line != lines.size() || begin.column - 1 != lines.back().size()) {
-                        std::cerr << i->message_ << std::endl;
-                        add_history(command.c_str());
-                        goto restart;
-                    }
-                }
-
-                driver.errors_.clear();
-
-                command += '\n';
-                prompt = "cy> ";
-                goto read;
-            }
-
-            if (driver.source_ == NULL)
-                goto restart;
-
-            std::ostringstream str;
-            driver.source_->Show(str);
-            code = str.str();
-        }
-
-        add_history(command.c_str());
-
-        if (debug)
-            std::cout << code << std::endl;
-
-        Run(code.c_str(), fout);
-    }
-
-    fputs("\n", fout);
-    fflush(fout);
-}
-
-void *Map(const char *path, size_t *psize) {
-    int fd;
-    _syscall(fd = open(path, O_RDONLY));
-
-    struct stat stat;
-    _syscall(fstat(fd, &stat));
-    size_t size(stat.st_size);
-
-    *psize = size;
-
-    void *base;
-    _syscall(base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0));
-
-    _syscall(close(fd));
-    return base;
-}
-
-int main(int argc, const char *argv[]) {
-    const char *script;
-
-    if (argc == 1)
-        script = NULL;
-    else {
-        CYSetArgs(argc - 1, argv + 1);
-        script = argv[1];
-    }
-
-    if (script == NULL || strcmp(script, "-") == 0)
-        Console();
-    else {
-        CYDriver driver(script);
-        cy::parser parser(driver);
-
-        size_t size;
-        char *start(reinterpret_cast<char *>(Map(script, &size)));
-        char *end(start + size);
-
-        if (size >= 2 && start[0] == '#' && start[1] == '!') {
-            start += 2;
-            while (start != end && *start++ != '\n');
-        }
-
-        driver.data_ = start;
-        driver.size_ = end - start;
-
-        if (parser.parse() != 0 || !driver.errors_.empty()) {
-            for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i)
-                std::cerr << i->location_.begin << ": " << i->message_ << std::endl;
-        } else if (driver.source_ != NULL) {
-            std::ostringstream str;
-            driver.source_->Show(str);
-            std::string code(str.str());
-            std::cout << code << std::endl;
-            Run(code.c_str(), stdout);
-        }
-    }
-
-    return 0;
-}
 
     CFLog(kCFLogLevelNotice, CFSTR("_trace():%u"), __LINE__); \
 } while (false)
 
-static JSContextRef Context_;
+static JSGlobalContextRef Context_;
 static JSObjectRef System_;
 
 static JSClassRef Functor_;
     CFSocketRef socket_;
 };
 
-JSObjectRef CYMakeInstance(JSContextRef context, id object) {
-    return JSObjectMake(context, Instance_, object);
+struct ptrData {
+    apr_pool_t *pool_;
+    void *value_;
+    sig::Type type_;
+
+    void *operator new(size_t size) {
+        apr_pool_t *pool;
+        apr_pool_create(&pool, NULL);
+        void *data(apr_palloc(pool, size));
+        reinterpret_cast<ptrData *>(data)->pool_ = pool;
+        return data;;
+    }
+
+    ptrData(void *value) :
+        value_(value)
+    {
+    }
+
+    virtual ~ptrData() {
+    }
+};
+
+struct ffiData : ptrData {
+    sig::Signature signature_;
+    ffi_cif cif_;
+
+    ffiData(const char *type, void (*value)()) :
+        ptrData(reinterpret_cast<void *>(value))
+    {
+        sig::Parse(pool_, &signature_, type);
+        sig::sig_ffi_cif(pool_, &sig::ObjectiveC, &signature_, &cif_);
+    }
+};
+
+struct ffoData : ffiData {
+    JSContextRef context_;
+    JSObjectRef function_;
+
+    ffoData(const char *type) :
+        ffiData(type, NULL)
+    {
+    }
+};
+
+struct selData : ptrData {
+    selData(SEL value) :
+        ptrData(value)
+    {
+    }
+
+    SEL GetValue() const {
+        return reinterpret_cast<SEL>(value_);
+    }
+};
+
+struct jocData : ptrData {
+    bool transient_;
+
+    jocData(id value, bool transient) :
+        ptrData(value)
+    {
+    }
+
+    virtual ~jocData() {
+        if (!transient_)
+            [GetValue() release];
+    }
+
+    id GetValue() const {
+        return reinterpret_cast<id>(value_);
+    }
+};
+
+JSObjectRef CYMakeInstance(JSContextRef context, id object, bool transient = true) {
+    if (!transient)
+        object = [object retain];
+    jocData *data(new jocData(object, transient));
+    return JSObjectMake(context, Instance_, data);
+}
+
+const char *CYPoolCString(apr_pool_t *pool, NSString *value) {
+    if (pool == NULL)
+        return [value UTF8String];
+    else {
+        size_t size([value maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1);
+        char *string(new(pool) char[size]);
+        if (![value getCString:string maxLength:size encoding:NSUTF8StringEncoding])
+            @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"[NSString getCString:maxLength:encoding:] == NO" userInfo:nil];
+        return string;
+    }
 }
 
 JSValueRef CYCastJSValue(JSContextRef context, bool value) {
 
 @end
 
+@implementation NSNull (Cycript)
+
+- (NSString *) cy$toJSON {
+    return @"null";
+}
+
+@end
+
 @implementation NSArray (Cycript)
 
 - (NSString *) cy$toJSON {
 }
 
 - (void *) cy$symbol {
-    return dlsym(RTLD_DEFAULT, [self UTF8String]);
+    CYPool pool;
+    return dlsym(RTLD_DEFAULT, CYPoolCString(pool, self));
 }
 
 @end
 CYRange WordStartRange_(0x1000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$
 CYRange WordEndRange_(0x3ff001000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$0-9
 
-JSContextRef CYGetJSContext() {
+JSGlobalContextRef CYGetJSContext() {
     return Context_;
 }
 
 }
 
 id CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSObjectRef object) {
-    if (JSValueIsObjectOfClass(context, object, Instance_))
-        return reinterpret_cast<id>(JSObjectGetPrivate(object));
+    if (JSValueIsObjectOfClass(context, object, Instance_)) {
+        jocData *data(reinterpret_cast<jocData *>(JSObjectGetPrivate(object)));
+        return data->GetValue();
+    }
+
     JSValueRef exception(NULL);
     bool array(JSValueIsInstanceOfConstructor(context, object, Array_, &exception));
     CYThrow(context, exception);
 }
 
 - (id) objectForKey:(id)key {
-    return CYCastNSObject(NULL, context_, CYGetProperty(context_, object_, CYJSString(key)));
+    return CYCastNSObject(NULL, context_, CYGetProperty(context_, object_, CYJSString(key))) ?: [NSNull null];
 }
 
 - (NSEnumerator *) keyEnumerator {
     JSValueRef exception(NULL);
     JSValueRef value(JSObjectGetPropertyAtIndex(context_, object_, index, &exception));
     CYThrow(context_, exception);
-    id object(CYCastNSObject(NULL, context_, value));
-    return object == nil ? [NSNull null] : object;
+    return CYCastNSObject(NULL, context_, value) ?: [NSNull null];
 }
 
 @end
 
-CFStringRef CYCopyJSONString(JSContextRef context, JSValueRef value) {
+CFStringRef CYCopyJSONString(JSContextRef context, JSValueRef value) { _pooled
     id object(CYCastNSObject(NULL, context, value));
     return reinterpret_cast<CFStringRef>([(object == nil ? @"null" : [object cy$toJSON]) retain]);
 }
 
+const char *CYPoolJSONString(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
+    NSString *json((NSString *) CYCopyJSONString(context, value));
+    const char *string(CYPoolCString(pool, json));
+    [json release];
+    return string;
+}
+
 static void OnData(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *value, void *info) {
     switch (type) {
         case kCFSocketDataCallBack:
     } CYCatch
 }
 
-typedef id jocData;
-
 static JSObjectRef Instance_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
     @try {
-        id data(reinterpret_cast<jocData>(JSObjectGetPrivate(object)));
-        return CYMakeInstance(context, [data alloc]);
+        jocData *data(reinterpret_cast<jocData *>(JSObjectGetPrivate(object)));
+        return CYMakeInstance(context, [data->GetValue() alloc]);
     } CYCatch
 }
 
-struct ptrData {
-    apr_pool_t *pool_;
-    void *value_;
-    sig::Type type_;
-
-    void *operator new(size_t size) {
-        apr_pool_t *pool;
-        apr_pool_create(&pool, NULL);
-        void *data(apr_palloc(pool, size));
-        reinterpret_cast<ptrData *>(data)->pool_ = pool;
-        return data;;
-    }
-
-    ptrData(void *value) :
-        value_(value)
-    {
-    }
-};
-
-struct ffiData : ptrData {
-    sig::Signature signature_;
-    ffi_cif cif_;
-
-    ffiData(const char *type, void (*value)() = NULL) :
-        ptrData(reinterpret_cast<void *>(value))
-    {
-        sig::Parse(pool_, &signature_, type);
-        sig::sig_ffi_cif(pool_, &sig::ObjectiveC, &signature_, &cif_);
-    }
-};
-
-struct selData : ptrData {
-    selData(SEL value) :
-        ptrData(value)
-    {
-    }
-
-    SEL GetValue() const {
-        return reinterpret_cast<SEL>(value_);
-    }
-};
-
 JSObjectRef CYMakeSelector(JSContextRef context, SEL sel) {
     selData *data(new selData(sel));
     return JSObjectMake(context, Selector_, data);
 
 static void Pointer_finalize(JSObjectRef object) {
     ptrData *data(reinterpret_cast<ptrData *>(JSObjectGetPrivate(object)));
+    data->~ptrData();
     apr_pool_destroy(data->pool_);
 }
 
-/*static void Instance_finalize(JSObjectRef object) {
-    id data(reinterpret_cast<jocData>(JSObjectGetPrivate(object)));
-}*/
-
 JSObjectRef CYMakeFunctor(JSContextRef context, void (*function)(), const char *type) {
     ffiData *data(new ffiData(type, function));
     return JSObjectMake(context, Functor_, data);
 }
 
-void Closure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
-}
-
-JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const char *type) {
-    // XXX: in case of exceptions this will leak
-    ffiData *data(new ffiData(type));
-
-    ffi_closure *closure;
-    _syscall(closure = (ffi_closure *) mmap(
-        NULL, sizeof(ffi_closure),
-        PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
-        -1, 0
-    ));
-
-    ffi_status status(ffi_prep_closure(closure, &data->cif_, &Closure_, data));
-    _assert(status == FFI_OK);
-
-    _syscall(mprotect(closure, sizeof(*closure), PROT_READ | PROT_EXEC));
-
-    return JSObjectMake(context, Functor_, data);
-}
-
-char *CYPoolCString(apr_pool_t *pool, JSStringRef value) {
-    size_t size(JSStringGetMaximumUTF8CStringSize(value));
-    char *string(new(pool) char[size]);
-    JSStringGetUTF8CString(value, string, size);
-    return string;
+const char *CYPoolCString(apr_pool_t *pool, JSStringRef value) {
+    if (pool == NULL)
+        return [CYCastNSString(NULL, value) UTF8String];
+    else {
+        size_t size(JSStringGetMaximumUTF8CStringSize(value));
+        char *string(new(pool) char[size]);
+        JSStringGetUTF8CString(value, string, size);
+        return string;
+    }
 }
 
-char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
+const char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
     if (JSValueIsNull(context, value))
         return NULL;
     return CYPoolCString(pool, CYJSString(context, value));
     char *utf8; \
     if (value == NULL) \
         utf8 = NULL; \
-    else { \
-        JSStringRef string(CYCopyJSString(context, value)); \
+    else if (JSStringRef string = CYCopyJSString(context, value)) { \
         size_t size(JSStringGetMaximumUTF8CStringSize(string)); \
         utf8 = reinterpret_cast<char *>(alloca(size)); \
         JSStringGetUTF8CString(string, utf8, size); \
         JSStringRelease(string); \
-    } \
+    } else \
+        utf8 = NULL; \
     utf8; \
 })
 
         break;
 
         case sig::string_P:
-            *reinterpret_cast<char **>(data) = CYPoolCString(pool, context, value);
+            *reinterpret_cast<const char **>(data) = CYPoolCString(pool, context, value);
         break;
 
         case sig::struct_P:
     } CYCatch
 }
 
+void Closure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
+    NSLog(@"Closure()");
+    ffoData *data(reinterpret_cast<ffoData *>(arg));
+
+    JSContextRef context(data->context_);
+
+    size_t count(data->cif_.nargs);
+    JSValueRef values[count];
+
+    for (size_t index(0); index != count; ++index)
+        values[index] = CYFromFFI(context, data->signature_.elements[1 + index].type, arguments[index]);
+
+    JSValueRef exception(NULL);
+    JSValueRef value(JSObjectCallAsFunction(context, data->function_, NULL, count, values, &exception));
+    CYThrow(context, exception);
+
+    CYPoolFFI(NULL, context, data->signature_.elements[0].type, result, value);
+}
+
+JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const char *type) {
+    // XXX: in case of exceptions this will leak
+    ffoData *data(new ffoData(type));
+
+    ffi_closure *closure;
+    _syscall(closure = (ffi_closure *) mmap(
+        NULL, sizeof(ffi_closure),
+        PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
+        -1, 0
+    ));
+
+    ffi_status status(ffi_prep_closure(closure, &data->cif_, &Closure_, data));
+    _assert(status == FFI_OK);
+
+    _syscall(mprotect(closure, sizeof(*closure), PROT_READ | PROT_EXEC));
+
+    data->value_ = closure;
+
+    data->context_ = CYGetJSContext();
+    data->function_ = function;
+
+    return JSObjectMake(context, Functor_, data);
+}
+
 static JSValueRef Global_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
     @try {
         CYPool pool;
                 case 0:
                     return JSEvaluateScript(CYGetJSContext(), CYJSString([entry objectAtIndex:1]), NULL, NULL, 0, NULL);
                 case 1:
-                    return CYMakeFunctor(context, reinterpret_cast<void (*)()>([name cy$symbol]), [[entry objectAtIndex:1] UTF8String]);
+                    return CYMakeFunctor(context, reinterpret_cast<void (*)()>([name cy$symbol]), CYPoolCString(pool, [entry objectAtIndex:1]));
                 case 2:
-                    CYPool pool;
                     sig::Signature signature;
-                    sig::Parse(pool, &signature, [[entry objectAtIndex:1] UTF8String]);
+                    sig::Parse(pool, &signature, CYPoolCString(pool, [entry objectAtIndex:1]));
                     return CYFromFFI(context, signature.elements[0].type, [name cy$symbol]);
             }
         return NULL;
     @try {
         CYPool pool;
         NSString *name(CYCastNSObject(pool, context, arguments[0]));
-        int argc(*_NSGetArgc() - 1);
-        char **argv(*_NSGetArgv() + 1);
+        int argc(*_NSGetArgc());
+        char **argv(*_NSGetArgv());
         for (int i(0); i != argc; ++i)
             NSLog(@"argv[%i]=%s", i, argv[i]);
+        _pooled
         return CYCastJSValue(context, UIApplicationMain(argc, argv, name, name));
     } CYCatch
 }
 static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
     const char *type;
 
+    CYPool pool;
+
     @try {
         if (count < 2)
             @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"too few arguments to objc_msgSend" userInfo:nil];
 
-        CYPool pool;
-
         id self(CYCastNSObject(pool, context, arguments[0]));
         if (self == nil)
             return CYJSNull(context);
 
         SEL _cmd(CYCastSEL(context, arguments[1]));
-        NSMethodSignature *method([self methodSignatureForSelector:_cmd]);
-        if (method == nil)
-            @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"unrecognized selector %s sent to object %p", sel_getName(_cmd), self] userInfo:nil];
 
-        type = [[method _typeString] UTF8String];
+        Class _class(object_getClass(self));
+        if (Method method = class_getInstanceMethod(_class, _cmd))
+            type = method_getTypeEncoding(method);
+        else { _pooled
+            NSMethodSignature *method([self methodSignatureForSelector:_cmd]);
+            if (method == nil)
+                @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"unrecognized selector %s sent to object %p", sel_getName(_cmd), self] userInfo:nil];
+            type = CYPoolCString(pool, [method _typeString]);
+        }
     } CYCatch
 
-    CYPool pool;
-
     sig::Signature signature;
     sig::Parse(pool, &signature, type);
 
     return Function_;
 }
 
+static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { _pooled
+    @try {
+        jocData *data(reinterpret_cast<jocData *>(JSObjectGetPrivate(_this)));
+        return CYCastJSValue(context, CYJSString([data->GetValue() description]));
+    } CYCatch
+}
+
+static JSValueRef Selector_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+    @try {
+        selData *data(reinterpret_cast<selData *>(JSObjectGetPrivate(_this)));
+        return CYCastJSValue(context, sel_getName(data->GetValue()));
+    } CYCatch
+}
+
 static JSValueRef Selector_callAsFunction_type(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
     @try {
         if (count != 2)
         SEL sel(data->GetValue());
         if (Method method = (*(instance ? &class_getInstanceMethod : class_getClassMethod))(_class, sel))
             return CYCastJSValue(context, method_getTypeEncoding(method));
-        else if (NSString *type = [Bridge_ objectForKey:[NSString stringWithFormat:@":%s", sel_getName(sel)]])
+        else if (NSString *type = [Bridge_ objectForKey:CYPoolRelease(pool, [[NSString alloc] initWithFormat:@":%s", sel_getName(sel)])])
             return CYCastJSValue(context, CYJSString(type));
         else
             return CYJSNull(context);
     {NULL, NULL, NULL, 0}
 };*/
 
-static JSStaticFunction Selector_staticFunctions[2] = {
+static JSStaticFunction Instance_staticFunctions[2] = {
+    {"toString", &Instance_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {NULL, NULL, 0}
+};
+
+static JSStaticFunction Selector_staticFunctions[3] = {
+    {"toString", &Selector_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {"type", &Selector_callAsFunction_type, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {NULL, NULL, 0}
 };
 
     definition = kJSClassDefinitionEmpty;
     definition.className = "Instance";
+    definition.parentClass = Pointer_;
+    definition.staticFunctions = Instance_staticFunctions;
     definition.getProperty = &Instance_getProperty;
     definition.setProperty = &Instance_setProperty;
     definition.deleteProperty = &Instance_deleteProperty;
     definition.callAsConstructor = &Instance_callAsConstructor;
-    //definition.finalize = &Instance_finalize;
     Instance_ = JSClassCreate(&definition);
 
     definition = kJSClassDefinitionEmpty;
     definition.getProperty = &Global_getProperty;
     JSClassRef Global(JSClassCreate(&definition));
 
-    JSContextRef context(JSGlobalContextCreate(Global));
+    JSGlobalContextRef context(JSGlobalContextCreate(Global));
     Context_ = context;
 
     JSObjectRef global(JSContextGetGlobalObject(context));