duktape: Import v2.6.0
diff --git a/duktape/duk_config.h b/duktape/duk_config.h
index 130168a..c7cebde 100644
--- a/duktape/duk_config.h
+++ b/duktape/duk_config.h
@@ -1,9 +1,9 @@
 /*
  *  duk_config.h configuration header generated by genconfig.py.
  *
- *  Git commit: 6001888049cb42656f8649db020e804bcdeca6a7
- *  Git describe: v2.5.0
- *  Git branch: master
+ *  Git commit: fffa346eff06a8764b02c31d4336f63a773a95c3
+ *  Git describe: v2.6.0
+ *  Git branch: v2-maintenance
  *
  *  Supported platforms:
  *      - Mac OSX, iPhone, Darwin
@@ -964,9 +964,7 @@
 #elif defined(DUK_F_PPC64)
 /* --- PowerPC 64-bit --- */
 #define DUK_USE_ARCH_STRING "ppc64"
-#if !defined(DUK_USE_BYTEORDER)
-#define DUK_USE_BYTEORDER 3
-#endif
+/* No forced byteorder (both little and big endian are possible). */
 #undef DUK_USE_PACKED_TVAL
 #define DUK_F_PACKED_TVAL_PROVIDED
 #elif defined(DUK_F_SPARC32)
@@ -2917,6 +2915,8 @@
 #define DUK_USE_CACHE_CATCHER
 #define DUK_USE_CALLSTACK_LIMIT 10000
 #define DUK_USE_CBOR_BUILTIN
+#define DUK_USE_CBOR_DEC_RECLIMIT 1000
+#define DUK_USE_CBOR_ENC_RECLIMIT 1000
 #define DUK_USE_CBOR_SUPPORT
 #define DUK_USE_COMPILER_RECLIMIT 2500
 #define DUK_USE_COROUTINE_SUPPORT
diff --git a/duktape/duktape.c b/duktape/duktape.c
index 366883c..cd2f791 100644
--- a/duktape/duktape.c
+++ b/duktape/duktape.c
@@ -1,8 +1,8 @@
 /*
- *  Single source autogenerated distributable for Duktape 2.5.0.
+ *  Single source autogenerated distributable for Duktape 2.6.0.
  *
- *  Git commit 6001888049cb42656f8649db020e804bcdeca6a7 (v2.5.0).
- *  Git branch master.
+ *  Git commit fffa346eff06a8764b02c31d4336f63a773a95c3 (v2.6.0).
+ *  Git branch v2-maintenance.
  *
  *  See Duktape AUTHORS.rst and LICENSE.txt for copyright and
  *  licensing information.
@@ -525,7 +525,8 @@
 	} while (0)
 
 #define DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL(u)  do { \
-		if (DUK__DBLUNION_IS_NAN_NOTFULL((u))) { \
+		/* Check must be full. */ \
+		if (DUK__DBLUNION_IS_NAN_FULL((u))) { \
 			DUK__DBLUNION_SET_NAN_NOTFULL((u)); \
 		} \
 	} while (0)
@@ -537,12 +538,11 @@
  */
 
 #if defined(DUK_USE_PACKED_TVAL)
-#if defined(DUK_USE_FULL_TVAL)
 #define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u)  DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL((u))
 #define DUK_DBLUNION_IS_NAN(u)               DUK__DBLUNION_IS_NAN_FULL((u))
 #define DUK_DBLUNION_IS_NORMALIZED_NAN(u)    DUK__DBLUNION_IS_NORMALIZED_NAN_FULL((u))
 #define DUK_DBLUNION_SET_NAN(d)              DUK__DBLUNION_SET_NAN_FULL((d))
-#else
+#if 0
 #define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u)  DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL((u))
 #define DUK_DBLUNION_IS_NAN(u)               DUK__DBLUNION_IS_NAN_NOTFULL((u))
 #define DUK_DBLUNION_IS_NORMALIZED_NAN(u)    DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL((u))
@@ -3141,10 +3141,12 @@
 /* JSON */
 #define DUK_STR_FMT_PTR                          "%p"
 #define DUK_STR_FMT_INVALID_JSON                 "invalid json (at offset %ld)"
-#define DUK_STR_JSONDEC_RECLIMIT                 "json decode recursion limit"
-#define DUK_STR_JSONENC_RECLIMIT                 "json encode recursion limit"
 #define DUK_STR_CYCLIC_INPUT                     "cyclic input"
 
+/* Generic codec */
+#define DUK_STR_DEC_RECLIMIT                     "decode recursion limit"
+#define DUK_STR_ENC_RECLIMIT                     "encode recursion limit"
+
 /* Object property access */
 #define DUK_STR_INVALID_BASE                     "invalid base value"
 #define DUK_STR_STRICT_CALLER_READ               "cannot read strict 'caller'"
@@ -11289,14 +11291,14 @@
 137,194,70,46,142,68,165,19,236,1,64,174,187,161,95,37,134,204,23,225,35,
 23,71,34,82,137,246,128,160,89,93,208,167,147,195,201,194,70,46,142,68,165,
 19,238,1,64,182,187,161,71,105,20,19,177,139,163,145,41,68,16,7,6,15,82,70,
-72,115,96,0,0,0,0,0,2,234,32,91,60,165,195,201,194,8,134,149,216,162,0,192,
-41,225,8,2,48,177,36,1,149,13,196,15,0,200,209,97,199,128,99,32,176,195,
-192,113,57,143,0,167,133,32,230,80,28,202,139,175,238,2,48,189,192,20,1,
-119,80,87,193,186,129,89,56,72,197,209,200,193,185,35,23,71,109,13,219,36,
-98,232,237,156,13,26,208,211,14,102,19,87,137,91,95,128,0,10,96,24,92,0,0,
-83,2,53,56,0,0,165,3,28,204,160,160,226,100,226,200,211,76,241,240,0,1,102,
-8,22,75,64,137,73,20,230,105,133,7,19,39,22,70,154,103,143,128,0,11,48,20,
-28,76,156,113,75,34,78,62,0,0,45,3,103,31,0,0,22,65,44,57,137,62,33,179,
+72,115,96,0,0,0,0,0,15,106,32,91,60,165,195,201,194,8,134,149,216,162,0,
+192,41,225,8,2,48,177,36,1,149,13,196,15,0,200,209,97,199,128,99,32,176,
+195,192,113,57,143,0,167,133,32,230,80,28,202,139,175,238,2,48,189,192,20,
+1,119,80,87,193,186,129,89,56,72,197,209,200,193,185,35,23,71,109,13,219,
+36,98,232,237,156,13,26,208,211,14,102,19,87,137,91,95,128,0,10,96,24,92,0,
+0,83,2,53,56,0,0,165,3,28,204,160,160,226,100,226,200,211,76,241,240,0,1,
+102,8,22,75,64,137,73,20,230,105,133,7,19,39,22,70,154,103,143,128,0,11,48,
+20,28,76,156,113,75,34,78,62,0,0,45,3,103,31,0,0,22,65,44,57,137,62,33,179,
 216,162,152,192,131,18,124,162,27,61,138,41,108,32,196,159,16,217,232,235,
 81,76,104,73,137,62,81,13,158,142,181,20,184,16,98,79,136,108,244,244,168,
 166,56,36,196,159,40,134,207,79,74,138,93,10,49,39,194,173,192,158,158,149,
@@ -11489,7 +11491,7 @@
 137,194,70,46,142,68,165,19,236,1,64,174,187,161,95,37,134,204,23,225,35,
 23,71,34,82,137,246,128,160,89,93,208,167,147,195,201,194,70,46,142,68,165,
 19,238,1,64,182,187,161,71,105,20,19,177,139,163,145,41,68,16,7,6,15,82,70,
-72,115,96,32,106,2,128,0,0,0,0,91,60,165,195,201,194,8,134,149,216,162,0,
+72,115,96,32,106,15,0,0,0,0,0,91,60,165,195,201,194,8,134,149,216,162,0,
 192,41,225,8,2,48,177,36,1,149,13,196,15,0,200,209,97,199,128,99,32,176,
 195,192,113,57,143,0,167,133,32,230,80,28,202,139,175,238,2,48,189,192,20,
 1,119,80,87,193,186,129,89,56,72,197,209,200,193,185,35,23,71,109,13,219,
@@ -11689,14 +11691,14 @@
 137,194,70,46,142,68,165,19,236,1,64,174,187,161,95,37,134,204,23,225,35,
 23,71,34,82,137,246,128,160,89,93,208,167,147,195,201,194,70,46,142,68,165,
 19,238,1,64,182,187,161,71,105,20,19,177,139,163,145,41,68,16,7,6,15,82,70,
-72,115,96,0,2,234,32,0,0,0,0,91,60,165,195,201,194,8,134,149,216,162,0,192,
-41,225,8,2,48,177,36,1,149,13,196,15,0,200,209,97,199,128,99,32,176,195,
-192,113,57,143,0,167,133,32,230,80,28,202,139,175,238,2,48,189,192,20,1,
-119,80,87,193,186,129,89,56,72,197,209,200,193,185,35,23,71,109,13,219,36,
-98,232,237,156,13,26,208,211,14,102,19,87,137,91,95,128,0,10,96,24,92,0,0,
-83,2,53,56,0,0,165,3,28,204,160,160,226,100,226,200,211,76,241,240,0,1,102,
-8,22,75,64,137,73,20,230,105,133,7,19,39,22,70,154,103,143,128,0,11,48,20,
-28,76,156,113,75,34,78,62,0,0,45,3,103,31,0,0,22,65,44,57,137,62,33,179,
+72,115,96,0,15,106,32,0,0,0,0,91,60,165,195,201,194,8,134,149,216,162,0,
+192,41,225,8,2,48,177,36,1,149,13,196,15,0,200,209,97,199,128,99,32,176,
+195,192,113,57,143,0,167,133,32,230,80,28,202,139,175,238,2,48,189,192,20,
+1,119,80,87,193,186,129,89,56,72,197,209,200,193,185,35,23,71,109,13,219,
+36,98,232,237,156,13,26,208,211,14,102,19,87,137,91,95,128,0,10,96,24,92,0,
+0,83,2,53,56,0,0,165,3,28,204,160,160,226,100,226,200,211,76,241,240,0,1,
+102,8,22,75,64,137,73,20,230,105,133,7,19,39,22,70,154,103,143,128,0,11,48,
+20,28,76,156,113,75,34,78,62,0,0,45,3,103,31,0,0,22,65,44,57,137,62,33,179,
 216,162,152,192,131,18,124,162,27,61,138,41,108,32,196,159,16,217,232,235,
 81,76,104,73,137,62,81,13,158,142,181,20,184,16,98,79,136,108,244,244,168,
 166,56,36,196,159,40,134,207,79,74,138,93,10,49,39,194,173,192,158,158,149,
