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) 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"); + 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 +//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"]; @@ -35,46 +79,50 @@ function caml_weak_create (n) { } //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"); - x[caml_ephe_key_offset + i] = v; + 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"); - return (x[caml_ephe_key_offset + i ]===undefined)?0:x[caml_ephe_key_offset + i]; + var weak = x[caml_ephe_key_offset + i ]; + 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) { - if(x[caml_ephe_key_offset + i]!==undefined && x[caml_ephe_key_offset + i] !==0) - return 1; - else +function caml_ephe_check_key(x, i) { + var weak = x[caml_ephe_key_offset + i]; + 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, @@ -82,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; } @@ -141,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; }