X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/67110a156d28581856737ca3de13b4dbe4718288..cdff65f8e03d25cd3f782b264e15e596d2259857:/ObjectiveC/Library.mm?ds=sidebyside diff --git a/ObjectiveC/Library.mm b/ObjectiveC/Library.mm index 1904f24..742e3ef 100644 --- a/ObjectiveC/Library.mm +++ b/ObjectiveC/Library.mm @@ -294,6 +294,7 @@ static JSClassRef ObjectiveC_Images_; #endif #ifdef __APPLE__ +static Class __NSMallocBlock__; static Class NSCFBoolean_; static Class NSCFType_; static Class NSGenericDeallocHandler_; @@ -638,30 +639,47 @@ _finline bool CYJSValueIsInstanceOfCachedConstructor(JSContextRef context, JSVal return _jsccall(JSValueIsInstanceOfConstructor, context, value, CYGetCachedObject(context, cache)); } -NSObject *CYMakeBlock(void (*invoke)(), sig::Signature &signature) { - BlockLiteral *literal(reinterpret_cast(malloc(sizeof(BlockLiteral)))); +struct CYBlockDescriptor { + struct { + BlockDescriptor1 one_; + BlockDescriptor2 two_; + BlockDescriptor3 three_; + } d_; + + Closure_privateData *internal_; +}; - struct Descriptor { - struct { - BlockDescriptor1 one_; - BlockDescriptor2 two_; - BlockDescriptor3 three_; - } d_; +void CYDisposeBlock(BlockLiteral *literal) { + delete reinterpret_cast(literal->descriptor)->internal_; +} - CYPool pool_; - }; +static JSValueRef BlockAdapter_(JSContextRef context, size_t count, JSValueRef values[], JSObjectRef function) { + JSObjectRef _this(CYCastJSObject(context, values[0])); + return CYCallAsFunction(context, function, _this, count - 1, values + 1); +} - Descriptor *descriptor(new Descriptor); +static void BlockClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) { + CYExecuteClosure(cif, result, arguments, arg, &BlockAdapter_); +} + +NSObject *CYMakeBlock(JSContextRef context, JSObjectRef function, sig::Signature &signature) { + _assert(__NSMallocBlock__ != Nil); + BlockLiteral *literal(reinterpret_cast(malloc(sizeof(BlockLiteral)))); + + CYBlockDescriptor *descriptor(new CYBlockDescriptor); memset(&descriptor->d_, 0, sizeof(descriptor->d_)); - literal->isa = objc_getClass("__NSGlobalBlock__"); + descriptor->internal_ = CYMakeFunctor_(context, function, signature, &BlockClosure_); + literal->invoke = reinterpret_cast(descriptor->internal_->GetValue()); + + literal->isa = __NSMallocBlock__; literal->flags = BLOCK_HAS_SIGNATURE | BLOCK_HAS_COPY_DISPOSE | BLOCK_IS_GLOBAL; literal->reserved = 0; - literal->invoke = reinterpret_cast(invoke); literal->descriptor = descriptor; descriptor->d_.one_.size = sizeof(descriptor->d_); - descriptor->d_.three_.signature = sig::Unparse(descriptor->pool_, &signature); + descriptor->d_.two_.dispose_helper = &CYDisposeBlock; + descriptor->d_.three_.signature = sig::Unparse(*descriptor->internal_->pool_, &signature); return reinterpret_cast(literal); } @@ -672,11 +690,6 @@ NSObject *CYCastNSObject(CYPool *pool, JSContextRef context, JSObjectRef object) return internal->GetValue(); } - if (JSValueIsObjectOfClass(context, object, Functor_)) { - cy::Functor *internal(reinterpret_cast(JSObjectGetPrivate(object))); - return CYMakeBlock(internal->GetValue(), internal->signature_); - } - bool array(CYJSValueIsInstanceOfCachedConstructor(context, object, Array_s)); id value(array ? [CYJSArray alloc] : [CYJSObject alloc]); return CYPoolRelease(pool, [value initWithJSObject:object inContext:context]); @@ -1055,7 +1068,7 @@ NSObject *CYCopyNSObject(CYPool &pool, JSContextRef context, JSValueRef value) { } - (NSString *) cy$toCYON:(bool)objective { - return [[self description] cy$toCYON:objective]; + return [@"#" stringByAppendingString:[[self description] cy$toCYON:true]]; } - (bool) cy$hasProperty:(NSString *)name { @@ -1096,6 +1109,19 @@ NSObject *CYCopyNSObject(CYPool &pool, JSContextRef context, JSValueRef value) { return [[self description] cy$toCYON:objective]; } +@end +/* }}} */ +/* Bridge: NSSet {{{ */ +@implementation NSSet (Cycript) + +- (NSString *) cy$toCYON:(bool)objective { + NSMutableString *json([[[NSMutableString alloc] init] autorelease]); + [json appendString:@"[NSSet setWithArray:"]; + [json appendString:CYCastNSCYON([self allObjects], true)]; + [json appendString:@"]]"]; + return json; +} + @end /* }}} */ /* Bridge: NSString {{{ */ @@ -1452,12 +1478,32 @@ static void CYObjectiveC_CallFunction(JSContextRef context, ffi_cif *cif, void ( } CYSadCatch() } 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) { - // XXX: do something epic about blocks - case sig::block_P: + case sig::block_P: { + _assert(type->data.signature.count != 0); + sig::Signature signature; + sig::Copy(*pool, signature, type->data.signature); + + sig::Element *elements(new(*pool) sig::Element[++signature.count]); + elements[0] = signature.elements[0]; + memcpy(elements + 2, signature.elements + 1, sizeof(sig::Element) * (signature.count - 2)); + signature.elements = elements; + + elements[1].name = NULL; + elements[1].type = new(*pool) sig::Type(); + elements[1].offset = _not(size_t); + + memset(elements[1].type, 0, sizeof(sig::Type)); + elements[1].type->primitive = sig::object_P; + + JSObjectRef function(CYCastJSObject(context, value)); + *reinterpret_cast(data) = CYMakeBlock(context, function, signature); + } break; + case sig::object_P: case sig::typename_P: - // XXX: this works for return values, but not for properties and fields *reinterpret_cast(data) = CYCastNSObject(pool, context, value); break; @@ -2460,7 +2506,7 @@ static JSValueRef Message_callAsFunction(JSContextRef context, JSObjectRef objec static JSObjectRef Super_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { if (count != 2) - throw CYJSError(context, "incorrect number of arguments to Super constructor"); + throw CYJSError(context, "incorrect number of arguments to objc_super constructor"); CYPool pool; id self(CYCastNSObject(&pool, context, arguments[0])); Class _class(CYCastClass(pool, context, arguments[1])); @@ -2723,6 +2769,8 @@ void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry { Object_ = objc_getClass("Object"); #ifdef __APPLE__ + __NSMallocBlock__ = objc_getClass("__NSMallocBlock__"); + // XXX: apparently, iOS now has both of these NSCFBoolean_ = objc_getClass("__NSCFBoolean"); if (NSCFBoolean_ == nil) @@ -2925,14 +2973,10 @@ void CYObjectiveC_SetupContext(JSContextRef context) { CYPoolTry { CYSetProperty(context, cycript, CYJSString("Instance"), Instance); CYSetProperty(context, cycript, CYJSString("Selector"), Selector); - CYSetProperty(context, cycript, CYJSString("Super"), Super); + CYSetProperty(context, cycript, CYJSString("objc_super"), Super); JSObjectRef box(JSObjectMakeFunctionWithCallback(context, CYJSString("box"), &Instance_box_callAsFunction)); - CYSetProperty(context, Instance, CYJSString("box"), box); - -#if defined(__APPLE__) && defined(__arm__) && 0 - CYSetProperty(context, all, CYJSString("objc_registerClassPair"), &objc_registerClassPair_, kJSPropertyAttributeDontEnum); -#endif + CYSetProperty(context, Instance, CYJSString("box"), box, kJSPropertyAttributeDontEnum); #ifdef __APPLE__ CYSetProperty(context, all, CYJSString("choose"), &choose, kJSPropertyAttributeDontEnum); @@ -2961,3 +3005,25 @@ struct CYObjectiveC { _assert(hooks_ != NULL); } } CYObjectiveC; + +extern "C" void CydgetSetupContext(JSGlobalContextRef context) { CYObjectiveTry_ { + CYSetupContext(context); +} CYObjectiveCatch } + +extern "C" void CydgetMemoryParse(const uint16_t **data, size_t *size) { try { + CYPool pool; + + CYUTF8String utf8(CYPoolUTF8String(pool, CYUTF16String(*data, *size))); + utf8 = CYPoolCode(pool, utf8); + + CYUTF16String utf16(CYPoolUTF16String(pool, CYUTF8String(utf8.data, utf8.size))); + size_t bytes(utf16.size * sizeof(uint16_t)); + uint16_t *copy(reinterpret_cast(malloc(bytes))); + memcpy(copy, utf16.data, bytes); + + *data = copy; + *size = utf16.size; +} catch (const CYException &exception) { + CYPool pool; + @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"%s", exception.PoolCString(pool)] userInfo:nil]; +} }