@@ -16443,6 +16445,7 @@
 	duk_ljstate lj;
 	duk_bool_t creating_error;
 	duk_hthread *curr_thread;
+	duk_uint8_t thread_state;
 	duk_int_t call_recursion_depth;
 };
 
@@ -16541,6 +16544,7 @@
 	duk_memcpy((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate));
 	snapshot->creating_error = heap->creating_error;
 	snapshot->curr_thread = heap->curr_thread;
+	snapshot->thread_state = thr->state;
 	snapshot->call_recursion_depth = heap->call_recursion_depth;
 
 	lj->jmpbuf_ptr = NULL;
@@ -16550,6 +16554,8 @@
 	heap->creating_error = 0;
 	heap->curr_thread = NULL;
 	heap->call_recursion_depth = 0;
+
+	thr->state = DUK_HTHREAD_STATE_INACTIVE;
 }
 
 DUK_EXTERNAL void duk_resume(duk_hthread *thr, const duk_thread_state *state) {
@@ -16566,6 +16572,8 @@
 	DUK_ASSERT(thr->heap->pf_prevent_count == 0);
 	DUK_ASSERT(thr->heap->creating_error == 0);
 
+	thr->state = snapshot->thread_state;
+
 	heap = thr->heap;
 
 	duk_memcpy((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate));
@@ -30090,6 +30098,8 @@
 	duk_uint8_t *buf_end;
 	duk_size_t len;
 	duk_idx_t idx_buf;
+	duk_uint_t recursion_depth;
+	duk_uint_t recursion_limit;
 } duk_cbor_encode_context;
 
 typedef struct {
@@ -30097,6 +30107,8 @@
 	const duk_uint8_t *buf;
 	duk_size_t off;
 	duk_size_t len;
+	duk_uint_t recursion_depth;
+	duk_uint_t recursion_limit;
 } duk_cbor_decode_context;
 
 DUK_LOCAL void duk__cbor_encode_value(duk_cbor_encode_context *enc_ctx);
@@ -30120,6 +30132,34 @@
 	(void) duk_type_error(enc_ctx->thr, "cbor encode error");
 }
 
+DUK_LOCAL void duk__cbor_encode_req_stack(duk_cbor_encode_context *enc_ctx) {
+	duk_require_stack(enc_ctx->thr, 4);
+}
+
+DUK_LOCAL void duk__cbor_encode_objarr_entry(duk_cbor_encode_context *enc_ctx) {
+	duk_hthread *thr = enc_ctx->thr;
+
+	/* Native stack check in object/array recursion. */
+	duk_native_stack_check(thr);
+
+	/* When working with deeply recursive structures, this is important
+	 * to ensure there's no effective depth limit.
+	 */
+	duk__cbor_encode_req_stack(enc_ctx);
+
+	DUK_ASSERT(enc_ctx->recursion_depth <= enc_ctx->recursion_limit);
+	if (enc_ctx->recursion_depth >= enc_ctx->recursion_limit) {
+		DUK_ERROR_RANGE(thr, DUK_STR_ENC_RECLIMIT);
+		DUK_WO_NORETURN(return;);
+	}
+	enc_ctx->recursion_depth++;
+}
+
+DUK_LOCAL void duk__cbor_encode_objarr_exit(duk_cbor_encode_context *enc_ctx) {
+	DUK_ASSERT(enc_ctx->recursion_depth > 0);
+	enc_ctx->recursion_depth--;
+}
+
 /* Check that a size_t is in uint32 range to avoid out-of-range casts. */
 DUK_LOCAL void duk__cbor_encode_sizet_uint32_check(duk_cbor_encode_context *enc_ctx, duk_size_t len) {
 	if (DUK_UNLIKELY(sizeof(duk_size_t) > sizeof(duk_uint32_t) && len > (duk_size_t) DUK_UINT32_MAX)) {
@@ -30522,6 +30562,8 @@
 	/* Caller must ensure space. */
 	DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8);
 
+	duk__cbor_encode_objarr_entry(enc_ctx);
+
 	/* XXX: Support for specific built-ins like Date and RegExp. */
 	if (duk_is_array(enc_ctx->thr, -1)) {
 		/* Shortest encoding for arrays >= 256 in length is actually
@@ -30546,7 +30588,7 @@
 		duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x40U);
 		duk__cbor_encode_ensure(enc_ctx, len);
 		p = enc_ctx->ptr;
-		duk_memcpy((void *) p, (const void *) buf, len);
+		duk_memcpy_unsafe((void *) p, (const void *) buf, len);
 		p += len;
 		enc_ctx->ptr = p;
 	} else {
@@ -30585,6 +30627,8 @@
 			enc_ctx->ptr = p;
 		}
 	}
+
+	duk__cbor_encode_objarr_exit(enc_ctx);
 }
 
 DUK_LOCAL void duk__cbor_encode_buffer(duk_cbor_encode_context *enc_ctx) {
@@ -30601,7 +30645,7 @@
 	duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x40U);
 	duk__cbor_encode_ensure(enc_ctx, len);
 	p = enc_ctx->ptr;
-	duk_memcpy((void *) p, (const void *) buf, len);
+	duk_memcpy_unsafe((void *) p, (const void *) buf, len);
 	p += len;
 	enc_ctx->ptr = p;
 }
@@ -30648,11 +30692,6 @@
 	 * This can be improved by registering custom tags with IANA.
 	 */
 
-	/* When working with deeply recursive structures, this is important
-	 * to ensure there's no effective depth limit.
-	 */
-	duk_require_stack(enc_ctx->thr, 4);
-
 	/* Reserve space for up to 64-bit types (1 initial byte + 8
 	 * followup bytes).  This allows encoding of integers, floats,
 	 * string/buffer length fields, etc without separate checks
@@ -30720,12 +30759,33 @@
  *  Decoding
  */
 
-DUK_LOCAL void duk__cbor_req_stack(duk_cbor_decode_context *dec_ctx) {
+DUK_LOCAL void duk__cbor_decode_error(duk_cbor_decode_context *dec_ctx) {
+	(void) duk_type_error(dec_ctx->thr, "cbor decode error");
+}
+
+DUK_LOCAL void duk__cbor_decode_req_stack(duk_cbor_decode_context *dec_ctx) {
 	duk_require_stack(dec_ctx->thr, 4);
 }
 
-DUK_LOCAL void duk__cbor_decode_error(duk_cbor_decode_context *dec_ctx) {
-	(void) duk_type_error(dec_ctx->thr, "cbor decode error");
+DUK_LOCAL void duk__cbor_decode_objarr_entry(duk_cbor_decode_context *dec_ctx) {
+	duk_hthread *thr = dec_ctx->thr;
+
+	/* Native stack check in object/array recursion. */
+	duk_native_stack_check(thr);
+
+	duk__cbor_decode_req_stack(dec_ctx);
+
+	DUK_ASSERT(dec_ctx->recursion_depth <= dec_ctx->recursion_limit);
+	if (dec_ctx->recursion_depth >= dec_ctx->recursion_limit) {
+		DUK_ERROR_RANGE(thr, DUK_STR_DEC_RECLIMIT);
+		DUK_WO_NORETURN(return;);
+	}
+	dec_ctx->recursion_depth++;
+}
+
+DUK_LOCAL void duk__cbor_decode_objarr_exit(duk_cbor_decode_context *dec_ctx) {
+	DUK_ASSERT(dec_ctx->recursion_depth > 0);
+	dec_ctx->recursion_depth--;
 }
 
 DUK_LOCAL duk_uint8_t duk__cbor_decode_readbyte(duk_cbor_decode_context *dec_ctx) {
@@ -31004,9 +31064,7 @@
 
 			buf_data = (duk_uint8_t *) duk_require_buffer(dec_ctx->thr, idx, &buf_size);
 			if (p != NULL) {
-				if (buf_size > 0U) {
-					duk_memcpy((void *) p, (const void *) buf_data, buf_size);
-				}
+				duk_memcpy_unsafe((void *) p, (const void *) buf_data, buf_size);
 				p += buf_size;
 			} else {
 				total_size += buf_size;
@@ -31171,7 +31229,7 @@
 DUK_LOCAL duk_bool_t duk__cbor_decode_array(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_uint8_t ai) {
 	duk_uint32_t idx, len;
 
-	duk__cbor_req_stack(dec_ctx);
+	duk__cbor_decode_objarr_entry(dec_ctx);
 
 	/* Support arrays up to 0xfffffffeU in length.  0xffffffff is
 	 * used as an indefinite length marker.
@@ -31181,7 +31239,7 @@
 	} else {
 		len = duk__cbor_decode_aival_uint32(dec_ctx, ib);
 		if (len == 0xffffffffUL) {
-			return 0;
+			goto failure;
 		}
 	}
 
@@ -31193,7 +31251,7 @@
 		}
 		if (idx == len) {
 			if (ai == 0x1fU) {
-				return 0;
+				goto failure;
 			}
 			break;
 		}
@@ -31201,24 +31259,32 @@
 		duk_put_prop_index(dec_ctx->thr, -2, (duk_uarridx_t) idx);
 		idx++;
 		if (idx == 0U) {
-			return 0;  /* wrapped */
+			goto failure;  /* wrapped */
 		}
 	}
 
+#if 0
+ success:
+#endif
+	duk__cbor_decode_objarr_exit(dec_ctx);
 	return 1;
+
+ failure:
+	/* No need to unwind recursion checks, caller will throw. */
+	return 0;
 }
 
 DUK_LOCAL duk_bool_t duk__cbor_decode_map(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_uint8_t ai) {
 	duk_uint32_t count;
 
-	duk__cbor_req_stack(dec_ctx);
+	duk__cbor_decode_objarr_entry(dec_ctx);
 
 	if (ai == 0x1fU) {
 		count = 0xffffffffUL;
 	} else {
 		count = duk__cbor_decode_aival_uint32(dec_ctx, ib);
 		if (count == 0xffffffffUL) {
-			return 0;
+			goto failure;
 		}
 	}
 
@@ -31249,7 +31315,15 @@
 		duk_put_prop(dec_ctx->thr, -3);
 	}
 
+#if 0
+ success:
+#endif
+	duk__cbor_decode_objarr_exit(dec_ctx);
 	return 1;
+
+ failure:
+	/* No need to unwind recursion checks, caller will throw. */
+	return 0;
 }
 
 DUK_LOCAL duk_double_t duk__cbor_decode_float(duk_cbor_decode_context *dec_ctx) {
@@ -31626,8 +31700,13 @@
 	enc_ctx.buf = buf;
 	enc_ctx.buf_end = buf + enc_ctx.len;
 
+	enc_ctx.recursion_depth = 0;
+	enc_ctx.recursion_limit = DUK_USE_CBOR_ENC_RECLIMIT;
+
 	duk_dup(thr, idx);
+	duk__cbor_encode_req_stack(&enc_ctx);
 	duk__cbor_encode_value(&enc_ctx);
+	DUK_ASSERT(enc_ctx.recursion_depth == 0);
 	duk_resize_buffer(enc_ctx.thr, enc_ctx.idx_buf, (duk_size_t) (enc_ctx.ptr - enc_ctx.buf));
 	duk_replace(thr, idx);
 }
@@ -31649,8 +31728,12 @@
 	dec_ctx.off = 0;
 	/* dec_ctx.len: set above */
 
-	duk__cbor_req_stack(&dec_ctx);
+	dec_ctx.recursion_depth = 0;
+	dec_ctx.recursion_limit = DUK_USE_CBOR_DEC_RECLIMIT;
+
+	duk__cbor_decode_req_stack(&dec_ctx);
 	duk__cbor_decode_value(&dec_ctx);
+	DUK_ASSERT(dec_ctx.recursion_depth == 0);
 	if (dec_ctx.off != dec_ctx.len) {
 		(void) duk_type_error(thr, "trailing garbage");
 	}
@@ -36373,28 +36456,28 @@
 #define DUK__JSON_STRINGIFY_BUFSIZE 128
 #define DUK__JSON_MAX_ESC_LEN 10  /* '\Udeadbeef' */
 
-DUK_LOCAL_DECL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL void duk__json_dec_syntax_error(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL void duk__json_dec_eat_white(duk_json_dec_ctx *js_ctx);
 #if defined(DUK_USE_JX)
-DUK_LOCAL_DECL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL duk_uint8_t duk__json_dec_peek(duk_json_dec_ctx *js_ctx);
 #endif
-DUK_LOCAL_DECL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n);
-DUK_LOCAL_DECL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx);
-DUK_LOCAL_DECL void duk__dec_string(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL duk_uint8_t duk__json_dec_get(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL duk_uint8_t duk__json_dec_get_nonwhite(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL duk_uint_fast32_t duk__json_dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n);
+DUK_LOCAL_DECL void duk__json_dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx);
+DUK_LOCAL_DECL void duk__json_dec_string(duk_json_dec_ctx *js_ctx);
 #if defined(DUK_USE_JX)
-DUK_LOCAL_DECL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_pointer(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_buffer(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL void duk__json_dec_plain_string(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL void duk__json_dec_pointer(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL void duk__json_dec_buffer(duk_json_dec_ctx *js_ctx);
 #endif
-DUK_LOCAL_DECL void duk__dec_number(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_object(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_array(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_value(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL void duk__json_dec_number(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL void duk__json_dec_objarr_entry(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL void duk__json_dec_objarr_exit(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL void duk__json_dec_object(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL void duk__json_dec_array(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL void duk__json_dec_value(duk_json_dec_ctx *js_ctx);
+DUK_LOCAL_DECL void duk__json_dec_reviver_walk(duk_json_dec_ctx *js_ctx);
 
 DUK_LOCAL_DECL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch);
 DUK_LOCAL_DECL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2);
@@ -36405,29 +36488,29 @@
 #endif
 DUK_LOCAL_DECL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx);
 DUK_LOCAL_DECL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q);
-DUK_LOCAL_DECL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k);
-DUK_LOCAL_DECL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str);
-DUK_LOCAL_DECL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
-DUK_LOCAL_DECL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
-DUK_LOCAL_DECL void duk__enc_object(duk_json_enc_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__enc_array(duk_json_enc_ctx *js_ctx);
-DUK_LOCAL_DECL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder);
-DUK_LOCAL_DECL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv);
-DUK_LOCAL_DECL void duk__enc_double(duk_json_enc_ctx *js_ctx);
+DUK_LOCAL_DECL void duk__json_enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k);
+DUK_LOCAL_DECL void duk__json_enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str);
+DUK_LOCAL_DECL void duk__json_enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
+DUK_LOCAL_DECL void duk__json_enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
+DUK_LOCAL_DECL void duk__json_enc_object(duk_json_enc_ctx *js_ctx);
+DUK_LOCAL_DECL void duk__json_enc_array(duk_json_enc_ctx *js_ctx);
+DUK_LOCAL_DECL duk_bool_t duk__json_enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder);
+DUK_LOCAL_DECL duk_bool_t duk__json_enc_allow_into_proplist(duk_tval *tv);
+DUK_LOCAL_DECL void duk__json_enc_double(duk_json_enc_ctx *js_ctx);
 #if defined(DUK_USE_FASTINT)
-DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv);
+DUK_LOCAL_DECL void duk__json_enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv);
 #endif
 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
-DUK_LOCAL_DECL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
-DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr);
+DUK_LOCAL_DECL void duk__json_enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
+DUK_LOCAL_DECL void duk__json_enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr);
 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_LOCAL_DECL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj);
+DUK_LOCAL_DECL void duk__json_enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj);
 #endif
 #endif
 #if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
