X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/dace80755cd90ff908df4a546f5a0e17a8dad186..2ca4dab349cc3f91032b17ced6b76023b4e67115:/ObjectiveC/Library.mm diff --git a/ObjectiveC/Library.mm b/ObjectiveC/Library.mm index 6440a59..4ef7be8 100644 --- a/ObjectiveC/Library.mm +++ b/ObjectiveC/Library.mm @@ -19,20 +19,18 @@ **/ /* }}} */ -#include +#include "cycript.hpp" #include "ObjectiveC/Internal.hpp" -#include - -#include "cycript.hpp" +#include +#include -#include "ObjectiveC/Internal.hpp" +#include #ifdef __APPLE__ #include #include -#include #endif #ifdef __APPLE__ @@ -91,45 +89,6 @@ 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(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(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 &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 &)>(method_getImplementation(toCYON))(value, sel, objective, objects); - else if (objc_method *methodSignatureForSelector = class_getInstanceMethod(_class, @selector(methodSignatureForSelector:))) { - if (reinterpret_cast(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 &)>(method_getImplementation(toCYON))(value, sel, objective, objects); + else if (objc_method *methodSignatureForSelector = class_getInstanceMethod(_class, @selector(methodSignatureForSelector:))) + if (reinterpret_cast(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 *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(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(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(data)) { - JSValueRef value(CYCastJSValue(context, object)); - if (initialize) - [object release]; - return value; + if (NSObject *value = *reinterpret_cast(data)) { + JSObjectRef object(CYMakeInstance(context, value)); + + if (initialize) { + Instance *internal(reinterpret_cast(JSObjectGetPrivate(object))); + + if ((internal->flags_ & Instance::Uninitialized) != 0) { + internal->flags_ = static_cast(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(data), true); + if (Class value = *reinterpret_cast(data)) + return CYMakeInstance(context, value, Instance::Permanent); + else goto null; case sig::selector_P: - if (SEL sel = *reinterpret_cast(data)) - return CYMakeSelector(context, sel); + if (SEL value = *reinterpret_cast(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(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(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(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) } @@ -2077,6 +2014,7 @@ static JSValueRef Internal_getProperty(JSContextRef context, JSObjectRef object, const char *encoding(ivar_getTypeEncoding(ivar)); _assert(encoding != NULL); + _assert(encoding[0] != '\0'); if (encoding[0] == 'b') { unsigned length, shift; CYBitField(length, shift, self, ivar, encoding, offset); @@ -2085,7 +2023,7 @@ static JSValueRef Internal_getProperty(JSContextRef context, JSObjectRef object, uintptr_t mask((1 << length) - 1); return CYCastJSValue(context, (field >> shift) & mask); } else { - auto type(new(pool) Type_privateData(ivar_getTypeEncoding(ivar))); + auto type(new(pool) Type_privateData(encoding)); return CYFromFFI(context, type->type_, type->GetFFI(), data); } } @@ -2127,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) { @@ -2164,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(malloc(sizeof(Class) * size))); @@ -2190,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 @@ -2219,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; @@ -2272,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) } @@ -2292,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) } @@ -2578,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(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 { @@ -2618,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(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 { @@ -2676,6 +2600,7 @@ static JSValueRef Instance_callAsFunction_valueOf(JSContextRef context, JSObject Instance *internal(reinterpret_cast(JSObjectGetPrivate(_this))); id value(internal->GetValue()); + _assert(value != nil); if (![value respondsToSelector:@selector(cy$valueOfInContext:)]) return _this; @@ -2911,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);