X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/58321c0afd977fa7a47f5d81ee0674ca7582c309..c4481e4036f73f230903a9521612bbca5ff32359:/Execute.cpp
diff --git a/Execute.cpp b/Execute.cpp
index 2bdd59f..9a2eb95 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-2014 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,14 +44,17 @@
#include
#include
-#include "Parser.hpp"
-
+#include "Code.hpp"
#include "Decode.hpp"
#include "Error.hpp"
#include "JavaScript.hpp"
#include "String.hpp"
-struct CYHooks *hooks_;
+std::vector hooks_;
+
+CYRegisterHook::CYRegisterHook(CYHook *hook) {
+ hooks_.push_back(hook);
+}
/* JavaScript Properties {{{ */
bool CYHasProperty(JSContextRef context, JSObjectRef object, JSStringRef name) {
@@ -77,6 +80,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(JSObjectGetPrototype(context, object) == value);
+}
/* }}} */
/* JavaScript Strings {{{ */
JSStringRef CYCopyJSString(const char *value) {
@@ -356,7 +364,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";
@@ -381,20 +389,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, 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) {
+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, static_cast(reinterpret_cast(&objects)))};
+ JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toCYON, object, 1, arguments));
_assert(value != NULL);
return CYPoolCString(pool, context, value);
}
@@ -402,7 +421,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)) {
@@ -415,6 +434,8 @@ const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSObjectRef object)
}
}
+ _assert(objects.insert(object).second);
+
std::ostringstream str;
str << '{';
@@ -442,7 +463,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";
}
@@ -456,7 +477,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;
@@ -474,7 +507,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;
@@ -641,9 +674,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 : hooks_)
+ if (hook->PoolFFI != NULL)
+ if ((*hook->PoolFFI)(pool, context, type, ffi, data, value))
+ return;
CYThrow("unimplemented signature code: '%c''\n", type->primitive);
}
@@ -694,9 +728,10 @@ 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 : hooks_)
+ 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);
}
@@ -958,11 +993,15 @@ 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);
+ for (CYHook *hook : hooks_)
+ 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);
+ from:
return CYFromFFI(context, signature->elements[0].type, cif->rtype, value, initialize);
}
@@ -1351,6 +1390,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")));
@@ -1365,7 +1406,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;
}
@@ -1503,24 +1544,32 @@ 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(hooks_.size());
+ for (size_t i(0); i != hooks_.size(); ++i) {
+ CYHook *hook(hooks_[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(hooks_.size()); i != 0; --i) {
+ CYHook *hook(hooks_[i-1]);
+ if (hook->ExecuteEnd != NULL)
+ (*hook->ExecuteEnd)(context_, handles_[i-1]);
+ }
}
};
@@ -1542,7 +1591,8 @@ const char *CYExecute(JSContextRef context, CYPool &pool, CYUTF8String code) {
return NULL;
const char *json; try {
- json = CYPoolCCYON(pool, context, result, &exception);
+ std::set objects;
+ json = CYPoolCCYON(pool, context, result, objects, &exception);
} catch (const char *error) {
return error;
}
@@ -1636,8 +1686,9 @@ void CYInitializeDynamic() {
Result_ = JSStringCreateWithUTF8CString("_");
- if (hooks_ != NULL && hooks_->Initialize != NULL)
- (*hooks_->Initialize)();
+ for (CYHook *hook : hooks_)
+ if (hook->Initialize != NULL)
+ (*hook->Initialize)();
}
void CYThrow(JSContextRef context, JSValueRef value) {
@@ -1646,8 +1697,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 {
@@ -1686,8 +1738,9 @@ JSGlobalContextRef CYGetJSContext(JSContextRef 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));
@@ -1717,7 +1770,9 @@ static JSValueRef require(JSContextRef context, JSObjectRef object, JSObjectRef
CYJSString property("exports");
JSObjectRef module;
- const char *path(pool.strcat(lib, "/cycript0.9/", 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));
@@ -1728,20 +1783,33 @@ 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);
@@ -1804,7 +1872,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));
@@ -1831,7 +1899,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);
@@ -1849,8 +1917,9 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) {
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 : hooks_)
+ if (hook->SetupContext != NULL)
+ (*hook->SetupContext)(context);
CYArrayPush(context, alls, cycript);
}