-DUK_LOCAL_DECL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
+DUK_LOCAL_DECL void duk__json_enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
 #endif
-DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth);
+DUK_LOCAL_DECL void duk__json_enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth);
 
 /*
  *  Helper tables
@@ -36552,7 +36635,7 @@
  *  CESU-8 encodings.
  */
 
-DUK_LOCAL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx) {
+DUK_LOCAL void duk__json_dec_syntax_error(duk_json_dec_ctx *js_ctx) {
 	/* Shared handler to minimize parser size.  Cause will be
 	 * hidden, unfortunately, but we'll have an offset which
 	 * is often quite enough.
@@ -36562,7 +36645,7 @@
 	DUK_WO_NORETURN(return;);
 }
 
-DUK_LOCAL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx) {
+DUK_LOCAL void duk__json_dec_eat_white(duk_json_dec_ctx *js_ctx) {
 	const duk_uint8_t *p;
 	duk_uint8_t t;
 
@@ -36593,24 +36676,24 @@
 }
 
 #if defined(DUK_USE_JX)
-DUK_LOCAL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx) {
+DUK_LOCAL duk_uint8_t duk__json_dec_peek(duk_json_dec_ctx *js_ctx) {
 	DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
 	return *js_ctx->p;
 }
 #endif
 
-DUK_LOCAL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx) {
+DUK_LOCAL duk_uint8_t duk__json_dec_get(duk_json_dec_ctx *js_ctx) {
 	DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
 	return *js_ctx->p++;
 }
 
-DUK_LOCAL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx) {
-	duk__dec_eat_white(js_ctx);
-	return duk__dec_get(js_ctx);
+DUK_LOCAL duk_uint8_t duk__json_dec_get_nonwhite(duk_json_dec_ctx *js_ctx) {
+	duk__json_dec_eat_white(js_ctx);
+	return duk__json_dec_get(js_ctx);
 }
 
 /* For JX, expressing the whole unsigned 32-bit range matters. */
-DUK_LOCAL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n) {
+DUK_LOCAL duk_uint_fast32_t duk__json_dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n) {
 	duk_small_uint_t i;
 	duk_uint_fast32_t res = 0;
 	duk_uint8_t x;
@@ -36619,7 +36702,7 @@
 	for (i = 0; i < n; i++) {
 		/* XXX: share helper from lexer; duk_lexer.c / hexval(). */
 
-		x = duk__dec_get(js_ctx);
+		x = duk__json_dec_get(js_ctx);
 		DUK_DDD(DUK_DDDPRINT("decode_hex_escape: i=%ld, n=%ld, res=%ld, x=%ld",
 		                     (long) i, (long) n, (long) res, (long) x));
 
@@ -36638,12 +36721,12 @@
 	return res;
 
  syntax_error:
-	duk__dec_syntax_error(js_ctx);
+	duk__json_dec_syntax_error(js_ctx);
 	DUK_UNREACHABLE();
 	return 0;
 }
 
-DUK_LOCAL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx) {
+DUK_LOCAL void duk__json_dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx) {
 	duk_hstring *h;
 	const duk_uint8_t *p;
 	duk_uint8_t x, y;
@@ -36665,7 +36748,7 @@
 		if (x == 0) {
 			break;
 		}
-		y = duk__dec_get(js_ctx);
+		y = duk__json_dec_get(js_ctx);
 		if (x != y) {
 			/* Catches EOF of JSON input. */
 			goto syntax_error;
@@ -36676,18 +36759,18 @@
 	return;
 
  syntax_error:
-	duk__dec_syntax_error(js_ctx);
+	duk__json_dec_syntax_error(js_ctx);
 	DUK_UNREACHABLE();
 }
 
-DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_uint8_t **ext_p) {
+DUK_LOCAL duk_small_int_t duk__json_dec_string_escape(duk_json_dec_ctx *js_ctx, duk_uint8_t **ext_p) {
 	duk_uint_fast32_t cp;
 
 	/* EOF (-1) will be cast to an unsigned value first
 	 * and then re-cast for the switch.  In any case, it
 	 * will match the default case (syntax error).
 	 */
-	cp = (duk_uint_fast32_t) duk__dec_get(js_ctx);
+	cp = (duk_uint_fast32_t) duk__json_dec_get(js_ctx);
 	switch (cp) {
 	case DUK_ASC_BACKSLASH: break;
 	case DUK_ASC_DOUBLEQUOTE: break;
@@ -36698,13 +36781,13 @@
 	case DUK_ASC_LC_F: cp = 0x0c; break;
 	case DUK_ASC_LC_B: cp = 0x08; break;
 	case DUK_ASC_LC_U: {
-		cp = duk__dec_decode_hex_escape(js_ctx, 4);
+		cp = duk__json_dec_decode_hex_escape(js_ctx, 4);
 		break;
 	}
 #if defined(DUK_USE_JX)
 	case DUK_ASC_UC_U: {
 		if (js_ctx->flag_ext_custom) {
-			cp = duk__dec_decode_hex_escape(js_ctx, 8);
+			cp = duk__json_dec_decode_hex_escape(js_ctx, 8);
 		} else {
 			return 1;  /* syntax error */
 		}
@@ -36712,7 +36795,7 @@
 	}
 	case DUK_ASC_LC_X: {
 		if (js_ctx->flag_ext_custom) {
-			cp = duk__dec_decode_hex_escape(js_ctx, 2);
+			cp = duk__json_dec_decode_hex_escape(js_ctx, 2);
 		} else {
 			return 1;  /* syntax error */
 		}
@@ -36729,7 +36812,7 @@
 	return 0;
 }
 
-DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) {
+DUK_LOCAL void duk__json_dec_string(duk_json_dec_ctx *js_ctx) {
 	duk_hthread *thr = js_ctx->thr;
 	duk_bufwriter_ctx bw_alloc;
 	duk_bufwriter_ctx *bw;
@@ -36788,7 +36871,7 @@
 				 * quite slow but it's uncommon).
 				 */
 				js_ctx->p = p;
-				if (duk__dec_string_escape(js_ctx, &q) != 0) {
+				if (duk__json_dec_string_escape(js_ctx, &q) != 0) {
 					goto syntax_error;
 				}
 				break;
@@ -36805,12 +36888,12 @@
 
 		q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, DUK_UNICODE_MAX_XUTF8_LENGTH, q);
 
-		x = duk__dec_get(js_ctx);
+		x = duk__json_dec_get(js_ctx);
 
 		if (x == DUK_ASC_DOUBLEQUOTE) {
 			break;
 		} else if (x == DUK_ASC_BACKSLASH) {
-			if (duk__dec_string_escape(js_ctx, &q) != 0) {
+			if (duk__json_dec_string_escape(js_ctx, &q) != 0) {
 				goto syntax_error;
 			}
 		} else if (x < 0x20) {
@@ -36830,7 +36913,7 @@
 	return;
 
  syntax_error:
-	duk__dec_syntax_error(js_ctx);
+	duk__json_dec_syntax_error(js_ctx);
 	DUK_UNREACHABLE();
 }
 
@@ -36838,7 +36921,7 @@
 /* Decode a plain string consisting entirely of identifier characters.
  * Used to parse plain keys (e.g. "foo: 123").
  */
-DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) {
+DUK_LOCAL void duk__json_dec_plain_string(duk_json_dec_ctx *js_ctx) {
 	duk_hthread *thr = js_ctx->thr;
 	const duk_uint8_t *p;
 	duk_small_int_t x;
@@ -36880,7 +36963,7 @@
 #endif  /* DUK_USE_JX */
 
 #if defined(DUK_USE_JX)
-DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
+DUK_LOCAL void duk__json_dec_pointer(duk_json_dec_ctx *js_ctx) {
 	duk_hthread *thr = js_ctx->thr;
 	const duk_uint8_t *p;
 	duk_small_int_t x;
@@ -36927,13 +37010,13 @@
 	return;
 
  syntax_error:
-	duk__dec_syntax_error(js_ctx);
+	duk__json_dec_syntax_error(js_ctx);
 	DUK_UNREACHABLE();
 }
 #endif  /* DUK_USE_JX */
 
 #if defined(DUK_USE_JX)
-DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
+DUK_LOCAL void duk__json_dec_buffer(duk_json_dec_ctx *js_ctx) {
 	duk_hthread *thr = js_ctx->thr;
 	const duk_uint8_t *p;
 	duk_uint8_t *buf;
@@ -36985,13 +37068,13 @@
 	return;
 
  syntax_error:
-	duk__dec_syntax_error(js_ctx);
+	duk__json_dec_syntax_error(js_ctx);
 	DUK_UNREACHABLE();
 }
 #endif  /* DUK_USE_JX */
 
 /* Parse a number, other than NaN or +/- Infinity */
-DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) {
+DUK_LOCAL void duk__json_dec_number(duk_json_dec_ctx *js_ctx) {
 	duk_hthread *thr = js_ctx->thr;
 	const duk_uint8_t *p_start;
 	const duk_uint8_t *p;
@@ -37047,7 +37130,7 @@
 	                     (duk_tval *) duk_get_tval(thr, -1)));
 	duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
 	if (duk_is_nan(thr, -1)) {
-		duk__dec_syntax_error(js_ctx);
+		duk__json_dec_syntax_error(js_ctx);
 	}
 	DUK_ASSERT(duk_is_number(thr, -1));
 	DUK_DDD(DUK_DDDPRINT("parse_number: final number: %!T",
@@ -37056,22 +37139,24 @@
 	/* [ ... num ] */
 }
 
-DUK_LOCAL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx) {
+DUK_LOCAL void duk__json_dec_objarr_entry(duk_json_dec_ctx *js_ctx) {
 	duk_hthread *thr = js_ctx->thr;
 	duk_require_stack(thr, DUK_JSON_DEC_REQSTACK);
 
 	/* c recursion check */
 
+	duk_native_stack_check(thr);
+
 	DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0);  /* unsigned */
 	DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
 	if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
-		DUK_ERROR_RANGE(thr, DUK_STR_JSONDEC_RECLIMIT);
+		DUK_ERROR_RANGE(thr, DUK_STR_DEC_RECLIMIT);
 		DUK_WO_NORETURN(return;);
 	}
 	js_ctx->recursion_depth++;
 }
 
-DUK_LOCAL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx) {
+DUK_LOCAL void duk__json_dec_objarr_exit(duk_json_dec_ctx *js_ctx) {
 	/* c recursion check */
 
 	DUK_ASSERT(js_ctx->recursion_depth > 0);
@@ -37079,14 +37164,14 @@
 	js_ctx->recursion_depth--;
 }
 
-DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
+DUK_LOCAL void duk__json_dec_object(duk_json_dec_ctx *js_ctx) {
 	duk_hthread *thr = js_ctx->thr;
 	duk_int_t key_count;  /* XXX: a "first" flag would suffice */
 	duk_uint8_t x;
 
 	DUK_DDD(DUK_DDDPRINT("parse_object"));
 
-	duk__dec_objarr_entry(js_ctx);
+	duk__json_dec_objarr_entry(js_ctx);
 
 	duk_push_object(thr);
 
@@ -37094,7 +37179,7 @@
 
 	key_count = 0;
 	for (;;) {
-		x = duk__dec_get_nonwhite(js_ctx);
+		x = duk__json_dec_get_nonwhite(js_ctx);
 
 		DUK_DDD(DUK_DDDPRINT("parse_object: obj=%!T, x=%ld, key_count=%ld",
 		                     (duk_tval *) duk_get_tval(thr, -1),
@@ -37104,7 +37189,7 @@
 
 		if (x == DUK_ASC_COMMA && key_count > 0) {
 			/* accept comma, expect new value */
-			x = duk__dec_get_nonwhite(js_ctx);
+			x = duk__json_dec_get_nonwhite(js_ctx);
 		} else if (x == DUK_ASC_RCURLY) {
 			/* eat closing brace */
 			break;
@@ -37121,11 +37206,11 @@
 		/* parse key and value */
 
 		if (x == DUK_ASC_DOUBLEQUOTE) {
-			duk__dec_string(js_ctx);
+			duk__json_dec_string(js_ctx);
 #if defined(DUK_USE_JX)
 		} else if (js_ctx->flag_ext_custom &&
 		           duk_unicode_is_identifier_start((duk_codepoint_t) x)) {
-			duk__dec_plain_string(js_ctx);
+			duk__json_dec_plain_string(js_ctx);
 #endif
 		} else {
 			goto syntax_error;
@@ -37133,12 +37218,12 @@
 
 		/* [ ... obj key ] */
 
-		x = duk__dec_get_nonwhite(js_ctx);
+		x = duk__json_dec_get_nonwhite(js_ctx);
 		if (x != DUK_ASC_COLON) {
 			goto syntax_error;
 		}
 
-		duk__dec_value(js_ctx);
+		duk__json_dec_value(js_ctx);
 
 		/* [ ... obj key val ] */
 
@@ -37154,22 +37239,22 @@
 	DUK_DDD(DUK_DDDPRINT("parse_object: final object is %!T",
 	                     (duk_tval *) duk_get_tval(thr, -1)));
 
-	duk__dec_objarr_exit(js_ctx);
+	duk__json_dec_objarr_exit(js_ctx);
 	return;
 
  syntax_error:
-	duk__dec_syntax_error(js_ctx);
+	duk__json_dec_syntax_error(js_ctx);
 	DUK_UNREACHABLE();
 }
 
-DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
+DUK_LOCAL void duk__json_dec_array(duk_json_dec_ctx *js_ctx) {
 	duk_hthread *thr = js_ctx->thr;
 	duk_uarridx_t arr_idx;
 	duk_uint8_t x;
 
 	DUK_DDD(DUK_DDDPRINT("parse_array"));
 
-	duk__dec_objarr_entry(js_ctx);
+	duk__json_dec_objarr_entry(js_ctx);
 
 	duk_push_array(thr);
 
@@ -37177,7 +37262,7 @@
 
 	arr_idx = 0;
 	for (;;) {
-		x = duk__dec_get_nonwhite(js_ctx);
+		x = duk__json_dec_get_nonwhite(js_ctx);
 
 		DUK_DDD(DUK_DDDPRINT("parse_array: arr=%!T, x=%ld, arr_idx=%ld",
 		                     (duk_tval *) duk_get_tval(thr, -1),
@@ -37193,7 +37278,7 @@
 			break;
 		} else if (arr_idx == 0) {
 			/* accept anything, expect first value (EOF will be
-			 * caught by duk__dec_value() below.
+			 * caught by duk__json_dec_value() below.
 			 */
 			js_ctx->p--;  /* backtrack (safe) */
 		} else {
@@ -37203,7 +37288,7 @@
 
 		/* parse value */
 
-		duk__dec_value(js_ctx);
+		duk__json_dec_value(js_ctx);
 
 		/* [ ... arr val ] */
 
@@ -37222,30 +37307,30 @@
 	DUK_DDD(DUK_DDDPRINT("parse_array: final array is %!T",
 	                     (duk_tval *) duk_get_tval(thr, -1)));
 
-	duk__dec_objarr_exit(js_ctx);
+	duk__json_dec_objarr_exit(js_ctx);
 	return;
 
  syntax_error:
-	duk__dec_syntax_error(js_ctx);
+	duk__json_dec_syntax_error(js_ctx);
 	DUK_UNREACHABLE();
 }
 
-DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
+DUK_LOCAL void duk__json_dec_value(duk_json_dec_ctx *js_ctx) {
 	duk_hthread *thr = js_ctx->thr;
 	duk_uint8_t x;
 
-	x = duk__dec_get_nonwhite(js_ctx);
+	x = duk__json_dec_get_nonwhite(js_ctx);
 
 	DUK_DDD(DUK_DDDPRINT("parse_value: initial x=%ld", (long) x));
 
-	/* Note: duk__dec_req_stridx() backtracks one char */
+	/* Note: duk__json_dec_req_stridx() backtracks one char */
 
 	if (x == DUK_ASC_DOUBLEQUOTE) {
-		duk__dec_string(js_ctx);
+		duk__json_dec_string(js_ctx);
 	} else if ((x >= DUK_ASC_0 && x <= DUK_ASC_9) || (x == DUK_ASC_MINUS)) {
 #if defined(DUK_USE_JX)
-		if (js_ctx->flag_ext_custom && x == DUK_ASC_MINUS && duk__dec_peek(js_ctx) == DUK_ASC_UC_I) {
-			duk__dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY);  /* "-Infinity", '-' has been eaten */
+		if (js_ctx->flag_ext_custom && x == DUK_ASC_MINUS && duk__json_dec_peek(js_ctx) == DUK_ASC_UC_I) {
+			duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY);  /* "-Infinity", '-' has been eaten */
 			duk_push_number(thr, -DUK_DOUBLE_INFINITY);
 		} else {
 #else
@@ -37253,60 +37338,63 @@
 #endif
 			/* We already ate 'x', so backup one byte. */
 			js_ctx->p--;  /* safe */
-			duk__dec_number(js_ctx);
+			duk__json_dec_number(js_ctx);
 		}
 	} else if (x == DUK_ASC_LC_T) {
-		duk__dec_req_stridx(js_ctx, DUK_STRIDX_TRUE);
+		duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_TRUE);
 		duk_push_true(thr);
 	} else if (x == DUK_ASC_LC_F) {
-		duk__dec_req_stridx(js_ctx, DUK_STRIDX_FALSE);
+		duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_FALSE);
 		duk_push_false(thr);
 	} else if (x == DUK_ASC_LC_N) {
-		duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_NULL);
+		duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_LC_NULL);
 		duk_push_null(thr);
 #if defined(DUK_USE_JX)
 	} else if (js_ctx->flag_ext_custom && x == DUK_ASC_LC_U) {
-		duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_UNDEFINED);
+		duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_LC_UNDEFINED);
 		duk_push_undefined(thr);
 	} else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_N) {
-		duk__dec_req_stridx(js_ctx, DUK_STRIDX_NAN);
+		duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_NAN);
 		duk_push_nan(thr);
 	} else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_I) {
-		duk__dec_req_stridx(js_ctx, DUK_STRIDX_INFINITY);
+		duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_INFINITY);
 		duk_push_number(thr, DUK_DOUBLE_INFINITY);
 	} else if (js_ctx->flag_ext_custom && x == DUK_ASC_LPAREN) {
-		duk__dec_pointer(js_ctx);
+		duk__json_dec_pointer(js_ctx);
 	} else if (js_ctx->flag_ext_custom && x == DUK_ASC_PIPE) {
-		duk__dec_buffer(js_ctx);
+		duk__json_dec_buffer(js_ctx);
 #endif
 	} else if (x == DUK_ASC_LCURLY) {
-		duk__dec_object(js_ctx);
+		duk__json_dec_object(js_ctx);
 	} else if (x == DUK_ASC_LBRACKET) {
-		duk__dec_array(js_ctx);
+		duk__json_dec_array(js_ctx);
 	} else {
 		/* catches EOF (NUL) */
 		goto syntax_error;
 	}
 
-	duk__dec_eat_white(js_ctx);
+	duk__json_dec_eat_white(js_ctx);
 
 	/* [ ... val ] */
 	return;
 
  syntax_error:
-	duk__dec_syntax_error(js_ctx);
+	duk__json_dec_syntax_error(js_ctx);
 	DUK_UNREACHABLE();
 }
 
-/* Recursive value reviver, implements the Walk() algorithm.  No C recursion
- * check is done here because the initial parsing step will already ensure
- * there is a reasonable limit on C recursion depth and hence object depth.
+/* Recursive value reviver, implements the Walk() algorithm.  The parsing
+ * step ensures there is a reasonable depth limit to the input.  However,
+ * the reviver may create more depth by editing object or array entries, so
+ * we have both C recursion limit and native stack checks here.
  */
-DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) {
+DUK_LOCAL void duk__json_dec_reviver_walk(duk_json_dec_ctx *js_ctx) {
 	duk_hthread *thr = js_ctx->thr;
 	duk_hobject *h;
 	duk_uarridx_t i, arr_len;
 
+	duk__json_dec_objarr_entry(js_ctx);
+
 	DUK_DDD(DUK_DDDPRINT("walk: top=%ld, holder=%!T, name=%!T",
 	                     (long) duk_get_top(thr),
 	                     (duk_tval *) duk_get_tval(thr, -2),
@@ -37329,7 +37417,7 @@
 
 				duk_dup_top(thr);
 				(void) duk_push_uint_to_hstring(thr, (duk_uint_t) i);  /* -> [ ... holder name val val ToString(i) ] */
-				duk__dec_reviver_walk(js_ctx);  /* -> [ ... holder name val new_elem ] */
+				duk__json_dec_reviver_walk(js_ctx);  /* -> [ ... holder name val new_elem ] */
 
 				if (duk_is_undefined(thr, -1)) {
 					duk_pop(thr);
@@ -37356,7 +37444,7 @@
 				duk_dup_m2(thr);
 
 				/* [ ... holder name val enum obj_key val obj_key ] */
-				duk__dec_reviver_walk(js_ctx);
+				duk__json_dec_reviver_walk(js_ctx);
 
 				/* [ ... holder name val enum obj_key new_elem ] */
 				if (duk_is_undefined(thr, -1)) {
@@ -37385,6 +37473,8 @@
 	duk_insert(thr, -4);  /* -> [ ... reviver holder name val ] */
 	duk_call_method(thr, 2);  /* -> [ ... res ] */
 
+	duk__json_dec_objarr_exit(js_ctx);
+
 	DUK_DDD(DUK_DDDPRINT("walk: top=%ld, result=%!T",
 	                     (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, -1)));
 }
@@ -37494,7 +37584,7 @@
 	return q;
 }
 
-DUK_LOCAL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k) {
+DUK_LOCAL void duk__json_enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k) {
 	const duk_int8_t *p, *p_start, *p_end;  /* Note: intentionally signed. */
 	duk_size_t k_len;
 	duk_codepoint_t cp;
@@ -37537,7 +37627,7 @@
 	}
 
  quote_normally:
-	duk__enc_quote_string(js_ctx, k);
+	duk__json_enc_quote_string(js_ctx, k);
 }
 
 /* The Quote(value) operation: quote a string.
@@ -37545,13 +37635,13 @@
  * Stack policy: [ ] -> [ ].
  */
 
-DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str) {
+DUK_LOCAL void duk__json_enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str) {
 	duk_hthread *thr = js_ctx->thr;
 	const duk_uint8_t *p, *p_start, *p_end, *p_now, *p_tmp;
 	duk_uint8_t *q;
 	duk_ucodepoint_t cp;  /* typed for duk_unicode_decode_xutf8() */
 
-	DUK_DDD(DUK_DDDPRINT("duk__enc_quote_string: h_str=%!O", (duk_heaphdr *) h_str));
+	DUK_DDD(DUK_DDDPRINT("duk__json_enc_quote_string: h_str=%!O", (duk_heaphdr *) h_str));
 
 	DUK_ASSERT(h_str != NULL);
 	p_start = DUK_HSTRING_GET_DATA(h_str);
@@ -37682,7 +37772,7 @@
 /* Encode a double (checked by caller) from stack top.  Stack top may be
  * replaced by serialized string but is not popped (caller does that).
  */
-DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
+DUK_LOCAL void duk__json_enc_double(duk_json_enc_ctx *js_ctx) {
 	duk_hthread *thr;
 	duk_tval *tv;
 	duk_double_t d;
@@ -37746,7 +37836,7 @@
 
 #if defined(DUK_USE_FASTINT)
 /* Encode a fastint from duk_tval ptr, no value stack effects. */
-DUK_LOCAL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv) {
+DUK_LOCAL void duk__json_enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv) {
 	duk_int64_t v;
 
 	/* Fastint range is signed 48-bit so longest value is -2^47 = -140737488355328
@@ -37771,7 +37861,7 @@
 
 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
 #if defined(DUK_USE_HEX_FASTPATH)
-DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
+DUK_LOCAL duk_uint8_t *duk__json_enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
 	duk_uint8_t *q;
 	duk_uint16_t *q16;
 	duk_small_uint_t x;
@@ -37829,7 +37919,7 @@
 	return q;
 }
 #else  /* DUK_USE_HEX_FASTPATH */
-DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
+DUK_LOCAL duk_uint8_t *duk__json_enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
 	const duk_uint8_t *p;
 	const duk_uint8_t *p_end;
 	duk_uint8_t *q;
@@ -37848,7 +37938,7 @@
 }
 #endif  /* DUK_USE_HEX_FASTPATH */
 
-DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_data, duk_size_t buf_len) {
+DUK_LOCAL void duk__json_enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_data, duk_size_t buf_len) {
 	duk_hthread *thr;
 	duk_uint8_t *q;
 	duk_size_t space;
@@ -37880,7 +37970,7 @@
 #if defined(DUK_USE_JX)
 	{
 		*q++ = DUK_ASC_PIPE;
-		q = duk__enc_buffer_data_hex(buf_data, buf_len, q);
+		q = duk__json_enc_buffer_data_hex(buf_data, buf_len, q);
 		*q++ = DUK_ASC_PIPE;
 
 	}
@@ -37893,7 +37983,7 @@
 		DUK_ASSERT(js_ctx->flag_ext_compatible);
 		duk_memcpy((void *) q, (const void *) "{\"_buf\":\"", 9);  /* len: 9 */
 		q += 9;
-		q = duk__enc_buffer_data_hex(buf_data, buf_len, q);
+		q = duk__json_enc_buffer_data_hex(buf_data, buf_len, q);
 		*q++ = DUK_ASC_DOUBLEQUOTE;
 		*q++ = DUK_ASC_RCURLY;
 	}
@@ -37902,15 +37992,15 @@
 	DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
 }
 
-DUK_LOCAL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
-	duk__enc_buffer_data(js_ctx,
+DUK_LOCAL void duk__json_enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
+	duk__json_enc_buffer_data(js_ctx,
 	                     (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h),
 	                     (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
 }
 #endif  /* DUK_USE_JX || DUK_USE_JC */
 
 #if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
-DUK_LOCAL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
+DUK_LOCAL void duk__json_enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
 	duk_size_t i, n;
 	const duk_uint8_t *buf;
 	duk_uint8_t *q;
@@ -37934,7 +38024,7 @@
 	buf = (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h);
 	if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
 		for (i = 0; i < n; i++) {
-			duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth + 1);
+			duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth + 1);
 			q = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, 32);
 			q += DUK_SPRINTF((char *) q, "\"%lu\": %u,", (unsigned long) i, (unsigned int) buf[i]);
 			DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q);
