X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/3fe283c53edc2a98d0164d893a4a667245da8e78..a5662a5364816f852acb056d5c2b2fc94e0c0a5c:/Execute.cpp?ds=sidebyside
diff --git a/Execute.cpp b/Execute.cpp
index 5baca2a..9f45354 100644
--- a/Execute.cpp
+++ b/Execute.cpp
@@ -1,21 +1,21 @@
/* Cycript - Optimizing JavaScript Compiler/Runtime
- * Copyright (C) 2009-2013 Jay Freeman (saurik)
+ * Copyright (C) 2009-2015 Jay Freeman (saurik)
*/
-/* GNU General Public License, Version 3 {{{ */
+/* GNU Affero General Public License, Version 3 {{{ */
/*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program 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 General Public License
- * along with Cycript. If not, see .
+ * GNU Affero General Public License for more details.
+
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
**/
/* }}} */
@@ -44,16 +44,26 @@
#include
#include
-#include "Parser.hpp"
-
+#include "Code.hpp"
#include "Decode.hpp"
#include "Error.hpp"
#include "JavaScript.hpp"
#include "String.hpp"
-struct CYHooks *hooks_;
+static std::vector &GetHooks() {
+ static std::vector hooks;
+ return hooks;
+}
+
+CYRegisterHook::CYRegisterHook(CYHook *hook) {
+ GetHooks().push_back(hook);
+}
/* JavaScript Properties {{{ */
+bool CYHasProperty(JSContextRef context, JSObjectRef object, JSStringRef name) {
+ return JSObjectHasProperty(context, object, name);
+}
+
JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, size_t index) {
return _jsccall(JSObjectGetPropertyAtIndex, context, object, index);
}
@@ -73,6 +83,11 @@ void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, J
void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef (*callback)(JSContextRef, JSObjectRef, JSObjectRef, size_t, const JSValueRef[], JSValueRef *), JSPropertyAttributes attributes) {
CYSetProperty(context, object, name, JSObjectMakeFunctionWithCallback(context, name, callback), attributes);
}
+
+void CYSetPrototype(JSContextRef context, JSObjectRef object, JSValueRef value) {
+ JSObjectSetPrototype(context, object, value);
+ _assert(CYIsStrictEqual(context, JSObjectGetPrototype(context, object), value));
+}
/* }}} */
/* JavaScript Strings {{{ */
JSStringRef CYCopyJSString(const char *value) {
@@ -139,6 +154,7 @@ JSStringRef toCYON_s;
JSStringRef toJSON_s;
JSStringRef toPointer_s;
JSStringRef toString_s;
+JSStringRef weak_s;
static JSStringRef Result_;
@@ -152,7 +168,6 @@ void CYFinalize(JSObjectRef object) {
void Structor_(CYPool &pool, sig::Type *&type) {
if (
type->primitive == sig::pointer_P &&
- type->data.data.type != NULL &&
type->data.data.type->primitive == sig::struct_P &&
type->data.data.type->name != NULL &&
strcmp(type->data.data.type->name, "_objc_class") == 0
@@ -227,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_);
@@ -249,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);
}
@@ -308,6 +324,14 @@ bool CYIsCallable(JSContextRef context, JSValueRef value) {
return value != NULL && JSValueIsObject(context, value) && JSObjectIsFunction(context, (JSObjectRef) value);
}
+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));
}
@@ -344,7 +368,7 @@ static JSValueRef $cyq(JSContextRef context, JSObjectRef object, JSObjectRef _th
static void (*JSSynchronousGarbageCollectForDebugging$)(JSContextRef);
-void CYGarbageCollect(JSContextRef context) {
+_visible void CYGarbageCollect(JSContextRef context) {
(JSSynchronousGarbageCollectForDebugging$ ?: &JSGarbageCollect)(context);
}
@@ -353,7 +377,7 @@ static JSValueRef Cycript_gc_callAsFunction(JSContextRef context, JSObjectRef ob
return CYJSUndefined(context);
} CYCatch(NULL) }
-const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value, JSValueRef *exception) { CYTry {
+const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value, std::set &objects, JSValueRef *exception) { CYTry {
switch (JSType type = JSValueGetType(context, value)) {
case kJSTypeUndefined:
return "undefined";
@@ -378,20 +402,31 @@ const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value, JS
} break;
case kJSTypeObject:
- return CYPoolCCYON(pool, context, (JSObjectRef) value);
+ return CYPoolCCYON(pool, context, (JSObjectRef) value, objects);
default:
throw CYJSError(context, "JSValueGetType() == 0x%x", type);
}
} CYCatch(NULL) }
-const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value) {
- return _jsccall(CYPoolCCYON, pool, context, value);
+const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value, std::set &objects) {
+ return _jsccall(CYPoolCCYON, pool, context, value, objects);
}
-const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSObjectRef object) {
+const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value, std::set *objects) {
+ if (objects != NULL)
+ return CYPoolCCYON(pool, context, value, *objects);
+ else {
+ std::set objects;
+ return CYPoolCCYON(pool, context, value, objects);
+ }
+}
+
+const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSObjectRef object, std::set &objects) {
JSValueRef toCYON(CYGetProperty(context, object, toCYON_s));
if (CYIsCallable(context, toCYON)) {
- JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toCYON, object, 0, NULL));
+ // XXX: this needs to be abstracted behind some kind of function
+ 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);
}
@@ -399,7 +434,7 @@ const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSObjectRef object)
JSValueRef toJSON(CYGetProperty(context, object, toJSON_s));
if (CYIsCallable(context, toJSON)) {
JSValueRef arguments[1] = {CYCastJSValue(context, CYJSString(""))};
- return _jsccall(CYPoolCCYON, pool, context, CYCallAsFunction(context, (JSObjectRef) toJSON, object, 1, arguments));
+ return _jsccall(CYPoolCCYON, pool, context, CYCallAsFunction(context, (JSObjectRef) toJSON, object, 1, arguments), objects);
}
if (JSObjectIsFunction(context, object)) {
@@ -412,6 +447,8 @@ const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSObjectRef object)
}
}
+ _assert(objects.insert(object).second);
+
std::ostringstream str;
str << '{';
@@ -439,7 +476,7 @@ const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSObjectRef object)
try {
JSValueRef value(CYGetProperty(context, object, name));
- str << CYPoolCCYON(pool, context, value);
+ str << CYPoolCCYON(pool, context, value, objects);
} catch (const CYException &error) {
str << "@error";
}
@@ -453,7 +490,19 @@ const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSObjectRef object)
return pool.strmemdup(string.c_str(), string.size());
}
+std::set *CYCastObjects(JSContextRef context, JSObjectRef _this, size_t count, const JSValueRef arguments[]) {
+ if (count == 0)
+ return NULL;
+ return CYCastPointer *>(context, arguments[0]);
+}
+
static JSValueRef Array_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+ std::set *objects(CYCastObjects(context, _this, count, arguments));
+ // XXX: this is horribly inefficient
+ std::set backup;
+ if (objects == NULL)
+ objects = &backup;
+
CYPool pool;
std::ostringstream str;
@@ -471,7 +520,7 @@ static JSValueRef Array_callAsFunction_toCYON(JSContextRef context, JSObjectRef
try {
JSValueRef value(CYGetProperty(context, _this, index));
if (!JSValueIsUndefined(context, value))
- str << CYPoolCCYON(pool, context, value);
+ str << CYPoolCCYON(pool, context, value, *objects);
else {
str << ',';
comma = false;
@@ -529,7 +578,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: {
@@ -638,9 +689,10 @@ void CYPoolFFI(CYPool *pool, JSContextRef context, sig::Type *type, ffi_type *ff
break;
default:
- if (hooks_ != NULL && hooks_->PoolFFI != NULL)
- if ((*hooks_->PoolFFI)(pool, context, type, ffi, data, value))
- return;
+ for (CYHook *hook : GetHooks())
+ if (hook->PoolFFI != NULL)
+ if ((*hook->PoolFFI)(pool, context, type, ffi, data, value))
+ return;
CYThrow("unimplemented signature code: '%c''\n", type->primitive);
}
@@ -691,15 +743,16 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void
null:
return CYJSNull(context);
default:
- if (hooks_ != NULL && hooks_->FromFFI != NULL)
- if (JSValueRef value = (*hooks_->FromFFI)(context, type, ffi, data, initialize, owner))
- return value;
+ for (CYHook *hook : GetHooks())
+ if (hook->FromFFI != NULL)
+ if (JSValueRef value = (*hook->FromFFI)(context, type, ffi, data, initialize, owner))
+ return value;
CYThrow("unimplemented signature code: '%c''\n", type->primitive);
}
}
-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_);
@@ -710,7 +763,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);
}
@@ -718,20 +771,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;
@@ -742,7 +791,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));
@@ -754,15 +803,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) {
@@ -937,6 +990,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");
@@ -955,11 +1012,13 @@ JSValueRef CYCallFunction(CYPool &pool, JSContextRef context, size_t setups, voi
uint8_t value[cif->rtype->size];
- if (hooks_ != NULL && hooks_->CallFunction != NULL)
- (*hooks_->CallFunction)(context, cif, function, value, values);
- else
- ffi_call(cif, function, value, values);
+ 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)
+ call = hook->CallFunction;
+ call(pool, context, cif, function, value, values);
return CYFromFFI(context, signature->elements[0].type, cif->rtype, value, initialize);
}
@@ -992,6 +1051,33 @@ JSObjectRef CYMakeType(JSContextRef context, sig::Signature *signature) {
return CYMakeType(context, &type);
}
+static bool All_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
+ JSObjectRef global(CYGetGlobalObject(context));
+ JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
+ JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
+
+ for (size_t i(0), count(CYArrayLength(context, alls)); i != count; ++i)
+ if (JSObjectRef space = CYCastJSObject(context, CYArrayGet(context, alls, count - i - 1)))
+ if (CYHasProperty(context, space, property))
+ return true;
+
+ CYPool pool;
+ CYUTF8String name(CYPoolUTF8String(pool, context, property));
+
+ size_t length(name.size);
+ char keyed[length + 2];
+ memcpy(keyed + 1, name.data, length + 1);
+
+ static const char *modes = "0124";
+ for (size_t i(0); i != 4; ++i) {
+ keyed[0] = modes[i];
+ if (CYBridgeHash(keyed, length + 1) != NULL)
+ return true;
+ }
+
+ return false;
+}
+
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"))));
@@ -1321,6 +1407,8 @@ static JSValueRef CYValue_callAsFunction_toCYON(JSContextRef context, JSObjectRe
} CYCatch(NULL) }
static JSValueRef Pointer_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+ std::set *objects(CYCastObjects(context, _this, count, arguments));
+
Pointer *internal(reinterpret_cast(JSObjectGetPrivate(_this)));
if (internal->length_ != _not(size_t)) {
JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
@@ -1335,7 +1423,7 @@ static JSValueRef Pointer_callAsFunction_toCYON(JSContextRef context, JSObjectRe
if (JSValueIsUndefined(context, value))
goto pointer;
CYPool pool;
- return CYCastJSValue(context, pool.strcat("&", CYPoolCCYON(pool, context, value), NULL));
+ return CYCastJSValue(context, pool.strcat("&", CYPoolCCYON(pool, context, value, objects), NULL));
} catch (const CYException &e) {
goto pointer;
}
@@ -1376,7 +1464,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);
@@ -1420,6 +1508,10 @@ static JSStaticValue Functor_staticValues[2] = {
{NULL, NULL, NULL, 0}
};
+namespace cy {
+ JSStaticValue const * const Functor::StaticValues = Functor_staticValues;
+}
+
static JSStaticValue Type_staticValues[4] = {
{"alignment", &Type_getProperty_alignment, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"name", &Type_getProperty_name, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
@@ -1446,7 +1538,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)
@@ -1469,50 +1561,61 @@ JSObjectRef CYGetGlobalObject(JSContextRef context) {
return JSContextGetGlobalObject(context);
}
+// XXX: this is neither exceptin safe nor even terribly sane
class ExecutionHandle {
private:
JSContextRef context_;
- void *handle_;
+ std::vector handles_;
public:
ExecutionHandle(JSContextRef context) :
context_(context)
{
- if (hooks_ != NULL && hooks_->ExecuteStart != NULL)
- handle_ = (*hooks_->ExecuteStart)(context_);
- else
- handle_ = NULL;
+ handles_.resize(GetHooks().size());
+ for (size_t i(0); i != GetHooks().size(); ++i) {
+ CYHook *hook(GetHooks()[i]);
+ if (hook->ExecuteStart != NULL)
+ handles_[i] = (*hook->ExecuteStart)(context_);
+ else
+ handles_[i] = NULL;
+ }
}
~ExecutionHandle() {
- if (hooks_ != NULL && hooks_->ExecuteEnd != NULL)
- (*hooks_->ExecuteEnd)(context_, handle_);
+ for (size_t i(GetHooks().size()); i != 0; --i) {
+ CYHook *hook(GetHooks()[i-1]);
+ if (hook->ExecuteEnd != NULL)
+ (*hook->ExecuteEnd)(context_, handles_[i-1]);
+ }
}
};
-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 {
- json = CYPoolCCYON(pool, context, result, &exception);
- } catch (const char *error) {
- return error;
- }
-
+ std::set objects;
+ const char *json(CYPoolCCYON(pool, context, result, objects, &exception));
if (exception != NULL)
goto error;
@@ -1521,6 +1624,10 @@ const char *CYExecute(JSContextRef context, CYPool &pool, CYUTF8String code) {
return json;
}
+_visible void CYCancel() {
+ cancel_ = true;
+}
+
static bool initialized_ = false;
void CYInitializeDynamic() {
@@ -1535,6 +1642,7 @@ void CYInitializeDynamic() {
definition = kJSClassDefinitionEmpty;
definition.className = "All";
+ definition.hasProperty = &All_hasProperty;
definition.getProperty = &All_getProperty;
definition.getPropertyNames = &All_getPropertyNames;
All_ = JSClassCreate(&definition);
@@ -1598,11 +1706,13 @@ void CYInitializeDynamic() {
toJSON_s = JSStringCreateWithUTF8CString("toJSON");
toPointer_s = JSStringCreateWithUTF8CString("toPointer");
toString_s = JSStringCreateWithUTF8CString("toString");
+ weak_s = JSStringCreateWithUTF8CString("weak");
Result_ = JSStringCreateWithUTF8CString("_");
- if (hooks_ != NULL && hooks_->Initialize != NULL)
- (*hooks_->Initialize)();
+ for (CYHook *hook : GetHooks())
+ if (hook->Initialize != NULL)
+ (*hook->Initialize)();
}
void CYThrow(JSContextRef context, JSValueRef value) {
@@ -1611,8 +1721,9 @@ void CYThrow(JSContextRef context, JSValueRef value) {
}
const char *CYJSError::PoolCString(CYPool &pool) const {
+ std::set objects;
// XXX: this used to be CYPoolCString
- return CYPoolCCYON(pool, context_, value_);
+ return CYPoolCCYON(pool, context_, value_, objects);
}
JSValueRef CYJSError::CastJSValue(JSContextRef context) const {
@@ -1648,11 +1759,10 @@ 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(fd = open(path, O_RDONLY));
+ int fd(_syscall_(open(path, O_RDONLY), 1, ENOENT));
+ if (fd == -1)
+ return NULL;
struct stat stat;
_syscall(fstat(fd, &stat));
@@ -1667,49 +1777,6 @@ void *CYMapFile(const char *path, size_t *psize) {
return base;
}
-static void CYRunSetups(JSContextRef context) {
- std::string folder("/etc/cycript/setup.d");
- DIR *setups(opendir(folder.c_str()));
- if (setups == NULL)
- return;
-
- for (;;) {
- dirent setup;
- dirent *result;
- _syscall(readdir_r(setups, &setup, &result));
-
- if (result == NULL)
- break;
- _assert(result == &setup);
-
- const char *name(setup.d_name);
- size_t length(strlen(name));
- if (length < 4)
- continue;
-
- if (name[0] == '.')
- continue;
- if (memcmp(name + length - 3, ".cy", 3) != 0)
- continue;
-
- std::string script(folder + "/" + name);
- CYUTF8String utf8;
- utf8.data = reinterpret_cast(CYMapFile(script.c_str(), &utf8.size));
-
- CYPool pool;
- CYUTF16String utf16(CYPoolUTF16String(pool, utf8));
- munmap(const_cast(utf8.data), utf8.size);
-
- // XXX: this should not be used
- CydgetMemoryParse(&utf16.data, &utf16.size);
-
- CYExecute(context, pool, CYPoolUTF8String(pool, utf16));
- free(const_cast(utf16.data));
- }
-
- _syscall(closedir(setups));
-}
-
static JSValueRef require(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
_assert(count == 1);
CYPool pool;
@@ -1725,7 +1792,9 @@ static JSValueRef require(JSContextRef context, JSObjectRef object, JSObjectRef
CYJSString property("exports");
JSObjectRef module;
- const char *path(pool.strcat(lib, "/cycript/", CYPoolCString(pool, context, arguments[0]), ".cy", NULL));
+ const char *name(CYPoolCString(pool, context, arguments[0]));
+ const char *path(pool.strcat(lib, "/cycript0.9/", name, ".cy", NULL));
+
CYJSString key(path);
JSObjectRef modules(CYGetCachedObject(context, CYJSString("modules")));
JSValueRef cache(CYGetProperty(context, modules, key));
@@ -1736,25 +1805,41 @@ static JSValueRef require(JSContextRef context, JSObjectRef object, JSObjectRef
CYUTF8String code;
code.data = reinterpret_cast(CYMapFile(path, &code.size));
- std::stringstream wrap;
- wrap << "(function (exports, require, module) { " << code << "\n});";
- code = CYPoolCode(pool, wrap.str().c_str());
+ if (code.data == NULL) {
+ if (strchr(name, '/') == NULL && (
+#ifdef __APPLE__
+ dlopen(pool.strcat("/System/Library/Frameworks/", name, ".framework/", name, NULL), RTLD_LAZY | RTLD_GLOBAL) != NULL ||
+ dlopen(pool.strcat("/System/Library/PrivateFrameworks/", name, ".framework/", name, NULL), RTLD_LAZY | RTLD_GLOBAL) != NULL ||
+#endif
+ false))
+ return CYJSUndefined(NULL);
- JSValueRef value(_jsccall(JSEvaluateScript, context, CYJSString(code), NULL, NULL, 0));
- JSObjectRef function(CYCastJSObject(context, value));
+ CYThrow("Can't find module: %s", name);
+ }
module = JSObjectMake(context, NULL, NULL);
+ CYSetProperty(context, modules, key, module);
+
JSObjectRef exports(JSObjectMake(context, NULL, NULL));
CYSetProperty(context, module, property, exports);
+ std::stringstream wrap;
+ wrap << "(function (exports, require, module) { " << code << "\n});";
+ code = CYPoolCode(pool, wrap);
+
+ JSValueRef value(_jsccall(JSEvaluateScript, context, CYJSString(code), NULL, NULL, 0));
+ JSObjectRef function(CYCastJSObject(context, value));
+
JSValueRef arguments[3] = { exports, JSObjectMakeFunctionWithCallback(context, CYJSString("require"), &require), module };
CYCallAsFunction(context, function, NULL, 3, arguments);
- CYSetProperty(context, modules, key, module);
}
return CYGetProperty(context, module, property);
} CYCatch(NULL) }
+extern "C" void CYDestroyWeak(JSWeakObjectMapRef weak, void *data) {
+}
+
extern "C" void CYSetupContext(JSGlobalContextRef context) {
CYInitializeDynamic();
@@ -1770,6 +1855,12 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) {
JSObjectRef Array_prototype(CYCastJSObject(context, CYGetProperty(context, Array, prototype_s)));
CYSetProperty(context, cy, CYJSString("Array_prototype"), Array_prototype);
+ JSObjectRef Boolean(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Boolean"))));
+ CYSetProperty(context, cy, CYJSString("Boolean"), Boolean);
+
+ JSObjectRef Boolean_prototype(CYCastJSObject(context, CYGetProperty(context, Boolean, prototype_s)));
+ CYSetProperty(context, cy, CYJSString("Boolean_prototype"), Boolean_prototype);
+
JSObjectRef Error(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Error"))));
CYSetProperty(context, cy, CYJSString("Error"), Error);
@@ -1779,6 +1870,12 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) {
JSObjectRef Function_prototype(CYCastJSObject(context, CYGetProperty(context, Function, prototype_s)));
CYSetProperty(context, cy, CYJSString("Function_prototype"), Function_prototype);
+ JSObjectRef Number(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Number"))));
+ CYSetProperty(context, cy, CYJSString("Number"), Number);
+
+ JSObjectRef Number_prototype(CYCastJSObject(context, CYGetProperty(context, Number, prototype_s)));
+ CYSetProperty(context, cy, CYJSString("Number_prototype"), Number_prototype);
+
JSObjectRef Object(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Object"))));
CYSetProperty(context, cy, CYJSString("Object"), Object);
@@ -1800,7 +1897,7 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) {
CYSetProperty(context, cycript, CYJSString("gc"), &Cycript_gc_callAsFunction);
JSObjectRef Functor(JSObjectMakeConstructor(context, Functor_, &Functor_new));
- JSObjectSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Functor, prototype_s)), Function_prototype);
+ CYSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Functor, prototype_s)), Function_prototype);
CYSetProperty(context, cycript, CYJSString("Functor"), Functor);
CYSetProperty(context, cycript, CYJSString("Pointer"), JSObjectMakeConstructor(context, Pointer_, &Pointer_new));
@@ -1827,7 +1924,7 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) {
next = JSObjectGetPrototype(context, curr);
}
- JSObjectSetPrototype(context, last, all);
+ CYSetPrototype(context, last, all);
}
CYSetProperty(context, global, CYJSString("$cyq"), &$cyq, kJSPropertyAttributeDontEnum);
@@ -1842,20 +1939,26 @@ 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));
- if (hooks_ != NULL && hooks_->SetupContext != NULL)
- (*hooks_->SetupContext)(context);
+ for (CYHook *hook : GetHooks())
+ if (hook->SetupContext != NULL)
+ (*hook->SetupContext)(context);
CYArrayPush(context, alls, cycript);
-
- CYRunSetups(context);
}
static JSGlobalContextRef context_;
-JSGlobalContextRef CYGetJSContext() {
+_visible JSGlobalContextRef CYGetJSContext() {
CYInitializeDynamic();
if (context_ == NULL) {
@@ -1866,7 +1969,7 @@ JSGlobalContextRef CYGetJSContext() {
return context_;
}
-void CYDestroyContext() {
+_visible void CYDestroyContext() {
if (context_ == NULL)
return;
JSGlobalContextRelease(context_);