Duktape: Update to version 1.6.0.

This commit is contained in:
Michael Drake 2016-12-28 15:01:03 +00:00
parent b227be8cd2
commit 7c03ae91fd
3 changed files with 324 additions and 125 deletions

View File

@ -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:

View File

@ -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' */
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++;
}
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, &reg_varbind, &rc_varname);
if (args_op == DUK_OP_NONE) {
duk__expr(comp_ctx, res, args_rbp /*rbp_flags*/);
if (toplevel_assign) {
/* Any 'res' will do. */
DUK_DDD(DUK_DDDPRINT("plain assignment, toplevel assign, use as is"));
@ -61807,42 +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

View File

@ -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)