X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/62ca2b826a50e29394b6b930a2531220ced3b508..5a36c6cf6ef94d7f7c6b55c8acf05e81ea0c64b3:/Tweak.mm diff --git a/Tweak.mm b/Tweak.mm index 2dc974a..0efe892 100644 --- a/Tweak.mm +++ b/Tweak.mm @@ -38,6 +38,13 @@ /* }}} */ #include +#include "Struct.hpp" + +#include "sig/parse.hpp" +#include "sig/ffi_type.hpp" + +#include +#include #include @@ -60,6 +67,9 @@ #include #include +#undef _assert +#undef _trace + /* XXX: bad _assert */ #define _assert(test) do { \ if ((test)) break; \ @@ -71,12 +81,80 @@ CFLog(kCFLogLevelNotice, CFSTR("_trace():%u"), __LINE__); \ } while (false) -static JSContextRef context_; +/* Objective-C Handle<> {{{ */ +template +class _H { + typedef _H This_; + + private: + Type_ *value_; + + _finline void Retain_() { + if (value_ != nil) + [value_ retain]; + } + + _finline void Clear_() { + if (value_ != nil) + [value_ release]; + } + + public: + _finline _H(const This_ &rhs) : + value_(rhs.value_ == nil ? nil : [rhs.value_ retain]) + { + } + + _finline _H(Type_ *value = NULL, bool mended = false) : + value_(value) + { + if (!mended) + Retain_(); + } + + _finline ~_H() { + Clear_(); + } + + _finline operator Type_ *() const { + return value_; + } + + _finline This_ &operator =(Type_ *value) { + if (value_ != value) { + Type_ *old(value_); + value_ = value; + Retain_(); + if (old != nil) + [old release]; + } return *this; + } +}; +/* }}} */ + +#define _pooled _H _pool([[NSAutoreleasePool alloc] init], true); + +void *operator new(size_t size, apr_pool_t *pool) { + return apr_palloc(pool, size); +} + +void *operator new [](size_t size, apr_pool_t *pool) { + return apr_palloc(pool, size); +} + +static JSContextRef Context_; + +static JSClassRef ffi_; static JSClassRef joc_; +static JSClassRef ptr_; +static JSClassRef sel_; + static JSObjectRef Array_; + static JSStringRef name_; static JSStringRef message_; static JSStringRef length_; + static Class NSCFBoolean_; struct Client { @@ -84,9 +162,17 @@ struct Client { CFSocketRef socket_; }; +JSObjectRef CYMakeObject(JSContextRef context, id object) { + return JSObjectMake(context, joc_, [object retain]); +} + +@interface NSMethodSignature (Cyrver) +- (NSString *) _typeString; +@end + @interface NSObject (Cyrver) - (NSString *) cy$toJSON; -// XXX: - (JSValueRef) cy$JSValueInContext:(JSContextRef)context; +- (JSValueRef) cy$JSValueInContext:(JSContextRef)context; @end @implementation NSObject (Cyrver) @@ -95,6 +181,10 @@ struct Client { return [self description]; } +- (JSValueRef) cy$JSValueInContext:(JSContextRef)context { + return CYMakeObject(context, self); +} + @end @implementation WebUndefined (Cyrver) @@ -134,7 +224,8 @@ struct Client { - (NSString *) cy$toJSON { NSMutableString *json([[[NSMutableString alloc] init] autorelease]); - [json appendString:@"({"]; + [json appendString:@"("]; + [json appendString:@"{"]; bool comma(false); for (id key in self) { @@ -185,7 +276,7 @@ struct Client { @end -@interface CY$JSObject : NSDictionary { +@interface CYJSObject : NSDictionary { JSObjectRef object_; JSContextRef context_; } @@ -200,7 +291,7 @@ struct Client { @end -@interface CY$JSArray : NSArray { +@interface CYJSArray : NSArray { JSObjectRef object_; JSContextRef context_; } @@ -213,72 +304,68 @@ struct Client { @end JSContextRef JSGetContext() { - return context_; + return Context_; } -id JSObjectToNSObject(JSContextRef ctx, JSObjectRef object) { - if (JSValueIsObjectOfClass(ctx, object, joc_)) +#define CYCatch \ + @catch (id error) { \ + CYThrow(context, error, exception); \ + return NULL; \ + } + +void CYThrow(JSContextRef context, JSValueRef value); + +id CYCastNSObject(JSContextRef context, JSObjectRef object) { + if (JSValueIsObjectOfClass(context, object, joc_)) return reinterpret_cast(JSObjectGetPrivate(object)); - // XXX: exception - else if (JSValueIsInstanceOfConstructor(ctx, object, Array_, NULL)) - return [[[CY$JSArray alloc] initWithJSObject:object inContext:ctx] autorelease]; - else - return [[[CY$JSObject alloc] initWithJSObject:object inContext:ctx] autorelease]; + JSValueRef exception(NULL); + bool array(JSValueIsInstanceOfConstructor(context, object, Array_, &exception)); + CYThrow(context, exception); + if (array) + return [[[CYJSArray alloc] initWithJSObject:object inContext:context] autorelease]; + return [[[CYJSObject alloc] initWithJSObject:object inContext:context] autorelease]; } CFStringRef CYCopyCFString(JSStringRef value) { return JSStringCopyCFString(kCFAllocatorDefault, value); } -void CYThrow(JSContextRef ctx, JSValueRef value); - -CFStringRef CYCopyCFString(JSContextRef ctx, JSValueRef value) { +CFStringRef CYCopyCFString(JSContextRef context, JSValueRef value) { JSValueRef exception(NULL); - JSStringRef string(JSValueToStringCopy(ctx, value, &exception)); - CYThrow(context_, exception); + JSStringRef string(JSValueToStringCopy(context, value, &exception)); + CYThrow(context, exception); CFStringRef object(CYCopyCFString(string)); JSStringRelease(string); return object; } +CFNumberRef CYCopyCFNumber(JSContextRef context, JSValueRef value) { + JSValueRef exception(NULL); + double number(JSValueToNumber(context, value, &exception)); + CYThrow(context, exception); + return CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &number); +} + NSString *CYCastNSString(JSStringRef value) { return [reinterpret_cast(CYCopyCFString(value)) autorelease]; } -CFTypeRef CYCopyCFType(JSContextRef ctx, JSValueRef value) { - JSType type(JSValueGetType(ctx, value)); - - switch (type) { +CFTypeRef CYCopyCFType(JSContextRef context, JSValueRef value) { + switch (JSValueGetType(context, value)) { case kJSTypeUndefined: return CFRetain([WebUndefined undefined]); - break; - case kJSTypeNull: return nil; - break; - case kJSTypeBoolean: - return CFRetain(JSValueToBoolean(ctx, value) ? kCFBooleanTrue : kCFBooleanFalse); - break; - - case kJSTypeNumber: { - JSValueRef exception(NULL); - double number(JSValueToNumber(ctx, value, &exception)); - CYThrow(context_, exception); - return CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &number); - } break; - + return CFRetain(JSValueToBoolean(context, value) ? kCFBooleanTrue : kCFBooleanFalse); + case kJSTypeNumber: + return CYCopyCFNumber(context, value); case kJSTypeString: - return CYCopyCFString(context_, value); - break; - + return CYCopyCFString(context, value); case kJSTypeObject: - return CFRetain((CFTypeRef) JSObjectToNSObject(ctx, (JSObjectRef) value)); - break; - + return CFRetain((CFTypeRef) CYCastNSObject(context, (JSObjectRef) value)); default: _assert(false); - break; } } @@ -290,26 +377,58 @@ NSArray *CYCastNSArray(JSPropertyNameArrayRef names) { return array; } -id CYCastNSObject(JSContextRef ctx, JSValueRef value) { - const NSObject *object(reinterpret_cast(CYCopyCFType(ctx, value))); +id CYCastNSObject(JSContextRef context, JSValueRef value) { + const NSObject *object(reinterpret_cast(CYCopyCFType(context, value))); return object == nil ? nil : [object autorelease]; } -void CYThrow(JSContextRef ctx, JSValueRef value) { +void CYThrow(JSContextRef context, JSValueRef value) { if (value == NULL) return; - @throw CYCastNSObject(ctx, value); + @throw CYCastNSObject(context, value); } -JSValueRef CYCastJSValue(JSContextRef ctx, id value) { - return [value cy$JSValueInContext:ctx]; +JSValueRef CYCastJSValue(JSContextRef context, id value) { + return value == nil ? JSValueMakeNull(context) : [value cy$JSValueInContext:context]; } -JSStringRef CYCopyJSString(JSContextRef ctx, id value) { +JSStringRef CYCopyJSString(id value) { return JSStringCreateWithCFString(reinterpret_cast([value description])); } -@implementation CY$JSObject +JSStringRef CYCopyJSString(const char *value) { + return JSStringCreateWithUTF8CString(value); +} + +JSStringRef CYCopyJSString(JSStringRef value) { + return JSStringRetain(value); +} + +// XXX: this is not a safe handle +class CYString { + private: + JSStringRef string_; + + public: + template + CYString(Type_ value) { + string_ = CYCopyJSString(value); + } + + ~CYString() { + JSStringRelease(string_); + } + + operator JSStringRef() const { + return string_; + } +}; + +void CYThrow(JSContextRef context, id error, JSValueRef *exception) { + *exception = CYCastJSValue(context, error); +} + +@implementation CYJSObject - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { if ((self = [super init]) != nil) { @@ -327,9 +446,7 @@ JSStringRef CYCopyJSString(JSContextRef ctx, id value) { - (id) objectForKey:(id)key { JSValueRef exception(NULL); - JSStringRef string(CYCopyJSString(context_, key)); - JSValueRef value(JSObjectGetProperty(context_, object_, string, &exception)); - JSStringRelease(string); + JSValueRef value(JSObjectGetProperty(context_, object_, CYString(key), &exception)); CYThrow(context_, exception); return CYCastNSObject(context_, value); } @@ -343,24 +460,20 @@ JSStringRef CYCopyJSString(JSContextRef ctx, id value) { - (void) setObject:(id)object forKey:(id)key { JSValueRef exception(NULL); - JSStringRef string(CYCopyJSString(context_, key)); - JSObjectSetProperty(context_, object_, string, CYCastJSValue(context_, object), kJSPropertyAttributeNone, &exception); - JSStringRelease(string); + JSObjectSetProperty(context_, object_, CYString(key), CYCastJSValue(context_, object), kJSPropertyAttributeNone, &exception); CYThrow(context_, exception); } - (void) removeObjectForKey:(id)key { JSValueRef exception(NULL); - JSStringRef string(CYCopyJSString(context_, key)); // XXX: this returns a bool - JSObjectDeleteProperty(context_, object_, string, &exception); - JSStringRelease(string); + JSObjectDeleteProperty(context_, object_, CYString(key), &exception); CYThrow(context_, exception); } @end -@implementation CY$JSArray +@implementation CYJSArray - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { if ((self = [super init]) != nil) { @@ -388,8 +501,8 @@ JSStringRef CYCopyJSString(JSContextRef ctx, id value) { @end -CFStringRef JSValueToJSONCopy(JSContextRef ctx, JSValueRef value) { - id object(CYCastNSObject(ctx, value)); +CFStringRef JSValueToJSONCopy(JSContextRef context, JSValueRef value) { + id object(CYCastNSObject(context, value)); return reinterpret_cast([(object == nil ? @"null" : [object cy$toJSON]) retain]); } @@ -466,19 +579,359 @@ static void OnAccept(CFSocketRef socket, CFSocketCallBackType type, CFDataRef ad } } -static JSValueRef joc_getProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef *exception) { +static JSValueRef joc_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef *exception) { return NULL; } -static JSValueRef obc_getProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef *exception) { +typedef id jocData; + +static JSObjectRef joc_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { _pooled + @try { + id data(reinterpret_cast(JSObjectGetPrivate(object))); + return CYMakeObject(context, [[data alloc] autorelease]); + } CYCatch +} + +struct ptrData { + apr_pool_t *pool_; + void *value_; + sig::Type type_; +}; + +static void ptr_finalize(JSObjectRef object) { + ptrData *data(reinterpret_cast(JSObjectGetPrivate(object))); + apr_pool_destroy(data->pool_); +} + +static void joc_finalize(JSObjectRef object) { + id data(reinterpret_cast(JSObjectGetPrivate(object))); + [data release]; +} + +static JSValueRef obc_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef *exception) { _pooled NSString *name([(NSString *) JSStringCopyCFString(kCFAllocatorDefault, propertyName) autorelease]); if (Class _class = NSClassFromString(name)) - return JSObjectMake(ctx, joc_, _class); + return CYMakeObject(context, _class); return NULL; } -MSInitialize { - NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); +void CYSetProperty(JSContextRef context, JSObjectRef object, const char *name, JSValueRef value) { + JSValueRef exception(NULL); + JSObjectSetProperty(context, object, CYString(name), value, kJSPropertyAttributeNone, &exception); + CYThrow(context, exception); +} + +struct ffiData { + apr_pool_t *pool_; + void (*function_)(); + const char *type_; + sig::Signature signature_; + ffi_cif cif_; +}; + +char *CYPoolCString(apr_pool_t *pool, JSStringRef value) { + size_t size(JSStringGetMaximumUTF8CStringSize(value)); + char *string(new(pool) char[size]); + JSStringGetUTF8CString(value, string, size); + JSStringRelease(value); + return string; +} + +// XXX: this macro is dangerous +#define CYCastCString(context, value) ({ \ + JSValueRef exception(NULL); \ + JSStringRef string(JSValueToStringCopy(context, value, &exception)); \ + CYThrow(context, exception); \ + size_t size(JSStringGetMaximumUTF8CStringSize(string)); \ + char *utf8(reinterpret_cast(alloca(size))); \ + JSStringGetUTF8CString(string, utf8, size); \ + JSStringRelease(string); \ + utf8; \ +}) + +SEL CYCastSEL(JSContextRef context, JSValueRef value) { + if (JSValueIsNull(context, value)) + return NULL; + else if (JSValueIsObjectOfClass(context, value, sel_)) + return reinterpret_cast(JSObjectGetPrivate((JSObjectRef) value)); + else + return sel_registerName(CYCastCString(context, value)); +} + +void *CYCastPointer(JSContextRef context, JSValueRef value) { + switch (JSValueGetType(context, value)) { + case kJSTypeNull: + return NULL; + case kJSTypeString: + return dlsym(RTLD_DEFAULT, CYCastCString(context, value)); + case kJSTypeObject: + if (JSValueIsObjectOfClass(context, value, ptr_)) { + ptrData *data(reinterpret_cast(JSObjectGetPrivate((JSObjectRef) value))); + return data->value_; + } + default: + JSValueRef exception(NULL); + double number(JSValueToNumber(context, value, &exception)); + CYThrow(context, exception); + return reinterpret_cast(static_cast(number)); + } +} + +void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, void *data, JSValueRef value) { + switch (type->primitive) { + case sig::boolean_P: + *reinterpret_cast(data) = JSValueToBoolean(context, value); + break; + +#define CYPoolFFI_(primitive, native) \ + case sig::primitive ## _P: { \ + JSValueRef exception(NULL); \ + double number(JSValueToNumber(context, value, &exception)); \ + CYThrow(context, exception); \ + *reinterpret_cast(data) = number; \ + } break; + + CYPoolFFI_(uchar, unsigned char) + CYPoolFFI_(char, char) + CYPoolFFI_(ushort, unsigned short) + CYPoolFFI_(short, short) + CYPoolFFI_(ulong, unsigned long) + CYPoolFFI_(long, long) + CYPoolFFI_(uint, unsigned int) + CYPoolFFI_(int, int) + CYPoolFFI_(ulonglong, unsigned long long) + CYPoolFFI_(longlong, long long) + CYPoolFFI_(float, float) + CYPoolFFI_(double, double) + + case sig::object_P: + case sig::typename_P: + *reinterpret_cast(data) = CYCastNSObject(context, value); + break; + + case sig::selector_P: + *reinterpret_cast(data) = CYCastSEL(context, value); + break; + + case sig::pointer_P: + *reinterpret_cast(data) = CYCastPointer(context, value); + break; + + case sig::string_P: { + JSValueRef exception(NULL); + JSStringRef string(JSValueToStringCopy(context, value, &exception)); + CYThrow(context, exception); + size_t size(JSStringGetMaximumUTF8CStringSize(string)); + char *utf8(new(pool) char[size]); + JSStringGetUTF8CString(string, utf8, size); + JSStringRelease(string); + *reinterpret_cast(data) = utf8; + } break; + + case sig::struct_P: + goto fail; + + case sig::void_P: + break; + + default: fail: + NSLog(@"CYPoolFFI(%c)\n", type->primitive); + _assert(false); + } +} + +JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, void *data) { + JSValueRef value; + + switch (type->primitive) { + case sig::boolean_P: + value = JSValueMakeBoolean(context, *reinterpret_cast(data)); + break; + +#define CYFromFFI_(primitive, native) \ + case sig::primitive ## _P: \ + value = JSValueMakeNumber(context, *reinterpret_cast(data)); \ + break; + + CYFromFFI_(uchar, unsigned char) + CYFromFFI_(char, char) + CYFromFFI_(ushort, unsigned short) + CYFromFFI_(short, short) + CYFromFFI_(ulong, unsigned long) + CYFromFFI_(long, long) + CYFromFFI_(uint, unsigned int) + CYFromFFI_(int, int) + CYFromFFI_(ulonglong, unsigned long long) + CYFromFFI_(longlong, long long) + CYFromFFI_(float, float) + CYFromFFI_(double, double) + + case sig::object_P: + case sig::typename_P: { + value = CYCastJSValue(context, *reinterpret_cast(data)); + } break; + + case sig::selector_P: { + SEL sel(*reinterpret_cast(data)); + value = sel == NULL ? JSValueMakeNull(context) : JSObjectMake(context, sel_, sel); + } break; + + case sig::pointer_P: { + if (void *pointer = *reinterpret_cast(data)) { + apr_pool_t *pool; + apr_pool_create(&pool, NULL); + ptrData *data(new(pool) ptrData()); + data->pool_ = pool; + data->value_ = pointer; + value = JSObjectMake(context, ptr_, data); + } else value = JSValueMakeNull(context); + } break; + + case sig::string_P: { + char *utf8(*reinterpret_cast(data)); + value = utf8 == NULL ? JSValueMakeNull(context) : JSValueMakeString(context, CYString(utf8)); + } break; + + case sig::struct_P: + goto fail; + + case sig::void_P: + value = NULL; + break; + + default: fail: + NSLog(@"CYFromFFI(%c)\n", type->primitive); + _assert(false); + } + + return value; +} + +class CYPool { + private: + apr_pool_t *pool_; + + public: + CYPool() { + apr_pool_create(&pool_, NULL); + } + + ~CYPool() { + apr_pool_destroy(pool_); + } + + operator apr_pool_t *() const { + return pool_; + } +}; + +static JSValueRef CYCallFunction(JSContextRef context, size_t count, const JSValueRef *arguments, JSValueRef *exception, sig::Signature *signature, ffi_cif *cif, void (*function)()) { _pooled + @try { + if (count != signature->count - 1) + [NSException raise:NSInvalidArgumentException format:@"incorrect number of arguments to ffi function"]; + + CYPool pool; + void *values[count]; + + for (unsigned index(0); index != count; ++index) { + sig::Element *element(&signature->elements[index + 1]); + values[index] = new(pool) uint8_t[cif->arg_types[index]->size]; + CYPoolFFI(pool, context, element->type, values[index], arguments[index]); + } + + uint8_t value[cif->rtype->size]; + ffi_call(cif, function, value, values); + + return CYFromFFI(context, signature->elements[0].type, value); + } CYCatch +} + +bool stret(ffi_type *ffi_type) { + return ffi_type->type == FFI_TYPE_STRUCT && ( + ffi_type->size > OBJC_MAX_STRUCT_BY_VALUE || + struct_forward_array[ffi_type->size] != 0 + ); +} + +static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { _pooled + const char *type; + + @try { + if (count < 2) + [NSException raise:NSInvalidArgumentException format:@"too few arguments to objc_msgSend"]; + + id self(CYCastNSObject(context, arguments[0])); + if (self == nil) + return JSValueMakeNull(context); + + SEL _cmd(CYCastSEL(context, arguments[1])); + NSMethodSignature *method([self methodSignatureForSelector:_cmd]); + if (method == nil) + [NSException raise:NSInvalidArgumentException format:@"unrecognized selector %s sent to object %p", sel_getName(_cmd), self]; + + type = [[method _typeString] UTF8String]; + } CYCatch + + CYPool pool; + + sig::Signature signature; + sig::Parse(pool, &signature, type); + + ffi_cif cif; + sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif); + + void (*function)() = stret(cif.rtype) ? reinterpret_cast(&objc_msgSend_stret) : reinterpret_cast(&objc_msgSend); + return CYCallFunction(context, count, arguments, exception, &signature, &cif, function); +} + +static JSValueRef ffi_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + ffiData *data(reinterpret_cast(JSObjectGetPrivate(object))); + return CYCallFunction(context, count, arguments, exception, &data->signature_, &data->cif_, data->function_); +} + +static void ffi_finalize(JSObjectRef object) { + ffiData *data(reinterpret_cast(JSObjectGetPrivate(object))); + apr_pool_destroy(data->pool_); +} + +JSObjectRef CYMakeFunction(JSContextRef context, void (*function)(), const char *type) { + apr_pool_t *pool; + apr_pool_create(&pool, NULL); + + ffiData *data(new(pool) ffiData()); + + data->pool_ = pool; + data->function_ = function; + data->type_ = apr_pstrdup(pool, type); + + sig::Parse(pool, &data->signature_, type); + sig::sig_ffi_cif(pool, &sig::ObjectiveC, &data->signature_, &data->cif_); + + return JSObjectMake(context, ffi_, data); +} + +JSObjectRef ffi(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + @try { + if (count != 2) + [NSException raise:NSInvalidArgumentException format:@"incorrect number of arguments to ffi constructor"]; + void (*function)() = reinterpret_cast(CYCastPointer(context, arguments[0])); + const char *type(CYCastCString(context, arguments[1])); + return CYMakeFunction(context, function, type); + } CYCatch +} + +JSValueRef ptr_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef *exception) { + ptrData *data(reinterpret_cast(JSObjectGetPrivate(object))); + return JSValueMakeNumber(context, reinterpret_cast(data->value_)); +} + +static JSStaticValue ptr_staticValues[2] = { + {"value", &ptr_getProperty_value, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete}, + {NULL, NULL, NULL, 0} +}; + +MSInitialize { _pooled + apr_initialize(); NSCFBoolean_ = objc_getClass("NSCFBoolean"); @@ -508,24 +961,131 @@ MSInitialize { JSClassRef obc(JSClassCreate(&definition)); definition = kJSClassDefinitionEmpty; + definition.className = "ffi"; + definition.callAsFunction = &ffi_callAsFunction; + definition.finalize = &ffi_finalize; + ffi_ = JSClassCreate(&definition); + + definition = kJSClassDefinitionEmpty; + definition.className = "ptr"; + definition.staticValues = ptr_staticValues; + definition.finalize = &ptr_finalize; + ptr_ = JSClassCreate(&definition); + + definition = kJSClassDefinitionEmpty; + definition.className = "sel"; + sel_ = JSClassCreate(&definition); + + definition = kJSClassDefinitionEmpty; + definition.className = "joc"; definition.getProperty = &joc_getProperty; + definition.callAsConstructor = &joc_callAsConstructor; + definition.finalize = &joc_finalize; joc_ = JSClassCreate(&definition); - context_ = JSGlobalContextCreate(obc); - - JSObjectRef global(JSContextGetGlobalObject(JSGetContext())); + JSContextRef context(JSGlobalContextCreate(obc)); + Context_ = context; + + JSObjectRef global(JSContextGetGlobalObject(context)); + + CYSetProperty(context, global, "ffi", JSObjectMakeConstructor(context, ffi_, &ffi)); + CYSetProperty(context, global, "obc", JSObjectMake(context, obc, NULL)); + +#define CYSetFunction_(name, type) \ + CYSetProperty(context, global, #name, CYMakeFunction(context, reinterpret_cast(&name), type)) + + CYSetFunction_(class_addIvar, "B#*LC*"); + CYSetFunction_(class_addMethod, "B#:^?*"); + CYSetFunction_(class_addProtocol, "B#@"); + CYSetFunction_(class_conformsToProtocol, "B#@"); + CYSetFunction_(class_copyIvarList, "^^{objc_ivar=}#^I"); + CYSetFunction_(class_copyMethodList, "^^{objc_method=}#^I"); + CYSetFunction_(class_copyPropertyList, "^^{objc_property=}#^I"); + CYSetFunction_(class_copyProtocolList, "^@#^I"); + CYSetFunction_(class_createInstance, "@#L"); + CYSetFunction_(class_getClassMethod, "^{objc_method=}#:"); + CYSetFunction_(class_getClassVariable, "^{objc_ivar=}#*"); + CYSetFunction_(class_getInstanceMethod, "^{objc_method=}#:"); + CYSetFunction_(class_getInstanceSize, "L#"); + CYSetFunction_(class_getInstanceVariable, "^{objc_ivar=}#*"); + CYSetFunction_(class_getIvarLayout, "*#"); + CYSetFunction_(class_getMethodImplementation, "^?#:"); + CYSetFunction_(class_getMethodImplementation_stret, "^?#:"); + CYSetFunction_(class_getName, "*#"); + CYSetFunction_(class_getProperty, "^{objc_property=}#*"); + CYSetFunction_(class_getSuperclass, "##"); + CYSetFunction_(class_getVersion, "i#"); + CYSetFunction_(class_getWeakIvarLayout, "*#"); + CYSetFunction_(class_isMetaClass, "B#"); + CYSetFunction_(class_replaceMethod, "^?#:^?*"); + CYSetFunction_(class_respondsToSelector, "B#:"); + CYSetFunction_(class_setIvarLayout, "v#*"); + CYSetFunction_(class_setSuperclass, "###"); + CYSetFunction_(class_setVersion, "v#i"); + CYSetFunction_(class_setWeakIvarLayout, "v#*"); + CYSetFunction_(ivar_getName, "*^{objc_ivar=}"); + CYSetFunction_(ivar_getOffset, "i^{objc_ivar=}"); + CYSetFunction_(ivar_getTypeEncoding, "*^{objc_ivar=}"); + CYSetFunction_(method_copyArgumentType, "^c^{objc_method=}I"); + CYSetFunction_(method_copyReturnType, "^c^{objc_method=}"); + CYSetFunction_(method_exchangeImplementations, "v^{objc_method=}^{objc_method=}"); + CYSetFunction_(method_getArgumentType, "v^{objc_method=}I^cL"); + CYSetFunction_(method_getImplementation, "^?^{objc_method=}"); + CYSetFunction_(method_getName, ":^{objc_method=}"); + CYSetFunction_(method_getNumberOfArguments, "I^{objc_method=}"); + CYSetFunction_(method_getReturnType, "v^{objc_method=}^cL"); + CYSetFunction_(method_getTypeEncoding, "*^{objc_method=}"); + CYSetFunction_(method_setImplementation, "^?^{objc_method=}^?"); + CYSetFunction_(objc_allocateClassPair, "##*L"); + CYSetFunction_(objc_copyProtocolList, "^@^I"); + CYSetFunction_(objc_duplicateClass, "##*L"); + CYSetFunction_(objc_getClass, "#*"); + CYSetFunction_(objc_getClassList, "i^#i"); + CYSetFunction_(objc_getFutureClass, "#*"); + CYSetFunction_(objc_getMetaClass, "@*"); + CYSetFunction_(objc_getProtocol, "@*"); + CYSetFunction_(objc_getRequiredClass, "@*"); + CYSetFunction_(objc_lookUpClass, "@*"); + CYSetFunction_(objc_registerClassPair, "v#"); + CYSetFunction_(objc_setFutureClass, "v#*"); + CYSetFunction_(object_copy, "@@L"); + CYSetFunction_(object_dispose, "@@"); + CYSetFunction_(object_getClass, "#@"); + CYSetFunction_(object_getClassName, "*@"); + CYSetFunction_(object_getIndexedIvars, "^v@"); + CYSetFunction_(object_getInstanceVariable, "^{objc_ivar=}@*^^v"); + CYSetFunction_(object_getIvar, "@@^{objc_ivar=}"); + CYSetFunction_(object_setClass, "#@#"); + CYSetFunction_(object_setInstanceVariable, "^{objc_ivar=}@*^v"); + CYSetFunction_(object_setIvar, "v@^{objc_ivar=}@"); + CYSetFunction_(property_getAttributes, "*^{objc_property=}"); + CYSetFunction_(property_getName, "*^{objc_property=}"); + CYSetFunction_(protocol_conformsToProtocol, "B@@"); + CYSetFunction_(protocol_copyMethodDescriptionList, "^{objc_method_description=:*}@BB^I"); + CYSetFunction_(protocol_copyPropertyList, "^{objc_property=}@^I"); + CYSetFunction_(protocol_copyProtocolList, "^@@^I"); + CYSetFunction_(protocol_getMethodDescription, "{objc_method_description=:*}@:BB"); + CYSetFunction_(protocol_getName, "*@"); + CYSetFunction_(protocol_getProperty, "^{objc_property=}@*BB"); + CYSetFunction_(protocol_isEqual, "B@@"); + CYSetFunction_(sel_getName, "*:"); + CYSetFunction_(sel_getUid, ":*"); + CYSetFunction_(sel_isEqual, "B::"); + CYSetFunction_(sel_registerName, ":*"); + + CYSetProperty(context, global, "objc_msgSend", JSObjectMakeFunctionWithCallback(context, CYString("objc_msgSend"), &$objc_msgSend)); + + CYSetProperty(context, global, "YES", JSValueMakeBoolean(context, true)); + CYSetProperty(context, global, "NO", JSValueMakeBoolean(context, false)); + CYSetProperty(context, global, "nil", JSValueMakeNull(context)); name_ = JSStringCreateWithUTF8CString("name"); message_ = JSStringCreateWithUTF8CString("message"); length_ = JSStringCreateWithUTF8CString("length"); - JSStringRef name(JSStringCreateWithUTF8CString("Array")); JSValueRef exception(NULL); - JSValueRef value(JSObjectGetProperty(JSGetContext(), global, name, &exception)); - CYThrow(context_, exception); - JSStringRelease(name); + JSValueRef value(JSObjectGetProperty(JSGetContext(), global, CYString("Array"), &exception)); + CYThrow(context, exception); Array_ = JSValueToObject(JSGetContext(), value, &exception); - CYThrow(context_, exception); - - [pool release]; + CYThrow(context, exception); }