summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--content/handlers/javascript/duktape/duk_config.h4
-rw-r--r--content/handlers/javascript/duktape/duktape.c407
-rw-r--r--content/handlers/javascript/duktape/duktape.h23
-rw-r--r--desktop/netsurf.c3
-rw-r--r--desktop/tree.c8
-rw-r--r--frontends/amiga/gui.c273
-rwxr-xr-xfrontends/amiga/launch.c22
-rw-r--r--frontends/amiga/memory.h8
-rwxr-xr-xfrontends/amiga/object.c24
-rw-r--r--frontends/amiga/tree.c4
-rw-r--r--frontends/beos/cookies.cpp1
-rw-r--r--frontends/riscos/gui.c1
-rw-r--r--utils/messages.c25
-rw-r--r--utils/messages.h5
-rwxr-xr-xutils/test-netsurf (renamed from test-netsurf)0
16 files changed, 541 insertions, 269 deletions
diff --git a/Makefile b/Makefile
index dc1c21fa7..2596e7af6 100644
--- a/Makefile
+++ b/Makefile
@@ -73,7 +73,7 @@ ifeq ($(HOST),beos)
TARGET := beos
endif
ifeq ($(TARGET),haiku)
- TARGET := beos
+ override TARGET := beos
endif
endif
diff --git a/content/handlers/javascript/duktape/duk_config.h b/content/handlers/javascript/duktape/duk_config.h
index c336603eb..f9c95ae33 100644
--- a/content/handlers/javascript/duktape/duk_config.h
+++ b/content/handlers/javascript/duktape/duk_config.h
@@ -1,8 +1,8 @@
/*
* duk_config.h configuration header generated by genconfig.py.
*
- * Git commit: 2cc76e9ff1f64869e1146ad7317d8cbe33bbd27e
- * Git describe: v1.5.1
+ * Git commit: 17e3d86cf8b4788bd0d37658f833ab440ce43a1c
+ * Git describe: v1.6.0
* Git branch: HEAD
*
* Supported platforms:
diff --git a/content/handlers/javascript/duktape/duktape.c b/content/handlers/javascript/duktape/duktape.c
index e1867c0ba..b64383b11 100644
--- a/content/handlers/javascript/duktape/duktape.c
+++ b/content/handlers/javascript/duktape/duktape.c
@@ -1,9 +1,9 @@
/* Omit from static analysis. */
#ifndef __clang_analyzer__
/*
- * Single source autogenerated distributable for Duktape 1.5.1.
+ * Single source autogenerated distributable for Duktape 1.6.0.
*
- * Git commit 2cc76e9ff1f64869e1146ad7317d8cbe33bbd27e (v1.5.1).
+ * Git commit 17e3d86cf8b4788bd0d37658f833ab440ce43a1c (v1.6.0).
* Git branch HEAD.
*
* See Duktape AUTHORS.rst and LICENSE.txt for copyright and
@@ -1631,9 +1631,9 @@ DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
#endif /* !DUK_SINGLE_FILE */
#if defined(DUK_USE_BUILTIN_INITJS)
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
+DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[204];
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTIN_INITJS_DATA_LENGTH 187
+#define DUK_BUILTIN_INITJS_DATA_LENGTH 204
#endif /* DUK_USE_BUILTIN_INITJS */
#define DUK_BIDX_GLOBAL 0
#define DUK_BIDX_GLOBAL_ENV 1
@@ -9221,7 +9221,7 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_typedarray_set,
};
#if defined(DUK_USE_BUILTIN_INITJS)
-DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = {
+DUK_INTERNAL const duk_uint8_t duk_initjs_data[204] = {
40,102,117,110,99,116,105,111,110,40,100,44,97,41,123,102,117,110,99,116,
105,111,110,32,98,40,97,44,98,44,99,41,123,79,98,106,101,99,116,46,100,101,
102,105,110,101,80,114,111,112,101,114,116,121,40,97,44,98,44,123,118,97,
@@ -9229,8 +9229,9 @@ DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = {
109,101,114,97,98,108,101,58,33,49,44,99,111,110,102,105,103,117,114,97,98,
108,101,58,33,48,125,41,125,98,40,97,46,76,111,103,103,101,114,44,34,99,
108,111,103,34,44,110,101,119,32,97,46,76,111,103,103,101,114,40,34,67,34,
-41,41,59,98,40,97,44,34,109,111,100,76,111,97,100,101,100,34,44,123,125,41,
-125,41,40,116,104,105,115,44,68,117,107,116,97,112,101,41,59,10,0,
+41,41,59,98,40,97,44,34,109,111,100,76,111,97,100,101,100,34,44,79,98,106,
+101,99,116,46,99,114,101,97,116,101,40,110,117,108,108,41,41,125,41,40,116,
+104,105,115,44,68,117,107,116,97,112,101,41,59,10,0,
};
#endif /* DUK_USE_BUILTIN_INITJS */
#if defined(DUK_USE_DOUBLE_LE)
@@ -9354,7 +9355,7 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
-191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,0,0,0,64,65,98,
+191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,0,0,0,0,90,98,
32,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,
60,56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
@@ -9534,7 +9535,7 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
-191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,32,98,65,64,0,0,0,
+191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,32,98,90,0,0,0,0,
0,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,60,
56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
@@ -9714,7 +9715,7 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
-191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,64,65,98,32,0,0,0,
+191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,90,98,32,0,0,0,
0,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,60,
56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
@@ -14047,6 +14048,15 @@ DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
/* include removed: duk_internal.h */
+typedef struct duk_internal_thread_state duk_internal_thread_state;
+
+struct duk_internal_thread_state {
+ duk_ljstate lj;
+ duk_bool_t handling_error;
+ duk_hthread *curr_thread;
+ duk_int_t call_recursion_depth;
+};
+
DUK_EXTERNAL
duk_context *duk_create_heap(duk_alloc_function alloc_func,
duk_realloc_function realloc_func,
@@ -14112,6 +14122,57 @@ DUK_EXTERNAL void duk_destroy_heap(duk_context *ctx) {
duk_heap_free(heap);
}
+DUK_EXTERNAL void duk_suspend(duk_context *ctx, duk_thread_state *state) {
+ duk_hthread *thr = (duk_hthread *) ctx;
+ duk_internal_thread_state *snapshot = (duk_internal_thread_state *) (void *) state;
+ duk_heap *heap;
+ duk_ljstate *lj;
+
+ DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(thr->heap != NULL);
+ DUK_ASSERT(state != NULL); /* unvalidated */
+
+ heap = thr->heap;
+ lj = &heap->lj;
+
+ duk_push_tval(ctx, &lj->value1);
+ duk_push_tval(ctx, &lj->value2);
+
+ DUK_MEMCPY((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate));
+ snapshot->handling_error = heap->handling_error;
+ snapshot->curr_thread = heap->curr_thread;
+ snapshot->call_recursion_depth = heap->call_recursion_depth;
+
+ lj->jmpbuf_ptr = NULL;
+ lj->type = DUK_LJ_TYPE_UNKNOWN;
+ DUK_TVAL_SET_UNDEFINED(&lj->value1);
+ DUK_TVAL_SET_UNDEFINED(&lj->value2);
+ heap->handling_error = 0;
+ heap->curr_thread = NULL;
+ heap->call_recursion_depth = 0;
+}
+
+DUK_EXTERNAL void duk_resume(duk_context *ctx, const duk_thread_state *state) {
+ duk_hthread *thr = (duk_hthread *) ctx;
+ const duk_internal_thread_state *snapshot = (const duk_internal_thread_state *) (const void *) state;
+ duk_heap *heap;
+
+ DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(thr->heap != NULL);
+ DUK_ASSERT(state != NULL); /* unvalidated */
+
+ heap = thr->heap;
+
+ DUK_MEMCPY((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate));
+ heap->handling_error = snapshot->handling_error;
+ heap->curr_thread = snapshot->curr_thread;
+ heap->call_recursion_depth = snapshot->call_recursion_depth;
+
+ duk_pop_2(ctx);
+}
+
/* XXX: better place for this */
DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) {
duk_hthread *thr = (duk_hthread *) ctx;
@@ -14417,7 +14478,7 @@ DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t
return rc;
}
-DUK_EXTERNAL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_index) {
+DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t idx_key) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_tval *tv_obj;
duk_tval *tv_key;
@@ -14425,16 +14486,19 @@ DUK_EXTERNAL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_index) {
duk_small_int_t throw_flag;
duk_bool_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
-
/* Note: copying tv_obj and tv_key to locals to shield against a valstack
* resize is not necessary for a property put right now (putprop protects
* against it internally).
*/
- tv_obj = duk_require_tval(ctx, obj_index);
- tv_key = duk_require_tval(ctx, -2);
- tv_val = duk_require_tval(ctx, -1);
+ /* Key and value indices are either (-2, -1) or (-1, -2). Given idx_key,
+ * idx_val is always (idx_key ^ 0x01).
+ */
+ DUK_ASSERT((idx_key == -2 && (idx_key ^ 1) == -1) ||
+ (idx_key == -1 && (idx_key ^ 1) == -2));
+ tv_obj = duk_require_tval(ctx, obj_idx);
+ tv_key = duk_require_tval(ctx, idx_key);
+ tv_val = duk_require_tval(ctx, idx_key ^ 1);
throw_flag = duk_is_strict_call(ctx);
rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag);
@@ -14444,26 +14508,33 @@ DUK_EXTERNAL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_index) {
return rc; /* 1 if property found, 0 otherwise */
}
-DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
+DUK_EXTERNAL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_idx) {
+ DUK_ASSERT_CTX_VALID(ctx);
+ return duk__put_prop_shared(ctx, obj_idx, -2);
+}
+
+DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) {
DUK_ASSERT_CTX_VALID(ctx);
DUK_ASSERT(key != NULL);
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_string(ctx, key);
- duk_swap_top(ctx, -2); /* [val key] -> [key val] */
- return duk_put_prop(ctx, obj_index);
+ /* Careful here and with other duk_put_prop_xxx() helpers: the
+ * target object and the property value may be in the same value
+ * stack slot (unusual, but still conceptually clear).
+ */
+ obj_idx = duk_normalize_index(ctx, obj_idx);
+ (void) duk_push_string(ctx, key);
+ return duk__put_prop_shared(ctx, obj_idx, -1);
}
-DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
+DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
DUK_ASSERT_CTX_VALID(ctx);
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_uarridx(ctx, arr_index);
- duk_swap_top(ctx, -2); /* [val key] -> [key val] */
- return duk_put_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(ctx, obj_idx);
+ duk_push_uarridx(ctx, arr_idx);
+ return duk__put_prop_shared(ctx, obj_idx, -1);
}
-DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
+DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_int_t stridx) {
duk_hthread *thr = (duk_hthread *) ctx;
DUK_ASSERT_CTX_VALID(ctx);
@@ -14471,10 +14542,9 @@ DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_inde
DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
DUK_UNREF(thr);
- obj_index = duk_require_normalize_index(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(ctx, obj_idx);
duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- duk_swap_top(ctx, -2); /* [val key] -> [key val] */
- return duk_put_prop(ctx, obj_index);
+ return duk__put_prop_shared(ctx, obj_idx, -1);
}
DUK_EXTERNAL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_index) {
@@ -31391,12 +31461,17 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
* standard JSON (and no JX/JC support here now).
*/
DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path"));
+#if defined(DUK_USE_JX)
+ DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
+#else
DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
+#endif
} else {
if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) {
DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
}
}
+
DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
emitted = 1;
}
@@ -31729,6 +31804,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
* combinations properly.
*/
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
+ js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_NULL; /* standard JSON; array gaps */
#if defined(DUK_USE_JX)
if (flags & DUK_JSON_FLAG_EXT_CUSTOM) {
js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_UNDEFINED;
@@ -33931,7 +34007,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx
cp = (duk_ucodepoint_t) duk_to_uint32(ctx, i);
DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
#else
- cp = (duk_ucodepoint_t) duk_to_uint32(ctx, i);
+ cp = (duk_ucodepoint_t) duk_to_uint16(ctx, i);
DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp);
#endif
}
@@ -42036,18 +42112,23 @@ DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPILEDFUNCTION_GET_DATA(heap, f));
- tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap, f);
- tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap, f);
- while (tv < tv_end) {
- duk__mark_tval(heap, tv);
- tv++;
- }
+ if (DUK_HCOMPILEDFUNCTION_GET_DATA(heap, f) != NULL) {
+ tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap, f);
+ tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap, f);
+ while (tv < tv_end) {
+ duk__mark_tval(heap, tv);
+ tv++;
+ }
- fn = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap, f);
- fn_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap, f);
- while (fn < fn_end) {
- duk__mark_heaphdr(heap, (duk_heaphdr *) *fn);
- fn++;
+ fn = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap, f);
+ fn_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap, f);
+ while (fn < fn_end) {
+ duk__mark_heaphdr(heap, (duk_heaphdr *) *fn);
+ fn++;
+ }
+ } else {
+ /* May happen in some out-of-memory corner cases. */
+ DUK_D(DUK_DPRINT("duk_hcompiledfunction 'data' is NULL, skipping marking"));
}
} else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
duk_hnativefunction *f = (duk_hnativefunction *) h;
@@ -43927,20 +44008,23 @@ DUK_LOCAL void duk__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h)
duk_tval *tv, *tv_end;
duk_hobject **funcs, **funcs_end;
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f) != NULL); /* compiled functions must be created 'atomically' */
-
- tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, f);
- tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, f);
- while (tv < tv_end) {
- duk_tval_decref(thr, tv);
- tv++;
- }
+ if (DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f) != NULL) {
+ tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, f);
+ tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, f);
+ while (tv < tv_end) {
+ duk_tval_decref(thr, tv);
+ tv++;
+ }
- funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, f);
- funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, f);
- while (funcs < funcs_end) {
- duk_heaphdr_decref(thr, (duk_heaphdr *) *funcs);
- funcs++;
+ funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, f);
+ funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, f);
+ while (funcs < funcs_end) {
+ duk_heaphdr_decref(thr, (duk_heaphdr *) *funcs);
+ funcs++;
+ }
+ } else {
+ /* May happen in some out-of-memory corner cases. */
+ DUK_D(DUK_DPRINT("duk_hcompiledfunction 'data' is NULL, skipping decref"));
}
duk_heaphdr_decref(thr, (duk_heaphdr *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f));
@@ -46870,8 +46954,13 @@ DUK_INTERNAL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, d
duk_uint_t sanity;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(h != NULL);
- /* allow 'p' to be NULL; then the result is always false */
+
+ /* False if the object is NULL or the prototype 'p' is NULL.
+ * In particular, false if both are NULL (don't compare equal).
+ */
+ if (h == NULL || p == NULL) {
+ return 0;
+ }
sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
do {
@@ -51358,8 +51447,17 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *o
DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */
goto success;
} else {
+ duk_hobject *h_get = NULL;
+ duk_hobject *h_set = NULL;
+ duk_tval tv_tmp;
+
DUK_ASSERT(desc.a_idx < 0);
+ /* Set property slot to an empty state. Careful not to invoke
+ * any side effects while using desc.e_idx so that it doesn't
+ * get invalidated by a finalizer mutating our object.
+ */
+
/* remove hash entry (no decref) */
#if defined(DUK_USE_HOBJECT_HASH_PART)
if (desc.h_idx >= 0) {
@@ -51380,21 +51478,17 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *o
DUK_DDD(DUK_DDDPRINT("before removing value, e_idx %ld, key %p, key at slot %p",
(long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)));
DUK_DDD(DUK_DDDPRINT("removing value at e_idx %ld", (long) desc.e_idx));
+ DUK_MEMSET((void *) &tv_tmp, 0, sizeof(tv_tmp));
+ DUK_TVAL_SET_UNDEFINED(&tv_tmp);
if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx)) {
- duk_hobject *tmp;
-
- tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, desc.e_idx);
+ h_get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, desc.e_idx);
+ h_set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, desc.e_idx);
DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, desc.e_idx, NULL);
- DUK_UNREF(tmp);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
-
- tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, desc.e_idx);
DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, desc.e_idx, NULL);
- DUK_UNREF(tmp);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
} else {
tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
+ DUK_TVAL_SET_TVAL(&tv_tmp, tv);
+ DUK_TVAL_SET_UNDEFINED(tv);
}
#if 0
/* Not strictly necessary because if key == NULL, flag MUST be ignored. */
@@ -51407,7 +51501,14 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *o
DUK_DDD(DUK_DDDPRINT("removing key at e_idx %ld", (long) desc.e_idx));
DUK_ASSERT(key == DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx));
DUK_HOBJECT_E_SET_KEY(thr->heap, obj, desc.e_idx, NULL);
- DUK_HSTRING_DECREF(thr, key); /* side effects */
+
+ /* Do decrefs only with safe pointers to avoid side effects
+ * disturbing e_idx.
+ */
+ DUK_TVAL_DECREF(thr, &tv_tmp);
+ DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_get);
+ DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_set);
+ DUK_HSTRING_DECREF(thr, key);
goto success;
}
@@ -52581,6 +52682,7 @@ void duk_hobject_define_property_helper(duk_context *ctx,
} else {
duk_bool_t rc;
duk_tval *tv1;
+ duk_tval tv_tmp;
/* curr is data, desc is accessor */
if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
@@ -52600,9 +52702,12 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
+ /* Avoid side effects that might disturb curr.e_idx until
+ * we're done editing the slot.
+ */
tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
- /* XXX: just decref */
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
+ DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
+ DUK_TVAL_SET_UNDEFINED(tv1);
DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
@@ -52612,6 +52717,8 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_DDD(DUK_DDDPRINT("flags after data->accessor conversion: 0x%02lx",
(unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
+ DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
+
/* re-lookup to update curr.flags
* XXX: would be faster to update directly
*/
@@ -52627,7 +52734,8 @@ void duk_hobject_define_property_helper(duk_context *ctx,
if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
duk_bool_t rc;
- duk_hobject *tmp;
+ duk_hobject *h_get;
+ duk_hobject *h_set;
/* curr is accessor, desc is data */
if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
@@ -52639,15 +52747,14 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_DDD(DUK_DDDPRINT("convert property to data property"));
+ /* Avoid side effects that might disturb curr.e_idx until
+ * we're done editing the slot.
+ */
DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
- tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
- DUK_UNREF(tmp);
+ h_get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
- tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
- DUK_UNREF(tmp);
+ h_set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
DUK_TVAL_SET_UNDEFINED(DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx));
DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
@@ -52656,6 +52763,9 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_DDD(DUK_DDDPRINT("flags after accessor->data conversion: 0x%02lx",
(unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
+ DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_get); /* side effects */
+ DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_set); /* side effects */
+
/* re-lookup to update curr.flags
* XXX: would be faster to update directly
*/
@@ -59766,6 +59876,7 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x
}
case DUK_IVAL_NONE:
default: {
+ DUK_D(DUK_DPRINT("invalid ivalue type: %ld", (long) x->t));
break;
}
}
@@ -61735,13 +61846,24 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
* left-hand-side values (e.g. as in "f() = 1") must NOT cause a
* SyntaxError, but rather a run-time ReferenceError.
*
- * Assignment expression value is conceptually the LHS/RHS value
- * copied into a fresh temporary so that it won't change even if
- * LHS/RHS values change (e.g. when they're identifiers). Doing this
- * concretely produces inefficient bytecode, so we try to avoid the
- * extra temporary for some known-to-be-safe cases. Currently the
- * only safe case we detect is a "top level assignment", for example
- * "x = y + z;", where the assignment expression value is ignored.
+ * When evaluating X <op>= Y, the LHS (X) is conceptually evaluated
+ * to a temporary first. The RHS is then evaluated. Finally, the
+ * <op> is applied to the initial value of RHS (not the value after
+ * RHS evaluation), and written to X. Doing so concretely generates
+ * inefficient code so we'd like to avoid the temporary when possible.
+ * See: https://github.com/svaarala/duktape/pull/992.
+ *
+ * The expression value (final LHS value, written to RHS) is
+ * conceptually copied into a fresh temporary so that it won't
+ * change even if the LHS/RHS values change in outer expressions.
+ * For example, it'd be generally incorrect for the expression value
+ * to be the RHS register binding, unless there's a guarantee that it
+ * won't change during further expression evaluation. Using the
+ * temporary concretely produces inefficient bytecode, so we try to
+ * avoid the extra temporary for some known-to-be-safe cases.
+ * Currently the only safe case we detect is a "top level assignment",
+ * for example "x = y + z;", where the assignment expression value is
+ * ignored.
* See: test-dev-assign-expr.js and test-bug-assign-mutate-gh381.js.
*/
@@ -61761,7 +61883,9 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
* is a reg-bound identifier. The RHS ('res') is right associative
* so it has consumed all other assignment level operations; the
* only relevant lower binding power construct is comma operator
- * which will ignore the expression value provided here.
+ * which will ignore the expression value provided here. Usually
+ * the top level assignment expression value is ignored, but it
+ * is relevant for e.g. eval code.
*/
toplevel_assign = (comp_ctx->curr_func.nud_count == 1 && /* one token before */
comp_ctx->curr_func.led_count == 1); /* one operator (= assign) */
@@ -61777,23 +61901,17 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
DUK_ASSERT(left->x1.t == DUK_ISPEC_VALUE); /* LHS is already side effect free */
- /* Keep the RHS as an unresolved ivalue for now, so it
- * can be a plain value or a unary/binary operation here.
- * We resolve it before finishing but doing it later allows
- * better bytecode in some cases.
- */
- duk__expr(comp_ctx, res, args_rbp /*rbp_flags*/);
-
h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
DUK_ASSERT(h_varname != NULL);
if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
- /* E5 Section 11.13.1 (and others for other assignments), step 4 */
+ /* E5 Section 11.13.1 (and others for other assignments), step 4. */
goto syntax_error_lvalue;
}
duk_dup(ctx, left->x1.valstack_idx);
(void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
if (args_op == DUK_OP_NONE) {
+ duk__expr(comp_ctx, res, args_rbp /*rbp_flags*/);
if (toplevel_assign) {
/* Any 'res' will do. */
DUK_DDD(DUK_DDDPRINT("plain assignment, toplevel assign, use as is"));
@@ -61807,42 +61925,98 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
}
}
} else {
- duk__ivalue_toregconst(comp_ctx, res);
- DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
+ /* For X <op>= Y we need to evaluate the pre-op
+ * value of X before evaluating the RHS: the RHS
+ * can change X, but when we do <op> we must use
+ * the pre-op value.
+ */
+ duk_reg_t reg_temp;
+
+ reg_temp = DUK__ALLOCTEMP(comp_ctx);
if (reg_varbind >= 0) {
duk_reg_t reg_res;
+ duk_reg_t reg_src;
+ duk_int_t pc_temp_load;
+ duk_int_t pc_before_rhs;
+ duk_int_t pc_after_rhs;
if (toplevel_assign) {
/* 'reg_varbind' is the operation result and can also
* become the expression value for top level assignments
* such as: "var x; x += y;".
*/
+ DUK_DD(DUK_DDPRINT("<op>= expression is top level, write directly to reg_varbind"));
reg_res = reg_varbind;
} else {
/* Not safe to use 'reg_varbind' as assignment expression
* value, so go through a temp.
*/
- reg_res = DUK__ALLOCTEMP(comp_ctx);
+ DUK_DD(DUK_DDPRINT("<op>= expression is not top level, write to reg_temp"));
+ reg_res = reg_temp; /* reg_res should be smallest possible */
+ reg_temp = DUK__ALLOCTEMP(comp_ctx);
+ }
+
+ /* Try to optimize X <op>= Y for reg-bound
+ * variables. Detect side-effect free RHS
+ * narrowly by seeing whether it emits code.
+ * If not, rewind the code emitter and overwrite
+ * the unnecessary temp reg load.
+ */
+
+ pc_temp_load = duk__get_current_pc(comp_ctx);
+ duk__emit_a_bc(comp_ctx,
+ DUK_OP_LDREG,
+ (duk_regconst_t) reg_temp,
+ reg_varbind);
+
+ pc_before_rhs = duk__get_current_pc(comp_ctx);
+ duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
+ DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
+ pc_after_rhs = duk__get_current_pc(comp_ctx);
+
+ DUK_DD(DUK_DDPRINT("pc_temp_load=%ld, pc_before_rhs=%ld, pc_after_rhs=%ld",
+ (long) pc_temp_load, (long) pc_before_rhs,
+ (long) pc_after_rhs));
+
+ if (pc_after_rhs == pc_before_rhs) {
+ /* Note: if the reg_temp load generated shuffling
+ * instructions, we may need to rewind more than
+ * one instruction, so use explicit PC computation.
+ */
+ DUK_DD(DUK_DDPRINT("rhs is side effect free, rewind and avoid unnecessary temp for reg-based <op>="));
+ DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, (pc_temp_load - pc_before_rhs) * sizeof(duk_compiler_instr));
+ reg_src = reg_varbind;
+ } else {
+ DUK_DD(DUK_DDPRINT("rhs evaluation emitted code, not sure if rhs is side effect free; use temp reg for LHS"));
+ reg_src = reg_temp;
}
duk__emit_a_b_c(comp_ctx,
args_op,
(duk_regconst_t) reg_res,
- (duk_regconst_t) reg_varbind,
+ (duk_regconst_t) reg_src,
res->x1.regconst);
+
res->x1.regconst = (duk_regconst_t) reg_res;
+
+ /* Ensure compact use of temps. */
+ if (DUK__ISTEMP(comp_ctx, reg_res)) {
+ DUK__SETTEMP(comp_ctx, reg_res + 1);
+ }
} else {
/* When LHS is not register bound, always go through a
* temporary. No optimization for top level assignment.
*/
- duk_reg_t reg_temp;
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
duk__emit_a_bc(comp_ctx,
DUK_OP_GETVAR,
(duk_regconst_t) reg_temp,
rc_varname);
+
+ duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
+ DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
+
duk__emit_a_b_c(comp_ctx,
args_op,
(duk_regconst_t) reg_temp,
@@ -61928,10 +62102,10 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
DUK__IVAL_FLAG_REQUIRE_TEMP | DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
/* Evaluate RHS only when LHS is safe. */
- duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
- DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
if (args_op == DUK_OP_NONE) {
+ duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
+ DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
rc_res = res->x1.regconst;
} else {
reg_temp = DUK__ALLOCTEMP(comp_ctx);
@@ -61940,6 +62114,10 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
(duk_regconst_t) reg_temp,
(duk_regconst_t) reg_obj,
rc_key);
+
+ duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
+ DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
+
duk__emit_a_b_c(comp_ctx,
args_op,
(duk_regconst_t) reg_temp,
@@ -61971,17 +62149,18 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
duk_regconst_t rc_res;
- /* first evaluate LHS fully to ensure all side effects are out */
+ /* First evaluate LHS fully to ensure all side effects are out. */
duk__ivalue_toplain_ignore(comp_ctx, left);
- /* then evaluate RHS fully (its value becomes the expression value too) */
+ /* Then evaluate RHS fully (its value becomes the expression value too).
+ * Technically we'd need the side effect safety check here too, but because
+ * we always throw using INVLHS the result doesn't matter.
+ */
rc_res = duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
duk__emit_extraop_only(comp_ctx,
DUK_EXTRAOP_INVLHS);
- /* XXX: this value is irrelevant because of INVLHS? */
-
res->t = DUK_IVAL_PLAIN;
res->x1.t = DUK_ISPEC_REGCONST;
res->x1.regconst = rc_res;
@@ -71183,7 +71362,12 @@ DUK_LOCAL void duk__inc_data_inner_refcounts(duk_hthread *thr, duk_hcompiledfunc
duk_tval *tv, *tv_end;
duk_hobject **funcs, **funcs_end;
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f) != NULL); /* compiled functions must be created 'atomically' */
+ /* If function creation fails due to out-of-memory, the data buffer
+ * pointer may be NULL in some cases. That's actually possible for
+ * GC code, but shouldn't be possible here because the incomplete
+ * function will be unwound from the value stack and never instantiated.
+ */
+ DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f) != NULL);
DUK_UNREF(thr);
tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, f);
@@ -78997,6 +79181,7 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
duk_hobject *h_regexp;
duk_hstring *h_bytecode;
duk_hstring *h_input;
+ duk_uint8_t *p_buf;
const duk_uint8_t *pc;
const duk_uint8_t *sp;
duk_small_int_t match = 0;
@@ -79067,17 +79252,21 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
DUK_ASSERT(re_ctx.nsaved >= 2);
DUK_ASSERT((re_ctx.nsaved % 2) == 0);
- duk_push_fixed_buffer(ctx, sizeof(duk_uint8_t *) * re_ctx.nsaved);
+ p_buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, sizeof(duk_uint8_t *) * re_ctx.nsaved);
+ DUK_UNREF(p_buf);
re_ctx.saved = (const duk_uint8_t **) duk_get_buffer(ctx, -1, NULL);
DUK_ASSERT(re_ctx.saved != NULL);
/* [ ... re_obj input bc saved_buf ] */
- /* buffer is automatically zeroed */
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
for (i = 0; i < re_ctx.nsaved; i++) {
re_ctx.saved[i] = (duk_uint8_t *) NULL;
}
+#elif defined(DUK_USE_ZERO_BUFFER_DATA)
+ /* buffer is automatically zeroed */
+#else
+ DUK_MEMZERO((void *) p_buf, sizeof(duk_uint8_t *) * re_ctx.nsaved);
#endif
DUK_DDD(DUK_DDDPRINT("regexp ctx initialized, flags=0x%08lx, nsaved=%ld, recursion_limit=%ld, steps_limit=%ld",
diff --git a/content/handlers/javascript/duktape/duktape.h b/content/handlers/javascript/duktape/duktape.h
index 2cb9a5047..eb47a707b 100644
--- a/content/handlers/javascript/duktape/duktape.h
+++ b/content/handlers/javascript/duktape/duktape.h
@@ -1,12 +1,12 @@
/*
- * Duktape public API for Duktape 1.5.1.
+ * Duktape public API for Duktape 1.6.0.
*
* See the API reference for documentation on call semantics.
* The exposed API is inside the DUK_API_PUBLIC_H_INCLUDED
* include guard. Other parts of the header are Duktape
* internal and related to platform/compiler/feature detection.
*
- * Git commit 2cc76e9ff1f64869e1146ad7317d8cbe33bbd27e (v1.5.1).
+ * Git commit 17e3d86cf8b4788bd0d37658f833ab440ce43a1c (v1.6.0).
* Git branch HEAD.
*
* See Duktape AUTHORS.rst and LICENSE.txt for copyright and
@@ -163,6 +163,7 @@ extern "C" {
* in Duktape web documentation.
*/
+struct duk_thread_state;
struct duk_memory_functions;
struct duk_function_list_entry;
struct duk_number_list_entry;
@@ -170,6 +171,7 @@ struct duk_number_list_entry;
/* duk_context is now defined in duk_config.h because it may also be
* referenced there by prototypes.
*/
+typedef struct duk_thread_state duk_thread_state;
typedef struct duk_memory_functions duk_memory_functions;
typedef struct duk_function_list_entry duk_function_list_entry;
typedef struct duk_number_list_entry duk_number_list_entry;
@@ -190,6 +192,14 @@ typedef void (*duk_debug_write_flush_function) (void *udata);
typedef duk_idx_t (*duk_debug_request_function) (duk_context *ctx, void *udata, duk_idx_t nvalues);
typedef void (*duk_debug_detached_function) (void *udata);
+struct duk_thread_state {
+ /* XXX: Enough space to hold internal suspend/resume structure.
+ * This is rather awkward and to be fixed when the internal
+ * structure is visible for the public API header.
+ */
+ char data[128];
+};
+
struct duk_memory_functions {
duk_alloc_function alloc_func;
duk_realloc_function realloc_func;
@@ -218,15 +228,15 @@ struct duk_number_list_entry {
* have 99 for patch level (e.g. 0.10.99 would be a development version
* after 0.10.0 but before the next official release).
*/
-#define DUK_VERSION 10501L
+#define DUK_VERSION 10600L
/* Git commit, describe, and branch for Duktape build. Useful for
* non-official snapshot builds so that application code can easily log
* which Duktape snapshot was used. Not available in the Ecmascript
* environment.
*/
-#define DUK_GIT_COMMIT "2cc76e9ff1f64869e1146ad7317d8cbe33bbd27e"
-#define DUK_GIT_DESCRIBE "v1.5.1"
+#define DUK_GIT_COMMIT "17e3d86cf8b4788bd0d37658f833ab440ce43a1c"
+#define DUK_GIT_DESCRIBE "v1.6.0"
#define DUK_GIT_BRANCH "HEAD"
/* Duktape debug protocol version used by this build. */
@@ -397,6 +407,9 @@ duk_context *duk_create_heap(duk_alloc_function alloc_func,
duk_fatal_function fatal_handler);
DUK_EXTERNAL_DECL void duk_destroy_heap(duk_context *ctx);
+DUK_EXTERNAL_DECL void duk_suspend(duk_context *ctx, duk_thread_state *state);
+DUK_EXTERNAL_DECL void duk_resume(duk_context *ctx, const duk_thread_state *state);
+
#define duk_create_heap_default() \
duk_create_heap(NULL, NULL, NULL, NULL, NULL)
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index d129ef72f..4a1473753 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -279,6 +279,9 @@ void netsurf_exit(void)
LOG("Destroying System colours");
ns_system_colour_finalize();
+ LOG("Destroying Messages");
+ messages_destroy();
+
corestrings_fini();
LOG("Remaining lwc strings:");
lwc_iterate_strings(netsurf_lwc_iterator, NULL);
diff --git a/desktop/tree.c b/desktop/tree.c
index 4972777ba..6acf179da 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -129,10 +129,6 @@ static bool treeview_test_init(struct tree *tree)
switch (tree->flags) {
case TREE_COOKIES:
- assert(ssl_current_session == NULL &&
- "Call sslcert_viewer_init directly, "
- "this compat. layer can't cope with simultanious "
- "sslcert viewers");
err = cookie_manager_init(&cw_t, (struct core_window *)tree);
if (err != NSERROR_OK)
guit->misc->warning("Couldn't init new cookie manager.", 0);
@@ -149,6 +145,10 @@ static bool treeview_test_init(struct tree *tree)
guit->misc->warning("Couldn't init new hotlist.", 0);
break;
case TREE_SSLCERT:
+ assert(ssl_current_session == NULL &&
+ "Call sslcert_viewer_init directly, "
+ "this compat. layer can't cope with simultanious "
+ "sslcert viewers");
err = sslcert_viewer_init(&cw_t, (struct core_window *)tree,
ssl_current_session);
if (err != NSERROR_OK)
diff --git a/frontends/amiga/gui.c b/frontends/amiga/gui.c
index 76785051f..2c7bc82f6 100644
--- a/frontends/amiga/gui.c
+++ b/frontends/amiga/gui.c
@@ -217,7 +217,6 @@ static bool cli_force = false;
#define USERS_DIR "PROGDIR:Users"
static char *users_dir = NULL;
-static char *current_user = NULL;
static char *current_user_dir;
static char *current_user_faviconcache;
@@ -285,6 +284,7 @@ STRPTR ami_locale_langs(int *codeset)
acceptlangs = ASPrintf("%s", remapped);
}
}
+ if(remapped != NULL) free(remapped);
}
else
{
@@ -354,8 +354,7 @@ static bool ami_gui_check_resource(char *fullpath, const char *file)
netsurf_mkpath(&fullpath, &fullpath_len, 2, fullpath, remapped);
lock = Lock(fullpath, ACCESS_READ);
- if(lock)
- {
+ if(lock) {
UnLock(lock);
found = true;
}
@@ -371,7 +370,7 @@ bool ami_locate_resource(char *fullpath, const char *file)
struct Locale *locale;
int i;
bool found = false;
- char *remapped;
+ char *remapped = NULL;
size_t fullpath_len = 1024;
/* Check NetSurf user data area first */
@@ -397,11 +396,12 @@ bool ami_locate_resource(char *fullpath, const char *file)
strcpy(fullpath, "PROGDIR:Resources/");
if(locale->loc_PrefLanguages[i]) {
- ami_gui_map_filename(&remapped, "PROGDIR:Resources",
- locale->loc_PrefLanguages[i], "LangNames");
- netsurf_mkpath(&fullpath, &fullpath_len, 2, fullpath, remapped);
-
- found = ami_gui_check_resource(fullpath, file);
+ if(ami_gui_map_filename(&remapped, "PROGDIR:Resources",
+ locale->loc_PrefLanguages[i], "LangNames") == true) {
+ netsurf_mkpath(&fullpath, &fullpath_len, 2, fullpath, remapped);
+ found = ami_gui_check_resource(fullpath, file);
+ free(remapped);
+ }
} else {
continue;
}
@@ -429,7 +429,17 @@ bool ami_locate_resource(char *fullpath, const char *file)
return found;
}
-static bool ami_open_resources(void)
+static void ami_gui_resources_free(void)
+{
+ ami_schedule_free();
+ ami_object_fini();
+
+ FreeSysObject(ASOT_PORT, appport);
+ FreeSysObject(ASOT_PORT, sport);
+ FreeSysObject(ASOT_PORT, schedulermsgport);
+}
+
+static bool ami_gui_resources_open(void)
{
urlStringClass = MakeStringClass();
@@ -445,6 +455,13 @@ static bool ami_open_resources(void)
ASO_NoTrack, FALSE,
TAG_DONE))) return false;
+ if(ami_schedule_create(schedulermsgport) != NSERROR_OK) {
+ ami_misc_fatal_error("Failed to initialise scheduler");
+ return false;
+ }
+
+ ami_object_init();
+
return true;
}
@@ -905,11 +922,12 @@ static struct RDArgs *ami_gui_commandline(int *restrict argc, char ** argv,
return NULL;
}
-static void ami_gui_read_tooltypes(struct WBArg *wbarg)
+static char *ami_gui_read_tooltypes(struct WBArg *wbarg)
{
struct DiskObject *dobj;
STRPTR *toolarray;
char *s;
+ char *current_user = NULL;
if((*wbarg->wa_Name) && (dobj = GetDiskObject(wbarg->wa_Name))) {
toolarray = (STRPTR *)dobj->do_ToolTypes;
@@ -919,13 +937,16 @@ static void ami_gui_read_tooltypes(struct WBArg *wbarg)
FreeDiskObject(dobj);
}
+ return current_user;
}
-static void ami_gui_read_all_tooltypes(int argc, char **argv)
+static STRPTR ami_gui_read_all_tooltypes(int argc, char **argv)
{
struct WBStartup *WBenchMsg;
struct WBArg *wbarg;
char i = 0;
+ char *current_user = NULL;
+ char *cur_user = NULL;
if(argc == 0) { /* Started from WB */
WBenchMsg = (struct WBStartup *)argv;
@@ -934,11 +955,17 @@ static void ami_gui_read_all_tooltypes(int argc, char **argv)
if((wbarg->wa_Lock) && (*wbarg->wa_Name))
olddir = SetCurrentDir(wbarg->wa_Lock);
- ami_gui_read_tooltypes(wbarg);
+ cur_user = ami_gui_read_tooltypes(wbarg);
+ if(cur_user != NULL) {
+ if(current_user != NULL) FreeVec(current_user);
+ current_user = cur_user;
+ }
if(olddir !=-1) SetCurrentDir(olddir);
}
}
+
+ return current_user;
}
void ami_gui_set_default_gg(void)
@@ -1311,8 +1338,9 @@ int ami_key_to_nskey(ULONG keycode, struct InputEvent *ie)
break;
default:
if((chars = MapRawKey(ie,buffer,20,NULL)) > 0) {
- utf8_from_local_encoding(buffer, chars, &utf8);
+ if(utf8_from_local_encoding(buffer, chars, &utf8) != NSERROR_OK) return 0;
nskey = utf8_to_ucs4(utf8, utf8_char_byte_length(utf8));
+ free(utf8);
if(ie->ie_Qualifier & IEQUALIFIER_RCOMMAND) {
switch(nskey) {
@@ -2914,6 +2942,9 @@ void ami_quit_netsurf(void)
struct nsObject *nnode;
struct gui_window_2 *gwin;
+ /* Disable the multiple tabs open warning */
+ nsoption_set_bool(tab_close_warn, false);
+
if(!IsMinListEmpty(window_list)) {
node = (struct nsObject *)GetHead((struct List *)window_list);
@@ -2973,7 +3004,6 @@ void ami_quit_netsurf_delayed(void)
free(utf8gadgets);
#endif
if(res == -1) { /* Requester timed out */
- nsoption_set_bool(tab_close_warn, false);
ami_quit_netsurf();
}
}
@@ -3061,6 +3091,13 @@ static void gui_quit(void)
FreeStringClass(urlStringClass);
FreeObjList(window_list);
+
+ ami_clipboard_free();
+ ami_gui_resources_free();
+
+ LOG("Closing screen");
+ ami_gui_close_screen(scrn, locked_screen, FALSE);
+ if(nsscreentitle) FreeVec(nsscreentitle);
}
char *ami_gui_get_cache_favicon_name(nsurl *url, bool only_if_avail)
@@ -4527,8 +4564,7 @@ static void gui_window_destroy(struct gui_window *g)
if((g->shared->tabs == 1) && (nsoption_bool(tab_always_show) == false))
ami_toggletabbar(g->shared, false);
- ami_utf8_free(g->tabtitle);
-
+ if(g->tabtitle) free(g->tabtitle);
free(g);
return;
}
@@ -4574,6 +4610,7 @@ static void gui_window_destroy(struct gui_window *g)
Remove(g->tab_node);
FreeClickTabNode(g->tab_node);
}
+ if(g->tabtitle) free(g->tabtitle);
free(g); // g->shared should be freed by DelObject()
if(IsMinListEmpty(window_list))
@@ -4595,8 +4632,7 @@ static void gui_window_set_title(struct gui_window *g, const char *restrict titl
utf8title = ami_utf8_easy((char *)title);
- if(g->tab_node) // && (g->shared->tabs > 1))
- {
+ if(g->tab_node) {
node = g->tab_node;
if((g->tabtitle == NULL) || (strcmp(utf8title, g->tabtitle)))
@@ -4606,7 +4642,7 @@ static void gui_window_set_title(struct gui_window *g, const char *restrict titl
CLICKTAB_Labels, ~0,
TAG_DONE);
- if(g->tabtitle) ami_utf8_free(g->tabtitle);
+ if(g->tabtitle) free(g->tabtitle);
g->tabtitle = strdup(utf8title);
SetClickTabNodeAttrs(node, TNA_Text, g->tabtitle,
@@ -5452,6 +5488,84 @@ uint32 ami_gui_get_app_id(void)
return ami_appid;
}
+/* Get current user directory for user-specific NetSurf data
+ * Returns NULL on error
+ */
+static char *ami_gui_get_user_dir(STRPTR current_user)
+{
+ BPTR lock = 0;
+ char temp[1024];
+ int32 user = 0;
+
+ if(current_user == NULL) {
+ user = GetVar("user", temp, 1024, GVF_GLOBAL_ONLY);
+ current_user = ASPrintf("%s", (user == -1) ? "Default" : temp);
+ }
+ LOG("User: %s", current_user);
+
+ if(users_dir == NULL) {
+ users_dir = ASPrintf("%s", USERS_DIR);
+ if(users_dir == NULL) {
+ ami_misc_fatal_error("Failed to allocate memory");
+ FreeVec(current_user);
+ return NULL;
+ }
+ }
+
+ if(LIB_IS_AT_LEAST((struct Library *)DOSBase, 51, 96)) {
+#ifdef __amigaos4__
+ struct InfoData *infodata = AllocDosObject(DOS_INFODATA, 0);
+ if(infodata == NULL) {
+ ami_misc_fatal_error("Failed to allocate memory");
+ FreeVec(current_user);
+ return NULL;
+ }
+ GetDiskInfoTags(GDI_StringNameInput, users_dir,
+ GDI_InfoData, infodata,
+ TAG_DONE);
+ if(infodata->id_DiskState == ID_DISKSTATE_WRITE_PROTECTED) {
+ FreeDosObject(DOS_INFODATA, infodata);
+ ami_misc_fatal_error("User directory MUST be on a writeable volume");
+ FreeVec(current_user);
+ return NULL;
+ }
+ FreeDosObject(DOS_INFODATA, infodata);
+#else
+#warning FIXME for OS3 and older OS4
+#endif
+ } else {
+//TODO: check volume write status using old API
+ }
+
+ int len = strlen(current_user);
+ len += strlen(users_dir);
+ len += 2; /* for poss path sep and NULL term */
+
+ current_user_dir = malloc(len);
+ if(current_user_dir == NULL) {
+ ami_misc_fatal_error("Failed to allocate memory");
+ FreeVec(current_user);
+ return NULL;
+ }
+
+ strlcpy(current_user_dir, users_dir, len);
+ AddPart(current_user_dir, current_user, len);
+ FreeVec(users_dir);
+ FreeVec(current_user);
+
+ LOG("User dir: %s", current_user_dir);
+
+ if((lock = CreateDirTree(current_user_dir)))
+ UnLock(lock);
+
+ ami_nsoption_set_location(current_user_dir);
+
+ current_user_faviconcache = ASPrintf("%s/IconCache", current_user_dir);
+ if((lock = CreateDirTree(current_user_faviconcache))) UnLock(lock);
+
+ return current_user_dir;
+}
+
static struct gui_window_table amiga_window_table = {
.create = gui_window_create,
.destroy = gui_window_destroy,
@@ -5515,8 +5629,8 @@ int main(int argc, char** argv)
char script[1024];
char temp[1024];
STRPTR current_user_cache = NULL;
+ STRPTR current_user = NULL;
BPTR lock = 0;
- int32 user = 0;
nserror ret;
int nargc = 0;
char *nargv = NULL;
@@ -5563,99 +5677,24 @@ int main(int argc, char** argv)
struct Interupt *memhandler = ami_memory_init();
#endif
- ami_object_init();
-
- if (ami_open_resources() == false) { /* alloc message ports */
+ if (ami_gui_resources_open() == false) { /* alloc msgports, objects and other miscelleny */
ami_misc_fatal_error("Unable to allocate resources");
ami_gui_splash_close(splash_window);
ami_libs_close();
return RETURN_FAIL;
}
- if(ami_schedule_create(schedulermsgport) != NSERROR_OK) {
- ami_misc_fatal_error("Failed to initialise scheduler");
- ami_gui_splash_close(splash_window);
- ami_libs_close();
- return RETURN_FAIL;
- }
-
- ami_gui_read_all_tooltypes(argc, argv);
+ current_user = ami_gui_read_all_tooltypes(argc, argv);
struct RDArgs *args = ami_gui_commandline(&argc, argv, &nargc, &nargv);
- if(current_user == NULL) {
- user = GetVar("user", temp, 1024, GVF_GLOBAL_ONLY);
- current_user = ASPrintf("%s", (user == -1) ? "Default" : temp);
- }
- LOG("User: %s", current_user);
-
- if(users_dir == NULL) {
- users_dir = ASPrintf("%s", USERS_DIR);
- if(users_dir == NULL) {
- ami_misc_fatal_error("Failed to allocate memory");
- ami_schedule_free();
- ami_gui_splash_close(splash_window);
- ami_libs_close();
- return RETURN_FAIL;
- }
- }
-
- if(LIB_IS_AT_LEAST((struct Library *)DOSBase, 51, 96)) {
-#ifdef __amigaos4__
- struct InfoData *infodata = AllocDosObject(DOS_INFODATA, 0);
- if(infodata == NULL) {
- ami_misc_fatal_error("Failed to allocate memory");
- ami_schedule_free();
- ami_gui_splash_close(splash_window);
- ami_libs_close();
- return RETURN_FAIL;
- }
- GetDiskInfoTags(GDI_StringNameInput, users_dir,
- GDI_InfoData, infodata,
- TAG_DONE);
- if(infodata->id_DiskState == ID_DISKSTATE_WRITE_PROTECTED) {
- FreeDosObject(DOS_INFODATA, infodata);
- ami_misc_fatal_error("User directory MUST be on a writeable volume");
- ami_schedule_free();
- ami_gui_splash_close(splash_window);
- ami_libs_close();
- return RETURN_FAIL;
- }
- FreeDosObject(DOS_INFODATA, infodata);
-#else
-#warning FIXME for OS3 and older OS4
-#endif
- } else {
-//TODO: check volume write status using old API
- }
-
- int len = strlen(current_user);
- len += strlen(users_dir);
- len += 2; /* for poss path sep and NULL term */
-
- current_user_dir = malloc(len);
+ current_user_dir = ami_gui_get_user_dir(current_user);
if(current_user_dir == NULL) {
- ami_misc_fatal_error("Failed to allocate memory");
- ami_schedule_free();
+ ami_gui_resources_free();
ami_gui_splash_close(splash_window);
ami_libs_close();
return RETURN_FAIL;
}
- strlcpy(current_user_dir, users_dir, len);
- AddPart(current_user_dir, current_user, len);
- FreeVec(users_dir);
- LOG("User dir: %s", current_user_dir);
-
- if((lock = CreateDirTree(current_user_dir)))
- UnLock(lock);
-
- ami_nsoption_set_location(current_user_dir);
- current_user_cache = ASPrintf("%s/Cache", current_user_dir);
- current_user_faviconcache = ASPrintf("%s/IconCache", current_user_dir);
-
- if((lock = CreateDirTree(current_user_cache))) UnLock(lock);
- if((lock = CreateDirTree(current_user_faviconcache))) UnLock(lock);
-
ami_mime_init("PROGDIR:Resources/mimetypes");
sprintf(temp, "%s/mimetypes.user", current_user_dir);
ami_mime_init(temp);
@@ -5673,7 +5712,7 @@ int main(int argc, char** argv)
ret = nsoption_init(ami_set_options, &nsoptions, &nsoptions_default);
if (ret != NSERROR_OK) {
ami_misc_fatal_error("Options failed to initialise");
- ami_schedule_free();
+ ami_gui_resources_free();
ami_gui_splash_close(splash_window);
ami_libs_close();
return RETURN_FAIL;
@@ -5686,7 +5725,9 @@ int main(int argc, char** argv)
if (ami_locate_resource(messages, "Messages") == false) {
ami_misc_fatal_error("Cannot open Messages file");
- ami_schedule_free();
+ ami_nsoption_free();
+ nsoption_finalise(nsoptions, nsoptions_default);
+ ami_gui_resources_free();
ami_gui_splash_close(splash_window);
ami_libs_close();
return RETURN_FAIL;
@@ -5694,16 +5735,23 @@ int main(int argc, char** argv)
ret = messages_add_from_file(messages);
+ current_user_cache = ASPrintf("%s/Cache", current_user_dir);
+ if((lock = CreateDirTree(current_user_cache))) UnLock(lock);
+
ret = netsurf_init(current_user_cache);
+
+ if(current_user_cache != NULL) FreeVec(current_user_cache);
+
if (ret != NSERROR_OK) {
ami_misc_fatal_error("NetSurf failed to initialise");
- ami_schedule_free();
+ ami_nsoption_free();
+ nsoption_finalise(nsoptions, nsoptions_default);
+ ami_gui_resources_free();
ami_gui_splash_close(splash_window);
ami_libs_close();
return RETURN_FAIL;
}
- if(current_user_cache != NULL) FreeVec(current_user_cache);
ret = amiga_icon_init();
search_web_init(nsoption_charp(search_engines_file));
@@ -5748,30 +5796,17 @@ int main(int argc, char** argv)
netsurf_exit();
+ nsoption_finalise(nsoptions, nsoptions_default);
ami_nsoption_free();
free(current_user_dir);
FreeVec(current_user_faviconcache);
- FreeVec(current_user);
-
- ami_clipboard_free();
- ami_schedule_free();
-
- FreeSysObject(ASOT_PORT, appport);
- FreeSysObject(ASOT_PORT, sport);
- FreeSysObject(ASOT_PORT, schedulermsgport);
-
- ami_object_fini();
- ami_bitmap_fini();
#ifndef __amigaos4__
/* OS3 low memory handler */
ami_memory_fini(memhandler);
#endif
- LOG("Closing screen");
- ami_gui_close_screen(scrn, locked_screen, FALSE);
- if(nsscreentitle) FreeVec(nsscreentitle);
-
+ ami_bitmap_fini();
ami_libs_close();
return RETURN_OK;
diff --git a/frontends/amiga/launch.c b/frontends/amiga/launch.c
index 31800ef7a..10c32aeed 100755
--- a/frontends/amiga/launch.c
+++ b/frontends/amiga/launch.c
@@ -74,19 +74,19 @@ static void ami_openurl_free_list(struct MinList *list)
struct ami_protocol *node;
struct ami_protocol *nnode;
- if(IsMinListEmpty(list)) return;
- node = (struct ami_protocol *)GetHead((struct List *)list);
-
- do
- {
- nnode=(struct ami_protocol *)GetSucc((struct Node *)node);
+ if(IsMinListEmpty(list) == NULL) {
+ node = (struct ami_protocol *)GetHead((struct List *)list);
- Remove((struct Node *)node);
- if (node->protocol) lwc_string_unref(node->protocol);
- free(node);
- node = NULL;
- }while((node=nnode));
+ do
+ {
+ nnode=(struct ami_protocol *)GetSucc((struct Node *)node);
+ Remove((struct Node *)node);
+ if (node->protocol) lwc_string_unref(node->protocol);
+ free(node);
+ node = NULL;
+ }while((node=nnode));
+ }
free(list);
}
diff --git a/frontends/amiga/memory.h b/frontends/amiga/memory.h
index 7abf0a387..a9a882e46 100644
--- a/frontends/amiga/memory.h
+++ b/frontends/amiga/memory.h
@@ -51,10 +51,10 @@ void *ami_memory_clear_alloc(size_t size, UBYTE value);
#define ami_memory_itempool_alloc(p,s) ItemPoolAlloc(p)
#define ami_memory_itempool_free(p,i,s) ItemPoolFree(p,i)
#else
-#define ami_memory_itempool_create(s) CreatePool(MEMF_ANY, 20 * s, s)
-#define ami_memory_itempool_delete(p) DeletePool(p)
-#define ami_memory_itempool_alloc(p,s) AllocPooled(p, s)
-#define ami_memory_itempool_free(p,i,s) FreePooled(p,i,s)
+#define ami_memory_itempool_create(s) ((APTR)1)
+#define ami_memory_itempool_delete(p) ((void)0)
+#define ami_memory_itempool_alloc(p,s) malloc(s)
+#define ami_memory_itempool_free(p,i,s) free(i)
#endif
/* clib2 slab allocator */
diff --git a/frontends/amiga/object.c b/frontends/amiga/object.c
index 2ebca7593..37fc724bf 100755
--- a/frontends/amiga/object.c
+++ b/frontends/amiga/object.c
@@ -119,18 +119,18 @@ void FreeObjList(struct MinList *objlist)
struct nsObject *node;
struct nsObject *nnode;
- if(IsMinListEmpty((struct MinList *)objlist)) return;
- node = (struct nsObject *)GetHead((struct List *)objlist);
-
- do {
- nnode=(struct nsObject *)GetSucc((struct Node *)node);
- if(node->Type == AMINS_RECT) {
- DelObjectNoFree(node);
- } else {
- DelObject(node);
- }
- } while((node=nnode));
-
+ if(IsMinListEmpty((struct MinList *)objlist) == FALSE) {
+ node = (struct nsObject *)GetHead((struct List *)objlist);
+
+ do {
+ nnode = (struct nsObject *)GetSucc((struct Node *)node);
+ if(node->Type == AMINS_RECT) {
+ DelObjectNoFree(node);
+ } else {
+ DelObject(node);
+ }
+ } while((node = nnode));
+ }
free(objlist);
}
diff --git a/frontends/amiga/tree.c b/frontends/amiga/tree.c
index 90497092d..79753a7d3 100644
--- a/frontends/amiga/tree.c
+++ b/frontends/amiga/tree.c
@@ -234,6 +234,7 @@ static void ami_tree_redraw_req_dr(void *p)
if(ami_gui_get_space_box(twin->objects[GID_BROWSER], &bbox) != NSERROR_OK) {
amiga_warn_user("NoMemory", "");
+ free(atrr_data);
return;
}
@@ -282,6 +283,8 @@ static void ami_tree_redraw_req(void *p)
.plot = &amiplot
};
+ free(atrr_data);
+
if(!twin->win) return;
ami_update_pointer(twin->win, GUI_POINTER_WAIT);
@@ -341,7 +344,6 @@ static void ami_tree_redraw_req(void *p)
}
}
- free(atrr_data);
ami_gui_free_space_box(bbox);
ami_update_pointer(twin->win, GUI_POINTER_DEFAULT);
ami_clearclipreg(glob);
diff --git a/frontends/beos/cookies.cpp b/frontends/beos/cookies.cpp
index 66cf8bbef..91a9beb4c 100644
--- a/frontends/beos/cookies.cpp
+++ b/frontends/beos/cookies.cpp
@@ -27,7 +27,6 @@ extern "C" {
#include "netsurf/cookie_db.h"
#include "netsurf/keypress.h"
#include "desktop/cookie_manager.h"
-#include "desktop/tree.h"
}
#include "beos/cookies.h"
diff --git a/frontends/riscos/gui.c b/frontends/riscos/gui.c
index a534bceff..3ac9d4aa9 100644
--- a/frontends/riscos/gui.c
+++ b/frontends/riscos/gui.c
@@ -2513,6 +2513,7 @@ int main(int argc, char** argv)
}
netsurf_exit();
+ nsoption_finalise(nsoptions, nsoptions_default);
return 0;
}
diff --git a/utils/messages.c b/utils/messages.c
index e69a85524..0c558cdfc 100644
--- a/utils/messages.c
+++ b/utils/messages.c
@@ -177,6 +177,22 @@ messages_get_ctx(const char *key, struct hash_table *ctx)
return r;
}
+
+/**
+ * Free memory used by a messages hash.
+ * The context will not be valid after this function returns.
+ *
+ * \param ctx context of messages file to free
+ */
+static void messages_destroy_ctx(struct hash_table *ctx)
+{
+ if (ctx == NULL)
+ return;
+
+ hash_destroy(ctx);
+}
+
+
/* exported interface documented in messages.h */
nserror messages_add_from_file(const char *path)
{
@@ -390,3 +406,12 @@ const char *messages_get_errorcode(nserror code)
/* Unknown error */
return messages_get_ctx("Unknown", messages_hash);
}
+
+
+/* exported function documented in utils/messages.h */
+void messages_destroy(void)
+{
+ messages_destroy_ctx(messages_hash);
+ messages_hash = NULL;
+}
+
diff --git a/utils/messages.h b/utils/messages.h
index 784e5fe6a..4024f7e77 100644
--- a/utils/messages.h
+++ b/utils/messages.h
@@ -90,4 +90,9 @@ const char *messages_get_errorcode(nserror code);
char *messages_get_buff(const char *key, ...);
+/**
+ * Free memory used by the standard Messages hash
+ */
+void messages_destroy(void);
+
#endif
diff --git a/test-netsurf b/utils/test-netsurf
index 90c7e121b..90c7e121b 100755
--- a/test-netsurf
+++ b/utils/test-netsurf