From f45374f409a41356651b41bed3e1671697080290 Mon Sep 17 00:00:00 2001 From: "Jay Freeman (saurik)" Date: Wed, 6 Jan 2016 12:01:06 -0800 Subject: [PATCH] Lazy load JVM, as it is slow and crashes on iOS 9. --- Java/Execute.cpp | 32 +++++++++++++++++++------------- libcycript.cy | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 13 deletions(-) diff --git a/Java/Execute.cpp b/Java/Execute.cpp index 8e7acbf..d9eb1e6 100644 --- a/Java/Execute.cpp +++ b/Java/Execute.cpp @@ -1247,6 +1247,8 @@ CYJavaForEachPrimitive return true; } CYCatch(false) } +static JNIEnv *GetJNI(JSContextRef context, JNIEnv *&env); + static JSValueRef JavaPackage_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { auto internal(CYJavaPackage::Get(context, _this)); std::ostringstream name; @@ -1272,7 +1274,10 @@ static JSValueRef CYJavaPackage_getProperty(JSContextRef context, JSObjectRef ob name << package << '/'; name << next; + if (internal->jni_ == NULL) + GetJNI(context, internal->jni_); JNIEnv *jni(internal->jni_); + if (auto _class = jni->FindClass(name.str().c_str())) return CYGetJavaClass(context, CYJavaLocal(jni, _class)); jni->ExceptionClear(); @@ -1468,18 +1473,22 @@ static JavaVM *CYGetJavaVM(JSContextRef context) { return jvm; } -static JNIEnv *GetJNI(JSContextRef context) { +static JNIEnv *GetJNI(JSContextRef context, JNIEnv *&env) { auto jvm(CYGetJavaVM(context)); - if (jvm == NULL) - return NULL; - - JNIEnv *env; + _assert(jvm != NULL); _jnicall(jvm->GetEnv(reinterpret_cast(&env), CYJavaVersion)); CYJavaEnv jni(env); + // XXX: this happens once per stub :/ + auto Cycript$(jni.FindClass("Cycript")); jni.RegisterNatives(Cycript$, Cycript_, sizeof(Cycript_) / sizeof(Cycript_[0])); + JSObjectRef java(CYGetCachedObject(context, CYJSString("Java"))); + JSValueRef arguments[1]; + arguments[0] = CYCastJSValue(context, CYJSString("setup")); + CYCallAsFunction(context, CYCastJSObject(context, CYGetProperty(context, java, CYJSString("emit"))), java, 1, arguments); + return env; } @@ -1590,25 +1599,22 @@ CYJavaForEachPrimitive } void CYJava_SetupContext(JSContextRef context) { - JNIEnv *jni(GetJNI(context)); - if (jni == NULL) - return; - JSObjectRef global(CYGetGlobalObject(context)); - //JSObjectRef cy(CYCastJSObject(context, CYGetProperty(context, global, cy_s))); + JSObjectRef cy(CYCastJSObject(context, CYGetProperty(context, global, cy_s))); JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript")))); JSObjectRef all(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("all")))); //JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls")))); JSObjectRef Java(JSObjectMake(context, NULL, NULL)); CYSetProperty(context, cycript, CYJSString("Java"), Java); + CYSetProperty(context, cy, CYJSString("Java"), Java); - JSObjectRef Packages(CYJavaPackage::Make(context, jni, CYJavaPackage::Path())); - CYSetProperty(context, all, CYJSString("Packages"), Packages); + JSObjectRef Packages(CYJavaPackage::Make(context, nullptr, CYJavaPackage::Path())); + CYSetProperty(context, all, CYJSString("Packages"), Packages, kJSPropertyAttributeDontEnum); for (auto name : (const char *[]) {"java", "javax", "android", "com", "net", "org"}) { CYJSString js(name); - CYSetProperty(context, all, js, CYGetProperty(context, Packages, js)); + CYSetProperty(context, all, js, CYJavaPackage::Make(context, nullptr, CYJavaPackage::Path(1, name)), kJSPropertyAttributeDontEnum); } } diff --git a/libcycript.cy b/libcycript.cy index 6f798ea..da34baa 100644 --- a/libcycript.cy +++ b/libcycript.cy @@ -83,7 +83,42 @@ $cy_set(RegExp.prototype, { }, }); +// XXX: Java should just always be available if ("Java" in Cycript) { + +// XXX: this is a half-assed EventEmitter +// XXX: this doesn't even have the same semantics + +Java.handlers_ = {}; + +Java.on = function(event, handler) { + var handlers; + if (event in this.handlers_) + handlers = this.handlers_[event]; + else { + handlers = []; + this.handlers_[event] = handlers; + } + + if (this.handlers_ == null) + handler(); + else + handlers.push(handler); +}; + +Java.emit = function(event) { + if (event in this.handlers_) { + var handlers = this.handlers_[event]; + if (handlers != null) + for (var handler of handlers) + handler(); + } + + this.handlers_[event] = null; +}; + +Java.on('setup', function() { + system.print("JVM\n"); $cy_set(java.lang.Boolean.prototype, { toCYON: function() { return `new java.lang.Boolean(${this->value})`; @@ -150,6 +185,8 @@ if ("Java" in Cycript) { this.put(key, value); }, }); +}); + } if ("ObjectiveC" in Cycript) { -- 2.47.2