changeset 372:3c378be73844

js: try another approach to shared ownership
author David Demelier <markand@malikania.fr>
date Mon, 25 Oct 2021 13:44:49 +0200
parents 8ac282bd5935
children ebaf5490b32f
files src/libmlk-core-js/core/js-drawable-stack.c src/libmlk-core-js/core/js-drawable.c src/libmlk-core-js/core/js-drawable.h src/libmlk-core-js/core/js-game.c src/libmlk-core-js/core/js-state.c src/libmlk-core-js/core/js-state.h
diffstat 6 files changed, 175 insertions(+), 136 deletions(-) [+]
line wrap: on
line diff
--- a/src/libmlk-core-js/core/js-drawable-stack.c	Mon Oct 25 12:43:09 2021 +0200
+++ b/src/libmlk-core-js/core/js-drawable-stack.c	Mon Oct 25 13:44:49 2021 +0200
@@ -76,10 +76,18 @@
 DrawableStack_add(duk_context *ctx)
 {
 	struct drawable_stack *st = self(ctx);
-	struct drawable *dw = js_drawable_require(ctx, 0);
+	struct js_drawable *dw = js_drawable_require(ctx, 0);
 
-	if (drawable_stack_add(st, dw) < 0)
-		drawable_finish(dw);
+	if (drawable_stack_add(st, &dw->dw) < 0)
+		drawable_finish(&dw->dw);
+	else {
+		duk_push_this(ctx);
+		dw->parent = duk_get_heapptr(ctx, -1);
+		duk_push_sprintf(ctx, "%p", dw);
+		duk_dup(ctx, 0);
+		duk_put_prop(ctx, -3);
+		duk_pop(ctx);
+	}
 
 	return 0;
 }
--- a/src/libmlk-core-js/core/js-drawable.c	Mon Oct 25 12:43:09 2021 +0200
+++ b/src/libmlk-core-js/core/js-drawable.c	Mon Oct 25 13:44:49 2021 +0200
@@ -25,51 +25,42 @@
 
 #define SIGNATURE DUK_HIDDEN_SYMBOL("Mlk.Drawable")
 
