Gitweb links:
...log
http://git.netsurf-browser.org/netsurf.git/shortlog/770c277ccc182f504be0a316390d59c05a59e041
...commit
http://git.netsurf-browser.org/netsurf.git/commit/770c277ccc182f504be0a316390d59c05a59e041
...tree
http://git.netsurf-browser.org/netsurf.git/tree/770c277ccc182f504be0a316390d59c05a59e041
The branch, master has been updated
via 770c277ccc182f504be0a316390d59c05a59e041 (commit)
via 539d5da5c4b814322cfac07b825a2b222951dacd (commit)
via 7c03ae91fd8a99576cd5f0b8e5311f990ae5739b (commit)
from b227be8cd2108405793e117fa150808dd6120f29 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=770c277ccc182f504be0a316390d59c05a59e041
commit 770c277ccc182f504be0a316390d59c05a59e041
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Duktape: Prevent clang static analysis.
Restore 336326af3aab93f31474fa6de28782457ae4a1c0 for 1.6.0 import.
diff --git a/content/handlers/javascript/duktape/duktape.c
b/content/handlers/javascript/duktape/duktape.c
index 732cb80..b64383b 100644
--- a/content/handlers/javascript/duktape/duktape.c
+++ b/content/handlers/javascript/duktape/duktape.c
@@ -1,3 +1,5 @@
+/* Omit from static analysis. */
+#ifndef __clang_analyzer__
/*
* Single source autogenerated distributable for Duktape 1.6.0.
*
@@ -86753,3 +86755,4 @@ DUK_INTERNAL duk_double_t
duk_util_tinyrandom_get_double(duk_hthread *thr) {
return t;
}
+#endif
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=539d5da5c4b814322cfac07b825a2b222951dacd
commit 539d5da5c4b814322cfac07b825a2b222951dacd
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Duktape: Make declarations match definitions for duk_raw_read_xxx_be
Restore 6d63f7959af64a45b0643d0610fcbdb0c07bfbc4 for 1.6.0 import.
diff --git a/content/handlers/javascript/duktape/duktape.c
b/content/handlers/javascript/duktape/duktape.c
index ca17277..732cb80 100644
--- a/content/handlers/javascript/duktape/duktape.c
+++ b/content/handlers/javascript/duktape/duktape.c
@@ -2248,12 +2248,12 @@ DUK_INTERNAL_DECL duk_uint8_t
*duk_bw_insert_ensure_area(duk_hthread *thr, duk_b
DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr,
duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
/* No duk_bw_remove_ensure_slice(), functionality would be identical. */
-DUK_INTERNAL_DECL duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p);
-DUK_INTERNAL_DECL duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p);
-DUK_INTERNAL_DECL duk_double_t duk_raw_read_double_be(duk_uint8_t **p);
-DUK_INTERNAL_DECL void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val);
-DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val);
-DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t
val);
+DUK_INTERNAL_DECL DUK_INLINE duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p);
+DUK_INTERNAL_DECL DUK_INLINE duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p);
+DUK_INTERNAL_DECL DUK_INLINE duk_double_t duk_raw_read_double_be(duk_uint8_t
**p);
+DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_u16_be(duk_uint8_t **p,
duk_uint16_t val);
+DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_u32_be(duk_uint8_t **p,
duk_uint32_t val);
+DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_double_be(duk_uint8_t **p,
duk_double_t val);
#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger.
*/
DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=7c03ae91fd8a99576cd5f0b8e5311f990ae5739b
commit 7c03ae91fd8a99576cd5f0b8e5311f990ae5739b
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Duktape: Update to version 1.6.0.
diff --git a/content/handlers/javascript/duktape/duk_config.h
b/content/handlers/javascript/duktape/duk_config.h
index c336603..f9c95ae 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 e1867c0..ca17277 100644
--- a/content/handlers/javascript/duktape/duktape.c
+++ b/content/handlers/javascript/duktape/duktape.c
@@ -1,9 +1,7 @@
-/* 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 +1629,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
@@ -2250,12 +2248,12 @@ DUK_INTERNAL_DECL duk_uint8_t
*duk_bw_insert_ensure_area(duk_hthread *thr, duk_b
DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr,
duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
/* No duk_bw_remove_ensure_slice(), functionality would be identical. */
-DUK_INTERNAL_DECL DUK_INLINE duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p);
-DUK_INTERNAL_DECL DUK_INLINE duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p);
-DUK_INTERNAL_DECL DUK_INLINE duk_double_t duk_raw_read_double_be(duk_uint8_t
**p);
-DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_u16_be(duk_uint8_t **p,
duk_uint16_t val);
-DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_u32_be(duk_uint8_t **p,
duk_uint32_t val);
-DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_double_be(duk_uint8_t **p,
duk_double_t val);
+DUK_INTERNAL_DECL duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p);
+DUK_INTERNAL_DECL duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p);
+DUK_INTERNAL_DECL duk_double_t duk_raw_read_double_be(duk_uint8_t **p);
+DUK_INTERNAL_DECL void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val);
+DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val);
+DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t
val);
#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger.
*/
DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
@@ -9221,7 +9219,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 +9227,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 +9353,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 +9533,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 +9713,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 +14046,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 +14120,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 +14476,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 +14484,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 +14506,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 +14540,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 +31459,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 +31802,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 +34005,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 +42110,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 +44006,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 +46952,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 +51445,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 +51476,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 +51499,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 +52680,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 +52700,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 +52715,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 +52732,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 +52745,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 +52761,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 +59874,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 +61844,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 +61881,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 +61899,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 +61923,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 +62100,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 +62112,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 +62147,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 +71360,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 +79179,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 +79250,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",
@@ -86566,4 +86753,3 @@ DUK_INTERNAL duk_double_t
duk_util_tinyrandom_get_double(duk_hthread *thr) {
return t;
}
-#endif
diff --git a/content/handlers/javascript/duktape/duktape.h
b/content/handlers/javascript/duktape/duktape.h
index 2cb9a50..eb47a70 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)
-----------------------------------------------------------------------
Summary of changes:
content/handlers/javascript/duktape/duk_config.h | 4 +-
content/handlers/javascript/duktape/duktape.c | 407 ++++++++++++++++------
content/handlers/javascript/duktape/duktape.h | 23 +-
3 files changed, 318 insertions(+), 116 deletions(-)
diff --git a/content/handlers/javascript/duktape/duk_config.h
b/content/handlers/javascript/duktape/duk_config.h
index c336603..f9c95ae 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 e1867c0..b64383b 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 2cb9a50..eb47a70 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)
--
NetSurf Browser
_______________________________________________
netsurf-commits mailing list
[email protected]
http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/netsurf-commits-netsurf-browser.org