about summary refs log tree commit diff stats
path: root/src/bindings
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-06-03 20:28:29 +0200
committerbptato <nincsnevem662@gmail.com>2024-06-03 20:28:29 +0200
commitdfb03387691e72f8832734255765ddfdd38db372 (patch)
tree31f2c489859aa8bd7d7bc2b3b1854f11708b45f2 /src/bindings
parent34b0abd1a5811afa88b16442c0dc327881456d8f (diff)
downloadchawan-dfb03387691e72f8832734255765ddfdd38db372.tar.gz
js: fix runtime cleanup
This is a minefield.

Intuitively, you would think that just clearing the opaque and manually
freeing registered object should be enough. Unfortunately, this is
not true; we do not store whether we are actually holding a reference to
registered JS objects, so this approach leads to double frees.

Instead, we add a QJS callback that is called right after the final
GC cleanup, but before the list_free assertion. This way, we can be sure
that any object still in our registry is referenced by us, and can
therefore unreference them safely.
Diffstat (limited to 'src/bindings')
-rw-r--r--src/bindings/quickjs.nim4
1 files changed, 4 insertions, 0 deletions
diff --git a/src/bindings/quickjs.nim b/src/bindings/quickjs.nim
index 836bedac..20dd048b 100644
--- a/src/bindings/quickjs.nim
+++ b/src/bindings/quickjs.nim
@@ -132,6 +132,8 @@ type
   JSClassExoticMethodsConst* {.importc: "const JSClassExoticMethods *",
     header: qjsheader.} = ptr JSClassExoticMethods
 
+  JSRuntimeCleanUpFunc* {.importc.} = proc(rt: JSRuntime) {.cdecl.}
+
   JSClassDef* {.importc, header: qjsheader.} = object
     class_name*: cstring
     finalizer*: JSClassFinalizer
@@ -555,6 +557,8 @@ proc JS_ExecutePendingJob*(rt: JSRuntime; pctx: ptr JSContext): cint
 
 proc JS_GetRuntimeOpaque*(rt: JSRuntime): pointer
 proc JS_SetRuntimeOpaque*(rt: JSRuntime; p: pointer)
+proc JS_SetRuntimeCleanUpFunc*(rt: JSRuntime;
+  cleanup_func: JSRuntimeCleanUpFunc)
 
 proc JS_SetContextOpaque*(ctx: JSContext; opaque: pointer)
 proc JS_GetContextOpaque*(ctx: JSContext): pointer