X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/8aae0f85ad333a78139595a81e02ee359979a4f3..a0a889ede9c85b8d7b6155a0ce19bcee45c4c654:/ObjectiveC/Library.mm diff --git a/ObjectiveC/Library.mm b/ObjectiveC/Library.mm index 8e50804..580660e 100644 --- a/ObjectiveC/Library.mm +++ b/ObjectiveC/Library.mm @@ -44,12 +44,14 @@ #include #include "Code.hpp" +#include "Decode.hpp" #include "Error.hpp" #include "JavaScript.hpp" #include "String.hpp" #include "Execute.hpp" #include "ObjectiveC/Internal.hpp" +#include "ObjectiveC/Syntax.hpp" #define CYObjectiveTry_ { \ try @@ -841,8 +843,43 @@ NSObject *CYCopyNSObject(CYPool &pool, JSContextRef context, JSValueRef value) { /* }}} */ /* Bridge: NSBlock {{{ */ #ifdef __APPLE__ -@interface NSBlock +@interface NSBlock : NSObject - (void) invoke; +@end + +static const char *CYBlockEncoding(NSBlock *self); +static sig::Signature *CYBlockSignature(CYPool &pool, NSBlock *self); + +@implementation NSBlock (Cycript) + +- (NSString *) cy$toCYON:(bool)objective inSet:(std::set &)objects { + CYLocalPool pool; + + sig::Signature *signature(CYBlockSignature(pool, self)); + // XXX: I am checking signature->count due to Decode doing it for block_P + if (signature == NULL || signature->count == 0) + return [super cy$toCYON:objective inSet:objects]; + _oassert(objects.insert(self).second); + + sig::Block type; + sig::Copy(pool, type.signature, *signature); + + CYTypedIdentifier *typed((new(pool) CYTypeExpression(CYDecodeType(pool, &type)))->typed_); + CYTypeFunctionWith *function(typed->Function()); + _assert(function != NULL); + + _assert(function->parameters_ != NULL); + CYObjCBlock *block(new(pool) CYObjCBlock(typed, function->parameters_, NULL)); + + std::ostringstream str; + CYOptions options; + CYOutput out(*str.rdbuf(), options); + block->Output(out, CYNoFlags); + + std::string value(str.str()); + return CYCastNSString(NULL, CYUTF8String(value.c_str(), value.size())); +} + @end #endif /* }}} */ @@ -1227,12 +1264,11 @@ NSArray *CYCastNSArray(JSContextRef context, JSPropertyNameArrayRef names) { return array; } -JSValueRef CYCastJSValue(JSContextRef context, NSObject *value) { CYPoolTry { +JSValueRef CYCastJSValue(JSContextRef context, NSObject *value) { if (value == nil) return CYJSNull(context); - else - return CYMakeInstance(context, value); -} CYPoolCatch(NULL) return /*XXX*/ NULL; } + return CYMakeInstance(context, value); +} @implementation CYJSObject @@ -1456,6 +1492,12 @@ static JSObjectRef CYMakeSelector(JSContextRef context, SEL sel) { return JSObjectMake(context, Selector_, internal); } +static JSValueRef CYCastJSValue(JSContextRef context, SEL sel) { + if (sel == NULL) + return CYJSNull(context); + return CYMakeSelector(context, sel); +} + static SEL CYCastSEL(JSContextRef context, JSValueRef value) { if (JSValueIsObjectOfClass(context, value, Selector_)) { Selector_privateData *internal(reinterpret_cast(JSObjectGetPrivate((JSObjectRef) value))); @@ -1478,8 +1520,8 @@ static void CYObjectiveC_CallFunction(CYPool &pool, JSContextRef context, ffi_ci CYCallFunction(pool, context, cif, function, value, values); } CYSadCatch() } +static NSBlock *CYCastNSBlock(CYPool &pool, JSContextRef context, JSValueRef value, const sig::Signature *signature) { #ifdef __APPLE__ -static NSBlock *CYCastNSBlock(CYPool &pool, JSContextRef context, JSValueRef value, sig::Signature *signature) { if (JSValueIsNull(context, value)) return nil; JSObjectRef object(CYCastJSObject(context, value)); @@ -1505,82 +1547,71 @@ static NSBlock *CYCastNSBlock(CYPool &pool, JSContextRef context, JSValueRef val memcpy(modified.elements + 2, signature->elements + 1, sizeof(sig::Element) * (signature->count - 1)); modified.elements[1].name = NULL; - modified.elements[1].type = new(pool) sig::Type(); + modified.elements[1].type = new(pool) sig::Object(); modified.elements[1].offset = _not(size_t); - memset(modified.elements[1].type, 0, sizeof(sig::Type)); - modified.elements[1].type->primitive = sig::object_P; - return CYMakeBlock(context, object, modified); -} +#else + _assert(false); #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 +namespace sig { - 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 +void Block::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const { + // XXX: this function might not handle the idea of a null pool + *reinterpret_cast(data) = CYCastNSBlock(*pool, context, value, &signature); +} - case sig::object_P: - case sig::typename_P: - *reinterpret_cast(data) = CYCastNSObject(pool, context, value); - break; +// XXX: assigning to an indirect id * works for return values, but not for properties and fields +void Object::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const { + *reinterpret_cast(data) = CYCastNSObject(pool, context, value); +} - case sig::selector_P: - *reinterpret_cast(data) = CYCastSEL(context, value); - break; +void Meta::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const { + *reinterpret_cast(data) = CYCastNSObject(pool, context, value); +} - default: - return false; - } +void Selector::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const { + *reinterpret_cast(data) = CYCastSEL(context, value); +} - return true; -} CYSadCatch(false) } - -static JSValueRef CYObjectiveC_FromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) { CYPoolTry { - switch (type->primitive) { - // XXX: do something epic about blocks - case sig::block_P: - case sig::object_P: - 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: - if (Class value = *reinterpret_cast(data)) - return CYMakeInstance(context, value, Instance::Permanent); - else goto null; - - case sig::selector_P: - if (SEL value = *reinterpret_cast(data)) - return CYMakeSelector(context, value); - else goto null; - - null: - return CYJSNull(context); - default: - return NULL; +JSValueRef Object::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const { + NSObject *value(*reinterpret_cast(data)); + if (value == NULL) + return CYJSNull(context); + 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]; } -} CYPoolCatch(NULL) return /*XXX*/ NULL; } + + return object; +} + +JSValueRef Meta::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const { + if (Class value = *reinterpret_cast(data)) + return CYMakeInstance(context, value, Instance::Permanent); + return CYJSNull(context); +} + +JSValueRef Selector::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const { + return CYCastJSValue(context, *reinterpret_cast(data)); +} + +JSValueRef Block::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const { + return CYCastJSValue(context, *reinterpret_cast(data)); +} + +} static bool CYImplements(id object, Class _class, SEL selector, bool devoid = false) { if (objc_method *method = class_getInstanceMethod(_class, selector)) { @@ -1901,6 +1932,16 @@ static const char *CYBlockEncoding(NSBlock *self) { return descriptor3->signature; } +static sig::Signature *CYBlockSignature(CYPool &pool, NSBlock *self) { + const char *encoding(CYBlockEncoding(self)); + if (encoding == NULL) + return NULL; + // XXX: this should be stored on a FunctionInstance private value subclass + sig::Signature *signature(new(pool) sig::Signature()); + sig::Parse(pool, signature, encoding, &Structor_); + return signature; +} + static JSValueRef FunctionInstance_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { Instance *internal(reinterpret_cast(JSObjectGetPrivate(object))); id self(internal->GetValue()); @@ -1915,7 +1956,7 @@ static JSValueRef FunctionInstance_callAsFunction(JSContextRef context, JSObject sig::Parse(pool, &signature, encoding, &Structor_); ffi_cif cif; - sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif); + sig::sig_ffi_cif(pool, &signature, &cif); BlockLiteral *literal(reinterpret_cast(self)); void (*function)() = reinterpret_cast(literal->invoke); @@ -2017,7 +2058,7 @@ static JSValueRef Internal_getProperty(JSContextRef context, JSObjectRef object, #endif auto type(new(pool) Type_privateData(encoding)); - return CYFromFFI(context, type->type_, type->GetFFI(), data); + return type->type_->FromFFI(context, type->GetFFI(), data); } } @@ -2046,7 +2087,7 @@ static bool Internal_setProperty(JSContextRef context, JSObjectRef object, JSStr field = field & ~(mask << shift) | (uintptr_t(CYCastDouble(context, value)) & mask) << shift; } else { auto type(new(pool) Type_privateData(ivar_getTypeEncoding(ivar))); - CYPoolFFI(&pool, context, type->type_, type->GetFFI(), reinterpret_cast(self) + ivar_getOffset(ivar), value); + type->type_->PoolFFI(&pool, context, type->GetFFI(), reinterpret_cast(self) + ivar_getOffset(ivar), value); return true; } } @@ -2377,11 +2418,7 @@ JSValueRef CYSendMessage(CYPool &pool, JSContextRef context, id self, Class _cla sig::Element *element(&elements[index]); element->name = NULL; element->offset = _not(size_t); - - sig::Type *type(new (pool) sig::Type); - memset(type, 0, sizeof(*type)); - type->primitive = sig::object_P; - element->type = type; + element->type = new(pool) sig::Object(); } signature.elements = elements; @@ -2389,7 +2426,7 @@ JSValueRef CYSendMessage(CYPool &pool, JSContextRef context, id self, Class _cla } ffi_cif cif; - sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif); + sig::sig_ffi_cif(pool, &signature, &cif); if (imp == NULL) { #ifndef CY_NO_STRET @@ -2486,10 +2523,9 @@ static JSObjectRef Selector_new(JSContextRef context, JSObjectRef object, size_t } CYCatch(NULL) } static JSObjectRef Instance_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { - if (count > 1) + 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); + return CYMakeInstance(context, CYCastPointer(context, arguments[0])); } CYCatch(NULL) } static JSValueRef CYValue_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry { @@ -2501,30 +2537,29 @@ static JSValueRef CYValue_callAsFunction_$cya(JSContextRef context, JSObjectRef CYValue *internal(reinterpret_cast(JSObjectGetPrivate(_this))); Type_privateData *typical(internal->GetType()); + sig::Void XXX; + sig::Type *type; ffi_type *ffi; if (typical == NULL) { - type = NULL; + type = &XXX; ffi = NULL; } else { type = typical->type_; ffi = typical->ffi_; } - return CYMakePointer(context, &internal->value_, _not(size_t), type, ffi, object); + return CYMakePointer(context, &internal->value_, *type, ffi, object); } CYCatch(NULL) } static JSValueRef FunctionInstance_getProperty_type(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry { Instance *internal(reinterpret_cast(JSObjectGetPrivate(object))); - const char *encoding(CYBlockEncoding(internal->GetValue())); - if (encoding == NULL) - return CYJSNull(context); - // XXX: this should be stored on a FunctionInstance private value subclass CYPool pool; - sig::Signature signature; - sig::Parse(pool, &signature, encoding, &Structor_); - return CYMakeType(context, &signature); + sig::Signature *signature(CYBlockSignature(pool, internal->GetValue())); + if (signature == NULL) + return CYJSNull(context); + return CYMakeType(context, signature); } CYCatch(NULL) } static JSValueRef Instance_getProperty_constructor(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry { @@ -2630,11 +2665,8 @@ static JSValueRef Class_callAsFunction_pointerTo(JSContextRef context, JSObjectR if (!CYIsClass(value)) CYThrow("non-Class object cannot be used as Type"); - sig::Type type; - memset(&type, 0, sizeof(type)); - type.primitive = sig::object_P; - type.name = class_getName(value); - return CYMakeType(context, &type); + sig::Object type(class_getName(value)); + return CYMakeType(context, type); } CYCatch(NULL) return /*XXX*/ NULL; } static JSValueRef Selector_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { @@ -2734,8 +2766,8 @@ JSValueRef NSCFType$cy$toJSON$inContext$(id self, SEL sel, JSValueRef key, JSCon void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry { CYPool &pool(CYGetGlobalPool()); - Object_type = new(pool) Type_privateData(sig::object_P); - Selector_type = new(pool) Type_privateData(sig::selector_P); + Object_type = new(pool) Type_privateData(sig::Object()); + Selector_type = new(pool) Type_privateData(sig::Selector()); NSArray_ = objc_getClass("NSArray"); NSBlock_ = objc_getClass("NSBlock"); @@ -2981,9 +3013,9 @@ void CYObjectiveC_SetupContext(JSContextRef context) { CYPoolTry { JSObjectRef cache(CYGetCachedObject(context, CYJSString("cache"))); CYSetProperty(context, cache, CYJSString("YES"), JSValueMakeBoolean(context, true), kJSPropertyAttributeDontEnum); CYSetProperty(context, cache, CYJSString("NO"), JSValueMakeBoolean(context, false), kJSPropertyAttributeDontEnum); - CYSetProperty(context, cache, CYJSString("id"), CYMakeType(context, "@"), kJSPropertyAttributeDontEnum); - CYSetProperty(context, cache, CYJSString("Class"), CYMakeType(context, "#"), kJSPropertyAttributeDontEnum); - CYSetProperty(context, cache, CYJSString("SEL"), CYMakeType(context, ":"), kJSPropertyAttributeDontEnum); + CYSetProperty(context, cache, CYJSString("id"), CYMakeType(context, sig::Object()), kJSPropertyAttributeDontEnum); + CYSetProperty(context, cache, CYJSString("Class"), CYMakeType(context, sig::Meta()), kJSPropertyAttributeDontEnum); + CYSetProperty(context, cache, CYJSString("SEL"), CYMakeType(context, sig::Selector()), kJSPropertyAttributeDontEnum); } CYPoolCatch() } static void *CYObjectiveC_CastSymbol(const char *name) { @@ -3001,8 +3033,6 @@ static CYHook CYObjectiveCHook = { &CYObjectiveC_CallFunction, &CYObjectiveC_Initialize, &CYObjectiveC_SetupContext, - &CYObjectiveC_PoolFFI, - &CYObjectiveC_FromFFI, &CYObjectiveC_CastSymbol, };