]> git.saurik.com Git - cycript.git/blobdiff - Execute.cpp
Forgot earlier yy modification: CYTypeArrayOf type.
[cycript.git] / Execute.cpp
index 7eb2f802b6103154748df75892b7fbe773881309..dd258265db86cd6cbbb74ae69b9bad7cd77f4f09 100644 (file)
@@ -1,5 +1,5 @@
 /* Cycript - Optimizing JavaScript Compiler/Runtime
- * Copyright (C) 2009-2010  Jay Freeman (saurik)
+ * Copyright (C) 2009-2012  Jay Freeman (saurik)
 */
 
 /* GNU Lesser General Public License, Version 3 {{{ */
@@ -131,7 +131,7 @@ size_t CYGetIndex(apr_pool_t *pool, JSContextRef context, JSStringRef value) {
 
 static JSClassRef All_;
 static JSClassRef Context_;
-static JSClassRef Functor_;
+JSClassRef Functor_;
 static JSClassRef Global_;
 static JSClassRef Pointer_;
 static JSClassRef Struct_;
@@ -257,6 +257,10 @@ JSObjectRef CYMakeStruct(JSContextRef context, void *data, sig::Type *type, ffi_
     return JSObjectMake(context, Struct_, internal);
 }
 
+static void *CYCastSymbol(const char *name) {
+    return dlsym(RTLD_DEFAULT, name);
+}
+
 JSValueRef CYCastJSValue(JSContextRef context, bool value) {
     return JSValueMakeBoolean(context, value);
 }
@@ -401,6 +405,16 @@ const char *CYPoolCCYON(apr_pool_t *pool, JSContextRef context, JSObjectRef obje
         return cyon;
     }
 
+    if (JSObjectIsFunction(context, object)) {
+        JSValueRef toString(CYGetProperty(context, object, toString_s));
+        if (CYIsCallable(context, toString)) {
+            JSValueRef arguments[1] = {CYCastJSValue(context, CYJSString(""))};
+            JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toString, object, 1, arguments));
+            _assert(value != NULL);
+            return CYPoolCString(pool, context, value);
+        }
+    }
+
     std::ostringstream str;
 
     str << '{';
@@ -483,21 +497,24 @@ JSObjectRef CYMakePointer(JSContextRef context, void *pointer, size_t length, si
     return JSObjectMake(context, Pointer_, internal);
 }
 
-static JSObjectRef CYMakeFunctor(JSContextRef context, void (*function)(), const char *type, void **cache = NULL) {
-    cy::Functor *internal;
+static JSObjectRef CYMakeFunctor(JSContextRef context, void (*function)(), const char *type) {
+    return JSObjectMake(context, Functor_, new cy::Functor(type, function));
+}
 
-    if (cache != NULL && *cache != NULL) {
+static JSObjectRef CYMakeFunctor(JSContextRef context, const char *symbol, const char *type, void **cache) {
+    cy::Functor *internal;
+    if (*cache != NULL)
         internal = reinterpret_cast<cy::Functor *>(*cache);
-        ++internal->count_;
-    } else {
-        internal = new cy::Functor(type, function);
+    else {
+        void (*function)()(reinterpret_cast<void (*)()>(CYCastSymbol(symbol)));
+        if (function == NULL)
+            return NULL;
 
-        if (cache != NULL) {
-            *cache = internal;
-            ++internal->count_;
-        }
+        internal = new cy::Functor(type, function);
+        *cache = internal;
     }
 
+    ++internal->count_;
     return JSObjectMake(context, Functor_, internal);
 }
 
@@ -675,7 +692,7 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void
     }
 }
 
