+ JavaVM *jvm;
+ JNIEnv *env;
+
+ if (void *libandroid_runtime = dlopen("libandroid_runtime.so", RTLD_LAZY | RTLD_GLOBAL)) {
+ class AndroidRuntime$;
+ AndroidRuntime$ *(*AndroidRuntime$$init$)(AndroidRuntime$ *self, char *args, unsigned int size)(NULL);
+ int (*AndroidRuntime$startVm)(AndroidRuntime$ *self, JavaVM **jvm, JNIEnv **env)(NULL);
+ int (*AndroidRuntime$startReg)(JNIEnv *env)(NULL);
+ int (*AndroidRuntime$addOption)(AndroidRuntime$ *self, const char *option, void *extra)(NULL);
+ int (*AndroidRuntime$addVmArguments)(AndroidRuntime$ *self, int, const char *const argv[])(NULL);
+ AndroidRuntime$ *(*AndroidRuntime$finalize)(AndroidRuntime$ *self)(NULL);
+
+ dlset(AndroidRuntime$$init$, "_ZN7android14AndroidRuntimeC1EPcj", libandroid_runtime);
+ dlset(AndroidRuntime$startVm, "_ZN7android14AndroidRuntime7startVmEPP7_JavaVMPP7_JNIEnv", libandroid_runtime);
+ dlset(AndroidRuntime$startReg, "_ZN7android14AndroidRuntime8startRegEP7_JNIEnv", libandroid_runtime);
+ dlset(AndroidRuntime$addOption, "_ZN7android14AndroidRuntime9addOptionEPKcPv", libandroid_runtime);
+ dlset(AndroidRuntime$addVmArguments, "_ZN7android14AndroidRuntime14addVmArgumentsEiPKPKc", libandroid_runtime);
+ dlset(AndroidRuntime$finalize, "_ZN7android14AndroidRuntimeD1Ev", libandroid_runtime);
+
+ // XXX: it would also be interesting to attach this to a global pool
+ AndroidRuntime$ *runtime(pool.calloc<AndroidRuntime$>(1, 1024));
+
+ _assert(AndroidRuntime$$init$ != NULL);
+ AndroidRuntime$$init$(runtime, NULL, 0);
+
+ if (AndroidRuntime$addOption == NULL) {
+ _assert(AndroidRuntime$addVmArguments != NULL);
+ std::vector<const char *> arguments;
+ for (const auto &option : options)
+ arguments.push_back(option.optionString);
+ AndroidRuntime$addVmArguments(runtime, arguments.size(), arguments.data());
+ } else for (const auto &option : options)
+ AndroidRuntime$addOption(runtime, option.optionString, option.extraInfo);
+
+ int failure;
+
+ _assert(AndroidRuntime$startVm != NULL);
+ failure = AndroidRuntime$startVm(runtime, &jvm, &env);
+ _assert(failure == 0);
+
+ _assert(AndroidRuntime$startReg != NULL);
+ failure = AndroidRuntime$startReg(env);
+ _assert(failure == 0);
+
+ return jvm;
+ }
+
+ jint (*$JNI_CreateJavaVM)(JavaVM **jvm, void **, void *);
+ dlset($JNI_CreateJavaVM, "JNI_CreateJavaVM", handle);
+
+ JavaVMInitArgs args;
+ memset(&args, 0, sizeof(args));
+ args.version = CYJavaVersion;
+ args.nOptions = options.size();
+ args.options = options.data();
+ _jnicall($JNI_CreateJavaVM(&jvm, reinterpret_cast<void **>(&env), &args));
+ return jvm;
+}
+
+static JNIEnv *GetJNI(JSContextRef context, JNIEnv *&env) {
+ auto jvm(CYGetJavaVM(context));
+ _assert(jvm != NULL);
+ _jnicall(jvm->GetEnv(reinterpret_cast<void **>(&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;