1 /* Cycript - Optimizing JavaScript Compiler/Runtime
 
   2  * Copyright (C) 2009-2012  Jay Freeman (saurik)
 
   5 /* GNU Lesser General Public License, Version 3 {{{ */
 
   7  * Cycript is free software: you can redistribute it and/or modify it under
 
   8  * the terms of the GNU Lesser General Public License as published by the
 
   9  * Free Software Foundation, either version 3 of the License, or (at your
 
  10  * option) any later version.
 
  12  * Cycript is distributed in the hope that it will be useful, but WITHOUT
 
  13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
  14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 
  15  * License for more details.
 
  17  * You should have received a copy of the GNU Lesser General Public License
 
  18  * along with Cycript.  If not, see <http://www.gnu.org/licenses/>.
 
  26 #include <Foundation/Foundation.h>
 
  28 #include "ObjectiveC/Internal.hpp"
 
  30 #include <objc/objc-api.h>
 
  32 #include "cycript.hpp"
 
  34 #include "ObjectiveC/Internal.hpp"
 
  37 #include <CoreFoundation/CoreFoundation.h>
 
  38 #include <JavaScriptCore/JSStringRefCF.h>
 
  39 #include <WebKit/WebScriptObject.h>
 
  40 #include <objc/runtime.h>
 
  44 #include "JavaScript.hpp"
 
  46 #include "Execute.hpp"
 
  53 #define CYObjectiveTry_(context) { \
 
  54     JSContextRef context_(context); \
 
  56 #define CYObjectiveTry { \
 
  58 #define CYObjectiveCatch \
 
  59     catch (const CYException &error) { \
 
  60         @throw CYCastNSObject(NULL, context_, error.CastJSValue(context_)); \
 
  66     NSAutoreleasePool *_pool([[NSAutoreleasePool alloc] init]); \
 
  68 #define CYPoolCatch(value) \
 
  69     @catch (NSException *error) { \
 
  70         _saved = [error retain]; \
 
  71         throw CYJSError(context, CYCastJSValue(context, error)); \
 
  76             [_saved autorelease]; \
 
  82 #define CYSadCatch(value) \
 
  83     @catch (NSException *error ) { \
 
  84         throw CYJSError(context, CYCastJSValue(context, error)); \
 
  89 #define class_getSuperclass GSObjCSuper
 
  90 #define class_getInstanceVariable GSCGetInstanceVariableDefinition
 
  91 #define class_getName GSNameFromClass
 
  93 #define class_removeMethods(cls, list) GSRemoveMethodList(cls, list, YES)
 
  95 #define ivar_getName(ivar) ((ivar)->ivar_name)
 
  96 #define ivar_getOffset(ivar) ((ivar)->ivar_offset)
 
  97 #define ivar_getTypeEncoding(ivar) ((ivar)->ivar_type)
 
  99 #define method_getName(method) ((method)->method_name)
 
 100 #define method_getImplementation(method) ((method)->method_imp)
 
 101 #define method_getTypeEncoding(method) ((method)->method_types)
 
 102 #define method_setImplementation(method, imp) ((void) ((method)->method_imp = (imp)))
 
 105 #define objc_getClass GSClassFromName
 
 107 #define objc_getProtocol GSProtocolFromName
 
 109 #define object_getClass GSObjCClass
 
 111 #define object_getInstanceVariable(object, name, value) ({ \
 
 112     objc_ivar *ivar(class_getInstanceVariable(object_getClass(object), name)); \
 
 113     _assert(value != NULL); \
 
 115         GSObjCGetVariable(object, ivar_getOffset(ivar), sizeof(void *), value); \
 
 119 #define object_setIvar(object, ivar, value) ({ \
 
 120     void *data = (value); \
 
 121     GSObjCSetVariable(object, ivar_getOffset(ivar), sizeof(void *), &data); \
 
 124 #define protocol_getName(protocol) [(protocol) name]
 
 127 static void (*$objc_setAssociatedObject)(id object, void *key, id value, objc_AssociationPolicy policy);
 
 128 static id (*$objc_getAssociatedObject)(id object, void *key);
 
 129 static void (*$objc_removeAssociatedObjects)(id object);
 
 131 JSValueRef CYSendMessage(apr_pool_t *pool, JSContextRef context, id self, Class super, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize, JSValueRef *exception);
 
 133 /* Objective-C Pool Release {{{ */
 
 134 apr_status_t CYPoolRelease_(void *data) {
 
 135     id object(reinterpret_cast<id>(data));
 
 140 id CYPoolRelease_(apr_pool_t *pool, id object) {
 
 143     else if (pool == NULL)
 
 144         return [object autorelease];
 
 146         apr_pool_cleanup_register(pool, object, &CYPoolRelease_, &apr_pool_cleanup_null);
 
 151 template <typename Type_>
 
 152 Type_ CYPoolRelease(apr_pool_t *pool, Type_ object) {
 
 153     return (Type_) CYPoolRelease_(pool, (id) object);
 
 156 /* Objective-C Strings {{{ */
 
 157 const char *CYPoolCString(apr_pool_t *pool, JSContextRef context, NSString *value) {
 
 159         return [value UTF8String];
 
 161         size_t size([value maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1);
 
 162         char *string(new(pool) char[size]);
 
 163         if (![value getCString:string maxLength:size encoding:NSUTF8StringEncoding])
 
 164             throw CYJSError(context, "[NSString getCString:maxLength:encoding:] == NO");
 
 169 JSStringRef CYCopyJSString(JSContextRef context, NSString *value) {
 
 171     return JSStringCreateWithCFString(reinterpret_cast<CFStringRef>(value));
 
 174     return CYCopyJSString(CYPoolCString(pool, context, value));
 
 178 JSStringRef CYCopyJSString(JSContextRef context, NSObject *value) {
 
 181     // XXX: this definition scares me; is anyone using this?!
 
 182     NSString *string([value description]);
 
 183     return CYCopyJSString(context, string);
 
 186 NSString *CYCopyNSString(const CYUTF8String &value) {
 
 188     return (NSString *) CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(value.data), value.size, kCFStringEncodingUTF8, true);
 
 190     return [[NSString alloc] initWithBytes:value.data length:value.size encoding:NSUTF8StringEncoding];
 
 194 NSString *CYCopyNSString(JSContextRef context, JSStringRef value) {
 
 196     return (NSString *) JSStringCopyCFString(kCFAllocatorDefault, value);
 
 199     return CYCopyNSString(CYPoolUTF8String(pool, context, value));
 
 203 NSString *CYCopyNSString(JSContextRef context, JSValueRef value) {
 
 204     return CYCopyNSString(context, CYJSString(context, value));
 
 207 NSString *CYCastNSString(apr_pool_t *pool, const CYUTF8String &value) {
 
 208     return CYPoolRelease(pool, CYCopyNSString(value));
 
 211 NSString *CYCastNSString(apr_pool_t *pool, SEL sel) {
 
 212     const char *name(sel_getName(sel));
 
 213     return CYPoolRelease(pool, CYCopyNSString(CYUTF8String(name, strlen(name))));
 
 216 NSString *CYCastNSString(apr_pool_t *pool, JSContextRef context, JSStringRef value) {
 
 217     return CYPoolRelease(pool, CYCopyNSString(context, value));
 
 220 CYUTF8String CYCastUTF8String(NSString *value) {
 
 221     NSData *data([value dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO]);
 
 222     return CYUTF8String(reinterpret_cast<const char *>([data bytes]), [data length]);
 
 226 JSValueRef CYCastJSValue(JSContextRef context, NSObject *value);
 
 228 void CYThrow(JSContextRef context, NSException *error, JSValueRef *exception) {
 
 229     if (exception == NULL)
 
 231     *exception = CYCastJSValue(context, error);
 
 234 size_t CYGetIndex(NSString *value) {
 
 235     return CYGetIndex(CYCastUTF8String(value));
 
 238 bool CYGetOffset(apr_pool_t *pool, JSContextRef context, NSString *value, ssize_t &index) {
 
 239     return CYGetOffset(CYPoolCString(pool, context, value), index);
 
 242 static JSClassRef Instance_;
 
 244 static JSClassRef ArrayInstance_;
 
 245 static JSClassRef FunctionInstance_;
 
 246 static JSClassRef ObjectInstance_;
 
 247 static JSClassRef StringInstance_;
 
 249 static JSClassRef Internal_;
 
 250 static JSClassRef Message_;
 
 251 static JSClassRef Messages_;
 
 252 static JSClassRef Selector_;
 
 253 static JSClassRef Super_;
 
 255 static JSClassRef ObjectiveC_Classes_;
 
 256 static JSClassRef ObjectiveC_Constants_;
 
 257 static JSClassRef ObjectiveC_Protocols_;
 
 260 static JSClassRef ObjectiveC_Image_Classes_;
 
 261 static JSClassRef ObjectiveC_Images_;
 
 265 static Class NSCFBoolean_;
 
 266 static Class NSCFType_;
 
 267 static Class NSGenericDeallocHandler_;
 
 268 static Class NSMessageBuilder_;
 
 269 static Class NSZombie_;
 
 271 static Class NSBoolNumber_;
 
 274 static Class NSArray_;
 
 275 static Class NSBlock_;
 
 276 static Class NSDictionary_;
 
 277 static Class NSString_;
 
 278 static Class Object_;
 
 280 static Type_privateData *Object_type;
 
 281 static Type_privateData *Selector_type;
 
 283 Type_privateData *Instance::GetType() const {
 
 287 Type_privateData *Selector_privateData::GetType() const {
 
 288     return Selector_type;
 
 291 static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception);
 
 293 JSValueRef CYGetClassPrototype(JSContextRef context, id self) {
 
 295         return CYGetCachedObject(context, CYJSString("Instance_prototype"));
 
 297     JSObjectRef global(CYGetGlobalObject(context));
 
 298     JSObjectRef cy(CYCastJSObject(context, CYGetProperty(context, global, cy_s)));
 
 301     sprintf(label, "i%p", self);
 
 302     CYJSString name(label);
 
 304     JSValueRef value(CYGetProperty(context, cy, name));
 
 305     if (!JSValueIsUndefined(context, value))
 
 308     JSClassRef _class(NULL);
 
 309     JSValueRef prototype;
 
 311     if (self == NSArray_)
 
 312         prototype = CYGetCachedObject(context, CYJSString("ArrayInstance_prototype"));
 
 313     else if (self == NSBlock_)
 
 314         prototype = CYGetCachedObject(context, CYJSString("FunctionInstance_prototype"));
 
 315     else if (self == NSDictionary_)
 
 316         prototype = CYGetCachedObject(context, CYJSString("ObjectInstance_prototype"));
 
 317     else if (self == NSString_)
 
 318         prototype = CYGetCachedObject(context, CYJSString("StringInstance_prototype"));
 
 320         prototype = CYGetClassPrototype(context, class_getSuperclass(self));
 
 322     JSObjectRef object(JSObjectMake(context, _class, NULL));
 
 323     JSObjectSetPrototype(context, object, prototype);
 
 324     CYSetProperty(context, cy, name, object);
 
 329 JSObjectRef Messages::Make(JSContextRef context, Class _class, bool array) {
 
 330     JSObjectRef value(JSObjectMake(context, Messages_, new Messages(_class)));
 
 331     if (_class == NSArray_)
 
 333     if (Class super = class_getSuperclass(_class))
 
 334         JSObjectSetPrototype(context, value, Messages::Make(context, super, array));
 
 336         JSObjectSetPrototype(context, value, Array_prototype_);*/
 
 340 JSObjectRef Internal::Make(JSContextRef context, id object, JSObjectRef owner) {
 
 341     return JSObjectMake(context, Internal_, new Internal(object, context, owner));
 
 345 JSObjectRef Super::Make(JSContextRef context, id object, Class _class) {
 
 346     JSObjectRef value(JSObjectMake(context, Super_, new Super(object, _class)));
 
 350 JSObjectRef Instance::Make(JSContextRef context, id object, Flags flags) {
 
 351     JSObjectRef value(JSObjectMake(context, Instance_, new Instance(object, flags)));
 
 352     JSObjectSetPrototype(context, value, CYGetClassPrototype(context, object_getClass(object)));
 
 356 Instance::~Instance() {
 
 357     if ((flags_ & Transient) == 0)
 
 358         // XXX: does this handle background threads correctly?
 
 359         // XXX: this simply does not work on the console because I'm stupid
 
 360         [GetValue() performSelector:@selector(release) withObject:nil afterDelay:0];
 
 363 struct Message_privateData :
 
 368     Message_privateData(SEL sel, const char *type, IMP value = NULL) :
 
 369         cy::Functor(type, reinterpret_cast<void (*)()>(value)),
 
 375 JSObjectRef CYMakeInstance(JSContextRef context, id object, bool transient) {
 
 376     Instance::Flags flags;
 
 379         flags = Instance::Transient;
 
 381         flags = Instance::None;
 
 382         object = [object retain];
 
 385     return Instance::Make(context, object, flags);
 
 388 @interface NSMethodSignature (Cycript)
 
 389 - (NSString *) _typeString;
 
 392 @interface NSObject (Cycript)
 
 394 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context;
 
 395 - (JSType) cy$JSType;
 
 397 - (NSObject *) cy$toJSON:(NSString *)key;
 
 398 - (NSString *) cy$toCYON;
 
 400 - (bool) cy$hasProperty:(NSString *)name;
 
 401 - (NSObject *) cy$getProperty:(NSString *)name;
 
 402 - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value;
 
 403 - (bool) cy$deleteProperty:(NSString *)name;
 
 404 - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context;
 
 406 + (bool) cy$hasImplicitProperties;
 
 412 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context;
 
 415 NSString *CYCastNSCYON(id value) {
 
 421         Class _class(object_getClass(value));
 
 422         SEL sel(@selector(cy$toCYON));
 
 424         if (objc_method *toCYON = class_getInstanceMethod(_class, sel))
 
 425             string = reinterpret_cast<NSString *(*)(id, SEL)>(method_getImplementation(toCYON))(value, sel);
 
 426         else if (objc_method *methodSignatureForSelector = class_getInstanceMethod(_class, @selector(methodSignatureForSelector:))) {
 
 427             if (reinterpret_cast<NSMethodSignature *(*)(id, SEL, SEL)>(method_getImplementation(methodSignatureForSelector))(value, @selector(methodSignatureForSelector:), sel) != nil)
 
 428                 string = [value cy$toCYON];
 
 433             else if (value == NSZombie_)
 
 434                 string = @"_NSZombie_";
 
 435             else if (_class == NSZombie_)
 
 436                 string = [NSString stringWithFormat:@"<_NSZombie_: %p>", value];
 
 437             // XXX: frowny /in/ the pants
 
 438             else if (value == NSGenericDeallocHandler_ || value == NSMessageBuilder_ || value == Object_)
 
 442                 string = [NSString stringWithFormat:@"%@", value];
 
 447             string = @"undefined";
 
 454 struct PropertyAttributes {
 
 459     const char *variable;
 
 472     PropertyAttributes(objc_property_t property) :
 
 484         name = property_getName(property);
 
 485         const char *attributes(property_getAttributes(property));
 
 487         for (char *state, *token(apr_strtok(apr_pstrdup(pool_, attributes), ",", &state)); token != NULL; token = apr_strtok(NULL, ",", &state)) {
 
 489                 case 'R': readonly = true; break;
 
 490                 case 'C': copy = true; break;
 
 491                 case '&': retain = true; break;
 
 492                 case 'N': nonatomic = true; break;
 
 493                 case 'G': getter_ = token + 1; break;
 
 494                 case 'S': setter_ = token + 1; break;
 
 495                 case 'V': variable = token + 1; break;
 
 499         /*if (variable == NULL) {
 
 500             variable = property_getName(property);
 
 501             size_t size(strlen(variable));
 
 502             char *name(new(pool_) char[size + 2]);
 
 504             memcpy(name + 1, variable, size);
 
 505             name[size + 1] = '\0';
 
 510     const char *Getter() {
 
 512             getter_ = apr_pstrdup(pool_, name);
 
 516     const char *Setter() {
 
 517         if (setter_ == NULL && !readonly) {
 
 518             size_t length(strlen(name));
 
 520             char *temp(new(pool_) char[length + 5]);
 
 526                 temp[3] = toupper(name[0]);
 
 527                 memcpy(temp + 4, name + 1, length - 1);
 
 530             temp[length + 3] = ':';
 
 531             temp[length + 4] = '\0';
 
 542 NSObject *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) {
 
 543     return [(NSString *) CFCopyDescription((CFTypeRef) self) autorelease];
 
 548 @interface CYWebUndefined : NSObject {
 
 551 + (CYWebUndefined *) undefined;
 
 555 @implementation CYWebUndefined
 
 557 + (CYWebUndefined *) undefined {
 
 558     static CYWebUndefined *instance_([[CYWebUndefined alloc] init]);
 
 564 #define WebUndefined CYWebUndefined
 
 567 /* Bridge: CYJSObject {{{ */
 
 568 @interface CYJSObject : NSMutableDictionary {
 
 570     JSGlobalContextRef context_;
 
 573 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context;
 
 575 - (NSObject *) cy$toJSON:(NSString *)key;
 
 577 - (NSUInteger) count;
 
 578 - (id) objectForKey:(id)key;
 
 579 - (NSEnumerator *) keyEnumerator;
 
 580 - (void) setObject:(id)object forKey:(id)key;
 
 581 - (void) removeObjectForKey:(id)key;
 
 585 /* Bridge: CYJSArray {{{ */
 
 586 @interface CYJSArray : NSMutableArray {
 
 588     JSGlobalContextRef context_;
 
 591 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context;
 
 593 - (NSUInteger) count;
 
 594 - (id) objectAtIndex:(NSUInteger)index;
 
 596 - (void) addObject:(id)anObject;
 
 597 - (void) insertObject:(id)anObject atIndex:(NSUInteger)index;
 
 598 - (void) removeLastObject;
 
 599 - (void) removeObjectAtIndex:(NSUInteger)index;
 
 600 - (void) replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
 
 605 NSObject *CYCastNSObject_(apr_pool_t *pool, JSContextRef context, JSObjectRef object) {
 
 606     JSObjectRef Array(CYGetCachedObject(context, Array_s));
 
 607     JSValueRef exception(NULL);
 
 608     bool array(JSValueIsInstanceOfConstructor(context, object, Array, &exception));
 
 609     CYThrow(context, exception);
 
 610     id value(array ? [CYJSArray alloc] : [CYJSObject alloc]);
 
 611     return CYPoolRelease(pool, [value initWithJSObject:object inContext:context]);
 
 614 NSObject *CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSObjectRef object) {
 
 615     if (!JSValueIsObjectOfClass(context, object, Instance_))
 
 616         return CYCastNSObject_(pool, context, object);
 
 618         Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
 
 619         return internal->GetValue();
 
 623 NSNumber *CYCopyNSNumber(JSContextRef context, JSValueRef value) {
 
 624     return [[NSNumber alloc] initWithDouble:CYCastDouble(context, value)];
 
 628 @interface NSBoolNumber : NSNumber {
 
 633 id CYNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef value, bool cast) {
 
 637     switch (JSType type = JSValueGetType(context, value)) {
 
 638         case kJSTypeUndefined:
 
 639             object = [WebUndefined undefined];
 
 649             object = (id) (CYCastBool(context, value) ? kCFBooleanTrue : kCFBooleanFalse);
 
 652             object = [[NSBoolNumber alloc] initWithBool:CYCastBool(context, value)];
 
 658             object = CYCopyNSNumber(context, value);
 
 663             object = CYCopyNSString(context, value);
 
 668             // XXX: this might could be more efficient
 
 669             object = CYCastNSObject(pool, context, (JSObjectRef) value);
 
 674             throw CYJSError(context, "JSValueGetType() == 0x%x", type);
 
 681         return CYPoolRelease(pool, object);
 
 683         return [object retain];
 
 686 NSObject *CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
 
 687     return CYNSObject(pool, context, value, true);
 
 690 NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
 
 691     return CYNSObject(pool, context, value, false);
 
 694 /* Bridge: NSArray {{{ */
 
 695 @implementation NSArray (Cycript)
 
 698     return [[self mutableCopy] autorelease];
 
 701 - (NSString *) cy$toCYON {
 
 702     NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
 
 703     [json appendString:@"@["];
 
 707     for (id object in self) {
 
 709     for (size_t index(0), count([self count]); index != count; ++index) {
 
 710         id object([self objectAtIndex:index]);
 
 713             [json appendString:@","];
 
 716         if (object == nil || [object cy$JSType] != kJSTypeUndefined)
 
 717             [json appendString:CYCastNSCYON(object)];
 
 719             [json appendString:@","];
 
 724     [json appendString:@"]"];
 
 728 - (bool) cy$hasProperty:(NSString *)name {
 
 729     if ([name isEqualToString:@"length"])
 
 732     size_t index(CYGetIndex(name));
 
 733     if (index == _not(size_t) || index >= [self count])
 
 734         return [super cy$hasProperty:name];
 
 739 - (NSObject *) cy$getProperty:(NSString *)name {
 
 740     if ([name isEqualToString:@"length"]) {
 
 741         NSUInteger count([self count]);
 
 743         return [NSNumber numberWithUnsignedInteger:count];
 
 745         return [NSNumber numberWithUnsignedInt:count];
 
 749     size_t index(CYGetIndex(name));
 
 750     if (index == _not(size_t) || index >= [self count])
 
 751         return [super cy$getProperty:name];
 
 753         return [self objectAtIndex:index];
 
 756 - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
 
 757     [super cy$getPropertyNames:names inContext:context];
 
 759     for (size_t index(0), count([self count]); index != count; ++index) {
 
 760         id object([self objectAtIndex:index]);
 
 761         if (object == nil || [object cy$JSType] != kJSTypeUndefined) {
 
 763             sprintf(name, "%zu", index);
 
 764             JSPropertyNameAccumulatorAddName(names, CYJSString(name));
 
 769 + (bool) cy$hasImplicitProperties {
 
 775 /* Bridge: NSBlock {{{ */
 
 782 /* Bridge: NSBoolNumber {{{ */
 
 784 @implementation NSBoolNumber (Cycript)
 
 786 - (JSType) cy$JSType {
 
 787     return kJSTypeBoolean;
 
 790 - (NSObject *) cy$toJSON:(NSString *)key {
 
 794 - (NSString *) cy$toCYON {
 
 795     return [self boolValue] ? @"@true" : @"@false";
 
 798 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
 
 799     return CYCastJSValue(context, (bool) [self boolValue]);
 
 805 /* Bridge: NSDictionary {{{ */
 
 806 @implementation NSDictionary (Cycript)
 
 809     return [[self mutableCopy] autorelease];
 
 812 - (NSString *) cy$toCYON {
 
 813     NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
 
 814     [json appendString:@"@{"];
 
 818     for (NSObject *key in self) {
 
 820     NSEnumerator *keys([self keyEnumerator]);
 
 821     while (NSObject *key = [keys nextObject]) {
 
 824             [json appendString:@","];
 
 827         [json appendString:CYCastNSCYON(key)];
 
 828         [json appendString:@":"];
 
 829         NSObject *object([self objectForKey:key]);
 
 830         [json appendString:CYCastNSCYON(object)];
 
 833     [json appendString:@"}"];
 
 837 - (bool) cy$hasProperty:(NSString *)name {
 
 838     return [self objectForKey:name] != nil;
 
 841 - (NSObject *) cy$getProperty:(NSString *)name {
 
 842     return [self objectForKey:name];
 
 845 - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
 
 846     [super cy$getPropertyNames:names inContext:context];
 
 849     for (NSObject *key in self) {
 
 851     NSEnumerator *keys([self keyEnumerator]);
 
 852     while (NSObject *key = [keys nextObject]) {
 
 854         JSPropertyNameAccumulatorAddName(names, CYJSString(context, key));
 
 858 + (bool) cy$hasImplicitProperties {
 
 864 /* Bridge: NSMutableArray {{{ */
 
 865 @implementation NSMutableArray (Cycript)
 
 867 - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value {
 
 868     if ([name isEqualToString:@"length"]) {
 
 869         // XXX: is this not intelligent?
 
 870         NSNumber *number(reinterpret_cast<NSNumber *>(value));
 
 872         NSUInteger size([number unsignedIntegerValue]);
 
 874         NSUInteger size([number unsignedIntValue]);
 
 876         NSUInteger count([self count]);
 
 878             [self removeObjectsInRange:NSMakeRange(size, count - size)];
 
 879         else if (size != count) {
 
 880             WebUndefined *undefined([WebUndefined undefined]);
 
 881             for (size_t i(count); i != size; ++i)
 
 882                 [self addObject:undefined];
 
 887     size_t index(CYGetIndex(name));
 
 888     if (index == _not(size_t))
 
 889         return [super cy$setProperty:name to:value];
 
 891     id object(value ?: [NSNull null]);
 
 893     size_t count([self count]);
 
 895         [self replaceObjectAtIndex:index withObject:object];
 
 897         if (index != count) {
 
 898             WebUndefined *undefined([WebUndefined undefined]);
 
 899             for (size_t i(count); i != index; ++i)
 
 900                 [self addObject:undefined];
 
 903         [self addObject:object];
 
 909 - (bool) cy$deleteProperty:(NSString *)name {
 
 910     size_t index(CYGetIndex(name));
 
 911     if (index == _not(size_t) || index >= [self count])
 
 912         return [super cy$deleteProperty:name];
 
 913     [self replaceObjectAtIndex:index withObject:[WebUndefined undefined]];
 
 919 /* Bridge: NSMutableDictionary {{{ */
 
 920 @implementation NSMutableDictionary (Cycript)
 
 922 - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value {
 
 923     [self setObject:(value ?: [NSNull null]) forKey:name];
 
 927 - (bool) cy$deleteProperty:(NSString *)name {
 
 928     if ([self objectForKey:name] == nil)
 
 931         [self removeObjectForKey:name];
 
 938 /* Bridge: NSNumber {{{ */
 
 939 @implementation NSNumber (Cycript)
 
 941 - (JSType) cy$JSType {
 
 943     // XXX: this just seems stupid
 
 944     if ([self class] == NSCFBoolean_)
 
 945         return kJSTypeBoolean;
 
 947     return kJSTypeNumber;
 
 950 - (NSObject *) cy$toJSON:(NSString *)key {
 
 954 - (NSString *) cy$toCYON {
 
 955     return [self cy$JSType] != kJSTypeBoolean ? [NSString stringWithFormat:@"@%@", self] : [self boolValue] ? @"@true" : @"@false";
 
 958 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
 
 959     return [self cy$JSType] != kJSTypeBoolean ? CYCastJSValue(context, [self doubleValue]) : CYCastJSValue(context, [self boolValue]);
 
 964 /* Bridge: NSNull {{{ */
 
 965 @implementation NSNull (Cycript)
 
 967 - (JSType) cy$JSType {
 
 971 - (NSObject *) cy$toJSON:(NSString *)key {
 
 975 - (NSString *) cy$toCYON {
 
 981 /* Bridge: NSObject {{{ */
 
 982 @implementation NSObject (Cycript)
 
 988 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
 
 992 - (JSType) cy$JSType {
 
 993     return kJSTypeObject;
 
 996 - (NSObject *) cy$toJSON:(NSString *)key {
 
 997     return [self description];
 
1000 - (NSString *) cy$toCYON {
 
1001     return [[self cy$toJSON:@""] cy$toCYON];
 
1004 - (bool) cy$hasProperty:(NSString *)name {
 
1008 - (NSObject *) cy$getProperty:(NSString *)name {
 
1012 - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value {
 
1016 - (bool) cy$deleteProperty:(NSString *)name {
 
1020 - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
 
1023 + (bool) cy$hasImplicitProperties {
 
1029 /* Bridge: NSProxy {{{ */
 
1030 @implementation NSProxy (Cycript)
 
1032 - (NSObject *) cy$toJSON:(NSString *)key {
 
1033     return [self description];
 
1036 - (NSString *) cy$toCYON {
 
1037     return [[self cy$toJSON:@""] cy$toCYON];
 
1042 /* Bridge: NSString {{{ */
 
1043 @implementation NSString (Cycript)
 
1046     return [[self copy] autorelease];
 
1049 - (JSType) cy$JSType {
 
1050     return kJSTypeString;
 
1053 - (NSObject *) cy$toJSON:(NSString *)key {
 
1057 - (NSString *) cy$toCYON {
 
1058     std::ostringstream str;
 
1060     CYUTF8String string(CYCastUTF8String(self));
 
1061     CYStringify(str, string.data, string.size);
 
1062     std::string value(str.str());
 
1063     return CYCastNSString(NULL, CYUTF8String(value.c_str(), value.size()));
 
1066 - (bool) cy$hasProperty:(NSString *)name {
 
1067     if ([name isEqualToString:@"length"])
 
1070     size_t index(CYGetIndex(name));
 
1071     if (index == _not(size_t) || index >= [self length])
 
1072         return [super cy$hasProperty:name];
 
1077 - (NSObject *) cy$getProperty:(NSString *)name {
 
1078     if ([name isEqualToString:@"length"]) {
 
1079         NSUInteger count([self length]);
 
1081         return [NSNumber numberWithUnsignedInteger:count];
 
1083         return [NSNumber numberWithUnsignedInt:count];
 
1087     size_t index(CYGetIndex(name));
 
1088     if (index == _not(size_t) || index >= [self length])
 
1089         return [super cy$getProperty:name];
 
1091         return [self substringWithRange:NSMakeRange(index, 1)];
 
1094 - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
 
1095     [super cy$getPropertyNames:names inContext:context];
 
1097     for (size_t index(0), length([self length]); index != length; ++index) {
 
1099         sprintf(name, "%zu", index);
 
1100         JSPropertyNameAccumulatorAddName(names, CYJSString(name));
 
1104 // XXX: this might be overly restrictive for NSString; I think I need a half-way between /injecting/ implicit properties and /accepting/ implicit properties
 
1105 + (bool) cy$hasImplicitProperties {
 
1109 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
 
1110     return CYCastJSValue(context, CYJSString(context, self));
 
1111 } CYObjectiveCatch }
 
1115 /* Bridge: WebUndefined {{{ */
 
1116 @implementation WebUndefined (Cycript)
 
1118 - (JSType) cy$JSType {
 
1119     return kJSTypeUndefined;
 
1122 - (NSObject *) cy$toJSON:(NSString *)key {
 
1126 - (NSString *) cy$toCYON {
 
1127     return @"undefined";
 
1130 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
 
1131     return CYJSUndefined(context);
 
1132 } CYObjectiveCatch }
 
1137 static bool CYIsClass(id self) {
 
1139     // XXX: this is a lame object_isClass
 
1140     return class_getInstanceMethod(object_getClass(self), @selector(alloc)) != NULL;
 
1142     return GSObjCIsClass(self);
 
1146 Class CYCastClass(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
 
1147     id self(CYCastNSObject(pool, context, value));
 
1148     if (CYIsClass(self))
 
1149         return (Class) self;
 
1150     throw CYJSError(context, "got something that is not a Class");
 
1154 NSArray *CYCastNSArray(JSContextRef context, JSPropertyNameArrayRef names) {
 
1156     size_t size(JSPropertyNameArrayGetCount(names));
 
1157     NSMutableArray *array([NSMutableArray arrayWithCapacity:size]);
 
1158     for (size_t index(0); index != size; ++index)
 
1159         [array addObject:CYCastNSString(pool, context, JSPropertyNameArrayGetNameAtIndex(names, index))];
 
1163 JSValueRef CYCastJSValue(JSContextRef context, NSObject *value) { CYPoolTry {
 
1165         return CYJSNull(context);
 
1167         return CYMakeInstance(context, value, false);
 
1168 } CYPoolCatch(NULL) return /*XXX*/ NULL; }
 
1170 @implementation CYJSObject
 
1172 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { CYObjectiveTry {
 
1173     if ((self = [super init]) != nil) {
 
1175         context_ = CYGetJSContext(context);
 
1176         JSGlobalContextRetain(context_);
 
1177         JSValueProtect(context_, object_);
 
1179 } CYObjectiveCatch }
 
1181 - (void) dealloc { CYObjectiveTry {
 
1182     JSValueUnprotect(context_, object_);
 
1183     JSGlobalContextRelease(context_);
 
1185 } CYObjectiveCatch }
 
1187 - (NSObject *) cy$toJSON:(NSString *)key { CYObjectiveTry {
 
1188     JSValueRef toJSON(CYGetProperty(context_, object_, toJSON_s));
 
1189     if (!CYIsCallable(context_, toJSON))
 
1190         return [super cy$toJSON:key];
 
1192         JSValueRef arguments[1] = {CYCastJSValue(context_, key)};
 
1193         JSValueRef value(CYCallAsFunction(context_, (JSObjectRef) toJSON, object_, 1, arguments));
 
1194         // XXX: do I really want an NSNull here?!
 
1195         return CYCastNSObject(NULL, context_, value) ?: [NSNull null];
 
1197 } CYObjectiveCatch }
 
1199 - (NSString *) cy$toCYON { CYObjectiveTry {
 
1201     JSValueRef exception(NULL);
 
1202     const char *cyon(CYPoolCCYON(pool, context_, object_));
 
1203     CYThrow(context_, exception);
 
1205         return [super cy$toCYON];
 
1207         return [NSString stringWithUTF8String:cyon];
 
1208 } CYObjectiveCatch }
 
1210 - (NSUInteger) count { CYObjectiveTry {
 
1211     JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context_, object_));
 
1212     size_t size(JSPropertyNameArrayGetCount(names));
 
1213     JSPropertyNameArrayRelease(names);
 
1215 } CYObjectiveCatch }
 
1217 - (id) objectForKey:(id)key { CYObjectiveTry {
 
1218     JSValueRef value(CYGetProperty(context_, object_, CYJSString(context_, (NSObject *) key)));
 
1219     if (JSValueIsUndefined(context_, value))
 
1221     return CYCastNSObject(NULL, context_, value) ?: [NSNull null];
 
1222 } CYObjectiveCatch }
 
1224 - (NSEnumerator *) keyEnumerator { CYObjectiveTry {
 
1225     JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context_, object_));
 
1226     NSEnumerator *enumerator([CYCastNSArray(context_, names) objectEnumerator]);
 
1227     JSPropertyNameArrayRelease(names);
 
1229 } CYObjectiveCatch }
 
1231 - (void) setObject:(id)object forKey:(id)key { CYObjectiveTry {
 
1232     CYSetProperty(context_, object_, CYJSString(context_, (NSObject *) key), CYCastJSValue(context_, (NSString *) object));
 
1233 } CYObjectiveCatch }
 
1235 - (void) removeObjectForKey:(id)key { CYObjectiveTry {
 
1236     JSValueRef exception(NULL);
 
1237     (void) JSObjectDeleteProperty(context_, object_, CYJSString(context_, (NSObject *) key), &exception);
 
1238     CYThrow(context_, exception);
 
1239 } CYObjectiveCatch }
 
1243 @implementation CYJSArray
 
1245 - (NSString *) cy$toCYON {
 
1247     return [NSString stringWithUTF8String:CYPoolCCYON(pool, context_, object_)];
 
1250 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { CYObjectiveTry {
 
1251     if ((self = [super init]) != nil) {
 
1253         context_ = CYGetJSContext(context);
 
1254         JSGlobalContextRetain(context_);
 
1255         JSValueProtect(context_, object_);
 
1257 } CYObjectiveCatch }
 
1259 - (void) dealloc { CYObjectiveTry {
 
1260     JSValueUnprotect(context_, object_);
 
1261     JSGlobalContextRelease(context_);
 
1263 } CYObjectiveCatch }
 
1265 - (NSUInteger) count { CYObjectiveTry {
 
1266     return CYArrayLength(context_, object_);
 
1267 } CYObjectiveCatch }
 
1269 - (id) objectAtIndex:(NSUInteger)index { CYObjectiveTry {
 
1270     size_t bounds([self count]);
 
1271     if (index >= bounds)
 
1272         @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray objectAtIndex:]: index (%zu) beyond bounds (%zu)", index, bounds] userInfo:nil];
 
1273     JSValueRef exception(NULL);
 
1274     JSValueRef value(JSObjectGetPropertyAtIndex(context_, object_, index, &exception));
 
1275     CYThrow(context_, exception);
 
1276     return CYCastNSObject(NULL, context_, value) ?: [NSNull null];
 
1277 } CYObjectiveCatch }
 
1279 - (void) addObject:(id)object { CYObjectiveTry {
 
1280     CYArrayPush(context_, object_, CYCastJSValue(context_, (NSObject *) object));
 
1281 } CYObjectiveCatch }
 
1283 - (void) insertObject:(id)object atIndex:(NSUInteger)index { CYObjectiveTry {
 
1284     size_t bounds([self count] + 1);
 
1285     if (index >= bounds)
 
1286         @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray insertObject:atIndex:]: index (%zu) beyond bounds (%zu)", index, bounds] userInfo:nil];
 
1287     JSValueRef exception(NULL);
 
1288     JSValueRef arguments[3];
 
1289     arguments[0] = CYCastJSValue(context_, index);
 
1290     arguments[1] = CYCastJSValue(context_, 0);
 
1291     arguments[2] = CYCastJSValue(context_, (NSObject *) object);
 
1292     JSObjectRef Array(CYGetCachedObject(context_, CYJSString("Array_prototype")));
 
1293     JSObjectCallAsFunction(context_, CYCastJSObject(context_, CYGetProperty(context_, Array, splice_s)), object_, 3, arguments, &exception);
 
1294     CYThrow(context_, exception);
 
1295 } CYObjectiveCatch }
 
1297 - (void) removeLastObject { CYObjectiveTry {
 
1298     JSValueRef exception(NULL);
 
1299     JSObjectRef Array(CYGetCachedObject(context_, CYJSString("Array_prototype")));
 
1300     JSObjectCallAsFunction(context_, CYCastJSObject(context_, CYGetProperty(context_, Array, pop_s)), object_, 0, NULL, &exception);
 
1301     CYThrow(context_, exception);
 
1302 } CYObjectiveCatch }
 
1304 - (void) removeObjectAtIndex:(NSUInteger)index { CYObjectiveTry {
 
1305     size_t bounds([self count]);
 
1306     if (index >= bounds)
 
1307         @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray removeObjectAtIndex:]: index (%zu) beyond bounds (%zu)", index, bounds] userInfo:nil];
 
1308     JSValueRef exception(NULL);
 
1309     JSValueRef arguments[2];
 
1310     arguments[0] = CYCastJSValue(context_, index);
 
1311     arguments[1] = CYCastJSValue(context_, 1);
 
1312     JSObjectRef Array(CYGetCachedObject(context_, CYJSString("Array_prototype")));
 
1313     JSObjectCallAsFunction(context_, CYCastJSObject(context_, CYGetProperty(context_, Array, splice_s)), object_, 2, arguments, &exception);
 
1314     CYThrow(context_, exception);
 
1315 } CYObjectiveCatch }
 
1317 - (void) replaceObjectAtIndex:(NSUInteger)index withObject:(id)object { CYObjectiveTry {
 
1318     size_t bounds([self count]);
 
1319     if (index >= bounds)
 
1320         @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray replaceObjectAtIndex:withObject:]: index (%zu) beyond bounds (%zu)", index, bounds] userInfo:nil];
 
1321     CYSetProperty(context_, object_, index, CYCastJSValue(context_, (NSObject *) object));
 
1322 } CYObjectiveCatch }
 
1326 // XXX: inherit from or replace with CYJSObject
 
1327 @interface CYInternal : NSObject {
 
1328     JSGlobalContextRef context_;
 
1329     JSObjectRef object_;
 
1334 @implementation CYInternal
 
1337     JSValueUnprotect(context_, object_);
 
1338     JSGlobalContextRelease(context_);
 
1342 - (id) initInContext:(JSContextRef)context {
 
1343     if ((self = [super init]) != nil) {
 
1344         context_ = CYGetJSContext(context);
 
1345         JSGlobalContextRetain(context_);
 
1349 - (bool) hasProperty:(JSStringRef)name inContext:(JSContextRef)context {
 
1350     if (object_ == NULL)
 
1353     return JSObjectHasProperty(context, object_, name);
 
1356 - (JSValueRef) getProperty:(JSStringRef)name inContext:(JSContextRef)context {
 
1357     if (object_ == NULL)
 
1360     return CYGetProperty(context, object_, name);
 
1363 - (void) setProperty:(JSStringRef)name toValue:(JSValueRef)value inContext:(JSContextRef)context {
 
1364     @synchronized (self) {
 
1365         if (object_ == NULL) {
 
1366             object_ = JSObjectMake(context, NULL, NULL);
 
1367             JSValueProtect(context, object_);
 
1371     CYSetProperty(context, object_, name, value);
 
1374 + (CYInternal *) get:(id)object {
 
1375     if ($objc_getAssociatedObject == NULL)
 
1378     @synchronized (object) {
 
1379         if (CYInternal *internal = $objc_getAssociatedObject(object, @selector(cy$internal)))
 
1386 + (CYInternal *) set:(id)object inContext:(JSContextRef)context {
 
1387     if ($objc_getAssociatedObject == NULL)
 
1390     @synchronized (object) {
 
1391         if (CYInternal *internal = $objc_getAssociatedObject(object, @selector(cy$internal)))
 
1394         if ($objc_setAssociatedObject == NULL)
 
1397         CYInternal *internal([[[CYInternal alloc] initInContext:context] autorelease]);
 
1398         objc_setAssociatedObject(object, @selector(cy$internal), internal, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
 
1407 static JSObjectRef CYMakeSelector(JSContextRef context, SEL sel) {
 
1408     Selector_privateData *internal(new Selector_privateData(sel));
 
1409     return JSObjectMake(context, Selector_, internal);
 
1412 static SEL CYCastSEL(JSContextRef context, JSValueRef value) {
 
1413     if (JSValueIsObjectOfClass(context, value, Selector_)) {
 
1414         Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate((JSObjectRef) value)));
 
1415         return reinterpret_cast<SEL>(internal->value_);
 
1417         return CYCastPointer<SEL>(context, value);
 
1420 void *CYObjectiveC_ExecuteStart(JSContextRef context) { CYSadTry {
 
1421     return (void *) [[NSAutoreleasePool alloc] init];
 
1422 } CYSadCatch(NULL) }
 
1424 void CYObjectiveC_ExecuteEnd(JSContextRef context, void *handle) { CYSadTry {
 
1425     return [(NSAutoreleasePool *) handle release];
 
1428 JSValueRef CYObjectiveC_RuntimeProperty(JSContextRef context, CYUTF8String name) { CYPoolTry {
 
1430         return Instance::Make(context, nil);
 
1431     if (Class _class = objc_getClass(name.data))
 
1432         return CYMakeInstance(context, _class, true);
 
1433     if (Protocol *protocol = objc_getProtocol(name.data))
 
1434         return CYMakeInstance(context, protocol, true);
 
1436 } CYPoolCatch(NULL) return /*XXX*/ NULL; }
 
1438 static void CYObjectiveC_CallFunction(JSContextRef context, ffi_cif *cif, void (*function)(), uint8_t *value, void **values) { CYSadTry {
 
1439     ffi_call(cif, function, value, values);
 
1442 static bool CYObjectiveC_PoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, JSValueRef value) { CYSadTry {
 
1443     switch (type->primitive) {
 
1444         // XXX: do something epic about blocks
 
1447         case sig::typename_P:
 
1448             *reinterpret_cast<id *>(data) = CYCastNSObject(pool, context, value);
 
1451         case sig::selector_P:
 
1452             *reinterpret_cast<SEL *>(data) = CYCastSEL(context, value);
 
1460 } CYSadCatch(false) }
 
1462 static JSValueRef CYObjectiveC_FromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) { CYPoolTry {
 
1463     switch (type->primitive) {
 
1464         // XXX: do something epic about blocks
 
1467             if (NSObject *object = *reinterpret_cast<NSObject **>(data)) {
 
1468                 JSValueRef value(CYCastJSValue(context, object));
 
1474         case sig::typename_P:
 
1475             return CYMakeInstance(context, *reinterpret_cast<Class *>(data), true);
 
1477         case sig::selector_P:
 
1478             if (SEL sel = *reinterpret_cast<SEL *>(data))
 
1479                 return CYMakeSelector(context, sel);
 
1483             return CYJSNull(context);
 
1487 } CYPoolCatch(NULL) return /*XXX*/ NULL; }
 
1489 static bool CYImplements(id object, Class _class, SEL selector, bool devoid) {
 
1490     if (objc_method *method = class_getInstanceMethod(_class, selector)) {
 
1493 #if OBJC_API_VERSION >= 2
 
1495         method_getReturnType(method, type, sizeof(type));
 
1497         const char *type(method_getTypeEncoding(method));
 
1503     // XXX: possibly use a more "awesome" check?
 
1507 static const char *CYPoolTypeEncoding(apr_pool_t *pool, JSContextRef context, SEL sel, objc_method *method) {
 
1509         return method_getTypeEncoding(method);
 
1511     const char *name(sel_getName(sel));
 
1512     size_t length(strlen(name));
 
1514     char keyed[length + 2];
 
1516     keyed[length + 1] = '\0';
 
1517     memcpy(keyed + 1, name, length);
 
1519     if (CYBridgeEntry *entry = CYBridgeHash(keyed, length + 1))
 
1520         return entry->value_;
 
1525 static void MessageClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
 
1526     Closure_privateData *internal(reinterpret_cast<Closure_privateData *>(arg));
 
1528     JSContextRef context(internal->context_);
 
1530     size_t count(internal->cif_.nargs);
 
1531     JSValueRef values[count];
 
1533     for (size_t index(0); index != count; ++index)
 
1534         values[index] = CYFromFFI(context, internal->signature_.elements[1 + index].type, internal->cif_.arg_types[index], arguments[index]);
 
1536     JSObjectRef _this(CYCastJSObject(context, values[0]));
 
1538     JSValueRef value(CYCallAsFunction(context, internal->function_, _this, count - 2, values + 2));
 
1539     CYPoolFFI(NULL, context, internal->signature_.elements[0].type, internal->cif_.rtype, result, value);
 
1542 static JSObjectRef CYMakeMessage(JSContextRef context, SEL sel, IMP imp, const char *type) {
 
1543     Message_privateData *internal(new Message_privateData(sel, type, imp));
 
1544     return JSObjectMake(context, Message_, internal);
 
1547 static IMP CYMakeMessage(JSContextRef context, JSValueRef value, const char *type) {
 
1548     JSObjectRef function(CYCastJSObject(context, value));
 
1549     Closure_privateData *internal(CYMakeFunctor_(context, function, type, &MessageClosure_));
 
1550     // XXX: see notes in Library.cpp about needing to leak
 
1551     return reinterpret_cast<IMP>(internal->GetValue());
 
1554 static bool Messages_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
 
1555     Messages *internal(reinterpret_cast<Messages *>(JSObjectGetPrivate(object)));
 
1556     Class _class(internal->GetValue());
 
1559     const char *name(CYPoolCString(pool, context, property));
 
1561     if (SEL sel = sel_getUid(name))
 
1562         if (class_getInstanceMethod(_class, sel) != NULL)
 
1568 static JSValueRef Messages_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
 
1569     Messages *internal(reinterpret_cast<Messages *>(JSObjectGetPrivate(object)));
 
1570     Class _class(internal->GetValue());
 
1573     const char *name(CYPoolCString(pool, context, property));
 
1575     if (SEL sel = sel_getUid(name))
 
1576         if (objc_method *method = class_getInstanceMethod(_class, sel))
 
1577             return CYMakeMessage(context, sel, method_getImplementation(method), method_getTypeEncoding(method));
 
1582 static bool Messages_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) {
 
1583     Messages *internal(reinterpret_cast<Messages *>(JSObjectGetPrivate(object)));
 
1584     Class _class(internal->GetValue());
 
1587     const char *name(CYPoolCString(pool, context, property));
 
1589     SEL sel(sel_registerName(name));
 
1591     objc_method *method(class_getInstanceMethod(_class, sel));
 
1596     if (JSValueIsObjectOfClass(context, value, Message_)) {
 
1597         Message_privateData *message(reinterpret_cast<Message_privateData *>(JSObjectGetPrivate((JSObjectRef) value)));
 
1598         type = sig::Unparse(pool, &message->signature_);
 
1599         imp = reinterpret_cast<IMP>(message->GetValue());
 
1601         type = CYPoolTypeEncoding(pool, context, sel, method);
 
1602         imp = CYMakeMessage(context, value, type);
 
1606         method_setImplementation(method, imp);
 
1609         GSMethodList list(GSAllocMethodList(1));
 
1610         GSAppendMethodToList(list, sel, type, imp, YES);
 
1611         GSAddMethodList(_class, list, YES);
 
1612         GSFlushMethodCacheForClass(_class);
 
1614         class_addMethod(_class, sel, imp, type);
 
1621 #if 0 && OBJC_API_VERSION < 2
 
1622 static bool Messages_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
 
1623     Messages *internal(reinterpret_cast<Messages *>(JSObjectGetPrivate(object)));
 
1624     Class _class(internal->GetValue());
 
1627     const char *name(CYPoolCString(pool, context, property));
 
1629     if (SEL sel = sel_getUid(name))
 
1630         if (objc_method *method = class_getInstanceMethod(_class, sel)) {
 
1631             objc_method_list list = {NULL, 1, {method}};
 
1632             class_removeMethods(_class, &list);
 
1640 static void Messages_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
 
1641     Messages *internal(reinterpret_cast<Messages *>(JSObjectGetPrivate(object)));
 
1642     Class _class(internal->GetValue());
 
1644 #if OBJC_API_VERSION >= 2
 
1646     objc_method **data(class_copyMethodList(_class, &size));
 
1647     for (size_t i(0); i != size; ++i)
 
1648         JSPropertyNameAccumulatorAddName(names, CYJSString(sel_getName(method_getName(data[i]))));
 
1651     for (objc_method_list *methods(_class->methods); methods != NULL; methods = methods->method_next)
 
1652         for (int i(0); i != methods->method_count; ++i)
 
1653             JSPropertyNameAccumulatorAddName(names, CYJSString(sel_getName(method_getName(&methods->method_list[i]))));
 
1657 static bool CYHasImplicitProperties(Class _class) {
 
1658     // XXX: this is an evil hack to deal with NSProxy; fix elsewhere
 
1659     if (!CYImplements(_class, object_getClass(_class), @selector(cy$hasImplicitProperties), false))
 
1661     return [_class cy$hasImplicitProperties];
 
1664 static bool Instance_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
 
1665     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
 
1666     id self(internal->GetValue());
 
1668     if (JSStringIsEqualToUTF8CString(property, "$cyi"))
 
1672     NSString *name(CYCastNSString(pool, context, property));
 
1674     if (CYInternal *internal = [CYInternal get:self])
 
1675         if ([internal hasProperty:property inContext:context])
 
1678     Class _class(object_getClass(self));
 
1681         // XXX: this is an evil hack to deal with NSProxy; fix elsewhere
 
1682         if (CYImplements(self, _class, @selector(cy$hasProperty:), false))
 
1683             if ([self cy$hasProperty:name])
 
1685     } CYPoolCatch(false)
 
1687     const char *string(CYPoolCString(pool, context, name));
 
1690     if (class_getProperty(_class, string) != NULL)
 
1694     if (CYHasImplicitProperties(_class))
 
1695         if (SEL sel = sel_getUid(string))
 
1696             if (CYImplements(self, _class, sel, true))
 
1702 static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
 
1703     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
 
1704     id self(internal->GetValue());
 
1706     if (JSStringIsEqualToUTF8CString(property, "$cyi"))
 
1707         return Internal::Make(context, self, object);
 
1710     NSString *name(CYCastNSString(pool, context, property));
 
1712     if (CYInternal *internal = [CYInternal get:self])
 
1713         if (JSValueRef value = [internal getProperty:property inContext:context])
 
1717         if (NSObject *data = [self cy$getProperty:name])
 
1718             return CYCastJSValue(context, data);
 
1721     const char *string(CYPoolCString(pool, context, name));
 
1722     Class _class(object_getClass(self));
 
1725     if (objc_property_t property = class_getProperty(_class, string)) {
 
1726         PropertyAttributes attributes(property);
 
1727         SEL sel(sel_registerName(attributes.Getter()));
 
1728         return CYSendMessage(pool, context, self, NULL, sel, 0, NULL, false, exception);
 
1732     if (CYHasImplicitProperties(_class))
 
1733         if (SEL sel = sel_getUid(string))
 
1734             if (CYImplements(self, _class, sel, true))
 
1735                 return CYSendMessage(pool, context, self, NULL, sel, 0, NULL, false, exception);
 
1740 static bool Instance_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
 
1741     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
 
1742     id self(internal->GetValue());
 
1746     NSString *name(CYCastNSString(pool, context, property));
 
1747     NSObject *data(CYCastNSObject(pool, context, value));
 
1750         if ([self cy$setProperty:name to:data])
 
1754     const char *string(CYPoolCString(pool, context, name));
 
1755     Class _class(object_getClass(self));
 
1758     if (objc_property_t property = class_getProperty(_class, string)) {
 
1759         PropertyAttributes attributes(property);
 
1760         if (const char *setter = attributes.Setter()) {
 
1761             SEL sel(sel_registerName(setter));
 
1762             JSValueRef arguments[1] = {value};
 
1763             CYSendMessage(pool, context, self, NULL, sel, 1, arguments, false, exception);
 
1769     size_t length(strlen(string));
 
1771     char set[length + 5];
 
1777     if (string[0] != '\0') {
 
1778         set[3] = toupper(string[0]);
 
1779         memcpy(set + 4, string + 1, length - 1);
 
1782     set[length + 3] = ':';
 
1783     set[length + 4] = '\0';
 
1785     if (SEL sel = sel_getUid(set))
 
1786         if (CYImplements(self, _class, sel, false)) {
 
1787             JSValueRef arguments[1] = {value};
 
1788             CYSendMessage(pool, context, self, NULL, sel, 1, arguments, false, exception);
 
1792     if (CYInternal *internal = [CYInternal set:self inContext:context]) {
 
1793         [internal setProperty:property toValue:value inContext:context];
 
1800 static bool Instance_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
 
1801     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
 
1802     id self(internal->GetValue());
 
1805         NSString *name(CYCastNSString(NULL, context, property));
 
1806         return [self cy$deleteProperty:name];
 
1808 } CYCatch return /*XXX*/ NULL; }
 
1810 static void Instance_getPropertyNames_message(JSPropertyNameAccumulatorRef names, objc_method *method) {
 
1811     const char *name(sel_getName(method_getName(method)));
 
1812     if (strchr(name, ':') != NULL)
 
1815     const char *type(method_getTypeEncoding(method));
 
1816     if (type == NULL || *type == '\0' || *type == 'v')
 
1819     JSPropertyNameAccumulatorAddName(names, CYJSString(name));
 
1822 static void Instance_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
 
1823     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
 
1824     id self(internal->GetValue());
 
1827     Class _class(object_getClass(self));
 
1832         objc_property_t *data(class_copyPropertyList(_class, &size));
 
1833         for (size_t i(0); i != size; ++i)
 
1834             JSPropertyNameAccumulatorAddName(names, CYJSString(property_getName(data[i])));
 
1839     if (CYHasImplicitProperties(_class))
 
1840         for (Class current(_class); current != nil; current = class_getSuperclass(current)) {
 
1841 #if OBJC_API_VERSION >= 2
 
1843             objc_method **data(class_copyMethodList(current, &size));
 
1844             for (size_t i(0); i != size; ++i)
 
1845                 Instance_getPropertyNames_message(names, data[i]);
 
1848             for (objc_method_list *methods(current->methods); methods != NULL; methods = methods->method_next)
 
1849                 for (int i(0); i != methods->method_count; ++i)
 
1850                     Instance_getPropertyNames_message(names, &methods->method_list[i]);
 
1855         // XXX: this is an evil hack to deal with NSProxy; fix elsewhere
 
1856         if (CYImplements(self, _class, @selector(cy$getPropertyNames:inContext:), false))
 
1857             [self cy$getPropertyNames:names inContext:context];
 
1861 static JSObjectRef Instance_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
 
1862     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
 
1863     JSObjectRef value(Instance::Make(context, [internal->GetValue() alloc], Instance::Uninitialized));
 
1867 static JSValueRef Instance_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
 
1868     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
 
1869     id self(internal->GetValue());
 
1871     if (![self isKindOfClass:NSBlock_])
 
1872         CYThrow("non-NSBlock object is not a function");
 
1874     struct BlockDescriptor1 {
 
1875         unsigned long int reserved;
 
1876         unsigned long int size;
 
1879     struct BlockDescriptor2 {
 
1880         void (*copy_helper)(void *dst, void *src);
 
1881         void (*dispose_helper)(void *src);
 
1884     struct BlockDescriptor3 {
 
1885         const char *signature;
 
1889     struct BlockLiteral {
 
1893         void (*invoke)(void *, ...);
 
1895     } *literal = reinterpret_cast<BlockLiteral *>(self);
 
1898         BLOCK_DEALLOCATING = 0x0001,
 
1899         BLOCK_REFCOUNT_MASK = 0xfffe,
 
1900         BLOCK_NEEDS_FREE = 1 << 24,
 
1901         BLOCK_HAS_COPY_DISPOSE = 1 << 25,
 
1902         BLOCK_HAS_CTOR = 1 << 26,
 
1903         BLOCK_IS_GC = 1 << 27,
 
1904         BLOCK_IS_GLOBAL = 1 << 28,
 
1905         BLOCK_HAS_STRET = 1 << 29,
 
1906         BLOCK_HAS_SIGNATURE = 1 << 30,
 
1909     if ((literal->flags & BLOCK_HAS_SIGNATURE) != 0) {
 
1910         uint8_t *descriptor(reinterpret_cast<uint8_t *>(literal->descriptor));
 
1911         descriptor += sizeof(BlockDescriptor1);
 
1912         if ((literal->flags & BLOCK_HAS_COPY_DISPOSE) != 0)
 
1913             descriptor += sizeof(BlockDescriptor2);
 
1914         BlockDescriptor3 *descriptor3(reinterpret_cast<BlockDescriptor3 *>(descriptor));
 
1916         if (const char *type = descriptor3->signature) {
 
1922             sig::Signature signature;
 
1923             sig::Parse(pool, &signature, type, &Structor_);
 
1926             sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
 
1928             void (*function)() = reinterpret_cast<void (*)()>(literal->invoke);
 
1929             return CYCallFunction(pool, context, 1, setup, count, arguments, false, exception, &signature, &cif, function);
 
1934         CYThrow("NSBlock without signature field passed arguments");
 
1938     } CYPoolCatch(NULL);
 
1943 static bool Instance_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef instance, JSValueRef *exception) { CYTry {
 
1944     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate((JSObjectRef) constructor)));
 
1945     Class _class(internal->GetValue());
 
1946     if (!CYIsClass(_class))
 
1949     if (JSValueIsObjectOfClass(context, instance, Instance_)) {
 
1950         Instance *linternal(reinterpret_cast<Instance *>(JSObjectGetPrivate((JSObjectRef) instance)));
 
1951         // XXX: this isn't always safe
 
1952         return [linternal->GetValue() isKindOfClass:_class];
 
1958 static JSValueRef Instance_box_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
 
1960         throw CYJSError(context, "incorrect number of arguments to Instance");
 
1962     id value(CYCastNSObject(pool, context, arguments[0]));
 
1964         value = [NSNull null];
 
1965     return CYCastJSValue(context, [value cy$box]);
 
1968 static bool Internal_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
 
1969     Internal *internal(reinterpret_cast<Internal *>(JSObjectGetPrivate(object)));
 
1972     id self(internal->GetValue());
 
1973     const char *name(CYPoolCString(pool, context, property));
 
1975     if (object_getInstanceVariable(self, name, NULL) != NULL)
 
1981 static JSValueRef Internal_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
 
1982     Internal *internal(reinterpret_cast<Internal *>(JSObjectGetPrivate(object)));
 
1985     id self(internal->GetValue());
 
1986     const char *name(CYPoolCString(pool, context, property));
 
1988     if (objc_ivar *ivar = object_getInstanceVariable(self, name, NULL)) {
 
1989         Type_privateData type(pool, ivar_getTypeEncoding(ivar));
 
1990         // XXX: if this fails and throws an exception the person we are throwing it to gets the wrong exception
 
1991         return CYFromFFI(context, type.type_, type.GetFFI(), reinterpret_cast<uint8_t *>(self) + ivar_getOffset(ivar));
 
1997 static bool Internal_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
 
1998     Internal *internal(reinterpret_cast<Internal *>(JSObjectGetPrivate(object)));
 
2001     id self(internal->GetValue());
 
2002     const char *name(CYPoolCString(pool, context, property));
 
2004     if (objc_ivar *ivar = object_getInstanceVariable(self, name, NULL)) {
 
2005         Type_privateData type(pool, ivar_getTypeEncoding(ivar));
 
2006         CYPoolFFI(pool, context, type.type_, type.GetFFI(), reinterpret_cast<uint8_t *>(self) + ivar_getOffset(ivar), value);
 
2013 static void Internal_getPropertyNames_(Class _class, JSPropertyNameAccumulatorRef names) {
 
2014     if (Class super = class_getSuperclass(_class))
 
2015         Internal_getPropertyNames_(super, names);
 
2017 #if OBJC_API_VERSION >= 2
 
2019     objc_ivar **data(class_copyIvarList(_class, &size));
 
2020     for (size_t i(0); i != size; ++i)
 
2021         JSPropertyNameAccumulatorAddName(names, CYJSString(ivar_getName(data[i])));
 
2024     if (objc_ivar_list *ivars = _class->ivars)
 
2025         for (int i(0); i != ivars->ivar_count; ++i)
 
2026             JSPropertyNameAccumulatorAddName(names, CYJSString(ivar_getName(&ivars->ivar_list[i])));
 
2030 static void Internal_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
 
2031     Internal *internal(reinterpret_cast<Internal *>(JSObjectGetPrivate(object)));
 
2034     id self(internal->GetValue());
 
2035     Class _class(object_getClass(self));
 
2037     Internal_getPropertyNames_(_class, names);
 
2040 static JSValueRef Internal_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
 
2041     Internal *internal(reinterpret_cast<Internal *>(JSObjectGetPrivate(object)));
 
2042     return internal->GetOwner();
 
2045 static JSValueRef ObjectiveC_Classes_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
 
2047     NSString *name(CYCastNSString(pool, context, property));
 
2048     if (Class _class = NSClassFromString(name))
 
2049         return CYMakeInstance(context, _class, true);
 
2053 static void ObjectiveC_Classes_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
 
2055     size_t size(objc_getClassList(NULL, 0));
 
2056     Class *data(reinterpret_cast<Class *>(malloc(sizeof(Class) * size)));
 
2059     size_t writ(objc_getClassList(data, size));
 
2062         if (Class *copy = reinterpret_cast<Class *>(realloc(data, sizeof(Class) * writ))) {
 
2068     for (size_t i(0); i != writ; ++i)
 
2069         JSPropertyNameAccumulatorAddName(names, CYJSString(class_getName(data[i])));
 
2075     while (Class _class = objc_next_class(&state))
 
2076         JSPropertyNameAccumulatorAddName(names, CYJSString(class_getName(_class)));
 
2080 #if OBJC_API_VERSION >= 2
 
2081 static JSValueRef ObjectiveC_Image_Classes_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
 
2082     const char *internal(reinterpret_cast<const char *>(JSObjectGetPrivate(object)));
 
2085     const char *name(CYPoolCString(pool, context, property));
 
2087     const char **data(objc_copyClassNamesForImage(internal, &size));
 
2089     for (size_t i(0); i != size; ++i)
 
2090         if (strcmp(name, data[i]) == 0) {
 
2091             if (Class _class = objc_getClass(name)) {
 
2092                 value = CYMakeInstance(context, _class, true);
 
2103 static void ObjectiveC_Image_Classes_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
 
2104     const char *internal(reinterpret_cast<const char *>(JSObjectGetPrivate(object)));
 
2106     const char **data(objc_copyClassNamesForImage(internal, &size));
 
2107     for (size_t i(0); i != size; ++i)
 
2108         JSPropertyNameAccumulatorAddName(names, CYJSString(data[i]));
 
2112 static JSValueRef ObjectiveC_Images_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
 
2114     const char *name(CYPoolCString(pool, context, property));
 
2116     const char **data(objc_copyImageNames(&size));
 
2117     for (size_t i(0); i != size; ++i)
 
2118         if (strcmp(name, data[i]) == 0) {
 
2127     JSObjectRef value(JSObjectMake(context, NULL, NULL));
 
2128     CYSetProperty(context, value, CYJSString("classes"), JSObjectMake(context, ObjectiveC_Image_Classes_, const_cast<char *>(name)));
 
2132 static void ObjectiveC_Images_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
 
2134     const char **data(objc_copyImageNames(&size));
 
2135     for (size_t i(0); i != size; ++i)
 
2136         JSPropertyNameAccumulatorAddName(names, CYJSString(data[i]));
 
2141 static JSValueRef ObjectiveC_Protocols_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
 
2143     const char *name(CYPoolCString(pool, context, property));
 
2144     if (Protocol *protocol = objc_getProtocol(name))
 
2145         return CYMakeInstance(context, protocol, true);
 
2149 static void ObjectiveC_Protocols_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
 
2150 #if OBJC_API_VERSION >= 2
 
2152     Protocol **data(objc_copyProtocolList(&size));
 
2153     for (size_t i(0); i != size; ++i)
 
2154         JSPropertyNameAccumulatorAddName(names, CYJSString(protocol_getName(data[i])));
 
2161 static JSValueRef ObjectiveC_Constants_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
 
2163     CYUTF8String name(CYPoolUTF8String(pool, context, property));
 
2165         return Instance::Make(context, nil);
 
2169 static void ObjectiveC_Constants_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
 
2170     JSPropertyNameAccumulatorAddName(names, CYJSString("nil"));
 
2174 static bool stret(ffi_type *ffi_type) {
 
2175     return ffi_type->type == FFI_TYPE_STRUCT && (
 
2176         ffi_type->size > OBJC_MAX_STRUCT_BY_VALUE ||
 
2177         struct_forward_array[ffi_type->size] != 0
 
2182 JSValueRef CYSendMessage(apr_pool_t *pool, JSContextRef context, id self, Class _class, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize, JSValueRef *exception) { CYTry {
 
2186         _class = object_getClass(self);
 
2190     if (objc_method *method = class_getInstanceMethod(_class, _cmd)) {
 
2191         imp = method_getImplementation(method);
 
2192         type = method_getTypeEncoding(method);
 
2197             NSMethodSignature *method([self methodSignatureForSelector:_cmd]);
 
2199                 throw CYJSError(context, "unrecognized selector %s sent to object %p", sel_getName(_cmd), self);
 
2200             type = CYPoolCString(pool, context, [method _typeString]);
 
2208     sig::Signature signature;
 
2209     sig::Parse(pool, &signature, type, &Structor_);
 
2211     size_t used(count + 3);
 
2212     if (used > signature.count) {
 
2213         sig::Element *elements(new (pool) sig::Element[used]);
 
2214         memcpy(elements, signature.elements, used * sizeof(sig::Element));
 
2216         for (size_t index(signature.count); index != used; ++index) {
 
2217             sig::Element *element(&elements[index]);
 
2218             element->name = NULL;
 
2219             element->offset = _not(size_t);
 
2221             sig::Type *type(new (pool) sig::Type);
 
2222             memset(type, 0, sizeof(*type));
 
2223             type->primitive = sig::object_P;
 
2224             element->type = type;
 
2227         signature.elements = elements;
 
2228         signature.count = used;
 
2232     sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
 
2236         if (stret(cif.rtype))
 
2237             imp = class_getMethodImplementation_stret(_class, _cmd);
 
2239             imp = class_getMethodImplementation(_class, _cmd);
 
2241         objc_super super = {self, _class};
 
2242         imp = objc_msg_lookup_super(&super, _cmd);
 
2246     void (*function)() = reinterpret_cast<void (*)()>(imp);
 
2247     return CYCallFunction(pool, context, 2, setup, count, arguments, initialize, exception, &signature, &cif, function);
 
2250 static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
 
2252         throw CYJSError(context, "too few arguments to objc_msgSend");
 
2262     if (JSValueIsObjectOfClass(context, arguments[0], Super_)) {
 
2263         cy::Super *internal(reinterpret_cast<cy::Super *>(JSObjectGetPrivate((JSObjectRef) arguments[0])));
 
2264         self = internal->GetValue();
 
2265         _class = internal->class_;;
 
2266         uninitialized = false;
 
2267     } else if (JSValueIsObjectOfClass(context, arguments[0], Instance_)) {
 
2268         Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate((JSObjectRef) arguments[0])));
 
2269         self = internal->GetValue();
 
2271         uninitialized = internal->IsUninitialized();
 
2273             internal->value_ = nil;
 
2275         self = CYCastNSObject(pool, context, arguments[0]);
 
2277         uninitialized = false;
 
2281         return CYJSNull(context);
 
2283     _cmd = CYCastSEL(context, arguments[1]);
 
2285     return CYSendMessage(pool, context, self, _class, _cmd, count - 2, arguments + 2, uninitialized, exception);
 
2288 static JSValueRef Selector_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
 
2289     JSValueRef setup[count + 2];
 
2292     memcpy(setup + 2, arguments, sizeof(JSValueRef) * count);
 
2293     return $objc_msgSend(context, NULL, NULL, count + 2, setup, exception);
 
2296 static JSValueRef Message_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
 
2298     Message_privateData *internal(reinterpret_cast<Message_privateData *>(JSObjectGetPrivate(object)));
 
2300     // XXX: handle Instance::Uninitialized?
 
2301     id self(CYCastNSObject(pool, context, _this));
 
2305     setup[1] = &internal->sel_;
 
2307     return CYCallFunction(pool, context, 2, setup, count, arguments, false, exception, &internal->signature_, &internal->cif_, internal->GetValue());
 
2310 static JSObjectRef Super_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
 
2312         throw CYJSError(context, "incorrect number of arguments to Super constructor");
 
2314     id self(CYCastNSObject(pool, context, arguments[0]));
 
2315     Class _class(CYCastClass(pool, context, arguments[1]));
 
2316     return cy::Super::Make(context, self, _class);
 
2319 static JSObjectRef Selector_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
 
2321         throw CYJSError(context, "incorrect number of arguments to Selector constructor");
 
2323     const char *name(CYPoolCString(pool, context, arguments[0]));
 
2324     return CYMakeSelector(context, sel_registerName(name));
 
2327 static JSObjectRef Instance_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
 
2329         throw CYJSError(context, "incorrect number of arguments to Instance constructor");
 
2330     id self(count == 0 ? nil : CYCastPointer<id>(context, arguments[0]));
 
2331     return CYMakeInstance(context, self, false);
 
2334 static JSValueRef CYValue_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
 
2335     CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(object)));
 
2336     return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->value_));
 
2339 static JSValueRef CYValue_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
 
2340     CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this)));
 
2341     Type_privateData *typical(internal->GetType());
 
2346     if (typical == NULL) {
 
2350         type = typical->type_;
 
2351         ffi = typical->ffi_;
 
2354     return CYMakePointer(context, &internal->value_, _not(size_t), type, ffi, object);
 
2357 static JSValueRef Instance_getProperty_constructor(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
 
2358     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
 
2359     return Instance::Make(context, (id) object_getClass(internal->GetValue()));
 
2362 static JSValueRef Instance_getProperty_prototype(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
 
2363     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
 
2364     id self(internal->GetValue());
 
2365     if (!CYIsClass(self))
 
2366         return CYJSUndefined(context);
 
2367     return CYGetClassPrototype(context, self);
 
2370 static JSValueRef Instance_getProperty_messages(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
 
2371     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
 
2372     id self(internal->GetValue());
 
2373     if (!CYIsClass(self))
 
2374         return CYJSUndefined(context);
 
2375     return Messages::Make(context, (Class) self);
 
2378 static JSValueRef Instance_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
 
2379     if (!JSValueIsObjectOfClass(context, _this, Instance_))
 
2382     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
 
2383     return CYCastJSValue(context, CYJSString(context, CYCastNSCYON(internal->GetValue())));
 
2386 static JSValueRef Instance_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
 
2387     if (!JSValueIsObjectOfClass(context, _this, Instance_))
 
2390     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
 
2397             key = CYCastNSString(NULL, context, CYJSString(context, arguments[0]));
 
2398         // XXX: check for support of cy$toJSON?
 
2399         return CYCastJSValue(context, CYJSString(context, [internal->GetValue() cy$toJSON:key]));
 
2401 } CYCatch return /*XXX*/ NULL; }
 
2403 static JSValueRef Instance_callAsFunction_valueOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
 
2404     if (!JSValueIsObjectOfClass(context, _this, Instance_))
 
2407     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
 
2408     id value(internal->GetValue());
 
2410     if (![value respondsToSelector:@selector(cy$valueOfInContext:)])
 
2413     if (JSValueRef result = [value cy$valueOfInContext:context])
 
2417 } CYCatch return /*XXX*/ NULL; }
 
2419 static JSValueRef Instance_callAsFunction_toPointer(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
 
2420     if (!JSValueIsObjectOfClass(context, _this, Instance_))
 
2423     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
 
2424     // XXX: but... but... THIS ISN'T A POINTER! :(
 
2425     return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->GetValue()));
 
2426 } CYCatch return /*XXX*/ NULL; }
 
2428 static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
 
2429     if (!JSValueIsObjectOfClass(context, _this, Instance_))
 
2432     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
 
2433     id value(internal->GetValue());
 
2436         return CYCastJSValue(context, "nil");
 
2439         // XXX: this seems like a stupid implementation; what if it crashes? why not use the CYONifier backend?
 
2440         return CYCastJSValue(context, CYJSString(context, [value description]));
 
2442 } CYCatch return /*XXX*/ NULL; }
 
2444 static JSValueRef Selector_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
 
2445     Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate(_this)));
 
2446     return CYCastJSValue(context, sel_getName(internal->GetValue()));
 
2449 static JSValueRef Selector_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
 
2450     return Selector_callAsFunction_toString(context, object, _this, count, arguments, exception);
 
2453 static JSValueRef Selector_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
 
2454     Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate(_this)));
 
2455     const char *name(sel_getName(internal->GetValue()));
 
2458         NSString *string([NSString stringWithFormat:@"@selector(%s)", name]);
 
2459         return CYCastJSValue(context, CYJSString(context, string));
 
2461 } CYCatch return /*XXX*/ NULL; }
 
2463 static JSValueRef Selector_callAsFunction_type(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
 
2465         throw CYJSError(context, "incorrect number of arguments to Selector.type");
 
2468     Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate(_this)));
 
2469     SEL sel(internal->GetValue());
 
2471     objc_method *method;
 
2472     if (Class _class = CYCastClass(pool, context, arguments[0]))
 
2473         method = class_getInstanceMethod(_class, sel);
 
2477     if (const char *type = CYPoolTypeEncoding(pool, context, sel, method))
 
2478         return CYCastJSValue(context, CYJSString(type));
 
2480     return CYJSNull(context);
 
2483 static JSStaticValue Selector_staticValues[2] = {
 
2484     {"value", &CYValue_getProperty_value, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete},
 
2485     {NULL, NULL, NULL, 0}
 
2488 static JSStaticValue Instance_staticValues[5] = {
 
2489     {"constructor", &Instance_getProperty_constructor, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
2490     {"messages", &Instance_getProperty_messages, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
2491     {"prototype", &Instance_getProperty_prototype, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
2492     {"value", &CYValue_getProperty_value, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
2493     {NULL, NULL, NULL, 0}
 
2496 static JSStaticFunction Instance_staticFunctions[7] = {
 
2497     {"$cya", &CYValue_callAsFunction_$cya, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
2498     {"toCYON", &Instance_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
2499     {"toJSON", &Instance_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
2500     {"valueOf", &Instance_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
2501     {"toPointer", &Instance_callAsFunction_toPointer, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
2502     {"toString", &Instance_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
2506 static JSStaticFunction Internal_staticFunctions[2] = {
 
2507     {"$cya", &Internal_callAsFunction_$cya, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
2511 static JSStaticFunction Selector_staticFunctions[5] = {
 
2512     {"toCYON", &Selector_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
2513     {"toJSON", &Selector_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
2514     {"toString", &Selector_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
2515     {"type", &Selector_callAsFunction_type, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
2519 void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry {
 
2520     $objc_setAssociatedObject = reinterpret_cast<void (*)(id, void *, id value, objc_AssociationPolicy)>(dlsym(RTLD_DEFAULT, "objc_setAssociatedObject"));
 
2521     $objc_getAssociatedObject = reinterpret_cast<id (*)(id, void *)>(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject"));
 
2522     $objc_removeAssociatedObjects = reinterpret_cast<void (*)(id)>(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects"));
 
2524     apr_pool_t *pool(CYGetGlobalPool());
 
2526     Object_type = new(pool) Type_privateData("@");
 
2527     Selector_type = new(pool) Type_privateData(":");
 
2530     NSCFBoolean_ = objc_getClass("NSCFBoolean");
 
2531     if (NSCFBoolean_ == nil)
 
2532         NSCFBoolean_ = objc_getClass("__NSCFBoolean");
 
2534     NSCFType_ = objc_getClass("NSCFType");
 
2535     NSGenericDeallocHandler_ = objc_getClass("__NSGenericDeallocHandler");
 
2536     NSMessageBuilder_ = objc_getClass("NSMessageBuilder");
 
2537     NSZombie_ = objc_getClass("_NSZombie_");
 
2539     NSBoolNumber_ = objc_getClass("NSBoolNumber");
 
2542     NSArray_ = objc_getClass("NSArray");
 
2543     NSBlock_ = objc_getClass("NSBlock");
 
2544     NSDictionary_ = objc_getClass("NSDictionary");
 
2545     NSString_ = objc_getClass("NSString");
 
2546     Object_ = objc_getClass("Object");
 
2548     JSClassDefinition definition;
 
2550     definition = kJSClassDefinitionEmpty;
 
2551     definition.className = "Instance";
 
2552     definition.staticValues = Instance_staticValues;
 
2553     definition.staticFunctions = Instance_staticFunctions;
 
2554     definition.hasProperty = &Instance_hasProperty;
 
2555     definition.getProperty = &Instance_getProperty;
 
2556     definition.setProperty = &Instance_setProperty;
 
2557     definition.deleteProperty = &Instance_deleteProperty;
 
2558     definition.getPropertyNames = &Instance_getPropertyNames;
 
2559     definition.callAsConstructor = &Instance_callAsConstructor;
 
2560     definition.callAsFunction = &Instance_callAsFunction;
 
2561     definition.hasInstance = &Instance_hasInstance;
 
2562     definition.finalize = &CYFinalize;
 
2563     Instance_ = JSClassCreate(&definition);
 
2565     definition.className = "ArrayInstance";
 
2566     ArrayInstance_ = JSClassCreate(&definition);
 
2568     definition.className = "FunctionInstance";
 
2569     FunctionInstance_ = JSClassCreate(&definition);
 
2571     definition.className = "ObjectInstance";
 
2572     ObjectInstance_ = JSClassCreate(&definition);
 
2574     definition.className = "StringInstance";
 
2575     StringInstance_ = JSClassCreate(&definition);
 
2577     definition = kJSClassDefinitionEmpty;
 
2578     definition.className = "Internal";
 
2579     definition.staticFunctions = Internal_staticFunctions;
 
2580     definition.hasProperty = &Internal_hasProperty;
 
2581     definition.getProperty = &Internal_getProperty;
 
2582     definition.setProperty = &Internal_setProperty;
 
2583     definition.getPropertyNames = &Internal_getPropertyNames;
 
2584     definition.finalize = &CYFinalize;
 
2585     Internal_ = JSClassCreate(&definition);
 
2587     definition = kJSClassDefinitionEmpty;
 
2588     definition.className = "Message";
 
2589     definition.staticFunctions = cy::Functor::StaticFunctions;
 
2590     definition.callAsFunction = &Message_callAsFunction;
 
2591     definition.finalize = &CYFinalize;
 
2592     Message_ = JSClassCreate(&definition);
 
2594     definition = kJSClassDefinitionEmpty;
 
2595     definition.className = "Messages";
 
2596     definition.hasProperty = &Messages_hasProperty;
 
2597     definition.getProperty = &Messages_getProperty;
 
2598     definition.setProperty = &Messages_setProperty;
 
2599 #if 0 && OBJC_API_VERSION < 2
 
2600     definition.deleteProperty = &Messages_deleteProperty;
 
2602     definition.getPropertyNames = &Messages_getPropertyNames;
 
2603     definition.finalize = &CYFinalize;
 
2604     Messages_ = JSClassCreate(&definition);
 
2606     definition = kJSClassDefinitionEmpty;
 
2607     definition.className = "Selector";
 
2608     definition.staticValues = Selector_staticValues;
 
2609     definition.staticFunctions = Selector_staticFunctions;
 
2610     definition.callAsFunction = &Selector_callAsFunction;
 
2611     definition.finalize = &CYFinalize;
 
2612     Selector_ = JSClassCreate(&definition);
 
2614     definition = kJSClassDefinitionEmpty;
 
2615     definition.className = "Super";
 
2616     definition.staticFunctions = Internal_staticFunctions;
 
2617     definition.finalize = &CYFinalize;
 
2618     Super_ = JSClassCreate(&definition);
 
2620     definition = kJSClassDefinitionEmpty;
 
2621     definition.className = "ObjectiveC::Classes";
 
2622     definition.getProperty = &ObjectiveC_Classes_getProperty;
 
2623     definition.getPropertyNames = &ObjectiveC_Classes_getPropertyNames;
 
2624     ObjectiveC_Classes_ = JSClassCreate(&definition);
 
2626     definition = kJSClassDefinitionEmpty;
 
2627     definition.className = "ObjectiveC::Constants";
 
2628     definition.getProperty = &ObjectiveC_Constants_getProperty;
 
2629     definition.getPropertyNames = &ObjectiveC_Constants_getPropertyNames;
 
2630     ObjectiveC_Constants_ = JSClassCreate(&definition);
 
2632 #if OBJC_API_VERSION >= 2
 
2633     definition = kJSClassDefinitionEmpty;
 
2634     definition.className = "ObjectiveC::Images";
 
2635     definition.getProperty = &ObjectiveC_Images_getProperty;
 
2636     definition.getPropertyNames = &ObjectiveC_Images_getPropertyNames;
 
2637     ObjectiveC_Images_ = JSClassCreate(&definition);
 
2639     definition = kJSClassDefinitionEmpty;
 
2640     definition.className = "ObjectiveC::Image::Classes";
 
2641     definition.getProperty = &ObjectiveC_Image_Classes_getProperty;
 
2642     definition.getPropertyNames = &ObjectiveC_Image_Classes_getPropertyNames;
 
2643     ObjectiveC_Image_Classes_ = JSClassCreate(&definition);
 
2646     definition = kJSClassDefinitionEmpty;
 
2647     definition.className = "ObjectiveC::Protocols";
 
2648     definition.getProperty = &ObjectiveC_Protocols_getProperty;
 
2649     definition.getPropertyNames = &ObjectiveC_Protocols_getPropertyNames;
 
2650     ObjectiveC_Protocols_ = JSClassCreate(&definition);
 
2653     class_addMethod(NSCFType_, @selector(cy$toJSON:), reinterpret_cast<IMP>(&NSCFType$cy$toJSON), "@12@0:4@8");
 
2657 void CYObjectiveC_SetupContext(JSContextRef context) { CYPoolTry {
 
2658     JSObjectRef global(CYGetGlobalObject(context));
 
2659     JSObjectRef cy(CYCastJSObject(context, CYGetProperty(context, global, cy_s)));
 
2660     JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
 
2661     JSObjectRef all(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("all"))));
 
2662     JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
 
2664     JSObjectRef ObjectiveC(JSObjectMake(context, NULL, NULL));
 
2665     CYSetProperty(context, cycript, CYJSString("ObjectiveC"), ObjectiveC);
 
2667     JSObjectRef protocols(JSObjectMake(context, ObjectiveC_Protocols_, NULL));
 
2668     CYSetProperty(context, ObjectiveC, CYJSString("protocols"), protocols);
 
2669     CYArrayPush(context, alls, protocols);
 
2671     JSObjectRef classes(JSObjectMake(context, ObjectiveC_Classes_, NULL));
 
2672     CYSetProperty(context, ObjectiveC, CYJSString("classes"), classes);
 
2673     CYArrayPush(context, alls, classes);
 
2675     JSObjectRef constants(JSObjectMake(context, ObjectiveC_Constants_, NULL));
 
2676     CYSetProperty(context, ObjectiveC, CYJSString("constants"), constants);
 
2677     CYArrayPush(context, alls, constants);
 
2679 #if OBJC_API_VERSION >= 2
 
2680     CYSetProperty(context, ObjectiveC, CYJSString("images"), JSObjectMake(context, ObjectiveC_Images_, NULL));
 
2683     JSObjectRef Instance(JSObjectMakeConstructor(context, Instance_, &Instance_new));
 
2684     JSObjectRef Message(JSObjectMakeConstructor(context, Message_, NULL));
 
2685     JSObjectRef Selector(JSObjectMakeConstructor(context, Selector_, &Selector_new));
 
2686     JSObjectRef Super(JSObjectMakeConstructor(context, Super_, &Super_new));
 
2688     JSObjectRef Instance_prototype(CYCastJSObject(context, CYGetProperty(context, Instance, prototype_s)));
 
2689     CYSetProperty(context, cy, CYJSString("Instance_prototype"), Instance_prototype);
 
2691     JSObjectRef ArrayInstance(JSObjectMakeConstructor(context, ArrayInstance_, NULL));
 
2692     JSObjectRef ArrayInstance_prototype(CYCastJSObject(context, CYGetProperty(context, ArrayInstance, prototype_s)));
 
2693     CYSetProperty(context, cy, CYJSString("ArrayInstance_prototype"), ArrayInstance_prototype);
 
2694     JSObjectRef Array_prototype(CYGetCachedObject(context, CYJSString("Array_prototype")));
 
2695     JSObjectSetPrototype(context, ArrayInstance_prototype, Array_prototype);
 
2697     JSObjectRef FunctionInstance(JSObjectMakeConstructor(context, FunctionInstance_, NULL));
 
2698     JSObjectRef FunctionInstance_prototype(CYCastJSObject(context, CYGetProperty(context, FunctionInstance, prototype_s)));
 
2699     CYSetProperty(context, cy, CYJSString("FunctionInstance_prototype"), FunctionInstance_prototype);
 
2700     JSObjectRef Function_prototype(CYGetCachedObject(context, CYJSString("Function_prototype")));
 
2701     JSObjectSetPrototype(context, FunctionInstance_prototype, Function_prototype);
 
2703     JSObjectRef ObjectInstance(JSObjectMakeConstructor(context, ObjectInstance_, NULL));
 
2704     JSObjectRef ObjectInstance_prototype(CYCastJSObject(context, CYGetProperty(context, ObjectInstance, prototype_s)));
 
2705     CYSetProperty(context, cy, CYJSString("ObjectInstance_prototype"), ObjectInstance_prototype);
 
2706     JSObjectRef Object_prototype(CYGetCachedObject(context, CYJSString("Object_prototype")));
 
2707     JSObjectSetPrototype(context, ObjectInstance_prototype, Object_prototype);
 
2709     JSObjectRef StringInstance(JSObjectMakeConstructor(context, StringInstance_, NULL));
 
2710     JSObjectRef StringInstance_prototype(CYCastJSObject(context, CYGetProperty(context, StringInstance, prototype_s)));
 
2711     CYSetProperty(context, cy, CYJSString("StringInstance_prototype"), StringInstance_prototype);
 
2712     JSObjectRef String_prototype(CYGetCachedObject(context, CYJSString("String_prototype")));
 
2713     JSObjectSetPrototype(context, StringInstance_prototype, String_prototype);
 
2715     CYSetProperty(context, cycript, CYJSString("Instance"), Instance);
 
2716     CYSetProperty(context, cycript, CYJSString("Selector"), Selector);
 
2717     CYSetProperty(context, cycript, CYJSString("Super"), Super);
 
2719     JSObjectRef box(JSObjectMakeFunctionWithCallback(context, CYJSString("box"), &Instance_box_callAsFunction));
 
2720     CYSetProperty(context, Instance, CYJSString("box"), box);
 
2722 #if defined(__APPLE__) && defined(__arm__) && 0
 
2723     CYSetProperty(context, all, CYJSString("objc_registerClassPair"), &objc_registerClassPair_, kJSPropertyAttributeDontEnum);
 
2726     CYSetProperty(context, all, CYJSString("objc_msgSend"), &$objc_msgSend, kJSPropertyAttributeDontEnum);
 
2728     JSObjectSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Message, prototype_s)), Function_prototype);
 
2729     JSObjectSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Selector, prototype_s)), Function_prototype);
 
2732 static CYHooks CYObjectiveCHooks = {
 
2733     &CYObjectiveC_ExecuteStart,
 
2734     &CYObjectiveC_ExecuteEnd,
 
2735     &CYObjectiveC_CallFunction,
 
2736     &CYObjectiveC_Initialize,
 
2737     &CYObjectiveC_SetupContext,
 
2738     &CYObjectiveC_PoolFFI,
 
2739     &CYObjectiveC_FromFFI,
 
2742 struct CYObjectiveC {
 
2744         hooks_ = &CYObjectiveCHooks;
 
2745         // XXX: evil magic juju to make this actually take effect on a Mac when compiled with autoconf/libtool doom!
 
2746         _assert(hooks_ != NULL);