Gitweb links:
...log
http://git.netsurf-browser.org/netsurf.git/shortlog/80e7ac7345f084da1b909cd7dee32cf05aa5cb56
...commit
http://git.netsurf-browser.org/netsurf.git/commit/80e7ac7345f084da1b909cd7dee32cf05aa5cb56
...tree
http://git.netsurf-browser.org/netsurf.git/tree/80e7ac7345f084da1b909cd7dee32cf05aa5cb56
The branch, master has been updated
via 80e7ac7345f084da1b909cd7dee32cf05aa5cb56 (commit)
via 3c4652c1c3a2231b2bb1e2bf43e6c16fc54d10bf (commit)
via 66a23c25605c9c7eca7b5c9b420a079ce1203faf (commit)
via 337082f715951fe9f5b46f1a4710ca415f67e22d (commit)
via 17b28e85c12309d60e3c45acb096b9989a7834ff (commit)
via 313dc9b099a172914f312120f0f9d0260a3588cf (commit)
from 2503b17f02588e7e3705ccd62fa4b80ce256dcbe (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=80e7ac7345f084da1b909cd7dee32cf05aa5cb56
commit 80e7ac7345f084da1b909cd7dee32cf05aa5cb56
Author: Daniel Silverstone <[email protected]>
Commit: Daniel Silverstone <[email protected]>
Dukky: Add refcounting to threads
In order to cope with threads which manage to navigate entirely
while executing (sadly possible) we need to handle the possibility
that a thread is destroyed by the browser but still needs to live
until it returns from whatever exec it was doing at the time.
Signed-off-by: Daniel Silverstone <[email protected]>
diff --git a/content/handlers/javascript/duktape/dukky.c
b/content/handlers/javascript/duktape/dukky.c
index f47dec8..862f0e4 100644
--- a/content/handlers/javascript/duktape/dukky.c
+++ b/content/handlers/javascript/duktape/dukky.c
@@ -59,6 +59,7 @@
struct jsheap {
duk_context *ctx; /**< duktape base context */
duk_uarridx_t next_thread; /**< monotonic thread counter */
+ unsigned int live_threads; /**< number of live threads */
uint64_t exec_start_time;
};
@@ -66,6 +67,8 @@ struct jsheap {
* dukky javascript thread
*/
struct jsthread {
+ bool pending_destroy; /**< Whether this thread is pending destruction */
+ unsigned int in_use; /**< The number of times this thread is in use */
jsheap *heap; /**< The heap this thread belongs to */
duk_context *ctx; /**< The duktape thread context */
duk_uarridx_t thread_idx; /**< The thread number */
@@ -621,6 +624,7 @@ js_newheap(int timeout, jsheap **heap)
/* exported interface documented in js.h */
void js_destroyheap(jsheap *heap)
{
+ assert(heap->live_threads == 0);
NSLOG(dukky, DEBUG, "Destroying duktape javascript context");
duk_destroy_heap(heap->ctx);
free(heap);
@@ -652,6 +656,7 @@ nserror js_newthread(jsheap *heap, void *win_priv, void
*doc_priv, jsthread **th
ret->ctx = duk_require_context(heap->ctx, -1);
ret->thread_idx = heap->next_thread++;
duk_put_prop_index(heap->ctx, -2, ret->thread_idx);
+ heap->live_threads++;
duk_pop(heap->ctx); /* ... */
duk_push_int(CTX, 0);
duk_push_int(CTX, 1);
@@ -738,11 +743,16 @@ nserror js_newthread(jsheap *heap, void *win_priv, void
*doc_priv, jsthread **th
#undef CTX
#define CTX (thread->ctx)
-
-/* exported interface documented in js.h */
-void js_destroythread(jsthread *thread)
+/**
+ * Destroy a Duktape thread
+ */
+static void dukky_destroythread(jsthread *thread)
{
jsheap *heap = thread->heap;
+
+ assert(thread->in_use == 0);
+ assert(thread->pending_destroy = true);
+
/* Closing down the extant thread */
NSLOG(dukky, DEBUG, "Closing down extant thread %p in heap %p", thread,
heap);
duk_get_global_string(CTX, MAGIC(closedownThread));
@@ -759,6 +769,33 @@ void js_destroythread(jsthread *thread)
/* Finally give the heap a chance to clean up */
duk_gc(heap->ctx, 0);
duk_gc(heap->ctx, DUK_GC_COMPACT);
+ heap->live_threads--;
+}
+
+/* exported interface documented in js.h */
+void js_destroythread(jsthread *thread)
+{
+ thread->pending_destroy = true;
+ if (thread->in_use == 0) {
+ dukky_destroythread(thread);
+ }
+}
+
+static void dukky_enter_thread(jsthread *thread)
+{
+ assert(thread != NULL);
+ thread->in_use++;
+}
+
+static void dukky_leave_thread(jsthread *thread)
+{
+ assert(thread != NULL);
+ assert(thread->in_use > 0);
+
+ thread->in_use--;
+ if (thread->in_use == 0 && thread->pending_destroy == true) {
+ dukky_destroythread(thread);
+ }
}
duk_bool_t dukky_check_timeout(void *udata)
@@ -845,12 +882,15 @@ void dukky_log_stack_frame(duk_context *ctx, const char *
reason)
bool
js_exec(jsthread *thread, const uint8_t *txt, size_t txtlen, const char *name)
{
+ bool ret = false;
assert(thread);
if (txt == NULL || txtlen == 0) {
return false;
}
+ dukky_enter_thread(thread);
+
duk_set_top(CTX, 0);
NSLOG(dukky, DEEPDEBUG, "Running %"PRIsizet" bytes from %s", txtlen,
name);
/* NSLOG(dukky, DEEPDEBUG, "\n%s\n", txt); */
@@ -877,11 +917,14 @@ js_exec(jsthread *thread, const uint8_t *txt, size_t
txtlen, const char *name)
if (duk_get_top(CTX) == 0) duk_push_boolean(CTX, false);
NSLOG(dukky, DEEPDEBUG, "Returning %s",
duk_get_boolean(CTX, 0) ? "true" : "false");
- return duk_get_boolean(CTX, 0);
+ ret = duk_get_boolean(CTX, 0);
+ goto out;
handle_error:
dukky_dump_error(CTX);
- return false;
+out:
+ dukky_leave_thread(thread);
+ return ret;
}
static const char* dukky_event_proto(dom_event *evt)
@@ -1406,6 +1449,8 @@ void js_handle_new_element(jsthread *thread, struct
dom_element *node)
if (exc != DOM_NO_ERR) return;
if (map == NULL) return;
+ dukky_enter_thread(thread);
+
exc = dom_namednodemap_get_length(map, &siz);
if (exc != DOM_NO_ERR) goto out;
@@ -1455,11 +1500,14 @@ out:
dom_node_unref(attr);
dom_namednodemap_unref(map);
+
+ dukky_leave_thread(thread);
}
void js_event_cleanup(jsthread *thread, struct dom_event *evt)
{
assert(thread);
+ dukky_enter_thread(thread);
/* ... */
duk_get_global_string(CTX, EVENT_MAGIC);
/* ... EVENT_MAP */
@@ -1469,6 +1517,7 @@ void js_event_cleanup(jsthread *thread, struct dom_event
*evt)
/* ... EVENT_MAP */
duk_pop(CTX);
/* ... */
+ dukky_leave_thread(thread);
}
bool js_fire_event(jsthread *thread, const char *type, struct dom_document
*doc, struct dom_node *target)
@@ -1507,6 +1556,7 @@ bool js_fire_event(jsthread *thread, const char *type,
struct dom_document *doc,
dom_event_unref(evt);
return true;
}
+ dukky_enter_thread(thread);
/* ... */
duk_get_global_string(CTX, HANDLER_MAGIC);
/* ... handlers */
@@ -1523,6 +1573,7 @@ bool js_fire_event(jsthread *thread, const char *type,
struct dom_document *doc,
exc = dom_html_document_get_body(doc, &body);
if (exc != DOM_NO_ERR) {
dom_event_unref(evt);
+ dukky_leave_thread(thread);
return true;
}
dukky_push_node(CTX, (struct dom_node *)body);
@@ -1533,6 +1584,7 @@ bool js_fire_event(jsthread *thread, const char *type,
struct dom_document *doc,
dom_node_unref(body);
/* ... handlers */
duk_pop(CTX);
+ dukky_leave_thread(thread);
return true;
}
/* Unref the body, we don't need it any more */
@@ -1574,6 +1626,7 @@ bool js_fire_event(jsthread *thread, const char *type,
struct dom_document *doc,
/* ... */
js_event_cleanup(thread, evt);
dom_event_unref(evt);
+ dukky_leave_thread(thread);
return true;
}
/* ... result */
@@ -1581,5 +1634,6 @@ bool js_fire_event(jsthread *thread, const char *type,
struct dom_document *doc,
/* ... */
js_event_cleanup(thread, evt);
dom_event_unref(evt);
+ dukky_leave_thread(thread);
return true;
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=3c4652c1c3a2231b2bb1e2bf43e6c16fc54d10bf
commit 3c4652c1c3a2231b2bb1e2bf43e6c16fc54d10bf
Author: Daniel Silverstone <[email protected]>
Commit: Daniel Silverstone <[email protected]>
Dukky: Upgrade dukky binding to support new heap/thread split
Update the duktape bindings and dukky interface to support the
new JS heap/thread split. Heaps may have multiple active threads
though in general there will only be 2 at a time.
Signed-off-by: Daniel Silverstone <[email protected]>
diff --git a/content/handlers/javascript/duktape/Window.bnd
b/content/handlers/javascript/duktape/Window.bnd
index 44a5170..b4a467d 100644
--- a/content/handlers/javascript/duktape/Window.bnd
+++ b/content/handlers/javascript/duktape/Window.bnd
@@ -216,8 +216,8 @@ window_remove_callback_by_handle(duk_context *ctx,
} RING_ITERATE_END(window->schedule_ring, sched);
}
-/* This is the dodgy compartment closedown method */
-static duk_ret_t dukky_window_closedown_compartment(duk_context *ctx)
+/* This is the dodgy thread closedown method */
+static duk_ret_t dukky_window_closedown_thread(duk_context *ctx)
{
window_private_t *priv = NULL;
@@ -230,7 +230,7 @@ static duk_ret_t
dukky_window_closedown_compartment(duk_context *ctx)
return 0;
}
- NSLOG(dukky, DEEPDEBUG, "Closing down compartment");
+ NSLOG(dukky, DEEPDEBUG, "Closing down thread");
while (priv->schedule_ring != NULL) {
window_remove_callback_by_handle(ctx,
priv,
@@ -361,10 +361,10 @@ prototype Window()
/* ** WebAssembly */
/* As yet, Duktape lacks WA */
#undef EXPOSE
- /* Add s3kr1t method to close the compartment */
+ /* Add s3kr1t method to close the JS thread (browsing context) */
duk_dup(ctx, 0);
- duk_push_string(ctx, MAGIC(closedownCompartment));
- duk_push_c_function(ctx, dukky_window_closedown_compartment,
DUK_VARARGS);
+ duk_push_string(ctx, MAGIC(closedownThread));
+ duk_push_c_function(ctx, dukky_window_closedown_thread, DUK_VARARGS);
duk_def_prop(ctx, -3,
DUK_DEFPROP_HAVE_VALUE |
DUK_DEFPROP_HAVE_WRITABLE |
diff --git a/content/handlers/javascript/duktape/dukky.c
b/content/handlers/javascript/duktape/dukky.c
index 560a12f..f47dec8 100644
--- a/content/handlers/javascript/duktape/dukky.c
+++ b/content/handlers/javascript/duktape/dukky.c
@@ -51,16 +51,26 @@
#define HANDLER_MAGIC MAGIC(HANDLER_MAP)
#define EVENT_LISTENER_JS_MAGIC MAGIC(EVENT_LISTENER_JS_MAP)
#define GENERICS_MAGIC MAGIC(GENERICS_TABLE)
+#define THREAD_MAP MAGIC(THREAD_MAP)
/**
- * dukky javascript context
+ * dukky javascript heap
*/
-struct jscontext {
+struct jsheap {
duk_context *ctx; /**< duktape base context */
- duk_context *thread; /**< duktape compartment */
+ duk_uarridx_t next_thread; /**< monotonic thread counter */
uint64_t exec_start_time;
};
+/**
+ * dukky javascript thread
+ */
+struct jsthread {
+ jsheap *heap; /**< The heap this thread belongs to */
+ duk_context *ctx; /**< The duktape thread context */
+ duk_uarridx_t thread_idx; /**< The thread number */
+};
+
static duk_ret_t dukky_populate_object(duk_context *ctx, void *udata)
{
/* ... obj args protoname nargs */
@@ -556,36 +566,6 @@ static void dukky_free_function(void *udata, void *ptr)
free(ptr);
}
-
-#define CTX (ctx->thread)
-
-/**
- * close current compartment
- *
- * \param ctx javascript context
- * \return NSERROR_OK on sucess.
- */
-static nserror dukky_closecompartment(jscontext *ctx)
-{
- /* ensure there is an active compartment */
- if (ctx->thread == NULL) {
- return NSERROR_OK;
- }
-
- /* Closing down the extant compartment */
- NSLOG(dukky, DEEPDEBUG, "Closing down extant compartment...");
- duk_get_global_string(ctx->thread, MAGIC(closedownCompartment));
- dukky_pcall(CTX, 0, true);
- NSLOG(dukky, DEEPDEBUG, "Popping the thread off the stack");
- duk_set_top(ctx->ctx, 0);
- duk_gc(ctx->ctx, 0);
- duk_gc(ctx->ctx, DUK_GC_COMPACT);
-
- ctx->thread = NULL;
-
- return NSERROR_OK;
-}
-
/* exported interface documented in js.h */
void js_initialise(void)
{
@@ -608,12 +588,12 @@ void js_finalise(void)
/* exported interface documented in js.h */
nserror
-js_newcontext(int timeout, jscontext **jsctx)
+js_newheap(int timeout, jsheap **heap)
{
duk_context *ctx;
- jscontext *ret = calloc(1, sizeof(*ret));
- *jsctx = NULL;
- NSLOG(dukky, DEBUG, "Creating new duktape javascript context");
+ jsheap *ret = calloc(1, sizeof(*ret));
+ *heap = NULL;
+ NSLOG(dukky, DEBUG, "Creating new duktape javascript heap");
if (ret == NULL) return NSERROR_NOMEM;
ctx = ret->ctx = duk_create_heap(
dukky_alloc_function,
@@ -629,36 +609,50 @@ js_newcontext(int timeout, jscontext **jsctx)
duk_put_global_string(ctx, PROTO_MAGIC);
/* Create prototypes here */
dukky_create_prototypes(ctx);
+ /* Now create the thread map */
+ duk_push_object(ctx);
+ duk_put_global_string(ctx, THREAD_MAP);
- *jsctx = ret;
+ *heap = ret;
return NSERROR_OK;
}
/* exported interface documented in js.h */
-void js_destroycontext(jscontext *ctx)
+void js_destroyheap(jsheap *heap)
{
NSLOG(dukky, DEBUG, "Destroying duktape javascript context");
- dukky_closecompartment(ctx);
- duk_destroy_heap(ctx->ctx);
- free(ctx);
+ duk_destroy_heap(heap->ctx);
+ free(heap);
}
+/* Just for here, the CTX is in ret, not thread */
+#define CTX (ret->ctx)
/* exported interface documented in js.h */
-jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv)
+nserror js_newthread(jsheap *heap, void *win_priv, void *doc_priv, jsthread
**thread)
{
- assert(ctx != NULL);
+ jsthread *ret;
+ assert(heap != NULL);
+
+ ret = calloc(1, sizeof (*ret));
+ if (ret == NULL) {
+ NSLOG(dukky, ERROR, "Unable to allocate new JS thread
structure");
+ return NSERROR_NOMEM;
+ }
+
NSLOG(dukky, DEBUG,
- "New javascript/duktape compartment, win_priv=%p, doc_priv=%p",
+ "New javascript/duktape thread, win_priv=%p, doc_priv=%p",
win_priv, doc_priv);
- /* Pop any active thread off */
- dukky_closecompartment(ctx);
-
- /* create new compartment thread */
- duk_push_thread(ctx->ctx);
- ctx->thread = duk_require_context(ctx->ctx, -1);
+ /* create new thread */
+ duk_get_global_string(heap->ctx, THREAD_MAP); /* ... threads */
+ duk_push_thread(heap->ctx); /* ... threads thread */
+ ret->heap = heap;
+ ret->ctx = duk_require_context(heap->ctx, -1);
+ ret->thread_idx = heap->next_thread++;
+ duk_put_prop_index(heap->ctx, -2, ret->thread_idx);
+ duk_pop(heap->ctx); /* ... */
duk_push_int(CTX, 0);
duk_push_int(CTX, 1);
duk_push_int(CTX, 2);
@@ -689,13 +683,15 @@ jsobject *js_newcompartment(jscontext *ctx, void
*win_priv, void *doc_priv)
if (duk_pcompile_lstring_filename(CTX, DUK_COMPILE_EVAL,
(const char *)polyfill_js,
polyfill_js_len) != 0) {
NSLOG(dukky, CRITICAL, "%s", duk_safe_to_string(CTX, -1));
- NSLOG(dukky, CRITICAL, "Unable to compile polyfill.js,
compartment aborted");
- return NULL;
+ NSLOG(dukky, CRITICAL, "Unable to compile polyfill.js, thread
aborted");
+ js_destroythread(ret);
+ return NSERROR_INIT_FAILED;
}
/* ..., (generics.js) */
if (dukky_pcall(CTX, 0, true) != 0) {
- NSLOG(dukky, CRITICAL, "Unable to run polyfill.js, compartment
aborted");
- return NULL;
+ NSLOG(dukky, CRITICAL, "Unable to run polyfill.js, thread
aborted");
+ js_destroythread(ret);
+ return NSERROR_INIT_FAILED;
}
/* ..., result */
duk_pop(CTX);
@@ -708,13 +704,15 @@ jsobject *js_newcompartment(jscontext *ctx, void
*win_priv, void *doc_priv)
if (duk_pcompile_lstring_filename(CTX, DUK_COMPILE_EVAL,
(const char *)generics_js,
generics_js_len) != 0) {
NSLOG(dukky, CRITICAL, "%s", duk_safe_to_string(CTX, -1));
- NSLOG(dukky, CRITICAL, "Unable to compile generics.js,
compartment aborted");
- return NULL;
+ NSLOG(dukky, CRITICAL, "Unable to compile generics.js, thread
aborted");
+ js_destroythread(ret);
+ return NSERROR_INIT_FAILED;
}
/* ..., (generics.js) */
if (dukky_pcall(CTX, 0, true) != 0) {
- NSLOG(dukky, CRITICAL, "Unable to run generics.js, compartment
aborted");
- return NULL;
+ NSLOG(dukky, CRITICAL, "Unable to run generics.js, thread
aborted");
+ js_destroythread(ret);
+ return NSERROR_INIT_FAILED;
}
/* ..., result */
duk_pop(CTX);
@@ -729,15 +727,44 @@ jsobject *js_newcompartment(jscontext *ctx, void
*win_priv, void *doc_priv)
duk_pop(CTX);
/* ... */
- dukky_log_stack_frame(CTX, "New compartment created");
+ dukky_log_stack_frame(CTX, "New thread created");
+ NSLOG(dukky, DEBUG, "New thread is %p in heap %p", thread, heap);
+ *thread = ret;
- return (jsobject *)ctx;
+ return NSERROR_OK;
+}
+
+/* Now switch to the long term CTX behaviour */
+#undef CTX
+#define CTX (thread->ctx)
+
+
+/* exported interface documented in js.h */
+void js_destroythread(jsthread *thread)
+{
+ jsheap *heap = thread->heap;
+ /* Closing down the extant thread */
+ NSLOG(dukky, DEBUG, "Closing down extant thread %p in heap %p", thread,
heap);
+ duk_get_global_string(CTX, MAGIC(closedownThread));
+ dukky_pcall(CTX, 0, true);
+
+ /* Now delete the thread from the heap */
+ duk_get_global_string(heap->ctx, THREAD_MAP); /* ... threads */
+ duk_del_prop_index(heap->ctx, -1, thread->thread_idx);
+ duk_pop(heap->ctx); /* ... */
+
+ /* We can now free the thread object */
+ free(thread);
+
+ /* Finally give the heap a chance to clean up */
+ duk_gc(heap->ctx, 0);
+ duk_gc(heap->ctx, DUK_GC_COMPACT);
}
duk_bool_t dukky_check_timeout(void *udata)
{
#define JS_EXEC_TIMEOUT_MS 10000 /* 10 seconds */
- jscontext *ctx = (jscontext *) udata;
+ jsheap *heap = (jsheap *) udata;
uint64_t now;
(void) nsu_getmonotonic_ms(&now);
@@ -746,8 +773,8 @@ duk_bool_t dukky_check_timeout(void *udata)
* so only test for execution timeout if we've recorded a
* start time.
*/
- return ctx->exec_start_time != 0 &&
- now > (ctx->exec_start_time + JS_EXEC_TIMEOUT_MS);
+ return heap->exec_start_time != 0 &&
+ now > (heap->exec_start_time + JS_EXEC_TIMEOUT_MS);
}
static void dukky_dump_error(duk_context *ctx)
@@ -761,14 +788,19 @@ static void dukky_dump_error(duk_context *ctx)
/* ..., errobj */
}
+static void dukky_reset_start_time(duk_context *ctx)
+{
+ duk_memory_functions funcs;
+ jsheap *heap;
+ duk_get_memory_functions(ctx, &funcs);
+ heap = funcs.udata;
+ (void) nsu_getmonotonic_ms(&heap->exec_start_time);
+}
+
duk_int_t dukky_pcall(duk_context *ctx, duk_size_t argc, bool reset_timeout)
{
if (reset_timeout) {
- duk_memory_functions funcs;
- jscontext *jsctx;
- duk_get_memory_functions(ctx, &funcs);
- jsctx = funcs.udata;
- (void) nsu_getmonotonic_ms(&jsctx->exec_start_time);
+ dukky_reset_start_time(ctx);
}
duk_int_t ret = duk_pcall(ctx, argc);
@@ -811,9 +843,9 @@ void dukky_log_stack_frame(duk_context *ctx, const char *
reason)
/* exported interface documented in js.h */
bool
-js_exec(jscontext *ctx, const uint8_t *txt, size_t txtlen, const char *name)
+js_exec(jsthread *thread, const uint8_t *txt, size_t txtlen, const char *name)
{
- assert(ctx);
+ assert(thread);
if (txt == NULL || txtlen == 0) {
return false;
@@ -823,7 +855,7 @@ js_exec(jscontext *ctx, const uint8_t *txt, size_t txtlen,
const char *name)
NSLOG(dukky, DEEPDEBUG, "Running %"PRIsizet" bytes from %s", txtlen,
name);
/* NSLOG(dukky, DEEPDEBUG, "\n%s\n", txt); */
- (void) nsu_getmonotonic_ms(&ctx->exec_start_time);
+ dukky_reset_start_time(CTX);
if (name != NULL) {
duk_push_string(CTX, name);
} else {
@@ -1023,9 +1055,7 @@ bool dukky_get_current_value_of_event_handler(duk_context
*ctx,
static void dukky_generic_event_handler(dom_event *evt, void *pw)
{
- duk_memory_functions funcs;
duk_context *ctx = (duk_context *)pw;
- jscontext *jsctx;
dom_string *name;
dom_exception exc;
dom_event_target *targ;
@@ -1033,10 +1063,6 @@ static void dukky_generic_event_handler(dom_event *evt,
void *pw)
duk_uarridx_t idx;
event_listener_flags flags;
- /* Retrieve the JS context from the Duktape context */
- duk_get_memory_functions(ctx, &funcs);
- jsctx = funcs.udata;
-
NSLOG(dukky, DEBUG, "Handling an event in duktape interface...");
exc = dom_event_get_type(evt, &name);
if (exc != DOM_NO_ERR) {
@@ -1084,7 +1110,7 @@ static void dukky_generic_event_handler(dom_event *evt,
void *pw)
/* ... handler node */
dukky_push_event(ctx, evt);
/* ... handler node event */
- (void) nsu_getmonotonic_ms(&jsctx->exec_start_time);
+ dukky_reset_start_time(ctx);
if (duk_pcall_method(ctx, 1) != 0) {
/* Failed to run the method */
/* ... err */
@@ -1183,7 +1209,7 @@ handle_extras:
/* ... copy handler callback node */
dukky_push_event(ctx, evt);
/* ... copy handler callback node event */
- (void) nsu_getmonotonic_ms(&jsctx->exec_start_time);
+ dukky_reset_start_time(ctx);
if (duk_pcall_method(ctx, 1) != 0) {
/* Failed to run the method */
/* ... copy handler err */
@@ -1355,9 +1381,9 @@ void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t
idx)
}
-void js_handle_new_element(jscontext *ctx, struct dom_element *node)
+void js_handle_new_element(jsthread *thread, struct dom_element *node)
{
- assert(ctx);
+ assert(thread);
assert(node);
dom_namednodemap *map;
dom_exception exc;
@@ -1431,9 +1457,9 @@ out:
dom_namednodemap_unref(map);
}
-void js_event_cleanup(jscontext *ctx, struct dom_event *evt)
+void js_event_cleanup(jsthread *thread, struct dom_event *evt)
{
- assert(ctx);
+ assert(thread);
/* ... */
duk_get_global_string(CTX, EVENT_MAGIC);
/* ... EVENT_MAP */
@@ -1445,7 +1471,7 @@ void js_event_cleanup(jscontext *ctx, struct dom_event
*evt)
/* ... */
}
-bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc,
struct dom_node *target)
+bool js_fire_event(jsthread *thread, const char *type, struct dom_document
*doc, struct dom_node *target)
{
dom_exception exc;
dom_event *evt;
@@ -1523,7 +1549,7 @@ bool js_fire_event(jscontext *ctx, const char *type,
struct dom_document *doc, s
/* ... handler Window */
dukky_push_event(CTX, evt);
/* ... handler Window event */
- (void) nsu_getmonotonic_ms(&ctx->exec_start_time);
+ dukky_reset_start_time(CTX);
if (duk_pcall_method(CTX, 1) != 0) {
/* Failed to run the handler */
/* ... err */
@@ -1546,14 +1572,14 @@ bool js_fire_event(jscontext *ctx, const char *type,
struct dom_document *doc, s
duk_pop_n(CTX, 6);
/* ... */
- js_event_cleanup(ctx, evt);
+ js_event_cleanup(thread, evt);
dom_event_unref(evt);
return true;
}
/* ... result */
duk_pop(CTX);
/* ... */
- js_event_cleanup(ctx, evt);
+ js_event_cleanup(thread, evt);
dom_event_unref(evt);
return true;
}
diff --git a/content/handlers/javascript/duktape/polyfill.js
b/content/handlers/javascript/duktape/polyfill.js
index 7fa4611..5f02156 100644
--- a/content/handlers/javascript/duktape/polyfill.js
+++ b/content/handlers/javascript/duktape/polyfill.js
@@ -1,6 +1,6 @@
/* Polyfiller for Duktape for NetSurf
*
- * This JavaScript will be loaded into compartments before the generics
+ * This JavaScript will be loaded into heaps before the generics
*
* We only care for the side-effects of this, be careful.
*/
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=66a23c25605c9c7eca7b5c9b420a079ce1203faf
commit 66a23c25605c9c7eca7b5c9b420a079ce1203faf
Author: Daniel Silverstone <[email protected]>
Commit: Daniel Silverstone <[email protected]>
Browser: Split JS threads between current and loading
Signed-off-by: Daniel Silverstone <[email protected]>
diff --git a/desktop/browser_private.h b/desktop/browser_private.h
index 562abf1..89dc5cc 100644
--- a/desktop/browser_private.h
+++ b/desktop/browser_private.h
@@ -264,7 +264,12 @@ struct browser_window {
/** current javascript context */
struct jsheap *jsheap;
- struct jsthread *jsthread;
+
+ /** The JS thread (if any) for the current content */
+ struct jsthread *current_jsthread;
+
+ /** The JS thread (if any) for the loading content */
+ struct jsthread *loading_jsthread;
/** cache of the currently displayed status text. */
struct {
diff --git a/desktop/browser_window.c b/desktop/browser_window.c
index bd446a0..c98eca8 100644
--- a/desktop/browser_window.c
+++ b/desktop/browser_window.c
@@ -702,6 +702,10 @@ browser_window_convert_to_download(struct browser_window
*bw,
/* remove content from browser window */
hlcache_handle_release(bw->loading_content);
bw->loading_content = NULL;
+ if (bw->loading_jsthread != NULL) {
+ js_destroythread(bw->loading_jsthread);
+ bw->loading_jsthread = NULL;
+ }
browser_window_stop_throbber(bw);
}
@@ -719,10 +723,15 @@ static nserror browser_window_content_ready(struct
browser_window *bw)
if (bw->current_content != NULL) {
content_close(bw->current_content);
hlcache_handle_release(bw->current_content);
+ if (bw->current_jsthread != NULL) {
+ js_destroythread(bw->current_jsthread);
+ }
}
bw->current_content = bw->loading_content;
+ bw->current_jsthread = bw->loading_jsthread;
bw->loading_content = NULL;
+ bw->loading_jsthread = NULL;
if (!bw->internal_nav) {
/* Transfer the fetch parameters */
@@ -1280,6 +1289,10 @@ browser_window__handle_error(struct browser_window *bw,
if (c == bw->loading_content) {
bw->loading_content = NULL;
+ if (bw->loading_jsthread != NULL) {
+ js_destroythread(bw->loading_jsthread);
+ bw->loading_jsthread = NULL;
+ }
} else if (c == bw->current_content) {
bw->current_content = NULL;
browser_window_remove_caret(bw, false);
@@ -1486,18 +1499,16 @@ browser_window_callback(hlcache_handle *c, const
hlcache_event *event, void *pw)
break;
case CONTENT_MSG_GETTHREAD:
- {
- /* only the content object created by the browser
- * window requires a new global compartment object
- */
- jsthread *thread;
- assert(bw->loading_content == c);
- if (js_newthread(bw->jsheap,
- bw,
- hlcache_handle_get_content(c),
- &thread) == NSERROR_OK) {
- *(event->data.jsthread) = thread;
- }
+ /* only the content object created by the browser
+ * window requires a new javascript thread object
+ */
+ assert(bw->loading_content == c);
+ assert(bw->loading_jsthread == NULL);
+ if (js_newthread(bw->jsheap,
+ bw,
+ hlcache_handle_get_content(c),
+ &bw->loading_jsthread) == NSERROR_OK) {
+ *(event->data.jsthread) = bw->loading_jsthread;
}
break;
@@ -1741,12 +1752,22 @@ static void browser_window_destroy_internal(struct
browser_window *bw)
bw->loading_content = NULL;
}
+ if (bw->loading_jsthread != NULL) {
+ js_destroythread(bw->loading_jsthread);
+ bw->loading_jsthread = NULL;
+ }
+
if (bw->current_content != NULL) {
content_close(bw->current_content);
hlcache_handle_release(bw->current_content);
bw->current_content = NULL;
}
+ if (bw->current_jsthread != NULL) {
+ js_destroythread(bw->current_jsthread);
+ bw->current_jsthread = NULL;
+ }
+
if (bw->favicon.loading != NULL) {
hlcache_handle_abort(bw->favicon.loading);
hlcache_handle_release(bw->favicon.loading);
@@ -1766,6 +1787,7 @@ static void browser_window_destroy_internal(struct
browser_window *bw)
if (bw->jsheap != NULL) {
js_destroyheap(bw->jsheap);
+ bw->jsheap = NULL;
}
/* These simply free memory, so are safe here */
@@ -4069,6 +4091,10 @@ void browser_window_stop(struct browser_window *bw)
hlcache_handle_abort(bw->loading_content);
hlcache_handle_release(bw->loading_content);
bw->loading_content = NULL;
+ if (bw->loading_jsthread != NULL) {
+ js_destroythread(bw->loading_jsthread);
+ bw->loading_jsthread = NULL;
+ }
}
if (bw->current_content != NULL &&
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=337082f715951fe9f5b46f1a4710ca415f67e22d
commit 337082f715951fe9f5b46f1a4710ca415f67e22d
Author: Daniel Silverstone <[email protected]>
Commit: Daniel Silverstone <[email protected]>
JS: Add concept of thread destroy
Signed-off-by: Daniel Silverstone <[email protected]>
diff --git a/content/handlers/javascript/js.h b/content/handlers/javascript/js.h
index 126cb7c..ce9bb9b 100644
--- a/content/handlers/javascript/js.h
+++ b/content/handlers/javascript/js.h
@@ -97,6 +97,20 @@ void js_destroyheap(jsheap *heap);
nserror js_newthread(jsheap *heap, void *win_priv, void *doc_priv, jsthread
**thread);
/**
+ * Destroy a javascript thread
+ *
+ * This should be called when the browsing context is done with the thread.
+ *
+ * Essentially it should be called when the content is about to be destroyed
+ * but in reality it can be called when the browser window relinquishes its
+ * handle on the content since nominally the browser window itself owns
+ * the thread.
+ *
+ * \param thread The thread to be destroyed
+ */
+void js_destroythread(jsthread *thread);
+
+/**
* execute some javascript in a context
*/
bool js_exec(jsthread *thread, const uint8_t *txt, size_t txtlen, const char
*name);
diff --git a/content/handlers/javascript/none/none.c
b/content/handlers/javascript/none/none.c
index b79d324..ff09f52 100644
--- a/content/handlers/javascript/none/none.c
+++ b/content/handlers/javascript/none/none.c
@@ -51,6 +51,10 @@ nserror js_newthread(jsheap *heap, void *win_priv, void
*doc_priv, jsthread **th
return NSERROR_NOT_IMPLEMENTED;
}
+void js_destroythread(jsthread *thread)
+{
+}
+
bool js_exec(jsthread *thread, const uint8_t *txt, size_t txtlen, const char
*name)
{
return true;
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=17b28e85c12309d60e3c45acb096b9989a7834ff
commit 17b28e85c12309d60e3c45acb096b9989a7834ff
Author: Daniel Silverstone <[email protected]>
Commit: Daniel Silverstone <[email protected]>
JS: Split concept of JS context into heap and thread
In preparation for proper splitting of Javascript support into
heaps and threads, this renames the types and corrects the no-js
builds to still work. At this time no substantive change in
semantics exists, and the duktape build won't work.
Signed-off-by: Daniel Silverstone <[email protected]>
diff --git a/content/content.h b/content/content.h
index f8f8d32..c2605a7 100644
--- a/content/content.h
+++ b/content/content.h
@@ -72,7 +72,7 @@ typedef enum {
CONTENT_MSG_REFRESH, /**< wants refresh */
CONTENT_MSG_DOWNLOAD, /**< download, not for display */
CONTENT_MSG_LINK, /**< RFC5988 link */
- CONTENT_MSG_GETCTX, /**< Javascript context */
+ CONTENT_MSG_GETTHREAD, /**< Javascript thread */
CONTENT_MSG_GETDIMS, /**< Get viewport dimensions. */
CONTENT_MSG_SCROLL, /**< Request to scroll content */
CONTENT_MSG_DRAGSAVE, /**< Allow drag saving of content */
@@ -180,9 +180,9 @@ union content_msg_data {
struct content_rfc5988_link *rfc5988_link;
/**
- * CONTENT_MSG_GETCTX - Javascript context
+ * CONTENT_MSG_GETTHREAD - Javascript context (thread)
*/
- struct jscontext **jscontext;
+ struct jsthread **jsthread;
/**
* CONTENT_MSG_GETDIMS - Get the viewport dimensions
diff --git a/content/handlers/html/html.c b/content/handlers/html/html.c
index d1b810f..26be58d 100644
--- a/content/handlers/html/html.c
+++ b/content/handlers/html/html.c
@@ -757,8 +757,8 @@ void html_finish_conversion(html_content *htmlc)
* object, but with its target set to the Document object (and
* the currentTarget set to the Window object)
*/
- if (htmlc->jscontext != NULL) {
- js_fire_event(htmlc->jscontext, "load", htmlc->document, NULL);
+ if (htmlc->jsthread != NULL) {
+ js_fire_event(htmlc->jsthread, "load", htmlc->document, NULL);
}
/* convert dom tree to box tree */
@@ -896,20 +896,20 @@ dom_default_action_DOMNodeInserted_cb(struct dom_event
*evt, void *pw)
}
if (htmlc->enable_scripting) {
/* ensure javascript context is available */
- if (htmlc->jscontext == NULL) {
+ if (htmlc->jsthread == NULL) {
union content_msg_data msg_data;
- msg_data.jscontext = &htmlc->jscontext;
+ msg_data.jsthread = &htmlc->jsthread;
content_broadcast(&htmlc->base,
- CONTENT_MSG_GETCTX,
+ CONTENT_MSG_GETTHREAD,
&msg_data);
NSLOG(netsurf, INFO,
"javascript context: %p (htmlc:
%p)",
- htmlc->jscontext,
+ htmlc->jsthread,
htmlc);
}
- if (htmlc->jscontext != NULL) {
- js_handle_new_element(htmlc->jscontext,
+ if (htmlc->jsthread != NULL) {
+ js_handle_new_element(htmlc->jsthread,
(dom_element *) node);
}
}
@@ -1015,8 +1015,8 @@ dom_default_action_finished_cb(struct dom_event *evt,
void *pw)
{
html_content *htmlc = pw;
- if (htmlc->jscontext != NULL)
- js_event_cleanup(htmlc->jscontext, evt);
+ if (htmlc->jsthread != NULL)
+ js_event_cleanup(htmlc->jsthread, evt);
}
/* callback function selector
@@ -1136,7 +1136,7 @@ html_create_html_data(html_content *c, const
http_parameter *params)
c->search_string = NULL;
c->scripts_count = 0;
c->scripts = NULL;
- c->jscontext = NULL;
+ c->jsthread = NULL;
c->enable_scripting = nsoption_bool(enable_javascript);
c->base.active = 1; /* The html content itself is active */
diff --git a/content/handlers/html/html_internal.h
b/content/handlers/html/html_internal.h
index 9b363dc..a640781 100644
--- a/content/handlers/html/html_internal.h
+++ b/content/handlers/html/html_internal.h
@@ -151,8 +151,8 @@ typedef struct html_content {
unsigned int scripts_count;
/** Scripts */
struct html_script *scripts;
- /** javascript context */
- struct jscontext *jscontext;
+ /** javascript thread in use */
+ struct jsthread *jsthread;
/** Number of entries in stylesheet_content. */
unsigned int stylesheet_count;
diff --git a/content/handlers/html/html_object.c
b/content/handlers/html/html_object.c
index 223f551..3a60c47 100644
--- a/content/handlers/html/html_object.c
+++ b/content/handlers/html/html_object.c
@@ -340,8 +340,9 @@ html_object_callback(hlcache_handle *object,
/* Don't care about favicons that aren't on top level content */
break;
- case CONTENT_MSG_GETCTX:
- *(event->data.jscontext) = NULL;
+ case CONTENT_MSG_GETTHREAD:
+ /* Objects don't have JS threads */
+ *(event->data.jsthread) = NULL;
break;
case CONTENT_MSG_GETDIMS:
diff --git a/content/handlers/html/html_script.c
b/content/handlers/html/html_script.c
index 4df5f33..301acad 100644
--- a/content/handlers/html/html_script.c
+++ b/content/handlers/html/html_script.c
@@ -42,7 +42,7 @@
#include "html/html.h"
#include "html/html_internal.h"
-typedef bool (script_handler_t)(struct jscontext *jscontext, const uint8_t
*data, size_t size, const char *name);
+typedef bool (script_handler_t)(struct jsthread *jsthread, const uint8_t
*data, size_t size, const char *name);
static script_handler_t *select_script_handler(content_type ctype)
@@ -62,7 +62,7 @@ nserror html_script_exec(html_content *c, bool allow_defer)
script_handler_t *script_handler;
bool have_run_something = false;
- if (c->jscontext == NULL) {
+ if (c->jsthread == NULL) {
return NSERROR_BAD_PARAMETER;
}
@@ -95,7 +95,7 @@ nserror html_script_exec(html_content *c, bool allow_defer)
size_t size;
data = content_get_source_data(
s->data.handle, &size );
- script_handler(c->jscontext, data, size,
+ script_handler(c->jsthread, data, size,
nsurl_access(hlcache_handle_get_url(s->data.handle)));
have_run_something = true;
/* We have to re-acquire this here since the
@@ -319,12 +319,12 @@ convert_script_sync_cb(hlcache_handle *script,
/* attempt to execute script */
script_handler =
select_script_handler(content_get_type(s->data.handle));
- if (script_handler != NULL && parent->jscontext != NULL) {
+ if (script_handler != NULL && parent->jsthread != NULL) {
/* script has a handler */
const uint8_t *data;
size_t size;
data = content_get_source_data(s->data.handle, &size );
- script_handler(parent->jscontext, data, size,
+ script_handler(parent->jsthread, data, size,
nsurl_access(hlcache_handle_get_url(s->data.handle)));
}
@@ -549,7 +549,7 @@ exec_inline_script(html_content *c, dom_node *node,
dom_string *mimetype)
lwc_string_unref(lwcmimetype);
if (script_handler != NULL) {
- script_handler(c->jscontext,
+ script_handler(c->jsthread,
(const uint8_t *)dom_string_data(script),
dom_string_byte_length(script),
"?inline script?");
@@ -575,13 +575,13 @@ html_process_script(void *ctx, dom_node *node)
/* We should only ever be here if scripting was enabled for this
* content so it's correct to make a javascript context if there
* isn't one already. */
- if (c->jscontext == NULL) {
+ if (c->jsthread == NULL) {
union content_msg_data msg_data;
- msg_data.jscontext = &c->jscontext;
- content_broadcast(&c->base, CONTENT_MSG_GETCTX, &msg_data);
- NSLOG(netsurf, INFO, "javascript context %p ", c->jscontext);
- if (c->jscontext == NULL) {
+ msg_data.jsthread = &c->jsthread;
+ content_broadcast(&c->base, CONTENT_MSG_GETTHREAD, &msg_data);
+ NSLOG(netsurf, INFO, "javascript context %p ", c->jsthread);
+ if (c->jsthread == NULL) {
/* no context and it could not be created, abort */
return DOM_HUBBUB_OK;
}
@@ -668,6 +668,6 @@ nserror html_script_free(html_content *html)
/* exported internal interface documented in html/html_internal.h */
nserror html_script_invalidate_ctx(html_content *htmlc)
{
- htmlc->jscontext = NULL;
+ htmlc->jsthread = NULL;
return NSERROR_OK;
}
diff --git a/content/handlers/javascript/js.h b/content/handlers/javascript/js.h
index 522dd98..126cb7c 100644
--- a/content/handlers/javascript/js.h
+++ b/content/handlers/javascript/js.h
@@ -25,9 +25,6 @@
#include "utils/errors.h"
-typedef struct jscontext jscontext;
-typedef struct jsobject jsobject;
-
struct dom_event;
struct dom_document;
struct dom_node;
@@ -35,6 +32,27 @@ struct dom_element;
struct dom_string;
/**
+ * JavaScript interpreter heap
+ *
+ * In order to try and be moderately performant, we create a heap
+ * per browser window. This heap is shared by all browsing contexts
+ * we end up creating in that window.
+ */
+typedef struct jsheap jsheap;
+
+/**
+ * JavaScript interpreter thread
+ *
+ * When we create a browsing context itself (window+content) we have
+ * to create a JS thread to attach to the browsing context.
+ *
+ * JS threads are associated with heaps and will be destroyed when
+ * the heap is destroyed. They can be shut down manually though
+ * and should be for object lifetime safety reasons.
+ */
+typedef struct jsthread jsthread;
+
+/**
* Initialise javascript interpreter
*/
void js_initialise(void);
@@ -45,41 +63,51 @@ void js_initialise(void);
void js_finalise(void);
/**
- * Create a new javascript context.
+ * Create a new javascript heap.
*
- * There is usually one context per browsing context (browser window)
+ * There is usually one heap per browser window.
*
* \param timeout elapsed wallclock time (in seconds) before \a callback is
called
- * \param jsctx Updated to the created JS context
+ * \param heap Updated to the created JS heap
* \return NSERROR_OK on success, appropriate error otherwise.
*/
-nserror js_newcontext(int timeout, jscontext **jsctx);
+nserror js_newheap(int timeout, jsheap **heap);
/**
- * Destroy a previously created context
+ * Destroy a previously created heap.
+ *
+ * \param heap The heap to destroy
*/
-void js_destroycontext(jscontext *ctx);
+void js_destroyheap(jsheap *heap);
/**
- * Create a new javascript compartment
+ * Create a new javascript thread
*
* This is called once for a page with javascript script tags on
- * it. It constructs a fresh global window object.
+ * it. It constructs a fresh global window object and prepares the JS
+ * browsing context. It's important that threads are shut down cleanly
+ * when the browsing context is going to be cleaned up.
+ *
+ * \param heap The heap to create the thread within
+ * \param win_priv The value to give to the Window constructor as the window
+ * \param doc_priv The value to give to the Document constructor as the
document
+ * \param thread Updated to the created thread
+ * \return NSERROR_OK on success, appropriate error otherwise
*/
-jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv);
+nserror js_newthread(jsheap *heap, void *win_priv, void *doc_priv, jsthread
**thread);
/**
* execute some javascript in a context
*/
-bool js_exec(jscontext *ctx, const uint8_t *txt, size_t txtlen, const char
*name);
+bool js_exec(jsthread *thread, const uint8_t *txt, size_t txtlen, const char
*name);
/**
* fire an event at a dom node
*/
-bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc,
struct dom_node *target);
+bool js_fire_event(jsthread *thread, const char *type, struct dom_document
*doc, struct dom_node *target);
bool
-js_dom_event_add_listener(jscontext *ctx,
+js_dom_event_add_listener(jsthread *thread,
struct dom_document *document,
struct dom_node *node,
struct dom_string *event_type_dom,
@@ -94,7 +122,7 @@ js_dom_event_add_listener(jscontext *ctx,
* by the context provided. The JS implementation must then scan the element
* for on* attributes and register appropriate listeners for those handlers.
*/
-void js_handle_new_element(jscontext *ctx, struct dom_element *node);
+void js_handle_new_element(jsthread *thread, struct dom_element *node);
/**
* Handle an event propagation finished callback.
@@ -104,6 +132,6 @@ void js_handle_new_element(jscontext *ctx, struct
dom_element *node);
* it may need to perform before the DOM finishes and the event may end up
* freed.
*/
-void js_event_cleanup(jscontext *ctx, struct dom_event *evt);
+void js_event_cleanup(jsthread *thread, struct dom_event *evt);
#endif /* NETSURF_JAVASCRIPT_JS_H_ */
diff --git a/content/handlers/javascript/none/none.c
b/content/handlers/javascript/none/none.c
index 26b9b53..b79d324 100644
--- a/content/handlers/javascript/none/none.c
+++ b/content/handlers/javascript/none/none.c
@@ -35,35 +35,36 @@ void js_finalise(void)
{
}
-nserror js_newcontext(int timeout, jscontext **jsctx)
+nserror js_newheap(int timeout, jsheap **heap)
{
- *jsctx = NULL;
+ *heap = NULL;
return NSERROR_OK;
}
-void js_destroycontext(jscontext *ctx)
+void js_destroyheap(jsheap *heap)
{
}
-jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv)
+nserror js_newthread(jsheap *heap, void *win_priv, void *doc_priv, jsthread
**thread)
{
- return NULL;
+ *thread = NULL;
+ return NSERROR_NOT_IMPLEMENTED;
}
-bool js_exec(jscontext *ctx, const uint8_t *txt, size_t txtlen, const char
*name)
+bool js_exec(jsthread *thread, const uint8_t *txt, size_t txtlen, const char
*name)
{
return true;
}
-bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc,
struct dom_node *target)
+bool js_fire_event(jsthread *thread, const char *type, struct dom_document
*doc, struct dom_node *target)
{
return true;
}
-void js_handle_new_element(jscontext *ctx, struct dom_element *node)
+void js_handle_new_element(jsthread *thread, struct dom_element *node)
{
}
-void js_event_cleanup(jscontext *ctx, struct dom_event *evt)
+void js_event_cleanup(jsthread *thread, struct dom_event *evt)
{
}
diff --git a/desktop/browser_private.h b/desktop/browser_private.h
index c9f9bbc..562abf1 100644
--- a/desktop/browser_private.h
+++ b/desktop/browser_private.h
@@ -263,7 +263,8 @@ struct browser_window {
bool can_edit;
/** current javascript context */
- struct jscontext *jsctx;
+ struct jsheap *jsheap;
+ struct jsthread *jsthread;
/** cache of the currently displayed status text. */
struct {
diff --git a/desktop/browser_window.c b/desktop/browser_window.c
index 3d1a19f..bd446a0 100644
--- a/desktop/browser_window.c
+++ b/desktop/browser_window.c
@@ -1485,15 +1485,19 @@ browser_window_callback(hlcache_handle *c, const
hlcache_event *event, void *pw)
}
break;
- case CONTENT_MSG_GETCTX:
- /* only the content object created by the browser
- * window requires a new global compartment object
- */
- assert(bw->loading_content == c);
- if (js_newcompartment(bw->jsctx,
- bw,
- hlcache_handle_get_content(c)) != NULL) {
- *(event->data.jscontext) = bw->jsctx;
+ case CONTENT_MSG_GETTHREAD:
+ {
+ /* only the content object created by the browser
+ * window requires a new global compartment object
+ */
+ jsthread *thread;
+ assert(bw->loading_content == c);
+ if (js_newthread(bw->jsheap,
+ bw,
+ hlcache_handle_get_content(c),
+ &thread) == NSERROR_OK) {
+ *(event->data.jsthread) = thread;
+ }
}
break;
@@ -1760,8 +1764,8 @@ static void browser_window_destroy_internal(struct
browser_window *bw)
bw->box = NULL;
}
- if (bw->jsctx != NULL) {
- js_destroycontext(bw->jsctx);
+ if (bw->jsheap != NULL) {
+ js_destroyheap(bw->jsheap);
}
/* These simply free memory, so are safe here */
@@ -3085,7 +3089,7 @@ browser_window_initialise_common(enum
browser_window_create_flags flags,
assert(bw);
/* new javascript context for each window/(i)frame */
- err = js_newcontext(nsoption_int(script_timeout), &bw->jsctx);
+ err = js_newheap(nsoption_int(script_timeout), &bw->jsheap);
if (err != NSERROR_OK)
return err;
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=313dc9b099a172914f312120f0f9d0260a3588cf
commit 313dc9b099a172914f312120f0f9d0260a3588cf
Author: Daniel Silverstone <[email protected]>
Commit: Daniel Silverstone <[email protected]>
JS: Remove unused slow script callback
Signed-off-by: Daniel Silverstone <[email protected]>
diff --git a/content/handlers/javascript/duktape/dukky.c
b/content/handlers/javascript/duktape/dukky.c
index dcbff68..560a12f 100644
--- a/content/handlers/javascript/duktape/dukky.c
+++ b/content/handlers/javascript/duktape/dukky.c
@@ -608,7 +608,7 @@ void js_finalise(void)
/* exported interface documented in js.h */
nserror
-js_newcontext(int timeout, jscallback *cb, void *cbctx, jscontext **jsctx)
+js_newcontext(int timeout, jscontext **jsctx)
{
duk_context *ctx;
jscontext *ret = calloc(1, sizeof(*ret));
diff --git a/content/handlers/javascript/js.h b/content/handlers/javascript/js.h
index d5af721..522dd98 100644
--- a/content/handlers/javascript/js.h
+++ b/content/handlers/javascript/js.h
@@ -28,8 +28,6 @@
typedef struct jscontext jscontext;
typedef struct jsobject jsobject;
-typedef bool(jscallback)(void *ctx);
-
struct dom_event;
struct dom_document;
struct dom_node;
@@ -52,12 +50,10 @@ void js_finalise(void);
* There is usually one context per browsing context (browser window)
*
* \param timeout elapsed wallclock time (in seconds) before \a callback is
called
- * \param cb the callback when the runtime exceeds the timeout
- * \param cbctx The context to pass to the callback
* \param jsctx Updated to the created JS context
* \return NSERROR_OK on success, appropriate error otherwise.
*/
-nserror js_newcontext(int timeout, jscallback *cb, void *cbctx, jscontext
**jsctx);
+nserror js_newcontext(int timeout, jscontext **jsctx);
/**
* Destroy a previously created context
diff --git a/content/handlers/javascript/none/none.c
b/content/handlers/javascript/none/none.c
index 80a9ce4..26b9b53 100644
--- a/content/handlers/javascript/none/none.c
+++ b/content/handlers/javascript/none/none.c
@@ -35,8 +35,7 @@ void js_finalise(void)
{
}
-nserror js_newcontext(int timeout, jscallback *cb, void *cbctx,
- jscontext **jsctx)
+nserror js_newcontext(int timeout, jscontext **jsctx)
{
*jsctx = NULL;
return NSERROR_OK;
diff --git a/desktop/browser_window.c b/desktop/browser_window.c
index 3c072ef..3d1a19f 100644
--- a/desktop/browser_window.c
+++ b/desktop/browser_window.c
@@ -330,22 +330,6 @@ browser_window__get_contextual_content(struct
browser_window *bw,
/**
- * slow script handler
- */
-static bool slow_script(void *ctx)
-{
- static int count = 0;
- NSLOG(netsurf, INFO, "Continuing execution %d", count);
- count++;
- if (count > 1) {
- count = 0;
- return false;
- }
- return true;
-}
-
-
-/**
* implements the download operation of a window navigate
*/
static nserror
@@ -3101,8 +3085,7 @@ browser_window_initialise_common(enum
browser_window_create_flags flags,
assert(bw);
/* new javascript context for each window/(i)frame */
- err = js_newcontext(nsoption_int(script_timeout),
- slow_script, NULL, &bw->jsctx);
+ err = js_newcontext(nsoption_int(script_timeout), &bw->jsctx);
if (err != NSERROR_OK)
return err;
-----------------------------------------------------------------------
Summary of changes:
content/content.h | 6 +-
content/handlers/html/html.c | 22 +-
content/handlers/html/html_internal.h | 4 +-
content/handlers/html/html_object.c | 5 +-
content/handlers/html/html_script.c | 24 +--
content/handlers/javascript/duktape/Window.bnd | 12 +-
content/handlers/javascript/duktape/dukky.c | 260 +++++++++++++++--------
content/handlers/javascript/duktape/polyfill.js | 2 +-
content/handlers/javascript/js.h | 80 +++++--
content/handlers/javascript/none/none.c | 24 ++-
desktop/browser_private.h | 8 +-
desktop/browser_window.c | 65 +++---
12 files changed, 327 insertions(+), 185 deletions(-)
diff --git a/content/content.h b/content/content.h
index f8f8d32..c2605a7 100644
--- a/content/content.h
+++ b/content/content.h
@@ -72,7 +72,7 @@ typedef enum {
CONTENT_MSG_REFRESH, /**< wants refresh */
CONTENT_MSG_DOWNLOAD, /**< download, not for display */
CONTENT_MSG_LINK, /**< RFC5988 link */
- CONTENT_MSG_GETCTX, /**< Javascript context */
+ CONTENT_MSG_GETTHREAD, /**< Javascript thread */
CONTENT_MSG_GETDIMS, /**< Get viewport dimensions. */
CONTENT_MSG_SCROLL, /**< Request to scroll content */
CONTENT_MSG_DRAGSAVE, /**< Allow drag saving of content */
@@ -180,9 +180,9 @@ union content_msg_data {
struct content_rfc5988_link *rfc5988_link;
/**
- * CONTENT_MSG_GETCTX - Javascript context
+ * CONTENT_MSG_GETTHREAD - Javascript context (thread)
*/
- struct jscontext **jscontext;
+ struct jsthread **jsthread;
/**
* CONTENT_MSG_GETDIMS - Get the viewport dimensions
diff --git a/content/handlers/html/html.c b/content/handlers/html/html.c
index d1b810f..26be58d 100644
--- a/content/handlers/html/html.c
+++ b/content/handlers/html/html.c
@@ -757,8 +757,8 @@ void html_finish_conversion(html_content *htmlc)
* object, but with its target set to the Document object (and
* the currentTarget set to the Window object)
*/
- if (htmlc->jscontext != NULL) {
- js_fire_event(htmlc->jscontext, "load", htmlc->document, NULL);
+ if (htmlc->jsthread != NULL) {
+ js_fire_event(htmlc->jsthread, "load", htmlc->document, NULL);
}
/* convert dom tree to box tree */
@@ -896,20 +896,20 @@ dom_default_action_DOMNodeInserted_cb(struct dom_event
*evt, void *pw)
}
if (htmlc->enable_scripting) {
/* ensure javascript context is available */
- if (htmlc->jscontext == NULL) {
+ if (htmlc->jsthread == NULL) {
union content_msg_data msg_data;
- msg_data.jscontext = &htmlc->jscontext;
+ msg_data.jsthread = &htmlc->jsthread;
content_broadcast(&htmlc->base,
- CONTENT_MSG_GETCTX,
+ CONTENT_MSG_GETTHREAD,
&msg_data);
NSLOG(netsurf, INFO,
"javascript context: %p (htmlc:
%p)",
- htmlc->jscontext,
+ htmlc->jsthread,
htmlc);
}
- if (htmlc->jscontext != NULL) {
- js_handle_new_element(htmlc->jscontext,
+ if (htmlc->jsthread != NULL) {
+ js_handle_new_element(htmlc->jsthread,
(dom_element *) node);
}
}
@@ -1015,8 +1015,8 @@ dom_default_action_finished_cb(struct dom_event *evt,
void *pw)
{
html_content *htmlc = pw;
- if (htmlc->jscontext != NULL)
- js_event_cleanup(htmlc->jscontext, evt);
+ if (htmlc->jsthread != NULL)
+ js_event_cleanup(htmlc->jsthread, evt);
}
/* callback function selector
@@ -1136,7 +1136,7 @@ html_create_html_data(html_content *c, const
http_parameter *params)
c->search_string = NULL;
c->scripts_count = 0;
c->scripts = NULL;
- c->jscontext = NULL;
+ c->jsthread = NULL;
c->enable_scripting = nsoption_bool(enable_javascript);
c->base.active = 1; /* The html content itself is active */
diff --git a/content/handlers/html/html_internal.h
b/content/handlers/html/html_internal.h
index 9b363dc..a640781 100644
--- a/content/handlers/html/html_internal.h
+++ b/content/handlers/html/html_internal.h
@@ -151,8 +151,8 @@ typedef struct html_content {
unsigned int scripts_count;
/** Scripts */
struct html_script *scripts;
- /** javascript context */
- struct jscontext *jscontext;
+ /** javascript thread in use */
+ struct jsthread *jsthread;
/** Number of entries in stylesheet_content. */
unsigned int stylesheet_count;
diff --git a/content/handlers/html/html_object.c
b/content/handlers/html/html_object.c
index 223f551..3a60c47 100644
--- a/content/handlers/html/html_object.c
+++ b/content/handlers/html/html_object.c
@@ -340,8 +340,9 @@ html_object_callback(hlcache_handle *object,
/* Don't care about favicons that aren't on top level content */
break;
- case CONTENT_MSG_GETCTX:
- *(event->data.jscontext) = NULL;
+ case CONTENT_MSG_GETTHREAD:
+ /* Objects don't have JS threads */
+ *(event->data.jsthread) = NULL;
break;
case CONTENT_MSG_GETDIMS:
diff --git a/content/handlers/html/html_script.c
b/content/handlers/html/html_script.c
index 4df5f33..301acad 100644
--- a/content/handlers/html/html_script.c
+++ b/content/handlers/html/html_script.c
@@ -42,7 +42,7 @@
#include "html/html.h"
#include "html/html_internal.h"
-typedef bool (script_handler_t)(struct jscontext *jscontext, const uint8_t
*data, size_t size, const char *name);
+typedef bool (script_handler_t)(struct jsthread *jsthread, const uint8_t
*data, size_t size, const char *name);
static script_handler_t *select_script_handler(content_type ctype)
@@ -62,7 +62,7 @@ nserror html_script_exec(html_content *c, bool allow_defer)
script_handler_t *script_handler;
bool have_run_something = false;
- if (c->jscontext == NULL) {
+ if (c->jsthread == NULL) {
return NSERROR_BAD_PARAMETER;
}
@@ -95,7 +95,7 @@ nserror html_script_exec(html_content *c, bool allow_defer)
size_t size;
data = content_get_source_data(
s->data.handle, &size );
- script_handler(c->jscontext, data, size,
+ script_handler(c->jsthread, data, size,
nsurl_access(hlcache_handle_get_url(s->data.handle)));
have_run_something = true;
/* We have to re-acquire this here since the
@@ -319,12 +319,12 @@ convert_script_sync_cb(hlcache_handle *script,
/* attempt to execute script */
script_handler =
select_script_handler(content_get_type(s->data.handle));
- if (script_handler != NULL && parent->jscontext != NULL) {
+ if (script_handler != NULL && parent->jsthread != NULL) {
/* script has a handler */
const uint8_t *data;
size_t size;
data = content_get_source_data(s->data.handle, &size );
- script_handler(parent->jscontext, data, size,
+ script_handler(parent->jsthread, data, size,
nsurl_access(hlcache_handle_get_url(s->data.handle)));
}
@@ -549,7 +549,7 @@ exec_inline_script(html_content *c, dom_node *node,
dom_string *mimetype)
lwc_string_unref(lwcmimetype);
if (script_handler != NULL) {
- script_handler(c->jscontext,
+ script_handler(c->jsthread,
(const uint8_t *)dom_string_data(script),
dom_string_byte_length(script),
"?inline script?");
@@ -575,13 +575,13 @@ html_process_script(void *ctx, dom_node *node)
/* We should only ever be here if scripting was enabled for this
* content so it's correct to make a javascript context if there
* isn't one already. */
- if (c->jscontext == NULL) {
+ if (c->jsthread == NULL) {
union content_msg_data msg_data;
- msg_data.jscontext = &c->jscontext;
- content_broadcast(&c->base, CONTENT_MSG_GETCTX, &msg_data);
- NSLOG(netsurf, INFO, "javascript context %p ", c->jscontext);
- if (c->jscontext == NULL) {
+ msg_data.jsthread = &c->jsthread;
+ content_broadcast(&c->base, CONTENT_MSG_GETTHREAD, &msg_data);
+ NSLOG(netsurf, INFO, "javascript context %p ", c->jsthread);
+ if (c->jsthread == NULL) {
/* no context and it could not be created, abort */
return DOM_HUBBUB_OK;
}
@@ -668,6 +668,6 @@ nserror html_script_free(html_content *html)
/* exported internal interface documented in html/html_internal.h */
nserror html_script_invalidate_ctx(html_content *htmlc)
{
- htmlc->jscontext = NULL;
+ htmlc->jsthread = NULL;
return NSERROR_OK;
}
diff --git a/content/handlers/javascript/duktape/Window.bnd
b/content/handlers/javascript/duktape/Window.bnd
index 44a5170..b4a467d 100644
--- a/content/handlers/javascript/duktape/Window.bnd
+++ b/content/handlers/javascript/duktape/Window.bnd
@@ -216,8 +216,8 @@ window_remove_callback_by_handle(duk_context *ctx,
} RING_ITERATE_END(window->schedule_ring, sched);
}
-/* This is the dodgy compartment closedown method */
-static duk_ret_t dukky_window_closedown_compartment(duk_context *ctx)
+/* This is the dodgy thread closedown method */
+static duk_ret_t dukky_window_closedown_thread(duk_context *ctx)
{
window_private_t *priv = NULL;
@@ -230,7 +230,7 @@ static duk_ret_t
dukky_window_closedown_compartment(duk_context *ctx)
return 0;
}
- NSLOG(dukky, DEEPDEBUG, "Closing down compartment");
+ NSLOG(dukky, DEEPDEBUG, "Closing down thread");
while (priv->schedule_ring != NULL) {
window_remove_callback_by_handle(ctx,
priv,
@@ -361,10 +361,10 @@ prototype Window()
/* ** WebAssembly */
/* As yet, Duktape lacks WA */
#undef EXPOSE
- /* Add s3kr1t method to close the compartment */
+ /* Add s3kr1t method to close the JS thread (browsing context) */
duk_dup(ctx, 0);
- duk_push_string(ctx, MAGIC(closedownCompartment));
- duk_push_c_function(ctx, dukky_window_closedown_compartment,
DUK_VARARGS);
+ duk_push_string(ctx, MAGIC(closedownThread));
+ duk_push_c_function(ctx, dukky_window_closedown_thread, DUK_VARARGS);
duk_def_prop(ctx, -3,
DUK_DEFPROP_HAVE_VALUE |
DUK_DEFPROP_HAVE_WRITABLE |
diff --git a/content/handlers/javascript/duktape/dukky.c
b/content/handlers/javascript/duktape/dukky.c
index dcbff68..862f0e4 100644
--- a/content/handlers/javascript/duktape/dukky.c
+++ b/content/handlers/javascript/duktape/dukky.c
@@ -51,16 +51,29 @@
#define HANDLER_MAGIC MAGIC(HANDLER_MAP)
#define EVENT_LISTENER_JS_MAGIC MAGIC(EVENT_LISTENER_JS_MAP)
#define GENERICS_MAGIC MAGIC(GENERICS_TABLE)
+#define THREAD_MAP MAGIC(THREAD_MAP)
/**
- * dukky javascript context
+ * dukky javascript heap
*/
-struct jscontext {
+struct jsheap {
duk_context *ctx; /**< duktape base context */
- duk_context *thread; /**< duktape compartment */
+ duk_uarridx_t next_thread; /**< monotonic thread counter */
+ unsigned int live_threads; /**< number of live threads */
uint64_t exec_start_time;
};
+/**
+ * dukky javascript thread
+ */
+struct jsthread {
+ bool pending_destroy; /**< Whether this thread is pending destruction */
+ unsigned int in_use; /**< The number of times this thread is in use */
+ jsheap *heap; /**< The heap this thread belongs to */
+ duk_context *ctx; /**< The duktape thread context */
+ duk_uarridx_t thread_idx; /**< The thread number */
+};
+
static duk_ret_t dukky_populate_object(duk_context *ctx, void *udata)
{
/* ... obj args protoname nargs */
@@ -556,36 +569,6 @@ static void dukky_free_function(void *udata, void *ptr)
free(ptr);
}
-
-#define CTX (ctx->thread)
-
-/**
- * close current compartment
- *
- * \param ctx javascript context
- * \return NSERROR_OK on sucess.
- */
-static nserror dukky_closecompartment(jscontext *ctx)
-{
- /* ensure there is an active compartment */
- if (ctx->thread == NULL) {
- return NSERROR_OK;
- }
-
- /* Closing down the extant compartment */
- NSLOG(dukky, DEEPDEBUG, "Closing down extant compartment...");
- duk_get_global_string(ctx->thread, MAGIC(closedownCompartment));
- dukky_pcall(CTX, 0, true);
- NSLOG(dukky, DEEPDEBUG, "Popping the thread off the stack");
- duk_set_top(ctx->ctx, 0);
- duk_gc(ctx->ctx, 0);
- duk_gc(ctx->ctx, DUK_GC_COMPACT);
-
- ctx->thread = NULL;
-
- return NSERROR_OK;
-}
-
/* exported interface documented in js.h */
void js_initialise(void)
{
@@ -608,12 +591,12 @@ void js_finalise(void)
/* exported interface documented in js.h */
nserror
-js_newcontext(int timeout, jscallback *cb, void *cbctx, jscontext **jsctx)
+js_newheap(int timeout, jsheap **heap)
{
duk_context *ctx;
- jscontext *ret = calloc(1, sizeof(*ret));
- *jsctx = NULL;
- NSLOG(dukky, DEBUG, "Creating new duktape javascript context");
+ jsheap *ret = calloc(1, sizeof(*ret));
+ *heap = NULL;
+ NSLOG(dukky, DEBUG, "Creating new duktape javascript heap");
if (ret == NULL) return NSERROR_NOMEM;
ctx = ret->ctx = duk_create_heap(
dukky_alloc_function,
@@ -629,36 +612,52 @@ js_newcontext(int timeout, jscallback *cb, void *cbctx,
jscontext **jsctx)
duk_put_global_string(ctx, PROTO_MAGIC);
/* Create prototypes here */
dukky_create_prototypes(ctx);
+ /* Now create the thread map */
+ duk_push_object(ctx);
+ duk_put_global_string(ctx, THREAD_MAP);
- *jsctx = ret;
+ *heap = ret;
return NSERROR_OK;
}
/* exported interface documented in js.h */
-void js_destroycontext(jscontext *ctx)
+void js_destroyheap(jsheap *heap)
{
+ assert(heap->live_threads == 0);
NSLOG(dukky, DEBUG, "Destroying duktape javascript context");
- dukky_closecompartment(ctx);
- duk_destroy_heap(ctx->ctx);
- free(ctx);
+ duk_destroy_heap(heap->ctx);
+ free(heap);
}
+/* Just for here, the CTX is in ret, not thread */
+#define CTX (ret->ctx)
/* exported interface documented in js.h */
-jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv)
+nserror js_newthread(jsheap *heap, void *win_priv, void *doc_priv, jsthread
**thread)
{
- assert(ctx != NULL);
+ jsthread *ret;
+ assert(heap != NULL);
+
+ ret = calloc(1, sizeof (*ret));
+ if (ret == NULL) {
+ NSLOG(dukky, ERROR, "Unable to allocate new JS thread
structure");
+ return NSERROR_NOMEM;
+ }
+
NSLOG(dukky, DEBUG,
- "New javascript/duktape compartment, win_priv=%p, doc_priv=%p",
+ "New javascript/duktape thread, win_priv=%p, doc_priv=%p",
win_priv, doc_priv);
- /* Pop any active thread off */
- dukky_closecompartment(ctx);
-
- /* create new compartment thread */
- duk_push_thread(ctx->ctx);
- ctx->thread = duk_require_context(ctx->ctx, -1);
+ /* create new thread */
+ duk_get_global_string(heap->ctx, THREAD_MAP); /* ... threads */
+ duk_push_thread(heap->ctx); /* ... threads thread */
+ ret->heap = heap;
+ ret->ctx = duk_require_context(heap->ctx, -1);
+ ret->thread_idx = heap->next_thread++;
+ duk_put_prop_index(heap->ctx, -2, ret->thread_idx);
+ heap->live_threads++;
+ duk_pop(heap->ctx); /* ... */
duk_push_int(CTX, 0);
duk_push_int(CTX, 1);
duk_push_int(CTX, 2);
@@ -689,13 +688,15 @@ jsobject *js_newcompartment(jscontext *ctx, void
*win_priv, void *doc_priv)
if (duk_pcompile_lstring_filename(CTX, DUK_COMPILE_EVAL,
(const char *)polyfill_js,
polyfill_js_len) != 0) {
NSLOG(dukky, CRITICAL, "%s", duk_safe_to_string(CTX, -1));
- NSLOG(dukky, CRITICAL, "Unable to compile polyfill.js,
compartment aborted");
- return NULL;
+ NSLOG(dukky, CRITICAL, "Unable to compile polyfill.js, thread
aborted");
+ js_destroythread(ret);
+ return NSERROR_INIT_FAILED;
}
/* ..., (generics.js) */
if (dukky_pcall(CTX, 0, true) != 0) {
- NSLOG(dukky, CRITICAL, "Unable to run polyfill.js, compartment
aborted");
- return NULL;
+ NSLOG(dukky, CRITICAL, "Unable to run polyfill.js, thread
aborted");
+ js_destroythread(ret);
+ return NSERROR_INIT_FAILED;
}
/* ..., result */
duk_pop(CTX);
@@ -708,13 +709,15 @@ jsobject *js_newcompartment(jscontext *ctx, void
*win_priv, void *doc_priv)
if (duk_pcompile_lstring_filename(CTX, DUK_COMPILE_EVAL,
(const char *)generics_js,
generics_js_len) != 0) {
NSLOG(dukky, CRITICAL, "%s", duk_safe_to_string(CTX, -1));
- NSLOG(dukky, CRITICAL, "Unable to compile generics.js,
compartment aborted");
- return NULL;
+ NSLOG(dukky, CRITICAL, "Unable to compile generics.js, thread
aborted");
+ js_destroythread(ret);
+ return NSERROR_INIT_FAILED;
}
/* ..., (generics.js) */
if (dukky_pcall(CTX, 0, true) != 0) {
- NSLOG(dukky, CRITICAL, "Unable to run generics.js, compartment
aborted");
- return NULL;
+ NSLOG(dukky, CRITICAL, "Unable to run generics.js, thread
aborted");
+ js_destroythread(ret);
+ return NSERROR_INIT_FAILED;
}
/* ..., result */
duk_pop(CTX);
@@ -729,15 +732,76 @@ jsobject *js_newcompartment(jscontext *ctx, void
*win_priv, void *doc_priv)
duk_pop(CTX);
/* ... */
- dukky_log_stack_frame(CTX, "New compartment created");
+ dukky_log_stack_frame(CTX, "New thread created");
+ NSLOG(dukky, DEBUG, "New thread is %p in heap %p", thread, heap);
+ *thread = ret;
- return (jsobject *)ctx;
+ return NSERROR_OK;
+}
+
+/* Now switch to the long term CTX behaviour */
+#undef CTX
+#define CTX (thread->ctx)
+
+/**
+ * Destroy a Duktape thread
+ */
+static void dukky_destroythread(jsthread *thread)
+{
+ jsheap *heap = thread->heap;
+
+ assert(thread->in_use == 0);
+ assert(thread->pending_destroy = true);
+
+ /* Closing down the extant thread */
+ NSLOG(dukky, DEBUG, "Closing down extant thread %p in heap %p", thread,
heap);
+ duk_get_global_string(CTX, MAGIC(closedownThread));
+ dukky_pcall(CTX, 0, true);
+
+ /* Now delete the thread from the heap */
+ duk_get_global_string(heap->ctx, THREAD_MAP); /* ... threads */
+ duk_del_prop_index(heap->ctx, -1, thread->thread_idx);
+ duk_pop(heap->ctx); /* ... */
+
+ /* We can now free the thread object */
+ free(thread);
+
+ /* Finally give the heap a chance to clean up */
+ duk_gc(heap->ctx, 0);
+ duk_gc(heap->ctx, DUK_GC_COMPACT);
+ heap->live_threads--;
+}
+
+/* exported interface documented in js.h */
+void js_destroythread(jsthread *thread)
+{
+ thread->pending_destroy = true;
+ if (thread->in_use == 0) {
+ dukky_destroythread(thread);
+ }
+}
+
+static void dukky_enter_thread(jsthread *thread)
+{
+ assert(thread != NULL);
+ thread->in_use++;
+}
+
+static void dukky_leave_thread(jsthread *thread)
+{
+ assert(thread != NULL);
+ assert(thread->in_use > 0);
+
+ thread->in_use--;
+ if (thread->in_use == 0 && thread->pending_destroy == true) {
+ dukky_destroythread(thread);
+ }
}
duk_bool_t dukky_check_timeout(void *udata)
{
#define JS_EXEC_TIMEOUT_MS 10000 /* 10 seconds */
- jscontext *ctx = (jscontext *) udata;
+ jsheap *heap = (jsheap *) udata;
uint64_t now;
(void) nsu_getmonotonic_ms(&now);
@@ -746,8 +810,8 @@ duk_bool_t dukky_check_timeout(void *udata)
* so only test for execution timeout if we've recorded a
* start time.
*/
- return ctx->exec_start_time != 0 &&
- now > (ctx->exec_start_time + JS_EXEC_TIMEOUT_MS);
+ return heap->exec_start_time != 0 &&
+ now > (heap->exec_start_time + JS_EXEC_TIMEOUT_MS);
}
static void dukky_dump_error(duk_context *ctx)
@@ -761,14 +825,19 @@ static void dukky_dump_error(duk_context *ctx)
/* ..., errobj */
}
+static void dukky_reset_start_time(duk_context *ctx)
+{
+ duk_memory_functions funcs;
+ jsheap *heap;
+ duk_get_memory_functions(ctx, &funcs);
+ heap = funcs.udata;
+ (void) nsu_getmonotonic_ms(&heap->exec_start_time);
+}
+
duk_int_t dukky_pcall(duk_context *ctx, duk_size_t argc, bool reset_timeout)
{
if (reset_timeout) {
- duk_memory_functions funcs;
- jscontext *jsctx;
- duk_get_memory_functions(ctx, &funcs);
- jsctx = funcs.udata;
- (void) nsu_getmonotonic_ms(&jsctx->exec_start_time);
+ dukky_reset_start_time(ctx);
}
duk_int_t ret = duk_pcall(ctx, argc);
@@ -811,19 +880,22 @@ void dukky_log_stack_frame(duk_context *ctx, const char *
reason)
/* exported interface documented in js.h */
bool
-js_exec(jscontext *ctx, const uint8_t *txt, size_t txtlen, const char *name)
+js_exec(jsthread *thread, const uint8_t *txt, size_t txtlen, const char *name)
{
- assert(ctx);
+ bool ret = false;
+ assert(thread);
if (txt == NULL || txtlen == 0) {
return false;
}
+ dukky_enter_thread(thread);
+
duk_set_top(CTX, 0);
NSLOG(dukky, DEEPDEBUG, "Running %"PRIsizet" bytes from %s", txtlen,
name);
/* NSLOG(dukky, DEEPDEBUG, "\n%s\n", txt); */
- (void) nsu_getmonotonic_ms(&ctx->exec_start_time);
+ dukky_reset_start_time(CTX);
if (name != NULL) {
duk_push_string(CTX, name);
} else {
@@ -845,11 +917,14 @@ js_exec(jscontext *ctx, const uint8_t *txt, size_t
txtlen, const char *name)
if (duk_get_top(CTX) == 0) duk_push_boolean(CTX, false);
NSLOG(dukky, DEEPDEBUG, "Returning %s",
duk_get_boolean(CTX, 0) ? "true" : "false");
- return duk_get_boolean(CTX, 0);
+ ret = duk_get_boolean(CTX, 0);
+ goto out;
handle_error:
dukky_dump_error(CTX);
- return false;
+out:
+ dukky_leave_thread(thread);
+ return ret;
}
static const char* dukky_event_proto(dom_event *evt)
@@ -1023,9 +1098,7 @@ bool dukky_get_current_value_of_event_handler(duk_context
*ctx,
static void dukky_generic_event_handler(dom_event *evt, void *pw)
{
- duk_memory_functions funcs;
duk_context *ctx = (duk_context *)pw;
- jscontext *jsctx;
dom_string *name;
dom_exception exc;
dom_event_target *targ;
@@ -1033,10 +1106,6 @@ static void dukky_generic_event_handler(dom_event *evt,
void *pw)
duk_uarridx_t idx;
event_listener_flags flags;
- /* Retrieve the JS context from the Duktape context */
- duk_get_memory_functions(ctx, &funcs);
- jsctx = funcs.udata;
-
NSLOG(dukky, DEBUG, "Handling an event in duktape interface...");
exc = dom_event_get_type(evt, &name);
if (exc != DOM_NO_ERR) {
@@ -1084,7 +1153,7 @@ static void dukky_generic_event_handler(dom_event *evt,
void *pw)
/* ... handler node */
dukky_push_event(ctx, evt);
/* ... handler node event */
- (void) nsu_getmonotonic_ms(&jsctx->exec_start_time);
+ dukky_reset_start_time(ctx);
if (duk_pcall_method(ctx, 1) != 0) {
/* Failed to run the method */
/* ... err */
@@ -1183,7 +1252,7 @@ handle_extras:
/* ... copy handler callback node */
dukky_push_event(ctx, evt);
/* ... copy handler callback node event */
- (void) nsu_getmonotonic_ms(&jsctx->exec_start_time);
+ dukky_reset_start_time(ctx);
if (duk_pcall_method(ctx, 1) != 0) {
/* Failed to run the method */
/* ... copy handler err */
@@ -1355,9 +1424,9 @@ void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t
idx)
}
-void js_handle_new_element(jscontext *ctx, struct dom_element *node)
+void js_handle_new_element(jsthread *thread, struct dom_element *node)
{
- assert(ctx);
+ assert(thread);
assert(node);
dom_namednodemap *map;
dom_exception exc;
@@ -1380,6 +1449,8 @@ void js_handle_new_element(jscontext *ctx, struct
dom_element *node)
if (exc != DOM_NO_ERR) return;
if (map == NULL) return;
+ dukky_enter_thread(thread);
+
exc = dom_namednodemap_get_length(map, &siz);
if (exc != DOM_NO_ERR) goto out;
@@ -1429,11 +1500,14 @@ out:
dom_node_unref(attr);
dom_namednodemap_unref(map);
+
+ dukky_leave_thread(thread);
}
-void js_event_cleanup(jscontext *ctx, struct dom_event *evt)
+void js_event_cleanup(jsthread *thread, struct dom_event *evt)
{
- assert(ctx);
+ assert(thread);
+ dukky_enter_thread(thread);
/* ... */
duk_get_global_string(CTX, EVENT_MAGIC);
/* ... EVENT_MAP */
@@ -1443,9 +1517,10 @@ void js_event_cleanup(jscontext *ctx, struct dom_event
*evt)
/* ... EVENT_MAP */
duk_pop(CTX);
/* ... */
+ dukky_leave_thread(thread);
}
-bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc,
struct dom_node *target)
+bool js_fire_event(jsthread *thread, const char *type, struct dom_document
*doc, struct dom_node *target)
{
dom_exception exc;
dom_event *evt;
@@ -1481,6 +1556,7 @@ bool js_fire_event(jscontext *ctx, const char *type,
struct dom_document *doc, s
dom_event_unref(evt);
return true;
}
+ dukky_enter_thread(thread);
/* ... */
duk_get_global_string(CTX, HANDLER_MAGIC);
/* ... handlers */
@@ -1497,6 +1573,7 @@ bool js_fire_event(jscontext *ctx, const char *type,
struct dom_document *doc, s
exc = dom_html_document_get_body(doc, &body);
if (exc != DOM_NO_ERR) {
dom_event_unref(evt);
+ dukky_leave_thread(thread);
return true;
}
dukky_push_node(CTX, (struct dom_node *)body);
@@ -1507,6 +1584,7 @@ bool js_fire_event(jscontext *ctx, const char *type,
struct dom_document *doc, s
dom_node_unref(body);
/* ... handlers */
duk_pop(CTX);
+ dukky_leave_thread(thread);
return true;
}
/* Unref the body, we don't need it any more */
@@ -1523,7 +1601,7 @@ bool js_fire_event(jscontext *ctx, const char *type,
struct dom_document *doc, s
/* ... handler Window */
dukky_push_event(CTX, evt);
/* ... handler Window event */
- (void) nsu_getmonotonic_ms(&ctx->exec_start_time);
+ dukky_reset_start_time(CTX);
if (duk_pcall_method(CTX, 1) != 0) {
/* Failed to run the handler */
/* ... err */
@@ -1546,14 +1624,16 @@ bool js_fire_event(jscontext *ctx, const char *type,
struct dom_document *doc, s
duk_pop_n(CTX, 6);
/* ... */
- js_event_cleanup(ctx, evt);
+ js_event_cleanup(thread, evt);
dom_event_unref(evt);
+ dukky_leave_thread(thread);
return true;
}
/* ... result */
duk_pop(CTX);
/* ... */
- js_event_cleanup(ctx, evt);
+ js_event_cleanup(thread, evt);
dom_event_unref(evt);
+ dukky_leave_thread(thread);
return true;
}
diff --git a/content/handlers/javascript/duktape/polyfill.js
b/content/handlers/javascript/duktape/polyfill.js
index 7fa4611..5f02156 100644
--- a/content/handlers/javascript/duktape/polyfill.js
+++ b/content/handlers/javascript/duktape/polyfill.js
@@ -1,6 +1,6 @@
/* Polyfiller for Duktape for NetSurf
*
- * This JavaScript will be loaded into compartments before the generics
+ * This JavaScript will be loaded into heaps before the generics
*
* We only care for the side-effects of this, be careful.
*/
diff --git a/content/handlers/javascript/js.h b/content/handlers/javascript/js.h
index d5af721..ce9bb9b 100644
--- a/content/handlers/javascript/js.h
+++ b/content/handlers/javascript/js.h
@@ -25,11 +25,6 @@
#include "utils/errors.h"
-typedef struct jscontext jscontext;
-typedef struct jsobject jsobject;
-
-typedef bool(jscallback)(void *ctx);
-
struct dom_event;
struct dom_document;
struct dom_node;
@@ -37,6 +32,27 @@ struct dom_element;
struct dom_string;
/**
+ * JavaScript interpreter heap
+ *
+ * In order to try and be moderately performant, we create a heap
+ * per browser window. This heap is shared by all browsing contexts
+ * we end up creating in that window.
+ */
+typedef struct jsheap jsheap;
+
+/**
+ * JavaScript interpreter thread
+ *
+ * When we create a browsing context itself (window+content) we have
+ * to create a JS thread to attach to the browsing context.
+ *
+ * JS threads are associated with heaps and will be destroyed when
+ * the heap is destroyed. They can be shut down manually though
+ * and should be for object lifetime safety reasons.
+ */
+typedef struct jsthread jsthread;
+
+/**
* Initialise javascript interpreter
*/
void js_initialise(void);
@@ -47,43 +63,65 @@ void js_initialise(void);
void js_finalise(void);
/**
- * Create a new javascript context.
+ * Create a new javascript heap.
*
- * There is usually one context per browsing context (browser window)
+ * There is usually one heap per browser window.
*
* \param timeout elapsed wallclock time (in seconds) before \a callback is
called
- * \param cb the callback when the runtime exceeds the timeout
- * \param cbctx The context to pass to the callback
- * \param jsctx Updated to the created JS context
+ * \param heap Updated to the created JS heap
* \return NSERROR_OK on success, appropriate error otherwise.
*/
-nserror js_newcontext(int timeout, jscallback *cb, void *cbctx, jscontext
**jsctx);
+nserror js_newheap(int timeout, jsheap **heap);
/**
- * Destroy a previously created context
+ * Destroy a previously created heap.
+ *
+ * \param heap The heap to destroy
*/
-void js_destroycontext(jscontext *ctx);
+void js_destroyheap(jsheap *heap);
/**
- * Create a new javascript compartment
+ * Create a new javascript thread
*
* This is called once for a page with javascript script tags on
- * it. It constructs a fresh global window object.
+ * it. It constructs a fresh global window object and prepares the JS
+ * browsing context. It's important that threads are shut down cleanly
+ * when the browsing context is going to be cleaned up.
+ *
+ * \param heap The heap to create the thread within
+ * \param win_priv The value to give to the Window constructor as the window
+ * \param doc_priv The value to give to the Document constructor as the
document
+ * \param thread Updated to the created thread
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+nserror js_newthread(jsheap *heap, void *win_priv, void *doc_priv, jsthread
**thread);
+
+/**
+ * Destroy a javascript thread
+ *
+ * This should be called when the browsing context is done with the thread.
+ *
+ * Essentially it should be called when the content is about to be destroyed
+ * but in reality it can be called when the browser window relinquishes its
+ * handle on the content since nominally the browser window itself owns
+ * the thread.
+ *
+ * \param thread The thread to be destroyed
*/
-jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv);
+void js_destroythread(jsthread *thread);
/**
* execute some javascript in a context
*/
-bool js_exec(jscontext *ctx, const uint8_t *txt, size_t txtlen, const char
*name);
+bool js_exec(jsthread *thread, const uint8_t *txt, size_t txtlen, const char
*name);
/**
* fire an event at a dom node
*/
-bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc,
struct dom_node *target);
+bool js_fire_event(jsthread *thread, const char *type, struct dom_document
*doc, struct dom_node *target);
bool
-js_dom_event_add_listener(jscontext *ctx,
+js_dom_event_add_listener(jsthread *thread,
struct dom_document *document,
struct dom_node *node,
struct dom_string *event_type_dom,
@@ -98,7 +136,7 @@ js_dom_event_add_listener(jscontext *ctx,
* by the context provided. The JS implementation must then scan the element
* for on* attributes and register appropriate listeners for those handlers.
*/
-void js_handle_new_element(jscontext *ctx, struct dom_element *node);
+void js_handle_new_element(jsthread *thread, struct dom_element *node);
/**
* Handle an event propagation finished callback.
@@ -108,6 +146,6 @@ void js_handle_new_element(jscontext *ctx, struct
dom_element *node);
* it may need to perform before the DOM finishes and the event may end up
* freed.
*/
-void js_event_cleanup(jscontext *ctx, struct dom_event *evt);
+void js_event_cleanup(jsthread *thread, struct dom_event *evt);
#endif /* NETSURF_JAVASCRIPT_JS_H_ */
diff --git a/content/handlers/javascript/none/none.c
b/content/handlers/javascript/none/none.c
index 80a9ce4..ff09f52 100644
--- a/content/handlers/javascript/none/none.c
+++ b/content/handlers/javascript/none/none.c
@@ -35,36 +35,40 @@ void js_finalise(void)
{
}
-nserror js_newcontext(int timeout, jscallback *cb, void *cbctx,
- jscontext **jsctx)
+nserror js_newheap(int timeout, jsheap **heap)
{
- *jsctx = NULL;
+ *heap = NULL;
return NSERROR_OK;
}
-void js_destroycontext(jscontext *ctx)
+void js_destroyheap(jsheap *heap)
{
}
-jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv)
+nserror js_newthread(jsheap *heap, void *win_priv, void *doc_priv, jsthread
**thread)
{
- return NULL;
+ *thread = NULL;
+ return NSERROR_NOT_IMPLEMENTED;
}
-bool js_exec(jscontext *ctx, const uint8_t *txt, size_t txtlen, const char
*name)
+void js_destroythread(jsthread *thread)
+{
+}
+
+bool js_exec(jsthread *thread, const uint8_t *txt, size_t txtlen, const char
*name)
{
return true;
}
-bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc,
struct dom_node *target)
+bool js_fire_event(jsthread *thread, const char *type, struct dom_document
*doc, struct dom_node *target)
{
return true;
}
-void js_handle_new_element(jscontext *ctx, struct dom_element *node)
+void js_handle_new_element(jsthread *thread, struct dom_element *node)
{
}
-void js_event_cleanup(jscontext *ctx, struct dom_event *evt)
+void js_event_cleanup(jsthread *thread, struct dom_event *evt)
{
}
diff --git a/desktop/browser_private.h b/desktop/browser_private.h
index c9f9bbc..89dc5cc 100644
--- a/desktop/browser_private.h
+++ b/desktop/browser_private.h
@@ -263,7 +263,13 @@ struct browser_window {
bool can_edit;
/** current javascript context */
- struct jscontext *jsctx;
+ struct jsheap *jsheap;
+
+ /** The JS thread (if any) for the current content */
+ struct jsthread *current_jsthread;
+
+ /** The JS thread (if any) for the loading content */
+ struct jsthread *loading_jsthread;
/** cache of the currently displayed status text. */
struct {
diff --git a/desktop/browser_window.c b/desktop/browser_window.c
index 3c072ef..c98eca8 100644
--- a/desktop/browser_window.c
+++ b/desktop/browser_window.c
@@ -330,22 +330,6 @@ browser_window__get_contextual_content(struct
browser_window *bw,
/**
- * slow script handler
- */
-static bool slow_script(void *ctx)
-{
- static int count = 0;
- NSLOG(netsurf, INFO, "Continuing execution %d", count);
- count++;
- if (count > 1) {
- count = 0;
- return false;
- }
- return true;
-}
-
-
-/**
* implements the download operation of a window navigate
*/
static nserror
@@ -718,6 +702,10 @@ browser_window_convert_to_download(struct browser_window
*bw,
/* remove content from browser window */
hlcache_handle_release(bw->loading_content);
bw->loading_content = NULL;
+ if (bw->loading_jsthread != NULL) {
+ js_destroythread(bw->loading_jsthread);
+ bw->loading_jsthread = NULL;
+ }
browser_window_stop_throbber(bw);
}
@@ -735,10 +723,15 @@ static nserror browser_window_content_ready(struct
browser_window *bw)
if (bw->current_content != NULL) {
content_close(bw->current_content);
hlcache_handle_release(bw->current_content);
+ if (bw->current_jsthread != NULL) {
+ js_destroythread(bw->current_jsthread);
+ }
}
bw->current_content = bw->loading_content;
+ bw->current_jsthread = bw->loading_jsthread;
bw->loading_content = NULL;
+ bw->loading_jsthread = NULL;
if (!bw->internal_nav) {
/* Transfer the fetch parameters */
@@ -1296,6 +1289,10 @@ browser_window__handle_error(struct browser_window *bw,
if (c == bw->loading_content) {
bw->loading_content = NULL;
+ if (bw->loading_jsthread != NULL) {
+ js_destroythread(bw->loading_jsthread);
+ bw->loading_jsthread = NULL;
+ }
} else if (c == bw->current_content) {
bw->current_content = NULL;
browser_window_remove_caret(bw, false);
@@ -1501,15 +1498,17 @@ browser_window_callback(hlcache_handle *c, const
hlcache_event *event, void *pw)
}
break;
- case CONTENT_MSG_GETCTX:
+ case CONTENT_MSG_GETTHREAD:
/* only the content object created by the browser
- * window requires a new global compartment object
+ * window requires a new javascript thread object
*/
assert(bw->loading_content == c);
- if (js_newcompartment(bw->jsctx,
- bw,
- hlcache_handle_get_content(c)) != NULL) {
- *(event->data.jscontext) = bw->jsctx;
+ assert(bw->loading_jsthread == NULL);
+ if (js_newthread(bw->jsheap,
+ bw,
+ hlcache_handle_get_content(c),
+ &bw->loading_jsthread) == NSERROR_OK) {
+ *(event->data.jsthread) = bw->loading_jsthread;
}
break;
@@ -1753,12 +1752,22 @@ static void browser_window_destroy_internal(struct
browser_window *bw)
bw->loading_content = NULL;
}
+ if (bw->loading_jsthread != NULL) {
+ js_destroythread(bw->loading_jsthread);
+ bw->loading_jsthread = NULL;
+ }
+
if (bw->current_content != NULL) {
content_close(bw->current_content);
hlcache_handle_release(bw->current_content);
bw->current_content = NULL;
}
+ if (bw->current_jsthread != NULL) {
+ js_destroythread(bw->current_jsthread);
+ bw->current_jsthread = NULL;
+ }
+
if (bw->favicon.loading != NULL) {
hlcache_handle_abort(bw->favicon.loading);
hlcache_handle_release(bw->favicon.loading);
@@ -1776,8 +1785,9 @@ static void browser_window_destroy_internal(struct
browser_window *bw)
bw->box = NULL;
}
- if (bw->jsctx != NULL) {
- js_destroycontext(bw->jsctx);
+ if (bw->jsheap != NULL) {
+ js_destroyheap(bw->jsheap);
+ bw->jsheap = NULL;
}
/* These simply free memory, so are safe here */
@@ -3101,8 +3111,7 @@ browser_window_initialise_common(enum
browser_window_create_flags flags,
assert(bw);
/* new javascript context for each window/(i)frame */
- err = js_newcontext(nsoption_int(script_timeout),
- slow_script, NULL, &bw->jsctx);
+ err = js_newheap(nsoption_int(script_timeout), &bw->jsheap);
if (err != NSERROR_OK)
return err;
@@ -4082,6 +4091,10 @@ void browser_window_stop(struct browser_window *bw)
hlcache_handle_abort(bw->loading_content);
hlcache_handle_release(bw->loading_content);
bw->loading_content = NULL;
+ if (bw->loading_jsthread != NULL) {
+ js_destroythread(bw->loading_jsthread);
+ bw->loading_jsthread = NULL;
+ }
}
if (bw->current_content != NULL &&
--
NetSurf Browser
_______________________________________________
netsurf-commits mailing list
[email protected]
http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/netsurf-commits-netsurf-browser.org