@@ -37950,14 +38040,14 @@
 	DUK__UNEMIT_1(js_ctx);  /* eat trailing comma */
 
 	if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
-		duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
+		duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth);
 	}
 	DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
 }
 #endif  /* DUK_USE_JSON_STRINGIFY_FASTPATH */
 
 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
-DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
+DUK_LOCAL void duk__json_enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
 	char buf[64];  /* XXX: how to figure correct size? */
 	const char *fmt;
 
@@ -37995,14 +38085,14 @@
 
 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
-DUK_LOCAL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj) {
+DUK_LOCAL void duk__json_enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj) {
 	DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
 
 	if (h_bufobj->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
 		DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
 	} else {
 		/* Handle both full and partial slice (as long as covered). */
-		duk__enc_buffer_data(js_ctx,
+		duk__json_enc_buffer_data(js_ctx,
 		                     (duk_uint8_t *) DUK_HBUFOBJ_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj),
 		                     (duk_size_t) h_bufobj->length);
 	}
@@ -38014,7 +38104,7 @@
  * directly related to indent depth.
  */
 #if defined(DUK_USE_PREFER_SIZE)
-DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) {
+DUK_LOCAL void duk__json_enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) {
 	DUK_ASSERT(js_ctx->h_gap != NULL);
 	DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0);  /* caller guarantees */
 
