From 45e136e1952a70411882241a313e3dedc78cfdef Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Sat, 30 Apr 2022 20:12:26 +0200 Subject: [PATCH 1/3] Runtime: proper semantic for weak --- README.md | 2 -- manual/overview.wiki | 2 -- runtime/weak.js | 26 +++++++++++++++++++++----- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 81ea86e9b4..f96a668608 100644 --- a/README.md +++ b/README.md @@ -72,8 +72,6 @@ js_of_ocaml cubes.byte Most of the OCaml standard library is supported. However, -- Weak semantic cannot be implemented using JavaScript. A dummy implementation - is provided. - Most of the Sys module is not supported. Extra libraries distributed with OCaml (such as Thread) are not supported in diff --git a/manual/overview.wiki b/manual/overview.wiki index 748ec59c57..dfb287d109 100644 --- a/manual/overview.wiki +++ b/manual/overview.wiki @@ -60,8 +60,6 @@ You can find an OCaml toplevel running in the browser <= x.length) caml_invalid_argument ("Weak.set"); - x[caml_ephe_key_offset + i] = v; + if(v == 0) { + if(x[caml_ephe_key_offset + i] instanceof globalThis.WeakRef && x[1].unregister) + x[1].unregister(x[caml_ephe_key_offset + i].deref()). + x[caml_ephe_key_offset + i] = undefined; + } + else if (v[1] instanceof Object && globalThis.WeakRef) { + if(x[1].register) x[1].register(v[1], undefined, v[1]); + x[caml_ephe_key_offset + i] = new globalThis.WeakRef(v[1]); + } + else x[caml_ephe_key_offset + i] = v[1]; return 0; } //Provides: caml_weak_get @@ -47,7 +59,9 @@ function caml_weak_set(x, i, v) { function caml_weak_get(x, i) { if(i < 0 || caml_ephe_key_offset + i >= x.length) caml_invalid_argument ("Weak.get_key"); - return (x[caml_ephe_key_offset + i ]===undefined)?0:x[caml_ephe_key_offset + i]; + var weak = x[caml_ephe_key_offset + i ]; + if(weak instanceof globalThis.WeakRef) weak = weak.deref(); + return (weak===undefined)?0:[0, weak]; } //Provides: caml_weak_get_copy //Requires: caml_weak_get,caml_ephe_key_offset @@ -65,7 +79,9 @@ function caml_weak_get_copy(x, i) { //Provides: caml_weak_check mutable //Requires: caml_ephe_key_offset function caml_weak_check(x, i) { - if(x[caml_ephe_key_offset + i]!==undefined && x[caml_ephe_key_offset + i] !==0) + var weak = x[caml_ephe_key_offset + i]; + if(weak instanceof globalThis.WeakRef) weak = weak.deref(); + if(weak!==undefined) return 1; else return 0; From 29667c618b49653f7beb084a4754b42451fafb55 Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Mon, 2 May 2022 11:08:31 +0200 Subject: [PATCH 2/3] Runtime: improve weak/ephe implementation --- runtime/weak.js | 170 ++++++++++++++++++++++++++++++------------------ 1 file changed, 107 insertions(+), 63 deletions(-) diff --git a/runtime/weak.js b/runtime/weak.js index a108ecc389..f510cd4193 100644 --- a/runtime/weak.js +++ b/runtime/weak.js @@ -25,72 +25,104 @@ var caml_ephe_key_offset = 3 //Provides: caml_ephe_data_offset var caml_ephe_data_offset = 2 +//Provides: caml_ephe_set_key +//Requires: caml_invalid_argument, caml_ephe_key_offset +function caml_ephe_set_key(x, i, v) { + if(i < 0 || caml_ephe_key_offset + i >= x.length) + caml_invalid_argument ("Weak.set"); + if (v instanceof Object && globalThis.WeakRef) { + if(x[1].register) x[1].register(v, undefined, v); + x[caml_ephe_key_offset + i] = new globalThis.WeakRef(v); + } + else x[caml_ephe_key_offset + i] = v; + return 0 +} + +//Provides: caml_ephe_unset_key +//Requires: caml_invalid_argument, caml_ephe_key_offset +function caml_ephe_unset_key(x, i) { + if(i < 0 || caml_ephe_key_offset + i >= x.length) + caml_invalid_argument ("Weak.set"); + if(globalThis.WeakRef && x[caml_ephe_key_offset + i] instanceof globalThis.WeakRef && x[1].unregister) { + var old = x[caml_ephe_key_offset + i].deref(); + if(old !== undefined) { + var count = 0 + for(var j = caml_ephe_key_offset; j < x.length; j++){ + var key = x[j]; + if(key instanceof globalThis.WeakRef){ + key = key.deref() + if(key === old) count++; + } + } + if(count == 1) x[1].unregister(old); + } + } + x[caml_ephe_key_offset + i] = undefined; + return 0 +} + + +//Provides: caml_ephe_create +//Requires: caml_weak_create, caml_ephe_data_offset +function caml_ephe_create (n) { + var x = caml_weak_create(n); + return x; +} + //Provides: caml_weak_create //Requires: caml_ephe_key_offset, caml_invalid_argument,caml_ephe_data_offset function caml_weak_create (n) { if (n < 0) caml_invalid_argument ("Weak.create"); var x = [251,"caml_ephe_list_head"]; - if(globalThis.FinalizationRegistry){ - x[1] = new globalThis.FinalizationRegistry(function () { x[caml_ephe_data_offset] = undefined}); - } x.length = caml_ephe_key_offset + n; return x; } //Provides: caml_weak_set -//Requires: caml_ephe_key_offset, caml_invalid_argument +//Requires: caml_invalid_argument +//Requires: caml_ephe_set_key, caml_ephe_unset_key function caml_weak_set(x, i, v) { - if(i < 0 || caml_ephe_key_offset + i >= x.length) - caml_invalid_argument ("Weak.set"); - if(v == 0) { - if(x[caml_ephe_key_offset + i] instanceof globalThis.WeakRef && x[1].unregister) - x[1].unregister(x[caml_ephe_key_offset + i].deref()). - x[caml_ephe_key_offset + i] = undefined; - } - else if (v[1] instanceof Object && globalThis.WeakRef) { - if(x[1].register) x[1].register(v[1], undefined, v[1]); - x[caml_ephe_key_offset + i] = new globalThis.WeakRef(v[1]); - } - else x[caml_ephe_key_offset + i] = v[1]; + if(v == 0) caml_ephe_unset_key(x,i) + else caml_ephe_set_key(x,i,v[1]) return 0; } -//Provides: caml_weak_get +//Provides: caml_ephe_get_key //Requires: caml_ephe_key_offset, caml_invalid_argument -function caml_weak_get(x, i) { +function caml_ephe_get_key(x, i) { if(i < 0 || caml_ephe_key_offset + i >= x.length) caml_invalid_argument ("Weak.get_key"); var weak = x[caml_ephe_key_offset + i ]; - if(weak instanceof globalThis.WeakRef) weak = weak.deref(); + if(globalThis.WeakRef && weak instanceof globalThis.WeakRef) weak = weak.deref(); return (weak===undefined)?0:[0, weak]; } -//Provides: caml_weak_get_copy -//Requires: caml_weak_get,caml_ephe_key_offset +//Provides: caml_ephe_get_key_copy +//Requires: caml_ephe_get_key,caml_ephe_key_offset //Requires: caml_obj_dup, caml_invalid_argument -function caml_weak_get_copy(x, i) { +function caml_ephe_get_key_copy(x, i) { if(i < 0 || caml_ephe_key_offset + i >= x.length) caml_invalid_argument ("Weak.get_copy"); - var y = caml_weak_get(x, i); + var y = caml_ephe_get_key(x, i); if (y === 0) return y; var z = y[1]; if (z instanceof Array) return [0, caml_obj_dup(z)]; return y; } -//Provides: caml_weak_check mutable +//Provides: caml_ephe_check_key mutable //Requires: caml_ephe_key_offset -function caml_weak_check(x, i) { +function caml_ephe_check_key(x, i) { var weak = x[caml_ephe_key_offset + i]; - if(weak instanceof globalThis.WeakRef) weak = weak.deref(); - if(weak!==undefined) - return 1; - else + if(globalThis.WeakRef && weak instanceof globalThis.WeakRef) weak = weak.deref(); + if(weak===undefined) return 0; + else + return 1; } -//Provides: caml_weak_blit +//Provides: caml_ephe_blit_key //Requires: caml_array_blit //Requires: caml_ephe_key_offset -function caml_weak_blit(a1, i1, a2, i2, len) { +function caml_ephe_blit_key(a1, i1, a2, i2, len) { // minus one because caml_array_blit works on ocaml array caml_array_blit(a1, caml_ephe_key_offset + i1 - 1, a2, caml_ephe_key_offset + i2 - 1, @@ -98,42 +130,29 @@ function caml_weak_blit(a1, i1, a2, i2, len) { return 0; } -//Provides: caml_ephe_create -//Requires: caml_weak_create -var caml_ephe_create = caml_weak_create - -//Provides: caml_ephe_blit_key -//Requires: caml_weak_blit -var caml_ephe_blit_key = caml_weak_blit - -//Provides: caml_ephe_get_key -//Requires: caml_weak_get -var caml_ephe_get_key = caml_weak_get +//Provides: caml_weak_blit +//Requires: caml_ephe_blit_key +var caml_weak_blit = caml_ephe_blit_key -//Provides: caml_ephe_get_key_copy -//Requires: caml_weak_get_copy -var caml_ephe_get_key_copy = caml_weak_get_copy +//Provides: caml_weak_get +//Requires: caml_ephe_get_key +var caml_weak_get = caml_ephe_get_key -//Provides: caml_ephe_check_key -//Requires: caml_weak_check -var caml_ephe_check_key = caml_weak_check -//Provides: caml_ephe_set_key -//Requires: caml_weak_set -function caml_ephe_set_key(x, i, v) { - return caml_weak_set(x, i, [0, v]) -} +//Provides: caml_weak_get_copy +//Requires: caml_ephe_get_key_copy +var caml_weak_get_copy = caml_ephe_get_key_copy -//Provides: caml_ephe_unset_key -//Requires: caml_weak_set -function caml_ephe_unset_key(x, i) { - return caml_weak_set(x, i, 0) -} +//Provides: caml_weak_check +//Requires: caml_ephe_check_key +var caml_weak_check = caml_ephe_check_key //Provides: caml_ephe_blit_data -//Requires: caml_ephe_data_offset +//Requires: caml_ephe_data_offset, caml_ephe_set_data, caml_ephe_unset_data function caml_ephe_blit_data(src, dst){ - dst[caml_ephe_data_offset] = src[caml_ephe_data_offset]; + var n = src[caml_ephe_data_offset]; + if(n === undefined) caml_ephe_unset_data(dst); + else caml_ephe_set_data(dst, n); return 0; } @@ -157,15 +176,40 @@ function caml_ephe_get_data_copy(x){ } //Provides: caml_ephe_set_data -//Requires: caml_ephe_data_offset +//Requires: caml_ephe_data_offset, caml_ephe_key_offset, caml_ephe_unset_data function caml_ephe_set_data(x, data){ + if(globalThis.FinalizationRegistry && globalThis.WeakRef) { + if(! (x[1] instanceof globalThis.FinalizationRegistry)) { + x[1] = new globalThis.FinalizationRegistry(function () { caml_ephe_unset_data(x) }); + //register all keys + for(var j = caml_ephe_key_offset; j < x.length; j++){ + var key = x[j]; + if(key instanceof globalThis.WeakRef) { + key = key.deref(); + if(key) x[1].register(key, undefined, key); + } + } + } + } x[caml_ephe_data_offset] = data; return 0; } //Provides: caml_ephe_unset_data -//Requires: caml_ephe_data_offset -function caml_ephe_unset_data(x, data){ +//Requires: caml_ephe_data_offset, caml_ephe_key_offset +function caml_ephe_unset_data(x){ + if(globalThis.FinalizationRegistry && globalThis.WeakRef) { + if(x[1] instanceof globalThis.FinalizationRegistry){ + //unregister all keys + for(var j = caml_ephe_key_offset; j < x.length; j++){ + var key = x[j]; + if(key instanceof globalThis.WeakRef) { + key = key.deref(); + if(key) x[1].unregister(key); + } + } + } + } x[caml_ephe_data_offset] = undefined; return 0; } From 621da6db8d4702c122434dcc56e9f0f4156a9d4b Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Mon, 2 May 2022 13:09:54 +0200 Subject: [PATCH 3/3] Changes --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index cd135e81f5..bf1790c9b7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ * Misc: use 4.14 in the CI * Lib: add missing options for Intl.DateTimeFormat * Lib: add missing options for Intl.NumberFormat +* Runtime: Implement weak semantic for weak and ephemeron ## Bug fixes * Compiler: fix rewriter bug in share_constant (fix #1247)