-struct self {
-	duk_context *ctx;
-	void *ptr;
-	struct drawable dw;
-	unsigned int refc;
-};
-
-static inline struct self *
+static inline struct js_drawable *
 self(duk_context *ctx)
 {
-	struct self *sf = NULL;
+	struct js_drawable *data = NULL;
 
 	duk_push_this(ctx);
 	duk_get_prop_string(ctx, -1, SIGNATURE);
-	sf = duk_to_pointer(ctx, -1);
+	data = duk_to_pointer(ctx, -1);
 	duk_pop_2(ctx);
 
-	if (!sf)
+	if (!data)
 		return (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Drawable object"), NULL;
 
-	return sf;
+	return data;
 }
 
-static inline int
-callable(struct self *s, const char *prop, duk_context **ctx)
+static inline duk_context *
+callable(struct js_drawable *data, const char *prop)
 {
-	int callable;
+	duk_context *ctx;
 
-	if (!s->ptr)
-		return 0;
+	if (!data->ptr)
+		return NULL;
 
-	duk_push_heapptr(s->ctx, s->ptr);
-	duk_get_prop_string(s->ctx, -1, prop);
-	duk_remove(s->ctx, -2);
+	duk_push_heapptr(data->ctx, data->ptr);
+	duk_get_prop_string(data->ctx, -1, prop);
+	duk_pull(data->ctx, -2);
 
-	if (duk_is_callable(s->ctx, -1)) {
-		*ctx = s->ctx;
-		callable = 1;
-	} else {
-		*ctx = NULL;
-		callable = 0;
-		duk_pop(s->ctx);
+	if (duk_is_callable(data->ctx, -2))
+		ctx = data->ctx;
+	else {
+		ctx = NULL;
+		duk_pop_n(data->ctx, 2);
 	}
 
-	return callable;
+	return ctx;
 }
 
 static int
@@ -78,10 +69,11 @@
 	duk_context *ctx;
 	int ret = 0;
 
-	if (callable(dw->data, "update", &ctx)) {
+	if ((ctx = callable(dw->data, "update"))) {
 		duk_push_uint(ctx, ticks);
-		duk_call(ctx, 1);
+		duk_call_method(ctx, 1);
 		ret = duk_to_int(ctx, -1);
+		duk_pop(ctx);
 	}
 
 	return ret;
@@ -92,8 +84,10 @@
 {
 	duk_context *ctx;
 
-	if (callable(dw->data, "draw", &ctx))
-		duk_call(ctx, 0);
+	if ((ctx = callable(dw->data, "draw"))) {
+		duk_call_method(ctx, 0);
+		duk_pop(ctx);
+	}
 }
 
 static void
@@ -101,17 +95,31 @@
 {
 	duk_context *ctx;
 
-	if (callable(dw->data, "end", &ctx))
-		duk_call(ctx, 0);
+	if ((ctx = callable(dw->data, "end"))) {
+		duk_call_method(ctx, 0);
+		duk_pop(ctx);
+	}
 }
 
 static void
 finish(struct drawable *dw)
 {
-	struct self *sf = dw->data;
+	struct js_drawable *data = dw->data;
+
+	/* I must not be called anymore. */
+	data->ptr = NULL;
 
-	if (!--sf->refc)
-		free(sf);
+	/* Remove myself from parent stack if any. */
+	if (data->parent) {
+		duk_push_heapptr(data->ctx, data->parent);
+		duk_push_sprintf(data->ctx, "%p", data);
+		duk_del_prop(data->ctx, -2);
+		duk_pop(data->ctx);
+		data->parent = NULL;
+	}
+
+	if (--data->refc == 0)
+		free(data);
 }
 
 static duk_ret_t
@@ -149,23 +157,23 @@
 static duk_ret_t
 Drawable_constructor(duk_context *ctx)
 {
-	struct self *self;
+	struct js_drawable *data;
 	const int x = duk_require_int(ctx, 0);
 	const int y = duk_require_int(ctx, 1);
 
-	self = alloc_new0(sizeof (*self));
-	self->refc = 1;
-	self->ctx = ctx;
-	self->dw.x = x;
-	self->dw.y = y;
-	self->dw.data = self;
-	self->dw.update = update;
-	self->dw.finish = finish;
-	self->dw.draw = draw;
-	self->dw.end = end;
+	data = alloc_new0(sizeof (*data));
+	data->refc = 1;
+	data->ctx = ctx;
+	data->dw.x = x;
+	data->dw.y = y;
+	data->dw.data = self;
+	data->dw.update = update;
+	data->dw.finish = finish;
+	data->dw.draw = draw;
+	data->dw.end = end;
 
 	duk_push_this(ctx);
-	self->ptr = duk_get_heapptr(ctx, -1);
+	data->ptr = duk_get_heapptr(ctx, -1);
 	duk_push_pointer(ctx, self);
 	duk_put_prop_string(ctx, -2, SIGNATURE);
 	duk_push_string(ctx, "x");
@@ -184,14 +192,12 @@
 static duk_ret_t
 Drawable_destructor(duk_context *ctx)
 {
-	struct self *sf;
+	struct js_drawable *data;
 
 	duk_get_prop_string(ctx, 0, SIGNATURE);
 
-	if ((sf = duk_to_pointer(ctx, -1))) {
-		sf->ptr = NULL;
-		drawable_finish(&sf->dw);
-	}
+	if ((data = duk_to_pointer(ctx, -1)))
+		drawable_finish(&data->dw);
 
 	duk_del_prop_string(ctx, 0, SIGNATURE);
 	duk_pop(ctx);
@@ -199,7 +205,6 @@
 	return 0;
 }
 
-
 void
 js_drawable_bind(duk_context *ctx)
 {
@@ -213,21 +218,21 @@
 	duk_put_global_string(ctx, "Drawable");
 }
 
-struct drawable *
+struct js_drawable *
 js_drawable_require(duk_context *ctx, duk_idx_t idx)
 {
-	struct self *sf = NULL;
+	struct js_drawable *data = NULL;
 
 	if (duk_is_object(ctx, idx)) {
 		duk_get_prop_string(ctx, idx, SIGNATURE);
-		sf = duk_to_pointer(ctx, -1);
+		data = duk_to_pointer(ctx, -1);
 		duk_pop(ctx);
 	}
 
-	if (!sf)
+	if (!data)
 		return (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Drawable object"), NULL;
 
-	sf->refc++;
+	data->refc++;
 
-	return &sf->dw;
+	return data;
 }
--- a/src/libmlk-core-js/core/js-drawable.h	Mon Oct 25 12:43:09 2021 +0200
+++ b/src/libmlk-core-js/core/js-drawable.h	Mon Oct 25 13:44:49 2021 +0200
@@ -21,12 +21,20 @@
 
 #include <duktape.h>
 
-struct drawable;
+#include <core/drawable.h>
+
+struct js_drawable {
+	duk_context *ctx;
+	void *ptr;
+	void *parent;
+	unsigned int refc;
+	struct drawable dw;
+};
 
 void
 js_drawable_bind(duk_context *);
 
-struct drawable *
+struct js_drawable *
 js_drawable_require(duk_context *, duk_idx_t);
 
 #endif /* !MLK_CORE_JS_DRAWABLE_H */
--- a/src/libmlk-core-js/core/js-game.c	Mon Oct 25 12:43:09 2021 +0200
+++ b/src/libmlk-core-js/core/js-game.c	Mon Oct 25 13:44:49 2021 +0200
@@ -31,14 +31,21 @@
 static duk_ret_t
 Game_push(duk_context *ctx)
 {
-	struct state *state = js_state_require(ctx, 0);
+	struct js_state *state = js_state_require(ctx, 0);
 
 	if (game.state == &game.states[GAME_STATE_MAX]) {
-		state_finish(state);
+		state_finish(&state->st);
 		return duk_error(ctx, DUK_ERR_RANGE_ERROR, "too many states");
 	}
 
-	game_push(state);
+	duk_push_this(ctx);
+	state->parent = duk_get_heapptr(ctx, -1);
+	duk_push_sprintf(ctx, "%p", state);
+	duk_dup(ctx, 0);
+	duk_put_prop(ctx, -3);
+	duk_pop(ctx);
+
+	game_push(&state->st);
 
 	return 0;
 }
--- a/src/libmlk-core-js/core/js-state.c	Mon Oct 25 12:43:09 2021 +0200
+++ b/src/libmlk-core-js/core/js-state.c	Mon Oct 25 13:44:49 2021 +0200
@@ -27,35 +27,26 @@
 
 #define SIGNATURE DUK_HIDDEN_SYMBOL("Mlk.State")
 
-struct self {
+static inline duk_context *
+callable(struct js_state *data, const char *prop)
+{
 	duk_context *ctx;
-	void *ptr;
-	struct state state;
-	unsigned int refc;
-};
 
-static inline int
-callable(struct self *s, const char *prop, duk_context **ctx)
-{
-	int callable;
+	if (!data->ptr)
+		return NULL;
 
-	if (!s->ptr)
-		return 0;
-
-	duk_push_heapptr(s->ctx, s->ptr);
-	duk_get_prop_string(s->ctx, -1, prop);
-	duk_remove(s->ctx, -2);
+	duk_push_heapptr(data->ctx, data->ptr);
+	duk_get_prop_string(data->ctx, -1, prop);
+	duk_pull(data->ctx, -2);
 
-	if (duk_is_callable(s->ctx, -1)) {
-		*ctx = s->ctx;
-		callable = 1;
-	} else {
-		*ctx = NULL;
-		callable = 0;
-		duk_pop(s->ctx);
+	if (duk_is_callable(data->ctx, -2))
+		ctx = data->ctx;
+	else {
+		ctx = NULL;
+		duk_pop_n(data->ctx, 2);
 	}
 
-	return callable;
+	return ctx;
 }
 
 static void
@@ -63,8 +54,8 @@
 {
 	duk_context *ctx;
 
-	if (callable(state->data, "start", &ctx)) {
-		duk_call(ctx, 0);
+	if ((ctx = callable(state->data, "start"))) {
+		duk_call_method(ctx, 0);
 		duk_pop(ctx);
 	}
 }
@@ -74,9 +65,9 @@
 {
 	duk_context *ctx;
 
-	if (callable(state->data, "handle", &ctx)) {
+	if ((ctx = callable(state->data, "handle"))) {
 		js_event_push(ctx, ev);
-		duk_call(ctx, 1);
+		duk_call_method(ctx, 1);
 		duk_pop(ctx);
 	}
 }
@@ -86,9 +77,9 @@
 {
 	duk_context *ctx;
 
-	if (callable(state->data, "update", &ctx)) {
+	if ((ctx = callable(state->data, "update"))) {
 		duk_push_uint(ctx, ticks);
-		duk_call(ctx, 1);
+		duk_call_method(ctx, 1);
 		duk_pop(ctx);
 	}
 }
@@ -98,8 +89,8 @@
 {
 	duk_context *ctx;
 
-	if (callable(state->data, "draw", &ctx)) {
-		duk_call(ctx, 0);
+	if ((ctx = callable(state->data, "draw"))) {
+		duk_call_method(ctx, 0);
 		duk_pop(ctx);
 	}
 }
@@ -109,8 +100,8 @@
 {
 	duk_context *ctx;
 
-	if (callable(state->data, "suspend", &ctx)) {
-		duk_call(ctx, 0);
+	if ((ctx = callable(state->data, "suspend"))) {
+		duk_call_method(ctx, 0);
 		duk_pop(ctx);
 	}
 }
@@ -120,8 +111,8 @@
 {
 	duk_context *ctx;
 
-	if (callable(state->data, "resume", &ctx)) {
-		duk_call(ctx, 0);
+	if ((ctx = callable(state->data, "resume"))) {
+		duk_call_method(ctx, 0);
 		duk_pop(ctx);
 	}
 }
@@ -131,8 +122,8 @@
 {
 	duk_context *ctx;
 
-	if (callable(state->data, "end", &ctx)) {
-		duk_call(ctx, 0);
+	if ((ctx = callable(state->data, "end"))) {
+		duk_call_method(ctx, 0);
 		duk_pop(ctx);
 	}
 }
@@ -140,33 +131,45 @@
 static void
 finish(struct state *state)
 {
-	struct self *self = state->data;
+	struct js_state *data = state->data;
+
+	/* I must not be called anymore. */
+	data->ptr = NULL;
 
-	if (!--self->refc)
-		free(self);
+	/* Remove myself from parent stack if any. */
+	if (data->parent) {
+		duk_push_heapptr(data->ctx, data->parent);
+		duk_push_sprintf(data->ctx, "%p", data);
+		duk_del_prop(data->ctx, -2);
+		duk_pop(data->ctx);
+		data->parent = NULL;
+	}
+
+	if (--data->refc == 0)
+		free(data);
 }
 
 static duk_ret_t
 State_constructor(duk_context *ctx)
 {
-	struct self *self;
+	struct js_state *data;
 
-	self = alloc_new0(sizeof (*self));
-	self->ctx = ctx;
-	self->refc = 1;
-	self->state.data = self;
-	self->state.start = start;
-	self->state.handle = handle;
-	self->state.update = update;
-	self->state.draw = draw;
-	self->state.suspend = suspend;
-	self->state.resume = resume;
-	self->state.end = end;
-	self->state.finish = finish;
+	data = alloc_new0(sizeof (*data));
+	data->ctx = ctx;
+	data->refc = 1;
+	data->st.data = data;
+	data->st.start = start;
+	data->st.handle = handle;
+	data->st.update = update;
+	data->st.draw = draw;
+	data->st.suspend = suspend;
+	data->st.resume = resume;
+	data->st.end = end;
+	data->st.finish = finish;
 
 	duk_push_this(ctx);
-	self->ptr = duk_get_heapptr(ctx, -1);
-	duk_push_pointer(ctx, self);
+	data->ptr = duk_get_heapptr(ctx, -1);
+	duk_push_pointer(ctx, data);
 	duk_put_prop_string(ctx, -2, SIGNATURE);
 	duk_pop(ctx);
 
@@ -176,14 +179,12 @@
 static duk_ret_t
 State_destructor(duk_context *ctx)
 {
-	struct self *self;
+	struct js_state *data;
 
 	duk_get_prop_string(ctx, 0, SIGNATURE);
 
-	if ((self = duk_to_pointer(ctx, -1))) {
-		self->ptr = NULL;
-		state_finish(&self->state);
-	}
+	if ((data = duk_to_pointer(ctx, -1)))
+		state_finish(&data->st);
 
 	duk_pop(ctx);
 
@@ -203,21 +204,21 @@
 	duk_put_global_string(ctx, "State");
 }
 
-struct state *
+struct js_state *
 js_state_require(duk_context *ctx, duk_idx_t idx)
 {
-	struct self *self = NULL;
+	struct js_state *data = NULL;
 
 	if (duk_is_object(ctx, idx)) {
 		duk_get_prop_string(ctx, idx, SIGNATURE);
-		self = duk_to_pointer(ctx, -1);
+		data = duk_to_pointer(ctx, -1);
 		duk_pop(ctx);
 	}
 
-	if (!self)
+	if (!data)
 		return (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a State object"), NULL;
 
-	self->refc++;
+	data->refc++;
 
-	return &self->state;
+	return data;
 }
--- a/src/libmlk-core-js/core/js-state.h	Mon Oct 25 12:43:09 2021 +0200
+++ b/src/libmlk-core-js/core/js-state.h	Mon Oct 25 13:44:49 2021 +0200
@@ -21,10 +21,20 @@
 
 #include <duktape.h>
 
+#include <core/state.h>
+
+struct js_state {
+	duk_context *ctx;
+	void *ptr;
+	void *parent;
+	unsigned int refc;
+	struct state st;
+};
+
 void
 js_state_bind(duk_context *);
 
-struct state *
+struct js_state *
 js_state_require(duk_context *, duk_idx_t);
 
 #endif /* !MLK_CORE_JS_STATE_H */