@@ -38024,7 +38114,7 @@
 	}
 }
 #else  /* DUK_USE_PREFER_SIZE */
-DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) {
+DUK_LOCAL void duk__json_enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) {
 	const duk_uint8_t *gap_data;
 	duk_size_t gap_len;
 	duk_size_t avail_bytes;   /* bytes of indent available for copying */
@@ -38077,13 +38167,14 @@
 #endif  /* DUK_USE_PREFER_SIZE */
 
 /* Shared entry handling for object/array serialization. */
-DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
+DUK_LOCAL void duk__json_enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
 	duk_hthread *thr = js_ctx->thr;
 	duk_hobject *h_target;
 	duk_uint_fast32_t i, n;
 
 	*entry_top = duk_get_top(thr);
 
+	duk_native_stack_check(thr);
 	duk_require_stack(thr, DUK_JSON_ENC_REQSTACK);
 
 	/* Loop check using a hybrid approach: a fixed-size visited[] array
@@ -38121,7 +38212,7 @@
 	DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0);  /* unsigned */
 	DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
 	if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
-		DUK_ERROR_RANGE(thr, DUK_STR_JSONENC_RECLIMIT);
+		DUK_ERROR_RANGE(thr, DUK_STR_ENC_RECLIMIT);
 		DUK_WO_NORETURN(return;);
 	}
 	js_ctx->recursion_depth++;
@@ -38131,7 +38222,7 @@
 }
 
 /* Shared exit handling for object/array serialization. */
-DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
+DUK_LOCAL void duk__json_enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
 	duk_hthread *thr = js_ctx->thr;
 	duk_hobject *h_target;
 
@@ -38163,7 +38254,7 @@
  *
  * Stack policy: [ object ] -> [ object ].
  */
-DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
+DUK_LOCAL void duk__json_enc_object(duk_json_enc_ctx *js_ctx) {
 	duk_hthread *thr = js_ctx->thr;
 	duk_hstring *h_key;
 	duk_idx_t entry_top;
@@ -38173,9 +38264,9 @@
 	duk_uarridx_t arr_len, i;
 	duk_size_t prev_size;
 
-	DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(thr, -1)));
+	DUK_DDD(DUK_DDDPRINT("duk__json_enc_object: obj=%!T", (duk_tval *) duk_get_tval(thr, -1)));
 
-	duk__enc_objarr_entry(js_ctx, &entry_top);
+	duk__json_enc_objarr_entry(js_ctx, &entry_top);
 
 	idx_obj = entry_top - 1;
 
@@ -38217,17 +38308,17 @@
 
 		prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
 		if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
-			duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
-			duk__enc_key_autoquote(js_ctx, h_key);
+			duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth);
+			duk__json_enc_key_autoquote(js_ctx, h_key);
 			DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
 		} else {
-			duk__enc_key_autoquote(js_ctx, h_key);
+			duk__json_enc_key_autoquote(js_ctx, h_key);
 			DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
 		}
 
 		/* [ ... key ] */
 
-		if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_obj) == 0)) {
+		if (DUK_UNLIKELY(duk__json_enc_value(js_ctx, idx_obj) == 0)) {
 			/* Value would yield 'undefined', so skip key altogether.
 			 * Side effects have already happened.
 			 */
@@ -38245,12 +38336,12 @@
 		DUK__UNEMIT_1(js_ctx);  /* eat trailing comma */
 		if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
 			DUK_ASSERT(js_ctx->recursion_depth >= 1);
-			duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
+			duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
 		}
 	}
 	DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
 
-	duk__enc_objarr_exit(js_ctx, &entry_top);
+	duk__json_enc_objarr_exit(js_ctx, &entry_top);
 
 	DUK_ASSERT_TOP(thr, entry_top);
 }
@@ -38259,17 +38350,17 @@
  *
  * Stack policy: [ array ] -> [ array ].
  */
-DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
+DUK_LOCAL void duk__json_enc_array(duk_json_enc_ctx *js_ctx) {
 	duk_hthread *thr = js_ctx->thr;
 	duk_idx_t entry_top;
 	duk_idx_t idx_arr;
 	duk_bool_t emitted;
 	duk_uarridx_t i, arr_len;
 
-	DUK_DDD(DUK_DDDPRINT("duk__enc_array: array=%!T",
+	DUK_DDD(DUK_DDDPRINT("duk__json_enc_array: array=%!T",
 	                     (duk_tval *) duk_get_tval(thr, -1)));
 
-	duk__enc_objarr_entry(js_ctx, &entry_top);
+	duk__json_enc_objarr_entry(js_ctx, &entry_top);
 
 	idx_arr = entry_top - 1;
 
@@ -38286,14 +38377,14 @@
 
 		if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
 			DUK_ASSERT(js_ctx->recursion_depth >= 1);
-			duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
+			duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth);
 		}
 
 		(void) duk_push_uint_to_hstring(thr, (duk_uint_t) i);  /* -> [ ... key ] */
 
 		/* [ ... key ] */
 
-		if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_arr) == 0)) {
+		if (DUK_UNLIKELY(duk__json_enc_value(js_ctx, idx_arr) == 0)) {
 			/* Value would normally be omitted, replace with 'null'. */
 			DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
 		} else {
@@ -38311,12 +38402,12 @@
 		DUK__UNEMIT_1(js_ctx);  /* eat trailing comma */
 		if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
 			DUK_ASSERT(js_ctx->recursion_depth >= 1);
-			duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
+			duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
 		}
 	}
 	DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
 
-	duk__enc_objarr_exit(js_ctx, &entry_top);
+	duk__json_enc_objarr_exit(js_ctx, &entry_top);
 
 	DUK_ASSERT_TOP(thr, entry_top);
 }
@@ -38325,14 +38416,14 @@
  *
  * Stack policy: [ ... key ] -> [ ... ]
  */
-DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder) {
+DUK_LOCAL duk_bool_t duk__json_enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder) {
 	duk_hthread *thr = js_ctx->thr;
 	duk_tval *tv;
 	duk_tval *tv_holder;
 	duk_tval *tv_key;
 	duk_small_int_t c;
 
-	DUK_DDD(DUK_DDDPRINT("duk__enc_value: idx_holder=%ld, holder=%!T, key=%!T",
+	DUK_DDD(DUK_DDDPRINT("duk__json_enc_value: idx_holder=%ld, holder=%!T, key=%!T",
 	                     (long) idx_holder, (duk_tval *) duk_get_tval(thr, idx_holder),
 	                     (duk_tval *) duk_get_tval(thr, -1)));
 
@@ -38402,7 +38493,7 @@
 			duk_hbufobj *h_bufobj;
 			h_bufobj = (duk_hbufobj *) h;
 			DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
-			duk__enc_bufobj(js_ctx, h_bufobj);
+			duk__json_enc_bufobj(js_ctx, h_bufobj);
 			goto pop2_emitted;
 		}
 		/* Otherwise bufferobjects get serialized as normal objects. */
@@ -38498,7 +38589,7 @@
 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
 	/* When JX/JC not in use, the type mask above will avoid this case if needed. */
 	case DUK_TAG_POINTER: {
-		duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
+		duk__json_enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
 		break;
 	}
 #endif  /* DUK_USE_JX || DUK_USE_JC */
@@ -38508,7 +38599,7 @@
 		if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
 			goto pop2_undef;
 		}
-		duk__enc_quote_string(js_ctx, h);
+		duk__json_enc_quote_string(js_ctx, h);
 		break;
 	}
 	case DUK_TAG_OBJECT: {
@@ -38521,9 +38612,9 @@
 		DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE(h));
 
 		if (duk_js_isarray_hobject(h)) {
-			duk__enc_array(js_ctx);
+			duk__json_enc_array(js_ctx);
 		} else {
-			duk__enc_object(js_ctx);
+			duk__json_enc_object(js_ctx);
 		}
 		break;
 	}
@@ -38536,7 +38627,7 @@
 	case DUK_TAG_BUFFER: {
 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
 		if (js_ctx->flag_ext_custom_or_compatible) {
-			duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv));
+			duk__json_enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv));
 			break;
 		}
 #endif
@@ -38545,7 +38636,7 @@
 		 * to handle realloc side effects correctly.
 		 */
 		duk_to_object(thr, -1);
-		duk__enc_object(js_ctx);
+		duk__json_enc_object(js_ctx);
 		break;
 	}
 	case DUK_TAG_LIGHTFUNC: {
@@ -38564,7 +38655,7 @@
 		/* Number serialization has a significant impact relative to
 		 * other fast path code, so careful fast path for fastints.
 		 */
-		duk__enc_fastint_tval(js_ctx, tv);
+		duk__json_enc_fastint_tval(js_ctx, tv);
 		break;
 #endif
 	default: {
@@ -38574,7 +38665,7 @@
 		/* XXX: A fast path for usual integers would be useful when
 		 * fastint support is not enabled.
 		 */
-		duk__enc_double(js_ctx);
+		duk__json_enc_double(js_ctx);
 		break;
 	}
 	}
