]> git.saurik.com Git - cycript.git/blobdiff - ObjectiveC/Library.mm
Implement all of the crazy ECMAScript octal stuff.
[cycript.git] / ObjectiveC / Library.mm
index 4ef7be89c76ea9c8b1af1f937ee17a3dd3b50ae4..dccc3ad3b8a9488f13d6dbd4a382604d8980067c 100644 (file)
@@ -1,5 +1,5 @@
 /* Cycript - Optimizing JavaScript Compiler/Runtime
- * Copyright (C) 2009-2014  Jay Freeman (saurik)
+ * Copyright (C) 2009-2015  Jay Freeman (saurik)
 */
 
 /* GNU Affero General Public License, Version 3 {{{ */
@@ -159,7 +159,7 @@ const char *CYPoolCString(CYPool &pool, JSContextRef context, NSString *value) {
     return string;
 }
 
-#ifdef __APPLE__
+#ifdef __clang__
 JSStringRef CYCopyJSString(JSContextRef context, NSString *value) {
     return JSStringCreateWithCFString(reinterpret_cast<CFStringRef>(value));
 }
@@ -170,7 +170,7 @@ JSStringRef CYCopyJSString(JSContextRef context, NSObject *value) {
         return NULL;
     // XXX: this definition scares me; is anyone using this?!
     NSString *string([value description]);
-#ifdef __APPLE__
+#ifdef __clang__
     return CYCopyJSString(context, string);
 #else
     CYPool pool;
@@ -264,7 +264,6 @@ static Class __NSMallocBlock__;
 static Class NSCFBoolean_;
 static Class NSCFType_;
 static Class NSGenericDeallocHandler_;
-static Class NSZombie_;
 #else
 static Class NSBoolNumber_;
 #endif
@@ -274,6 +273,7 @@ static Class NSBlock_;
 static Class NSDictionary_;
 static Class NSNumber_;
 static Class NSString_;
+static Class NSZombie_;
 static Class Object_;
 
 static Type_privateData *Object_type;
@@ -451,10 +451,8 @@ NSString *CYCastNSCYON(id value, bool objective, std::set<void *> &objects) {
             return [NSString stringWithUTF8String:name];
     }
 
-#ifdef __APPLE__
     if (_class == NSZombie_)
         return [NSString stringWithFormat:@"<_NSZombie_: %p>", value];
-#endif
 
     SEL sel(@selector(cy$toCYON:inSet:));
 
@@ -476,7 +474,6 @@ NSString *CYCastNSCYON(id value, bool objective, std::set<void *> *objects) {
     }
 }
 
-#ifdef __APPLE__
 struct PropertyAttributes {
     CYPool pool_;
 
@@ -564,7 +561,6 @@ struct PropertyAttributes {
     }
 
 };
-#endif
 
 @interface CYWebUndefined : NSObject {
 }
@@ -648,10 +644,6 @@ static JSValueRef BlockAdapter_(JSContextRef context, size_t count, JSValueRef v
     return CYCallAsFunction(context, function, _this, count - 1, values + 1);
 }
 
