diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | content/handlers/javascript/duktape/duk_config.h | 4 | ||||
-rw-r--r-- | content/handlers/javascript/duktape/duktape.c | 407 | ||||
-rw-r--r-- | content/handlers/javascript/duktape/duktape.h | 23 | ||||
-rw-r--r-- | desktop/netsurf.c | 3 | ||||
-rw-r--r-- | desktop/tree.c | 8 | ||||
-rw-r--r-- | frontends/amiga/gui.c | 273 | ||||
-rwxr-xr-x | frontends/amiga/launch.c | 22 | ||||
-rw-r--r-- | frontends/amiga/memory.h | 8 | ||||
-rwxr-xr-x | frontends/amiga/object.c | 24 | ||||
-rw-r--r-- | frontends/amiga/tree.c | 4 | ||||
-rw-r--r-- | frontends/beos/cookies.cpp | 1 | ||||
-rw-r--r-- | frontends/riscos/gui.c | 1 | ||||
-rw-r--r-- | utils/messages.c | 25 | ||||
-rw-r--r-- | utils/messages.h | 5 | ||||
-rwxr-xr-x | utils/test-netsurf (renamed from test-netsurf) | 0 |
16 files changed, 541 insertions, 269 deletions
@@ -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, ®_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 |