From b21525c7b2b9f64150f97e79f1f0788edbc7b3bf Mon Sep 17 00:00:00 2001 From: "Jay Freeman (saurik)" Date: Mon, 31 Aug 2009 21:37:08 +0000 Subject: [PATCH] Generalized FFI calls. --- Tweak.mm | 130 +++++++++++++++++++++++++++++++---------------- sig/ffi_type.cpp | 36 ++++++------- sig/ffi_type.hpp | 15 ++---- sig/parse.cpp | 32 +++++++----- sig/parse.hpp | 7 +-- 5 files changed, 128 insertions(+), 92 deletions(-) diff --git a/Tweak.mm b/Tweak.mm index 2be2afc..3bb663b 100644 --- a/Tweak.mm +++ b/Tweak.mm @@ -134,6 +134,14 @@ class _H { #define _pooled _H _pool([[NSAutoreleasePool alloc] init], true); +void *operator new(size_t size, apr_pool_t *pool) { + return apr_palloc(pool, size); +} + +void *operator new [](size_t size, apr_pool_t *pool) { + return apr_palloc(pool, size); +} + static JSContextRef Context_; static JSClassRef ffi_; @@ -264,7 +272,7 @@ struct Client { @end -@interface CY$JSObject : NSDictionary { +@interface CYJSObject : NSDictionary { JSObjectRef object_; JSContextRef context_; } @@ -279,7 +287,7 @@ struct Client { @end -@interface CY$JSArray : NSArray { +@interface CYJSArray : NSArray { JSObjectRef object_; JSContextRef context_; } @@ -297,15 +305,15 @@ JSContextRef JSGetContext() { void CYThrow(JSContextRef context, JSValueRef value); -id JSObjectToNSObject(JSContextRef context, JSObjectRef object) { +id CYCastNSObject(JSContextRef context, JSObjectRef object) { if (JSValueIsObjectOfClass(context, object, joc_)) return reinterpret_cast(JSObjectGetPrivate(object)); JSValueRef exception(NULL); bool array(JSValueIsInstanceOfConstructor(context, object, Array_, &exception)); CYThrow(context, exception); if (array) - return [[[CY$JSArray alloc] initWithJSObject:object inContext:context] autorelease]; - return [[[CY$JSObject alloc] initWithJSObject:object inContext:context] autorelease]; + return [[[CYJSArray alloc] initWithJSObject:object inContext:context] autorelease]; + return [[[CYJSObject alloc] initWithJSObject:object inContext:context] autorelease]; } CFStringRef CYCopyCFString(JSStringRef value) { @@ -353,7 +361,7 @@ CFTypeRef CYCopyCFType(JSContextRef context, JSValueRef value) { break; case kJSTypeObject: - return CFRetain((CFTypeRef) JSObjectToNSObject(context, (JSObjectRef) value)); + return CFRetain((CFTypeRef) CYCastNSObject(context, (JSObjectRef) value)); break; default: @@ -421,7 +429,7 @@ void CYThrow(JSContextRef context, id error, JSValueRef *exception) { *exception = CYCastJSValue(context, error); } -@implementation CY$JSObject +@implementation CYJSObject - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { if ((self = [super init]) != nil) { @@ -466,7 +474,7 @@ void CYThrow(JSContextRef context, id error, JSValueRef *exception) { @end -@implementation CY$JSArray +@implementation CYJSArray - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { if ((self = [super init]) != nil) { @@ -579,12 +587,14 @@ static JSValueRef joc_getProperty(JSContextRef context, JSObjectRef object, JSSt typedef id jocData; struct ptrData { + apr_pool_t *pool_; void *value_; + sig::Type type_; }; static void ptr_finalize(JSObjectRef object) { ptrData *data(reinterpret_cast(JSObjectGetPrivate(object))); - free(data); + apr_pool_destroy(data->pool_); } static void joc_finalize(JSObjectRef object) { @@ -615,26 +625,54 @@ struct ffiData { char *CYPoolCString(apr_pool_t *pool, JSStringRef value) { size_t size(JSStringGetMaximumUTF8CStringSize(value)); - char *string(reinterpret_cast(apr_palloc(pool, size))); + char *string(new(pool) char[size]); JSStringGetUTF8CString(value, string, size); JSStringRelease(value); return string; } +// XXX: this macro is dangerous +#define CYCastCString(context, value) ({ \ + JSValueRef exception(NULL); \ + JSStringRef string(JSValueToStringCopy(context, value, &exception)); \ + CYThrow(context, exception); \ + size_t size(JSStringGetMaximumUTF8CStringSize(string)); \ + char *utf8(reinterpret_cast(alloca(size))); \ + JSStringGetUTF8CString(string, utf8, size); \ + JSStringRelease(string); \ + utf8; \ +}) + SEL CYCastSEL(JSContextRef context, JSValueRef value) { if (JSValueIsNull(context, value)) return NULL; else if (JSValueIsObjectOfClass(context, value, sel_)) return reinterpret_cast(JSObjectGetPrivate((JSObjectRef) value)); - else { - JSValueRef exception(NULL); - JSStringRef string(JSValueToStringCopy(context, value, &exception)); - CYThrow(context, exception); - size_t size(JSStringGetMaximumUTF8CStringSize(string)); - char utf8[size]; - JSStringGetUTF8CString(string, utf8, size); - JSStringRelease(string); - return sel_registerName(utf8); + else + return sel_registerName(CYCastCString(context, value)); +} + +void *CYCastPointer(JSContextRef context, JSValueRef value) { + switch (JSValueGetType(context, value)) { + case kJSTypeNull: + return NULL; + break; + + case kJSTypeString: + return dlsym(RTLD_DEFAULT, CYCastCString(context, value)); + break; + + case kJSTypeObject: + if (JSValueIsObjectOfClass(context, value, ptr_)) { + ptrData *data(reinterpret_cast(JSObjectGetPrivate((JSObjectRef) value))); + return data->value_; + } + default: + JSValueRef exception(NULL); + double number(JSValueToNumber(context, value, &exception)); + CYThrow(context, exception); + return reinterpret_cast(static_cast(number)); + break; } } @@ -674,27 +712,16 @@ void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, void *da *reinterpret_cast(data) = CYCastSEL(context, value); break; - case sig::pointer_P: { - void *&pointer(*reinterpret_cast(data)); - if (JSValueIsNull(context, value)) - pointer = NULL; - else if (JSValueIsObjectOfClass(context, value, ptr_)) { - ptrData *data(reinterpret_cast(JSObjectGetPrivate((JSObjectRef) value))); - pointer = data->value_; - } else { - JSValueRef exception(NULL); - double number(JSValueToNumber(context, value, &exception)); - CYThrow(context, exception); - pointer = reinterpret_cast(static_cast(number)); - } - } break; + case sig::pointer_P: + *reinterpret_cast(data) = CYCastPointer(context, value); + break; case sig::string_P: { JSValueRef exception(NULL); JSStringRef string(JSValueToStringCopy(context, value, &exception)); CYThrow(context, exception); size_t size(JSStringGetMaximumUTF8CStringSize(string)); - char *utf8(reinterpret_cast(apr_palloc(pool, size))); + char *utf8(new(pool) char[size]); JSStringGetUTF8CString(string, utf8, size); JSStringRelease(string); *reinterpret_cast(data) = utf8; @@ -750,7 +777,10 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, void *data) { case sig::pointer_P: { if (void *pointer = *reinterpret_cast(data)) { - ptrData *data(reinterpret_cast(malloc(sizeof(ptrData)))); + apr_pool_t *pool; + apr_pool_create(&pool, NULL); + ptrData *data(new(pool) ptrData()); + data->pool_ = pool; data->value_ = pointer; value = JSObjectMake(context, ptr_, data); } else value = JSValueMakeNull(context); @@ -804,7 +834,7 @@ static JSValueRef CYCallFunction(JSContextRef context, size_t count, const JSVal for (unsigned index(0); index != count; ++index) { sig::Element *element(&signature->elements[index + 1]); - values[index] = apr_palloc(pool, cif->arg_types[index]->size); + values[index] = new(pool) uint8_t[cif->arg_types[index]->size]; CYPoolFFI(pool, context, element->type, values[index], arguments[index]); } @@ -853,7 +883,7 @@ static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObje sig::Parse(pool, &signature, type); ffi_cif cif; - sig::sig_ffi_cif(pool, &sig::sig_objc_ffi_type, &signature, &cif); + sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif); void (*function)() = stret(cif.rtype) ? reinterpret_cast(&objc_msgSend_stret) : reinterpret_cast(&objc_msgSend); return CYCallFunction(context, count, arguments, exception, &signature, &cif, function); @@ -869,21 +899,33 @@ static void ffi_finalize(JSObjectRef object) { apr_pool_destroy(data->pool_); } -void CYSetFunction(JSContextRef context, JSObjectRef object, const char *name, void (*function)(), const char *type) { +JSObjectRef CYMakeFunction(JSContextRef context, void (*function)(), const char *type) { apr_pool_t *pool; apr_pool_create(&pool, NULL); - ffiData *data(reinterpret_cast(apr_palloc(pool, sizeof(ffiData)))); + ffiData *data(new(pool) ffiData()); data->pool_ = pool; data->function_ = function; data->type_ = apr_pstrdup(pool, type); sig::Parse(pool, &data->signature_, type); - sig::sig_ffi_cif(pool, &sig::sig_objc_ffi_type, &data->signature_, &data->cif_); + sig::sig_ffi_cif(pool, &sig::ObjectiveC, &data->signature_, &data->cif_); - JSObjectRef value(JSObjectMake(context, ffi_, data)); - CYSetProperty(context, object, name, value); + return JSObjectMake(context, ffi_, data); +} + +JSObjectRef ffi(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + @try { + if (count != 2) + [NSException raise:NSInvalidArgumentException format:@"incorrect number of arguments to ffi constructor"]; + void (*function)() = reinterpret_cast(CYCastPointer(context, arguments[0])); + const char *type(CYCastCString(context, arguments[1])); + return CYMakeFunction(context, function, type); + } @catch (id error) { + CYThrow(context, error, exception); + return NULL; + } } JSValueRef ptr_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef *exception) { @@ -953,8 +995,10 @@ MSInitialize { _pooled JSObjectRef global(JSContextGetGlobalObject(context)); + CYSetProperty(context, global, "ffi", JSObjectMakeConstructor(context, ffi_, &ffi)); + #define CYSetFunction_(name, type) \ - CYSetFunction(context, global, #name, reinterpret_cast(&name), type) + CYSetProperty(context, global, #name, CYMakeFunction(context, reinterpret_cast(&name), type)) CYSetFunction_(class_addIvar, "B#*LC*"); CYSetFunction_(class_addMethod, "B#:^?*"); diff --git a/sig/ffi_type.cpp b/sig/ffi_type.cpp index 49e4084..00d04b2 100644 --- a/sig/ffi_type.cpp +++ b/sig/ffi_type.cpp @@ -5,7 +5,20 @@ namespace sig { -ffi_type *sig_objc_ffi_type(apr_pool_t *pool, struct Type *type) { +void sig_ffi_types( + apr_pool_t *pool, + ffi_type *(*sig_ffi_type)(apr_pool_t *, struct Type *), + struct Signature *signature, + ffi_type **types, + size_t skip = 0, + size_t offset = 0 +) { + _assert(signature->count >= skip); + for (size_t index = skip; index != signature->count; ++index) + types[index - skip + offset] = (*sig_ffi_type)(pool, signature->elements[index].type); +} + +ffi_type *ObjectiveC(apr_pool_t *pool, struct Type *type) { switch (type->primitive) { case typename_P: return &ffi_type_pointer; @@ -53,7 +66,7 @@ ffi_type *sig_objc_ffi_type(apr_pool_t *pool, struct Type *type) { aggregate->type = FFI_TYPE_STRUCT; aggregate->elements = reinterpret_cast(apr_palloc(pool, (type->data.signature.count + 1) * sizeof(ffi_type *))); - sig_ffi_types(pool, &sig_objc_ffi_type, &type->data.signature, aggregate->elements, 0, 0); + sig_ffi_types(pool, &ObjectiveC, &type->data.signature, aggregate->elements); aggregate->elements[type->data.signature.count] = NULL; return aggregate; @@ -65,7 +78,7 @@ ffi_type *sig_objc_ffi_type(apr_pool_t *pool, struct Type *type) { } } -ffi_type *sig_java_ffi_type(apr_pool_t *pool, struct Type *type) { +ffi_type *Java(apr_pool_t *pool, struct Type *type) { switch (type->primitive) { case typename_P: return &ffi_type_pointer; case union_P: return &ffi_type_pointer; @@ -100,24 +113,11 @@ ffi_type *sig_java_ffi_type(apr_pool_t *pool, struct Type *type) { } } -void sig_ffi_types( - apr_pool_t *pool, - ffi_type *(*sig_ffi_type)(apr_pool_t *, struct Type *), - struct Signature *signature, - ffi_type **ffi_types, - size_t skip, - size_t offset -) { - _assert(signature->count >= skip); - for (size_t index = skip; index != signature->count; ++index) - ffi_types[index - skip + offset] = (*sig_ffi_type)(pool, signature->elements[index].type); -} - void sig_ffi_cif( apr_pool_t *pool, ffi_type *(*sig_ffi_type)(apr_pool_t *, struct Type *), struct Signature *signature, - ffi_cif *ffi_cif, + ffi_cif *cif, size_t skip, ffi_type **types, size_t offset @@ -126,7 +126,7 @@ void sig_ffi_cif( types = reinterpret_cast(apr_palloc(pool, (signature->count - 1) * sizeof(ffi_type *))); ffi_type *type = (*sig_ffi_type)(pool, signature->elements[0].type); sig_ffi_types(pool, sig_ffi_type, signature, types, 1 + skip, offset); - ffi_status status = ffi_prep_cif(ffi_cif, FFI_DEFAULT_ABI, signature->count - 1 - skip + offset, type, types); + ffi_status status = ffi_prep_cif(cif, FFI_DEFAULT_ABI, signature->count - 1 - skip + offset, type, types); _assert(status == FFI_OK); } diff --git a/sig/ffi_type.hpp b/sig/ffi_type.hpp index c0a0bde..bc7e800 100644 --- a/sig/ffi_type.hpp +++ b/sig/ffi_type.hpp @@ -8,23 +8,14 @@ namespace sig { -ffi_type *sig_objc_ffi_type(apr_pool_t *pool, struct Type *type); -ffi_type *sig_java_ffi_type(apr_pool_t *pool, struct Type *type); - -void sig_ffi_types( - apr_pool_t *pool, - ffi_type *(*sig_ffi_type)(apr_pool_t *, struct Type *), - struct Signature *signature, - ffi_type **ffi_types, - size_t skip, - size_t offset -); +ffi_type *ObjectiveC(apr_pool_t *pool, struct Type *type); +ffi_type *Java(apr_pool_t *pool, struct Type *type); void sig_ffi_cif( apr_pool_t *pool, ffi_type *(*sig_ffi_type)(apr_pool_t *, struct Type *), struct Signature *signature, - ffi_cif *ffi_cif, + ffi_cif *cif, size_t skip = 0, ffi_type **types = NULL, size_t offset = 0 diff --git a/sig/parse.cpp b/sig/parse.cpp index cf628a8..a786039 100644 --- a/sig/parse.cpp +++ b/sig/parse.cpp @@ -14,6 +14,10 @@ namespace sig { void (*sig_aggregate)(apr_pool_t *pool, enum Primitive primitive, const char *name, struct Signature *signature, const char *types) = NULL; +void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, char eos); +struct Type *Parse_(apr_pool_t *pool, const char **name, char eos, bool named); + + /* XXX: I really screwed up this time */ void *prealloc_(apr_pool_t *pool, void *odata, size_t osize, size_t nsize) { void *ndata = apr_palloc(pool, nsize); @@ -21,7 +25,7 @@ void *prealloc_(apr_pool_t *pool, void *odata, size_t osize, size_t nsize) { return ndata; } -void sig_parse_signature(apr_pool_t *pool, struct Signature *signature, const char **name, char eos) { +void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, char eos) { _assert(*name != NULL); bool named = **name == '"'; @@ -48,7 +52,7 @@ void sig_parse_signature(apr_pool_t *pool, struct Signature *signature, const ch *name = quote + 1; } - element->type = sig_parse_type(pool, name, eos, named); + element->type = Parse_(pool, name, eos, named); if (**name < '0' || **name > '9') element->offset = _not(size_t); @@ -62,7 +66,7 @@ void sig_parse_signature(apr_pool_t *pool, struct Signature *signature, const ch } } -struct Type *sig_parse_type(apr_pool_t *pool, const char **name, char eos, bool named) { +struct Type *Parse_(apr_pool_t *pool, const char **name, char eos, bool named) { char next = *(*name)++; if (next == '?') return NULL; @@ -105,7 +109,7 @@ struct Type *sig_parse_type(apr_pool_t *pool, const char **name, char eos, bool case '[': type->primitive = array_P; type->data.data.size = strtoul(*name, (char **) name, 10); - type->data.data.type = sig_parse_type(pool, name, eos, false); + type->data.data.type = Parse_(pool, name, eos, false); if (**name != ']') { printf("']' != \"%s\"\n", *name); _assert(false); @@ -121,7 +125,7 @@ struct Type *sig_parse_type(apr_pool_t *pool, const char **name, char eos, bool } else if (**name == '"') { type->data.data.type = NULL; } else { - type->data.data.type = sig_parse_type(pool, name, eos, named); + type->data.data.type = Parse_(pool, name, eos, named); } break; @@ -163,7 +167,7 @@ struct Type *sig_parse_type(apr_pool_t *pool, const char **name, char eos, bool types = NULL; else { const char *temp = *name; - sig_parse_signature(pool, &type->data.signature, name, end); + Parse_(pool, &type->data.signature, name, end); types = (char *) apr_pstrmemdup(pool, temp, *name - temp - 1); } @@ -201,28 +205,28 @@ struct Type *sig_parse_type(apr_pool_t *pool, const char **name, char eos, bool void Parse(apr_pool_t *pool, struct Signature *signature, const char *name) { const char *temp = name; - sig_parse_signature(pool, signature, &temp, '\0'); + Parse_(pool, signature, &temp, '\0'); _assert(temp[-1] == '\0'); } -const char *sig_unparse_signature(apr_pool_t *pool, struct Signature *signature) { +const char *Unparse(apr_pool_t *pool, struct Signature *signature) { const char *value = ""; size_t offset; for (offset = 0; offset != signature->count; ++offset) { - const char *type = sig_unparse_type(pool, signature->elements[offset].type); + const char *type = Unparse(pool, signature->elements[offset].type); value = apr_pstrcat(pool, value, type, NULL); } return value; } -const char *sig_unparse_type(apr_pool_t *pool, struct Type *type) { +const char *Unparse(apr_pool_t *pool, struct Type *type) { if (type == NULL) return "?"; else switch (type->primitive) { case typename_P: return "#"; - case union_P: return apr_psprintf(pool, "(%s)", sig_unparse_signature(pool, &type->data.signature)); + case union_P: return apr_psprintf(pool, "(%s)", Unparse(pool, &type->data.signature)); case string_P: return "*"; case selector_P: return ":"; case object_P: return type->name == NULL ? "@" : apr_psprintf(pool, "@\"%s\"", type->name); @@ -234,11 +238,11 @@ const char *sig_unparse_type(apr_pool_t *pool, struct Type *type) { case ushort_P: return "S"; case array_P: { - const char *value = sig_unparse_type(pool, type->data.data.type); + const char *value = Unparse(pool, type->data.data.type); return apr_psprintf(pool, "[%lu%s]", type->data.data.size, value); } break; - case pointer_P: return apr_psprintf(pool, "^%s", type->data.data.type == NULL ? "" : sig_unparse_type(pool, type->data.data.type)); + case pointer_P: return apr_psprintf(pool, "^%s", type->data.data.type == NULL ? "" : Unparse(pool, type->data.data.type)); case bit_P: return apr_psprintf(pool, "b%zu", type->data.data.size); case char_P: return "c"; case double_P: return "d"; @@ -248,7 +252,7 @@ const char *sig_unparse_type(apr_pool_t *pool, struct Type *type) { case longlong_P: return "q"; case short_P: return "s"; case void_P: return "v"; - case struct_P: return apr_psprintf(pool, "{%s=%s}", type->name == NULL ? "?" : type->name, sig_unparse_signature(pool, &type->data.signature)); + case struct_P: return apr_psprintf(pool, "{%s=%s}", type->name == NULL ? "?" : type->name, Unparse(pool, &type->data.signature)); } _assert(false); diff --git a/sig/parse.hpp b/sig/parse.hpp index b315807..ea90454 100644 --- a/sig/parse.hpp +++ b/sig/parse.hpp @@ -9,13 +9,10 @@ namespace sig { extern void (*sig_aggregate)(apr_pool_t *pool, enum Primitive primitive, const char *name, struct Signature *signature, const char *types); -void sig_parse_signature(apr_pool_t *pool, struct Signature *signature, const char **name, char eos); -struct Type *sig_parse_type(apr_pool_t *pool, const char **name, char eos, bool named); - void Parse(apr_pool_t *pool, struct Signature *signature, const char *name); -const char *sig_unparse_signature(apr_pool_t *pool, struct Signature *signature); -const char *sig_unparse_type(apr_pool_t *pool, struct Type *type); +const char *Unparse(apr_pool_t *pool, struct Signature *signature); +const char *Unparse(apr_pool_t *pool, struct Type *type); } -- 2.45.2