-static void BlockClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
-    CYExecuteClosure(cif, result, arguments, arg, &BlockAdapter_);
-}
-
 NSBlock *CYMakeBlock(JSContextRef context, JSObjectRef function, sig::Signature &signature) {
     _assert(__NSMallocBlock__ != Nil);
     BlockLiteral *literal(reinterpret_cast<BlockLiteral *>(malloc(sizeof(BlockLiteral))));
@@ -659,7 +651,7 @@ NSBlock *CYMakeBlock(JSContextRef context, JSObjectRef function, sig::Signature
     CYBlockDescriptor *descriptor(new CYBlockDescriptor);
     memset(&descriptor->d_, 0, sizeof(descriptor->d_));
 
-    descriptor->internal_ = CYMakeFunctor_(context, function, signature, &BlockClosure_);
+    descriptor->internal_ = CYMakeFunctor_(context, function, signature, &BlockAdapter_);
     literal->invoke = reinterpret_cast<void (*)(void *, ...)>(descriptor->internal_->GetValue());
 
     literal->isa = __NSMallocBlock__;
@@ -771,7 +763,7 @@ NSObject *CYCopyNSObject(CYPool &pool, JSContextRef context, JSValueRef value) {
     [json appendString:@"@["];
 
     bool comma(false);
-#ifdef __APPLE__
+#ifdef __clang__
     for (id object in self) {
 #else
     for (size_t index(0), count([self count]); index != count; ++index) {
@@ -881,7 +873,7 @@ NSObject *CYCopyNSObject(CYPool &pool, JSContextRef context, JSValueRef value) {
     [json appendString:@"@{"];
 
     bool comma(false);
-#ifdef __APPLE__
+#ifdef __clang__
     for (NSObject *key in self) {
 #else
     NSEnumerator *keys([self keyEnumerator]);
@@ -912,7 +904,7 @@ NSObject *CYCopyNSObject(CYPool &pool, JSContextRef context, JSValueRef value) {
 - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
     [super cy$getPropertyNames:names inContext:context];
 
-#ifdef __APPLE__
+#ifdef __clang__
     for (NSObject *key in self) {
 #else
     NSEnumerator *keys([self keyEnumerator]);
@@ -935,11 +927,7 @@ NSObject *CYCopyNSObject(CYPool &pool, JSContextRef context, JSValueRef value) {
     if ([name isEqualToString:@"length"]) {
         // XXX: is this not intelligent?
         NSNumber *number(reinterpret_cast<NSNumber *>(value));
-#ifdef __APPLE__
         NSUInteger size([number unsignedIntegerValue]);
-#else
-        NSUInteger size([number unsignedIntValue]);
-#endif
         NSUInteger count([self count]);
         if (size < count)
             [self removeObjectsInRange:NSMakeRange(size, count - size)];
@@ -1095,6 +1083,21 @@ NSObject *CYCopyNSObject(CYPool &pool, JSContextRef context, JSValueRef value) {
     return true;
 }
 
+@end
+/* }}} */
+/* Bridge: NSOrderedSet {{{ */
+@implementation NSOrderedSet (Cycript)
+
+- (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
+    _oassert(objects.insert(self).second);
+
+    NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
+    [json appendString:@"[NSOrderedSet orderedSetWithArray:"];
+    [json appendString:CYCastNSCYON([self array], true, objects)];
+    [json appendString:@"]]"];
+    return json;
+}
+
 @end
 /* }}} */
 /* Bridge: NSProxy {{{ */
@@ -1195,11 +1198,7 @@ NSObject *CYCopyNSObject(CYPool &pool, JSContextRef context, JSValueRef value) {
 /* }}} */
 
 static bool CYIsClass(id self) {
-#ifdef __APPLE__
     return class_isMetaClass(object_getClass(self));
-#else
-    return GSObjCIsClass(self);
-#endif
 }
 
 Class CYCastClass(CYPool &pool, JSContextRef context, JSValueRef value) {
@@ -1466,8 +1465,8 @@ void CYObjectiveC_ExecuteEnd(JSContextRef context, void *handle) { CYSadTry {
     return [(NSAutoreleasePool *) handle release];
 } CYSadCatch() }
 
-static void CYObjectiveC_CallFunction(JSContextRef context, ffi_cif *cif, void (*function)(), uint8_t *value, void **values) { CYSadTry {
-    ffi_call(cif, function, value, values);
+static void CYObjectiveC_CallFunction(CYPool &pool, JSContextRef context, ffi_cif *cif, void (*function)(), void *value, void **values) { CYSadTry {
+    CYCallFunction(pool, context, cif, function, value, values);
 } CYSadCatch() }
 
 #ifdef __APPLE__
@@ -1578,12 +1577,8 @@ static bool CYImplements(id object, Class _class, SEL selector, bool devoid = fa
     if (objc_method *method = class_getInstanceMethod(_class, selector)) {
         if (!devoid)
             return true;
-#if OBJC_API_VERSION >= 2
         char type[16];
         method_getReturnType(method, type, sizeof(type));
-#else
-        const char *type(method_getTypeEncoding(method));
-#endif
         if (type[0] != 'v')
             return true;
     }
@@ -1597,10 +1592,6 @@ static JSValueRef MessageAdapter_(JSContextRef context, size_t count, JSValueRef
     return CYCallAsFunction(context, function, _this, count - 2, values + 2);
 }
 
-static void MessageClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
-    CYExecuteClosure(cif, result, arguments, arg, &MessageAdapter_);
-}
-
 static JSObjectRef CYMakeMessage(JSContextRef context, SEL sel, IMP imp, const char *type) {
     Message_privateData *internal(new Message_privateData(sel, type, imp));
     return JSObjectMake(context, Message_, internal);
@@ -1611,7 +1602,7 @@ static IMP CYMakeMessage(JSContextRef context, JSValueRef value, const char *enc
     CYPool pool;
     sig::Signature signature;
     sig::Parse(pool, &signature, encoding, &Structor_);
-    Closure_privateData *internal(CYMakeFunctor_(context, function, signature, &MessageClosure_));
+    Closure_privateData *internal(CYMakeFunctor_(context, function, signature, &MessageAdapter_));
     // XXX: see notes in Library.cpp about needing to leak
     return reinterpret_cast<IMP>(internal->GetValue());
 }
@@ -1725,10 +1716,8 @@ static bool Instance_hasProperty(JSContextRef context, JSObjectRef object, JSStr
 
     const char *string(CYPoolCString(pool, context, name));
 
-#ifdef __APPLE__
     if (class_getProperty(_class, string) != NULL)
         return true;
-#endif
 
     if (CYHasImplicitProperties(_class))
         if (SEL sel = sel_getUid(string))
@@ -1760,13 +1749,11 @@ static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object,
     const char *string(CYPoolCString(pool, context, name));
     Class _class(object_getClass(self));
 
-#ifdef __APPLE__
     if (objc_property_t property = class_getProperty(_class, string)) {
         PropertyAttributes attributes(property);
         SEL sel(sel_registerName(attributes.Getter()));
         return CYSendMessage(pool, context, self, NULL, sel, 0, NULL, false);
     }
-#endif
 
     if (CYHasImplicitProperties(_class))
         if (SEL sel = sel_getUid(string))
@@ -1793,7 +1780,6 @@ static bool Instance_setProperty(JSContextRef context, JSObjectRef object, JSStr
     const char *string(CYPoolCString(pool, context, name));
     Class _class(object_getClass(self));
 
-#ifdef __APPLE__
     if (objc_property_t property = class_getProperty(_class, string)) {
         PropertyAttributes attributes(property);
         if (const char *setter = attributes.Setter()) {
@@ -1803,7 +1789,6 @@ static bool Instance_setProperty(JSContextRef context, JSObjectRef object, JSStr
             return true;
         }
     }
-#endif
 
     size_t length(strlen(string));
 
@@ -1865,7 +1850,6 @@ static void Instance_getPropertyNames(JSContextRef context, JSObjectRef object,
     CYPool pool;
     Class _class(object_getClass(self));
 
-#ifdef __APPLE__
     {
         unsigned int size;
         objc_property_t *data(class_copyPropertyList(_class, &size));
@@ -1873,7 +1857,6 @@ static void Instance_getPropertyNames(JSContextRef context, JSObjectRef object,
             JSPropertyNameAccumulatorAddName(names, CYJSString(property_getName(data[i])));
         free(data);
     }
-#endif
 
     if (CYHasImplicitProperties(_class))
         for (Class current(_class); current != nil; current = class_getSuperclass(current)) {
@@ -2131,7 +2114,7 @@ static void ObjectiveC_Classes_getPropertyNames(JSContextRef context, JSObjectRe
     }
 }
 
-#if OBJC_API_VERSION >= 2
+#ifdef __APPLE__
 static JSValueRef ObjectiveC_Image_Classes_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
     const char *internal(reinterpret_cast<const char *>(JSObjectGetPrivate(object)));
 
@@ -2201,15 +2184,11 @@ static JSValueRef ObjectiveC_Protocols_getProperty(JSContextRef context, JSObjec
 } CYCatch(NULL) }
 
 static void ObjectiveC_Protocols_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
-#if OBJC_API_VERSION >= 2
     unsigned int size;
     Protocol **data(objc_copyProtocolList(&size));
     for (size_t i(0); i != size; ++i)
         JSPropertyNameAccumulatorAddName(names, CYJSString(protocol_getName(data[i])));
     free(data);
-#else
-    // XXX: fix this!
-#endif
 }
 
 static JSValueRef ObjectiveC_Constants_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
@@ -2283,7 +2262,7 @@ static JSValueRef choose(JSContextRef context, JSObjectRef object, JSObjectRef _
     CYGarbageCollect(context);
 
     CYPool pool;
-    Class _class(CYCastNSObject(&pool, context, arguments[0]));
+    id _class(CYCastNSObject(&pool, context, arguments[0]));
 
     vm_address_t *zones(NULL);
     unsigned size(0);
@@ -2345,6 +2324,8 @@ static bool stret(ffi_type *ffi_type) {
     );
 }
 #endif
+#else
+#define CY_NO_STRET
 #endif
 
 JSValueRef CYSendMessage(CYPool &pool, JSContextRef context, id self, Class _class, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize) {
@@ -2362,11 +2343,14 @@ JSValueRef CYSendMessage(CYPool &pool, JSContextRef context, id self, Class _cla
         imp = NULL;
 
         CYPoolTry {
-            NSMethodSignature *method([self methodSignatureForSelector:_cmd]);
-            if (method == nil)
-                throw CYJSError(context, "unrecognized selector %s sent to object %p", sel_getName(_cmd), self);
-            type = CYPoolCString(pool, context, [method _typeString]);
+            if (NSMethodSignature *method = [self methodSignatureForSelector:_cmd])
+                type = CYPoolCString(pool, context, [method _typeString]);
+            else
+                type = NULL;
         } CYPoolCatch(NULL)
+
+        if (type == NULL)
+            throw CYJSError(context, "unrecognized selector %s sent to object %p", sel_getName(_cmd), self);
     }
 
     void *setup[2];
@@ -2400,17 +2384,12 @@ JSValueRef CYSendMessage(CYPool &pool, JSContextRef context, id self, Class _cla
     sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
 
     if (imp == NULL) {
-#ifdef __APPLE__
 #ifndef CY_NO_STRET
         if (stret(cif.rtype))
             imp = class_getMethodImplementation_stret(_class, _cmd);
         else
 #endif
             imp = class_getMethodImplementation(_class, _cmd);
-#else
-        objc_super super = {self, _class};
-        imp = objc_msg_lookup_super(&super, _cmd);
-#endif
     }
 
     void (*function)() = reinterpret_cast<void (*)()>(imp);
@@ -2770,6 +2749,7 @@ void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry {
     NSZombie_ = objc_getClass("_NSZombie_");
 #else
     NSBoolNumber_ = objc_getClass("NSBoolNumber");
+    NSZombie_ = objc_getClass("NSZombie");
 #endif
 
     JSClassDefinition definition;
@@ -2867,7 +2847,7 @@ void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry {
     definition.getPropertyNames = &ObjectiveC_Constants_getPropertyNames;
     ObjectiveC_Constants_ = JSClassCreate(&definition);
 
-#if OBJC_API_VERSION >= 2
+#ifdef __APPLE__
     definition = kJSClassDefinitionEmpty;
     definition.className = "ObjectiveC::Images";
     definition.getProperty = &ObjectiveC_Images_getProperty;
@@ -2921,7 +2901,7 @@ void CYObjectiveC_SetupContext(JSContextRef context) { CYPoolTry {
     CYSetProperty(context, ObjectiveC, CYJSString("constants"), constants);
     CYArrayPush(context, alls, constants);
 
-#if OBJC_API_VERSION >= 2
+#ifdef __APPLE__
     CYSetProperty(context, ObjectiveC, CYJSString("images"), JSObjectMake(context, ObjectiveC_Images_, NULL));
 #endif
 
@@ -2991,6 +2971,15 @@ void CYObjectiveC_SetupContext(JSContextRef context) { CYPoolTry {
     CYSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Selector, prototype_s)), Function_prototype);
 } CYPoolCatch() }
 
+static void *CYObjectiveC_CastSymbol(const char *name) {
+    if (false);
+#ifdef __GNU_LIBOBJC__
+    else if (strcmp(name, "object_getClass") == 0)
+        return reinterpret_cast<void *>(&object_getClass);
+#endif
+    return NULL;
+}
+
 static CYHook CYObjectiveCHook = {
     &CYObjectiveC_ExecuteStart,
     &CYObjectiveC_ExecuteEnd,
@@ -2999,6 +2988,7 @@ static CYHook CYObjectiveCHook = {
     &CYObjectiveC_SetupContext,
     &CYObjectiveC_PoolFFI,
     &CYObjectiveC_FromFFI,
+    &CYObjectiveC_CastSymbol,
 };
 
 CYRegisterHook CYObjectiveC(&CYObjectiveCHook);