Skip to content

Commit 5c7a414

Browse files
committed
webassembly: Add C-level finaliser to JsProxy object.
And clear the corresponding `proxy_js_ref[js_ref]` entry when the finaliser runs. This then allows the JavaScript side to (eventually) free the corresponding JavaScript object. Signed-off-by: Damien George <damien@micropython.org>
1 parent c0ca4bb commit 5c7a414

File tree

2 files changed

+49
-6
lines changed

2 files changed

+49
-6
lines changed

ports/webassembly/objjsproxy.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,22 @@ static mp_obj_t jsproxy_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
234234
}
235235
}
236236

237+
EM_JS(void, proxy_js_free_obj, (int js_ref), {
238+
if (js_ref >= PROXY_JS_REF_NUM_STATIC) {
239+
proxy_js_ref[js_ref] = undefined;
240+
if (js_ref < proxy_js_ref_next) {
241+
proxy_js_ref_next = js_ref;
242+
}
243+
}
244+
});
245+
246+
static mp_obj_t jsproxy___del__(mp_obj_t self_in) {
247+
mp_obj_jsproxy_t *self = MP_OBJ_TO_PTR(self_in);
248+
proxy_js_free_obj(self->ref);
249+
return mp_const_none;
250+
}
251+
static MP_DEFINE_CONST_FUN_OBJ_1(jsproxy___del___obj, jsproxy___del__);
252+
237253
static mp_obj_t jsproxy_reflect_construct(size_t n_args, const mp_obj_t *args) {
238254
int arg0 = mp_obj_jsproxy_get_ref(args[0]);
239255
n_args -= 1;
@@ -274,7 +290,11 @@ void mp_obj_jsproxy_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
274290
if (dest[0] == MP_OBJ_NULL) {
275291
// Load attribute.
276292
uint32_t out[PVN];
277-
if (lookup_attr(self->ref, qstr_str(attr), out)) {
293+
if (attr == MP_QSTR___del__) {
294+
// For finaliser.
295+
dest[0] = MP_OBJ_FROM_PTR(&jsproxy___del___obj);
296+
dest[1] = self_in;
297+
} else if (lookup_attr(self->ref, qstr_str(attr), out)) {
278298
dest[0] = proxy_convert_js_to_mp_obj_cside(out);
279299
} else if (attr == MP_QSTR_new) {
280300
// Special case to handle construction of JS objects.
@@ -515,7 +535,7 @@ MP_DEFINE_CONST_OBJ_TYPE(
515535
);
516536

517537
mp_obj_t mp_obj_new_jsproxy(int ref) {
518-
mp_obj_jsproxy_t *o = mp_obj_malloc(mp_obj_jsproxy_t, &mp_type_jsproxy);
538+
mp_obj_jsproxy_t *o = mp_obj_malloc_with_finaliser(mp_obj_jsproxy_t, &mp_type_jsproxy);
519539
o->ref = ref;
520540
return MP_OBJ_FROM_PTR(o);
521541
}

ports/webassembly/proxy_js.js

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
* THE SOFTWARE.
2525
*/
2626

27+
// Number of static entries at the start of proxy_js_ref.
28+
const PROXY_JS_REF_NUM_STATIC = 2;
29+
2730
// These constants should match the constants in proxy_c.c.
2831

2932
const PROXY_KIND_MP_EXCEPTION = -1;
@@ -57,6 +60,28 @@ class PythonError extends Error {
5760

5861
function proxy_js_init() {
5962
globalThis.proxy_js_ref = [globalThis, undefined];
63+
globalThis.proxy_js_ref_next = PROXY_JS_REF_NUM_STATIC;
64+
}
65+
66+
// js_obj cannot be undefined
67+
function proxy_js_add_obj(js_obj) {
68+
// Search for the first free slot in proxy_js_ref.
69+
while (proxy_js_ref_next < proxy_js_ref.length) {
70+
if (proxy_js_ref[proxy_js_ref_next] === undefined) {
71+
// Free slot found, reuse it.
72+
const id = proxy_js_ref_next;
73+
++proxy_js_ref_next;
74+
proxy_js_ref[id] = js_obj;
75+
return id;
76+
}
77+
++proxy_js_ref_next;
78+
}
79+
80+
// No free slots, so grow proxy_js_ref by one (append at the end of the array).
81+
const id = proxy_js_ref.length;
82+
proxy_js_ref[id] = js_obj;
83+
proxy_js_ref_next = proxy_js_ref.length;
84+
return id;
6085
}
6186

6287
function proxy_call_python(target, argumentsList) {
@@ -147,8 +172,7 @@ function proxy_convert_js_to_mp_obj_jsside(js_obj, out) {
147172
Module.setValue(out + 4, js_obj._ref, "i32");
148173
} else {
149174
kind = PROXY_KIND_JS_OBJECT;
150-
const id = proxy_js_ref.length;
151-
proxy_js_ref[id] = js_obj;
175+
const id = proxy_js_add_obj(js_obj);
152176
Module.setValue(out + 4, id, "i32");
153177
}
154178
Module.setValue(out + 0, kind, "i32");
@@ -161,8 +185,7 @@ function proxy_convert_js_to_mp_obj_jsside_force_double_proxy(js_obj, out) {
161185
js_obj instanceof PyProxyThenable
162186
) {
163187
const kind = PROXY_KIND_JS_OBJECT;
164-
const id = proxy_js_ref.length;
165-
proxy_js_ref[id] = js_obj;
188+
const id = proxy_js_add_obj(js_obj);
166189
Module.setValue(out + 4, id, "i32");
167190
Module.setValue(out + 0, kind, "i32");
168191
} else {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy