/* Cycript - Optimizing JavaScript Compiler/Runtime
- * Copyright (C) 2009-2012 Jay Freeman (saurik)
+ * Copyright (C) 2009-2013 Jay Freeman (saurik)
*/
-/* GNU Lesser General Public License, Version 3 {{{ */
+/* GNU General Public License, Version 3 {{{ */
/*
- * Cycript is free software: you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by the
- * Free Software Foundation, either version 3 of the License, or (at your
- * option) any later version.
+ * Cycript is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
*
- * Cycript is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- * License for more details.
+ * Cycript is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * You should have received a copy of the GNU Lesser General Public License
+ * You should have received a copy of the GNU General Public License
* along with Cycript. If not, see <http://www.gnu.org/licenses/>.
**/
/* }}} */
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#include <JavaScriptCore/JSStringRefCF.h>
-#include <WebKit/WebScriptObject.h>
#include <objc/runtime.h>
#endif
#include <cmath>
#include <map>
+#include <set>
#include <dlfcn.h>
-#define CYObjectiveTry_(context) { \
- JSContextRef context_(context); \
+#define CYObjectiveTry_ { \
try
#define CYObjectiveTry { \
+ JSContextRef context(context_); \
try
#define CYObjectiveCatch \
catch (const CYException &error) { \
- @throw CYCastNSObject(NULL, context_, error.CastJSValue(context_)); \
+ @throw CYCastNSObject(NULL, context, error.CastJSValue(context)); \
} \
}
BLOCK_HAS_SIGNATURE = 1 << 30,
};
-JSValueRef CYSendMessage(apr_pool_t *pool, JSContextRef context, id self, Class super, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize, JSValueRef *exception);
+JSValueRef CYSendMessage(CYPool &pool, JSContextRef context, id self, Class super, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize);
/* Objective-C Pool Release {{{ */
-apr_status_t CYPoolRelease_(void *data) {
+void CYPoolRelease_(void *data) {
id object(reinterpret_cast<id>(data));
[object release];
- return APR_SUCCESS;
}
-id CYPoolRelease_(apr_pool_t *pool, id object) {
+id CYPoolRelease_(CYPool *pool, id object) {
if (object == nil)
return nil;
else if (pool == NULL)
return [object autorelease];
else {
- apr_pool_cleanup_register(pool, object, &CYPoolRelease_, &apr_pool_cleanup_null);
+ pool->atexit(CYPoolRelease_);
return object;
}
}
template <typename Type_>
-Type_ CYPoolRelease(apr_pool_t *pool, Type_ object) {
+Type_ CYPoolRelease(CYPool *pool, Type_ object) {
return (Type_) CYPoolRelease_(pool, (id) object);
}
/* }}} */
/* Objective-C Strings {{{ */
-const char *CYPoolCString(apr_pool_t *pool, JSContextRef context, NSString *value) {
- if (pool == NULL)
- return [value UTF8String];
- else {
- size_t size([value maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1);
- char *string(new(pool) char[size]);
- if (![value getCString:string maxLength:size encoding:NSUTF8StringEncoding])
- throw CYJSError(context, "[NSString getCString:maxLength:encoding:] == NO");
- return string;
- }
+const char *CYPoolCString(CYPool &pool, JSContextRef context, NSString *value) {
+ size_t size([value maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1);
+ char *string(new(pool) char[size]);
+ if (![value getCString:string maxLength:size encoding:NSUTF8StringEncoding])
+ throw CYJSError(context, "[NSString getCString:maxLength:encoding:] == NO");
+ return string;
}
JSStringRef CYCopyJSString(JSContextRef context, NSString *value) {
return CYCopyNSString(context, CYJSString(context, value));
}
-NSString *CYCastNSString(apr_pool_t *pool, const CYUTF8String &value) {
+NSString *CYCastNSString(CYPool *pool, const CYUTF8String &value) {
return CYPoolRelease(pool, CYCopyNSString(value));
}
-NSString *CYCastNSString(apr_pool_t *pool, SEL sel) {
+NSString *CYCastNSString(CYPool *pool, SEL sel) {
const char *name(sel_getName(sel));
return CYPoolRelease(pool, CYCopyNSString(CYUTF8String(name, strlen(name))));
}
-NSString *CYCastNSString(apr_pool_t *pool, JSContextRef context, JSStringRef value) {
+NSString *CYCastNSString(CYPool *pool, JSContextRef context, JSStringRef value) {
return CYPoolRelease(pool, CYCopyNSString(context, value));
}
return CYGetIndex(CYCastUTF8String(value));
}
-bool CYGetOffset(apr_pool_t *pool, JSContextRef context, NSString *value, ssize_t &index) {
+bool CYGetOffset(CYPool &pool, JSContextRef context, NSString *value, ssize_t &index) {
return CYGetOffset(CYPoolCString(pool, context, value), index);
}
static Class NSCFBoolean_;
static Class NSCFType_;
static Class NSGenericDeallocHandler_;
-static Class NSMessageBuilder_;
static Class NSZombie_;
+
+static std::set<Class> banned_;
#else
static Class NSBoolNumber_;
#endif
else if (_class == NSZombie_)
string = [NSString stringWithFormat:@"<_NSZombie_: %p>", value];
// XXX: frowny /in/ the pants
- else if (value == NSGenericDeallocHandler_ || value == NSMessageBuilder_ || value == Object_)
+ else if (banned_.find(value) != banned_.end())
string = nil;
#endif
else
name = property_getName(property);
const char *attributes(property_getAttributes(property));
- for (char *state, *token(apr_strtok(apr_pstrdup(pool_, attributes), ",", &state)); token != NULL; token = apr_strtok(NULL, ",", &state)) {
+ for (char *token(pool_.strdup(attributes)), *next; token != NULL; token = next) {
+ if ((next = strchr(token, ',')) != NULL)
+ *next++ = '\0';
switch (*token) {
case 'R': readonly = true; break;
case 'C': copy = true; break;
const char *Getter() {
if (getter_ == NULL)
- getter_ = apr_pstrdup(pool_, name);
+ getter_ = pool_.strdup(name);
return getter_;
}
};
#endif
-#ifndef __APPLE__
@interface CYWebUndefined : NSObject {
}
@end
#define WebUndefined CYWebUndefined
-#endif
/* Bridge: CYJSObject {{{ */
@interface CYJSObject : NSMutableDictionary {
}
_finline bool CYJSValueIsInstanceOfCachedConstructor(JSContextRef context, JSValueRef value, JSStringRef cache) {
- JSValueRef exception(NULL);
- JSObjectRef constructor(CYGetCachedObject(context, cache));
- bool is(JSValueIsInstanceOfConstructor(context, value, constructor, &exception));
- CYThrow(context, exception);
- return is;
+ return _jsccall(JSValueIsInstanceOfConstructor, context, value, CYGetCachedObject(context, cache));
}
NSObject *CYMakeBlock(void (*invoke)(), sig::Signature &signature) {
return reinterpret_cast<NSObject *>(literal);
}
-NSObject *CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSObjectRef object) {
+NSObject *CYCastNSObject(CYPool *pool, JSContextRef context, JSObjectRef object) {
if (CYJSValueIsNSObject(context, object)) {
Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
return internal->GetValue();
@end
#endif
-id CYNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef value, bool cast) {
+id CYNSObject(CYPool *pool, JSContextRef context, JSValueRef value, bool cast) {
id object;
bool copy;
return [object retain];
}
-NSObject *CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
+NSObject *CYCastNSObject(CYPool *pool, JSContextRef context, JSValueRef value) {
return CYNSObject(pool, context, value, true);
}
-NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
- return CYNSObject(pool, context, value, false);
+NSObject *CYCopyNSObject(CYPool &pool, JSContextRef context, JSValueRef value) {
+ return CYNSObject(&pool, context, value, false);
}
/* Bridge: NSArray {{{ */
}
- (JSValueRef) cy$getProperty:(NSString *)name inContext:(JSContextRef)context {
- CYObjectiveTry_(context) {
+ CYObjectiveTry_ {
if ([name isEqualToString:@"length"])
return CYCastJSValue(context, [self count]);
} CYObjectiveCatch
return objective ? value : [NSString stringWithFormat:@"@%@", value];
}
-- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
+- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
return CYCastJSValue(context, (bool) [self boolValue]);
} CYObjectiveCatch }
return objective ? value : [NSString stringWithFormat:@"@%@", value];
}
-- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
+- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
return [self cy$JSType] != kJSTypeBoolean ? CYCastJSValue(context, [self doubleValue]) : CYCastJSValue(context, static_cast<bool>([self boolValue]));
} CYObjectiveCatch }
return objective ? value : [NSString stringWithFormat:@"@%@", value];
}
-- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
+- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
return CYJSNull(context);
} CYObjectiveCatch }
return [self cy$valueOfInContext:context];
}
-- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
+- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
return NULL;
} CYObjectiveCatch }
return nil;
}
-- (JSValueRef) cy$getProperty:(NSString *)name inContext:(JSContextRef)context { CYObjectiveTry_(context) {
+- (JSValueRef) cy$getProperty:(NSString *)name inContext:(JSContextRef)context { CYObjectiveTry_ {
if (NSObject *value = [self cy$getProperty:name])
return CYCastJSValue(context, value);
return NULL;
}
}
-- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
+- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
return CYCastJSValue(context, CYJSString(context, self));
} CYObjectiveCatch }
//return objective ? value : [NSString stringWithFormat:@"@%@", value];
}
-- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
+- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
return CYJSUndefined(context);
} CYObjectiveCatch }
#endif
}
-Class CYCastClass(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
- id self(CYCastNSObject(pool, context, value));
+Class CYCastClass(CYPool &pool, JSContextRef context, JSValueRef value) {
+ id self(CYCastNSObject(&pool, context, value));
if (CYIsClass(self))
return (Class) self;
throw CYJSError(context, "got something that is not a Class");
size_t size(JSPropertyNameArrayGetCount(names));
NSMutableArray *array([NSMutableArray arrayWithCapacity:size]);
for (size_t index(0); index != size; ++index)
- [array addObject:CYCastNSString(pool, context, JSPropertyNameArrayGetNameAtIndex(names, index))];
+ [array addObject:CYCastNSString(&pool, context, JSPropertyNameArrayGetNameAtIndex(names, index))];
return array;
}
@implementation CYJSObject
-- (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { CYObjectiveTry {
+- (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { CYObjectiveTry_ {
if ((self = [super init]) != nil) {
object_ = object;
context_ = CYGetJSContext(context);
- (NSString *) cy$toCYON:(bool)objective { CYObjectiveTry {
CYPool pool;
- JSValueRef exception(NULL);
- const char *cyon(CYPoolCCYON(pool, context_, object_));
- CYThrow(context_, exception);
+ const char *cyon(CYPoolCCYON(pool, context, object_));
if (cyon == NULL)
return [super cy$toCYON:objective];
else
} CYObjectiveCatch }
- (NSUInteger) count { CYObjectiveTry {
- JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context_, object_));
+ JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context, object_));
size_t size(JSPropertyNameArrayGetCount(names));
JSPropertyNameArrayRelease(names);
return size;
} CYObjectiveCatch }
- (id) objectForKey:(id)key { CYObjectiveTry {
- JSValueRef value(CYGetProperty(context_, object_, CYJSString(context_, (NSObject *) key)));
- if (JSValueIsUndefined(context_, value))
+ JSValueRef value(CYGetProperty(context, object_, CYJSString(context, (NSObject *) key)));
+ if (JSValueIsUndefined(context, value))
return nil;
- return CYCastNSObject(NULL, context_, value) ?: [NSNull null];
+ return CYCastNSObject(NULL, context, value) ?: [NSNull null];
} CYObjectiveCatch }
- (NSEnumerator *) keyEnumerator { CYObjectiveTry {
- JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context_, object_));
- NSEnumerator *enumerator([CYCastNSArray(context_, names) objectEnumerator]);
+ JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context, object_));
+ NSEnumerator *enumerator([CYCastNSArray(context, names) objectEnumerator]);
JSPropertyNameArrayRelease(names);
return enumerator;
} CYObjectiveCatch }
- (void) setObject:(id)object forKey:(id)key { CYObjectiveTry {
- CYSetProperty(context_, object_, CYJSString(context_, (NSObject *) key), CYCastJSValue(context_, (NSString *) object));
+ CYSetProperty(context, object_, CYJSString(context, (NSObject *) key), CYCastJSValue(context, (NSString *) object));
} CYObjectiveCatch }
- (void) removeObjectForKey:(id)key { CYObjectiveTry {
- JSValueRef exception(NULL);
- (void) JSObjectDeleteProperty(context_, object_, CYJSString(context_, (NSObject *) key), &exception);
- CYThrow(context_, exception);
+ (void) _jsccall(JSObjectDeleteProperty, context, object_, CYJSString(context, (NSObject *) key));
} CYObjectiveCatch }
@end
@implementation CYJSArray
-- (NSString *) cy$toCYON:(bool)objective {
+- (NSString *) cy$toCYON:(bool)objective { CYObjectiveTry {
CYPool pool;
- return [NSString stringWithUTF8String:CYPoolCCYON(pool, context_, object_)];
-}
+ return [NSString stringWithUTF8String:CYPoolCCYON(pool, context, object_)];
+} CYObjectiveCatch }
-- (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { CYObjectiveTry {
+- (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { CYObjectiveTry_ {
if ((self = [super init]) != nil) {
object_ = object;
context_ = CYGetJSContext(context);
} CYObjectiveCatch }
- (NSUInteger) count { CYObjectiveTry {
- return CYArrayLength(context_, object_);
+ return CYArrayLength(context, object_);
} CYObjectiveCatch }
- (id) objectAtIndex:(NSUInteger)index { CYObjectiveTry {
size_t bounds([self count]);
if (index >= bounds)
@throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray objectAtIndex:]: index (%zu) beyond bounds (%zu)", static_cast<size_t>(index), bounds] userInfo:nil];
- JSValueRef exception(NULL);
- JSValueRef value(JSObjectGetPropertyAtIndex(context_, object_, index, &exception));
- CYThrow(context_, exception);
- return CYCastNSObject(NULL, context_, value) ?: [NSNull null];
+ JSValueRef value(_jsccall(JSObjectGetPropertyAtIndex, context, object_, index));
+ return CYCastNSObject(NULL, context, value) ?: [NSNull null];
} CYObjectiveCatch }
- (void) addObject:(id)object { CYObjectiveTry {
- CYArrayPush(context_, object_, CYCastJSValue(context_, (NSObject *) object));
+ CYArrayPush(context, object_, CYCastJSValue(context, (NSObject *) object));
} CYObjectiveCatch }
- (void) insertObject:(id)object atIndex:(NSUInteger)index { CYObjectiveTry {
size_t bounds([self count] + 1);
if (index >= bounds)
@throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray insertObject:atIndex:]: index (%zu) beyond bounds (%zu)", static_cast<size_t>(index), bounds] userInfo:nil];
- JSValueRef exception(NULL);
JSValueRef arguments[3];
- arguments[0] = CYCastJSValue(context_, index);
- arguments[1] = CYCastJSValue(context_, 0);
- arguments[2] = CYCastJSValue(context_, (NSObject *) object);
- JSObjectRef Array(CYGetCachedObject(context_, CYJSString("Array_prototype")));
- JSObjectCallAsFunction(context_, CYCastJSObject(context_, CYGetProperty(context_, Array, splice_s)), object_, 3, arguments, &exception);
- CYThrow(context_, exception);
+ arguments[0] = CYCastJSValue(context, index);
+ arguments[1] = CYCastJSValue(context, 0);
+ arguments[2] = CYCastJSValue(context, (NSObject *) object);
+ JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
+ _jsccall(JSObjectCallAsFunction, context, CYCastJSObject(context, CYGetProperty(context, Array, splice_s)), object_, 3, arguments);
} CYObjectiveCatch }
- (void) removeLastObject { CYObjectiveTry {
- JSValueRef exception(NULL);
- JSObjectRef Array(CYGetCachedObject(context_, CYJSString("Array_prototype")));
- JSObjectCallAsFunction(context_, CYCastJSObject(context_, CYGetProperty(context_, Array, pop_s)), object_, 0, NULL, &exception);
- CYThrow(context_, exception);
+ JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
+ _jsccall(JSObjectCallAsFunction, context, CYCastJSObject(context, CYGetProperty(context, Array, pop_s)), object_, 0, NULL);
} CYObjectiveCatch }
- (void) removeObjectAtIndex:(NSUInteger)index { CYObjectiveTry {
size_t bounds([self count]);
if (index >= bounds)
@throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray removeObjectAtIndex:]: index (%zu) beyond bounds (%zu)", static_cast<size_t>(index), bounds] userInfo:nil];
- JSValueRef exception(NULL);
JSValueRef arguments[2];
- arguments[0] = CYCastJSValue(context_, index);
- arguments[1] = CYCastJSValue(context_, 1);
- JSObjectRef Array(CYGetCachedObject(context_, CYJSString("Array_prototype")));
- JSObjectCallAsFunction(context_, CYCastJSObject(context_, CYGetProperty(context_, Array, splice_s)), object_, 2, arguments, &exception);
- CYThrow(context_, exception);
+ arguments[0] = CYCastJSValue(context, index);
+ arguments[1] = CYCastJSValue(context, 1);
+ JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
+ _jsccall(JSObjectCallAsFunction, context, CYCastJSObject(context, CYGetProperty(context, Array, splice_s)), object_, 2, arguments);
} CYObjectiveCatch }
- (void) replaceObjectAtIndex:(NSUInteger)index withObject:(id)object { CYObjectiveTry {
size_t bounds([self count]);
if (index >= bounds)
@throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray replaceObjectAtIndex:withObject:]: index (%zu) beyond bounds (%zu)", static_cast<size_t>(index), bounds] userInfo:nil];
- CYSetProperty(context_, object_, index, CYCastJSValue(context_, (NSObject *) object));
+ CYSetProperty(context, object_, index, CYCastJSValue(context, (NSObject *) object));
} CYObjectiveCatch }
@end
@implementation CYInternal
-- (void) dealloc {
+- (void) dealloc { CYObjectiveTry {
JSValueUnprotect(context_, object_);
JSGlobalContextRelease(context_);
[super dealloc];
-}
+} CYObjectiveCatch }
-- (id) initInContext:(JSContextRef)context {
+- (id) initInContext:(JSContextRef)context { CYObjectiveTry_ {
if ((self = [super init]) != nil) {
context_ = CYGetJSContext(context);
JSGlobalContextRetain(context_);
} return self;
-}
+} CYObjectiveCatch }
- (bool) hasProperty:(JSStringRef)name inContext:(JSContextRef)context {
if (object_ == NULL)
ffi_call(cif, function, value, values);
} CYSadCatch() }
-static bool CYObjectiveC_PoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, JSValueRef value) { CYSadTry {
+static bool CYObjectiveC_PoolFFI(CYPool *pool, JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, JSValueRef value) { CYSadTry {
switch (type->primitive) {
// XXX: do something epic about blocks
case sig::block_P:
case sig::object_P:
case sig::typename_P:
+ // XXX: this works for return values, but not for properties and fields
*reinterpret_cast<id *>(data) = CYCastNSObject(pool, context, value);
break;
return false;
}
-static const char *CYPoolTypeEncoding(apr_pool_t *pool, JSContextRef context, SEL sel, objc_method *method) {
+static const char *CYPoolTypeEncoding(CYPool &pool, JSContextRef context, SEL sel, objc_method *method) {
if (method != NULL)
return method_getTypeEncoding(method);
return false;
}
-static JSValueRef Messages_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
+static JSValueRef Messages_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
Messages *internal(reinterpret_cast<Messages *>(JSObjectGetPrivate(object)));
Class _class(internal->GetValue());
return CYMakeMessage(context, sel, method_getImplementation(method), method_getTypeEncoding(method));
return NULL;
-}
+} CYCatch(NULL) }
-static bool Messages_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) {
+static bool Messages_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
Messages *internal(reinterpret_cast<Messages *>(JSObjectGetPrivate(object)));
Class _class(internal->GetValue());
}
return true;
-}
+} CYCatch(false) }
#if 0 && OBJC_API_VERSION < 2
-static bool Messages_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
+static bool Messages_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
Messages *internal(reinterpret_cast<Messages *>(JSObjectGetPrivate(object)));
Class _class(internal->GetValue());
}
return false;
-}
+} CYCatch(false) }
#endif
static void Messages_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
return true;
CYPool pool;
- NSString *name(CYCastNSString(pool, context, property));
+ NSString *name(CYCastNSString(&pool, context, property));
if (CYInternal *internal = [CYInternal get:self])
if ([internal hasProperty:property inContext:context])
return Internal::Make(context, self, object);
CYPool pool;
- NSString *name(CYCastNSString(pool, context, property));
+ NSString *name(CYCastNSString(&pool, context, property));
if (CYInternal *internal = [CYInternal get:self])
if (JSValueRef value = [internal getProperty:property inContext:context])
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, exception);
+ return CYSendMessage(pool, context, self, NULL, sel, 0, NULL, false);
}
#endif
if (CYHasImplicitProperties(_class))
if (SEL sel = sel_getUid(string))
if (CYImplements(self, _class, sel, true))
- return CYSendMessage(pool, context, self, NULL, sel, 0, NULL, false, exception);
+ return CYSendMessage(pool, context, self, NULL, sel, 0, NULL, false);
return NULL;
} CYCatch(NULL) }
CYPool pool;
- NSString *name(CYCastNSString(pool, context, property));
- NSObject *data(CYCastNSObject(pool, context, value));
+ NSString *name(CYCastNSString(&pool, context, property));
+ NSObject *data(CYCastNSObject(&pool, context, value));
CYPoolTry {
if ([self cy$setProperty:name to:data])
if (const char *setter = attributes.Setter()) {
SEL sel(sel_registerName(setter));
JSValueRef arguments[1] = {value};
- CYSendMessage(pool, context, self, NULL, sel, 1, arguments, false, exception);
+ CYSendMessage(pool, context, self, NULL, sel, 1, arguments, false);
return true;
}
}
if (SEL sel = sel_getUid(set))
if (CYImplements(self, _class, sel)) {
JSValueRef arguments[1] = {value};
- CYSendMessage(pool, context, self, NULL, sel, 1, arguments, false, exception);
+ CYSendMessage(pool, context, self, NULL, sel, 1, arguments, false);
return true;
}
sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
void (*function)() = reinterpret_cast<void (*)()>(literal->invoke);
- return CYCallFunction(pool, context, 1, setup, count, arguments, false, exception, &signature, &cif, function);
+ return CYCallFunction(pool, context, 1, setup, count, arguments, false, &signature, &cif, function);
}
}
if (count == 0)
throw CYJSError(context, "incorrect number of arguments to Instance");
CYPool pool;
- id value(CYCastNSObject(pool, context, arguments[0]));
+ id value(CYCastNSObject(&pool, context, arguments[0]));
if (value == nil)
value = [NSNull null];
return CYCastJSValue(context, [value cy$box]);
return false;
}
+static void CYBitField(unsigned &length, unsigned &shift, id self, Ivar ivar, const char *encoding, unsigned offset) {
+ length = CYCastDouble(encoding + 1);
+ shift = 0;
+
+ unsigned int size;
+ objc_ivar **ivars(class_copyIvarList(object_getClass(self), &size));
+ for (size_t i(0); i != size; ++i)
+ if (ivars[i] == ivar)
+ break;
+ else if (ivar_getOffset(ivars[i]) == offset) {
+ const char *encoding(ivar_getTypeEncoding(ivars[i]));
+ _assert(encoding[0] == 'b');
+ shift += CYCastDouble(encoding + 1);
+ }
+ free(ivars);
+}
+
static JSValueRef Internal_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
Internal *internal(reinterpret_cast<Internal *>(JSObjectGetPrivate(object)));
CYPool pool;
id self(internal->GetValue());
const char *name(CYPoolCString(pool, context, property));
+#ifdef __arm64__
+ if (strcmp(name, "isa") == 0)
+ return CYCastJSValue(context, object_getClass(self));
+#endif
+
if (objc_ivar *ivar = object_getInstanceVariable(self, name, NULL)) {
- Type_privateData type(pool, ivar_getTypeEncoding(ivar));
- // XXX: if this fails and throws an exception the person we are throwing it to gets the wrong exception
- return CYFromFFI(context, type.type_, type.GetFFI(), reinterpret_cast<uint8_t *>(self) + ivar_getOffset(ivar));
+ ptrdiff_t offset(ivar_getOffset(ivar));
+ void *data(reinterpret_cast<uint8_t *>(self) + offset);
+
+ const char *encoding(ivar_getTypeEncoding(ivar));
+ if (encoding[0] == 'b') {
+ unsigned length, shift;
+ CYBitField(length, shift, self, ivar, encoding, offset);
+ _assert(shift + length <= sizeof(uintptr_t) * 8);
+ uintptr_t &field(*reinterpret_cast<uintptr_t *>(data));
+ uintptr_t mask((1 << length) - 1);
+ return CYCastJSValue(context, (field >> shift) & mask);
+ } else {
+ Type_privateData type(pool, ivar_getTypeEncoding(ivar));
+ return CYFromFFI(context, type.type_, type.GetFFI(), data);
+ }
}
return NULL;
const char *name(CYPoolCString(pool, context, property));
if (objc_ivar *ivar = object_getInstanceVariable(self, name, NULL)) {
- Type_privateData type(pool, ivar_getTypeEncoding(ivar));
- CYPoolFFI(pool, context, type.type_, type.GetFFI(), reinterpret_cast<uint8_t *>(self) + ivar_getOffset(ivar), value);
- return true;
+ ptrdiff_t offset(ivar_getOffset(ivar));
+ void *data(reinterpret_cast<uint8_t *>(self) + offset);
+
+ const char *encoding(ivar_getTypeEncoding(ivar));
+ if (encoding[0] == 'b') {
+ unsigned length, shift;
+ CYBitField(length, shift, self, ivar, encoding, offset);
+ _assert(shift + length <= sizeof(uintptr_t) * 8);
+ uintptr_t &field(*reinterpret_cast<uintptr_t *>(data));
+ uintptr_t mask((1 << length) - 1);
+ field = field & ~(mask << shift) | (uintptr_t(CYCastDouble(context, value)) & mask) << shift;
+ } else {
+ Type_privateData type(pool, ivar_getTypeEncoding(ivar));
+ CYPoolFFI(&pool, context, type.type_, type.GetFFI(), reinterpret_cast<uint8_t *>(self) + ivar_getOffset(ivar), value);
+ return true;
+ }
}
return false;
Internal_getPropertyNames_(_class, names);
}
-static JSValueRef Internal_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+static JSValueRef Internal_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
Internal *internal(reinterpret_cast<Internal *>(JSObjectGetPrivate(object)));
return internal->GetOwner();
-}
+} CYCatch(NULL) }
static JSValueRef ObjectiveC_Classes_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
CYPool pool;
- NSString *name(CYCastNSString(pool, context, property));
+ NSString *name(CYCastNSString(&pool, context, property));
if (Class _class = NSClassFromString(name))
return CYMakeInstance(context, _class, true);
return NULL;
#define OBJC_MAX_STRUCT_BY_VALUE 1
static int struct_forward_array[] = {
0, 0 };
+#elif defined(__arm64__)
+#define CY_NO_STRET
#else
#error missing objc-runtime-info
#endif
+#ifndef CY_NO_STRET
static bool stret(ffi_type *ffi_type) {
return ffi_type->type == FFI_TYPE_STRUCT && (
ffi_type->size > OBJC_MAX_STRUCT_BY_VALUE ||
);
}
#endif
+#endif
-JSValueRef CYSendMessage(apr_pool_t *pool, JSContextRef context, id self, Class _class, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize, JSValueRef *exception) { CYTry {
+JSValueRef CYSendMessage(CYPool &pool, JSContextRef context, id self, Class _class, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize) {
const char *type;
if (_class == NULL)
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};
}
void (*function)() = reinterpret_cast<void (*)()>(imp);
- return CYCallFunction(pool, context, 2, setup, count, arguments, initialize, exception, &signature, &cif, function);
-} CYCatch(NULL) }
+ return CYCallFunction(pool, context, 2, setup, count, arguments, initialize, &signature, &cif, function);
+}
static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
if (count < 2)
if (uninitialized)
internal->value_ = nil;
} else {
- self = CYCastNSObject(pool, context, arguments[0]);
+ self = CYCastNSObject(&pool, context, arguments[0]);
_class = nil;
uninitialized = false;
}
_cmd = CYCastSEL(context, arguments[1]);
- return CYSendMessage(pool, context, self, _class, _cmd, count - 2, arguments + 2, uninitialized, exception);
+ return CYSendMessage(pool, context, self, _class, _cmd, count - 2, arguments + 2, uninitialized);
} CYCatch(NULL) }
-static JSValueRef Selector_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+static JSValueRef Selector_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
JSValueRef setup[count + 2];
setup[0] = _this;
setup[1] = object;
memcpy(setup + 2, arguments, sizeof(JSValueRef) * count);
return $objc_msgSend(context, NULL, NULL, count + 2, setup, exception);
-}
+} CYCatch(NULL) }
-static JSValueRef Message_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+static JSValueRef Message_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
CYPool pool;
Message_privateData *internal(reinterpret_cast<Message_privateData *>(JSObjectGetPrivate(object)));
// XXX: handle Instance::Uninitialized?
- id self(CYCastNSObject(pool, context, _this));
+ id self(CYCastNSObject(&pool, context, _this));
void *setup[2];
setup[0] = &self;
setup[1] = &internal->sel_;
- return CYCallFunction(pool, context, 2, setup, count, arguments, false, exception, &internal->signature_, &internal->cif_, internal->GetValue());
-}
+ return CYCallFunction(pool, context, 2, setup, count, arguments, false, &internal->signature_, &internal->cif_, internal->GetValue());
+} CYCatch(NULL) }
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");
CYPool pool;
- id self(CYCastNSObject(pool, context, arguments[0]));
+ id self(CYCastNSObject(&pool, context, arguments[0]));
Class _class(CYCastClass(pool, context, arguments[1]));
return cy::Super::Make(context, self, _class);
} CYCatch(NULL) }
return CYMakeInstance(context, self, false);
} CYCatch(NULL) }
-static JSValueRef CYValue_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
+static JSValueRef CYValue_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(object)));
return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->value_));
-}
+} CYCatch(NULL) }
-static JSValueRef CYValue_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+static JSValueRef CYValue_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this)));
Type_privateData *typical(internal->GetType());
}
return CYMakePointer(context, &internal->value_, _not(size_t), type, ffi, object);
-}
+} CYCatch(NULL) }
-static JSValueRef Instance_getProperty_constructor(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
+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()));
-}
+} CYCatch(NULL) }
static JSValueRef Instance_getProperty_prototype(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
return CYGetClassPrototype(context, self);
} CYCatch(NULL) }
-static JSValueRef Instance_getProperty_messages(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
+static JSValueRef Instance_getProperty_messages(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
id self(internal->GetValue());
if (!CYIsClass(self))
return CYJSUndefined(context);
return Messages::Make(context, (Class) self);
-}
+} CYCatch(NULL) }
static JSValueRef Instance_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
if (!CYJSValueIsNSObject(context, _this))
return CYCastJSValue(context, sel_getName(internal->GetValue()));
} CYCatch(NULL) }
-static JSValueRef Selector_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+static JSValueRef Selector_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
return Selector_callAsFunction_toString(context, object, _this, count, arguments, exception);
-}
+} CYCatch(NULL) }
static JSValueRef Selector_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate(_this)));
};
#ifdef __APPLE__
-JSValueRef NSCFType$cy$toJSON$inContext$(id self, SEL sel, JSValueRef key, JSContextRef context) { CYObjectiveTry_(context) {
+JSValueRef NSCFType$cy$toJSON$inContext$(id self, SEL sel, JSValueRef key, JSContextRef context) { CYObjectiveTry_ {
return CYCastJSValue(context, [(NSString *) CFCopyDescription((CFTypeRef) self) autorelease]);
} CYObjectiveCatch }
#endif
$objc_getAssociatedObject = reinterpret_cast<id (*)(id, void *)>(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject"));
$objc_removeAssociatedObjects = reinterpret_cast<void (*)(id)>(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects"));
- apr_pool_t *pool(CYGetGlobalPool());
+ CYPool &pool(CYGetGlobalPool());
Object_type = new(pool) Type_privateData("@");
Selector_type = new(pool) Type_privateData(":");
+ NSArray_ = objc_getClass("NSArray");
+ NSBlock_ = objc_getClass("NSBlock");
+ NSDictionary_ = objc_getClass("NSDictionary");
+ NSString_ = objc_getClass("NSString");
+ Object_ = objc_getClass("Object");
+
#ifdef __APPLE__
// XXX: apparently, iOS now has both of these
NSCFBoolean_ = objc_getClass("__NSCFBoolean");
NSCFBoolean_ = objc_getClass("NSCFBoolean");
NSCFType_ = objc_getClass("NSCFType");
- NSGenericDeallocHandler_ = objc_getClass("__NSGenericDeallocHandler");
- NSMessageBuilder_ = objc_getClass("NSMessageBuilder");
+
NSZombie_ = objc_getClass("_NSZombie_");
+
+ banned_.insert(Object_);
+ banned_.insert(objc_getClass("__NSAtom"));
+ banned_.insert(objc_getClass("__NSGenericDeallocHandler"));
+ banned_.insert(objc_getClass("NSMessageBuilder"));
+ banned_.insert(objc_getClass("__NSMessageBuilder"));
#else
NSBoolNumber_ = objc_getClass("NSBoolNumber");
#endif
- NSArray_ = objc_getClass("NSArray");
- NSBlock_ = objc_getClass("NSBlock");
- NSDictionary_ = objc_getClass("NSDictionary");
- NSString_ = objc_getClass("NSString");
- Object_ = objc_getClass("Object");
-
JSClassDefinition definition;
definition = kJSClassDefinitionEmpty;
ObjectiveC_Protocols_ = JSClassCreate(&definition);
#ifdef __APPLE__
+// XXX: this is horrible; there has to be a better way to do this
+#ifdef __LP64__
+ class_addMethod(NSCFType_, @selector(cy$toJSON:inContext:), reinterpret_cast<IMP>(&NSCFType$cy$toJSON$inContext$), "^{OpaqueJSValue=}32@0:8@16^{OpaqueJSContext=}24");
+#else
class_addMethod(NSCFType_, @selector(cy$toJSON:inContext:), reinterpret_cast<IMP>(&NSCFType$cy$toJSON$inContext$), "^{OpaqueJSValue=}16@0:4@8^{OpaqueJSContext=}12");
#endif
+#endif
} CYPoolCatch() }
void CYObjectiveC_SetupContext(JSContextRef context) { CYPoolTry {