Skip to content

Commit 00a38d0

Browse files
committed
Runtime: reimplement weak/ephemeron
1 parent 59f4693 commit 00a38d0

File tree

1 file changed

+114
-75
lines changed

1 file changed

+114
-75
lines changed

runtime/weak.js

Lines changed: 114 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -25,79 +25,86 @@ var caml_ephe_key_offset = 3;
2525
//Provides: caml_ephe_data_offset
2626
var caml_ephe_data_offset = 2;
2727

28+
//Provides: caml_ephe_none
29+
var caml_ephe_none = { caml_ephe_none: 0 };
30+
2831
//Provides: caml_ephe_set_key
2932
//Requires: caml_invalid_argument, caml_ephe_key_offset
33+
//Requires: caml_ephe_get_data
34+
//Requires: caml_ephe_set_data_opt
3035
function caml_ephe_set_key(x, i, v) {
3136
if (i < 0 || caml_ephe_key_offset + i >= x.length)
3237
caml_invalid_argument("Weak.set");
33-
if (v instanceof Object && globalThis.WeakRef) {
34-
if (x[1].register) x[1].register(v, undefined, v);
35-
x[caml_ephe_key_offset + i] = new globalThis.WeakRef(v);
36-
} else x[caml_ephe_key_offset + i] = v;
38+
var old = caml_ephe_get_data(x);
39+
if (v instanceof Object && globalThis.WeakRef) v = new globalThis.WeakRef(v);
40+
x[caml_ephe_key_offset + i] = v;
41+
caml_ephe_set_data_opt(x, old);
3742
return 0;
3843
}
3944

4045
//Provides: caml_ephe_unset_key
4146
//Requires: caml_invalid_argument, caml_ephe_key_offset
47+
//Requires: caml_ephe_get_data
48+
//Requires: caml_ephe_set_data_opt
49+
//Requires: caml_ephe_none
4250
function caml_ephe_unset_key(x, i) {
4351
if (i < 0 || caml_ephe_key_offset + i >= x.length)
4452
caml_invalid_argument("Weak.set");
45-
if (
46-
globalThis.WeakRef &&
47-
x[caml_ephe_key_offset + i] instanceof globalThis.WeakRef &&
48-
x[1].unregister
49-
) {
50-
var old = x[caml_ephe_key_offset + i].deref();
51-
if (old !== undefined) {
52-
var count = 0;
53-
for (var j = caml_ephe_key_offset; j < x.length; j++) {
54-
var key = x[j];
55-
if (key instanceof globalThis.WeakRef) {
56-
key = key.deref();
57-
if (key === old) count++;
58-
}
59-
}
60-
if (count === 1) x[1].unregister(old);
61-
}
62-
}
63-
x[caml_ephe_key_offset + i] = undefined;
53+
var old = caml_ephe_get_data(x);
54+
x[caml_ephe_key_offset + i] = caml_ephe_none;
55+
caml_ephe_set_data_opt(x, old);
6456
return 0;
6557
}
6658

6759
//Provides: caml_ephe_create
68-
//Requires: caml_weak_create, caml_ephe_data_offset
60+
//Requires: caml_weak_create
6961
function caml_ephe_create(n) {
7062
var x = caml_weak_create(n);
7163
return x;
7264
}
7365

7466
//Provides: caml_weak_create
75-
//Requires: caml_ephe_key_offset, caml_invalid_argument,caml_ephe_data_offset
67+
//Requires: caml_ephe_key_offset, caml_invalid_argument
68+
//Requires: caml_ephe_none
7669
function caml_weak_create(n) {
7770
if (n < 0) caml_invalid_argument("Weak.create");
78-
var x = [251, "caml_ephe_list_head"];
79-
x.length = caml_ephe_key_offset + n;
71+
var alen = caml_ephe_key_offset + n;
72+
var x = new Array(alen);
73+
x[0] = 251;
74+
x[1] = "caml_ephe_list_head";
75+
for (var i = 2; i < alen; i++) {
76+
x[i] = caml_ephe_none;
77+
}
8078
return x;
8179
}
8280

