X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/79492f212da2fcaa4ce44d00fc08530e1630d05b..1d5e845a26a006ed88985816d86a5769b6a713b0:/Execute.cpp diff --git a/Execute.cpp b/Execute.cpp index f7ee724..89a796a 100644 --- a/Execute.cpp +++ b/Execute.cpp @@ -1,5 +1,5 @@ /* Cycript - Optimizing JavaScript Compiler/Runtime - * Copyright (C) 2009-2014 Jay Freeman (saurik) + * Copyright (C) 2009-2015 Jay Freeman (saurik) */ /* GNU Affero General Public License, Version 3 {{{ */ @@ -86,7 +86,7 @@ void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, J void CYSetPrototype(JSContextRef context, JSObjectRef object, JSValueRef value) { JSObjectSetPrototype(context, object, value); - _assert(CYIsEqual(context, JSObjectGetPrototype(context, object), value)); + _assert(CYIsStrictEqual(context, JSObjectGetPrototype(context, object), value)); } /* }}} */ /* JavaScript Strings {{{ */ @@ -154,6 +154,7 @@ JSStringRef toCYON_s; JSStringRef toJSON_s; JSStringRef toPointer_s; JSStringRef toString_s; +JSStringRef weak_s; static JSStringRef Result_; @@ -241,9 +242,6 @@ struct Struct_privateData : } }; -typedef std::map TypeMap; -static TypeMap Types_; - JSObjectRef CYMakeStruct(JSContextRef context, void *data, sig::Type *type, ffi_type *ffi, JSObjectRef owner) { Struct_privateData *internal(new Struct_privateData(context, owner)); CYPool &pool(*internal->pool_); @@ -263,6 +261,10 @@ JSObjectRef CYMakeStruct(JSContextRef context, void *data, sig::Type *type, ffi_ } static void *CYCastSymbol(const char *name) { + for (CYHook *hook : GetHooks()) + if (hook->CastSymbol != NULL) + if (void *value = (*hook->CastSymbol)(name)) + return value; return dlsym(RTLD_DEFAULT, name); } @@ -326,6 +328,10 @@ bool CYIsEqual(JSContextRef context, JSValueRef lhs, JSValueRef rhs) { return _jsccall(JSValueIsEqual, context, lhs, rhs); } +bool CYIsStrictEqual(JSContextRef context, JSValueRef lhs, JSValueRef rhs) { + return JSValueIsStrictEqual(context, lhs, rhs); +} + size_t CYArrayLength(JSContextRef context, JSObjectRef array) { return CYCastDouble(context, CYGetProperty(context, array, length_s)); } @@ -352,17 +358,9 @@ static JSValueRef System_print(JSContextRef context, JSObjectRef object, JSObjec return CYJSUndefined(context); } CYCatch(NULL) } -static size_t Nonce_(0); - -static JSValueRef $cyq(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { - CYPool pool; - const char *name(pool.strcat(CYPoolCString(pool, context, arguments[0]), pool.itoa(Nonce_++), NULL)); - return CYCastJSValue(context, name); -} CYCatch(NULL) } - static void (*JSSynchronousGarbageCollectForDebugging$)(JSContextRef); -void CYGarbageCollect(JSContextRef context) { +_visible void CYGarbageCollect(JSContextRef context) { (JSSynchronousGarbageCollectForDebugging$ ?: &JSGarbageCollect)(context); } @@ -419,7 +417,7 @@ const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSObjectRef object, JSValueRef toCYON(CYGetProperty(context, object, toCYON_s)); if (CYIsCallable(context, toCYON)) { // XXX: this needs to be abstracted behind some kind of function - JSValueRef arguments[1] = {CYCastJSValue(context, static_cast(reinterpret_cast(&objects)))}; + JSValueRef arguments[1] = {CYCastJSValue(context, reinterpret_cast(&objects))}; JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toCYON, object, 1, arguments)); _assert(value != NULL); return CYPoolCString(pool, context, value); @@ -572,7 +570,9 @@ static bool CYGetOffset(CYPool &pool, JSContextRef context, JSStringRef value, s } void *CYCastPointer_(JSContextRef context, JSValueRef value) { - switch (JSValueGetType(context, value)) { + if (value == NULL) + return NULL; + else switch (JSValueGetType(context, value)) { case kJSTypeNull: return NULL; case kJSTypeObject: { @@ -744,7 +744,7 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void } } -void CYExecuteClosure(ffi_cif *cif, void *result, void **arguments, void *arg, JSValueRef (*adapter)(JSContextRef, size_t, JSValueRef[], JSObjectRef)) { +void CYExecuteClosure(ffi_cif *cif, void *result, void **arguments, void *arg) { Closure_privateData *internal(reinterpret_cast(arg)); JSContextRef context(internal->context_); @@ -755,7 +755,7 @@ void CYExecuteClosure(ffi_cif *cif, void *result, void **arguments, void *arg, J 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(adapter(context, count, values, internal->function_)); + JSValueRef value(internal->adapter_(context, count, values, internal->function_)); CYPoolFFI(NULL, context, internal->signature_.elements[0].type, internal->cif_.rtype, result, value); } @@ -763,20 +763,16 @@ static JSValueRef FunctionAdapter_(JSContextRef context, size_t count, JSValueRe 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 sig::Signature &signature, void (*callback)(ffi_cif *, void *, void **, void *)) { +Closure_privateData *CYMakeFunctor_(JSContextRef context, JSObjectRef function, const sig::Signature &signature, JSValueRef (*adapter)(JSContextRef, size_t, JSValueRef[], JSObjectRef)) { // XXX: in case of exceptions this will leak // XXX: in point of fact, this may /need/ to leak :( - Closure_privateData *internal(new Closure_privateData(context, function, signature)); + Closure_privateData *internal(new Closure_privateData(context, function, adapter, signature)); #if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__)) void *executable; ffi_closure *writable(reinterpret_cast(ffi_closure_alloc(sizeof(ffi_closure), &executable))); - ffi_status status(ffi_prep_closure_loc(writable, &internal->cif_, callback, internal, executable)); + ffi_status status(ffi_prep_closure_loc(writable, &internal->cif_, &CYExecuteClosure, internal, executable)); _assert(status == FFI_OK); internal->value_ = executable; @@ -787,7 +783,7 @@ Closure_privateData *CYMakeFunctor_(JSContextRef context, JSObjectRef function, -1, 0 ))); - ffi_status status(ffi_prep_closure(closure, &internal->cif_, callback, internal)); + ffi_status status(ffi_prep_closure(closure, &internal->cif_, &CYExecuteClosure, internal)); _assert(status == FFI_OK); _syscall(mprotect(closure, sizeof(*closure), PROT_READ | PROT_EXEC)); @@ -799,15 +795,19 @@ Closure_privateData *CYMakeFunctor_(JSContextRef context, JSObjectRef function, } static JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const sig::Signature &signature) { - Closure_privateData *internal(CYMakeFunctor_(context, function, signature, &FunctionClosure_)); + Closure_privateData *internal(CYMakeFunctor_(context, function, signature, &FunctionAdapter_)); JSObjectRef object(JSObjectMake(context, Functor_, internal)); // XXX: see above notes about needing to leak JSValueProtect(CYGetJSContext(context), object); return object; } +JSValueRef CYGetCachedValue(JSContextRef context, JSStringRef name) { + return CYGetProperty(context, CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s)), name); +} + JSObjectRef CYGetCachedObject(JSContextRef context, JSStringRef name) { - return CYCastJSObject(context, CYGetProperty(context, CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s)), name)); + return CYCastJSObject(context, CYGetCachedValue(context, name)); } static JSObjectRef CYMakeFunctor(JSContextRef context, JSValueRef value, const sig::Signature &signature) { @@ -982,6 +982,10 @@ static void Struct_getPropertyNames(JSContextRef context, JSObjectRef object, JS } } +void CYCallFunction(CYPool &pool, JSContextRef context, ffi_cif *cif, void (*function)(), void *value, void **values) { + ffi_call(cif, function, value, values); +} + JSValueRef CYCallFunction(CYPool &pool, JSContextRef context, size_t setups, void *setup[], size_t count, const JSValueRef arguments[], bool initialize, sig::Signature *signature, ffi_cif *cif, void (*function)()) { if (setups + count != signature->count - 1) throw CYJSError(context, "incorrect number of arguments to ffi function"); @@ -1000,15 +1004,13 @@ JSValueRef CYCallFunction(CYPool &pool, JSContextRef context, size_t setups, voi uint8_t value[cif->rtype->size]; + void (*call)(CYPool &, JSContextRef, ffi_cif *, void (*)(), void *, void **) = &CYCallFunction; + // XXX: this only supports one hook, but it is a bad idea anyway for (CYHook *hook : GetHooks()) - if (hook->CallFunction != NULL) { - // XXX: this only supports one hook, but it is a bad idea anyway - (*hook->CallFunction)(context, cif, function, value, values); - goto from; - } - ffi_call(cif, function, value, values); + if (hook->CallFunction != NULL) + call = hook->CallFunction; - from: + call(pool, context, cif, function, value, values); return CYFromFFI(context, signature->elements[0].type, cif->rtype, value, initialize); } @@ -1454,7 +1456,7 @@ static JSValueRef Type_callAsFunction_toString(JSContextRef context, JSObjectRef static JSValueRef Type_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { Type_privateData *internal(reinterpret_cast(JSObjectGetPrivate(_this))); CYLocalPool pool; - std::ostringstream out; + std::stringbuf out; CYOptions options; CYOutput output(out, options); (new(pool) CYEncodedType(Decode(pool, internal->type_)))->Output(output, CYNoFlags); @@ -1528,7 +1530,7 @@ static JSStaticFunction Type_staticFunctions[14] = { static JSObjectRef (*JSObjectMakeArray$)(JSContextRef, size_t, const JSValueRef[], JSValueRef *); -void CYSetArgs(int argc, const char *argv[]) { +_visible void CYSetArgs(int argc, const char *argv[]) { JSContextRef context(CYGetJSContext()); JSValueRef args[argc]; for (int i(0); i != argc; ++i) @@ -1580,30 +1582,32 @@ class ExecutionHandle { } }; -const char *CYExecute(JSContextRef context, CYPool &pool, CYUTF8String code) { +static volatile bool cancel_; + +static bool CYShouldTerminate(JSContextRef context, void *arg) { + return cancel_; +} + +_visible const char *CYExecute(JSContextRef context, CYPool &pool, CYUTF8String code) { JSValueRef exception(NULL); + if (false) error: + return CYPoolCString(pool, context, CYJSString(context, exception)); ExecutionHandle handle(context); - JSValueRef result; try { - result = JSEvaluateScript(context, CYJSString(code), NULL, NULL, 0, &exception); - } catch (const char *error) { - return error; - } + cancel_ = false; + if (&JSContextGroupSetExecutionTimeLimit != NULL) + JSContextGroupSetExecutionTimeLimit(JSContextGetGroup(context), 0.5, &CYShouldTerminate, NULL); - if (exception != NULL) error: - return CYPoolCString(pool, context, CYJSString(context, exception)); + JSValueRef result(JSEvaluateScript(context, CYJSString(code), NULL, NULL, 0, &exception)); + if (exception != NULL) + goto error; if (JSValueIsUndefined(context, result)) return NULL; - const char *json; try { - std::set objects; - json = CYPoolCCYON(pool, context, result, objects, &exception); - } catch (const char *error) { - return error; - } - + std::set objects; + const char *json(CYPoolCCYON(pool, context, result, objects, &exception)); if (exception != NULL) goto error; @@ -1612,6 +1616,10 @@ const char *CYExecute(JSContextRef context, CYPool &pool, CYUTF8String code) { return json; } +_visible void CYCancel() { + cancel_ = true; +} + static bool initialized_ = false; void CYInitializeDynamic() { @@ -1690,6 +1698,7 @@ void CYInitializeDynamic() { toJSON_s = JSStringCreateWithUTF8CString("toJSON"); toPointer_s = JSStringCreateWithUTF8CString("toPointer"); toString_s = JSStringCreateWithUTF8CString("toString"); + weak_s = JSStringCreateWithUTF8CString("weak"); Result_ = JSStringCreateWithUTF8CString("_"); @@ -1742,10 +1751,8 @@ JSGlobalContextRef CYGetJSContext(JSContextRef context) { return reinterpret_cast(JSObjectGetPrivate(CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s))))->context_; } -extern "C" bool CydgetMemoryParse(const uint16_t **data, size_t *size); - void *CYMapFile(const char *path, size_t *psize) { - int fd(_syscall_(open(path, O_RDONLY), 1, {ENOENT})); + int fd(_syscall_(open(path, O_RDONLY), 1, ENOENT)); if (fd == -1) return NULL; @@ -1822,6 +1829,9 @@ static JSValueRef require(JSContextRef context, JSObjectRef object, JSObjectRef return CYGetProperty(context, module, property); } CYCatch(NULL) } +extern "C" void CYDestroyWeak(JSWeakObjectMapRef weak, void *data) { +} + extern "C" void CYSetupContext(JSGlobalContextRef context) { CYInitializeDynamic(); @@ -1909,8 +1919,6 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) { CYSetPrototype(context, last, all); } - CYSetProperty(context, global, CYJSString("$cyq"), &$cyq, kJSPropertyAttributeDontEnum); - JSObjectRef System(JSObjectMake(context, NULL, NULL)); CYSetProperty(context, cy, CYJSString("System"), System); @@ -1921,6 +1929,13 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) { //CYSetProperty(context, System, CYJSString("global"), global); CYSetProperty(context, System, CYJSString("print"), &System_print); +#ifdef __APPLE__ + if (&JSWeakObjectMapCreate != NULL) { + JSWeakObjectMapRef weak(JSWeakObjectMapCreate(context, NULL, &CYDestroyWeak)); + CYSetProperty(context, cy, weak_s, CYCastJSValue(context, reinterpret_cast(weak))); + } +#endif + if (CYBridgeEntry *entry = CYBridgeHash("1dlerror", 8)) entry->cache_ = new cy::Functor(entry->value_, reinterpret_cast(&dlerror)); @@ -1933,7 +1948,7 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) { static JSGlobalContextRef context_; -JSGlobalContextRef CYGetJSContext() { +_visible JSGlobalContextRef CYGetJSContext() { CYInitializeDynamic(); if (context_ == NULL) { @@ -1944,7 +1959,7 @@ JSGlobalContextRef CYGetJSContext() { return context_; } -void CYDestroyContext() { +_visible void CYDestroyContext() { if (context_ == NULL) return; JSGlobalContextRelease(context_);