@@ -38591,7 +38682,7 @@
 }
 
 /* E5 Section 15.12.3, main algorithm, step 4.b.ii steps 1-4. */
-DUK_LOCAL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv) {
+DUK_LOCAL duk_bool_t duk__json_enc_allow_into_proplist(duk_tval *tv) {
 	duk_small_int_t c;
 
 	/* XXX: some kind of external internal type checker?
@@ -38674,7 +38765,7 @@
 		if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
 			goto emit_undefined;
 		}
-		duk__enc_quote_string(js_ctx, h);
+		duk__json_enc_quote_string(js_ctx, h);
 		break;
 	}
 	case DUK_TAG_OBJECT: {
@@ -38719,7 +38810,7 @@
 		DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
 		if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
 			DUK_DD(DUK_DDPRINT("fast path recursion limit"));
-			DUK_ERROR_RANGE(js_ctx->thr, DUK_STR_JSONDEC_RECLIMIT);
+			DUK_ERROR_RANGE(js_ctx->thr, DUK_STR_DEC_RECLIMIT);
 			DUK_WO_NORETURN(return 0;);
 		}
 
@@ -38846,11 +38937,11 @@
 
 				prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
 				if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
-					duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
-					duk__enc_key_autoquote(js_ctx, k);
+					duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth);
+					duk__json_enc_key_autoquote(js_ctx, k);
 					DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
 				} else {
-					duk__enc_key_autoquote(js_ctx, k);
+					duk__json_enc_key_autoquote(js_ctx, k);
 					DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
 				}
 
@@ -38873,7 +38964,7 @@
 				DUK__UNEMIT_1(js_ctx);  /* eat trailing comma */
 				if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
 					DUK_ASSERT(js_ctx->recursion_depth >= 1);
-					duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
+					duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
 				}
 			}
 			DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
@@ -38901,7 +38992,7 @@
 				duk_bool_t has_inherited;
 
 				if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
-					duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
+					duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth);
 				}
 
 				if (DUK_LIKELY(i < asize)) {
@@ -38950,7 +39041,7 @@
 				DUK__UNEMIT_1(js_ctx);  /* eat trailing comma */
 				if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
 					DUK_ASSERT(js_ctx->recursion_depth >= 1);
-					duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
+					duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
 				}
 			}
 			DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
@@ -38992,7 +39083,7 @@
 			DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
 		} else if (c_bit & c_bufobj) {
-			duk__enc_bufobj(js_ctx, (duk_hbufobj *) obj);
+			duk__json_enc_bufobj(js_ctx, (duk_hbufobj *) obj);
 #endif
 #endif
 		} else if (c_bit & c_abort) {
@@ -39032,7 +39123,7 @@
 
 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
 		if (js_ctx->flag_ext_custom_or_compatible) {
-			duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv));
+			duk__json_enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv));
 			break;
 		}
 #endif
@@ -39040,13 +39131,13 @@
 		/* Plain buffers mimic Uint8Arrays, and have enumerable index
 		 * properties.
 		 */
-		duk__enc_buffer_json_fastpath(js_ctx, DUK_TVAL_GET_BUFFER(tv));
+		duk__json_enc_buffer_json_fastpath(js_ctx, DUK_TVAL_GET_BUFFER(tv));
 		break;
 	}
 	case DUK_TAG_POINTER: {
 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
 		if (js_ctx->flag_ext_custom_or_compatible) {
-			duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
+			duk__json_enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
 			break;
 		} else {
 			goto emit_undefined;
@@ -39068,7 +39159,7 @@
 		/* Number serialization has a significant impact relative to
 		 * other fast path code, so careful fast path for fastints.
 		 */
-		duk__enc_fastint_tval(js_ctx, tv);
+		duk__json_enc_fastint_tval(js_ctx, tv);
 		break;
 	}
 #endif
@@ -39081,7 +39172,7 @@
 
 		/* XXX: Stack discipline is annoying, could be changed in numconv. */
 		duk_push_tval(js_ctx->thr, tv);
-		duk__enc_double(js_ctx);
+		duk__json_enc_double(js_ctx);
 		duk_pop(js_ctx->thr);
 
 #if 0
@@ -39193,14 +39284,15 @@
 	                DUK_HSTRING_GET_BYTELEN(h_text);
 	DUK_ASSERT(*(js_ctx->p_end) == 0x00);
 
-	duk__dec_value(js_ctx);  /* -> [ ... value ] */
+	duk__json_dec_value(js_ctx);  /* -> [ ... value ] */
+	DUK_ASSERT(js_ctx->recursion_depth == 0);
 
-	/* Trailing whitespace has been eaten by duk__dec_value(), so if
+	/* Trailing whitespace has been eaten by duk__json_dec_value(), so if
 	 * we're not at end of input here, it's a SyntaxError.
 	 */
 
 	if (js_ctx->p != js_ctx->p_end) {
-		duk__dec_syntax_error(js_ctx);
+		duk__json_dec_syntax_error(js_ctx);
 	}
 
 	if (duk_is_callable(thr, idx_reviver)) {
@@ -39218,7 +39310,9 @@
 		                     (duk_tval *) duk_get_tval(thr, -2),
 		                     (duk_tval *) duk_get_tval(thr, -1)));
 
-		duk__dec_reviver_walk(js_ctx);  /* [ ... val root "" ] -> [ ... val val' ] */
+		DUK_ASSERT(js_ctx->recursion_depth == 0);
+		duk__json_dec_reviver_walk(js_ctx);  /* [ ... val root "" ] -> [ ... val val' ] */
+		DUK_ASSERT(js_ctx->recursion_depth == 0);
 		duk_remove_m2(thr);             /* -> [ ... val' ] */
 	} else {
 		DUK_DDD(DUK_DDDPRINT("reviver does not exist or is not callable: %!T",
@@ -39366,14 +39460,14 @@
 			duk_uarridx_t plist_idx = 0;
 			duk_small_uint_t enum_flags;
 
-			js_ctx->idx_proplist = duk_push_array(thr);  /* XXX: array internal? */
+			js_ctx->idx_proplist = duk_push_bare_array(thr);
 
 			enum_flags = DUK_ENUM_ARRAY_INDICES_ONLY |
 			             DUK_ENUM_SORT_ARRAY_INDICES;  /* expensive flag */
 			duk_enum(thr, idx_replacer, enum_flags);
 			while (duk_next(thr, -1 /*enum_index*/, 1 /*get_value*/)) {
 				/* [ ... proplist enum_obj key val ] */
-				if (duk__enc_allow_into_proplist(duk_get_tval(thr, -1))) {
+				if (duk__json_enc_allow_into_proplist(duk_get_tval(thr, -1))) {
 					/* XXX: duplicates should be eliminated here */
 					DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> accept",
 					                     (duk_tval *) duk_get_tval(thr, -2),
@@ -39533,7 +39627,7 @@
 	js_ctx->recursion_limit = DUK_USE_JSON_ENC_RECLIMIT;
 	DUK_ASSERT(js_ctx->recursion_depth == 0);
 
-	if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_holder) == 0)) {  /* [ ... holder key ] -> [ ... holder ] */
+	if (DUK_UNLIKELY(duk__json_enc_value(js_ctx, idx_holder) == 0)) {  /* [ ... holder key ] -> [ ... holder ] */
 		/* Result is undefined. */
 		duk_push_undefined(thr);
 	} else {
@@ -41436,7 +41530,9 @@
 		}
 
 		/* [ obj trap_result res_arr propname ] */
-		duk_put_prop_index(thr, -2, idx++);
+		duk_push_uarridx(thr, idx++);
+		duk_insert(thr, -2);
+		duk_def_prop(thr, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_SET_WEC);
 		continue;
 
 	 skip_key:
@@ -42461,6 +42557,7 @@
 #endif  /* DUK_USE_REGEXP_SUPPORT */
 			const duk_uint8_t *p_start, *p_end, *p;   /* input string scan */
 			const duk_uint8_t *q_start;               /* match string */
+			duk_size_t p_blen;
 			duk_size_t q_blen;
 
 #if defined(DUK_USE_REGEXP_SUPPORT)
@@ -42469,13 +42566,19 @@
 
 			p_start = DUK_HSTRING_GET_DATA(h_input);
 			p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
+			p_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_input);
 			p = p_start;
 
 			h_search = duk_known_hstring(thr, 0);
 			q_start = DUK_HSTRING_GET_DATA(h_search);
 			q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_search);
 
+			if (q_blen > p_blen) {
+				break;  /* no match */
+			}
+
 			p_end -= q_blen;  /* ensure full memcmp() fits in while */
+			DUK_ASSERT(p_end >= p);
 
 			match_start_coff = 0;
 
@@ -43290,44 +43393,65 @@
 #if defined(DUK_USE_ES6)
 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_hthread *thr) {
 	duk_int_t magic;
-	duk_hstring *h;
+	duk_hstring *h_target;
+	duk_size_t blen_target;
 	duk_hstring *h_search;
 	duk_size_t blen_search;
-	const duk_uint8_t *p_cmp_start;
-	duk_bool_t result;
+	duk_int_t off;
+	duk_bool_t result = 0;
+	duk_size_t blen_left;
 
-	h = duk_push_this_coercible_to_string(thr);
-	DUK_ASSERT(h != NULL);
+	/* Because string byte lengths are in [0,DUK_INT_MAX] it's safe to
+	 * subtract two string lengths without overflow.
+	 */
+	DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX);
+
+	h_target = duk_push_this_coercible_to_string(thr);
+	DUK_ASSERT(h_target != NULL);
 
 	h_search = duk__str_tostring_notregexp(thr, 0);
 	DUK_ASSERT(h_search != NULL);
 
 	magic = duk_get_current_magic(thr);
 
-	p_cmp_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
+	/* Careful to avoid pointer overflows in the matching logic. */
+
+	blen_target = DUK_HSTRING_GET_BYTELEN(h_target);
 	blen_search = DUK_HSTRING_GET_BYTELEN(h_search);
 
+#if 0
+	/* If search string is longer than the target string, we can
+	 * never match.  Could check explicitly, but should be handled
+	 * correctly below.
+	 */
+	if (blen_search > blen_target) {
+		goto finish;
+	}
+#endif
+
+	off = 0;
 	if (duk_is_undefined(thr, 1)) {
 		if (magic) {
-			p_cmp_start = p_cmp_start + DUK_HSTRING_GET_BYTELEN(h) - blen_search;
+			off = (duk_int_t) blen_target - (duk_int_t) blen_search;
 		} else {
-			/* p_cmp_start already OK */
+			DUK_ASSERT(off == 0);
 		}
 	} else {
 		duk_int_t len;
 		duk_int_t pos;
 
 		DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX);
-		len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
+		len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h_target);
 		pos = duk_to_int_clamped(thr, 1, 0, len);
 		DUK_ASSERT(pos >= 0 && pos <= len);
 
