Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions manual/overview.wiki
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ You can find an OCaml toplevel running in the browser <<a_file src="toplevel/ind
== Supported features ==

Most of the OCaml standard library is supported. However,
* Weak semantic cannot be implemented using JavaScript.
A dummy implementation is provided.
* Most of Sys module is not supported.

Extra libraries distributed with Ocaml (such as Thread) are not
Expand Down
164 changes: 112 additions & 52 deletions runtime/weak.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,60 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

// Weak API, but without the weak semantics
// Weak API

//Provides: caml_ephe_key_offset
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
//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"];
Expand All @@ -35,89 +79,80 @@ 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,
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;
}

Expand All @@ -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;
}
Expand Down