-static void FunctionClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
+void CYExecuteClosure(ffi_cif *cif, void *result, void **arguments, void *arg, JSValueRef (*adapter)(JSContextRef, size_t, JSValueRef[], JSObjectRef)) {
     Closure_privateData *internal(reinterpret_cast<Closure_privateData *>(arg));
 
     JSContextRef context(internal->context_);
@@ -686,10 +703,18 @@ static void FunctionClosure_(ffi_cif *cif, void *result, void **arguments, void
     for (size_t index(0); index != count; ++index)
         values[index] = CYFromFFI(context, internal->signature_.elements[1 + index].type, internal->cif_.arg_types[index], arguments[index]);
 
-    JSValueRef value(CYCallAsFunction(context, internal->function_, NULL, count, values));
+    JSValueRef value(adapter(context, count, values, internal->function_));
     CYPoolFFI(NULL, context, internal->signature_.elements[0].type, internal->cif_.rtype, result, value);
 }
 
+static JSValueRef FunctionAdapter_(JSContextRef context, size_t count, JSValueRef values[], JSObjectRef function) {
+    return CYCallAsFunction(context, function, NULL, count, values);
+}
+
+static void FunctionClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
+    CYExecuteClosure(cif, result, arguments, arg, &FunctionAdapter_);
+}
+
 Closure_privateData *CYMakeFunctor_(JSContextRef context, JSObjectRef function, const char *type, void (*callback)(ffi_cif *, void *, void **, void *)) {
     // XXX: in case of exceptions this will leak
     // XXX: in point of fact, this may /need/ to leak :(
@@ -937,20 +962,16 @@ static JSValueRef Functor_callAsFunction(JSContextRef context, JSObjectRef objec
     return CYCallFunction(pool, context, 0, NULL, count, arguments, false, exception, &internal->signature_, &internal->cif_, internal->GetValue());
 }
 
-static JSObjectRef CYMakeType(JSContextRef context, const char *type) {
+JSObjectRef CYMakeType(JSContextRef context, const char *type) {
     Type_privateData *internal(new Type_privateData(type));
     return JSObjectMake(context, Type_privateData::Class_, internal);
 }
 
-static JSObjectRef CYMakeType(JSContextRef context, sig::Type *type) {
+JSObjectRef CYMakeType(JSContextRef context, sig::Type *type) {
     Type_privateData *internal(new Type_privateData(type));
     return JSObjectMake(context, Type_privateData::Class_, internal);
 }
 
-static void *CYCastSymbol(const char *name) {
-    return dlsym(RTLD_DEFAULT, name);
-}
-
 static JSValueRef All_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
     JSObjectRef global(CYGetGlobalObject(context));
     JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
@@ -980,9 +1001,7 @@ static JSValueRef All_getProperty(JSContextRef context, JSObjectRef object, JSSt
                     return JSEvaluateScript(CYGetJSContext(context), CYJSString(entry->value_), NULL, NULL, 0, NULL);
 
                 case '1':
-                    if (void (*symbol)() = reinterpret_cast<void (*)()>(CYCastSymbol(name.data)))
-                        return CYMakeFunctor(context, symbol, entry->value_, &entry->cache_);
-                    else return NULL;
+                    return CYMakeFunctor(context, name.data, entry->value_, &entry->cache_);
 
                 case '2':
                     if (void *symbol = CYCastSymbol(name.data)) {
@@ -1019,7 +1038,7 @@ static void All_getPropertyNames(JSContextRef context, JSObjectRef object, JSPro
 
 static JSObjectRef Pointer_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 Functor constructor");
+        throw CYJSError(context, "incorrect number of arguments to Pointer constructor");
 
     CYPool pool;
 
@@ -1040,36 +1059,71 @@ static JSObjectRef Type_new(JSContextRef context, JSObjectRef object, size_t cou
     return CYMakeType(context, type);
 } CYCatch }
 
-static JSValueRef Type_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
-    Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
+static JSValueRef Type_callAsFunction_arrayOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+    if (count != 1)
+        throw CYJSError(context, "incorrect number of arguments to Type.arrayOf");
+    Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
+
+    CYPool pool;
+    size_t index(CYGetIndex(pool, context, CYJSString(context, arguments[0])));
+    if (index == _not(size_t))
+        throw CYJSError(context, "invalid array size used with Type.arrayOf");
 
     sig::Type type;
+    type.name = NULL;
+    type.flags = 0;
 
-    if (JSStringIsEqualToUTF8CString(property, "$cyi")) {
-        type.primitive = sig::pointer_P;
-        type.data.data.size = 0;
-    } else {
-        CYPool pool;
-        size_t index(CYGetIndex(pool, context, property));
-        if (index == _not(size_t))
-            return NULL;
-        type.primitive = sig::array_P;
-        type.data.data.size = index;
-    }
+    type.primitive = sig::array_P;
+    type.data.data.type = internal->type_;
+    type.data.data.size = index;
 
+    return CYMakeType(context, &type);
+} CYCatch }
+
+static JSValueRef Type_callAsFunction_constant(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+    if (count != 0)
+        throw CYJSError(context, "incorrect number of arguments to Type.constant");
+    Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
+
+    sig::Type type(*internal->type_);
+    type.flags |= JOC_TYPE_CONST;
+    return CYMakeType(context, &type);
+} CYCatch }
+
+static JSValueRef Type_callAsFunction_pointerTo(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+    if (count != 0)
+        throw CYJSError(context, "incorrect number of arguments to Type.pointerTo");
+    Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
+
+    sig::Type type;
     type.name = NULL;
     type.flags = 0;
 
+    type.primitive = sig::pointer_P;
     type.data.data.type = internal->type_;
+    type.data.data.size = 0;
 
     return CYMakeType(context, &type);
 } CYCatch }
 
-static JSValueRef Type_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
-    Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
+static JSValueRef Type_callAsFunction_withName(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+    if (count != 1)
+        throw CYJSError(context, "incorrect number of arguments to Type.withName");
+    Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
+
+    CYPool pool;
+    const char *name(CYPoolCString(pool, context, arguments[0]));
 
+    sig::Type type(*internal->type_);
+    type.name = name;
+    return CYMakeType(context, &type);
+} CYCatch }
+
+static JSValueRef Type_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
     if (count != 1)
         throw CYJSError(context, "incorrect number of arguments to type cast function");
