dokar3 / quickjs-kt Goto Github PK
View Code? Open in Web Editor NEWA QuickJS binding for idiomatic Kotlin, with Async/DSL/ES Modules support.
License: Apache License 2.0
A QuickJS binding for idiomatic Kotlin, with Async/DSL/ES Modules support.
License: Apache License 2.0
Currently, the detection of circular references not working on deep-level circular references:
// Not able to detect in this case
val set = mutableSetOf<Any?>()
val array = arrayOf(set)
set.add(array)
Need to re-implement the detection code.
Currently, all jobs will get canceled if one throws an error, regardless of whether they have been caught in JavaScript.
The behavior needs to be implemented correctly.
Related to #12
I love this library, but I have some questions.
Question1: Can I use exactly one same QuickJS
instance on two coroutines/threads?
Question2: According to the README, QuickJs.create(Dispatchers.Default)
, what exactly is the dispatcher parameter used for? Must it be a single-thread dispatcher(because JavaScript is a single-thread language)?
private suspend fun evalAndAwait(evalBlock: suspend () -> Any?): Any? {
ensureNotClosed()
evalException = null
loadModules()
val result = jsResultMutex.withLock {
jsMutex.withLock { evalBlock() }
awaitAsyncJobs()
jsMutex.withLock { getEvaluateResult(context, globals) }
}
handleException()
return result
}
I have a JS call which will be delayed for 5 seconds, within the 5 second other evaluate
calls block. I think it is the jsResultMutex
here blocks other evaluate
calls.
Currently, both FunctionBinding<R>
and AsyncFunctionBinding<R>
only allow generic return types
fun interface FunctionBinding<R> : Binding {
fun invoke(args: Array<Any?>): R
}
fun interface AsyncFunctionBinding<R> : Binding {
suspend fun invoke(args: Array<Any?>): R
}
I propose either making the Binding
interface public to be able to create your own implementation of binding with custom arguments type or changing the FunctionBinding
s to support custom argument types. I am making this an issue first because this would be a breaking change.
fun interface FunctionBinding<A, R> : Binding {
fun invoke(args: A): R
}
fun interface AsyncFunctionBinding<A, R> : Binding {
suspend fun invoke(args: A): R
}
As this QuickJs bindings library doesn't provide a fetch
implementation, following the example in your readme, having something like this:
interface FetchArguments {
val url: String
val options: FetchOptions
}
interface FetchOptions {
val method: String
val headers: Map<String, String>
val body: String
}
interface FetchResponse {
val ok: Boolean
val status: Int
val statusText: String
val headers: Map<String, String>
val body: String
val responseURL: String
val responseText: String
}
/* ------------------------- */
quickJs {
asyncFunction<FetchArguments, FetchResponse>("fetch") { args: FetchArguments ->
// Custom fetch implementation
}
}
would simplify the way we parse arguments, allowing for fewer type errors overall and providing closer to the original JavaScript experience.
Currently, the only alternative option I see is using Reflection. However, the documentation makes it unclear, whether we can provide pure functions through reflection, or we need to wrap them with objects (which is also not ideal, since calling http.get
is non-standard JavaScript and not every developer is willing to read the documentation to understand, why there is no fetch
function.
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
This repository currently has no open or pending branches.
scripts/package.json
@types/bun ^1.0.5
.github/workflows/benchmark.yaml
actions/checkout v4
actions/setup-java v4
jwlawson/actions-setup-cmake v2.0
goto-bus-stop/setup-zig v2
oven-sh/setup-bun v2
gradle/actions v3
stefanzweifel/git-auto-commit-action v5
.github/workflows/build.yaml
actions/checkout v4
actions/setup-java v4
jwlawson/actions-setup-cmake v2.0
goto-bus-stop/setup-zig v2
oven-sh/setup-bun v2
gradle/actions v3
.github/workflows/publish.yaml
actions/checkout v4
actions/setup-java v4
jwlawson/actions-setup-cmake v2.0
goto-bus-stop/setup-zig v2
oven-sh/setup-bun v2
gradle/actions v3
buildSrc/src/main/kotlin/com/dokar/quickjs/Platform.kt
buildSrc/src/main/kotlin/com/dokar/quickjs/applyQuickJsNativeBuildTasks.kt
buildSrc/src/main/kotlin/com/dokar/quickjs/buildQuickJsNativeLibrary.kt
buildSrc/src/main/kotlin/com/dokar/quickjs/disableUnsupportedPlatformTasks.kt
gradle.properties
settings.gradle.kts
build.gradle.kts
benchmark/build.gradle.kts
buildSrc/settings.gradle.kts
buildSrc/build.gradle.kts
gradle/libs.versions.toml
androidx.core:core-ktx 1.13.1
junit:junit 4.13.2
androidx.test.ext:junit 1.2.1
androidx.activity:activity-compose 1.9.0
androidx.compose.ui:ui-tooling 1.6.8
androidx.compose.ui:ui-tooling-preview 1.6.8
org.jetbrains.kotlin:kotlin-test 2.0.0
org.jetbrains.kotlin:kotlin-test-junit 2.0.0
org.jetbrains.kotlinx:kotlinx-coroutines-core 1.8.1
org.jetbrains.kotlinx:kotlinx-coroutines-test 1.8.1
org.jetbrains.kotlinx:kotlinx-benchmark-runtime 0.4.11
com.github.ajalt.clikt:clikt 4.4.0
org.jetbrains.kotlinx:kotlinx-serialization-properties 1.7.1
io.ktor:ktor-client-core 3.0.0-beta-2
io.ktor:ktor-client-cio 3.0.0-beta-2
com.squareup.moshi:moshi 1.15.1
com.squareup.moshi:moshi-kotlin-codegen 1.15.1
com.android.application 8.5.1
com.android.library 8.5.1
org.jetbrains.compose 1.6.11
org.jetbrains.kotlin.multiplatform 2.0.0
org.jetbrains.kotlin.jvm 2.0.0
org.jetbrains.kotlin.android 2.0.0
org.jetbrains.kotlinx.benchmark 0.4.11
org.jetbrains.kotlin.plugin.allopen 2.0.0
org.jetbrains.kotlin.plugin.compose 2.0.0
org.jetbrains.kotlin.plugin.serialization 2.0.0
com.vanniktech.maven.publish 0.29.0
com.google.devtools.ksp 2.0.0-1.0.23
quickjs/gradle.properties
quickjs/build.gradle.kts
quickjs-converter-ktxserialization/gradle.properties
quickjs-converter-ktxserialization/build.gradle.kts
quickjs-converter-moshi/gradle.properties
quickjs-converter-moshi/build.gradle.kts
samples/js-eval/build.gradle.kts
samples/openai/build.gradle.kts
samples/repl/build.gradle.kts
com.github.johnrengelman.shadow 8.1.1
gradle/wrapper/gradle-wrapper.properties
gradle 8.9
catch()
currently does not work as expected. The following code will throw an error.
quickJs {
asyncFunction("fetch") { error("Not implemented.") }
}
fetch("SOME_URL")
.catch((e) => {});
Hi,
I have a Kotlin Multiplatform project that fails at the linking step when building for iOS (device or simulator).
Here is the stack in XCode when trying to build :
Stack Trace :
Undefined symbols for architecture arm64:
"_JS_AtomToValue", referenced from:
_quickjs_JS_AtomToValue_wrapper62 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_Call", referenced from:
_quickjs_JS_Call_wrapper145 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_CallConstructor", referenced from:
_quickjs_JS_CallConstructor_wrapper147 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_DefinePropertyGetSet", referenced from:
_quickjs_JS_DefinePropertyGetSet_wrapper158 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_DefinePropertyValue", referenced from:
_quickjs_JS_DefinePropertyValue_wrapper155 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_DefinePropertyValueStr", referenced from:
_quickjs_JS_DefinePropertyValueStr_wrapper157 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_Eval", referenced from:
_quickjs_JS_Eval_wrapper150 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_EvalFunction", referenced from:
_quickjs_JS_EvalFunction_wrapper188 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_ExecutePendingJob", referenced from:
_quickjs_JS_ExecutePendingJob_wrapper184 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_FreeAtom", referenced from:
_quickjs_JS_FreeAtom_wrapper60 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_FreeCString", referenced from:
_quickjs_JS_FreeCString_wrapper118 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_GetArrayBuffer", referenced from:
_quickjs_JS_GetArrayBuffer_wrapper168 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_GetException", referenced from:
_quickjs_JS_GetException_wrapper91 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_GetGlobalObject", referenced from:
_quickjs_JS_GetGlobalObject_wrapper152 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_GetOwnPropertyNames", referenced from:
_quickjs_JS_GetOwnPropertyNames_wrapper143 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_GetPropertyInternal", referenced from:
_quickjs_JS_GetProperty_wrapper129 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_GetPropertyStr", referenced from:
_quickjs_JS_GetPropertyStr_wrapper130 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_GetPropertyUint32", referenced from:
_quickjs_JS_GetPropertyUint32_wrapper131 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_GetRuntime", referenced from:
_quickjs_JS_GetRuntime_wrapper20 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_IsArray", referenced from:
_quickjs_JS_IsArray_wrapper127 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_IsError", referenced from:
_quickjs_JS_IsError_wrapper92 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_IsFunction", referenced from:
_quickjs_JS_IsFunction_wrapper123 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_IsInstanceOf", referenced from:
_quickjs_JS_IsInstanceOf_wrapper153 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_JSONStringify", referenced from:
_quickjs_JS_JSONStringify_wrapper164 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_NewArray", referenced from:
_quickjs_JS_NewArray_wrapper126 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_NewArrayBuffer", referenced from:
_quickjs_JS_NewArrayBuffer_wrapper165 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_NewAtom", referenced from:
_quickjs_JS_NewAtom_wrapper57 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_NewCFunctionData", referenced from:
_quickjs_JS_NewCFunctionData_wrapper193 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_NewContext", referenced from:
_quickjs_JS_NewContext_wrapper15 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_NewError", referenced from:
_quickjs_JS_NewError_wrapper94 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_NewObject", referenced from:
_quickjs_JS_NewObject_wrapper122 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_NewPromiseCapability", referenced from:
_quickjs_JS_NewPromiseCapability_wrapper171 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_NewRuntime", referenced from:
_quickjs_JS_NewRuntime_wrapper2 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_NewString", referenced from:
_quickjs_JS_NewString_wrapper111 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_PromiseResult", referenced from:
_quickjs_JS_PromiseResult_wrapper173 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_PromiseState", referenced from:
_quickjs_JS_PromiseState_wrapper172 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_ReadObject", referenced from:
_quickjs_JS_ReadObject_wrapper187 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_SetHostPromiseRejectionTracker", referenced from:
_quickjs_JS_SetHostPromiseRejectionTracker_wrapper174 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_SetPropertyStr", referenced from:
_quickjs_JS_SetPropertyStr_wrapper136 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_SetPropertyUint32", referenced from:
_quickjs_JS_SetPropertyUint32_wrapper134 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_Throw", referenced from:
_quickjs_JS_Throw_wrapper90 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_ToBool", referenced from:
_quickjs_JS_ToBool_wrapper102 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_ToCStringLen2", referenced from:
_quickjs_JS_ToCString_wrapper117 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_ToFloat64", referenced from:
_quickjs_JS_ToFloat64_wrapper107 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_ToInt32", referenced from:
_quickjs_JS_ToInt32_wrapper103 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_ToInt64", referenced from:
_quickjs_JS_ToInt64_wrapper105 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_UpdateStackTop", referenced from:
_quickjs_JS_UpdateStackTop_wrapper7 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_JS_WriteObject", referenced from:
_quickjs_JS_WriteObject_wrapper185 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"___JS_FreeValue", referenced from:
_quickjs_JS_FreeValue_wrapper97 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
"_js_free", referenced from:
_quickjs_js_free_wrapper47 in Shared[arm64][9](libquickjs-kt:quickjs-cinterop-quickjs-cache.a.o)
ld: symbol(s) not found for architecture arm64
Steps to reproduce :
sourceSets
in build.gradle.kts
of the shared
modulequickJs
method in Greeting.kt
in commonMain
in shared
moduleiosApp
folderAny idea of where it comes from ?
Thanks for your help !
com.dokar.quickjs.QuickJsException: InternalError: stack overflow
at <anonymous> (main.js)
at <anonymous> (main.js)
at <anonymous> (main.js)
at <anonymous> (main.js)
at <anonymous> (main.js)
at Qu (main.js)
at <anonymous> (main.js)
at call (native)
at <anonymous> (main.js)
at Ut (main.js)
at ce (main.js)
at ve (main.js)
at <anonymous> (main.js)
at <anonymous> (main.js)
at xn (main.js)
at kn (main.js)
at <anonymous> (main.js)
at te (main.js)
at ne (main.js)
at <anonymous> (main.js)
at <anonymous> (main.js)
at <anonymous> (main.js)
at <anonymous> (main.js)
at <anonymous> (main.js)
at <anonymous> (main.js)
at <eval> (main.js:5)
Uncaught Kotlin exception: at 0 KKit 0x1032652c3 kfun:kotlin.Throwable#<init>(){} + 95
at 1 KKit 0x10325e4ef kfun:kotlin.Exception#<init>(){} + 87
at 2 KKit 0x1035e5ab3 kfun:com.dokar.quickjs.QuickJsException#<init>(kotlin.String?){} + 87
at 3 KKit 0x103604cd3 kfun:com.dokar.quickjs.bridge.newKtError#internal + 3611
at 4 KKit 0x103601fab kfun:com.dokar.quickjs.bridge#jsErrorToKtError(kotlinx.cinterop.CPointer<quickjs.JSContext>;kotlinx.cinterop.CValue<quickjs.JSValue>){}kotlin.Throwable + 5083
at 5 KKit 0x1035ff997 kfun:com.dokar.quickjs.bridge#toKtValue__at__kotlinx.cinterop.CValue<quickjs.JSValue>(kotlinx.cinterop.CPointer<quickjs.JSContext>){}kotlin.Any? + 5287
at 6 KKit 0x10361d673 kfun:com.dokar.quickjs.bridge.promiseRejectionHandler#internal + 491
at 7 KKit 0x10361d90f _717569636b6a732d6b743a717569636b6a732f55736572732f72756e6e65722f776f726b2f717569636b6a732d6b742f717569636b6a732d6b742f717569636b6a732f7372632f6e61746976654d61696e2f6b6f746c696e2f636f6d2f646f6b61722f717569636b6a732f6272696467652f70726f6d69736552656a656374696f6e48616e646c65722e6b74_knbridge0 + 307
at 8 KKit 0x103622273 _717569636b6a732d6b743a717569636b6a732f55736572732f72756e6e65722f776f726b2f717569636b6a732d6b742f717569636b6a732d6b742f717569636b6a732f7372632f6e61746976654d61696e2f6b6f746c696e2f636f6d2f646f6b61722f717569636b6a732f6272696467652f70726f6d69736552656a656374696f6e48616e646c65722e6b74_kncfun3 + 63
at 9 KKit 0x102ae122f fulfill_or_reject_promise + 347
at 10 KKit 0x102aa524f js_promise_resolve_function_call + 651
at 11 KKit 0x102a901fb JS_CallInternal + 599
at 12 KKit 0x102a8ff87 JS_Call + 107
at 13 KKit 0x102ae18db js_async_function_resume + 211
at 14 KKit 0x102aa5533 js_async_function_resolve_call + 299
at 15 KKit 0x102a901fb JS_CallInternal + 599
at 16 KKit 0x102a8ff87 JS_Call + 107
at 17 KKit 0x102ac91bb promise_reaction_job + 371
at 18 KKit 0x102a79b4b JS_ExecutePendingJob + 131
at 19 KKit 0x1035f5f4f kfun:com.dokar.quickjs.bridge#executePendingJob(kotlinx.cinterop.CPointer<quickjs.JSRuntime>){}com.dokar.quickjs.bridge.ExecuteJobResult + 847
at 20 KKit 0x1035f0503 kfun:com.dokar.quickjs.QuickJs.$invokeAsyncFunction$lambda$2COROUTINE$7.invokeSuspend#internal + 3755
at 21 KKit 0x1035f089b kfun:com.dokar.quickjs.QuickJs.invokeAsyncFunction$lambda$2#internal + 451
at 22 KKit 0x1035f0e63 kfun:com.dokar.quickjs.QuickJs.$invokeAsyncFunction$lambda$2$FUNCTION_REFERENCE$2.invoke#internal + 151
at 23 KKit 0x103390e3f kfun:kotlin.Function2#invoke(1:0;1:1){}1:2-trampoline + 115
at 24 KKit 0x10326deab kfun:kotlin.coroutines.intrinsics.object-4.invokeSuspend#internal + 731
at 25 KKit 0x10339075b kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#invokeSuspend(kotlin.Result<kotlin.Any?>){}kotlin.Any?-trampoline + 67
at 26 KKit 0x10326aaa3 kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#resumeWith(kotlin.Result<kotlin.Any?>){} + 623
at 27 KKit 0x10339083b kfun:kotlin.coroutines.Continuation#resumeWith(kotlin.Result<1:0>){}-trampoline + 99
at 28 KKit 0x10347382b kfun:kotlinx.coroutines.DispatchedTask#run(){} + 1879
at 29 KKit 0x1034a1d77 kfun:kotlinx.coroutines.Runnable#run(){}-trampoline + 91
at 30 KKit 0x10349962f kfun:kotlinx.coroutines.MultiWorkerDispatcher.$workerRunLoop$lambda$2COROUTINE$0.invokeSuspend#internal + 1467
at 31 KKit 0x10339075b kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#invokeSuspend(kotlin.Result<kotlin.Any?>){}kotlin.Any?-trampoline + 67
at 32 KKit 0x10326aaa3 kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#resumeWith(kotlin.Result<kotlin.Any?>){} + 623
at 33 KKit 0x10339083b kfun:kotlin.coroutines.Continuation#resumeWith(kotlin.Result<1:0>){}-trampoline + 99
at 34 KKit 0x10347382b kfun:kotlinx.coroutines.DispatchedTask#run(){} + 1879
at 35 KKit 0x1034a1d77 kfun:kotlinx.coroutines.Runnable#run(){}-trampoline + 91
at 36 KKit 0x10341c027 kfun:kotlinx.coroutines.EventLoopImplBase#processNextEvent(){}kotlin.Long + 287
at 37 KKit 0x1034a1ac3 kfun:kotlinx.coroutines.EventLoop#processNextEvent(){}kotlin.Long-trampoline + 51
at 38 KKit 0x103492bb3 kfun:kotlinx.coroutines.BlockingCoroutine.joinBlocking#internal + 435
at 39 KKit 0x103491a17 kfun:kotlinx.coroutines#runBlocking(kotlin.coroutines.CoroutineContext;kotlin.coroutines.SuspendFunction1<kotlinx.coroutines.CoroutineScope,0:0>){0§<kotlin.Any?>}0:0 + 1391
at 40 KKit 0x103491bf7 kfun:kotlinx.coroutines#runBlocking$default(kotlin.coroutines.CoroutineContext?;kotlin.coroutines.SuspendFunction1<kotlinx.coroutines.CoroutineScope,0:0>;kotlin.Int){0§<kotlin.Any?>}0:0 + 239
at 41 KKit 0x103497973 kfun:kotlinx.coroutines.MultiWorkerDispatcher.workerRunLoop#internal + 183
at 42 KKit 0x103498cef kfun:kotlinx.coroutines.MultiWorkerDispatcher.<init>$lambda$1$lambda$0#internal + 67
at 43 KKit 0x103499feb kfun:kotlinx.coroutines.MultiWorkerDispatcher.$<init>$lambda$1$lambda$0$FUNCTION_REFERENCE$5.invoke#internal + 71
at 44 KKit 0x10349a0bb kfun:kotlinx.coroutines.MultiWorkerDispatcher.$<init>$lambda$1$lambda$0$FUNCTION_REFERENCE$5.$<bridge-UNN>invoke(){}#internal + 71
at 45 KKit 0x10338d167 kfun:kotlin.Function0#invoke(){}1:0-trampoline + 99
at 46 KKit 0x103276b03 WorkerLaunchpad + 131
at 47 KKit 0x1033ed5f7 _ZN6Worker19processQueueElementEb + 2635
at 48 KKit 0x1033eca37 _ZN12_GLOBAL__N_113workerRoutineEPv + 219
at 49 libsystem_pthread.dylib 0x10591b413 _pthread_start + 103
at 50 libsystem_pthread.dylib 0x1059165df thread_start + 7
Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.runtime.BroadcastFrameClock@66c0528, StandaloneCoroutine{Cancelling}@d1d3290, FlushCoroutineDispatcher@6d74160]
at 0 KKit 0x10326512b kfun:kotlin.Throwable#<init>(kotlin.String?){} + 119
at 1 KKit 0x10325e577 kfun:kotlin.Exception#<init>(kotlin.String?){} + 115
at 2 KKit 0x10325e797 kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 115
at 3 KKit 0x10349b427 kfun:kotlinx.coroutines.internal.DiagnosticCoroutineContextException#<init>(kotlin.coroutines.CoroutineContext){} + 167
at 4 KKit 0x10346facb kfun:kotlinx.coroutines.internal#handleUncaughtCoroutineException(kotlin.coroutines.CoroutineContext;kotlin.Throwable){} + 647
at 5 KKit 0x103417b57 kfun:kotlinx.coroutines#handleCoroutineException(kotlin.coroutines.CoroutineContext;kotlin.Throwable){} + 515
at 6 KKit 0x10340b5a7 kfun:kotlinx.coroutines.StandaloneCoroutine.handleJobException#internal + 167
at 7 KKit 0x1034a353f kfun:kotlinx.coroutines.JobSupport#handleJobException(kotlin.Throwable){}kotlin.Boolean-trampoline + 59
at 8 KKit 0x103421d27 kfun:kotlinx.coroutines.JobSupport.finalizeFinishingState#internal + 1131
at 9 KKit 0x103429b43 kfun:kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath#internal + 2207
at 10 KKit 0x10342926b kfun:kotlinx.coroutines.JobSupport.tryMakeCompleting#internal + 755
at 11 KKit 0x103428d9b kfun:kotlinx.coroutines.JobSupport#makeCompletingOnce(kotlin.Any?){}kotlin.Any? + 379
at 12 KKit 0x10340953b kfun:kotlinx.coroutines.AbstractCoroutine#resumeWith(kotlin.Result<1:0>){} + 211
at 13 KKit 0x10339083b kfun:kotlin.coroutines.Continuation#resumeWith(kotlin.Result<1:0>){}-trampoline + 99
at 14 KKit 0x10326acbf kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#resumeWith(kotlin.Result<kotlin.Any?>){} + 1163
at 15 KKit 0x10339083b kfun:kotlin.coroutines.Continuation#resumeWith(kotlin.Result<1:0>){}-trampoline + 99
at 16 KKit 0x10347376f kfun:kotlinx.coroutines.DispatchedTask#run(){} + 1691
at 17 KKit 0x1034a1d77 kfun:kotlinx.coroutines.Runnable#run(){}-trampoline + 91
at 18 KKit 0x1039ef357 kfun:androidx.compose.ui.platform.FlushCoroutineDispatcher.dispatch$lambda$1$lambda$0#internal + 475
at 19 KKit 0x1039f08bf kfun:androidx.compose.ui.platform.FlushCoroutineDispatcher.$dispatch$lambda$1$lambda$0$FUNCTION_REFERENCE$4.invoke#internal + 75
at 20 KKit 0x1039f09bb kfun:androidx.compose.ui.platform.FlushCoroutineDispatcher.$dispatch$lambda$1$lambda$0$FUNCTION_REFERENCE$4.$<bridge-UNN>invoke(){}#internal + 71
at 21 KKit 0x10338d167 kfun:kotlin.Function0#invoke(){}1:0-trampoline + 99
at 22 KKit 0x1039eec5f kfun:androidx.compose.ui.platform.FlushCoroutineDispatcher.performRun#internal + 319
at 23 KKit 0x1039ef4df kfun:androidx.compose.ui.platform.FlushCoroutineDispatcher.dispatch$lambda$1#internal + 239
at 24 KKit 0x1039f036b kfun:androidx.compose.ui.platform.FlushCoroutineDispatcher.$dispatch$lambda$1$FUNCTION_REFERENCE$0.invoke#internal + 139
at 25 KKit 0x103390e3f kfun:kotlin.Function2#invoke(1:0;1:1){}1:2-trampoline + 115
at 26 KKit 0x10326deab kfun:kotlin.coroutines.intrinsics.object-4.invokeSuspend#internal + 731
at 27 KKit 0x10339075b kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#invokeSuspend(kotlin.Result<kotlin.Any?>){}kotlin.Any?-trampoline + 67
at 28 KKit 0x10326aaa3 kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#resumeWith(kotlin.Result<kotlin.Any?>){} + 623
at 29 KKit 0x10339083b kfun:kotlin.coroutines.Continuation#resumeWith(kotlin.Result<1:0>){}-trampoline + 99
at 30 KKit 0x10347382b kfun:kotlinx.coroutines.DispatchedTask#run(){} + 1879
at 31 KKit 0x1034a1d77 kfun:kotlinx.coroutines.Runnable#run(){}-trampoline + 91
at 32 KKit 0x10349d95f kfun:kotlinx.coroutines.DarwinMainDispatcher.dispatch$lambda$0#internal + 67
at 33 KKit 0x10349dbdb kfun:kotlinx.coroutines.DarwinMainDispatcher.$dispatch$lambda$0$FUNCTION_REFERENCE$1.invoke#internal + 71
at 34 KKit 0x10349dcab kfun:kotlinx.coroutines.DarwinMainDispatcher.$dispatch$lambda$0$FUNCTION_REFERENCE$1.$<bridge-UNN>invoke(){}#internal + 71
at 35 KKit 0x10338d167 kfun:kotlin.Function0#invoke(){}1:0-trampoline + 99
at 36 KKit 0x10349ebef _6f72672e6a6574627261696e732e6b6f746c696e783a6b6f746c696e782d636f726f7574696e65732d636f72652f6f70742f6275696c644167656e742f776f726b2f343465633665383530643563363366302f6b6f746c696e782d636f726f7574696e65732d636f72652f6e617469766544617277696e2f7372632f44697370617463686572732e6b74_knbridge13 + 191
at 37 libdispatch.dylib 0x180170103 _dispatch_call_block_and_release + 23
at 38 libdispatch.dylib 0x180171977 _dispatch_client_callout + 15
at 39 libdispatch.dylib 0x1801807c7 _dispatch_main_queue_drain + 1275
at 40 libdispatch.dylib 0x1801802bb _dispatch_main_queue_callback_4CF + 39
at 41 CoreFoundation 0x18040e95f __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 11
at 42 CoreFoundation 0x180409077 __CFRunLoopRun + 1935
at 43 CoreFoundation 0x1804084d3 CFRunLoopRunSpecific + 571
at 44 GraphicsServices 0x18ef2aae3 GSEventRunModal + 159
at 45 UIKitCore 0x1853d0a27 -[UIApplication _run] + 867
at 46 UIKitCore 0x1853d46af UIApplicationMain + 123
at 47 SwiftUI 0x1ccf100e3 OUTLINED_FUNCTION_65 + 491
at 48 SwiftUI 0x1ccf0ff8b OUTLINED_FUNCTION_65 + 147
at 49 SwiftUI 0x1ccbcd6d7 OUTLINED_FUNCTION_0 + 91
at 50 KKit 0x1028a4fb7 $s4KKit6iOSAppV5$mainyyFZ + 39
at 51 KKit 0x1028a5067 main + 11 (/Users/telephone/Code/KKit/iosApp/iosApp/iOSApp.swift:<unknown>)
at 52 dyld 0x105965543 0x0 + 4388705603
at 53 ??? 0x105a3a0df 0x0 + 4389576927
at 54 ??? 0xe544ffffffffffff 0x0 + -1926133265631019009
val js = """
var response = await kml.requestJson('https://icanhazdadjoke.com/');
let parsed = JSON.parse(response);
parsed.joke;
""".trimIndent()
val joke = quickJs {
define("kml") {
asyncFunction("requestJson") { args ->
delay(500)
"""
{"id":"bxXLeqzP7wc","joke":"Americans can't switch from pounds to kilograms overnight. That would cause mass confusion.","status":200}
""".trimIndent()
}
}
evaluate<Any?>(js)?.toString()
}
Causes this error. Not every time but frequently:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x0000000188e4aa9c, pid=63005, tid=90371
#
# JRE version: OpenJDK Runtime Environment (17.0.7) (build 17.0.7+0-17.0.7b1000.6-10550314)
# Java VM: OpenJDK 64-Bit Server VM (17.0.7+0-17.0.7b1000.6-10550314, mixed mode, tiered, compressed oops, compressed class ptrs, g1 gc, bsd-aarch64)
# Problematic frame:
# C [libsystem_platform.dylib+0xa9c] _platform_strcmp+0xc
#
# No core dump will be written. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
JNI global refs:
JNI global refs: 161, weak refs: 11
JNI global refs memory usage: 2099, weak refs: 833
OOME stack traces (most recent first):
Classloader memory used:
Loader jdk.internal.loader.ClassLoaders$AppClassLoader : 3926K
Loader bootstrap : 2694K
Loader jdk.internal.loader.ClassLoaders$PlatformClassLoader : 18987B
Loader jdk.internal.reflect.DelegatingClassLoader : 4278B
# An error report file with more information is saved as:
# /Users/dmelton/Developer/doug/kmlauncher/compose-multiplatform/composeApp/hs_err_pid63005.log
#
# If you would like to submit a bug report, please visit:
# https://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
I removed any actual networking, but simulated by that delay(500)
I try to run my project on my Android phone, but it fails with error:
2 files found with path 'lib/arm64-v8a/libquickjs.so' from inputs:
- C:\Users\Terry\.gradle\caches\8.8\transforms\d815028faf901d4d4975b34335a30e4f\transformed\quickjs-release\jni\arm64-v8a\libquickjs.so
- C:\Users\Terry\.gradle\caches\8.8\transforms\c5c5b7415d5b142347150f6c559b9ab3\transformed\zipline-release\jni\arm64-v8a\libquickjs.so
If you are using jniLibs and CMake IMPORTED targets, see
https://developer.android.com/r/tools/jniLibs-vs-imported-targets
Kotlin:
asyncFunction<Int, Unit>(it) {
res.send(it)
}
JS:
protoOf(JSImpl).version = function (res) { res(15); }
I pass the asyncFunction
defined to version
function in JS, then this exception is thrown
There are some leaks in the JS runtime after evaluation. They won't crash JS_FreeRuntime
but need to be fixed.
Currently, the evaluate
can cooperate with coroutine cancel, it will return when the current coroutine is cancelled, this is good.
BUT the async jobs triggered by evaluate
including their callbacks will last forever and continue to run after evaluate
has been cancelled, this is bad. We can say that the async jobs are leaked.
The root cause is here:
private val coroutineScope = CoroutineScope(jobDispatcher + exceptionHandler)
// ...
internal actual fun invokeAsyncFunction(
args: Array<Any?>,
block: suspend (bindingArgs: Array<Any?>) -> Any?,
) {
ensureNotClosed()
val (resolveHandle, rejectHandle) = promiseHandlesFromArgs(args)
val job = coroutineScope.launch {
try {
val result = block(args.sliceArray(2..<args.size))
jsMutex.withLock {
// Call resolve() on JNI side
invokeJsFunction(
context = context,
globals = globals,
handle = resolveHandle,
args = arrayOf(result)
)
}
} catch (e: Throwable) {
jsMutex.withLock {
// Call reject() on JNI side
invokeJsFunction(
context = context,
globals = globals,
handle = rejectHandle,
args = arrayOf(e)
)
}
}
jsMutex.withLock {
// The job is completed, see what we can do next:
// - Execute subsequent Promises
// - Cancel all jobs and fail, if rejected and JS didn't handle it
do {
val executed = executePendingJob(context, globals)
} while (executed)
}
}
jobsMutex.withLockSync { asyncJobs += job }
job.invokeOnCompletion {
jobsMutex.withLockSync { asyncJobs -= job }
}
}
invokeAsyncFunction
uses a independent CoroutineScope
instance to launch async jobs, but this CoroutineScope
instance doesn't has the coroutine Job
of evaluate
's current coroutine as its scope Job
, so all async jobs escape out of the "structured concurrency" of the evaluate
's current coroutine and won't get cancelled if evaluate
is cancelled.
The solution is quite simple: inject the Job
of evaluate
that triggers async jobs to the coroutine scope of those async jobs, then every async job triggered by an evaluate
will listen to this evaluate
's Job
and get cancelled automatically when this evaluate
is cancelled:
internal actual fun invokeAsyncFunction(
// ###################################################################
// inject the Job either through parameters or through outside context
evaluateJob: Job,
// ###################################################################
args: Array<Any?>,
block: suspend (bindingArgs: Array<Any?>) -> Any?,
) {
ensureNotClosed()
val (resolveHandle, rejectHandle) = promiseHandlesFromArgs(args)
// ###################################################################
// use the evaluate Job as the parent Job of this async job
val job = coroutineScope.launch(evaluateJob) {
// ###################################################################
// ............
}
jobsMutex.withLockSync { asyncJobs += job }
job.invokeOnCompletion {
jobsMutex.withLockSync { asyncJobs -= job }
}
}
Now our async jobs will get cancelled automatically, so we can wait for them in evaluate
even if we are in cancelled state:
private suspend fun awaitAsyncJobs() {
jsMutex.withLock {
do {
// Execute JS Promises, putting this in while(true) is unnecessary
// since we have the same loop after every asyncFunction call
val executed = executePendingJob(context, globals)
} while (executed)
}
// ######################################################################
// This is important.
//
// We have to wait for all async jobs to get completed (even if they are
// cancelled) before we return, so the code here must continue to run
// even if we are in cancelled state.
withContext(NonCancellable){
// ######################################################################
while (true) {
val jobs = jobsMutex.withLock { asyncJobs.filter { it.isActive } }
if (jobs.isEmpty()) {
// No jobs to run
break
}
jobs.joinAll()
}
}
}
Additionally, even when evaluate
is cancelled, the sync JS code must continue to run to push the JS code state to the correct final state so we can make sure no pending jobs are leaked, and JS code is not in a strange middle state that could probably causes strange bugs. All the clean-up steps must run as usual too:
internal actual fun invokeAsyncFunction(
// ###################################################################
// inject the Job either through parameters or through outside context
evaluateJob: Job,
// ###################################################################
args: Array<Any?>,
block: suspend (bindingArgs: Array<Any?>) -> Any?,
) {
ensureNotClosed()
val (resolveHandle, rejectHandle) = promiseHandlesFromArgs(args)
// ###################################################################
// use the evaluate Job as the parent Job of this async job
val job = coroutineScope.launch(evaluateJob) {
// ###################################################################
try {
val result = block(args.sliceArray(2..<args.size))
// ###################################################################
// JS sync code
withContext(NonCancellable){
// ###################################################################
jsMutex.withLock {
// Call resolve() on JNI side
invokeJsFunction(
context = context,
globals = globals,
handle = resolveHandle,
args = arrayOf(result)
)
}
}
} catch (e: Throwable) {
// ###################################################################
// JS sync code
withContext(NonCancellable) {
// ###################################################################
jsMutex.withLock {
// Call reject() on JNI side
invokeJsFunction(
context = context,
globals = globals,
handle = rejectHandle,
args = arrayOf(e)
)
}
}
}
// ###################################################################
// JS sync code
withContext(NonCancellable) {
// ###################################################################
jsMutex.withLock {
// The job is completed, see what we can do next:
// - Execute subsequent Promises
// - Cancel all jobs and fail, if rejected and JS didn't handle it
do {
val executed = executePendingJob(context, globals)
} while (executed)
}
}
}
jobsMutex.withLockSync { asyncJobs += job }
job.invokeOnCompletion {
jobsMutex.withLockSync { asyncJobs -= job }
}
}
private suspend fun awaitAsyncJobs() {
// ###################################################################
// JS sync code
withContext(NonCancellable) {
// ###################################################################
jsMutex.withLock {
do {
// Execute JS Promises, putting this in while(true) is unnecessary
// since we have the same loop after every asyncFunction call
val executed = executePendingJob(context, globals)
} while (executed)
}
}
// ######################################################################
// This is important.
//
// We have to wait for all async jobs to get completed (even if they are
// cancelled) before we return, so the code here must continue to run
// even if we are in cancelled state.
withContext(NonCancellable){
// ######################################################################
while (true) {
val jobs = jobsMutex.withLock { asyncJobs.filter { it.isActive } }
if (jobs.isEmpty()) {
// No jobs to run
break
}
jobs.joinAll()
}
}
}
private suspend fun evalAndAwait(evalBlock: suspend () -> Any?): Any? {
ensureNotClosed()
evalException = null
// ###################################################################
// NonCancellable to avoid loadModules() stops at a middle state
withContext(NonCancellable) {
// ###################################################################
loadModules()
}
val result = jsResultMutex.withLock {
jsMutex.withLock {
// ###################################################################
// NonCancellable to avoid evalBlock() stops at a middle state
withContext(NonCancellable) {
// ###################################################################
evalBlock()
}
}
// ###################################################################
// JS sync code
withContext(NonCancellable) {
// ###################################################################
awaitAsyncJobs()
}
// ###################################################################
// Clean-up run as usual
withContext(NonCancellable) {
// ###################################################################
jsMutex.withLock { getEvaluateResult(context, globals) }
}
}
handleException()
return result
}
Exception in thread "main" java.lang.IllegalStateException: Could not find 'libquickjs_ios_aarch64.a' binary in neither of [native/build/static_libs/]
at org.jetbrains.kotlin.native.interop.gen.LibraryUtilsKt.resolveLibraries(LibraryUtils.kt:31)
at org.jetbrains.kotlin.native.interop.gen.jvm.MainKt.processCLib(main.kt:459)
at org.jetbrains.kotlin.native.interop.gen.jvm.MainKt.processCLibSafe(main.kt:247)
at org.jetbrains.kotlin.native.interop.gen.jvm.MainKt.access$processCLibSafe(main.kt:1)
at org.jetbrains.kotlin.native.interop.gen.jvm.Interop.interop(main.kt:105)
at org.jetbrains.kotlin.cli.utilities.InteropCompilerKt.invokeInterop(InteropCompiler.kt:49)
at org.jetbrains.kotlin.cli.utilities.MainKt.mainImpl(main.kt:23)
at org.jetbrains.kotlin.cli.utilities.MainKt.main(main.kt:44)
Warning: Failed to generate cinterop for :quickjs:cinteropQuickjsIosArm64: Process 'command '/Users/telephone/Applications/Android Studio Koala Feature Drop 2024.1.2 Canary 8.app/Contents/jbr/Contents/Home/bin/java'' finished with non-zero exit value 1
Failed to generate cinterop for :quickjs:cinteropQuickjsIosArm64: Process 'command '/Users/telephone/Applications/Android Studio Koala Feature Drop 2024.1.2 Canary 8.app/Contents/jbr/Contents/Home/bin/java'' finished with non-zero exit value 1
org.gradle.process.internal.ExecException: Process 'command '/Users/telephone/Applications/Android Studio Koala Feature Drop 2024.1.2 Canary 8.app/Contents/jbr/Contents/Home/bin/java'' finished with non-zero exit value 1
at org.gradle.process.internal.DefaultExecHandle$ExecResultImpl.assertNormalExitValue(DefaultExecHandle.java:442)
at org.gradle.process.internal.DefaultJavaExecAction.execute(DefaultJavaExecAction.java:52)
at org.gradle.process.internal.DefaultExecActionFactory.javaexec(DefaultExecActionFactory.java:195)
at org.gradle.process.internal.DefaultExecOperations.javaexec(DefaultExecOperations.java:42)
at org.jetbrains.kotlin.compilerRunner.KotlinToolRunner$GradleExecutionContext$Companion$fromTaskContext$2.invoke(KotlinToolRunner.kt:70)
at org.jetbrains.kotlin.compilerRunner.KotlinToolRunner$GradleExecutionContext$Companion$fromTaskContext$2.invoke(KotlinToolRunner.kt:70)
at org.jetbrains.kotlin.compilerRunner.KotlinToolRunner.runViaExec(KotlinToolRunner.kt:175)
at org.jetbrains.kotlin.compilerRunner.KotlinToolRunner.run(KotlinToolRunner.kt:142)
at org.jetbrains.kotlin.compilerRunner.KotlinNativeToolRunner.run(nativeToolRunners.kt:153)
at org.jetbrains.kotlin.compilerRunner.KotlinNativeCInteropRunner$Companion$run$1.invoke(nativeToolRunners.kt:222)
at org.jetbrains.kotlin.compilerRunner.KotlinNativeCInteropRunner$Companion$run$1.invoke(nativeToolRunners.kt:222)
at org.jetbrains.kotlin.gradle.targets.native.tasks.IdeaSyncKotlinNativeCInteropRunnerExecutionContext.runWithContext(CInteropRunnerExecutionContextFactory.kt:51)
at org.jetbrains.kotlin.compilerRunner.KotlinNativeCInteropRunner$Companion.run(nativeToolRunners.kt:222)
at org.jetbrains.kotlin.gradle.tasks.CInteropProcess$processInterop$1.invoke(KotlinNativeTasks.kt:1216)
at org.jetbrains.kotlin.gradle.tasks.CInteropProcess$processInterop$1.invoke(KotlinNativeTasks.kt:1208)
at org.jetbrains.kotlin.compilerRunner.ReportUtilsKt.addBuildMetricsForTaskAction(reportUtils.kt:261)
at org.jetbrains.kotlin.gradle.tasks.CInteropProcess.processInterop(KotlinNativeTasks.kt:1208)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:125)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
at org.gradle.api.internal.tasks.execution.TaskExecution$3.run(TaskExecution.java:244)
at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
at org.gradle.api.internal.tasks.execution.TaskExecution.executeAction(TaskExecution.java:229)
at org.gradle.api.internal.tasks.execution.TaskExecution.executeActions(TaskExecution.java:212)
at org.gradle.api.internal.tasks.execution.TaskExecution.executeWithPreviousOutputFiles(TaskExecution.java:195)
at org.gradle.api.internal.tasks.execution.TaskExecution.execute(TaskExecution.java:162)
at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:105)
at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:44)
at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:59)
at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:56)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:56)
at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:44)
at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:41)
at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:74)
at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55)
at org.gradle.internal.execution.steps.PreCreateOutputParentsStep.execute(PreCreateOutputParentsStep.java:50)
at org.gradle.internal.execution.steps.PreCreateOutputParentsStep.execute(PreCreateOutputParentsStep.java:28)
at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:67)
at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:37)
at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:61)
at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:26)
at org.gradle.internal.execution.steps.CaptureOutputsAfterExecutionStep.execute(CaptureOutputsAfterExecutionStep.java:67)
at org.gradle.internal.execution.steps.CaptureOutputsAfterExecutionStep.execute(CaptureOutputsAfterExecutionStep.java:45)
at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:40)
at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:29)
at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:189)
at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$1(BuildCacheStep.java:75)
at org.gradle.internal.Either$Right.fold(Either.java:175)
at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:62)
at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:73)
at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:48)
at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:46)
at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:35)
at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:76)
at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$2(SkipUpToDateStep.java:54)
at java.base/java.util.Optional.orElseGet(Unknown Source)
at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:54)
at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:36)
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37)
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27)
at org.gradle.internal.execution.steps.ResolveIncrementalCachingStateStep.executeDelegate(ResolveIncrementalCachingStateStep.java:49)
at org.gradle.internal.execution.steps.ResolveIncrementalCachingStateStep.executeDelegate(ResolveIncrementalCachingStateStep.java:27)
at org.gradle.internal.execution.steps.AbstractResolveCachingStateStep.execute(AbstractResolveCachingStateStep.java:71)
at org.gradle.internal.execution.steps.AbstractResolveCachingStateStep.execute(AbstractResolveCachingStateStep.java:39)
at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:65)
at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:36)
at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:106)
at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:55)
at org.gradle.internal.execution.steps.AbstractCaptureStateBeforeExecutionStep.execute(AbstractCaptureStateBeforeExecutionStep.java:64)
at org.gradle.internal.execution.steps.AbstractCaptureStateBeforeExecutionStep.execute(AbstractCaptureStateBeforeExecutionStep.java:43)
at org.gradle.internal.execution.steps.AbstractSkipEmptyWorkStep.executeWithNonEmptySources(AbstractSkipEmptyWorkStep.java:125)
at org.gradle.internal.execution.steps.AbstractSkipEmptyWorkStep.execute(AbstractSkipEmptyWorkStep.java:56)
at org.gradle.internal.execution.steps.AbstractSkipEmptyWorkStep.execute(AbstractSkipEmptyWorkStep.java:36)
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38)
at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:36)
at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:23)
at org.gradle.internal.execution.steps.HandleStaleOutputsStep.execute(HandleStaleOutputsStep.java:75)
at org.gradle.internal.execution.steps.HandleStaleOutputsStep.execute(HandleStaleOutputsStep.java:41)
at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.lambda$execute$0(AssignMutableWorkspaceStep.java:35)
at org.gradle.api.internal.tasks.execution.TaskExecution$4.withWorkspace(TaskExecution.java:289)
at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.execute(AssignMutableWorkspaceStep.java:31)
at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.execute(AssignMutableWorkspaceStep.java:22)
at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:40)
at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:23)
at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.lambda$execute$2(ExecuteWorkBuildOperationFiringStep.java:67)
at java.base/java.util.Optional.orElseGet(Unknown Source)
at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:67)
at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:39)
at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:46)
at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:34)
at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:48)
at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:35)
at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:61)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:127)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:116)
at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:74)
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:42)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:331)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:318)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.lambda$execute$0(DefaultTaskExecutionGraph.java:314)
at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:80)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:314)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:303)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:463)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:380)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
can't know what is not a function, how can I fix it if I don't know the variable or the function name?
./quickjs/native/cmake/zig-ar.sh
./quickjs/native/cmake/zig-ranlib.sh
Have you tried to use a suspend function via reflection, as shown below? I'm getting an error "parameter count mismatched"
class Http {
suspend fun fetch(url: String) = "..."
}
quickJs {
define<Http>("http", Http())
evaluate<Any?>(
"""
await http.fetch("https://www.example.com")
""".trimIndent()
)
}
Can you add a section to the README on how to properly handle js exceptions?
This does not work if an exception occurs in the js code. An error is thrown but this does not catch it:
val result = try {
wrapper.evaluateJs(jscode)
}
catch (e: Exception) {
Logger.e { "Javascript error: $e" }
null
}
throws this error:
Exception in thread "DefaultDispatcher-worker-10" java.lang.RuntimeException: Exception while trying to handle coroutine exception
at kotlinx.coroutines.CoroutineExceptionHandlerKt.handlerException(CoroutineExceptionHandler.kt:33)
at kotlinx.coroutines.internal.CoroutineExceptionHandlerImpl_commonKt.handleUncaughtCoroutineException(CoroutineExceptionHandlerImpl.common.kt:38)
at kotlinx.coroutines.CoroutineExceptionHandlerKt.handleCoroutineException(CoroutineExceptionHandler.kt:28)
at kotlinx.coroutines.StandaloneCoroutine.handleJobException(Builders.common.kt:190)
at kotlinx.coroutines.JobSupport.finalizeFinishingState(JobSupport.kt:228)
at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath(JobSupport.kt:907)
at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:864)
at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:829)
at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:97)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
at kotlinx.coroutines.internal.ScopeCoroutine.afterResume(Scopes.kt:28)
at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:99)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:102)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:585)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:802)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:706)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:693)
Suppressed: java.lang.Error: Error: test
at dictionaryapi (main.js:5)
at <anonymous> (main.js:12)
at search (main.js)
at <eval> (main.js:2)
at com.dokar.quickjs.QuickJs.getEvaluateResult(Native Method)
at com.dokar.quickjs.QuickJs.evalAndAwait(QuickJs.jni.kt:220)
at com.dokar.quickjs.QuickJs.evaluateInternal(QuickJs.jni.kt:210)
...
This js code works as expected when I define my own host.log function, but it would be nicer if I could catch the error in kotlin:
try {
doStuff();
}
catch (err) {
host.log("caught js error: ", err);
}
thanks for all your quick updates!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.