8381
//Provides: caml_weak_set
84-
//Requires: caml_invalid_argument
8582
//Requires: caml_ephe_set_key, caml_ephe_unset_key
8683
function caml_weak_set(x, i, v) {
8784
if (v === 0) caml_ephe_unset_key(x, i);
8885
else caml_ephe_set_key(x, i, v[1]);
8986
return 0;
9087
}
9188
//Provides: caml_ephe_get_key
92-
//Requires: caml_ephe_key_offset, caml_invalid_argument
89+
//Requires: caml_ephe_key_offset, caml_ephe_data_offset
90+
//Requires: caml_invalid_argument
91+
//Requires: caml_ephe_none
9392
//Alias: caml_weak_get
93+
9494
function caml_ephe_get_key(x, i) {
9595
if (i < 0 || caml_ephe_key_offset + i >= x.length)
9696
caml_invalid_argument("Weak.get_key");
9797
var weak = x[caml_ephe_key_offset + i];
98-
if (globalThis.WeakRef && weak instanceof globalThis.WeakRef)
98+
if (weak === caml_ephe_none) return 0;
99+
if (globalThis.WeakRef && weak instanceof globalThis.WeakRef) {
99100
weak = weak.deref();
100-
return weak === undefined ? 0 : [0, weak];
101+
if (weak === undefined) {
102+
x[caml_ephe_key_offset + i] = caml_ephe_none;
103+
x[caml_ephe_data_offset] = caml_ephe_none;
104+
return 0;
105+
}
106+
}
107+
return [0, weak];
101108
}
102109
//Provides: caml_ephe_get_key_copy
103110
//Requires: caml_ephe_get_key,caml_ephe_key_offset
@@ -114,21 +121,34 @@ function caml_ephe_get_key_copy(x, i) {
114121
}
115122

116123
//Provides: caml_ephe_check_key mutable
117-
//Requires: caml_ephe_key_offset
124+
//Requires: caml_ephe_key_offset, caml_ephe_data_offset
125+
//Requires: caml_invalid_argument
126+
//Requires: caml_ephe_none
118127
//Alias: caml_weak_check
119128
function caml_ephe_check_key(x, i) {
129+
if (i < 0 || caml_ephe_key_offset + i >= x.length)
130+
caml_invalid_argument("Weak.check_key");
120131
var weak = x[caml_ephe_key_offset + i];
121-
if (globalThis.WeakRef && weak instanceof globalThis.WeakRef)
132+
if (weak === caml_ephe_none) return 0;
133+
if (globalThis.WeakRef && weak instanceof globalThis.WeakRef) {
122134
weak = weak.deref();
123-
if (weak === undefined) return 0;
124-
else return 1;
135+
if (weak === undefined) {
136+
x[caml_ephe_key_offset + i] = caml_ephe_none;
137+
x[caml_ephe_data_offset] = caml_ephe_none;
138+
return 0;
139+
}
140+
}
141+
return 1;
125142
}
126143