+    Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
+
     sig::Type *type(internal->type_);
     ffi_type *ffi(internal->GetFFI());
     // XXX: alignment?
@@ -1081,7 +1135,7 @@ static JSValueRef Type_callAsFunction(JSContextRef context, JSObjectRef object,
 
 static JSObjectRef Type_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
     if (count != 0)
-        throw CYJSError(context, "incorrect number of arguments to type cast function");
+        throw CYJSError(context, "incorrect number of arguments to Type allocator");
     Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
 
     sig::Type *type(internal->type_);
@@ -1125,7 +1179,7 @@ static JSValueRef CYValue_callAsFunction_toCYON(JSContextRef context, JSObjectRe
 static JSValueRef Pointer_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
     Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(_this)));
     if (internal->length_ != _not(size_t)) {
-        JSObjectRef Array(CYGetCachedObject(context, Array_s));
+        JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
         JSObjectRef toCYON(CYCastJSObject(context, CYGetProperty(context, Array, toCYON_s)));
         return CYCallAsFunction(context, toCYON, _this, count, arguments);
     } else {
@@ -1135,6 +1189,21 @@ static JSValueRef Pointer_callAsFunction_toCYON(JSContextRef context, JSObjectRe
     }
 } CYCatch }
 
+static JSValueRef Type_getProperty_alignment(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
+    Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
+    return CYCastJSValue(context, internal->GetFFI()->alignment);
+}
+
+static JSValueRef Type_getProperty_name(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
+    Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
+    return CYCastJSValue(context, internal->type_->name);
+}
+
+static JSValueRef Type_getProperty_size(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
+    Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
+    return CYCastJSValue(context, internal->GetFFI()->size);
+}
+
 static JSValueRef Type_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
     Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
     CYPool pool;
@@ -1146,13 +1215,9 @@ static JSValueRef Type_callAsFunction_toCYON(JSContextRef context, JSObjectRef o
     Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
     CYPool pool;
     const char *type(sig::Unparse(pool, internal->type_));
-    size_t size(strlen(type));
-    char *cyon(new(pool) char[12 + size + 1]);
-    memcpy(cyon, "new Type(\"", 10);
-    cyon[12 + size] = '\0';
-    cyon[12 + size - 2] = '"';
-    cyon[12 + size - 1] = ')';
-    memcpy(cyon + 10, type, size);
+    std::ostringstream str;
+    CYStringify(str, type, strlen(type));
+    char *cyon(apr_pstrcat(pool, "new Type(", str.str().c_str(), ")", NULL));
     return CYCastJSValue(context, CYJSString(cyon));
 } CYCatch }
 
@@ -1183,7 +1248,18 @@ namespace cy {
     JSStaticFunction const * const Functor::StaticFunctions = Functor_staticFunctions;
 }
 
-static JSStaticFunction Type_staticFunctions[4] = {
+static JSStaticValue Type_staticValues[4] = {
+    {"alignment", &Type_getProperty_alignment, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"name", &Type_getProperty_name, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"size", &Type_getProperty_size, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {NULL, NULL, NULL, 0}
+};
+
+static JSStaticFunction Type_staticFunctions[8] = {
+    {"arrayOf", &Type_callAsFunction_arrayOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"constant", &Type_callAsFunction_constant, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"pointerTo", &Type_callAsFunction_pointerTo, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"withName", &Type_callAsFunction_withName, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {"toCYON", &Type_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {"toJSON", &Type_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {"toString", &Type_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
@@ -1235,10 +1311,8 @@ const char *CYExecute(apr_pool_t *pool, CYUTF8String code) {
         return error;
     }
 
-    if (exception != NULL) { error:
-        result = CYCastJSValue(context, CYJSString(context, exception));
-        exception = NULL;
-    }
+    if (exception != NULL) error:
+        return CYPoolCString(pool, context, CYJSString(context, exception));
 
     if (JSValueIsUndefined(context, result))
         return NULL;
@@ -1313,8 +1387,8 @@ void CYInitializeDynamic() {
 
     definition = kJSClassDefinitionEmpty;
     definition.className = "Type";
+    definition.staticValues = Type_staticValues;
     definition.staticFunctions = Type_staticFunctions;
-    definition.getProperty = &Type_getProperty;
     definition.callAsFunction = &Type_callAsFunction;
     definition.callAsConstructor = &Type_callAsConstructor;
     definition.finalize = &CYFinalize;
@@ -1478,6 +1552,9 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) {
     //CYSetProperty(context, System, CYJSString("global"), global);
     CYSetProperty(context, System, CYJSString("print"), &System_print);
 
+    if (CYBridgeEntry *entry = CYBridgeHash("1dlerror", 8))
+        entry->cache_ = new cy::Functor(entry->value_, reinterpret_cast<void (*)()>(&dlerror));
+
     if (hooks_ != NULL && hooks_->SetupContext != NULL)
         (*hooks_->SetupContext)(context);