/* 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 <http://www.gnu.org/licenses/>.
+ * 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 <http://www.gnu.org/licenses/>.
**/
/* }}} */
#include "JavaScript.hpp"
#include "String.hpp"
-struct CYHooks *hooks_;
+static std::vector<CYHook *> &GetHooks() {
+ static std::vector<CYHook *> hooks;
+ return hooks;
+}
+
+CYRegisterHook::CYRegisterHook(CYHook *hook) {
+ GetHooks().push_back(hook);
+}
/* JavaScript Properties {{{ */
bool CYHasProperty(JSContextRef context, JSObjectRef object, JSStringRef name) {
void CYSetPrototype(JSContextRef context, JSObjectRef object, JSValueRef value) {
JSObjectSetPrototype(context, object, value);
- _assert(JSObjectGetPrototype(context, object) == value);
+ _assert(CYIsStrictEqual(context, JSObjectGetPrototype(context, object), value));
}
/* }}} */
/* JavaScript Strings {{{ */
JSStringRef toJSON_s;
JSStringRef toPointer_s;
JSStringRef toString_s;
+JSStringRef weak_s;
static JSStringRef Result_;
}
};
-typedef std::map<const char *, Type_privateData *, CYCStringLess> 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_);
}
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);
}
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));
}
}
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: {
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);
}
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);
}
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) {
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 : 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);
+ from:
return CYFromFFI(context, signature->elements[0].type, cif->rtype, value, initialize);
}
return JSContextGetGlobalObject(context);
}
+// XXX: this is neither exceptin safe nor even terribly sane
class ExecutionHandle {
private:
JSContextRef context_;
- void *handle_;
+ std::vector<void *> 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]);
+ }
}
};
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) {
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;
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);
//CYSetProperty(context, System, CYJSString("global"), global);
CYSetProperty(context, System, CYJSString("print"), &System_print);
+#ifdef __APPLE__
+ if (&JSWeakObjectMapCreate != NULL) {
+ JSWeakObjectMapRef weak(JSWeakObjectMapCreate(context, NULL, NULL));
+ CYSetProperty(context, cy, weak_s, CYCastJSValue(context, reinterpret_cast<uintptr_t>(weak)));
+ }
+#endif
+
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);
+ for (CYHook *hook : GetHooks())
+ if (hook->SetupContext != NULL)
+ (*hook->SetupContext)(context);
CYArrayPush(context, alls, cycript);
}