127144
//Provides: caml_ephe_blit_key
128145
//Requires: caml_array_blit
129146
//Requires: caml_ephe_key_offset
147+
//Requires: caml_ephe_get_data
148+
//Requires: caml_ephe_set_data_opt
130149
//Alias: caml_weak_blit
131150
function caml_ephe_blit_key(a1, i1, a2, i2, len) {
151+
var old = caml_ephe_get_data(a1);
132152
// minus one because caml_array_blit works on ocaml array
133153
caml_array_blit(
134154
a1,
@@ -137,77 +157,96 @@ function caml_ephe_blit_key(a1, i1, a2, i2, len) {
137157
caml_ephe_key_offset + i2 - 1,
138158
len,
139159
);
160+
caml_ephe_set_data_opt(a2, old);
140161
return 0;
141162
}
142163

143164
//Provides: caml_ephe_blit_data
144-
//Requires: caml_ephe_data_offset, caml_ephe_set_data, caml_ephe_unset_data
165+
//Requires: caml_ephe_get_data, caml_ephe_set_data_opt
145166
function caml_ephe_blit_data(src, dst) {
146-
var n = src[caml_ephe_data_offset];
147-
if (n === undefined) caml_ephe_unset_data(dst);
148-
else caml_ephe_set_data(dst, n);
167+
var old = caml_ephe_get_data(src);
168+
caml_ephe_set_data_opt(dst, old);
149169
return 0;
150170
}
151171

152172
//Provides: caml_ephe_get_data
153-
//Requires: caml_ephe_data_offset
173+
//Requires: caml_ephe_data_offset, caml_ephe_key_offset
174+
//Requires: caml_ephe_none
154175
function caml_ephe_get_data(x) {
155-
if (x[caml_ephe_data_offset] === undefined) return 0;
156-
else return [0, x[caml_ephe_data_offset]];
176+
var data = x[caml_ephe_data_offset];
177+
if (data === caml_ephe_none) return 0;
178+
for (var i = caml_ephe_key_offset; i < x.length; i++) {
179+
var k = x[i];
180+
if (k === caml_ephe_none) continue;
181+
if (!(globalThis.WeakRef && k instanceof globalThis.WeakRef)) continue;
182+
var d = k.deref();
183+
if (d === undefined) {
184+
x[i] = caml_ephe_none;
185+
x[caml_ephe_data_offset] = caml_ephe_none;
186+
return 0;
187+
}
188+
data = data.get(d);
189+
if (data === undefined) {
190+
x[caml_ephe_data_offset] = caml_ephe_none;
191+
return 0;
192+
}
193+
}
194+
return [0, data];
157195
}
158196

159197
//Provides: caml_ephe_get_data_copy
160-
//Requires: caml_ephe_data_offset
198+
//Requires: caml_ephe_get_data
161199
//Requires: caml_obj_dup
162200
function caml_ephe_get_data_copy(x) {
163-
if (x[caml_ephe_data_offset] === undefined) return 0;
164-
else return [0, caml_obj_dup(x[caml_ephe_data_offset])];
201+
var r = caml_ephe_get_data(x);
202+
if (r === 0) return 0;
203+
else return [0, caml_obj_dup(r[1])];
165204
}
166205

167206
//Provides: caml_ephe_set_data
168-
//Requires: caml_ephe_data_offset, caml_ephe_key_offset, caml_ephe_unset_data
207+
//Requires: caml_ephe_data_offset, caml_ephe_key_offset
208+
//Requires: caml_ephe_none
169209
function caml_ephe_set_data(x, data) {
170-
if (globalThis.FinalizationRegistry && globalThis.WeakRef) {
171-
if (!(x[1] instanceof globalThis.FinalizationRegistry)) {
172-
x[1] = new globalThis.FinalizationRegistry(function () {
173-
caml_ephe_unset_data(x);
174-
});
175-
//register all keys
176-
for (var j = caml_ephe_key_offset; j < x.length; j++) {
177-
var key = x[j];
178-
if (key instanceof globalThis.WeakRef) {
179-
key = key.deref();
180-
if (key) x[1].register(key, undefined, key);
181-
}
182-
}
210+
for (var i = caml_ephe_key_offset; i < x.length; i++) {
211+
var k = x[i];
212+
if (k === caml_ephe_none) continue;
213+
if (!(globalThis.WeakRef && k instanceof globalThis.WeakRef)) continue;
214+
var d = k.deref();
215+
if (d === undefined) {
216+
x[i] = caml_ephe_none;
217+
continue;
218+
}
219+
if (globalThis.WeakMap) {
220+
var data2 = new globalThis.WeakMap();
221+
data2.set(k, data);
222+
data = data2;
183223
}
184224
}
185225
x[caml_ephe_data_offset] = data;
186226
return 0;
187227
}
188228

229+
//Provides: caml_ephe_set_data_opt
230+
//Requires: caml_ephe_set_data
231+
//Requires: caml_ephe_unset_data
232+
function caml_ephe_set_data_opt(x, data_opt) {
233+
if (data_opt === 0) caml_ephe_unset_data(x);
234+
else caml_ephe_set_data(x, data_opt[1]);
235+
return 0;
236+
}
237+
189238
//Provides: caml_ephe_unset_data
190-
//Requires: caml_ephe_data_offset, caml_ephe_key_offset
239+
//Requires: caml_ephe_data_offset
240+
//Requires: caml_ephe_none
191241
function caml_ephe_unset_data(x) {
192-
if (globalThis.FinalizationRegistry && globalThis.WeakRef) {
193-
if (x[1] instanceof globalThis.FinalizationRegistry) {
194-
//unregister all keys
195-
for (var j = caml_ephe_key_offset; j < x.length; j++) {
196-
var key = x[j];
197-
if (key instanceof globalThis.WeakRef) {
198-
key = key.deref();
199-
if (key) x[1].unregister(key);
200-
}
201-
}
202-
}
203-
}
204-
x[caml_ephe_data_offset] = undefined;
242+
x[caml_ephe_data_offset] = caml_ephe_none;
205243
return 0;
206244
}
207245

208246
//Provides: caml_ephe_check_data
209-
//Requires: caml_ephe_data_offset
247+
//Requires: caml_ephe_get_data
210248
function caml_ephe_check_data(x) {
211-
if (x[caml_ephe_data_offset] === undefined) return 0;
249+
var data = caml_ephe_get_data(x);
250+
if (data === 0) return 0;
212251
else return 1;
213252
}

0 commit comments

Comments
 (0)