about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2023-06-05 19:42:52 +0200
committerbptato <nincsnevem662@gmail.com>2023-06-05 19:45:06 +0200
commit2307d2ad0a9f89cf625fbad2bbf6d5a81d62d812 (patch)
tree710e77c043ceb14c27c4910aec0992b736c47ae4 /src
parent9316348a1fbd73c1b9f696cfdb06ca5e08175922 (diff)
downloadchawan-2307d2ad0a9f89cf625fbad2bbf6d5a81d62d812.tar.gz
Pre-allocate alternative objects for finalizer
Not sure if this helps
Diffstat (limited to 'src')
-rw-r--r--src/js/javascript.nim15
1 files changed, 12 insertions, 3 deletions
diff --git a/src/js/javascript.nim b/src/js/javascript.nim
index 6b83517e..4eefd1b6 100644
--- a/src/js/javascript.nim
+++ b/src/js/javascript.nim
@@ -74,7 +74,12 @@ type
     Array_prototype_values: JSValue
 
   JSRuntimeOpaque* = ref object
-    plist: Table[pointer, pointer]
+    plist: Table[pointer, pointer] # Nim, JS
+    # Allocations in a finalizers lead to serious problems, so we pre-allocate
+    # alternative objects we can copy ours into when a JS object outlives its
+    # nim counterpart.
+    # In other words, it's an ugly hack on top of an ugly hack.
+    altplist: Table[pointer, pointer] # JS, Nim
     flist: seq[seq[JSCFunctionListEntry]]
     fins: Table[JSClassID, proc(val: JSValue)]
 
@@ -189,7 +194,11 @@ proc setOpaque*[T](ctx: JSContext, val: JSValue, opaque: T) =
   let header = cast[ptr JSRefCountHeader](p)
   inc header.ref_count # add jsvalue reference
   rtOpaque.plist[cast[pointer](opaque)] = p
+  let alt = new(T)
+  GC_ref(alt)
+  rtOpaque.altplist[p] = cast[pointer](alt)
   JS_SetOpaque(val, cast[pointer](opaque))
+  GC_ref(opaque)
 
 func isGlobal*(ctx: JSContext, class: string): bool =
   assert class != ""
@@ -1599,12 +1608,12 @@ proc nim_finalize_for_js[T](obj: T) =
         # Now it's on JS to decrement the new object's refcount.
         # (Yeah, it's an ugly hack, but I couldn't come up with anything
         # better.)
-        let newop = new(T)
+        let newop = cast[T](rtOpaque.altplist[p])
         newop[] = obj[]
-        GC_ref(newop)
         let np = cast[pointer](newop)
         JS_SetOpaque(val, np)
         rtOpaque.plist[np] = p
+        rtOpaque.altplist.del(p)
       else:
         # This was the last reference to the JS value.
         # First, trigger the custom finalizer (if there is one.)