+		off = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_target, (duk_uint_fast32_t) pos);
 		if (magic) {
-			p_cmp_start -= blen_search;  /* Conceptually subtracted last, but do already here. */
+			off -= (duk_int_t) blen_search;
 		}
-		DUK_ASSERT(pos >= 0 && pos <= len);
-
-		p_cmp_start += duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) pos);
+	}
+	if (off < 0 || off > (duk_int_t) blen_target) {
+		goto finish;
 	}
 
 	/* The main comparison can be done using a memcmp() rather than
@@ -43337,16 +43461,18 @@
 	 * comparison range.
 	 */
 
-	result = 0;
-	if (p_cmp_start >= DUK_HSTRING_GET_DATA(h) &&
-	    (duk_size_t) (p_cmp_start - (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h)) + blen_search <= DUK_HSTRING_GET_BYTELEN(h)) {
-		if (duk_memcmp((const void *) p_cmp_start,
-		               (const void *) DUK_HSTRING_GET_DATA(h_search),
-		               (size_t) blen_search) == 0) {
+	DUK_ASSERT(off >= 0);
+	DUK_ASSERT((duk_size_t) off <= blen_target);
+	blen_left = blen_target - (duk_size_t) off;
+	if (blen_left >= blen_search) {
+		const duk_uint8_t *p_cmp_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_target) + off;
+		const duk_uint8_t *p_search = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_search);
+		if (duk_memcmp_unsafe((const void *) p_cmp_start, (const void *) p_search, (size_t) blen_search) == 0) {
 			result = 1;
 		}
 	}
 
+ finish:
 	duk_push_boolean(thr, result);
 	return 1;
 }
@@ -52244,6 +52370,7 @@
 #if defined(DUK_USE_VOLUNTARY_GC)
 	duk_size_t tmp;
 #endif
+	duk_bool_t entry_creating_error;
 
 	DUK_STATS_INC(heap, stats_ms_try_count);
 #if defined(DUK_USE_DEBUG)
@@ -52314,6 +52441,8 @@
 	DUK_ASSERT(heap->ms_running == 0);
 	heap->ms_prevent_count = 1;
 	heap->ms_running = 1;
+	entry_creating_error = heap->creating_error;
+	heap->creating_error = 0;
 
 	/*
 	 *  Free activation/catcher freelists on every mark-and-sweep for now.
@@ -52444,6 +52573,7 @@
 	DUK_ASSERT(heap->ms_running == 1);
 	heap->ms_prevent_count = 0;
 	heap->ms_running = 0;
+	heap->creating_error = entry_creating_error;  /* for nested error handling, see GH-2278 */
 
 	/*
 	 *  Assertions after
@@ -55979,6 +56109,13 @@
 			keys[idx_insert] = h_curr;
 		}
 	}
+
+	/* Entry part has been reordered now with no side effects.
+	 * If the object has a hash part, it will now be incorrect
+	 * and we need to rehash.  Do that by forcing a resize to
+	 * the current size.
+	 */
+	duk_hobject_resize_entrypart(thr, h_obj, DUK_HOBJECT_GET_ESIZE(h_obj));
 }
 
 /*
@@ -74164,10 +74301,13 @@
 		 */
 		test_func_decl = allow_source_elem;
 #if defined(DUK_USE_NONSTD_FUNC_STMT)
-		/* Lenient: allow function declarations outside top level in
-		 * non-strict mode but reject them in strict mode.
+		/* Lenient: allow function declarations outside top level in both
+		 * strict and non-strict modes.  However, don't allow labelled
+		 * function declarations in strict mode.
 		 */
-		test_func_decl = test_func_decl || !comp_ctx->curr_func.is_strict;
+		test_func_decl = test_func_decl ||
+		                 !comp_ctx->curr_func.is_strict ||
+		                 label_id < 0;
 #endif  /* DUK_USE_NONSTD_FUNC_STMT */
 		/* Strict: never allow function declarations outside top level. */
 		if (test_func_decl) {
@@ -77196,17 +77336,21 @@
 			DUK_DD(DUK_DDPRINT("-> yield an error, converted to a throw in the resumer, propagate"));
 			goto check_longjmp;
 		} else {
-			duk_hthread_activation_unwind_norz(resumer);
-			duk__handle_yield(thr, resumer, &thr->heap->lj.value1);
+			/* When handling the yield, the last reference to
+			 * 'thr' may disappear.
+			 */
 
+			DUK_GC_TORTURE(resumer->heap);
+			duk_hthread_activation_unwind_norz(resumer);
+			DUK_GC_TORTURE(resumer->heap);
 			thr->state = DUK_HTHREAD_STATE_YIELDED;
 			thr->resumer = NULL;
 			DUK_HTHREAD_DECREF_NORZ(thr, resumer);
 			resumer->state = DUK_HTHREAD_STATE_RUNNING;
 			DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
-#if 0
-			thr = resumer;  /* not needed, as we exit right away */
-#endif
+			duk__handle_yield(thr, resumer, &thr->heap->lj.value1);
+			thr = resumer;
+			DUK_GC_TORTURE(resumer->heap);
 
 			DUK_DD(DUK_DDPRINT("-> yield a value, restart execution in resumer"));
 			retval = DUK__LONGJMP_RESTART;
@@ -83909,6 +84053,7 @@
                         duk_tval *val,
                         duk_bool_t strict) {
 	duk__id_lookup_result ref;
+	duk_tval tv_tmp_val;
 	duk_tval tv_tmp_obj;
 	duk_tval tv_tmp_key;
 	duk_bool_t parents;
@@ -83926,10 +84071,13 @@
 	DUK_ASSERT(val != NULL);
 	/* env and act may be NULL */
 
-        DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
-        DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
+	DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
+	DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
 	DUK_ASSERT_REFCOUNT_NONZERO_TVAL(val);
 
+	DUK_TVAL_SET_TVAL(&tv_tmp_val, val);  /* Stabilize. */
+	val = NULL;
+
 	/*
 	 *  In strict mode E5 protects 'eval' and 'arguments' from being
 	 *  assigned to (or even declared anywhere).  Attempt to do so
@@ -83961,7 +84109,7 @@
 
 			tv_val = ref.value;
 			DUK_ASSERT(tv_val != NULL);
-			DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, val);  /* side effects */
+			DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, &tv_tmp_val);  /* side effects */
 
 			/* ref.value invalidated here */
 		} else {
@@ -83969,7 +84117,7 @@
 
 			DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
 			DUK_TVAL_SET_STRING(&tv_tmp_key, name);
-			(void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict);
+			(void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, &tv_tmp_val, strict);
 
 			/* ref.value invalidated here */
 		}
@@ -83994,7 +84142,7 @@
 
 	DUK_TVAL_SET_OBJECT(&tv_tmp_obj, thr->builtins[DUK_BIDX_GLOBAL]);
 	DUK_TVAL_SET_STRING(&tv_tmp_key, name);
-	(void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, 0);  /* 0 = no throw */
+	(void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, &tv_tmp_val, 0);  /* 0 = no throw */
 
 	/* NB: 'val' may be invalidated here because put_value may realloc valstack,
 	 * caller beware.
@@ -91415,10 +91563,12 @@
 			 * as 'undefined'.  The same is done when saved[] pointers are insane
 			 * (this should, of course, never happen in practice).
 			 */
+			duk_push_uarridx(thr, (duk_uarridx_t) (i / 2));
+
 			if (re_ctx.saved[i] && re_ctx.saved[i + 1] && re_ctx.saved[i + 1] >= re_ctx.saved[i]) {
 				duk_push_lstring(thr,
 				                 (const char *) re_ctx.saved[i],
-				                 (duk_size_t) (re_ctx.saved[i+1] - re_ctx.saved[i]));
+				                 (duk_size_t) (re_ctx.saved[i + 1] - re_ctx.saved[i]));
 				if (i == 0) {
 					/* Assumes that saved[0] and saved[1] are always
 					 * set by regexp bytecode (if not, char_end_offset
@@ -91431,8 +91581,8 @@
 				duk_push_undefined(thr);
 			}
 
-			/* [ ... re_obj input bc saved_buf res_obj val ] */
-			duk_put_prop_index(thr, -2, (duk_uarridx_t) (i / 2));
+			/* [ ... re_obj input bc saved_buf res_obj idx val ] */
+			duk_def_prop(thr, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_SET_WEC);
 		}
 
 		/* [ ... re_obj input bc saved_buf res_obj ] */
diff --git a/duktape/duktape.h b/duktape/duktape.h
index 7850c99..e5b46c2 100644
--- a/duktape/duktape.h
+++ b/duktape/duktape.h
@@ -1,13 +1,13 @@
 /*
- *  Duktape public API for Duktape 2.5.0.
+ *  Duktape public API for Duktape 2.6.0.
  *
  *  See the API reference for documentation on call semantics.  The exposed,
  *  supported API is between the "BEGIN PUBLIC API" and "END PUBLIC API"
  *  comments.  Other parts of the header are Duktape internal and related to
  *  e.g. platform/compiler/feature detection.
  *
- *  Git commit 6001888049cb42656f8649db020e804bcdeca6a7 (v2.5.0).
- *  Git branch master.
+ *  Git commit fffa346eff06a8764b02c31d4336f63a773a95c3 (v2.6.0).
+ *  Git branch v2-maintenance.
  *
  *  See Duktape AUTHORS.rst and LICENSE.txt for copyright and
  *  licensing information.
@@ -176,16 +176,16 @@
  * development snapshots 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                       20500L
+#define DUK_VERSION                       20600L
 
 /* 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                    "6001888049cb42656f8649db020e804bcdeca6a7"
-#define DUK_GIT_DESCRIBE                  "v2.5.0"
-#define DUK_GIT_BRANCH                    "master"
+#define DUK_GIT_COMMIT                    "fffa346eff06a8764b02c31d4336f63a773a95c3"
+#define DUK_GIT_DESCRIBE                  "v2.6.0"
+#define DUK_GIT_BRANCH                    "v2-maintenance"
 
 /* External duk_config.h provides platform/compiler/OS dependent
  * typedefs and macros, and DUK_USE_xxx config options so that