]> git.saurik.com Git - cycript.git/blobdiff - ObjectiveC/Library.mm
Avoid error caused by passing -pthread to libtool.
[cycript.git] / ObjectiveC / Library.mm
index c486fed8a51afdde725a0e5dacf29a1666637acd..4ef7be89c76ea9c8b1af1f937ee17a3dd3b50ae4 100644 (file)
 **/
 /* }}} */
 
-#include <Foundation/Foundation.h>
+#include "cycript.hpp"
 
 #include "ObjectiveC/Internal.hpp"
 
-#include <objc/objc-api.h>
-
-#include "cycript.hpp"
+#include <objc/message.h>
+#include <objc/runtime.h>
 
-#include "ObjectiveC/Internal.hpp"
+#include <Foundation/Foundation.h>
 
 #ifdef __APPLE__
 #include <CoreFoundation/CoreFoundation.h>
 #include <JavaScriptCore/JSStringRefCF.h>
-#include <objc/runtime.h>
 #endif
 
 #ifdef __APPLE__
     if (!(test)) \
         @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"_assert(" #test ")" userInfo:nil];
 
-#ifndef __APPLE__
-#define class_getSuperclass GSObjCSuper
-#define class_getInstanceVariable GSCGetInstanceVariableDefinition
-#define class_getName GSNameFromClass
-
-#define class_removeMethods(cls, list) GSRemoveMethodList(cls, list, YES)
-
-#define ivar_getName(ivar) ((ivar)->ivar_name)
-#define ivar_getOffset(ivar) ((ivar)->ivar_offset)
-#define ivar_getTypeEncoding(ivar) ((ivar)->ivar_type)
-
-#define method_getName(method) ((method)->method_name)
-#define method_getImplementation(method) ((method)->method_imp)
-#define method_getTypeEncoding(method) ((method)->method_types)
-#define method_setImplementation(method, imp) ((void) ((method)->method_imp = (imp)))
-
-#undef objc_getClass
-#define objc_getClass GSClassFromName
-
-#define objc_getProtocol GSProtocolFromName
-
-#define object_getClass GSObjCClass
-
-#define object_getInstanceVariable(object, name, value) ({ \
-    objc_ivar *ivar(class_getInstanceVariable(object_getClass(object), name)); \
-    _assert(value != NULL); \
-    if (ivar != NULL) \
-        GSObjCGetVariable(object, ivar_getOffset(ivar), sizeof(void *), value); \
-    ivar; \
-})
-
-#define object_setIvar(object, ivar, value) ({ \
-    void *data = (value); \
-    GSObjCSetVariable(object, ivar_getOffset(ivar), sizeof(void *), &data); \
-})
-
-#define protocol_getName(protocol) [(protocol) name]
-#endif
-
 @class NSBlock;
 
 struct BlockLiteral {
@@ -200,21 +159,23 @@ const char *CYPoolCString(CYPool &pool, JSContextRef context, NSString *value) {
     return string;
 }
 
-JSStringRef CYCopyJSString(JSContextRef context, NSString *value) {
 #ifdef __APPLE__
+JSStringRef CYCopyJSString(JSContextRef context, NSString *value) {
     return JSStringCreateWithCFString(reinterpret_cast<CFStringRef>(value));
-#else
-    CYPool pool;
-    return CYCopyJSString(CYPoolCString(pool, context, value));
-#endif
 }
+#endif
 
 JSStringRef CYCopyJSString(JSContextRef context, NSObject *value) {
     if (value == nil)
         return NULL;
     // XXX: this definition scares me; is anyone using this?!
     NSString *string([value description]);
+#ifdef __APPLE__
     return CYCopyJSString(context, string);
+#else
+    CYPool pool;
+    return CYCopyJSString(CYPoolCString(pool, context, string));
+#endif
 }
 
 NSString *CYCopyNSString(const CYUTF8String &value) {
@@ -425,17 +386,28 @@ struct Message_privateData :
     }
 };
 
-JSObjectRef CYMakeInstance(JSContextRef context, id object, bool permanent) {
-    Instance::Flags flags;
+JSObjectRef CYMakeInstance(JSContextRef context, id object, Instance::Flags flags = Instance::None) {
+    _assert(object != nil);
 
-    if (permanent)
-        flags = Instance::Permanent;
-    else {
-        flags = Instance::None;
+#ifdef __APPLE__
+    JSWeakObjectMapRef weak(CYCastPointer<JSWeakObjectMapRef>(context, CYGetCachedValue(context, weak_s)));
+
+    if (weak != NULL && &JSWeakObjectMapGet != NULL)
+        if (JSObjectRef instance = JSWeakObjectMapGet(context, weak, object))
+            return instance;
+#endif
+
+    if ((flags & Instance::Permanent) == 0)
         object = [object retain];
-    }
 
-    return Instance::Make(context, object, flags);
+    JSObjectRef instance(Instance::Make(context, object, flags));
+
+#ifdef __APPLE__
+    if (weak != NULL && &JSWeakObjectMapSet != NULL)
+        JSWeakObjectMapSet(context, weak, object, instance);
+#endif
+
+    return instance;
 }
 
 @interface NSMethodSignature (Cycript)
@@ -467,42 +439,32 @@ JSObjectRef CYMakeInstance(JSContextRef context, id object, bool permanent) {
 @end
 
 NSString *CYCastNSCYON(id value, bool objective, std::set<void *> &objects) {
-    NSString *string;
+    _assert(value != nil);
+
+    Class _class(object_getClass(value));
+
+    if (class_isMetaClass(_class)) {
+        const char *name(class_getName(value));
+        if (class_isMetaClass(value))
+            return [NSString stringWithFormat:@"object_getClass(%s)", name];
+        else
+            return [NSString stringWithUTF8String:name];
+    }
 
-    if (value == nil)
-        string = @"nil";
-    else {
-        Class _class(object_getClass(value));
-        SEL sel(@selector(cy$toCYON:inSet:));
-
-        if (class_isMetaClass(_class)) {
-            const char *name(class_getName(value));
-            if (class_isMetaClass(value))
-                string = [NSString stringWithFormat:@"object_getClass(%s)", name];
-            else
-                string = [NSString stringWithUTF8String:name];
-        } else if (objc_method *toCYON = class_getInstanceMethod(_class, sel))
-            string = reinterpret_cast<NSString *(*)(id, SEL, bool, std::set<void *> &)>(method_getImplementation(toCYON))(value, sel, objective, objects);
-        else if (objc_method *methodSignatureForSelector = class_getInstanceMethod(_class, @selector(methodSignatureForSelector:))) {
-            if (reinterpret_cast<NSMethodSignature *(*)(id, SEL, SEL)>(method_getImplementation(methodSignatureForSelector))(value, @selector(methodSignatureForSelector:), sel) != nil)
-                string = [value cy$toCYON:objective inSet:objects];
-            else goto fail;
-        } else fail: {
-            if (false);
 #ifdef __APPLE__
-            else if (_class == NSZombie_)
-                string = [NSString stringWithFormat:@"<_NSZombie_: %p>", value];
+    if (_class == NSZombie_)
+        return [NSString stringWithFormat:@"<_NSZombie_: %p>", value];
 #endif
-            else
-                string = [NSString stringWithFormat:@"%@", value];
-        }
 
-        // XXX: frowny pants
-        if (string == nil)
-            string = @"undefined";
-    }
+    SEL sel(@selector(cy$toCYON:inSet:));
 
-    return string;
+    if (objc_method *toCYON = class_getInstanceMethod(_class, sel))
+        return reinterpret_cast<NSString *(*)(id, SEL, bool, std::set<void *> &)>(method_getImplementation(toCYON))(value, sel, objective, objects);
+    else if (objc_method *methodSignatureForSelector = class_getInstanceMethod(_class, @selector(methodSignatureForSelector:)))
+        if (reinterpret_cast<NSMethodSignature *(*)(id, SEL, SEL)>(method_getImplementation(methodSignatureForSelector))(value, @selector(methodSignatureForSelector:), sel) != nil)
+            return [value cy$toCYON:objective inSet:objects];
+
+    return [NSString stringWithFormat:@"%@", value];
 }
 
 NSString *CYCastNSCYON(id value, bool objective, std::set<void *> *objects) {
@@ -666,6 +628,7 @@ _finline bool CYJSValueIsInstanceOfCachedConstructor(JSContextRef context, JSVal
     return _jsccall(JSValueIsInstanceOfConstructor, context, value, CYGetCachedObject(context, cache));
 }
 
+#ifdef __APPLE__
 struct CYBlockDescriptor {
     struct {
         BlockDescriptor1 one_;
@@ -710,6 +673,7 @@ NSBlock *CYMakeBlock(JSContextRef context, JSObjectRef function, sig::Signature
 
     return reinterpret_cast<NSBlock *>(literal);
 }
+#endif
 
 NSObject *CYCastNSObject(CYPool *pool, JSContextRef context, JSObjectRef object) {
     if (CYJSValueIsNSObject(context, object)) {
@@ -817,7 +781,7 @@ NSObject *CYCopyNSObject(CYPool &pool, JSContextRef context, JSValueRef value) {
             [json appendString:@","];
         else
             comma = true;
-        if (object == nil || [object cy$JSType] != kJSTypeUndefined)
+        if (object != nil && [object cy$JSType] != kJSTypeUndefined)
             [json appendString:CYCastNSCYON(object, true, objects)];
         else {
             [json appendString:@","];
@@ -1259,7 +1223,7 @@ JSValueRef CYCastJSValue(JSContextRef context, NSObject *value) { CYPoolTry {
     if (value == nil)
         return CYJSNull(context);
     else
-        return CYMakeInstance(context, value, false);
+        return CYMakeInstance(context, value);
 } CYPoolCatch(NULL) return /*XXX*/ NULL; }
 
 @implementation CYJSObject
@@ -1443,6 +1407,7 @@ JSValueRef CYCastJSValue(JSContextRef context, NSObject *value) { CYPoolTry {
 }
 
 + (CYInternal *) get:(id)object {
+#ifdef __APPLE__
     if (&objc_getAssociatedObject == NULL)
         return nil;
 
@@ -1450,11 +1415,13 @@ JSValueRef CYCastJSValue(JSContextRef context, NSObject *value) { CYPoolTry {
         if (CYInternal *internal = objc_getAssociatedObject(object, @selector(cy$internal)))
             return internal;
     }
+#endif
 
     return nil;
 }
 
 + (CYInternal *) set:(id)object inContext:(JSContextRef)context {
+#ifdef __APPLE__
     if (&objc_getAssociatedObject == NULL)
         return nil;
 
@@ -1469,6 +1436,7 @@ JSValueRef CYCastJSValue(JSContextRef context, NSObject *value) { CYPoolTry {
         objc_setAssociatedObject(object, @selector(cy$internal), internal, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
         return internal;
     }
+#endif
 
     return nil;
 }
@@ -1502,6 +1470,7 @@ static void CYObjectiveC_CallFunction(JSContextRef context, ffi_cif *cif, void (
     ffi_call(cif, function, value, values);
 } CYSadCatch() }
 
+#ifdef __APPLE__
 static NSBlock *CYCastNSBlock(CYPool &pool, JSContextRef context, JSValueRef value, sig::Signature *signature) {
     if (JSValueIsNull(context, value))
         return nil;
@@ -1536,15 +1505,18 @@ static NSBlock *CYCastNSBlock(CYPool &pool, JSContextRef context, JSValueRef val
 
     return CYMakeBlock(context, object, modified);
 }
+#endif
 
 static bool CYObjectiveC_PoolFFI(CYPool *pool, JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, JSValueRef value) { CYSadTry {
     // XXX: assigning to an indirect id * works for return values, but not for properties and fields
 
     switch (type->primitive) {
+#ifdef __APPLE__
         case sig::block_P:
             // XXX: this function might not handle the idea of a null pool
             *reinterpret_cast<id *>(data) = CYCastNSBlock(*pool, context, value, &type->data.signature);
         break;
+#endif
 
         case sig::object_P:
         case sig::typename_P:
@@ -1567,19 +1539,32 @@ static JSValueRef CYObjectiveC_FromFFI(JSContextRef context, sig::Type *type, ff
         // XXX: do something epic about blocks
         case sig::block_P:
         case sig::object_P:
-            if (NSObject *object = *reinterpret_cast<NSObject **>(data)) {
-                JSValueRef value(CYCastJSValue(context, object));
-                if (initialize)
-                    [object release];
-                return value;
+            if (NSObject *value = *reinterpret_cast<NSObject **>(data)) {
+                JSObjectRef object(CYMakeInstance(context, value));
+
+                if (initialize) {
+                    Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
+
+                    if ((internal->flags_ & Instance::Uninitialized) != 0) {
+                        internal->flags_ = static_cast<Instance::Flags>(internal->flags_ & ~Instance::Uninitialized);
+                        _assert(internal->value_ == nil);
+                        internal->value_ = value;
+                    }
+
+                    [value release];
+                }
+
+                return object;
             } else goto null;
 
         case sig::typename_P:
-            return CYMakeInstance(context, *reinterpret_cast<Class *>(data), true);
+            if (Class value = *reinterpret_cast<Class *>(data))
+                return CYMakeInstance(context, value, Instance::Permanent);
+            else goto null;
 
         case sig::selector_P:
-            if (SEL sel = *reinterpret_cast<SEL *>(data))
-                return CYMakeSelector(context, sel);
+            if (SEL value = *reinterpret_cast<SEL *>(data))
+                return CYMakeSelector(context, value);
             else goto null;
 
         null:
@@ -1680,7 +1665,6 @@ static bool Messages_setProperty(JSContextRef context, JSObjectRef object, JSStr
     } else _assert(false);
 
     objc_method *method(NULL);
-#if OBJC_API_VERSION >= 2
     unsigned int size;
     objc_method **methods(class_copyMethodList(_class, &size));
     for (size_t i(0); i != size; ++i)
@@ -1689,65 +1673,24 @@ static bool Messages_setProperty(JSContextRef context, JSObjectRef object, JSStr
             break;
         }
     free(methods);
-#else
-    for (objc_method_list *methods(_class->methods); methods != NULL; methods = methods->method_next)
-        for (int i(0); i != methods->method_count; ++i)
-            if (sel_isEqual(method_getName(&methods->method_list[i]), sel)) {
-                method = &methods->method_list[i];
-                break;
-            }
-#endif
 
     if (method != NULL)
         method_setImplementation(method, imp);
-    else {
-#ifdef GNU_RUNTIME
-        GSMethodList list(GSAllocMethodList(1));
-        GSAppendMethodToList(list, sel, type, imp, YES);
-        GSAddMethodList(_class, list, YES);
-        GSFlushMethodCacheForClass(_class);
-#else
+    else
         class_addMethod(_class, sel, imp, type);
-#endif
-    }
 
     return true;
 } CYCatch(false) }
 
-#if 0 && OBJC_API_VERSION < 2
-static bool Messages_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
-    Messages *internal(reinterpret_cast<Messages *>(JSObjectGetPrivate(object)));
-    Class _class(internal->GetValue());
-
-    CYPool pool;
-    const char *name(CYPoolCString(pool, context, property));
-
-    if (SEL sel = sel_getUid(name))
-        if (objc_method *method = class_getInstanceMethod(_class, sel)) {
-            objc_method_list list = {NULL, 1, {method}};
-            class_removeMethods(_class, &list);
-            return true;
-        }
-
-    return false;
-} CYCatch(false) }
-#endif
-
 static void Messages_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
     Messages *internal(reinterpret_cast<Messages *>(JSObjectGetPrivate(object)));
     Class _class(internal->GetValue());
 
-#if OBJC_API_VERSION >= 2
     unsigned int size;
     objc_method **data(class_copyMethodList(_class, &size));
     for (size_t i(0); i != size; ++i)
         JSPropertyNameAccumulatorAddName(names, CYJSString(sel_getName(method_getName(data[i]))));
     free(data);
-#else
-    for (objc_method_list *methods(_class->methods); methods != NULL; methods = methods->method_next)
-        for (int i(0); i != methods->method_count; ++i)
-            JSPropertyNameAccumulatorAddName(names, CYJSString(sel_getName(method_getName(&methods->method_list[i]))));
-#endif
 }
 
 static bool CYHasImplicitProperties(Class _class) {
@@ -1934,17 +1877,11 @@ static void Instance_getPropertyNames(JSContextRef context, JSObjectRef object,
 
     if (CYHasImplicitProperties(_class))
         for (Class current(_class); current != nil; current = class_getSuperclass(current)) {
-#if OBJC_API_VERSION >= 2
             unsigned int size;
             objc_method **data(class_copyMethodList(current, &size));
             for (size_t i(0); i != size; ++i)
                 Instance_getPropertyNames_message(names, data[i]);
             free(data);
-#else
-            for (objc_method_list *methods(current->methods); methods != NULL; methods = methods->method_next)
-                for (int i(0); i != methods->method_count; ++i)
-                    Instance_getPropertyNames_message(names, &methods->method_list[i]);
-#endif
         }
 
     CYPoolTry {
@@ -1956,7 +1893,7 @@ static void Instance_getPropertyNames(JSContextRef context, JSObjectRef object,
 
 static JSObjectRef Instance_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
-    JSObjectRef value(Instance::Make(context, [internal->GetValue() alloc], Instance::Uninitialized));
+    JSObjectRef value(CYMakeInstance(context, [internal->GetValue() alloc], Instance::Uninitialized));
     return value;
 } CYCatch(NULL) }
 
@@ -2128,17 +2065,11 @@ static void Internal_getPropertyNames_(Class _class, JSPropertyNameAccumulatorRe
     if (Class super = class_getSuperclass(_class))
         Internal_getPropertyNames_(super, names);
 
-#if OBJC_API_VERSION >= 2
     unsigned int size;
     objc_ivar **data(class_copyIvarList(_class, &size));
     for (size_t i(0); i != size; ++i)
         JSPropertyNameAccumulatorAddName(names, CYJSString(ivar_getName(data[i])));
     free(data);
-#else
-    if (objc_ivar_list *ivars = _class->ivars)
-        for (int i(0); i != ivars->ivar_count; ++i)
-            JSPropertyNameAccumulatorAddName(names, CYJSString(ivar_getName(&ivars->ivar_list[i])));
-#endif
 }
 
 static void Internal_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
@@ -2165,11 +2096,10 @@ static JSValueRef ObjectiveC_Classes_getProperty(JSContextRef context, JSObjectR
     CYPool pool;
     NSString *name(CYCastNSString(&pool, context, property));
     if (Class _class = NSClassFromString(name))
-        return CYMakeInstance(context, _class, true);
+        return CYMakeInstance(context, _class, Instance::Permanent);
     return NULL;
 } CYCatch(NULL) }
 
-#ifdef __APPLE__
 static Class *CYCopyClassList(size_t &size) {
     size = objc_getClassList(NULL, 0);
     Class *data(reinterpret_cast<Class *>(malloc(sizeof(Class) * size)));
@@ -2191,21 +2121,14 @@ static Class *CYCopyClassList(size_t &size) {
         size = writ;
     }
 }
-#endif
 
 static void ObjectiveC_Classes_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
-#ifdef __APPLE__
     size_t size;
     if (Class *data = CYCopyClassList(size)) {
         for (size_t i(0); i != size; ++i)
             JSPropertyNameAccumulatorAddName(names, CYJSString(class_getName(data[i])));
         free(data);
     }
-#else
-    void *state(NULL);
-    while (Class _class = objc_next_class(&state))
-        JSPropertyNameAccumulatorAddName(names, CYJSString(class_getName(_class)));
-#endif
 }
 
 #if OBJC_API_VERSION >= 2
@@ -2220,7 +2143,7 @@ static JSValueRef ObjectiveC_Image_Classes_getProperty(JSContextRef context, JSO
     for (size_t i(0); i != size; ++i)
         if (strcmp(name, data[i]) == 0) {
             if (Class _class = objc_getClass(name)) {
-                value = CYMakeInstance(context, _class, true);
+                value = CYMakeInstance(context, _class, Instance::Permanent);
                 goto free;
             } else
                 break;
@@ -2273,7 +2196,7 @@ static JSValueRef ObjectiveC_Protocols_getProperty(JSContextRef context, JSObjec
     CYPool pool;
     const char *name(CYPoolCString(pool, context, property));
     if (Protocol *protocol = objc_getProtocol(name))
-        return CYMakeInstance(context, protocol, true);
+        return CYMakeInstance(context, protocol, Instance::Permanent);
     return NULL;
 } CYCatch(NULL) }
 
@@ -2293,7 +2216,7 @@ static JSValueRef ObjectiveC_Constants_getProperty(JSContextRef context, JSObjec
     CYPool pool;
     CYUTF8String name(CYPoolUTF8String(pool, context, property));
     if (name == "nil")
-        return Instance::Make(context, nil);
+        return CYJSNull(context);
     return NULL;
 } CYCatch(NULL) }
 
@@ -2579,7 +2502,7 @@ static JSObjectRef Instance_new(JSContextRef context, JSObjectRef object, size_t
     if (count > 1)
         throw CYJSError(context, "incorrect number of arguments to Instance constructor");
     id self(count == 0 ? nil : CYCastPointer<id>(context, arguments[0]));
-    return CYMakeInstance(context, self, false);
+    return CYMakeInstance(context, self);
 } CYCatch(NULL) }
 
 static JSValueRef CYValue_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
@@ -2619,7 +2542,7 @@ static JSValueRef FunctionInstance_getProperty_type(JSContextRef context, JSObje
 
 static JSValueRef Instance_getProperty_constructor(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
-    return Instance::Make(context, (id) object_getClass(internal->GetValue()));
+    return CYMakeInstance(context, object_getClass(internal->GetValue()), Instance::Permanent);
 } CYCatch(NULL) }
 
 static JSValueRef Instance_getProperty_prototype(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
@@ -2677,6 +2600,7 @@ static JSValueRef Instance_callAsFunction_valueOf(JSContextRef context, JSObject
 
     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
     id value(internal->GetValue());
+    _assert(value != nil);
 
     if (![value respondsToSelector:@selector(cy$valueOfInContext:)])
         return _this;
@@ -2912,9 +2836,6 @@ void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry {
     definition.hasProperty = &Messages_hasProperty;
     definition.getProperty = &Messages_getProperty;
     definition.setProperty = &Messages_setProperty;
-#if 0 && OBJC_API_VERSION < 2
-    definition.deleteProperty = &Messages_deleteProperty;
-#endif
     definition.getPropertyNames = &Messages_getPropertyNames;
     definition.finalize = &CYFinalize;
     Messages_ = JSClassCreate(&definition);