summaryrefslogtreecommitdiff
path: root/javascript/duktape/duktape.c
diff options
context:
space:
mode:
Diffstat (limited to 'javascript/duktape/duktape.c')
-rw-r--r--javascript/duktape/duktape.c4532
1 files changed, 2887 insertions, 1645 deletions
diff --git a/javascript/duktape/duktape.c b/javascript/duktape/duktape.c
index 530a27aea..184767de4 100644
--- a/javascript/duktape/duktape.c
+++ b/javascript/duktape/duktape.c
@@ -1,10 +1,8 @@
-// Omit from static analysis.
-#ifndef __clang_analyzer__
/*
* Single source autogenerated distributable for Duktape 1.3.99.
- * Git commit 40453939c5a5aa16898d19bbac4d02f77196cc8b (v1.3.0-138-g4045393).
- * Git branch regexp-canonicalize-lookup.
+ * Git commit b7b1c5fd2d1d4550140d57e05a7b32f540082bfa (v1.3.0-383-gb7b1c5f).
+ * Git branch duk-config-improvements.
*
* See Duktape AUTHORS.rst and LICENSE.txt for copyright and
* licensing information.
@@ -158,23 +156,31 @@ DUK_USE_USER_DECLARE()
#ifndef DUK_REPLACEMENTS_H_INCLUDED
#define DUK_REPLACEMENTS_H_INCLUDED
-#ifdef DUK_USE_REPL_FPCLASSIFY
+#if defined(DUK_USE_COMPUTED_INFINITY)
+DUK_INTERNAL_DECL double duk_computed_infinity;
+#endif
+
+#if defined(DUK_USE_COMPUTED_NAN)
+DUK_INTERNAL_DECL double duk_computed_nan;
+#endif
+
+#if defined(DUK_USE_REPL_FPCLASSIFY)
DUK_INTERNAL_DECL int duk_repl_fpclassify(double x);
#endif
-#ifdef DUK_USE_REPL_SIGNBIT
+#if defined(DUK_USE_REPL_SIGNBIT)
DUK_INTERNAL_DECL int duk_repl_signbit(double x);
#endif
-#ifdef DUK_USE_REPL_ISFINITE
+#if defined(DUK_USE_REPL_ISFINITE)
DUK_INTERNAL_DECL int duk_repl_isfinite(double x);
#endif
-#ifdef DUK_USE_REPL_ISNAN
+#if defined(DUK_USE_REPL_ISNAN)
DUK_INTERNAL_DECL int duk_repl_isnan(double x);
#endif
-#ifdef DUK_USE_REPL_ISINF
+#if defined(DUK_USE_REPL_ISINF)
DUK_INTERNAL_DECL int duk_repl_isinf(double x);
#endif
@@ -727,11 +733,11 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#define DUK_STRIDX_TRY 389 /* 'try' */
#define DUK_STRIDX_TYPEOF 390 /* 'typeof' */
#define DUK_STRIDX_VAR 391 /* 'var' */
-#define DUK_STRIDX_VOID 392 /* 'void' */
-#define DUK_STRIDX_WHILE 393 /* 'while' */
-#define DUK_STRIDX_WITH 394 /* 'with' */
-#define DUK_STRIDX_CLASS 395 /* 'class' */
-#define DUK_STRIDX_CONST 396 /* 'const' */
+#define DUK_STRIDX_CONST 392 /* 'const' */
+#define DUK_STRIDX_VOID 393 /* 'void' */
+#define DUK_STRIDX_WHILE 394 /* 'while' */
+#define DUK_STRIDX_WITH 395 /* 'with' */
+#define DUK_STRIDX_CLASS 396 /* 'class' */
#define DUK_STRIDX_ENUM 397 /* 'enum' */
#define DUK_STRIDX_EXPORT 398 /* 'export' */
#define DUK_STRIDX_EXTENDS 399 /* 'extends' */
@@ -1534,6 +1540,8 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
#define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
#define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
+#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
+#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
#define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
#define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
#define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
@@ -1542,8 +1550,6 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
#define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
#define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
-#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
-#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
#define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
#define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
#define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
@@ -1586,16 +1592,16 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#define DUK_STRIDX_END_RESERVED 414 /* exclusive endpoint */
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[147];
+DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1952];
#ifdef DUK_USE_BUILTIN_INITJS
-DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[1757];
+DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
#endif /* DUK_USE_BUILTIN_INITJS */
#endif /* !DUK_SINGLE_FILE */
#define DUK_BUILTINS_DATA_LENGTH 1952
#ifdef DUK_USE_BUILTIN_INITJS
-#define DUK_BUILTIN_INITJS_DATA_LENGTH 1757
+#define DUK_BUILTIN_INITJS_DATA_LENGTH 187
#endif /* DUK_USE_BUILTIN_INITJS */
#define DUK_BIDX_GLOBAL 0
@@ -2072,11 +2078,11 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#define DUK_STRIDX_TRY 389 /* 'try' */
#define DUK_STRIDX_TYPEOF 390 /* 'typeof' */
#define DUK_STRIDX_VAR 391 /* 'var' */
-#define DUK_STRIDX_VOID 392 /* 'void' */
-#define DUK_STRIDX_WHILE 393 /* 'while' */
-#define DUK_STRIDX_WITH 394 /* 'with' */
-#define DUK_STRIDX_CLASS 395 /* 'class' */
-#define DUK_STRIDX_CONST 396 /* 'const' */
+#define DUK_STRIDX_CONST 392 /* 'const' */
+#define DUK_STRIDX_VOID 393 /* 'void' */
+#define DUK_STRIDX_WHILE 394 /* 'while' */
+#define DUK_STRIDX_WITH 395 /* 'with' */
+#define DUK_STRIDX_CLASS 396 /* 'class' */
#define DUK_STRIDX_ENUM 397 /* 'enum' */
#define DUK_STRIDX_EXPORT 398 /* 'export' */
#define DUK_STRIDX_EXTENDS 399 /* 'extends' */
@@ -2879,6 +2885,8 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
#define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
#define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
+#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
+#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
#define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
#define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
#define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
@@ -2887,8 +2895,6 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
#define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
#define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
-#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
-#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
#define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
#define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
#define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
@@ -2931,16 +2937,16 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#define DUK_STRIDX_END_RESERVED 414 /* exclusive endpoint */
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[147];
+DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1952];
#ifdef DUK_USE_BUILTIN_INITJS
-DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[1757];
+DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
#endif /* DUK_USE_BUILTIN_INITJS */
#endif /* !DUK_SINGLE_FILE */
#define DUK_BUILTINS_DATA_LENGTH 1952
#ifdef DUK_USE_BUILTIN_INITJS
-#define DUK_BUILTIN_INITJS_DATA_LENGTH 1757
+#define DUK_BUILTIN_INITJS_DATA_LENGTH 187
#endif /* DUK_USE_BUILTIN_INITJS */
#define DUK_BIDX_GLOBAL 0
@@ -3417,11 +3423,11 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#define DUK_STRIDX_TRY 389 /* 'try' */
#define DUK_STRIDX_TYPEOF 390 /* 'typeof' */
#define DUK_STRIDX_VAR 391 /* 'var' */
-#define DUK_STRIDX_VOID 392 /* 'void' */
-#define DUK_STRIDX_WHILE 393 /* 'while' */
-#define DUK_STRIDX_WITH 394 /* 'with' */
-#define DUK_STRIDX_CLASS 395 /* 'class' */
-#define DUK_STRIDX_CONST 396 /* 'const' */
+#define DUK_STRIDX_CONST 392 /* 'const' */
+#define DUK_STRIDX_VOID 393 /* 'void' */
+#define DUK_STRIDX_WHILE 394 /* 'while' */
+#define DUK_STRIDX_WITH 395 /* 'with' */
+#define DUK_STRIDX_CLASS 396 /* 'class' */
#define DUK_STRIDX_ENUM 397 /* 'enum' */
#define DUK_STRIDX_EXPORT 398 /* 'export' */
#define DUK_STRIDX_EXTENDS 399 /* 'extends' */
@@ -4224,6 +4230,8 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
#define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
#define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
+#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
+#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
#define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
#define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
#define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
@@ -4232,8 +4240,6 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
#define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
#define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
-#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
-#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
#define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
#define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
#define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
@@ -4276,16 +4282,16 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#define DUK_STRIDX_END_RESERVED 414 /* exclusive endpoint */
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[147];
+DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1952];
#ifdef DUK_USE_BUILTIN_INITJS
-DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[1757];
+DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
#endif /* DUK_USE_BUILTIN_INITJS */
#endif /* !DUK_SINGLE_FILE */
#define DUK_BUILTINS_DATA_LENGTH 1952
#ifdef DUK_USE_BUILTIN_INITJS
-#define DUK_BUILTIN_INITJS_DATA_LENGTH 1757
+#define DUK_BUILTIN_INITJS_DATA_LENGTH 187
#endif /* DUK_USE_BUILTIN_INITJS */
#define DUK_BIDX_GLOBAL 0
@@ -4834,9 +4840,17 @@ struct duk_bufwriter_ctx {
*/
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL duk_uint8_t duk_lc_digits[36];
-DUK_INTERNAL_DECL duk_uint8_t duk_uc_nybbles[16];
-DUK_INTERNAL_DECL duk_int8_t duk_hex_dectab[256];
+DUK_INTERNAL_DECL const duk_uint8_t duk_lc_digits[36];
+DUK_INTERNAL_DECL const duk_uint8_t duk_uc_nybbles[16];
+DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256];
+#if defined(DUK_USE_HEX_FASTPATH)
+DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256];
+DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256];
+#endif
+#if defined(DUK_USE_BASE64_FASTPATH)
+DUK_INTERNAL_DECL const duk_uint8_t duk_base64_enctab[64];
+DUK_INTERNAL_DECL const duk_int8_t duk_base64_dectab[256];
+#endif
#endif /* !DUK_SINGLE_FILE */
/* Note: assumes that duk_util_probe_steps size is 32 */
@@ -4846,7 +4860,9 @@ DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32];
#endif /* !DUK_SINGLE_FILE */
#endif
+#if defined(DUK_USE_STRHASH_DENSE)
DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed);
+#endif
#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size);
@@ -4934,20 +4950,23 @@ DUK_INTERNAL_DECL const char *duk_str_not_configurable;
#endif /* !DUK_SINGLE_FILE */
#define DUK_STR_INVALID_CONTEXT duk_str_invalid_context
-#define DUK_STR_INVALID_INDEX duk_str_invalid_index
+#define DUK_STR_INVALID_INDEX duk_str_invalid_call_args
#define DUK_STR_PUSH_BEYOND_ALLOC_STACK duk_str_push_beyond_alloc_stack
-#define DUK_STR_NOT_UNDEFINED duk_str_not_undefined
-#define DUK_STR_NOT_NULL duk_str_not_null
-#define DUK_STR_NOT_BOOLEAN duk_str_not_boolean
-#define DUK_STR_NOT_NUMBER duk_str_not_number
-#define DUK_STR_NOT_STRING duk_str_not_string
-#define DUK_STR_NOT_POINTER duk_str_not_pointer
-#define DUK_STR_NOT_BUFFER duk_str_not_buffer
+#define DUK_STR_NOT_UNDEFINED duk_str_unexpected_type
+#define DUK_STR_NOT_NULL duk_str_unexpected_type
+#define DUK_STR_NOT_BOOLEAN duk_str_unexpected_type
+#define DUK_STR_NOT_NUMBER duk_str_unexpected_type
+#define DUK_STR_NOT_STRING duk_str_unexpected_type
+#define DUK_STR_NOT_OBJECT duk_str_unexpected_type
+#define DUK_STR_NOT_POINTER duk_str_unexpected_type
+#define DUK_STR_NOT_BUFFER duk_str_not_buffer /* still in use with verbose messages */
#define DUK_STR_UNEXPECTED_TYPE duk_str_unexpected_type
-#define DUK_STR_NOT_THREAD duk_str_not_thread
-#define DUK_STR_NOT_COMPILEDFUNCTION duk_str_not_compiledfunction
-#define DUK_STR_NOT_NATIVEFUNCTION duk_str_not_nativefunction
-#define DUK_STR_NOT_C_FUNCTION duk_str_not_c_function
+#define DUK_STR_NOT_THREAD duk_str_unexpected_type
+#define DUK_STR_NOT_COMPILEDFUNCTION duk_str_unexpected_type
+#define DUK_STR_NOT_NATIVEFUNCTION duk_str_unexpected_type
+#define DUK_STR_NOT_C_FUNCTION duk_str_unexpected_type
+#define DUK_STR_NOT_FUNCTION duk_str_unexpected_type
+#define DUK_STR_NOT_REGEXP duk_str_unexpected_type
#define DUK_STR_DEFAULTVALUE_COERCE_FAILED duk_str_defaultvalue_coerce_failed
#define DUK_STR_NUMBER_OUTSIDE_RANGE duk_str_number_outside_range
#define DUK_STR_NOT_OBJECT_COERCIBLE duk_str_not_object_coercible
@@ -4968,20 +4987,9 @@ DUK_INTERNAL_DECL const char *duk_str_not_configurable;
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL const char *duk_str_invalid_context;
-DUK_INTERNAL_DECL const char *duk_str_invalid_index;
DUK_INTERNAL_DECL const char *duk_str_push_beyond_alloc_stack;
-DUK_INTERNAL_DECL const char *duk_str_not_undefined;
-DUK_INTERNAL_DECL const char *duk_str_not_null;
-DUK_INTERNAL_DECL const char *duk_str_not_boolean;
-DUK_INTERNAL_DECL const char *duk_str_not_number;
-DUK_INTERNAL_DECL const char *duk_str_not_string;
-DUK_INTERNAL_DECL const char *duk_str_not_pointer;
DUK_INTERNAL_DECL const char *duk_str_not_buffer;
DUK_INTERNAL_DECL const char *duk_str_unexpected_type;
-DUK_INTERNAL_DECL const char *duk_str_not_thread;
-DUK_INTERNAL_DECL const char *duk_str_not_compiledfunction;
-DUK_INTERNAL_DECL const char *duk_str_not_nativefunction;
-DUK_INTERNAL_DECL const char *duk_str_not_c_function;
DUK_INTERNAL_DECL const char *duk_str_defaultvalue_coerce_failed;
DUK_INTERNAL_DECL const char *duk_str_number_outside_range;
DUK_INTERNAL_DECL const char *duk_str_not_object_coercible;
@@ -5453,13 +5461,13 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo
#define DUK_TOK_TRY 22
#define DUK_TOK_TYPEOF 23
#define DUK_TOK_VAR 24
-#define DUK_TOK_VOID 25
-#define DUK_TOK_WHILE 26
-#define DUK_TOK_WITH 27
+#define DUK_TOK_CONST 25
+#define DUK_TOK_VOID 26
+#define DUK_TOK_WHILE 27
+#define DUK_TOK_WITH 28
/* reserved words: future reserved words */
-#define DUK_TOK_CLASS 28
-#define DUK_TOK_CONST 29
+#define DUK_TOK_CLASS 29
#define DUK_TOK_ENUM 30
#define DUK_TOK_EXPORT 31
#define DUK_TOK_EXTENDS 32
@@ -6158,11 +6166,6 @@ DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hack
* Packed 8-byte representation
*/
-/* sanity */
-#if !defined(DUK_USE_PACKED_TVAL_POSSIBLE)
-#error packed representation not supported
-#endif
-
/* use duk_double_union as duk_tval directly */
typedef union duk_double_union duk_tval;
@@ -7108,13 +7111,13 @@ struct duk_heaphdr_string {
} while (0)
/* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups,
- * etc, so it's very important for performance.
+ * etc, so it's very important for performance. Measure when changing.
*
* NOTE: the source and destination duk_tval pointers may be the same, and
* the macros MUST deal with that correctly.
*/
-/* Original idiom used. */
+/* Original idiom used, minimal code size. */
#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \
duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \
tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
@@ -7124,84 +7127,23 @@ struct duk_heaphdr_string {
DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
} while (0)
-#if 0 /* XXX: to optimize and measure */
-/* Original idiom but with forced fast refcount macros. */
-#define DUK_TVAL_SET_TVAL_UPDREF_ALT0F(thr,tvptr_dst,tvptr_src) do { \
- duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \
- tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
- DUK_TVAL_INCREF_FAST((thr), tv__src); \
- DUK_TVAL_DECREF_FAST((thr), &tv__tmp); /* side effects */ \
- } while (0)
-
-/* Use 'h__obj' temporary to avoid a full duk_tval copy. */
+/* Faster alternative: avoid making a temporary copy of tvptr_dst and use
+ * fast incref/decref macros.
+ */
#define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \
duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \
tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
- if (DUK_TVAL_IS_HEAP_ALLOCATED(tv__dst)) { \
- h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \
- DUK_ASSERT(h__obj != NULL); \
- } else { \
- h__obj = NULL; \
- } \
- DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
- DUK_TVAL_INCREF((thr), tv__src); \
- if (h__obj != NULL) { \
- DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \
- } \
- } while (0)
-
-/* Use 'h__obj' temporary to avoid a full duk_tval copy. */
-#define DUK_TVAL_SET_TVAL_UPDREF_ALT1A(thr,tvptr_dst,tvptr_src) do { \
- duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \
- tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
- if (DUK_UNLIKELY(DUK_TVAL_IS_HEAP_ALLOCATED(tv__dst))) { \
- h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \
- DUK_ASSERT(h__obj != NULL); \
- } else { \
- h__obj = NULL; \
- } \
- DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
DUK_TVAL_INCREF_FAST((thr), tv__src); \
- if (DUK_UNLIKELY(h__obj != NULL)) { \
- DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \
- } \
- } while (0)
-
-/* Avoid rechecking 'h__obj'. */
-#define DUK_TVAL_SET_TVAL_UPDREF_ALT2(thr,tvptr_dst,tvptr_src) do { \
- duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \
- tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
if (DUK_TVAL_IS_HEAP_ALLOCATED(tv__dst)) { \
h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \
DUK_ASSERT(h__obj != NULL); \
DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
- DUK_TVAL_INCREF((thr), tv__src); \
DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \
} else { \
DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
- DUK_TVAL_INCREF((thr), tv__src); \
} \
} while (0)
-/* Avoid rechecking 'h__obj'. */
-#define DUK_TVAL_SET_TVAL_UPDREF_ALT3(thr,tvptr_dst,tvptr_src) do { \
- duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \
- tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
- if (DUK_UNLIKELY(DUK_TVAL_IS_HEAP_ALLOCATED(tv__dst))) { \
- h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \
- DUK_ASSERT(h__obj != NULL); \
- DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
- DUK_TVAL_INCREF_FAST((thr), tv__src); \
- DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \
- } else { \
- DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
- DUK_TVAL_INCREF_FAST((thr), tv__src); \
- } \
- } while (0)
-#endif
-
/* XXX: no optimized variants yet */
#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0
@@ -7224,8 +7166,8 @@ struct duk_heaphdr_string {
#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
/* Optimized for speed. */
-#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0
-#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0
+#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT1
+#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT1
#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
#else
/* Optimized for size. */
@@ -7421,6 +7363,10 @@ duk_bool_t duk_valstack_resize_raw(duk_context *ctx,
duk_size_t min_new_size,
duk_small_uint_t flags);
+#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
+DUK_INTERNAL_DECL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index);
+#endif
+
DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index);
DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index);
DUK_INTERNAL_DECL void duk_push_tval(duk_context *ctx, duk_tval *tv);
@@ -7462,13 +7408,6 @@ DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx);
#define duk_push_size_t(ctx,val) \
duk_push_uint((ctx), (duk_uint_t) (val)) /* XXX: assumed to fit for now */
-/* internal helper for looking up a tagged type */
-#define DUK_GETTAGGED_FLAG_ALLOW_NULL (1L << 24)
-#define DUK_GETTAGGED_FLAG_CHECK_CLASS (1L << 25)
-#define DUK_GETTAGGED_CLASS_SHIFT 16
-
-DUK_INTERNAL_DECL duk_heaphdr *duk_get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t flags_and_tag);
-
DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index);
DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index);
DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index);
@@ -7476,10 +7415,7 @@ DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index
DUK_INTERNAL_DECL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index);
DUK_INTERNAL_DECL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index);
-#define duk_get_hobject_with_class(ctx,index,classnum) \
- ((duk_hobject *) duk_get_tagged_heaphdr_raw((ctx), (index), \
- DUK_TAG_OBJECT | DUK_GETTAGGED_FLAG_ALLOW_NULL | \
- DUK_GETTAGGED_FLAG_CHECK_CLASS | ((classnum) << DUK_GETTAGGED_CLASS_SHIFT)))
+DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum);
#if 0 /* This would be pointless: unexpected type and lightfunc would both return NULL */
DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index);
@@ -7494,6 +7430,10 @@ DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index)
#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index);
#endif
+DUK_INTERNAL_DECL void duk_to_object_class_string_top(duk_context *ctx);
+#if !defined(DUK_USE_PARANOID_ERRORS)
+DUK_INTERNAL_DECL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h);
+#endif
DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */
DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval);
@@ -7509,10 +7449,7 @@ DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t i
DUK_INTERNAL_DECL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index);
DUK_INTERNAL_DECL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index);
-#define duk_require_hobject_with_class(ctx,index,classnum) \
- ((duk_hobject *) duk_get_tagged_heaphdr_raw((ctx), (index), \
- DUK_TAG_OBJECT | \
- DUK_GETTAGGED_FLAG_CHECK_CLASS | ((classnum) << DUK_GETTAGGED_CLASS_SHIFT)))
+DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum);
DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx_t index);
DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index);
@@ -7540,6 +7477,11 @@ DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv);
DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv);
DUK_INTERNAL_DECL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
+#if !defined(DUK_USE_PARANOID_ERRORS)
+DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index);
+DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv);
+#endif
+
DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [val] */
DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [val] -> [] */
DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [] */
@@ -9806,6 +9748,7 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
#define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING (1 << 2) /* refcount code is processing refzero list */
#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 3) /* an error handler (user callback to augment/replace error) is running */
#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 4) /* executor interrupt running (used to avoid nested interrupts) */
+#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 5) /* heap destruction ongoing, finalizer rescue no longer possible */
#define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits))
#define DUK__HEAP_SET_FLAGS(heap,bits) do { \
@@ -9820,18 +9763,21 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
#define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
#define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
#define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
+#define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
#define DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
#define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
#define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
#define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
#define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
+#define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
#define DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
#define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
#define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
#define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
#define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
+#define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
/*
* Longjmp types, also double as identifying continuation type for a rethrow (in 'finally')
@@ -9856,8 +9802,9 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
#define DUK_MS_FLAG_EMERGENCY (1 << 0) /* emergency mode: try extra hard */
#define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE (1 << 1) /* don't resize stringtable (but may sweep it); needed during stringtable resize */
-#define DUK_MS_FLAG_NO_FINALIZERS (1 << 2) /* don't run finalizers (which may have arbitrary side effects) */
-#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 3) /* don't compact objects; needed during object property allocation resize */
+#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2) /* don't compact objects; needed during object property allocation resize */
+#define DUK_MS_FLAG_NO_FINALIZERS (1 << 3) /* don't run finalizers; leave finalizable objects in finalize_list for next round */
+#define DUK_MS_FLAG_SKIP_FINALIZERS (1 << 4) /* don't run finalizers; queue finalizable objects back to heap_allocated */
/*
* Thread switching
@@ -10221,6 +10168,7 @@ struct duk_heap {
duk_bool_t dbg_paused; /* currently paused: talk with debug client until step/resume */
duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */
duk_bool_t dbg_force_restart; /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */
+ duk_bool_t dbg_detaching; /* debugger detaching; used to avoid calling detach handler recursively */
duk_small_uint_t dbg_step_type; /* step type: none, step into, step over, step out */
duk_hthread *dbg_step_thread; /* borrowed; NULL if no step state (NULLed in unwind) */
duk_size_t dbg_step_csindex; /* callstack index */
@@ -10234,6 +10182,10 @@ struct duk_heap {
duk_uint32_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */
duk_uint32_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */
duk_double_t dbg_last_time; /* time when status/peek was last done (Date-based rate limit) */
+
+ /* Used to support single-byte stream lookahead. */
+ duk_bool_t dbg_have_next_byte;
+ duk_uint8_t dbg_next_byte;
#endif
/* string intern table (weak refs) */
@@ -10383,6 +10335,7 @@ DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uin
#define DUK_DBG_CMD_ALERT 0x03
#define DUK_DBG_CMD_LOG 0x04
#define DUK_DBG_CMD_THROW 0x05
+#define DUK_DBG_CMD_DETACHING 0x06
/* Initiated by debug client */
#define DUK_DBG_CMD_BASICINFO 0x10
@@ -10433,7 +10386,7 @@ DUK_INTERNAL_DECL void duk_debug_write_cstring(duk_hthread *thr, const char *dat
DUK_INTERNAL_DECL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h);
DUK_INTERNAL_DECL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length);
DUK_INTERNAL_DECL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h);
-DUK_INTERNAL_DECL void duk_debug_write_pointer(duk_hthread *thr, const void *ptr);
+DUK_INTERNAL_DECL void duk_debug_write_pointer(duk_hthread *thr, void *ptr);
#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
DUK_INTERNAL_DECL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h);
#endif
@@ -10448,9 +10401,11 @@ DUK_INTERNAL_DECL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uin
DUK_INTERNAL_DECL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command);
DUK_INTERNAL_DECL void duk_debug_write_eom(duk_hthread *thr);
-DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr);
-DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_debug_send_status(duk_hthread *thr);
+#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
DUK_INTERNAL_DECL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal);
+#endif
DUK_INTERNAL_DECL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc);
DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block);
@@ -10636,7 +10591,7 @@ DUK_INTERNAL_DECL duk_small_int_t duk_debug_level_stash;
DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...);
#endif /* DUK_USE_VARIADIC_MACROS */
-DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, duk_uint8_t *buffer, duk_size_t length);
+DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length);
DUK_INTERNAL_DECL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x);
DUK_INTERNAL_DECL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x);
DUK_INTERNAL_DECL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...);
@@ -10694,9 +10649,9 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
* fall back to awkward hacks.
*/
-#ifdef DUK_USE_VERBOSE_ERRORS
+#if defined(DUK_USE_VERBOSE_ERRORS)
-#ifdef DUK_USE_VARIADIC_MACROS
+#if defined(DUK_USE_VARIADIC_MACROS)
/* __VA_ARGS__ has comma issues for empty lists, so we mandate at least 1 argument for '...' (format string) */
#define DUK_ERROR(thr,err,...) duk_err_handle_error(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr), (err), __VA_ARGS__)
@@ -10718,7 +10673,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#else /* DUK_USE_VERBOSE_ERRORS */
-#ifdef DUK_USE_VARIADIC_MACROS
+#if defined(DUK_USE_VARIADIC_MACROS)
#define DUK_ERROR(thr,err,...) duk_err_handle_error((thr), (err))
#define DUK_ERROR_RAW(file,line,thr,err,...) duk_err_handle_error((thr), (err))
@@ -10770,7 +10725,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
* Assert macro: failure causes panic.
*/
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
/* the message should be a compile time constant without formatting (less risk);
* we don't care about assertion text size because they're not used in production
@@ -10862,11 +10817,54 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#endif
/*
+ * Error throwing helpers
+ *
+ * The goal is to provide verbose and configurable error messages. Call
+ * sites should be clean in source code and compile to a small footprint.
+ * Small footprint is also useful for performance because small cold paths
+ * reduce code cache pressure.
+ */
+
+#if defined(DUK_USE_VERBOSE_ERRORS)
+#if defined(DUK_USE_PARANOID_ERRORS)
+/* Verbose but paranoid errors. */
+
+#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
+ duk_err_require_type_index(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr), (index), (expectname)); \
+ } while (0)
+#else
+/* Verbose errors with key/value summaries. */
+
+#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
+ duk_err_require_type_index(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr), (index), (expectname)); \
+ } while (0)
+#endif
+#define DUK_ERROR_API_INDEX(thr,index) do { \
+ duk_err_api_index(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr), (index)); \
+ } while (0)
+#define DUK_ERROR_API(thr,msg) do { \
+ duk_err_api(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr), (msg)); \
+ } while (0)
+#else
+/* Non-verbose errors for low memory targets. */
+
+#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
+ duk_err_require_type_index(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr), (lowmemstr)); \
+ } while (0)
+#define DUK_ERROR_API_INDEX(thr,index) do { \
+ duk_err_api_index(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr)); \
+ } while (0)
+#define DUK_ERROR_API(thr,msg) do { \
+ duk_err_api(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr), (msg)); \
+ } while (0)
+#endif
+
+/*
* Prototypes
*/
-#ifdef DUK_USE_VERBOSE_ERRORS
-#ifdef DUK_USE_VARIADIC_MACROS
+#if defined(DUK_USE_VERBOSE_ERRORS)
+#if defined(DUK_USE_VARIADIC_MACROS)
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(const char *filename, duk_int_t line, duk_hthread *thr, duk_errcode_t code, const char *fmt, ...));
#else /* DUK_USE_VARIADIC_MACROS */
#if !defined(DUK_SINGLE_FILE)
@@ -10877,7 +10875,7 @@ DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(const char *filename, d
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error_stash(duk_hthread *thr, duk_errcode_t code, const char *fmt, ...));
#endif /* DUK_USE_VARIADIC_MACROS */
#else /* DUK_USE_VERBOSE_ERRORS */
-#ifdef DUK_USE_VARIADIC_MACROS
+#if defined(DUK_USE_VARIADIC_MACROS)
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code));
#else /* DUK_USE_VARIADIC_MACROS */
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error_nonverbose1(duk_hthread *thr, duk_errcode_t code, const char *fmt, ...));
@@ -10885,7 +10883,7 @@ DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error_nonverbose2(const char
#endif /* DUK_USE_VARIADIC_MACROS */
#endif /* DUK_USE_VERBOSE_ERRORS */
-#ifdef DUK_USE_VERBOSE_ERRORS
+#if defined(DUK_USE_VERBOSE_ERRORS)
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line));
#else
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code));
@@ -10900,6 +10898,20 @@ DUK_INTERNAL_DECL void duk_err_augment_error_create(duk_hthread *thr, duk_hthrea
DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr);
#endif
+#if defined(DUK_USE_VERBOSE_ERRORS)
+#if defined(DUK_USE_PARANOID_ERRORS)
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, duk_idx_t index, const char *expect_name));
+#else
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, duk_idx_t index, const char *expect_name));
+#endif
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, duk_idx_t index));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(const char *filename, duk_int_t linenumber, duk_hthread *thr, const char *message));
+#else
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, const char *error_msg));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api_index(const char *filename, duk_int_t linenumber, duk_hthread *thr));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(const char *filename, duk_int_t linenumber, duk_hthread *thr, const char *message));
+#endif
+
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_longjmp(duk_hthread *thr));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg));
@@ -11134,12 +11146,13 @@ extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348];
extern const duk_uint8_t duk_unicode_caseconv_uc[1288];
extern const duk_uint8_t duk_unicode_caseconv_lc[616];
-/* FIXME: CONDITIONAL */
+#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
/*
* Automatically generated by extract_caseconv.py, do not edit!
*/
extern const duk_uint16_t duk_unicode_re_canon_lookup[65536];
+#endif
/*
* Extern
@@ -11199,10 +11212,8 @@ DUK_INTERNAL_DECL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp)
/* How much stack to require on entry to object/array decode */
#define DUK_JSON_DEC_REQSTACK 32
-/* How large a loop detection stack to use for fast path */
-#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
+/* How large a loop detection stack to use */
#define DUK_JSON_ENC_LOOPARRAY 64
-#endif
/* Encoding state. Heap object references are all borrowed. */
typedef struct {
@@ -11210,7 +11221,6 @@ typedef struct {
duk_bufwriter_ctx bw; /* output bufwriter */
duk_hobject *h_replacer; /* replacer function */
duk_hstring *h_gap; /* gap (if empty string, NULL) */
- duk_hstring *h_indent; /* current indent (if gap is NULL, this is NULL) */
duk_idx_t idx_proplist; /* explicit PropertyList */
duk_idx_t idx_loop; /* valstack index of loop detection object */
duk_small_uint_t flags;
@@ -11219,6 +11229,7 @@ typedef struct {
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
duk_small_uint_t flag_ext_custom;
duk_small_uint_t flag_ext_compatible;
+ duk_small_uint_t flag_ext_custom_or_compatible;
#endif
duk_int_t recursion_depth;
duk_int_t recursion_limit;
@@ -11230,9 +11241,7 @@ typedef struct {
duk_small_uint_t stridx_custom_posinf;
duk_small_uint_t stridx_custom_function;
#endif
-#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
duk_hobject *visiting[DUK_JSON_ENC_LOOPARRAY]; /* indexed by recursion_depth */
-#endif
} duk_json_enc_ctx;
typedef struct {
@@ -11245,6 +11254,7 @@ typedef struct {
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
duk_small_uint_t flag_ext_custom;
duk_small_uint_t flag_ext_compatible;
+ duk_small_uint_t flag_ext_custom_or_compatible;
#endif
duk_int_t recursion_depth;
duk_int_t recursion_limit;
@@ -11527,6 +11537,31 @@ DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year);
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x);
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t year);
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x);
+/* Built-in providers */
+#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx);
+#endif
+#if defined(DUK_USE_DATE_NOW_TIME)
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(duk_context *ctx);
+#endif
+#if defined(DUK_USE_DATE_NOW_WINDOWS)
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx);
+#endif
+#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME)
+DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d);
+#endif
+#if defined(DUK_USE_DATE_TZO_WINDOWS)
+DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d);
+#endif
+#if defined(DUK_USE_DATE_PRS_STRPTIME)
+DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str);
+#endif
+#if defined(DUK_USE_DATE_PRS_GETDATE)
+DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str);
+#endif
+#if defined(DUK_USE_DATE_FMT_STRFTIME)
+DUK_INTERNAL_DECL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags);
+#endif
DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx);
@@ -11541,7 +11576,9 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_nop_setter(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx);
@@ -11696,20 +11733,9 @@ DUK_INTERNAL const char *duk_str_not_writable = "not writable";
DUK_INTERNAL const char *duk_str_not_configurable = "not configurable";
DUK_INTERNAL const char *duk_str_invalid_context = "invalid context";
-DUK_INTERNAL const char *duk_str_invalid_index = "invalid index";
DUK_INTERNAL const char *duk_str_push_beyond_alloc_stack = "attempt to push beyond currently allocated stack";
-DUK_INTERNAL const char *duk_str_not_undefined = "not undefined";
-DUK_INTERNAL const char *duk_str_not_null = "not null";
-DUK_INTERNAL const char *duk_str_not_boolean = "not boolean";
-DUK_INTERNAL const char *duk_str_not_number = "not number";
-DUK_INTERNAL const char *duk_str_not_string = "not string";
-DUK_INTERNAL const char *duk_str_not_pointer = "not pointer";
-DUK_INTERNAL const char *duk_str_not_buffer = "not buffer";
+DUK_INTERNAL const char *duk_str_not_buffer = "not buffer"; /* still in use with verbose messages */
DUK_INTERNAL const char *duk_str_unexpected_type = "unexpected type";
-DUK_INTERNAL const char *duk_str_not_thread = "not thread";
-DUK_INTERNAL const char *duk_str_not_compiledfunction = "not compiledfunction";
-DUK_INTERNAL const char *duk_str_not_nativefunction = "not nativefunction";
-DUK_INTERNAL const char *duk_str_not_c_function = "not c function";
DUK_INTERNAL const char *duk_str_defaultvalue_coerce_failed = "[[DefaultValue]] coerce failed";
DUK_INTERNAL const char *duk_str_number_outside_range = "number outside range";
DUK_INTERNAL const char *duk_str_not_object_coercible = "not object coercible";
@@ -11904,18 +11930,6 @@ DUK_INTERNAL void duk_debug_log(duk_small_int_t level, const char *file, duk_int
DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE);
duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
-#ifdef DUK_USE_DPRINT_RDTSC
- DUK_FPRINTF(DUK_STDERR, "%s[%s] <%llu> %s:%ld (%s):%s %s%s\n",
- (const char *) duk__get_term_1(level),
- (const char *) duk__get_level_string(level),
- (unsigned long long) DUK_USE_RDTSC(), /* match the inline asm in duk_features.h */
- (const char *) file,
- (long) line,
- (const char *) func,
- (const char *) duk__get_term_2(level),
- (const char *) duk__debug_buf,
- (const char *) duk__get_term_3(level));
-#else
DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%ld (%s):%s %s%s\n",
(const char *) duk__get_term_1(level),
(const char *) duk__get_level_string(level),
@@ -11925,7 +11939,6 @@ DUK_INTERNAL void duk_debug_log(duk_small_int_t level, const char *file, duk_int
(const char *) duk__get_term_2(level),
(const char *) duk__debug_buf,
(const char *) duk__get_term_3(level));
-#endif
DUK_FFLUSH(DUK_STDERR);
va_end(ap);
@@ -11947,18 +11960,6 @@ DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE);
duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
-#ifdef DUK_USE_DPRINT_RDTSC
- DUK_FPRINTF(DUK_STDERR, "%s[%s] <%llu> %s:%s (%s):%s %s%s\n",
- (const char *) duk__get_term_1(level),
- (const char *) duk__get_level_string(duk_debug_level_stash),
- (unsigned long long) DUK_USE_RDTSC(), /* match duk_features.h */
- (const char *) duk_debug_file_stash,
- (const char *) duk_debug_line_stash,
- (const char *) duk_debug_func_stash,
- (const char *) duk__get_term_2(level),
- (const char *) duk__debug_buf,
- (const char *) duk__get_term_3(level));
-#else
DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%s (%s):%s %s%s\n",
(const char *) duk__get_term_1(level),
(const char *) duk__get_level_string(duk_debug_level_stash),
@@ -11968,7 +11969,6 @@ DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
(const char *) duk__get_term_2(level),
(const char *) duk__debug_buf,
(const char *) duk__get_term_3(level));
-#endif
DUK_FFLUSH(DUK_STDERR);
va_end(ap);
@@ -12112,20 +12112,20 @@ DUK_INTERNAL const duk_uint8_t duk_strings_data[2624] = {
32,76,71,64,156,217,161,180,34,6,64,208,198,36,78,50,20,20,92,204,50,44,
147,32,134,226,17,114,33,202,134,129,107,192,202,232,160,180,104,166,135,
52,72,40,144,213,33,178,152,26,34,56,163,105,44,104,146,116,139,77,43,34,
-98,57,38,116,72,179,60,93,97,206,56,52,240,242,56,163,168,34,74,185,3,45,
-142,133,144,150,68,206,81,44,18,145,68,230,202,100,35,104,195,18,239,116,
-102,114,94,100,104,228,100,49,238,140,203,42,60,145,35,104,181,146,113,161,
-10,80,46,68,82,24,245,145,132,108,228,148,54,100,137,64,34,13,100,153,222,
-1,40,6,33,223,20,84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104,
-17,112,130,44,96,
+98,57,38,116,72,179,60,93,97,206,56,52,240,242,56,163,168,34,81,57,178,153,
+42,228,12,182,58,22,66,89,19,57,68,176,74,68,35,104,195,18,239,116,102,114,
+94,100,104,228,100,49,238,140,203,42,60,145,35,104,181,146,113,161,10,80,
+46,68,82,24,245,145,132,108,228,148,54,100,137,64,34,13,100,153,222,1,40,6,
+33,223,20,84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104,17,112,
+130,44,96,
};
/* to convert a heap stridx to a token number, subtract
* DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
*/
-/* native functions: 147 */
-DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = {
+/* native functions: 149 */
+DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_array_constructor,
duk_bi_array_constructor_is_array,
duk_bi_array_prototype_concat,
@@ -12173,9 +12173,11 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = {
duk_bi_duktape_object_info,
duk_bi_error_constructor_shared,
duk_bi_error_prototype_filename_getter,
+ duk_bi_error_prototype_filename_setter,
duk_bi_error_prototype_linenumber_getter,
- duk_bi_error_prototype_nop_setter,
+ duk_bi_error_prototype_linenumber_setter,
duk_bi_error_prototype_stack_getter,
+ duk_bi_error_prototype_stack_setter,
duk_bi_error_prototype_to_string,
duk_bi_function_constructor,
duk_bi_function_prototype,
@@ -12276,38 +12278,38 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = {
};
DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
-105,195,75,16,121,40,105,51,14,252,104,52,8,131,72,0,115,225,65,165,236,55,
-243,6,145,32,210,24,210,182,25,249,35,120,216,99,226,13,78,225,116,177,164,
+105,195,75,32,121,40,105,53,14,252,104,54,8,131,72,0,115,225,65,165,244,55,
+243,6,145,32,210,24,210,186,25,249,35,120,216,99,226,13,79,33,116,177,164,
180,44,192,4,202,52,150,220,24,0,169,70,146,219,123,0,23,40,210,91,110,96,
3,37,26,75,109,172,0,108,163,73,109,177,128,14,148,105,45,181,176,1,242,
-144,56,209,32,94,6,167,101,98,80,211,24,1,250,67,72,168,67,232,13,46,128,
-47,162,52,164,0,62,80,163,72,128,61,40,107,26,7,37,20,53,200,131,88,0,66,
-134,185,16,98,80,215,34,11,96,0,138,26,228,65,76,0,69,67,92,136,37,128,6,
-168,107,145,4,48,1,165,13,114,32,118,0,44,161,174,68,12,192,7,148,53,200,
-129,88,1,26,134,165,48,130,80,31,255,241,69,224,0,0,0,0,0,0,124,63,174,32,
+144,56,209,36,94,6,167,133,98,80,211,28,1,250,67,72,168,67,232,13,46,192,
+47,162,52,165,0,62,80,163,72,128,61,40,107,26,7,37,20,53,201,131,88,0,66,
+134,185,48,98,80,215,38,11,96,0,138,26,228,193,76,0,69,67,92,152,37,128,6,
+168,107,147,4,48,1,165,13,114,96,118,0,44,161,174,76,12,192,7,148,53,201,
+129,88,1,26,134,165,80,130,80,31,255,241,69,224,0,0,0,0,0,0,124,63,174,32,
0,0,0,0,0,0,120,63,175,98,7,140,16,116,194,7,12,48,108,196,6,140,80,100,
198,6,12,112,92,200,5,140,149,192,202,91,204,181,184,204,91,76,213,176,206,
90,204,240,84,208,5,13,9,124,210,43,13,24,64,226,131,205,112,56,216,3,77,
152,48,218,130,205,184,40,220,130,77,216,32,222,129,205,248,24,224,129,78,
-25,214,163,226,90,80,145,104,65,37,157,0,150,99,242,89,78,73,100,58,37,140,
-236,150,35,194,88,79,73,96,69,37,125,12,122,188,134,62,0,2,165,68,39,255,
-255,193,43,67,0,0,80,127,192,58,182,216,80,0,21,59,154,64,0,107,76,200,172,
-180,146,176,198,138,187,43,42,204,136,170,181,146,168,214,80,0,26,155,81,
-42,77,4,168,180,20,0,6,160,206,74,123,73,64,0,127,255,4,10,153,219,28,198,
-163,184,130,140,224,10,43,144,40,141,164,161,183,18,132,222,64,161,127,128,
-0,63,225,1,109,74,8,137,71,56,5,4,213,20,3,115,233,249,177,240,80,255,192,
+25,214,164,2,90,81,17,104,67,37,157,8,150,100,18,89,78,201,100,60,37,140,
+244,150,35,226,88,79,201,96,71,37,125,20,122,188,138,62,0,2,165,70,39,255,
+255,193,43,67,0,0,80,127,192,58,182,220,80,0,21,59,170,64,0,107,77,8,172,
+181,146,176,202,138,187,59,42,204,200,170,182,146,168,218,80,0,26,155,97,
+42,77,68,168,181,20,0,6,160,210,74,123,89,64,0,127,255,4,10,153,219,157,70,
+163,185,130,140,228,10,43,160,40,141,228,161,184,18,132,226,64,161,127,128,
+0,63,225,1,109,74,8,137,71,58,5,4,221,20,3,147,233,249,193,240,80,255,192,
6,120,2,64,127,195,0,173,28,56,20,96,80,128,0,206,192,143,167,64,164,156,
131,2,112,14,125,55,9,4,216,40,19,80,180,77,3,9,51,13,94,153,7,159,76,64,
207,192,0,102,0,103,255,255,242,240,67,73,112,33,168,0,12,180,16,212,0,10,
88,8,106,0,7,43,4,53,0,4,149,4,31,128,0,202,66,15,255,255,194,137,254,0,50,
-135,195,224,127,196,2,87,132,17,82,143,20,10,44,80,36,239,196,147,63,146,
-119,0,125,49,129,52,152,64,154,128,0,201,96,137,36,131,36,142,17,18,40,82,
-77,97,145,33,135,68,130,37,17,247,208,71,159,65,29,125,8,0,12,113,244,32,0,
-49,184,176,70,162,16,20,95,240,0,7,252,80,37,120,193,81,196,194,0,3,69,19,
-0,81,191,197,140,192,255,255,255,255,255,255,239,127,140,64,1,0,0,0,0,0,0,
-0,139,192,0,0,0,0,0,0,248,127,138,192,0,0,0,0,0,0,240,127,139,64,0,0,0,0,0,
-0,240,255,0,31,241,128,149,224,0,0,0,0,0,0,0,0,13,71,96,37,25,120,148,86,
-16,69,23,73,19,92,36,73,124,129,71,255,0,56,136,233,34,3,223,208,241,192,3,
+135,227,224,127,196,2,87,132,17,82,143,24,10,44,96,36,240,4,147,64,146,119,
+4,125,49,131,52,152,65,154,128,0,201,97,9,36,133,36,142,25,18,40,114,77,98,
+17,33,137,68,130,45,17,247,240,71,159,193,29,127,8,0,12,113,252,32,0,49,
+184,208,70,162,144,20,95,240,0,7,252,80,37,120,193,81,196,194,0,3,69,19,0,
+81,191,197,140,192,255,255,255,255,255,255,239,127,140,64,1,0,0,0,0,0,0,0,
+139,192,0,0,0,0,0,0,248,127,138,192,0,0,0,0,0,0,240,127,139,64,0,0,0,0,0,0,
+240,255,0,31,241,128,149,224,0,0,0,0,0,0,0,0,13,71,98,37,25,128,148,86,48,
+69,23,201,19,94,36,73,132,129,71,255,0,56,136,233,34,3,223,208,241,192,3,
254,56,18,188,128,0,0,0,0,0,15,135,251,104,228,128,135,18,4,0,6,26,72,16,0,
42,49,32,64,0,225,132,129,0,4,133,146,4,0,21,210,72,16,0,103,65,32,64,1,
220,228,100,162,146,130,20,74,8,72,248,64,2,33,3,225,0,9,131,143,132,0,42,
@@ -12318,9 +12320,9 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
33,127,0,29,120,144,207,128,15,60,8,103,192,7,221,228,37,0,32,119,16,148,0,
133,218,66,190,0,68,236,33,95,0,35,117,144,191,128,18,58,136,95,192,9,92,
195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,64,192,2,2,225,
-132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,240,71,19,201,40,
-239,64,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,137,129,109,203,140,
-11,78,94,96,13,28,200,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47,
+132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,244,71,19,217,40,
+239,128,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,145,153,109,203,139,
+203,78,96,98,13,28,208,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47,
252,0,9,255,44,19,104,173,237,146,8,128,20,207,240,0,39,252,192,77,162,183,
54,72,34,0,83,127,192,0,159,243,65,54,138,218,217,32,136,1,78,255,0,2,127,
206,4,218,43,99,100,130,32,5,63,252,0,9,255,60,19,104,173,109,146,8,128,15,
@@ -12328,126 +12330,51 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
144,26,208,59,206,126,191,144,139,185,143,218,176,63,160,138,217,81,197,
125,207,218,144,3,185,73,133,94,242,246,207,218,112,6,11,81,21,62,200,66,
80,26,80,51,78,223,217,167,168,57,143,218,48,51,78,223,217,167,168,61,143,
-210,104,39,17,158,156,80,0,22,114,113,64,0,153,169,197,0,3,102,40,33,150,
-156,80,0,70,82,113,64,1,89,41,197,0,6,100,39,20,0,29,142,156,80,0,134,50,
-98,243,21,53,121,136,160,144,0,22,26,120,24,73,197,0,9,96,167,20,0,41,128,
-156,80,0,181,250,113,64,3,1,255,254,0,81,20,100,47,145,216,23,255,240,0,11,
-255,248,0,3,255,252,81,252,0,0,0,0,8,4,252,68,0,129,167,1,26,144,9,165,0,
-26,177,199,197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,
-39,32,84,223,192,15,59,30,129,156,115,6,81,160,7,253,40,0,5,81,252,0,1,255,
-78,0,84,113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,66,0,3,69,
-117,0,85,159,192,0,31,245,97,10,100,0,0,0,0,0,0,0,32,10,164,130,97,221,191,
-113,3,20,146,12,18,200,47,74,30,23,37,15,128,0,143,146,135,192,0,133,169,
-67,224,0,98,196,161,240,0,65,90,80,248,0,41,63,255,194,109,65,11,137,191,
-174,45,153,98,242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,
-185,111,228,131,70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,
-174,0,25,168,194,64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,
-0,32,54,139,164,0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,
-164,0,140,208,46,144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,
-50,208,2,19,24,203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,
-127,255,128,21,38,73,7,1,132,128,0,133,105,252,19,140,0,0,0,0,0,0,15,3,240,
-25,127,102,0,1,91,127,4,227,0,0,0,0,0,0,3,192,252,6,95,218,128,0,87,31,193,
-56,192,0,0,0,0,0,0,240,63,1,151,246,224,0,21,215,240,78,48,0,0,0,0,0,0,0,
-16,0,101,253,200,0,5,121,252,19,140,0,0,0,0,0,0,0,4,0,25,127,118,0,1,95,
-127,4,227,0,0,0,0,0,0,0,65,0,6,95,222,128,0,88,31,193,56,192,0,0,0,0,0,0,
-16,64,1,151,247,224,0,22,23,240,78,48,0,0,0,0,0,0,4,16,0,101,254,8,0,5,137,
-252,19,140,0,0,0,0,0,0,2,4,0,25,127,134,0,1,99,127,0,89,218,146,20,74,228,
-80,171,17,64,162,132,248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,
-152,23,72,0,10,92,93,32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,
-76,93,32,1,73,33,116,128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,
-225,116,128,2,35,69,210,0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,
-10,162,69,218,0,58,136,25,98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,
-132,25,104,0,138,12,101,160,3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,
-145,252,101,160,3,71,225,150,128,1,159,70,90,0,22,124,25,104,0,33,236,101,
-160,1,135,161,152,128,2,158,70,98,0,26,120,25,136,0,169,220,102,32,3,180,
-117,150,57,214,0,157,85,98,112,80,137,241,66,128,0,166,213,33,53,24,66,121,
-106,0,
+210,104,40,17,158,160,80,0,22,114,129,64,0,153,170,5,0,3,102,41,33,150,160,
+80,0,70,82,129,64,1,89,42,5,0,6,100,40,20,0,29,142,160,80,0,134,50,114,243,
+21,61,121,136,164,144,0,22,26,136,24,74,5,0,9,96,168,20,0,41,128,160,80,0,
+181,250,129,64,3,1,255,254,0,81,20,132,47,146,88,23,255,240,0,11,255,248,0,
+3,255,252,81,252,0,0,0,0,8,4,252,68,0,129,167,1,26,144,9,165,0,26,177,199,
+197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,32,84,
+223,192,15,59,34,129,156,131,6,81,224,7,253,40,0,5,81,252,0,1,255,78,0,84,
+113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,194,0,3,69,119,0,85,
+159,192,0,31,245,97,10,100,0,0,0,0,0,0,0,32,10,164,130,97,221,191,113,3,20,
+178,12,19,72,47,76,30,23,38,15,128,0,143,147,7,192,0,133,169,131,224,0,98,
+196,193,240,0,65,90,96,248,0,41,63,255,194,109,65,11,137,191,174,45,153,98,
+242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,228,131,
+70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,168,194,
+64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,139,164,
+0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,140,208,46,
+144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,208,2,19,24,
+203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,255,128,21,
+38,81,7,1,132,128,0,133,105,252,19,140,0,0,0,0,0,0,15,3,240,25,127,102,0,1,
+91,127,4,227,0,0,0,0,0,0,3,192,252,6,95,218,128,0,87,31,193,56,192,0,0,0,0,
+0,0,240,63,1,151,246,224,0,21,215,240,78,48,0,0,0,0,0,0,0,16,0,101,253,200,
+0,5,121,252,19,140,0,0,0,0,0,0,0,4,0,25,127,118,0,1,95,127,4,227,0,0,0,0,0,
+0,0,65,0,6,95,222,128,0,88,31,193,56,192,0,0,0,0,0,0,16,64,1,151,247,224,0,
+22,23,240,78,48,0,0,0,0,0,0,4,16,0,101,254,8,0,5,137,252,19,140,0,0,0,0,0,
+0,2,4,0,25,127,134,0,1,99,127,0,89,218,162,20,75,36,80,172,17,64,166,132,
+248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,72,0,10,92,93,
+32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,1,73,33,116,
+128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,2,35,69,210,
+0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,0,58,136,25,
+98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,12,101,160,
+3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,71,225,150,
+128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,128,2,158,
+70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,182,57,214,128,157,87,98,
+112,80,137,241,66,128,0,166,213,161,53,24,66,121,114,0,
};
#ifdef DUK_USE_BUILTIN_INITJS
-DUK_INTERNAL const duk_uint8_t duk_initjs_data[1757] = {
-47,42,10,32,42,32,32,73,110,105,116,32,99,111,100,101,32,102,111,114,32,
-108,101,103,97,99,121,32,99,111,109,112,97,116,105,98,105,108,105,116,121,
-46,10,32,42,10,32,42,32,32,67,111,109,112,97,116,105,98,105,108,105,116,
-121,32,112,114,111,112,101,114,116,105,101,115,32,47,32,119,114,97,112,112,
-101,114,32,102,117,110,99,116,105,111,110,115,32,104,101,114,101,32,97,108,
-108,111,119,32,68,117,107,116,97,112,101,32,116,111,32,114,101,109,97,105,
-110,10,32,42,32,32,99,111,109,112,97,116,105,98,108,101,32,102,111,114,32,
-117,115,101,114,32,99,111,100,101,32,119,104,101,110,32,99,111,114,101,32,
-102,101,97,116,117,114,101,115,32,97,114,101,32,99,104,97,110,103,101,100,
-44,32,119,105,116,104,111,117,116,32,98,117,114,100,101,110,105,110,103,10,
-32,42,32,32,116,104,101,32,109,97,105,110,32,67,32,99,111,100,101,32,119,
-105,116,104,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,115,116,
-117,102,102,46,10,32,42,10,32,42,32,32,84,104,105,115,32,102,105,108,101,
-32,105,115,32,109,105,110,105,102,105,101,100,32,119,105,116,104,32,85,103,
-108,105,102,121,74,83,32,111,114,32,116,104,101,32,99,108,111,115,117,114,
-101,32,99,111,109,112,105,108,101,114,46,32,32,66,111,116,104,32,119,105,
-108,108,10,32,42,32,32,114,101,110,97,109,101,32,118,97,114,105,97,98,108,
-101,115,44,32,114,101,109,111,118,101,32,99,111,109,109,101,110,116,115,44,
-32,97,110,100,32,97,114,101,32,99,108,101,118,101,114,32,101,110,111,117,
-103,104,32,116,111,32,100,114,111,112,32,97,110,121,10,32,42,32,32,34,105,
-102,32,40,102,97,108,115,101,41,32,123,32,46,46,46,32,125,34,32,98,108,111,
-99,107,115,32,97,108,116,111,103,101,116,104,101,114,44,32,115,111,32,116,
-104,97,116,39,115,32,97,110,32,101,102,102,101,99,116,105,118,101,32,119,
-97,121,32,116,111,10,32,42,32,32,100,105,115,97,98,108,101,32,99,117,114,
-114,101,110,116,108,121,32,117,110,110,101,101,100,101,100,32,99,111,100,
-101,46,10,32,42,47,10,10,40,102,117,110,99,116,105,111,110,40,71,44,32,68,
-41,32,123,10,32,32,32,32,39,117,115,101,32,115,116,114,105,99,116,39,59,10,
-10,32,32,32,32,102,117,110,99,116,105,111,110,32,100,101,102,40,111,98,106,
-101,99,116,44,32,110,97,109,101,44,32,118,97,108,117,101,41,32,123,10,32,
-32,32,32,32,32,32,32,79,98,106,101,99,116,46,100,101,102,105,110,101,80,
-114,111,112,101,114,116,121,40,111,98,106,101,99,116,44,32,110,97,109,101,
-44,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,118,97,108,117,101,58,32,
-118,97,108,117,101,44,10,32,32,32,32,32,32,32,32,32,32,32,32,119,114,105,
-116,97,98,108,101,58,32,116,114,117,101,44,10,32,32,32,32,32,32,32,32,32,
-32,32,32,101,110,117,109,101,114,97,98,108,101,58,32,102,97,108,115,101,44,
-10,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,102,105,103,117,114,97,
-98,108,101,58,32,116,114,117,101,10,32,32,32,32,32,32,32,32,125,41,59,10,
-32,32,32,32,125,10,10,32,32,32,32,102,117,110,99,116,105,111,110,32,100,
-101,102,68,40,110,97,109,101,44,32,118,97,108,117,101,41,32,123,10,32,32,
-32,32,32,32,32,32,100,101,102,40,68,44,32,110,97,109,101,44,32,118,97,108,
-117,101,41,59,10,32,32,32,32,125,10,10,32,32,32,32,47,47,32,67,111,109,112,
-97,116,105,98,105,108,105,116,121,32,102,111,114,32,39,99,111,110,115,111,
-108,101,46,108,111,103,39,46,10,32,32,32,32,105,102,32,40,102,97,108,115,
-101,41,32,123,10,32,32,32,32,32,32,32,32,99,111,110,115,111,108,101,32,61,
-32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,103,58,32,102,117,
-110,99,116,105,111,110,40,41,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,
-32,32,32,32,112,114,105,110,116,40,65,114,114,97,121,46,112,114,111,116,
-111,116,121,112,101,46,106,111,105,110,46,99,97,108,108,40,97,114,103,117,
-109,101,110,116,115,44,32,39,32,39,41,41,59,10,32,32,32,32,32,32,32,32,32,
-32,32,32,125,10,32,32,32,32,32,32,32,32,125,59,10,32,32,32,32,125,10,10,32,
-32,32,32,47,47,32,68,117,107,116,97,112,101,46,108,105,110,101,40,41,32,
-119,97,115,32,114,101,109,111,118,101,100,32,105,110,32,68,117,107,116,97,
-112,101,32,48,46,49,49,46,48,44,32,104,101,114,101,39,115,32,97,110,32,101,
-120,97,109,112,108,101,10,32,32,32,32,47,47,32,114,101,112,108,97,99,101,
-109,101,110,116,32,117,115,101,114,32,99,111,100,101,32,99,111,117,108,100,
-32,117,115,101,46,10,32,32,32,32,105,102,32,40,102,97,108,115,101,41,32,
-123,10,32,32,32,32,32,32,32,32,100,101,102,40,68,44,32,39,108,105,110,101,
-39,44,32,102,117,110,99,116,105,111,110,32,40,41,32,123,10,32,32,32,32,32,
-32,32,32,32,32,32,32,39,117,115,101,32,100,117,107,32,110,111,116,97,105,
-108,39,59,10,10,32,32,32,32,32,32,32,32,32,32,32,32,47,42,32,84,97,105,108,
-32,99,97,108,108,115,32,97,114,101,32,112,114,101,118,101,110,116,101,100,
-32,116,111,32,101,110,115,117,114,101,32,99,97,108,108,105,110,103,32,97,
-99,116,105,118,97,116,105,111,110,32,101,120,105,115,116,115,46,10,32,32,
-32,32,32,32,32,32,32,32,32,32,32,42,32,67,97,108,108,32,115,116,97,99,107,
-32,105,110,100,105,99,101,115,58,32,45,49,32,61,32,68,117,107,116,97,112,
-101,46,97,99,116,44,32,45,50,32,61,32,103,101,116,67,117,114,114,101,110,
-116,76,105,110,101,44,32,45,51,32,61,32,99,97,108,108,101,114,10,32,32,32,
-32,32,32,32,32,32,32,32,32,32,42,47,10,10,32,32,32,32,32,32,32,32,32,32,32,
-32,114,101,116,117,114,110,32,40,68,117,107,116,97,112,101,46,97,99,116,40,
-45,51,41,32,124,124,32,123,125,41,46,108,105,110,101,78,117,109,98,101,114,
-59,10,32,32,32,32,32,32,32,32,125,41,59,10,32,32,32,32,125,10,10,32,32,32,
-32,47,47,32,76,111,103,103,101,114,32,111,98,106,101,99,116,32,102,111,114,
-32,67,32,99,111,100,101,32,112,114,111,118,105,100,101,100,32,98,121,32,
-105,110,105,116,32,99,111,100,101,32,110,111,119,46,10,32,32,32,32,105,102,
-32,40,116,114,117,101,41,32,123,10,32,32,32,32,32,32,32,32,100,101,102,40,
-68,46,76,111,103,103,101,114,44,32,39,99,108,111,103,39,44,32,110,101,119,
-32,68,46,76,111,103,103,101,114,40,39,67,39,41,41,59,10,32,32,32,32,125,10,
-10,32,32,32,32,47,47,32,84,114,97,99,107,105,110,103,32,116,97,98,108,101,
-32,102,111,114,32,67,111,109,109,111,110,74,83,32,109,111,100,117,108,101,
-32,108,111,97,100,105,110,103,46,10,32,32,32,32,105,102,32,40,116,114,117,
-101,41,32,123,10,32,32,32,32,32,32,32,32,100,101,102,40,68,44,32,39,109,
-111,100,76,111,97,100,101,100,39,44,32,123,125,41,59,10,32,32,32,32,125,10,
-125,41,40,116,104,105,115,44,32,68,117,107,116,97,112,101,41,59,10,0,
+DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = {
+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,
+108,117,101,58,99,44,119,114,105,116,97,98,108,101,58,33,48,44,101,110,117,
+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,
};
#endif /* DUK_USE_BUILTIN_INITJS */
#elif defined(DUK_USE_DOUBLE_BE)
@@ -12572,20 +12499,20 @@ DUK_INTERNAL const duk_uint8_t duk_strings_data[2624] = {
32,76,71,64,156,217,161,180,34,6,64,208,198,36,78,50,20,20,92,204,50,44,
147,32,134,226,17,114,33,202,134,129,107,192,202,232,160,180,104,166,135,
52,72,40,144,213,33,178,152,26,34,56,163,105,44,104,146,116,139,77,43,34,
-98,57,38,116,72,179,60,93,97,206,56,52,240,242,56,163,168,34,74,185,3,45,
-142,133,144,150,68,206,81,44,18,145,68,230,202,100,35,104,195,18,239,116,
-102,114,94,100,104,228,100,49,238,140,203,42,60,145,35,104,181,146,113,161,
-10,80,46,68,82,24,245,145,132,108,228,148,54,100,137,64,34,13,100,153,222,
-1,40,6,33,223,20,84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104,
-17,112,130,44,96,
+98,57,38,116,72,179,60,93,97,206,56,52,240,242,56,163,168,34,81,57,178,153,
+42,228,12,182,58,22,66,89,19,57,68,176,74,68,35,104,195,18,239,116,102,114,
+94,100,104,228,100,49,238,140,203,42,60,145,35,104,181,146,113,161,10,80,
+46,68,82,24,245,145,132,108,228,148,54,100,137,64,34,13,100,153,222,1,40,6,
+33,223,20,84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104,17,112,
+130,44,96,
};
/* to convert a heap stridx to a token number, subtract
* DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
*/
-/* native functions: 147 */
-DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = {
+/* native functions: 149 */
+DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_array_constructor,
duk_bi_array_constructor_is_array,
duk_bi_array_prototype_concat,
@@ -12633,9 +12560,11 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = {
duk_bi_duktape_object_info,
duk_bi_error_constructor_shared,
duk_bi_error_prototype_filename_getter,
+ duk_bi_error_prototype_filename_setter,
duk_bi_error_prototype_linenumber_getter,
- duk_bi_error_prototype_nop_setter,
+ duk_bi_error_prototype_linenumber_setter,
duk_bi_error_prototype_stack_getter,
+ duk_bi_error_prototype_stack_setter,
duk_bi_error_prototype_to_string,
duk_bi_function_constructor,
duk_bi_function_prototype,
@@ -12736,38 +12665,38 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = {
};
DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
-105,195,75,16,121,40,105,51,14,252,104,52,8,131,72,0,115,225,65,165,236,55,
-243,6,145,32,210,24,210,182,25,249,35,120,216,99,226,13,78,225,116,177,164,
+105,195,75,32,121,40,105,53,14,252,104,54,8,131,72,0,115,225,65,165,244,55,
+243,6,145,32,210,24,210,186,25,249,35,120,216,99,226,13,79,33,116,177,164,
180,44,192,4,202,52,150,220,24,0,169,70,146,219,123,0,23,40,210,91,110,96,
3,37,26,75,109,172,0,108,163,73,109,177,128,14,148,105,45,181,176,1,242,
-144,56,209,32,94,6,167,101,98,80,211,24,1,250,67,72,168,67,232,13,46,128,
-47,162,52,164,0,62,80,163,72,128,61,40,107,26,7,37,20,53,200,131,88,0,66,
-134,185,16,98,80,215,34,11,96,0,138,26,228,65,76,0,69,67,92,136,37,128,6,
-168,107,145,4,48,1,165,13,114,32,118,0,44,161,174,68,12,192,7,148,53,200,
-129,88,1,26,134,165,48,130,80,31,255,241,69,224,63,252,0,0,0,0,0,0,46,32,
+144,56,209,36,94,6,167,133,98,80,211,28,1,250,67,72,168,67,232,13,46,192,
+47,162,52,165,0,62,80,163,72,128,61,40,107,26,7,37,20,53,201,131,88,0,66,
+134,185,48,98,80,215,38,11,96,0,138,26,228,193,76,0,69,67,92,152,37,128,6,
+168,107,147,4,48,1,165,13,114,96,118,0,44,161,174,76,12,192,7,148,53,201,
+129,88,1,26,134,165,80,130,80,31,255,241,69,224,63,252,0,0,0,0,0,0,46,32,
63,248,0,0,0,0,0,0,47,98,7,140,16,116,194,7,12,48,108,196,6,140,80,100,198,
6,12,112,92,200,5,140,149,192,202,91,204,181,184,204,91,76,213,176,206,90,
204,240,84,208,5,13,9,124,210,43,13,24,64,226,131,205,112,56,216,3,77,152,
48,218,130,205,184,40,220,130,77,216,32,222,129,205,248,24,224,129,78,25,
-214,163,226,90,80,145,104,65,37,157,0,150,99,242,89,78,73,100,58,37,140,
-236,150,35,194,88,79,73,96,69,37,125,12,122,188,134,62,0,2,165,68,39,255,
-255,193,43,67,0,0,80,127,192,58,182,216,80,0,21,59,154,64,0,107,76,200,172,
-180,146,176,198,138,187,43,42,204,136,170,181,146,168,214,80,0,26,155,81,
-42,77,4,168,180,20,0,6,160,206,74,123,73,64,0,127,255,4,10,153,219,28,198,
-163,184,130,140,224,10,43,144,40,141,164,161,183,18,132,222,64,161,127,128,
-0,63,225,1,109,74,8,137,71,56,5,4,213,20,3,115,233,249,177,240,80,255,192,
-6,120,2,64,127,195,0,173,28,56,20,96,80,128,0,206,192,143,167,64,164,156,
-131,2,112,14,125,55,9,4,216,40,19,80,180,77,3,9,51,13,94,153,7,159,76,64,
-207,192,0,102,0,103,255,255,242,240,67,73,112,33,168,0,12,180,16,212,0,10,
-88,8,106,0,7,43,4,53,0,4,149,4,31,128,0,202,66,15,255,255,194,137,254,0,50,
-135,195,224,127,196,2,87,132,17,82,143,20,10,44,80,36,239,196,147,63,146,
-119,0,125,49,129,52,152,64,154,128,0,201,96,137,36,131,36,142,17,18,40,82,
-77,97,145,33,135,68,130,37,17,247,208,71,159,65,29,125,8,0,12,113,244,32,0,
-49,184,176,70,162,16,20,95,240,0,7,252,80,37,120,193,81,196,194,0,3,69,19,
-0,81,191,197,140,192,127,239,255,255,255,255,255,255,140,64,0,0,0,0,0,0,0,
-1,139,192,127,248,0,0,0,0,0,0,138,192,127,240,0,0,0,0,0,0,139,64,255,240,0,
-0,0,0,0,0,0,31,241,128,149,224,0,0,0,0,0,0,0,0,13,71,96,37,25,120,148,86,
-16,69,23,73,19,92,36,73,124,129,71,255,0,56,136,233,34,3,223,208,241,192,3,
+214,164,2,90,81,17,104,67,37,157,8,150,100,18,89,78,201,100,60,37,140,244,
+150,35,226,88,79,201,96,71,37,125,20,122,188,138,62,0,2,165,70,39,255,255,
+193,43,67,0,0,80,127,192,58,182,220,80,0,21,59,170,64,0,107,77,8,172,181,
+146,176,202,138,187,59,42,204,200,170,182,146,168,218,80,0,26,155,97,42,77,
+68,168,181,20,0,6,160,210,74,123,89,64,0,127,255,4,10,153,219,157,70,163,
+185,130,140,228,10,43,160,40,141,228,161,184,18,132,226,64,161,127,128,0,
+63,225,1,109,74,8,137,71,58,5,4,221,20,3,147,233,249,193,240,80,255,192,6,
+120,2,64,127,195,0,173,28,56,20,96,80,128,0,206,192,143,167,64,164,156,131,
+2,112,14,125,55,9,4,216,40,19,80,180,77,3,9,51,13,94,153,7,159,76,64,207,
+192,0,102,0,103,255,255,242,240,67,73,112,33,168,0,12,180,16,212,0,10,88,8,
+106,0,7,43,4,53,0,4,149,4,31,128,0,202,66,15,255,255,194,137,254,0,50,135,
+227,224,127,196,2,87,132,17,82,143,24,10,44,96,36,240,4,147,64,146,119,4,
+125,49,131,52,152,65,154,128,0,201,97,9,36,133,36,142,25,18,40,114,77,98,
+17,33,137,68,130,45,17,247,240,71,159,193,29,127,8,0,12,113,252,32,0,49,
+184,208,70,162,144,20,95,240,0,7,252,80,37,120,193,81,196,194,0,3,69,19,0,
+81,191,197,140,192,127,239,255,255,255,255,255,255,140,64,0,0,0,0,0,0,0,1,
+139,192,127,248,0,0,0,0,0,0,138,192,127,240,0,0,0,0,0,0,139,64,255,240,0,0,
+0,0,0,0,0,31,241,128,149,224,0,0,0,0,0,0,0,0,13,71,98,37,25,128,148,86,48,
+69,23,201,19,94,36,73,132,129,71,255,0,56,136,233,34,3,223,208,241,192,3,
254,56,18,188,135,255,128,0,0,0,0,0,11,104,228,128,135,18,4,0,6,26,72,16,0,
42,49,32,64,0,225,132,129,0,4,133,146,4,0,21,210,72,16,0,103,65,32,64,1,
220,228,100,162,146,130,20,74,8,72,248,64,2,33,3,225,0,9,131,143,132,0,42,
@@ -12778,9 +12707,9 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
33,127,0,29,120,144,207,128,15,60,8,103,192,7,221,228,37,0,32,119,16,148,0,
133,218,66,190,0,68,236,33,95,0,35,117,144,191,128,18,58,136,95,192,9,92,
195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,64,192,2,2,225,
-132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,240,71,19,201,40,
-239,64,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,137,129,109,203,140,
-11,78,94,96,13,28,200,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47,
+132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,244,71,19,217,40,
+239,128,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,145,153,109,203,139,
+203,78,96,98,13,28,208,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47,
252,0,9,255,44,19,104,173,237,146,8,128,20,207,240,0,39,252,192,77,162,183,
54,72,34,0,83,127,192,0,159,243,65,54,138,218,217,32,136,1,78,255,0,2,127,
206,4,218,43,99,100,130,32,5,63,252,0,9,255,60,19,104,173,109,146,8,128,15,
@@ -12788,125 +12717,51 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
69,154,208,15,249,139,144,191,190,142,123,218,176,15,253,197,81,217,74,224,
191,154,144,15,246,242,222,197,73,185,67,154,112,16,2,72,126,213,17,11,70,
26,80,15,249,168,39,153,159,206,243,90,48,15,253,168,39,153,159,206,243,82,
-104,39,17,158,156,80,0,22,114,113,64,0,153,169,197,0,3,102,40,33,150,156,
-80,0,70,82,113,64,1,89,41,197,0,6,100,39,20,0,29,142,156,80,0,134,50,98,
-243,21,53,121,136,160,144,0,22,26,120,24,73,197,0,9,96,167,20,0,41,128,156,
-80,0,181,250,113,64,3,1,255,254,0,81,20,100,47,145,216,23,255,240,0,11,255,
-248,0,3,255,252,81,252,4,12,68,248,0,0,0,0,0,129,167,1,26,144,9,165,0,26,
-177,199,197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,
-32,84,223,192,15,59,30,129,156,115,6,81,160,7,253,40,0,5,81,252,0,1,255,78,
-0,84,113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,66,0,3,69,117,0,
-85,159,192,0,31,245,97,10,100,32,0,0,0,0,0,0,0,10,164,130,97,221,191,113,3,
-20,146,12,18,200,47,74,30,23,37,15,128,0,143,146,135,192,0,133,169,67,224,
-0,98,196,161,240,0,65,90,80,248,0,41,63,255,194,109,65,11,137,191,174,45,
-153,98,242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,
-228,131,70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,
-168,194,64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,
-139,164,0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,
-140,208,46,144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,
-208,2,19,24,203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,
-255,128,21,38,73,7,1,132,128,0,133,105,252,19,140,3,255,0,0,0,0,0,0,0,25,
-127,102,0,1,91,127,4,227,0,255,192,0,0,0,0,0,0,6,95,218,128,0,87,31,193,56,
-192,63,240,0,0,0,0,0,0,1,151,246,224,0,21,215,240,78,48,16,0,0,0,0,0,0,0,0,
-101,253,200,0,5,121,252,19,140,4,0,0,0,0,0,0,0,0,25,127,118,0,1,95,127,4,
-227,1,0,64,0,0,0,0,0,0,6,95,222,128,0,88,31,193,56,192,64,16,0,0,0,0,0,0,1,
-151,247,224,0,22,23,240,78,48,16,4,0,0,0,0,0,0,0,101,254,8,0,5,137,252,19,
-140,4,2,0,0,0,0,0,0,0,25,127,134,0,1,99,127,0,89,218,146,20,74,228,80,171,
-17,64,162,132,248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,
-72,0,10,92,93,32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,
-1,73,33,116,128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,
-2,35,69,210,0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,
-0,58,136,25,98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,
-12,101,160,3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,
-71,225,150,128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,
-128,2,158,70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,150,57,214,0,
-157,85,98,112,80,137,241,66,128,0,166,213,33,53,24,66,121,106,0,
+104,40,17,158,160,80,0,22,114,129,64,0,153,170,5,0,3,102,41,33,150,160,80,
+0,70,82,129,64,1,89,42,5,0,6,100,40,20,0,29,142,160,80,0,134,50,114,243,21,
+61,121,136,164,144,0,22,26,136,24,74,5,0,9,96,168,20,0,41,128,160,80,0,181,
+250,129,64,3,1,255,254,0,81,20,132,47,146,88,23,255,240,0,11,255,248,0,3,
+255,252,81,252,4,12,68,248,0,0,0,0,0,129,167,1,26,144,9,165,0,26,177,199,
+197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,32,84,
+223,192,15,59,34,129,156,131,6,81,224,7,253,40,0,5,81,252,0,1,255,78,0,84,
+113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,194,0,3,69,119,0,85,
+159,192,0,31,245,97,10,100,32,0,0,0,0,0,0,0,10,164,130,97,221,191,113,3,20,
+178,12,19,72,47,76,30,23,38,15,128,0,143,147,7,192,0,133,169,131,224,0,98,
+196,193,240,0,65,90,96,248,0,41,63,255,194,109,65,11,137,191,174,45,153,98,
+242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,228,131,
+70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,168,194,
+64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,139,164,
+0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,140,208,46,
+144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,208,2,19,24,
+203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,255,128,21,
+38,81,7,1,132,128,0,133,105,252,19,140,3,255,0,0,0,0,0,0,0,25,127,102,0,1,
+91,127,4,227,0,255,192,0,0,0,0,0,0,6,95,218,128,0,87,31,193,56,192,63,240,
+0,0,0,0,0,0,1,151,246,224,0,21,215,240,78,48,16,0,0,0,0,0,0,0,0,101,253,
+200,0,5,121,252,19,140,4,0,0,0,0,0,0,0,0,25,127,118,0,1,95,127,4,227,1,0,
+64,0,0,0,0,0,0,6,95,222,128,0,88,31,193,56,192,64,16,0,0,0,0,0,0,1,151,247,
+224,0,22,23,240,78,48,16,4,0,0,0,0,0,0,0,101,254,8,0,5,137,252,19,140,4,2,
+0,0,0,0,0,0,0,25,127,134,0,1,99,127,0,89,218,162,20,75,36,80,172,17,64,166,
+132,248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,72,0,10,
+92,93,32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,1,73,33,
+116,128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,2,35,69,
+210,0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,0,58,
+136,25,98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,12,
+101,160,3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,71,
+225,150,128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,128,
+2,158,70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,182,57,214,128,157,
+87,98,112,80,137,241,66,128,0,166,213,161,53,24,66,121,114,0,
};
#ifdef DUK_USE_BUILTIN_INITJS
-DUK_INTERNAL const duk_uint8_t duk_initjs_data[1757] = {
-47,42,10,32,42,32,32,73,110,105,116,32,99,111,100,101,32,102,111,114,32,
-108,101,103,97,99,121,32,99,111,109,112,97,116,105,98,105,108,105,116,121,
-46,10,32,42,10,32,42,32,32,67,111,109,112,97,116,105,98,105,108,105,116,
-121,32,112,114,111,112,101,114,116,105,101,115,32,47,32,119,114,97,112,112,
-101,114,32,102,117,110,99,116,105,111,110,115,32,104,101,114,101,32,97,108,
-108,111,119,32,68,117,107,116,97,112,101,32,116,111,32,114,101,109,97,105,
-110,10,32,42,32,32,99,111,109,112,97,116,105,98,108,101,32,102,111,114,32,
-117,115,101,114,32,99,111,100,101,32,119,104,101,110,32,99,111,114,101,32,
-102,101,97,116,117,114,101,115,32,97,114,101,32,99,104,97,110,103,101,100,
-44,32,119,105,116,104,111,117,116,32,98,117,114,100,101,110,105,110,103,10,
-32,42,32,32,116,104,101,32,109,97,105,110,32,67,32,99,111,100,101,32,119,
-105,116,104,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,115,116,
-117,102,102,46,10,32,42,10,32,42,32,32,84,104,105,115,32,102,105,108,101,
-32,105,115,32,109,105,110,105,102,105,101,100,32,119,105,116,104,32,85,103,
-108,105,102,121,74,83,32,111,114,32,116,104,101,32,99,108,111,115,117,114,
-101,32,99,111,109,112,105,108,101,114,46,32,32,66,111,116,104,32,119,105,
-108,108,10,32,42,32,32,114,101,110,97,109,101,32,118,97,114,105,97,98,108,
-101,115,44,32,114,101,109,111,118,101,32,99,111,109,109,101,110,116,115,44,
-32,97,110,100,32,97,114,101,32,99,108,101,118,101,114,32,101,110,111,117,
-103,104,32,116,111,32,100,114,111,112,32,97,110,121,10,32,42,32,32,34,105,
-102,32,40,102,97,108,115,101,41,32,123,32,46,46,46,32,125,34,32,98,108,111,
-99,107,115,32,97,108,116,111,103,101,116,104,101,114,44,32,115,111,32,116,
-104,97,116,39,115,32,97,110,32,101,102,102,101,99,116,105,118,101,32,119,
-97,121,32,116,111,10,32,42,32,32,100,105,115,97,98,108,101,32,99,117,114,
-114,101,110,116,108,121,32,117,110,110,101,101,100,101,100,32,99,111,100,
-101,46,10,32,42,47,10,10,40,102,117,110,99,116,105,111,110,40,71,44,32,68,
-41,32,123,10,32,32,32,32,39,117,115,101,32,115,116,114,105,99,116,39,59,10,
-10,32,32,32,32,102,117,110,99,116,105,111,110,32,100,101,102,40,111,98,106,
-101,99,116,44,32,110,97,109,101,44,32,118,97,108,117,101,41,32,123,10,32,
-32,32,32,32,32,32,32,79,98,106,101,99,116,46,100,101,102,105,110,101,80,
-114,111,112,101,114,116,121,40,111,98,106,101,99,116,44,32,110,97,109,101,
-44,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,118,97,108,117,101,58,32,
-118,97,108,117,101,44,10,32,32,32,32,32,32,32,32,32,32,32,32,119,114,105,
-116,97,98,108,101,58,32,116,114,117,101,44,10,32,32,32,32,32,32,32,32,32,
-32,32,32,101,110,117,109,101,114,97,98,108,101,58,32,102,97,108,115,101,44,
-10,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,102,105,103,117,114,97,
-98,108,101,58,32,116,114,117,101,10,32,32,32,32,32,32,32,32,125,41,59,10,
-32,32,32,32,125,10,10,32,32,32,32,102,117,110,99,116,105,111,110,32,100,
-101,102,68,40,110,97,109,101,44,32,118,97,108,117,101,41,32,123,10,32,32,
-32,32,32,32,32,32,100,101,102,40,68,44,32,110,97,109,101,44,32,118,97,108,
-117,101,41,59,10,32,32,32,32,125,10,10,32,32,32,32,47,47,32,67,111,109,112,
-97,116,105,98,105,108,105,116,121,32,102,111,114,32,39,99,111,110,115,111,
-108,101,46,108,111,103,39,46,10,32,32,32,32,105,102,32,40,102,97,108,115,
-101,41,32,123,10,32,32,32,32,32,32,32,32,99,111,110,115,111,108,101,32,61,
-32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,103,58,32,102,117,
-110,99,116,105,111,110,40,41,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,
-32,32,32,32,112,114,105,110,116,40,65,114,114,97,121,46,112,114,111,116,
-111,116,121,112,101,46,106,111,105,110,46,99,97,108,108,40,97,114,103,117,
-109,101,110,116,115,44,32,39,32,39,41,41,59,10,32,32,32,32,32,32,32,32,32,
-32,32,32,125,10,32,32,32,32,32,32,32,32,125,59,10,32,32,32,32,125,10,10,32,
-32,32,32,47,47,32,68,117,107,116,97,112,101,46,108,105,110,101,40,41,32,
-119,97,115,32,114,101,109,111,118,101,100,32,105,110,32,68,117,107,116,97,
-112,101,32,48,46,49,49,46,48,44,32,104,101,114,101,39,115,32,97,110,32,101,
-120,97,109,112,108,101,10,32,32,32,32,47,47,32,114,101,112,108,97,99,101,
-109,101,110,116,32,117,115,101,114,32,99,111,100,101,32,99,111,117,108,100,
-32,117,115,101,46,10,32,32,32,32,105,102,32,40,102,97,108,115,101,41,32,
-123,10,32,32,32,32,32,32,32,32,100,101,102,40,68,44,32,39,108,105,110,101,
-39,44,32,102,117,110,99,116,105,111,110,32,40,41,32,123,10,32,32,32,32,32,
-32,32,32,32,32,32,32,39,117,115,101,32,100,117,107,32,110,111,116,97,105,
-108,39,59,10,10,32,32,32,32,32,32,32,32,32,32,32,32,47,42,32,84,97,105,108,
-32,99,97,108,108,115,32,97,114,101,32,112,114,101,118,101,110,116,101,100,
-32,116,111,32,101,110,115,117,114,101,32,99,97,108,108,105,110,103,32,97,
-99,116,105,118,97,116,105,111,110,32,101,120,105,115,116,115,46,10,32,32,
-32,32,32,32,32,32,32,32,32,32,32,42,32,67,97,108,108,32,115,116,97,99,107,
-32,105,110,100,105,99,101,115,58,32,45,49,32,61,32,68,117,107,116,97,112,
-101,46,97,99,116,44,32,45,50,32,61,32,103,101,116,67,117,114,114,101,110,
-116,76,105,110,101,44,32,45,51,32,61,32,99,97,108,108,101,114,10,32,32,32,
-32,32,32,32,32,32,32,32,32,32,42,47,10,10,32,32,32,32,32,32,32,32,32,32,32,
-32,114,101,116,117,114,110,32,40,68,117,107,116,97,112,101,46,97,99,116,40,
-45,51,41,32,124,124,32,123,125,41,46,108,105,110,101,78,117,109,98,101,114,
-59,10,32,32,32,32,32,32,32,32,125,41,59,10,32,32,32,32,125,10,10,32,32,32,
-32,47,47,32,76,111,103,103,101,114,32,111,98,106,101,99,116,32,102,111,114,
-32,67,32,99,111,100,101,32,112,114,111,118,105,100,101,100,32,98,121,32,
-105,110,105,116,32,99,111,100,101,32,110,111,119,46,10,32,32,32,32,105,102,
-32,40,116,114,117,101,41,32,123,10,32,32,32,32,32,32,32,32,100,101,102,40,
-68,46,76,111,103,103,101,114,44,32,39,99,108,111,103,39,44,32,110,101,119,
-32,68,46,76,111,103,103,101,114,40,39,67,39,41,41,59,10,32,32,32,32,125,10,
-10,32,32,32,32,47,47,32,84,114,97,99,107,105,110,103,32,116,97,98,108,101,
-32,102,111,114,32,67,111,109,109,111,110,74,83,32,109,111,100,117,108,101,
-32,108,111,97,100,105,110,103,46,10,32,32,32,32,105,102,32,40,116,114,117,
-101,41,32,123,10,32,32,32,32,32,32,32,32,100,101,102,40,68,44,32,39,109,
-111,100,76,111,97,100,101,100,39,44,32,123,125,41,59,10,32,32,32,32,125,10,
-125,41,40,116,104,105,115,44,32,68,117,107,116,97,112,101,41,59,10,0,
+DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = {
+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,
+108,117,101,58,99,44,119,114,105,116,97,98,108,101,58,33,48,44,101,110,117,
+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,
};
#endif /* DUK_USE_BUILTIN_INITJS */
#elif defined(DUK_USE_DOUBLE_ME)
@@ -13031,20 +12886,20 @@ DUK_INTERNAL const duk_uint8_t duk_strings_data[2624] = {
32,76,71,64,156,217,161,180,34,6,64,208,198,36,78,50,20,20,92,204,50,44,
147,32,134,226,17,114,33,202,134,129,107,192,202,232,160,180,104,166,135,
52,72,40,144,213,33,178,152,26,34,56,163,105,44,104,146,116,139,77,43,34,
-98,57,38,116,72,179,60,93,97,206,56,52,240,242,56,163,168,34,74,185,3,45,
-142,133,144,150,68,206,81,44,18,145,68,230,202,100,35,104,195,18,239,116,
-102,114,94,100,104,228,100,49,238,140,203,42,60,145,35,104,181,146,113,161,
-10,80,46,68,82,24,245,145,132,108,228,148,54,100,137,64,34,13,100,153,222,
-1,40,6,33,223,20,84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104,
-17,112,130,44,96,
+98,57,38,116,72,179,60,93,97,206,56,52,240,242,56,163,168,34,81,57,178,153,
+42,228,12,182,58,22,66,89,19,57,68,176,74,68,35,104,195,18,239,116,102,114,
+94,100,104,228,100,49,238,140,203,42,60,145,35,104,181,146,113,161,10,80,
+46,68,82,24,245,145,132,108,228,148,54,100,137,64,34,13,100,153,222,1,40,6,
+33,223,20,84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104,17,112,
+130,44,96,
};
/* to convert a heap stridx to a token number, subtract
* DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
*/
-/* native functions: 147 */
-DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = {
+/* native functions: 149 */
+DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_array_constructor,
duk_bi_array_constructor_is_array,
duk_bi_array_prototype_concat,
@@ -13092,9 +12947,11 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = {
duk_bi_duktape_object_info,
duk_bi_error_constructor_shared,
duk_bi_error_prototype_filename_getter,
+ duk_bi_error_prototype_filename_setter,
duk_bi_error_prototype_linenumber_getter,
- duk_bi_error_prototype_nop_setter,
+ duk_bi_error_prototype_linenumber_setter,
duk_bi_error_prototype_stack_getter,
+ duk_bi_error_prototype_stack_setter,
duk_bi_error_prototype_to_string,
duk_bi_function_constructor,
duk_bi_function_prototype,
@@ -13195,38 +13052,38 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = {
};
DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
-105,195,75,16,121,40,105,51,14,252,104,52,8,131,72,0,115,225,65,165,236,55,
-243,6,145,32,210,24,210,182,25,249,35,120,216,99,226,13,78,225,116,177,164,
+105,195,75,32,121,40,105,53,14,252,104,54,8,131,72,0,115,225,65,165,244,55,
+243,6,145,32,210,24,210,186,25,249,35,120,216,99,226,13,79,33,116,177,164,
180,44,192,4,202,52,150,220,24,0,169,70,146,219,123,0,23,40,210,91,110,96,
3,37,26,75,109,172,0,108,163,73,109,177,128,14,148,105,45,181,176,1,242,
-144,56,209,32,94,6,167,101,98,80,211,24,1,250,67,72,168,67,232,13,46,128,
-47,162,52,164,0,62,80,163,72,128,61,40,107,26,7,37,20,53,200,131,88,0,66,
-134,185,16,98,80,215,34,11,96,0,138,26,228,65,76,0,69,67,92,136,37,128,6,
-168,107,145,4,48,1,165,13,114,32,118,0,44,161,174,68,12,192,7,148,53,200,
-129,88,1,26,134,165,48,130,80,31,255,241,69,224,0,0,124,63,128,0,0,0,46,32,
+144,56,209,36,94,6,167,133,98,80,211,28,1,250,67,72,168,67,232,13,46,192,
+47,162,52,165,0,62,80,163,72,128,61,40,107,26,7,37,20,53,201,131,88,0,66,
+134,185,48,98,80,215,38,11,96,0,138,26,228,193,76,0,69,67,92,152,37,128,6,
+168,107,147,4,48,1,165,13,114,96,118,0,44,161,174,76,12,192,7,148,53,201,
+129,88,1,26,134,165,80,130,80,31,255,241,69,224,0,0,124,63,128,0,0,0,46,32,
0,0,120,63,128,0,0,0,47,98,7,140,16,116,194,7,12,48,108,196,6,140,80,100,
198,6,12,112,92,200,5,140,149,192,202,91,204,181,184,204,91,76,213,176,206,
90,204,240,84,208,5,13,9,124,210,43,13,24,64,226,131,205,112,56,216,3,77,
152,48,218,130,205,184,40,220,130,77,216,32,222,129,205,248,24,224,129,78,
-25,214,163,226,90,80,145,104,65,37,157,0,150,99,242,89,78,73,100,58,37,140,
-236,150,35,194,88,79,73,96,69,37,125,12,122,188,134,62,0,2,165,68,39,255,
-255,193,43,67,0,0,80,127,192,58,182,216,80,0,21,59,154,64,0,107,76,200,172,
-180,146,176,198,138,187,43,42,204,136,170,181,146,168,214,80,0,26,155,81,
-42,77,4,168,180,20,0,6,160,206,74,123,73,64,0,127,255,4,10,153,219,28,198,
-163,184,130,140,224,10,43,144,40,141,164,161,183,18,132,222,64,161,127,128,
-0,63,225,1,109,74,8,137,71,56,5,4,213,20,3,115,233,249,177,240,80,255,192,
+25,214,164,2,90,81,17,104,67,37,157,8,150,100,18,89,78,201,100,60,37,140,
+244,150,35,226,88,79,201,96,71,37,125,20,122,188,138,62,0,2,165,70,39,255,
+255,193,43,67,0,0,80,127,192,58,182,220,80,0,21,59,170,64,0,107,77,8,172,
+181,146,176,202,138,187,59,42,204,200,170,182,146,168,218,80,0,26,155,97,
+42,77,68,168,181,20,0,6,160,210,74,123,89,64,0,127,255,4,10,153,219,157,70,
+163,185,130,140,228,10,43,160,40,141,228,161,184,18,132,226,64,161,127,128,
+0,63,225,1,109,74,8,137,71,58,5,4,221,20,3,147,233,249,193,240,80,255,192,
6,120,2,64,127,195,0,173,28,56,20,96,80,128,0,206,192,143,167,64,164,156,
131,2,112,14,125,55,9,4,216,40,19,80,180,77,3,9,51,13,94,153,7,159,76,64,
207,192,0,102,0,103,255,255,242,240,67,73,112,33,168,0,12,180,16,212,0,10,
88,8,106,0,7,43,4,53,0,4,149,4,31,128,0,202,66,15,255,255,194,137,254,0,50,
-135,195,224,127,196,2,87,132,17,82,143,20,10,44,80,36,239,196,147,63,146,
-119,0,125,49,129,52,152,64,154,128,0,201,96,137,36,131,36,142,17,18,40,82,
-77,97,145,33,135,68,130,37,17,247,208,71,159,65,29,125,8,0,12,113,244,32,0,
-49,184,176,70,162,16,20,95,240,0,7,252,80,37,120,193,81,196,194,0,3,69,19,
-0,81,191,197,140,192,255,255,239,127,255,255,255,255,140,64,0,0,0,0,1,0,0,
-0,139,192,0,0,248,127,0,0,0,0,138,192,0,0,240,127,0,0,0,0,139,64,0,0,240,
-255,0,0,0,0,0,31,241,128,149,224,0,0,0,0,0,0,0,0,13,71,96,37,25,120,148,86,
-16,69,23,73,19,92,36,73,124,129,71,255,0,56,136,233,34,3,223,208,241,192,3,
+135,227,224,127,196,2,87,132,17,82,143,24,10,44,96,36,240,4,147,64,146,119,
+4,125,49,131,52,152,65,154,128,0,201,97,9,36,133,36,142,25,18,40,114,77,98,
+17,33,137,68,130,45,17,247,240,71,159,193,29,127,8,0,12,113,252,32,0,49,
+184,208,70,162,144,20,95,240,0,7,252,80,37,120,193,81,196,194,0,3,69,19,0,
+81,191,197,140,192,255,255,239,127,255,255,255,255,140,64,0,0,0,0,1,0,0,0,
+139,192,0,0,248,127,0,0,0,0,138,192,0,0,240,127,0,0,0,0,139,64,0,0,240,255,
+0,0,0,0,0,31,241,128,149,224,0,0,0,0,0,0,0,0,13,71,98,37,25,128,148,86,48,
+69,23,201,19,94,36,73,132,129,71,255,0,56,136,233,34,3,223,208,241,192,3,
254,56,18,188,128,0,15,135,240,0,0,0,11,104,228,128,135,18,4,0,6,26,72,16,
0,42,49,32,64,0,225,132,129,0,4,133,146,4,0,21,210,72,16,0,103,65,32,64,1,
220,228,100,162,146,130,20,74,8,72,248,64,2,33,3,225,0,9,131,143,132,0,42,
@@ -13237,9 +13094,9 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
33,127,0,29,120,144,207,128,15,60,8,103,192,7,221,228,37,0,32,119,16,148,0,
133,218,66,190,0,68,236,33,95,0,35,117,144,191,128,18,58,136,95,192,9,92,
195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,64,192,2,2,225,
-132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,240,71,19,201,40,
-239,64,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,137,129,109,203,140,
-11,78,94,96,13,28,200,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47,
+132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,244,71,19,217,40,
+239,128,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,145,153,109,203,139,
+203,78,96,98,13,28,208,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47,
252,0,9,255,44,19,104,173,237,146,8,128,20,207,240,0,39,252,192,77,162,183,
54,72,34,0,83,127,192,0,159,243,65,54,138,218,217,32,136,1,78,255,0,2,127,
206,4,218,43,99,100,130,32,5,63,252,0,9,255,60,19,104,173,109,146,8,128,15,
@@ -13247,126 +13104,51 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
110,218,208,16,139,185,143,251,206,126,191,154,176,17,197,125,207,255,160,
138,217,90,144,30,242,246,207,195,185,73,133,90,112,62,200,66,80,6,11,81,
21,26,80,39,168,57,143,243,78,223,217,154,48,39,168,61,143,243,78,223,217,
-146,104,39,17,158,156,80,0,22,114,113,64,0,153,169,197,0,3,102,40,33,150,
-156,80,0,70,82,113,64,1,89,41,197,0,6,100,39,20,0,29,142,156,80,0,134,50,
-98,243,21,53,121,136,160,144,0,22,26,120,24,73,197,0,9,96,167,20,0,41,128,
-156,80,0,181,250,113,64,3,1,255,254,0,81,20,100,47,145,216,23,255,240,0,11,
-255,248,0,3,255,252,81,252,8,4,252,68,0,0,0,0,0,129,167,1,26,144,9,165,0,
-26,177,199,197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,
-39,32,84,223,192,15,59,30,129,156,115,6,81,160,7,253,40,0,5,81,252,0,1,255,
-78,0,84,113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,66,0,3,69,
-117,0,85,159,192,0,31,245,97,10,100,0,0,0,32,0,0,0,0,10,164,130,97,221,191,
-113,3,20,146,12,18,200,47,74,30,23,37,15,128,0,143,146,135,192,0,133,169,
-67,224,0,98,196,161,240,0,65,90,80,248,0,41,63,255,194,109,65,11,137,191,
-174,45,153,98,242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,
-185,111,228,131,70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,
-174,0,25,168,194,64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,
-0,32,54,139,164,0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,
-164,0,140,208,46,144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,
-50,208,2,19,24,203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,
-127,255,128,21,38,73,7,1,132,128,0,133,105,252,19,140,0,0,15,3,240,0,0,0,0,
-25,127,102,0,1,91,127,4,227,0,0,3,192,252,0,0,0,0,6,95,218,128,0,87,31,193,
-56,192,0,0,240,63,0,0,0,0,1,151,246,224,0,21,215,240,78,48,0,0,0,16,0,0,0,
-0,0,101,253,200,0,5,121,252,19,140,0,0,0,4,0,0,0,0,0,25,127,118,0,1,95,127,
-4,227,0,0,0,65,0,0,0,0,0,6,95,222,128,0,88,31,193,56,192,0,0,16,64,0,0,0,0,
-1,151,247,224,0,22,23,240,78,48,0,0,4,16,0,0,0,0,0,101,254,8,0,5,137,252,
-19,140,0,0,2,4,0,0,0,0,0,25,127,134,0,1,99,127,0,89,218,146,20,74,228,80,
-171,17,64,162,132,248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,
-152,23,72,0,10,92,93,32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,
-76,93,32,1,73,33,116,128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,
-225,116,128,2,35,69,210,0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,
-10,162,69,218,0,58,136,25,98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,
-132,25,104,0,138,12,101,160,3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,
-145,252,101,160,3,71,225,150,128,1,159,70,90,0,22,124,25,104,0,33,236,101,
-160,1,135,161,152,128,2,158,70,98,0,26,120,25,136,0,169,220,102,32,3,180,
-117,150,57,214,0,157,85,98,112,80,137,241,66,128,0,166,213,33,53,24,66,121,
-106,0,
+146,104,40,17,158,160,80,0,22,114,129,64,0,153,170,5,0,3,102,41,33,150,160,
+80,0,70,82,129,64,1,89,42,5,0,6,100,40,20,0,29,142,160,80,0,134,50,114,243,
+21,61,121,136,164,144,0,22,26,136,24,74,5,0,9,96,168,20,0,41,128,160,80,0,
+181,250,129,64,3,1,255,254,0,81,20,132,47,146,88,23,255,240,0,11,255,248,0,
+3,255,252,81,252,8,4,252,68,0,0,0,0,0,129,167,1,26,144,9,165,0,26,177,199,
+197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,32,84,
+223,192,15,59,34,129,156,131,6,81,224,7,253,40,0,5,81,252,0,1,255,78,0,84,
+113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,194,0,3,69,119,0,85,
+159,192,0,31,245,97,10,100,0,0,0,32,0,0,0,0,10,164,130,97,221,191,113,3,20,
+178,12,19,72,47,76,30,23,38,15,128,0,143,147,7,192,0,133,169,131,224,0,98,
+196,193,240,0,65,90,96,248,0,41,63,255,194,109,65,11,137,191,174,45,153,98,
+242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,228,131,
+70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,168,194,
+64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,139,164,
+0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,140,208,46,
+144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,208,2,19,24,
+203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,255,128,21,
+38,81,7,1,132,128,0,133,105,252,19,140,0,0,15,3,240,0,0,0,0,25,127,102,0,1,
+91,127,4,227,0,0,3,192,252,0,0,0,0,6,95,218,128,0,87,31,193,56,192,0,0,240,
+63,0,0,0,0,1,151,246,224,0,21,215,240,78,48,0,0,0,16,0,0,0,0,0,101,253,200,
+0,5,121,252,19,140,0,0,0,4,0,0,0,0,0,25,127,118,0,1,95,127,4,227,0,0,0,65,
+0,0,0,0,0,6,95,222,128,0,88,31,193,56,192,0,0,16,64,0,0,0,0,1,151,247,224,
+0,22,23,240,78,48,0,0,4,16,0,0,0,0,0,101,254,8,0,5,137,252,19,140,0,0,2,4,
+0,0,0,0,0,25,127,134,0,1,99,127,0,89,218,162,20,75,36,80,172,17,64,166,132,
+248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,72,0,10,92,93,
+32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,1,73,33,116,
+128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,2,35,69,210,
+0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,0,58,136,25,
+98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,12,101,160,
+3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,71,225,150,
+128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,128,2,158,
+70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,182,57,214,128,157,87,98,
+112,80,137,241,66,128,0,166,213,161,53,24,66,121,114,0,
};
#ifdef DUK_USE_BUILTIN_INITJS
-DUK_INTERNAL const duk_uint8_t duk_initjs_data[1757] = {
-47,42,10,32,42,32,32,73,110,105,116,32,99,111,100,101,32,102,111,114,32,
-108,101,103,97,99,121,32,99,111,109,112,97,116,105,98,105,108,105,116,121,
-46,10,32,42,10,32,42,32,32,67,111,109,112,97,116,105,98,105,108,105,116,
-121,32,112,114,111,112,101,114,116,105,101,115,32,47,32,119,114,97,112,112,
-101,114,32,102,117,110,99,116,105,111,110,115,32,104,101,114,101,32,97,108,
-108,111,119,32,68,117,107,116,97,112,101,32,116,111,32,114,101,109,97,105,
-110,10,32,42,32,32,99,111,109,112,97,116,105,98,108,101,32,102,111,114,32,
-117,115,101,114,32,99,111,100,101,32,119,104,101,110,32,99,111,114,101,32,
-102,101,97,116,117,114,101,115,32,97,114,101,32,99,104,97,110,103,101,100,
-44,32,119,105,116,104,111,117,116,32,98,117,114,100,101,110,105,110,103,10,
-32,42,32,32,116,104,101,32,109,97,105,110,32,67,32,99,111,100,101,32,119,
-105,116,104,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,115,116,
-117,102,102,46,10,32,42,10,32,42,32,32,84,104,105,115,32,102,105,108,101,
-32,105,115,32,109,105,110,105,102,105,101,100,32,119,105,116,104,32,85,103,
-108,105,102,121,74,83,32,111,114,32,116,104,101,32,99,108,111,115,117,114,
-101,32,99,111,109,112,105,108,101,114,46,32,32,66,111,116,104,32,119,105,
-108,108,10,32,42,32,32,114,101,110,97,109,101,32,118,97,114,105,97,98,108,
-101,115,44,32,114,101,109,111,118,101,32,99,111,109,109,101,110,116,115,44,
-32,97,110,100,32,97,114,101,32,99,108,101,118,101,114,32,101,110,111,117,
-103,104,32,116,111,32,100,114,111,112,32,97,110,121,10,32,42,32,32,34,105,
-102,32,40,102,97,108,115,101,41,32,123,32,46,46,46,32,125,34,32,98,108,111,
-99,107,115,32,97,108,116,111,103,101,116,104,101,114,44,32,115,111,32,116,
-104,97,116,39,115,32,97,110,32,101,102,102,101,99,116,105,118,101,32,119,
-97,121,32,116,111,10,32,42,32,32,100,105,115,97,98,108,101,32,99,117,114,
-114,101,110,116,108,121,32,117,110,110,101,101,100,101,100,32,99,111,100,
-101,46,10,32,42,47,10,10,40,102,117,110,99,116,105,111,110,40,71,44,32,68,
-41,32,123,10,32,32,32,32,39,117,115,101,32,115,116,114,105,99,116,39,59,10,
-10,32,32,32,32,102,117,110,99,116,105,111,110,32,100,101,102,40,111,98,106,
-101,99,116,44,32,110,97,109,101,44,32,118,97,108,117,101,41,32,123,10,32,
-32,32,32,32,32,32,32,79,98,106,101,99,116,46,100,101,102,105,110,101,80,
-114,111,112,101,114,116,121,40,111,98,106,101,99,116,44,32,110,97,109,101,
-44,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,118,97,108,117,101,58,32,
-118,97,108,117,101,44,10,32,32,32,32,32,32,32,32,32,32,32,32,119,114,105,
-116,97,98,108,101,58,32,116,114,117,101,44,10,32,32,32,32,32,32,32,32,32,
-32,32,32,101,110,117,109,101,114,97,98,108,101,58,32,102,97,108,115,101,44,
-10,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,102,105,103,117,114,97,
-98,108,101,58,32,116,114,117,101,10,32,32,32,32,32,32,32,32,125,41,59,10,
-32,32,32,32,125,10,10,32,32,32,32,102,117,110,99,116,105,111,110,32,100,
-101,102,68,40,110,97,109,101,44,32,118,97,108,117,101,41,32,123,10,32,32,
-32,32,32,32,32,32,100,101,102,40,68,44,32,110,97,109,101,44,32,118,97,108,
-117,101,41,59,10,32,32,32,32,125,10,10,32,32,32,32,47,47,32,67,111,109,112,
-97,116,105,98,105,108,105,116,121,32,102,111,114,32,39,99,111,110,115,111,
-108,101,46,108,111,103,39,46,10,32,32,32,32,105,102,32,40,102,97,108,115,
-101,41,32,123,10,32,32,32,32,32,32,32,32,99,111,110,115,111,108,101,32,61,
-32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,103,58,32,102,117,
-110,99,116,105,111,110,40,41,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,
-32,32,32,32,112,114,105,110,116,40,65,114,114,97,121,46,112,114,111,116,
-111,116,121,112,101,46,106,111,105,110,46,99,97,108,108,40,97,114,103,117,
-109,101,110,116,115,44,32,39,32,39,41,41,59,10,32,32,32,32,32,32,32,32,32,
-32,32,32,125,10,32,32,32,32,32,32,32,32,125,59,10,32,32,32,32,125,10,10,32,
-32,32,32,47,47,32,68,117,107,116,97,112,101,46,108,105,110,101,40,41,32,
-119,97,115,32,114,101,109,111,118,101,100,32,105,110,32,68,117,107,116,97,
-112,101,32,48,46,49,49,46,48,44,32,104,101,114,101,39,115,32,97,110,32,101,
-120,97,109,112,108,101,10,32,32,32,32,47,47,32,114,101,112,108,97,99,101,
-109,101,110,116,32,117,115,101,114,32,99,111,100,101,32,99,111,117,108,100,
-32,117,115,101,46,10,32,32,32,32,105,102,32,40,102,97,108,115,101,41,32,
-123,10,32,32,32,32,32,32,32,32,100,101,102,40,68,44,32,39,108,105,110,101,
-39,44,32,102,117,110,99,116,105,111,110,32,40,41,32,123,10,32,32,32,32,32,
-32,32,32,32,32,32,32,39,117,115,101,32,100,117,107,32,110,111,116,97,105,
-108,39,59,10,10,32,32,32,32,32,32,32,32,32,32,32,32,47,42,32,84,97,105,108,
-32,99,97,108,108,115,32,97,114,101,32,112,114,101,118,101,110,116,101,100,
-32,116,111,32,101,110,115,117,114,101,32,99,97,108,108,105,110,103,32,97,
-99,116,105,118,97,116,105,111,110,32,101,120,105,115,116,115,46,10,32,32,
-32,32,32,32,32,32,32,32,32,32,32,42,32,67,97,108,108,32,115,116,97,99,107,
-32,105,110,100,105,99,101,115,58,32,45,49,32,61,32,68,117,107,116,97,112,
-101,46,97,99,116,44,32,45,50,32,61,32,103,101,116,67,117,114,114,101,110,
-116,76,105,110,101,44,32,45,51,32,61,32,99,97,108,108,101,114,10,32,32,32,
-32,32,32,32,32,32,32,32,32,32,42,47,10,10,32,32,32,32,32,32,32,32,32,32,32,
-32,114,101,116,117,114,110,32,40,68,117,107,116,97,112,101,46,97,99,116,40,
-45,51,41,32,124,124,32,123,125,41,46,108,105,110,101,78,117,109,98,101,114,
-59,10,32,32,32,32,32,32,32,32,125,41,59,10,32,32,32,32,125,10,10,32,32,32,
-32,47,47,32,76,111,103,103,101,114,32,111,98,106,101,99,116,32,102,111,114,
-32,67,32,99,111,100,101,32,112,114,111,118,105,100,101,100,32,98,121,32,
-105,110,105,116,32,99,111,100,101,32,110,111,119,46,10,32,32,32,32,105,102,
-32,40,116,114,117,101,41,32,123,10,32,32,32,32,32,32,32,32,100,101,102,40,
-68,46,76,111,103,103,101,114,44,32,39,99,108,111,103,39,44,32,110,101,119,
-32,68,46,76,111,103,103,101,114,40,39,67,39,41,41,59,10,32,32,32,32,125,10,
-10,32,32,32,32,47,47,32,84,114,97,99,107,105,110,103,32,116,97,98,108,101,
-32,102,111,114,32,67,111,109,109,111,110,74,83,32,109,111,100,117,108,101,
-32,108,111,97,100,105,110,103,46,10,32,32,32,32,105,102,32,40,116,114,117,
-101,41,32,123,10,32,32,32,32,32,32,32,32,100,101,102,40,68,44,32,39,109,
-111,100,76,111,97,100,101,100,39,44,32,123,125,41,59,10,32,32,32,32,125,10,
-125,41,40,116,104,105,115,44,32,68,117,107,116,97,112,101,41,59,10,0,
+DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = {
+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,
+108,117,101,58,99,44,119,114,105,116,97,98,108,101,58,33,48,44,101,110,117,
+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,
};
#endif /* DUK_USE_BUILTIN_INITJS */
#else
@@ -13381,9 +13163,9 @@ DUK_INTERNAL const duk_uint8_t duk_initjs_data[1757] = {
#define DUK__ERRFMT_BUFSIZE 256 /* size for formatting buffers */
-#ifdef DUK_USE_VERBOSE_ERRORS
+#if defined(DUK_USE_VERBOSE_ERRORS)
-#ifdef DUK_USE_VARIADIC_MACROS
+#if defined(DUK_USE_VARIADIC_MACROS)
DUK_INTERNAL void duk_err_handle_error(const char *filename, duk_int_t line, duk_hthread *thr, duk_errcode_t code, const char *fmt, ...) {
va_list ap;
char msg[DUK__ERRFMT_BUFSIZE];
@@ -13423,7 +13205,7 @@ DUK_INTERNAL void duk_err_handle_error_stash(duk_hthread *thr, duk_errcode_t cod
#else /* DUK_USE_VERBOSE_ERRORS */
-#ifdef DUK_USE_VARIADIC_MACROS
+#if defined(DUK_USE_VARIADIC_MACROS)
DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) {
duk_err_create_and_throw(thr, code);
}
@@ -13445,12 +13227,49 @@ DUK_INTERNAL void duk_err_handle_error_nonverbose2(const char *filename, duk_int
#endif /* DUK_USE_VERBOSE_ERRORS */
/*
+ * Error throwing helpers
+ */
+
+#if defined(DUK_USE_VERBOSE_ERRORS)
+#if defined(DUK_USE_PARANOID_ERRORS)
+DUK_INTERNAL void duk_err_require_type_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, duk_idx_t index, const char *expect_name) {
+ DUK_ERROR_RAW(filename, linenumber, thr, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
+ expect_name, duk_get_type_name((duk_context *) thr, index), (long) index);
+}
+#else
+DUK_INTERNAL void duk_err_require_type_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, duk_idx_t index, const char *expect_name) {
+ DUK_ERROR_RAW(filename, linenumber, thr, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
+ expect_name, duk_push_string_readable((duk_context *) thr, index), (long) index);
+}
+#endif
+DUK_INTERNAL void duk_err_api_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, duk_idx_t index) {
+ DUK_ERROR_RAW(filename, linenumber, thr, DUK_ERR_API_ERROR, "invalid stack index %ld", (long) (index));
+}
+DUK_INTERNAL void duk_err_api(const char *filename, duk_int_t linenumber, duk_hthread *thr, const char *message) {
+ DUK_ERROR_RAW(filename, linenumber, thr, DUK_ERR_API_ERROR, message);
+}
+#else
+DUK_INTERNAL void duk_err_require_type_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, const char *message) {
+ DUK_UNREF(filename); DUK_UNREF(linenumber); DUK_UNREF(message);
+ DUK_ERROR_RAW(filename, linenumber, thr, DUK_ERR_TYPE_ERROR, message);
+}
+DUK_INTERNAL void duk_err_api_index(const char *filename, duk_int_t linenumber, duk_hthread *thr) {
+ DUK_UNREF(filename); DUK_UNREF(linenumber);
+ DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_INDEX);
+}
+DUK_INTERNAL void duk_err_api(const char *filename, duk_int_t linenumber, duk_hthread *thr, const char *message) {
+ DUK_UNREF(filename); DUK_UNREF(linenumber); DUK_UNREF(message);
+ DUK_ERROR_RAW(filename, linenumber, thr, DUK_ERR_API_ERROR, message);
+}
+#endif
+
+/*
* Default fatal error handler
*/
DUK_INTERNAL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg) {
DUK_UNREF(ctx);
-#ifdef DUK_USE_FILE_IO
+#if defined(DUK_USE_FILE_IO)
DUK_FPRINTF(DUK_STDERR, "FATAL %ld: %s\n", (long) code, (const char *) (msg ? msg : "null"));
DUK_FFLUSH(DUK_STDERR);
#else
@@ -13467,7 +13286,7 @@ DUK_INTERNAL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code
#if !defined(DUK_USE_PANIC_HANDLER)
DUK_INTERNAL void duk_default_panic_handler(duk_errcode_t code, const char *msg) {
-#ifdef DUK_USE_FILE_IO
+#if defined(DUK_USE_FILE_IO)
DUK_FPRINTF(DUK_STDERR, "PANIC %ld: %s ("
#if defined(DUK_USE_PANIC_ABORT)
"calling abort"
@@ -13760,26 +13579,117 @@ DUK_INTERNAL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr,
return 0;
}
-/* (extended) utf-8 length without codepoint encoding validation, used
- * for string interning (should probably be inlined).
+/* Compute (extended) utf-8 length without codepoint encoding validation,
+ * used for string interning.
+ *
+ * NOTE: This algorithm is performance critical, more so than string hashing
+ * in some cases. It is needed when interning a string and needs to scan
+ * every byte of the string with no skipping. Having an ASCII fast path
+ * is useful if possible in the algorithm. The current algorithms were
+ * chosen from several variants, based on x64 gcc -O2 testing. See:
+ * https://github.com/svaarala/duktape/pull/422
*/
+
+#if defined(DUK_USE_PREFER_SIZE)
+/* Small variant; roughly 150 bytes smaller than the fast variant. */
DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) {
- const duk_uint8_t *p = data;
- const duk_uint8_t *p_end = data + blen;
- duk_size_t clen = 0;
+ const duk_uint8_t *p;
+ const duk_uint8_t *p_end;
+ duk_size_t ncont;
+ duk_size_t clen;
- while (p < p_end) {
- duk_uint8_t x = *p++;
- if (x < 0x80 || x >= 0xc0) {
- /* 10xxxxxx = continuation chars (0x80...0xbf), above
- * and below that initial bytes.
+ p = data;
+ p_end = data + blen;
+ ncont = 0;
+ while (p != p_end) {
+ duk_uint8_t x;
+ x = *p++;
+ if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
+ ncont++;
+ }
+ }
+
+ DUK_ASSERT(ncont <= blen);
+ clen = blen - ncont;
+ DUK_ASSERT(clen <= blen);
+ return clen;
+}
+#else /* DUK_USE_PREFER_SIZE */
+/* This seems like a good overall approach. Fast path for ASCII in 4 byte
+ * blocks.
+ */
+DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) {
+ const duk_uint8_t *p;
+ const duk_uint8_t *p_end;
+ const duk_uint32_t *p32_end;
+ const duk_uint32_t *p32;
+ duk_size_t ncont;
+ duk_size_t clen;
+
+ ncont = 0; /* number of continuation (non-initial) bytes in [0x80,0xbf] */
+ p = data;
+ p_end = data + blen;
+ if (blen < 16) {
+ goto skip_fastpath;
+ }
+
+ /* Align 'p' to 4; the input data may have arbitrary alignment.
+ * End of string check not needed because blen >= 16.
+ */
+ while (((duk_uintptr_t) (const void *) p) & 0x03) {
+ duk_uint8_t x;
+ x = *p++;
+ if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
+ ncont++;
+ }
+ }
+
+ /* Full, aligned 4-byte reads. */
+ p32_end = (const duk_uint32_t *) (const void *) (p + ((duk_size_t) (p_end - p) & (duk_size_t) (~0x03)));
+ p32 = (const duk_uint32_t *) (const void *) p;
+ while (p32 != (const duk_uint32_t *) p32_end) {
+ duk_uint32_t x;
+ x = *p32++;
+ if (DUK_LIKELY((x & 0x80808080UL) == 0)) {
+ ; /* ASCII fast path */
+ } else {
+ /* Flip highest bit of each byte which changes
+ * the bit pattern 10xxxxxx into 00xxxxxx which
+ * allows an easy bit mask test.
*/
- clen++;
+ x ^= 0x80808080UL;
+ if (DUK_UNLIKELY(!(x & 0xc0000000UL))) {
+ ncont++;
+ }
+ if (DUK_UNLIKELY(!(x & 0x00c00000UL))) {
+ ncont++;
+ }
+ if (DUK_UNLIKELY(!(x & 0x0000c000UL))) {
+ ncont++;
+ }
+ if (DUK_UNLIKELY(!(x & 0x000000c0UL))) {
+ ncont++;
+ }
+ }
+ }
+ p = (const duk_uint8_t *) p32;
+ /* Fall through to handle the rest. */
+
+ skip_fastpath:
+ while (p != p_end) {
+ duk_uint8_t x;
+ x = *p++;
+ if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
+ ncont++;
}
}
+ DUK_ASSERT(ncont <= blen);
+ clen = blen - ncont;
+ DUK_ASSERT(clen <= blen);
return clen;
}
+#endif /* DUK_USE_PREFER_SIZE */
/*
* Unicode range matcher
@@ -13814,7 +13724,7 @@ DUK_LOCAL duk_small_int_t duk__uni_range_match(const duk_uint8_t *unitab, duk_si
duk_codepoint_t prev_re;
DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
- bd_ctx.data = (duk_uint8_t *) unitab;
+ bd_ctx.data = (const duk_uint8_t *) unitab;
bd_ctx.length = (duk_size_t) unilen;
prev_re = 0;
@@ -14359,10 +14269,10 @@ duk_codepoint_t duk__case_transform_helper(duk_hthread *thr,
/* 1:1 or special conversions, but not locale/context specific: script generated rules */
DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
if (uppercase) {
- bd_ctx.data = (duk_uint8_t *) duk_unicode_caseconv_uc;
+ bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_uc;
bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_uc);
} else {
- bd_ctx.data = (duk_uint8_t *) duk_unicode_caseconv_lc;
+ bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_lc;
bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_lc);
}
return duk__slow_case_conversion(thr, bw, cp, &bd_ctx);
@@ -14400,7 +14310,7 @@ DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_in
/* [ ... input buffer ] */
- p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
+ p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
p = p_start;
@@ -14453,14 +14363,15 @@ DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_in
*/
DUK_INTERNAL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp) {
-#if 1 /* FIXME */
+#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
/* Fast canonicalization lookup at the cost of 128kB footprint. */
DUK_ASSERT(cp >= 0);
+ DUK_UNREF(thr);
if (DUK_LIKELY(cp < 0x10000L)) {
return (duk_codepoint_t) duk_unicode_re_canon_lookup[cp];
}
return cp;
-#else
+#else /* DUK_USE_REGEXP_CANON_WORKAROUND */
duk_codepoint_t y;
y = duk__case_transform_helper(thr,
@@ -14478,7 +14389,7 @@ DUK_INTERNAL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr,
}
return y;
-#endif
+#endif /* DUK_USE_REGEXP_CANON_WORKAROUND */
}
/*
@@ -14566,24 +14477,31 @@ DUK_INTERNAL duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = {
* hex nybble table.
*/
-DUK_INTERNAL duk_uint8_t duk_lc_digits[36] = {
- '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
- 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
- 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
- 'w', 'x', 'y', 'z'
+DUK_INTERNAL const duk_uint8_t duk_lc_digits[36] = {
+ DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
+ DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
+ DUK_ASC_8, DUK_ASC_9, DUK_ASC_LC_A, DUK_ASC_LC_B,
+ DUK_ASC_LC_C, DUK_ASC_LC_D, DUK_ASC_LC_E, DUK_ASC_LC_F,
+ DUK_ASC_LC_G, DUK_ASC_LC_H, DUK_ASC_LC_I, DUK_ASC_LC_J,
+ DUK_ASC_LC_K, DUK_ASC_LC_L, DUK_ASC_LC_M, DUK_ASC_LC_N,
+ DUK_ASC_LC_O, DUK_ASC_LC_P, DUK_ASC_LC_Q, DUK_ASC_LC_R,
+ DUK_ASC_LC_S, DUK_ASC_LC_T, DUK_ASC_LC_U, DUK_ASC_LC_V,
+ DUK_ASC_LC_W, DUK_ASC_LC_X, DUK_ASC_LC_Y, DUK_ASC_LC_Z
};
-DUK_INTERNAL duk_uint8_t duk_uc_nybbles[16] = {
- '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+DUK_INTERNAL const duk_uint8_t duk_uc_nybbles[16] = {
+ DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
+ DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
+ DUK_ASC_8, DUK_ASC_9, DUK_ASC_UC_A, DUK_ASC_UC_B,
+ DUK_ASC_UC_C, DUK_ASC_UC_D, DUK_ASC_UC_E, DUK_ASC_UC_F
};
/*
- * Table for decoding ASCII hex digits, -1 if invalid.
+ * Table for hex decoding ASCII hex digits
*/
-DUK_INTERNAL duk_int8_t duk_hex_dectab[256] = {
+DUK_INTERNAL const duk_int8_t duk_hex_dectab[256] = {
+ /* -1 if invalid */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */
@@ -14602,6 +14520,154 @@ DUK_INTERNAL duk_int8_t duk_hex_dectab[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */
};
+#if defined(DUK_USE_HEX_FASTPATH)
+/* Preshifted << 4. Must use 16-bit entry to allow negative value signaling. */
+DUK_INTERNAL const duk_int16_t duk_hex_dectab_shift4[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */
+ -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */
+ -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */
+};
+#endif
+
+/*
+ * Table for hex encoding bytes
+ */
+
+#if defined(DUK_USE_HEX_FASTPATH)
+/* Lookup to encode one byte directly into 2 characters:
+ *
+ * def genhextab(bswap):
+ * for i in xrange(256):
+ * t = chr(i).encode('hex')
+ * if bswap:
+ * t = t[1] + t[0]
+ * print('0x' + t.encode('hex') + 'U')
+ * print('big endian'); genhextab(False)
+ * print('little endian'); genhextab(True)
+*/
+DUK_INTERNAL const duk_uint16_t duk_hex_enctab[256] = {
+#if defined(DUK_USE_INTEGER_BE)
+ 0x3030U, 0x3031U, 0x3032U, 0x3033U, 0x3034U, 0x3035U, 0x3036U, 0x3037U,
+ 0x3038U, 0x3039U, 0x3061U, 0x3062U, 0x3063U, 0x3064U, 0x3065U, 0x3066U,
+ 0x3130U, 0x3131U, 0x3132U, 0x3133U, 0x3134U, 0x3135U, 0x3136U, 0x3137U,
+ 0x3138U, 0x3139U, 0x3161U, 0x3162U, 0x3163U, 0x3164U, 0x3165U, 0x3166U,
+ 0x3230U, 0x3231U, 0x3232U, 0x3233U, 0x3234U, 0x3235U, 0x3236U, 0x3237U,
+ 0x3238U, 0x3239U, 0x3261U, 0x3262U, 0x3263U, 0x3264U, 0x3265U, 0x3266U,
+ 0x3330U, 0x3331U, 0x3332U, 0x3333U, 0x3334U, 0x3335U, 0x3336U, 0x3337U,
+ 0x3338U, 0x3339U, 0x3361U, 0x3362U, 0x3363U, 0x3364U, 0x3365U, 0x3366U,
+ 0x3430U, 0x3431U, 0x3432U, 0x3433U, 0x3434U, 0x3435U, 0x3436U, 0x3437U,
+ 0x3438U, 0x3439U, 0x3461U, 0x3462U, 0x3463U, 0x3464U, 0x3465U, 0x3466U,
+ 0x3530U, 0x3531U, 0x3532U, 0x3533U, 0x3534U, 0x3535U, 0x3536U, 0x3537U,
+ 0x3538U, 0x3539U, 0x3561U, 0x3562U, 0x3563U, 0x3564U, 0x3565U, 0x3566U,
+ 0x3630U, 0x3631U, 0x3632U, 0x3633U, 0x3634U, 0x3635U, 0x3636U, 0x3637U,
+ 0x3638U, 0x3639U, 0x3661U, 0x3662U, 0x3663U, 0x3664U, 0x3665U, 0x3666U,
+ 0x3730U, 0x3731U, 0x3732U, 0x3733U, 0x3734U, 0x3735U, 0x3736U, 0x3737U,
+ 0x3738U, 0x3739U, 0x3761U, 0x3762U, 0x3763U, 0x3764U, 0x3765U, 0x3766U,
+ 0x3830U, 0x3831U, 0x3832U, 0x3833U, 0x3834U, 0x3835U, 0x3836U, 0x3837U,
+ 0x3838U, 0x3839U, 0x3861U, 0x3862U, 0x3863U, 0x3864U, 0x3865U, 0x3866U,
+ 0x3930U, 0x3931U, 0x3932U, 0x3933U, 0x3934U, 0x3935U, 0x3936U, 0x3937U,
+ 0x3938U, 0x3939U, 0x3961U, 0x3962U, 0x3963U, 0x3964U, 0x3965U, 0x3966U,
+ 0x6130U, 0x6131U, 0x6132U, 0x6133U, 0x6134U, 0x6135U, 0x6136U, 0x6137U,
+ 0x6138U, 0x6139U, 0x6161U, 0x6162U, 0x6163U, 0x6164U, 0x6165U, 0x6166U,
+ 0x6230U, 0x6231U, 0x6232U, 0x6233U, 0x6234U, 0x6235U, 0x6236U, 0x6237U,
+ 0x6238U, 0x6239U, 0x6261U, 0x6262U, 0x6263U, 0x6264U, 0x6265U, 0x6266U,
+ 0x6330U, 0x6331U, 0x6332U, 0x6333U, 0x6334U, 0x6335U, 0x6336U, 0x6337U,
+ 0x6338U, 0x6339U, 0x6361U, 0x6362U, 0x6363U, 0x6364U, 0x6365U, 0x6366U,
+ 0x6430U, 0x6431U, 0x6432U, 0x6433U, 0x6434U, 0x6435U, 0x6436U, 0x6437U,
+ 0x6438U, 0x6439U, 0x6461U, 0x6462U, 0x6463U, 0x6464U, 0x6465U, 0x6466U,
+ 0x6530U, 0x6531U, 0x6532U, 0x6533U, 0x6534U, 0x6535U, 0x6536U, 0x6537U,
+ 0x6538U, 0x6539U, 0x6561U, 0x6562U, 0x6563U, 0x6564U, 0x6565U, 0x6566U,
+ 0x6630U, 0x6631U, 0x6632U, 0x6633U, 0x6634U, 0x6635U, 0x6636U, 0x6637U,
+ 0x6638U, 0x6639U, 0x6661U, 0x6662U, 0x6663U, 0x6664U, 0x6665U, 0x6666U
+#else /* DUK_USE_INTEGER_BE */
+ 0x3030U, 0x3130U, 0x3230U, 0x3330U, 0x3430U, 0x3530U, 0x3630U, 0x3730U,
+ 0x3830U, 0x3930U, 0x6130U, 0x6230U, 0x6330U, 0x6430U, 0x6530U, 0x6630U,
+ 0x3031U, 0x3131U, 0x3231U, 0x3331U, 0x3431U, 0x3531U, 0x3631U, 0x3731U,
+ 0x3831U, 0x3931U, 0x6131U, 0x6231U, 0x6331U, 0x6431U, 0x6531U, 0x6631U,
+ 0x3032U, 0x3132U, 0x3232U, 0x3332U, 0x3432U, 0x3532U, 0x3632U, 0x3732U,
+ 0x3832U, 0x3932U, 0x6132U, 0x6232U, 0x6332U, 0x6432U, 0x6532U, 0x6632U,
+ 0x3033U, 0x3133U, 0x3233U, 0x3333U, 0x3433U, 0x3533U, 0x3633U, 0x3733U,
+ 0x3833U, 0x3933U, 0x6133U, 0x6233U, 0x6333U, 0x6433U, 0x6533U, 0x6633U,
+ 0x3034U, 0x3134U, 0x3234U, 0x3334U, 0x3434U, 0x3534U, 0x3634U, 0x3734U,
+ 0x3834U, 0x3934U, 0x6134U, 0x6234U, 0x6334U, 0x6434U, 0x6534U, 0x6634U,
+ 0x3035U, 0x3135U, 0x3235U, 0x3335U, 0x3435U, 0x3535U, 0x3635U, 0x3735U,
+ 0x3835U, 0x3935U, 0x6135U, 0x6235U, 0x6335U, 0x6435U, 0x6535U, 0x6635U,
+ 0x3036U, 0x3136U, 0x3236U, 0x3336U, 0x3436U, 0x3536U, 0x3636U, 0x3736U,
+ 0x3836U, 0x3936U, 0x6136U, 0x6236U, 0x6336U, 0x6436U, 0x6536U, 0x6636U,
+ 0x3037U, 0x3137U, 0x3237U, 0x3337U, 0x3437U, 0x3537U, 0x3637U, 0x3737U,
+ 0x3837U, 0x3937U, 0x6137U, 0x6237U, 0x6337U, 0x6437U, 0x6537U, 0x6637U,
+ 0x3038U, 0x3138U, 0x3238U, 0x3338U, 0x3438U, 0x3538U, 0x3638U, 0x3738U,
+ 0x3838U, 0x3938U, 0x6138U, 0x6238U, 0x6338U, 0x6438U, 0x6538U, 0x6638U,
+ 0x3039U, 0x3139U, 0x3239U, 0x3339U, 0x3439U, 0x3539U, 0x3639U, 0x3739U,
+ 0x3839U, 0x3939U, 0x6139U, 0x6239U, 0x6339U, 0x6439U, 0x6539U, 0x6639U,
+ 0x3061U, 0x3161U, 0x3261U, 0x3361U, 0x3461U, 0x3561U, 0x3661U, 0x3761U,
+ 0x3861U, 0x3961U, 0x6161U, 0x6261U, 0x6361U, 0x6461U, 0x6561U, 0x6661U,
+ 0x3062U, 0x3162U, 0x3262U, 0x3362U, 0x3462U, 0x3562U, 0x3662U, 0x3762U,
+ 0x3862U, 0x3962U, 0x6162U, 0x6262U, 0x6362U, 0x6462U, 0x6562U, 0x6662U,
+ 0x3063U, 0x3163U, 0x3263U, 0x3363U, 0x3463U, 0x3563U, 0x3663U, 0x3763U,
+ 0x3863U, 0x3963U, 0x6163U, 0x6263U, 0x6363U, 0x6463U, 0x6563U, 0x6663U,
+ 0x3064U, 0x3164U, 0x3264U, 0x3364U, 0x3464U, 0x3564U, 0x3664U, 0x3764U,
+ 0x3864U, 0x3964U, 0x6164U, 0x6264U, 0x6364U, 0x6464U, 0x6564U, 0x6664U,
+ 0x3065U, 0x3165U, 0x3265U, 0x3365U, 0x3465U, 0x3565U, 0x3665U, 0x3765U,
+ 0x3865U, 0x3965U, 0x6165U, 0x6265U, 0x6365U, 0x6465U, 0x6565U, 0x6665U,
+ 0x3066U, 0x3166U, 0x3266U, 0x3366U, 0x3466U, 0x3566U, 0x3666U, 0x3766U,
+ 0x3866U, 0x3966U, 0x6166U, 0x6266U, 0x6366U, 0x6466U, 0x6566U, 0x6666U
+#endif /* DUK_USE_INTEGER_BE */
+};
+#endif /* DUK_USE_HEX_FASTPATH */
+
+/*
+ * Table for base-64 encoding
+ */
+
+#if defined(DUK_USE_BASE64_FASTPATH)
+DUK_INTERNAL const duk_uint8_t duk_base64_enctab[64] = {
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, /* A...P */
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, /* Q...f */
+ 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, /* g...v */
+ 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f /* w.../ */
+};
+#endif /* DUK_USE_BASE64_FASTPATH */
+
+/*
+ * Table for base-64 decoding
+ */
+
+#if defined(DUK_USE_BASE64_FASTPATH)
+DUK_INTERNAL const duk_int8_t duk_base64_dectab[256] = {
+ /* -1 = error, -2 = allowed whitespace, -3 = padding ('='), 0...63 decoded bytes */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, /* 0x00...0x0f */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10...0x1f */
+ -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20...0x2f */
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1, /* 0x30...0x3f */
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40...0x4f */
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50...0x5f */
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60...0x6f */
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70...0x7f */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80...0x8f */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90...0x9f */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0...0xaf */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0...0xbf */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0...0xcf */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0...0xdf */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0...0xef */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0...0xff */
+};
+#endif /* DUK_USE_BASE64_FASTPATH */
+
/*
* Arbitrary byteswap for potentially unaligned values
*
@@ -16216,18 +16282,89 @@ DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t mag
* Encoding and decoding basic formats: hex, base64.
*
* These are in-place operations which may allow an optimized implementation.
+ *
+ * Base-64: https://tools.ietf.org/html/rfc4648#section-4
*/
/* include removed: duk_internal.h */
-/* dst length must be exactly ceil(len/3)*4 */
-DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, const duk_uint8_t *src_end,
- duk_uint8_t *dst, duk_uint8_t *dst_end) {
+/* Shared handling for encode/decode argument. Fast path handling for
+ * buffer and string values because they're the most common. In particular,
+ * avoid creating a temporary string or buffer when possible.
+ */
+DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
+ DUK_ASSERT(duk_is_valid_index(ctx, index)); /* checked by caller */
+ if (duk_is_buffer(ctx, index)) {
+ return (const duk_uint8_t *) duk_get_buffer(ctx, index, out_len);
+ } else {
+ return (const duk_uint8_t *) duk_to_lstring(ctx, index, out_len);
+ }
+}
+
+#if defined(DUK_USE_BASE64_FASTPATH)
+DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
+ duk_uint_t t;
+ duk_size_t n_full, n_full3, n_final;
+ const duk_uint8_t *src_end_fast;
+
+ n_full = srclen / 3; /* full 3-byte -> 4-char conversions */
+ n_full3 = n_full * 3;
+ n_final = srclen - n_full3;
+ DUK_ASSERT_DISABLE(n_final >= 0);
+ DUK_ASSERT(n_final <= 2);
+
+ src_end_fast = src + n_full3;
+ while (DUK_UNLIKELY(src != src_end_fast)) {
+ t = (duk_uint_t) (*src++);
+ t = (t << 8) + (duk_uint_t) (*src++);
+ t = (t << 8) + (duk_uint_t) (*src++);
+
+ *dst++ = duk_base64_enctab[t >> 18];
+ *dst++ = duk_base64_enctab[(t >> 12) & 0x3f];
+ *dst++ = duk_base64_enctab[(t >> 6) & 0x3f];
+ *dst++ = duk_base64_enctab[t & 0x3f];
+
+#if 0 /* Tested: not faster on x64 */
+ /* aaaaaabb bbbbcccc ccdddddd */
+ dst[0] = duk_base64_enctab[(src[0] >> 2) & 0x3f];
+ dst[1] = duk_base64_enctab[((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0f)];
+ dst[2] = duk_base64_enctab[((src[1] << 2) & 0x3f) | ((src[2] >> 6) & 0x03)];
+ dst[3] = duk_base64_enctab[src[2] & 0x3f];
+ src += 3; dst += 4;
+#endif
+ }
+
+ switch (n_final) {
+ /* case 0: nop */
+ case 1: {
+ /* XX== */
+ t = (duk_uint_t) (*src++);
+ *dst++ = duk_base64_enctab[t >> 2]; /* XXXXXX-- */
+ *dst++ = duk_base64_enctab[(t << 4) & 0x3f]; /* ------XX */
+ *dst++ = DUK_ASC_EQUALS;
+ *dst++ = DUK_ASC_EQUALS;
+ break;
+ }
+ case 2: {
+ /* XXX= */
+ t = (duk_uint_t) (*src++);
+ t = (t << 8) + (duk_uint_t) (*src++);
+ *dst++ = duk_base64_enctab[t >> 10]; /* XXXXXX-- -------- */
+ *dst++ = duk_base64_enctab[(t >> 4) & 0x3f]; /* ------XX XXXX---- */
+ *dst++ = duk_base64_enctab[(t << 2) & 0x3f]; /* -------- ----XXXX */
+ *dst++ = DUK_ASC_EQUALS;
+ break;
+ }
+ }
+}
+#else /* DUK_USE_BASE64_FASTPATH */
+DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
duk_small_uint_t i, snip;
- duk_uint_fast32_t t;
+ duk_uint_t t;
duk_uint_fast8_t x, y;
+ const duk_uint8_t *src_end;
- DUK_UNREF(dst_end);
+ src_end = src + srclen;
while (src < src_end) {
/* read 3 bytes into 't', padded by zero */
@@ -16238,7 +16375,7 @@ DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, const duk_uint8
if (src >= src_end) {
snip--;
} else {
- t += (duk_uint_fast32_t) (*src++);
+ t += (duk_uint_t) (*src++);
}
}
@@ -16272,22 +16409,159 @@ DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, const duk_uint8
y = '/';
}
- DUK_ASSERT(dst < dst_end);
*dst++ = (duk_uint8_t) y;
}
}
}
+#endif /* DUK_USE_BASE64_FASTPATH */
+
+#if defined(DUK_USE_BASE64_FASTPATH)
+DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) {
+ duk_int_t x;
+ duk_int_t t;
+ duk_small_uint_t n_equal;
+ duk_small_uint_t n_chars;
+ const duk_uint8_t *src_end;
+ const duk_uint8_t *src_end_safe;
+
+ src_end = src + srclen;
+ src_end_safe = src_end - 4; /* if 'src < src_end_safe', safe to read 4 bytes */
+
+ /* Innermost fast path processes 4 valid base-64 characters at a time
+ * but bails out on whitespace, padding chars ('=') and invalid chars.
+ * Once the slow path segment has been processed, we return to the
+ * inner fast path again. This handles e.g. base64 with newlines
+ * reasonably well because the majority of a line is in the fast path.
+ */
+ for (;;) {
+ /* Fast path, handle units with just actual encoding characters. */
+
+ while (src <= src_end_safe) {
+ /* The lookup byte is intentionally sign extended to (at least)
+ * 32 bits and then ORed. This ensures that is at least 1 byte
+ * is negative, the highest bit of 't' will be set at the end
+ * and we don't need to check every byte.
+ */
+ DUK_DDD(DUK_DDDPRINT("fast loop: src=%p, src_end_safe=%p, src_end=%p",
+ (const void *) src, (const void *) src_end_safe, (const void *) src_end));
+
+ t = (duk_int_t) duk_base64_dectab[*src++];
+ t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
+ t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
+ t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
+
+ if (DUK_UNLIKELY(t < 0)) {
+ DUK_DDD(DUK_DDDPRINT("fast loop unit was not clean, process one slow path unit"));
+ src -= 4;
+ break;
+ }
+
+ DUK_ASSERT(t <= 0xffffffL);
+ DUK_ASSERT((t >> 24) == 0);
+ *dst++ = (duk_uint8_t) (t >> 16);
+ *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
+ *dst++ = (duk_uint8_t) (t & 0xff);
+ }
+
+ /* Handle one slow path unit (or finish if we're done). */
+
+ n_equal = 0;
+ n_chars = 0;
+ t = 0;
+ for (;;) {
+ DUK_DDD(DUK_DDDPRINT("slow loop: src=%p, src_end=%p, n_chars=%ld, n_equal=%ld, t=%ld",
+ (const void *) src, (const void *) src_end, (long) n_chars, (long) n_equal, (long) t));
+
+ if (DUK_UNLIKELY(src >= src_end)) {
+ goto done; /* two level break */
+ }
+
+ x = duk_base64_dectab[*src++];
+ if (DUK_UNLIKELY(x < 0)) {
+ if (x == -2) {
+ continue; /* allowed ascii whitespace */
+ } else if (x == -3) {
+ n_equal++;
+ t <<= 6;
+ } else {
+ DUK_ASSERT(x == -1);
+ goto error;
+ }
+ } else {
+ DUK_ASSERT(x >= 0 && x <= 63);
+ if (n_equal > 0) {
+ /* Don't allow actual chars after equal sign. */
+ goto error;
+ }
+ t = (t << 6) + x;
+ }
+
+ if (DUK_UNLIKELY(n_chars == 3)) {
+ /* Emit 3 bytes and backtrack if there was padding. There's
+ * always space for the whole 3 bytes so no check needed.
+ */
+ DUK_ASSERT(t <= 0xffffffL);
+ DUK_ASSERT((t >> 24) == 0);
+ *dst++ = (duk_uint8_t) (t >> 16);
+ *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
+ *dst++ = (duk_uint8_t) (t & 0xff);
-DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, const duk_uint8_t *src_end,
- duk_uint8_t *dst, duk_uint8_t *dst_end, duk_uint8_t **out_dst_final) {
- duk_uint_fast32_t t;
+ if (DUK_UNLIKELY(n_equal > 0)) {
+ DUK_ASSERT(n_equal <= 4);
+
+ /* There may be whitespace between the equal signs. */
+ if (n_equal == 1) {
+ /* XXX= */
+ dst -= 1;
+ } else if (n_equal == 2) {
+ /* XX== */
+ dst -= 2;
+ } else {
+ goto error; /* invalid padding */
+ }
+
+ /* Continue parsing after padding, allows concatenated,
+ * padded base64.
+ */
+ }
+ break; /* back to fast loop */
+ } else {
+ n_chars++;
+ }
+ }
+ }
+ done:
+ DUK_DDD(DUK_DDDPRINT("done; src=%p, src_end=%p, n_chars=%ld",
+ (const void *) src, (const void *) src_end, (long) n_chars));
+
+ DUK_ASSERT(src == src_end);
+
+ if (n_chars != 0) {
+ /* Here we'd have the option of decoding unpadded base64
+ * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not
+ * accepted.
+ */
+ goto error;
+ }
+
+ *out_dst_final = dst;
+ return 1;
+
+ error:
+ return 0;
+}
+#else /* DUK_USE_BASE64_FASTPATH */
+DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) {
+ duk_uint_t t;
duk_uint_fast8_t x, y;
duk_small_uint_t group_idx;
+ duk_small_uint_t n_equal;
+ const duk_uint8_t *src_end;
- DUK_UNREF(dst_end);
-
+ src_end = src + srclen;
t = 0;
group_idx = 0;
+ n_equal = 0;
while (src < src_end) {
x = *src++;
@@ -16303,42 +16577,14 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, const duk
} else if (x == '/') {
y = 63;
} else if (x == '=') {
- /* We don't check the zero padding bytes here right now.
- * This seems to be common behavior for base-64 decoders.
+ /* We don't check the zero padding bytes here right now
+ * (that they're actually zero). This seems to be common
+ * behavior for base-64 decoders.
*/
- if (group_idx == 2) {
- /* xx== -> 1 byte, t contains 12 bits, 4 on right are zero */
- t = t >> 4;
- DUK_ASSERT(dst < dst_end);
- *dst++ = (duk_uint8_t) t;
-
- if (src >= src_end) {
- goto error;
- }
- x = *src++;
- if (x != '=') {
- goto error;
- }
- } else if (group_idx == 3) {
- /* xxx= -> 2 bytes, t contains 18 bits, 2 on right are zero */
- t = t >> 2;
- DUK_ASSERT(dst < dst_end);
- *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
- DUK_ASSERT(dst < dst_end);
- *dst++ = (duk_uint8_t) (t & 0xff);
- } else {
- goto error;
- }
-
- /* Here we can choose either to end parsing and ignore
- * whatever follows, or to continue parsing in case
- * multiple (possibly padded) base64 strings have been
- * concatenated. Currently, keep on parsing.
- */
- t = 0;
- group_idx = 0;
- continue;
+ n_equal++;
+ t <<= 6; /* shift in zeroes */
+ goto skip_add;
} else if (x == 0x09 || x == 0x0a || x == 0x0d || x == 0x20) {
/* allow basic ASCII whitespace */
continue;
@@ -16346,16 +16592,38 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, const duk
goto error;
}
+ if (n_equal > 0) {
+ /* Don't allow mixed padding and actual chars. */
+ goto error;
+ }
t = (t << 6) + y;
+ skip_add:
if (group_idx == 3) {
/* output 3 bytes from 't' */
- DUK_ASSERT(dst < dst_end);
*dst++ = (duk_uint8_t) ((t >> 16) & 0xff);
- DUK_ASSERT(dst < dst_end);
*dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
- DUK_ASSERT(dst < dst_end);
*dst++ = (duk_uint8_t) (t & 0xff);
+
+ if (DUK_UNLIKELY(n_equal > 0)) {
+ /* Backtrack. */
+ DUK_ASSERT(n_equal <= 4);
+ if (n_equal == 1) {
+ dst -= 1;
+ } else if (n_equal == 2) {
+ dst -= 2;
+ } else {
+ goto error; /* invalid padding */
+ }
+
+ /* Here we can choose either to end parsing and ignore
+ * whatever follows, or to continue parsing in case
+ * multiple (possibly padded) base64 strings have been
+ * concatenated. Currently, keep on parsing.
+ */
+ n_equal = 0;
+ }
+
t = 0;
group_idx = 0;
} else {
@@ -16377,23 +16645,11 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, const duk
error:
return 0;
}
-
-/* Shared handling for encode/decode argument. Fast path handling for
- * buffer and string values because they're the most common. In particular,
- * avoid creating a temporary string or buffer when possible.
- */
-DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
- DUK_ASSERT(duk_is_valid_index(ctx, index)); /* checked by caller */
- if (duk_is_buffer(ctx, index)) {
- return (const duk_uint8_t *) duk_get_buffer(ctx, index, out_len);
- } else {
- return (const duk_uint8_t *) duk_to_lstring(ctx, index, out_len);
- }
-}
+#endif /* DUK_USE_BASE64_FASTPATH */
DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) {
duk_hthread *thr = (duk_hthread *) ctx;
- duk_uint8_t *src;
+ const duk_uint8_t *src;
duk_size_t srclen;
duk_size_t dstlen;
duk_uint8_t *dst;
@@ -16406,7 +16662,7 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) {
*/
index = duk_require_normalize_index(ctx, index);
- src = (duk_uint8_t *) duk_to_buffer(ctx, index, &srclen);
+ src = duk__prep_codec_arg(ctx, index, &srclen);
/* Note: for srclen=0, src may be NULL */
/* Computation must not wrap; this limit works for 32-bit size_t:
@@ -16420,8 +16676,7 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) {
dstlen = (srclen + 2) / 3 * 4;
dst = (duk_uint8_t *) duk_push_fixed_buffer(ctx, dstlen);
- duk__base64_encode_helper((const duk_uint8_t *) src, (const duk_uint8_t *) (src + srclen),
- dst, (dst + dstlen));
+ duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst);
ret = duk_to_string(ctx, -1);
duk_replace(ctx, index);
@@ -16448,7 +16703,7 @@ DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) {
*/
index = duk_require_normalize_index(ctx, index);
- src = (const duk_uint8_t *) duk_to_lstring(ctx, index, &srclen);
+ src = duk__prep_codec_arg(ctx, index, &srclen);
/* Computation must not wrap, only srclen + 3 is at risk of
* wrapping because after that the number gets smaller.
@@ -16458,12 +16713,11 @@ DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) {
if (srclen > 4294967292UL) {
goto type_error;
}
- dstlen = (srclen + 3) / 4 * 3; /* upper limit */
+ dstlen = (srclen + 3) / 4 * 3; /* upper limit, assuming no whitespace etc */
dst = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, dstlen);
/* Note: for dstlen=0, dst may be NULL */
- retval = duk__base64_decode_helper((const duk_uint8_t *) src, (const duk_uint8_t *) (src + srclen),
- dst, dst + dstlen, &dst_final);
+ retval = duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final);
if (!retval) {
goto type_error;
}
@@ -16481,9 +16735,12 @@ DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) {
const duk_uint8_t *inp;
duk_size_t len;
duk_size_t i;
- duk_small_uint_t t;
duk_uint8_t *buf;
const char *ret;
+#if defined(DUK_USE_HEX_FASTPATH)
+ duk_size_t len_safe;
+ duk_uint16_t *p16;
+#endif
DUK_ASSERT_CTX_VALID(ctx);
@@ -16495,12 +16752,28 @@ DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) {
buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len * 2, DUK_BUF_FLAG_NOZERO /*flags*/);
DUK_ASSERT(buf != NULL);
+#if defined(DUK_USE_HEX_FASTPATH)
+ DUK_ASSERT((((duk_uintptr_t) buf) & 0x01U) == 0); /* pointer is aligned, guaranteed for fixed buffer */
+ p16 = (duk_uint16_t *) (void *) buf;
+ len_safe = len & ~0x03U;
+ for (i = 0; i < len_safe; i += 4) {
+ p16[0] = duk_hex_enctab[inp[i]];
+ p16[1] = duk_hex_enctab[inp[i + 1]];
+ p16[2] = duk_hex_enctab[inp[i + 2]];
+ p16[3] = duk_hex_enctab[inp[i + 3]];
+ p16 += 4;
+ }
+ for (; i < len; i++) {
+ *p16++ = duk_hex_enctab[inp[i]];
+ }
+#else /* DUK_USE_HEX_FASTPATH */
for (i = 0; i < len; i++) {
- /* XXX: by using two 256-entry tables could avoid shifting and masking. */
+ duk_small_uint_t t;
t = (duk_small_uint_t) inp[i];
buf[i*2 + 0] = duk_lc_digits[t >> 4];
buf[i*2 + 1] = duk_lc_digits[t & 0x0f];
}
+#endif /* DUK_USE_HEX_FASTPATH */
/* XXX: Using a string return value forces a string intern which is
* not always necessary. As a rough performance measure, hex encode
@@ -16519,8 +16792,13 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) {
const duk_uint8_t *inp;
duk_size_t len;
duk_size_t i;
- duk_small_int_t t;
+ duk_int_t t;
duk_uint8_t *buf;
+#if defined(DUK_USE_HEX_FASTPATH)
+ duk_int_t chk;
+ duk_uint8_t *p;
+ duk_size_t len_safe;
+#endif
DUK_ASSERT_CTX_VALID(ctx);
@@ -16536,18 +16814,55 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) {
buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len / 2, DUK_BUF_FLAG_NOZERO /*flags*/);
DUK_ASSERT(buf != NULL);
+#if defined(DUK_USE_HEX_FASTPATH)
+ p = buf;
+ len_safe = len & ~0x07U;
+ for (i = 0; i < len_safe; i += 8) {
+ t = ((duk_int_t) duk_hex_dectab_shift4[inp[i]]) |
+ ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
+ chk = t;
+ p[0] = (duk_uint8_t) t;
+ t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 2]]) |
+ ((duk_int_t) duk_hex_dectab[inp[i + 3]]);
+ chk |= t;
+ p[1] = (duk_uint8_t) t;
+ t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 4]]) |
+ ((duk_int_t) duk_hex_dectab[inp[i + 5]]);
+ chk |= t;
+ p[2] = (duk_uint8_t) t;
+ t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 6]]) |
+ ((duk_int_t) duk_hex_dectab[inp[i + 7]]);
+ chk |= t;
+ p[3] = (duk_uint8_t) t;
+ p += 4;
+
+ /* Check if any lookup above had a negative result. */
+ if (DUK_UNLIKELY(chk < 0)) {
+ goto type_error;
+ }
+ }
+ for (; i < len; i += 2) {
+ t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) |
+ ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
+ if (DUK_UNLIKELY(t < 0)) {
+ goto type_error;
+ }
+ *p++ = (duk_uint8_t) t;
+ }
+#else /* DUK_USE_HEX_FASTPATH */
for (i = 0; i < len; i += 2) {
/* For invalid characters the value -1 gets extended to
* at least 16 bits. If either nybble is invalid, the
* resulting 't' will be < 0.
*/
- t = (((duk_small_int_t) duk_hex_dectab[inp[i]]) << 4) |
- ((duk_small_int_t) duk_hex_dectab[inp[i + 1]]);
+ t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) |
+ ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
if (DUK_UNLIKELY(t < 0)) {
goto type_error;
}
buf[i >> 1] = (duk_uint8_t) t;
}
+#endif /* DUK_USE_HEX_FASTPATH */
duk_replace(ctx, index);
return;
@@ -16696,7 +17011,7 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) {
* file given to duk_peval_file() or similar, the
* error message is not the best possible.
*/
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_NO_SOURCECODE);
+ DUK_ERROR_API(thr, DUK_STR_NO_SOURCECODE);
}
DUK_ASSERT(h_sourcecode != NULL);
comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode);
@@ -16838,6 +17153,10 @@ DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx,
const char *str;
duk_size_t len;
+ /* XXX: should there be an error or an automatic detach if
+ * already attached?
+ */
+
DUK_ASSERT_CTX_VALID(ctx);
DUK_ASSERT(read_cb != NULL);
DUK_ASSERT(write_cb != NULL);
@@ -16851,6 +17170,7 @@ DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx,
heap->dbg_write_flush_cb = write_flush_cb;
heap->dbg_detached_cb = detached_cb;
heap->dbg_udata = udata;
+ heap->dbg_have_next_byte = 0;
/* Start in paused state. */
heap->dbg_processing = 0;
@@ -16888,7 +17208,7 @@ DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
- /* Can be called muliple times with no harm. */
+ /* Can be called multiple times with no harm. */
duk_debug_do_detach(thr->heap);
}
@@ -16936,12 +17256,12 @@ DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx,
DUK_UNREF(write_flush_cb);
DUK_UNREF(detached_cb);
DUK_UNREF(udata);
- duk_error(ctx, DUK_ERR_API_ERROR, "no debugger support");
+ DUK_ERROR_API((duk_hthread *) ctx, "no debugger support");
}
DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
DUK_ASSERT_CTX_VALID(ctx);
- duk_error(ctx, DUK_ERR_API_ERROR, "no debugger support");
+ DUK_ERROR_API((duk_hthread *) ctx, "no debugger support");
}
DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
@@ -17860,23 +18180,25 @@ DUK_EXTERNAL duk_int_t duk_api_global_line = 0;
#endif
/*
- * Helpers
+ * Misc helpers
*/
/* Check that there's room to push one value. */
#if defined(DUK_USE_VALSTACK_UNSAFE)
/* Faster but value stack overruns are memory unsafe. */
-#define DUK__CHECK_SPACE() do { \
+#define DUK__CHECK_SPACE() do { \
DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \
} while (0)
#else
-#define DUK__CHECK_SPACE() do { \
- if (thr->valstack_top >= thr->valstack_end) { \
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK); \
+#define DUK__CHECK_SPACE() do { \
+ if (DUK_UNLIKELY(thr->valstack_top >= thr->valstack_end)) { \
+ DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); \
} \
} while (0)
#endif
+DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag);
+
DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t index, duk_bool_t require) {
duk_hthread *thr;
duk_tval *tv;
@@ -17938,7 +18260,7 @@ DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t index, duk_b
error_notnumber:
if (require) {
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_NUMBER);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
/* not reachable */
}
return 0;
@@ -17995,7 +18317,7 @@ DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk
error_notnumber:
if (require) {
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_NUMBER);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
/* not reachable */
}
return 0;
@@ -18071,7 +18393,7 @@ DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t i
if (DUK_LIKELY(uindex < vs_size)) {
return (duk_idx_t) uindex;
}
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_INDEX);
+ DUK_ERROR_API_INDEX(thr, index);
return 0; /* unreachable */
}
@@ -18129,7 +18451,7 @@ DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index) {
if (DUK_LIKELY(uindex < vs_size)) {
return thr->valstack_bottom + uindex;
}
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_INDEX);
+ DUK_ERROR_API_INDEX(thr, index);
return NULL;
}
@@ -18149,7 +18471,8 @@ DUK_EXTERNAL void duk_require_valid_index(duk_context *ctx, duk_idx_t index) {
DUK_ASSERT(DUK_INVALID_INDEX < 0);
if (duk_normalize_index(ctx, index) < 0) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_INDEX);
+ DUK_ERROR_API_INDEX(thr, index);
+ return; /* unreachable */
}
}
@@ -18202,10 +18525,11 @@ DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) {
#if defined(DUK_USE_VALSTACK_UNSAFE)
DUK_ASSERT(uindex <= vs_limit);
+ DUK_UNREF(vs_limit);
#else
if (DUK_UNLIKELY(uindex > vs_limit)) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_INDEX);
- return;
+ DUK_ERROR_API_INDEX(thr, index);
+ return; /* unreachable */
}
#endif
DUK_ASSERT(uindex <= vs_limit);
@@ -18284,7 +18608,8 @@ DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_context *ctx) {
ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
if (DUK_UNLIKELY(ret < 0)) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_INDEX);
+ DUK_ERROR_API_INDEX(thr, -1);
+ return 0; /* unreachable */
}
return ret;
}
@@ -18680,7 +19005,8 @@ DUK_EXTERNAL void duk_dup_top(duk_context *ctx) {
DUK__CHECK_SPACE();
if (thr->valstack_top - thr->valstack_bottom <= 0) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_INDEX);
+ DUK_ERROR_API_INDEX(thr, -1);
+ return; /* unreachable */
}
tv_from = thr->valstack_top - 1;
tv_to = thr->valstack_top++;
@@ -18721,7 +19047,7 @@ DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) {
if (nbytes > 0) {
DUK_TVAL_SET_TVAL(&tv_tmp, q);
DUK_ASSERT(nbytes > 0);
- DUK_MEMMOVE((void *) (p + 1), (void *) p, nbytes);
+ DUK_MEMMOVE((void *) (p + 1), (const void *) p, (size_t) nbytes);
DUK_TVAL_SET_TVAL(p, &tv_tmp);
} else {
/* nop: insert top to top */
@@ -18800,7 +19126,7 @@ DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index) {
#endif
nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */
- DUK_MEMMOVE(p, p + 1, nbytes); /* zero size not an issue: pointers are valid */
+ DUK_MEMMOVE((void *) p, (const void *) (p + 1), (size_t) nbytes); /* zero size not an issue: pointers are valid */
DUK_TVAL_SET_UNDEFINED(q);
thr->valstack_top--;
@@ -18830,13 +19156,13 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx,
DUK_ASSERT(from_ctx != NULL);
if (to_ctx == from_ctx) {
- DUK_ERROR(to_thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CONTEXT);
+ DUK_ERROR_API(to_thr, DUK_STR_INVALID_CONTEXT);
return;
}
if ((count < 0) ||
(count > (duk_idx_t) to_thr->valstack_max)) {
/* Maximum value check ensures 'nbytes' won't wrap below. */
- DUK_ERROR(to_thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_COUNT);
+ DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT);
return;
}
@@ -18846,18 +19172,18 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx,
}
DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end);
if ((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes) {
- DUK_ERROR(to_thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
+ DUK_ERROR_API(to_thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
}
src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes);
if (src < (void *) from_thr->valstack_bottom) {
- DUK_ERROR(to_thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_COUNT);
+ DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT);
}
/* copy values (no overlap even if to_ctx == from_ctx; that's not
* allowed now anyway)
*/
DUK_ASSERT(nbytes > 0);
- DUK_MEMCPY((void *) to_thr->valstack_top, src, nbytes);
+ DUK_MEMCPY((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes);
p = to_thr->valstack_top;
to_thr->valstack_top = (duk_tval *) (void *) (((duk_uint8_t *) p) + nbytes);
@@ -18895,10 +19221,10 @@ DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t index) {
tv = duk_get_tval(ctx, index);
if (tv && DUK_TVAL_IS_UNDEFINED(tv)) {
- /* Note: accept both 'actual' and 'unused' undefined */
return;
}
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_UNDEFINED);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "undefined", DUK_STR_NOT_UNDEFINED);
+ return; /* not reachable */
}
DUK_EXTERNAL void duk_require_null(duk_context *ctx, duk_idx_t index) {
@@ -18911,7 +19237,7 @@ DUK_EXTERNAL void duk_require_null(duk_context *ctx, duk_idx_t index) {
if (tv && DUK_TVAL_IS_NULL(tv)) {
return;
}
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_NULL);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "null", DUK_STR_NOT_NULL);
return; /* not reachable */
}
@@ -18942,8 +19268,7 @@ DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t index) {
DUK_ASSERT(ret == 0 || ret == 1);
return ret;
}
-
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_BOOLEAN);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "boolean", DUK_STR_NOT_BOOLEAN);
return 0; /* not reachable */
}
@@ -18987,8 +19312,7 @@ DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t index)
DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret);
return ret.d;
}
-
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_NUMBER);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
return DUK_DOUBLE_NAN; /* not reachable */
}
@@ -19057,8 +19381,7 @@ DUK_EXTERNAL const char *duk_require_lstring(duk_context *ctx, duk_idx_t index,
if (ret) {
return ret;
}
-
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_STRING);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "string", DUK_STR_NOT_STRING);
return NULL; /* not reachable */
}
@@ -19102,8 +19425,7 @@ DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t index) {
void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
return (void *) p;
}
-
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_POINTER);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "pointer", DUK_STR_NOT_POINTER);
return NULL; /* not reachable */
}
@@ -19146,7 +19468,7 @@ DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t index, duk_si
}
if (throw_flag) {
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_BUFFER);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER);
}
return NULL;
}
@@ -19208,7 +19530,7 @@ DUK_LOCAL void *duk__get_buffer_data_helper(duk_context *ctx, duk_idx_t index, d
fail:
if (throw_flag) {
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_BUFFER);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER);
}
return NULL;
}
@@ -19221,78 +19543,68 @@ DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t index, du
return duk__get_buffer_data_helper(ctx, index, out_size, 1 /*throw_flag*/);
}
-/* Raw helper for getting a value from the stack, checking its tag, and possible its object class.
- * The tag cannot be a number because numbers don't have an internal tag in the packed representation.
+/* Raw helper for getting a value from the stack, checking its tag.
+ * The tag cannot be a number because numbers don't have an internal
+ * tag in the packed representation.
*/
-DUK_INTERNAL duk_heaphdr *duk_get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t flags_and_tag) {
- duk_hthread *thr = (duk_hthread *) ctx;
+
+DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag) {
duk_tval *tv;
- duk_small_uint_t tag = flags_and_tag & 0xffffU; /* tags can be up to 16 bits */
DUK_ASSERT_CTX_VALID(ctx);
tv = duk_get_tval(ctx, index);
if (tv && (DUK_TVAL_GET_TAG(tv) == tag)) {
duk_heaphdr *ret;
-
- /* Note: tag comparison in general doesn't work for numbers,
- * but it does work for everything else (heap objects here).
- */
ret = DUK_TVAL_GET_HEAPHDR(tv);
DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */
-
- /* If class check has been requested, tag must also be DUK_TAG_OBJECT.
- * This allows us to just check the class check flag without checking
- * the tag also.
- */
- DUK_ASSERT((flags_and_tag & DUK_GETTAGGED_FLAG_CHECK_CLASS) == 0 ||
- tag == DUK_TAG_OBJECT);
-
- if ((flags_and_tag & DUK_GETTAGGED_FLAG_CHECK_CLASS) == 0 || /* no class check */
- (duk_int_t) DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) ret) == /* or class check matches */
- (duk_int_t) ((flags_and_tag >> DUK_GETTAGGED_CLASS_SHIFT) & 0xff)) {
- return ret;
- }
- }
-
- if (flags_and_tag & DUK_GETTAGGED_FLAG_ALLOW_NULL) {
- return (duk_heaphdr *) NULL;
+ return ret;
}
- /* Formatting the tag number here is not very useful: the tag value
- * is Duktape internal (not the same as DUK_TYPE_xxx) and even depends
- * on the duk_tval layout. If anything, add a human readable type here.
- */
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_UNEXPECTED_TYPE);
- return NULL; /* not reachable */
+ return (duk_heaphdr *) NULL;
}
DUK_INTERNAL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index) {
- return (duk_hstring *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING | DUK_GETTAGGED_FLAG_ALLOW_NULL);
+ return (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING);
}
DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index) {
- return (duk_hstring *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING);
+ duk_heaphdr *h;
+ h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING);
+ if (h == NULL) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "string", DUK_STR_NOT_STRING);
+ }
+ return (duk_hstring *) h;
}
DUK_INTERNAL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index) {
- return (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT | DUK_GETTAGGED_FLAG_ALLOW_NULL);
+ return (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
}
DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index) {
- return (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
+ duk_heaphdr *h;
+ h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
+ if (h == NULL) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "object", DUK_STR_NOT_OBJECT);
+ }
+ return (duk_hobject *) h;
}
DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index) {
- return (duk_hbuffer *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER | DUK_GETTAGGED_FLAG_ALLOW_NULL);
+ return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER);
}
DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index) {
- return (duk_hbuffer *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER);
+ duk_heaphdr *h;
+ h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER);
+ if (h == NULL) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "buffer", DUK_STR_NOT_BUFFER);
+ }
+ return (duk_hbuffer *) h;
}
DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index) {
- duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT | DUK_GETTAGGED_FLAG_ALLOW_NULL);
+ duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
if (h != NULL && !DUK_HOBJECT_IS_THREAD(h)) {
h = NULL;
}
@@ -19301,16 +19613,15 @@ DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index) {
DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index) {
duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- DUK_ASSERT(h != NULL);
- if (!DUK_HOBJECT_IS_THREAD(h)) {
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_THREAD);
+ duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
+ if (!(h != NULL && DUK_HOBJECT_IS_THREAD(h))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "thread", DUK_STR_NOT_THREAD);
}
return (duk_hthread *) h;
}
DUK_INTERNAL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index) {
- duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT | DUK_GETTAGGED_FLAG_ALLOW_NULL);
+ duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
if (h != NULL && !DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
h = NULL;
}
@@ -19319,16 +19630,15 @@ DUK_INTERNAL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx,
DUK_INTERNAL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index) {
duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- DUK_ASSERT(h != NULL);
- if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_COMPILEDFUNCTION);
+ duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
+ if (!(h != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(h))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "compiledfunction", DUK_STR_NOT_COMPILEDFUNCTION);
}
return (duk_hcompiledfunction *) h;
}
DUK_INTERNAL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index) {
- duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT | DUK_GETTAGGED_FLAG_ALLOW_NULL);
+ duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
if (h != NULL && !DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
h = NULL;
}
@@ -19337,10 +19647,9 @@ DUK_INTERNAL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_
DUK_INTERNAL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index) {
duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- DUK_ASSERT(h != NULL);
- if (!DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_NATIVEFUNCTION);
+ duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
+ if (!(h != NULL && DUK_HOBJECT_IS_NATIVEFUNCTION(h))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION);
}
return (duk_hnativefunction *) h;
}
@@ -19379,11 +19688,17 @@ DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t i
ret = duk_get_c_function(ctx, index);
if (!ret) {
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_C_FUNCTION);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION);
}
return ret;
}
+DUK_EXTERNAL void duk_require_function(duk_context *ctx, duk_idx_t index) {
+ if (!duk_is_function(ctx, index)) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, index, "function", DUK_STR_NOT_FUNCTION);
+ }
+}
+
DUK_EXTERNAL duk_context *duk_get_context(duk_context *ctx, duk_idx_t index) {
DUK_ASSERT_CTX_VALID(ctx);
@@ -19427,7 +19742,7 @@ DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t index) {
return ret;
}
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_UNEXPECTED_TYPE);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "heapobject", DUK_STR_UNEXPECTED_TYPE);
return (void *) NULL; /* not reachable */
}
@@ -19444,7 +19759,7 @@ duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) {
* to an object). Return value is NULL if value is neither an object nor a
* lightfunc.
*/
-duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) {
+DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) {
duk_tval *tv;
DUK_ASSERT_CTX_VALID(ctx);
@@ -19477,8 +19792,7 @@ DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx
} else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
return NULL;
}
-
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_UNEXPECTED_TYPE);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT);
return NULL; /* not reachable */
}
@@ -19499,11 +19813,44 @@ DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx,
duk_to_object(ctx, index);
return duk_require_hobject(ctx, index);
}
-
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_UNEXPECTED_TYPE);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT);
return NULL; /* not reachable */
}
+DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) {
+ duk_hobject *h;
+
+ DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
+ DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
+ if (h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum) {
+ h = NULL;
+ }
+ return h;
+}
+
+DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) {
+ duk_hthread *thr;
+ duk_hobject *h;
+
+ DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
+ DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
+ thr = (duk_hthread *) ctx;
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
+ if (!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum)) {
+ duk_hstring *h_class;
+ h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum));
+ DUK_UNREF(h_class);
+
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE);
+ }
+ return h;
+}
+
DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index) {
duk_tval *tv;
@@ -19914,6 +20261,50 @@ DUK_EXTERNAL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index)
}
#endif
+/* Coerce top into Object.prototype.toString() output. */
+DUK_INTERNAL void duk_to_object_class_string_top(duk_context *ctx) {
+ duk_hthread *thr;
+ duk_uint_t typemask;
+ duk_hstring *h_strclass;
+
+ DUK_ASSERT_CTX_VALID(ctx);
+ thr = (duk_hthread *) ctx;
+
+ typemask = duk_get_type_mask(ctx, -1);
+ if (typemask & DUK_TYPE_MASK_UNDEFINED) {
+ h_strclass = DUK_HTHREAD_STRING_UC_UNDEFINED(thr);
+ } else if (typemask & DUK_TYPE_MASK_NULL) {
+ h_strclass = DUK_HTHREAD_STRING_UC_NULL(thr);
+ } else {
+ duk_hobject *h_obj;
+
+ duk_to_object(ctx, -1);
+ h_obj = duk_get_hobject(ctx, -1);
+ DUK_ASSERT(h_obj != NULL);
+
+ h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h_obj);
+ }
+ DUK_ASSERT(h_strclass != NULL);
+
+ duk_pop(ctx);
+ duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
+}
+
+#if !defined(DUK_USE_PARANOID_ERRORS)
+DUK_INTERNAL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h) {
+ duk_hthread *thr;
+ duk_hstring *h_strclass;
+
+ DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT(h != NULL);
+ thr = (duk_hthread *) ctx;
+
+ h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h);
+ DUK_ASSERT(h_strclass != NULL);
+ duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
+}
+#endif /* !DUK_USE_PARANOID_ERRORS */
+
/* XXX: other variants like uint, u32 etc */
DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) {
duk_hthread *thr = (duk_hthread *) ctx;
@@ -20102,8 +20493,10 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size
* duk_to_dynamic_buffer() call.
*/
duk_uint_t tmp;
+ duk_uint8_t *tmp_ptr;
- src_data = (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf);
+ tmp_ptr = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf);
+ src_data = (const duk_uint8_t *) tmp_ptr;
src_size = DUK_HBUFFER_GET_SIZE(h_buf);
tmp = (DUK_HBUFFER_HAS_DYNAMIC(h_buf) ? DUK_BUF_MODE_DYNAMIC : DUK_BUF_MODE_FIXED);
@@ -20112,7 +20505,7 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size
/* Note: src_data may be NULL if input is a zero-size
* dynamic buffer.
*/
- dst_data = (duk_uint8_t *) src_data;
+ dst_data = tmp_ptr;
goto skip_copy;
}
} else {
@@ -20131,7 +20524,7 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size
* target buffer is dynamic). Avoid zero-size memcpy()
* with an invalid pointer.
*/
- DUK_MEMCPY(dst_data, src_data, src_size);
+ DUK_MEMCPY((void *) dst_data, (const void *) src_data, (size_t) src_size);
}
duk_replace(ctx, index);
skip_copy:
@@ -20410,6 +20803,31 @@ DUK_EXTERNAL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index) {
DUK_UNREACHABLE();
}
+#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
+DUK_LOCAL const char *duk__type_names[] = {
+ "none",
+ "undefined",
+ "null",
+ "boolean",
+ "number",
+ "string",
+ "object",
+ "buffer",
+ "pointer",
+ "lightfunc"
+};
+
+DUK_INTERNAL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index) {
+ duk_int_t type_tag;
+
+ type_tag = duk_get_type(ctx, index);
+ DUK_ASSERT(type_tag >= DUK_TYPE_MIN && type_tag <= DUK_TYPE_MAX);
+ DUK_ASSERT(DUK_TYPE_MIN == 0 && sizeof(duk__type_names) / sizeof(const char *) == DUK_TYPE_MAX + 1);
+
+ return duk__type_names[type_tag];
+}
+#endif
+
DUK_EXTERNAL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t index, duk_int_t type) {
DUK_ASSERT_CTX_VALID(ctx);
@@ -20616,12 +21034,6 @@ DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t index) {
DUK_HOBJECT_FLAG_THREAD);
}
-DUK_EXTERNAL duk_bool_t duk_is_callable(duk_context *ctx, duk_idx_t index) {
- /* XXX: currently same as duk_is_function() */
- DUK_ASSERT_CTX_VALID(ctx);
- return duk_is_function(ctx, index);
-}
-
DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index) {
duk_tval *tv;
@@ -20888,7 +21300,7 @@ DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk
/* check stack before interning (avoid hanging temp) */
if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
+ DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
}
/* NULL with zero length represents an empty string; NULL with higher
@@ -20905,7 +21317,7 @@ DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk
DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, DUK_STR_STRING_TOO_LONG);
}
- h = duk_heap_string_intern_checked(thr, (duk_uint8_t *) str, (duk_uint32_t) len);
+ h = duk_heap_string_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len);
DUK_ASSERT(h != NULL);
tv_slot = thr->valstack_top++;
@@ -21164,7 +21576,7 @@ DUK_EXTERNAL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ct
duk_hthread *thr = (duk_hthread *) ctx;
DUK_ASSERT_CTX_VALID(ctx);
if (!target_ctx) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
return; /* not reached */
}
duk_push_hobject(ctx, (duk_hobject *) target_ctx);
@@ -21241,7 +21653,7 @@ DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va
/* failed, resize and try again */
sz = sz * 2;
if (sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_SPRINTF_TOO_LONG);
+ DUK_ERROR_API(thr, DUK_STR_SPRINTF_TOO_LONG);
}
}
@@ -21281,7 +21693,7 @@ DUK_INTERNAL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobje
/* check stack first */
if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
+ DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
}
h = duk_hobject_alloc(thr->heap, hobject_flags_and_class);
@@ -21381,7 +21793,7 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
/* check stack first */
if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
+ DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
}
obj = duk_hthread_alloc(thr->heap,
@@ -21440,7 +21852,7 @@ DUK_INTERNAL duk_idx_t duk_push_compiledfunction(duk_context *ctx) {
/* check stack first */
if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
+ DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
}
/* Template functions are not strictly constructable (they don't
@@ -21481,7 +21893,7 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function fu
/* check stack first */
if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
+ DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
}
if (func == NULL) {
goto api_error;
@@ -21517,7 +21929,7 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function fu
return ret;
api_error:
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
return 0; /* not reached */
}
@@ -21578,7 +21990,7 @@ DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function fun
/* check stack first */
if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
+ DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
}
if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) {
@@ -21602,7 +22014,7 @@ DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function fun
return ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
api_error:
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
return 0; /* not reached */
}
@@ -21616,7 +22028,7 @@ DUK_INTERNAL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_
/* check stack first */
if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
+ DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
}
obj = duk_hbufferobject_alloc(thr->heap, hobject_flags_and_class);
@@ -21859,7 +22271,7 @@ DUK_EXTERNAL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_sm
/* check stack first */
if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
+ DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
}
/* Check for maximum buffer length. */
@@ -21892,7 +22304,7 @@ DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) {
goto push_undefined;
}
- switch (DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) {
+ switch ((int) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) {
case DUK_HTYPE_STRING:
duk_push_hstring(ctx, (duk_hstring *) ptr);
break;
@@ -21969,13 +22381,13 @@ DUK_EXTERNAL void duk_pop_n(duk_context *ctx, duk_idx_t count) {
DUK_ASSERT_CTX_VALID(ctx);
if (DUK_UNLIKELY(count < 0)) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_COUNT);
+ DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT);
return;
}
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
if (DUK_UNLIKELY((duk_size_t) (thr->valstack_top - thr->valstack_bottom) < (duk_size_t) count)) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_POP_TOO_MANY);
+ DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY);
}
/*
@@ -22027,7 +22439,7 @@ DUK_EXTERNAL void duk_pop(duk_context *ctx) {
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_POP_TOO_MANY);
+ DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY);
}
tv = --thr->valstack_top; /* tv points to element just below prev top */
@@ -22063,7 +22475,7 @@ DUK_EXTERNAL void duk_throw(duk_context *ctx) {
DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
if (thr->valstack_top == thr->valstack_bottom) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
}
/* Errors are augmented when they are created, not when they are
@@ -22283,7 +22695,129 @@ DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, du
duk_push_lstring(ctx, (const char *) buf, sz * 2);
}
+#if !defined(DUK_USE_PARANOID_ERRORS)
+/*
+ * Push readable string summarizing duk_tval. The operation is side effect
+ * free and will only throw from internal errors (e.g. out of memory).
+ * This is used by e.g. property access code to summarize a key/base safely,
+ * and is not intended to be fast (but small and safe).
+ */
+
+#define DUK__READABLE_STRING_MAXCHARS 32
+
+/* String sanitizer which escapes ASCII control characters and a few other
+ * ASCII characters, passes Unicode as is, and replaces invalid UTF-8 with
+ * question marks. No errors are thrown for any input string, except in out
+ * of memory situations.
+ */
+DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring *h_input) {
+ duk_hthread *thr;
+ const duk_uint8_t *p, *p_start, *p_end;
+ duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_STRING_MAXCHARS +
+ 2 /*quotes*/ + 3 /*periods*/];
+ duk_uint8_t *q;
+ duk_ucodepoint_t cp;
+ duk_small_uint_t nchars;
+
+ DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT(h_input != NULL);
+ thr = (duk_hthread *) ctx;
+
+ p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
+ p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
+ p = p_start;
+ q = buf;
+
+ nchars = 0;
+ *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
+ for (;;) {
+ if (p >= p_end) {
+ break;
+ }
+ if (nchars == DUK__READABLE_STRING_MAXCHARS) {
+ *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
+ *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
+ *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
+ break;
+ }
+ if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) {
+ if (cp < 0x20 || cp == 0x7f || cp == DUK_ASC_SINGLEQUOTE || cp == DUK_ASC_BACKSLASH) {
+ DUK_ASSERT(DUK_UNICODE_MAX_XUTF8_LENGTH >= 4); /* estimate is valid */
+ DUK_ASSERT((cp >> 4) <= 0x0f);
+ *q++ = (duk_uint8_t) DUK_ASC_BACKSLASH;
+ *q++ = (duk_uint8_t) DUK_ASC_LC_X;
+ *q++ = (duk_uint8_t) duk_lc_digits[cp >> 4];
+ *q++ = (duk_uint8_t) duk_lc_digits[cp & 0x0f];
+ } else {
+ q += duk_unicode_encode_xutf8(cp, q);
+ }
+ } else {
+ p++; /* advance manually */
+ *q++ = (duk_uint8_t) DUK_ASC_QUESTION;
+ }
+ nchars++;
+ }
+ *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
+
+ duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (q - buf));
+}
+
+DUK_INTERNAL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv) {
+ duk_hthread *thr;
+
+ DUK_ASSERT_CTX_VALID(ctx);
+ thr = (duk_hthread *) ctx;
+ DUK_UNREF(thr);
+
+ if (tv == NULL) {
+ duk_push_string(ctx, "none");
+ } else {
+ switch (DUK_TVAL_GET_TAG(tv)) {
+ case DUK_TAG_STRING: {
+ duk__push_hstring_readable_unicode(ctx, DUK_TVAL_GET_STRING(tv));
+ break;
+ }
+ case DUK_TAG_OBJECT: {
+ duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ duk_push_hobject_class_string(ctx, h);
+ break;
+ }
+ case DUK_TAG_BUFFER: {
+ /* XXX: Hex encoded, length limited buffer summary here? */
+ duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
+ DUK_ASSERT(h != NULL);
+ duk_push_sprintf(ctx, "[buffer:%ld]", (long) DUK_HBUFFER_GET_SIZE(h));
+ break;
+ }
+ case DUK_TAG_POINTER: {
+ /* Surround with parentheses like in JX, ensures NULL pointer
+ * is distinguishable from null value ("(null)" vs "null").
+ */
+ duk_push_tval(ctx, tv);
+ duk_push_sprintf(ctx, "(%s)", duk_to_string(ctx, -1));
+ duk_remove(ctx, -2);
+ break;
+ }
+ default: {
+ duk_push_tval(ctx, tv);
+ break;
+ }
+ }
+ }
+
+ return duk_to_string(ctx, -1);
+}
+
+DUK_INTERNAL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index) {
+ DUK_ASSERT_CTX_VALID(ctx);
+ return duk_push_string_tval_readable(ctx, duk_get_tval(ctx, index));
+}
+#endif /* !DUK_USE_PARANOID_ERRORS */
+
#undef DUK__CHECK_SPACE
+#undef DUK__PACK_ARGS
+#undef DUK__READABLE_STRING_MAXCHARS
#line 1 "duk_api_string.c"
/*
* String manipulation
@@ -22304,7 +22838,7 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
if (DUK_UNLIKELY(count_in <= 0)) {
if (count_in < 0) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_COUNT);
+ DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT);
return;
}
DUK_ASSERT(count_in == 0);
@@ -22420,7 +22954,7 @@ DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decod
h_input = duk_require_hstring(ctx, index);
DUK_ASSERT(h_input != NULL);
- p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
+ p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
p = p_start;
@@ -22451,7 +22985,7 @@ DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char
bw = &bw_alloc;
DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* reasonable output estimate */
- p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
+ p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
p = p_start;
@@ -22585,7 +23119,8 @@ DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) {
DUK_ASSERT(q_end >= q_start);
DUK_DDD(DUK_DDDPRINT("trim: p_start=%p, p_end=%p, q_start=%p, q_end=%p",
- (void *) p_start, (void *) p_end, (void *) q_start, (void *) q_end));
+ (const void *) p_start, (const void *) p_end,
+ (const void *) q_start, (const void *) q_end));
if (q_start == p_start && q_end == p_end) {
DUK_DDD(DUK_DDDPRINT("nothing was trimmed: avoid interning (hashing etc)"));
@@ -23932,9 +24467,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
DUK_ASSERT_TOP(ctx, 2);
len = duk__push_this_obj_len_u32(ctx);
- if (!duk_is_callable(ctx, 0)) {
- goto type_error;
- }
+ duk_require_callable(ctx, 0);
/* if thisArg not supplied, behave as if undefined was supplied */
if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) {
@@ -24049,9 +24582,6 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
}
return 1;
-
- type_error:
- return DUK_RET_TYPE_ERROR;
}
/*
@@ -24619,7 +25149,7 @@ DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx,
DUK_INTERNAL void duk_hbufferobject_push_validated_read(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
duk_double_union du;
- DUK_MEMCPY((void *) du.uc, (const void *) p, elem_size);
+ DUK_MEMCPY((void *) du.uc, (const void *) p, (size_t) elem_size);
switch (h_bufobj->elem_type) {
case DUK_HBUFFEROBJECT_ELEM_UINT8:
@@ -24703,7 +25233,7 @@ DUK_INTERNAL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbuffe
DUK_UNREACHABLE();
}
- DUK_MEMCPY((void *) p, (const void *) du.uc, elem_size);
+ DUK_MEMCPY((void *) p, (const void *) du.uc, (size_t) elem_size);
}
/*
@@ -24894,9 +25424,14 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) {
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) {
+ duk_hthread *thr;
duk_hbufferobject *h_bufobj;
duk_hbuffer *h_val;
+ DUK_ASSERT_CTX_VALID(ctx);
+ thr = (duk_hthread *) ctx;
+ DUK_UNREF(thr);
+
/* XXX: function flag to make this automatic? */
if (!duk_is_constructor_call(ctx)) {
return DUK_RET_TYPE_ERROR;
@@ -24920,6 +25455,14 @@ DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) {
(void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1);
DUK_ASSERT(h_val != NULL);
+
+#if !defined(DUK_USE_ZERO_BUFFER_DATA)
+ /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
+ * is not set.
+ */
+ DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val));
+ DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) len);
+#endif
}
h_bufobj = duk_push_bufferobject_raw(ctx,
@@ -25131,6 +25674,14 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
elem_length_signed = (duk_int_t) duk_get_length(ctx, 0);
copy_mode = 2;
}
+ } else if (DUK_TVAL_IS_BUFFER(tv)) {
+ /* Accept plain buffer values like array initializers
+ * (new in Duktape 1.4.0).
+ */
+ duk_hbuffer *h_srcbuf;
+ h_srcbuf = DUK_TVAL_GET_BUFFER(tv);
+ elem_length_signed = (duk_int_t) DUK_HBUFFER_GET_SIZE(h_srcbuf);
+ copy_mode = 2; /* XXX: could add fast path for u8 compatible views */
} else {
/* Non-object argument is simply int coerced, matches
* V8 behavior (except for "null", which we coerce to
@@ -25277,6 +25828,13 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
* ambiguity with Float32/Float64 because zero bytes also
* represent 0.0.
*/
+#if !defined(DUK_USE_ZERO_BUFFER_DATA)
+ /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
+ * is not set.
+ */
+ DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val));
+ DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) byte_length);
+#endif
DUK_DDD(DUK_DDDPRINT("using no copy"));
break;
@@ -25419,7 +25977,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
if (DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, start_offset + slice_length)) {
DUK_MEMCPY((void *) buf_slice,
(const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
- slice_length);
+ (size_t) slice_length);
} else {
/* not covered, return all zeroes */
;
@@ -28835,7 +29393,10 @@ DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx) {
#if defined(DUK_USE_DATE_NOW_TIME)
/* Not a very good provider: only full seconds are available. */
DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(duk_context *ctx) {
- time_t t = time(NULL);
+ time_t t;
+
+ DUK_UNREF(ctx);
+ t = time(NULL);
return ((duk_double_t) t) * 1000.0;
}
#endif /* DUK_USE_DATE_NOW_TIME */
@@ -28951,6 +29512,13 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
(long) tms[1].tm_mday, (long) tms[1].tm_mon, (long) tms[1].tm_year,
(long) tms[1].tm_wday, (long) tms[1].tm_yday, (long) tms[1].tm_isdst));
+ /* tm_isdst is both an input and an output to mktime(), use 0 to
+ * avoid DST handling in mktime():
+ * - https://github.com/svaarala/duktape/issues/406
+ * - http://stackoverflow.com/questions/8558919/mktime-and-tm-isdst
+ */
+ tms[0].tm_isdst = 0;
+ tms[1].tm_isdst = 0;
t1 = mktime(&tms[0]); /* UTC */
t2 = mktime(&tms[1]); /* local */
if (t1 == (time_t) -1 || t2 == (time_t) -1) {
@@ -28961,11 +29529,6 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
*/
goto error;
}
- if (tms[1].tm_isdst > 0) {
- t2 += 3600;
- } else if (tms[1].tm_isdst < 0) {
- DUK_D(DUK_DPRINT("tm_isdst is negative: %d", (int) tms[1].tm_isdst));
- }
DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2));
/* Compute final offset in seconds, positive if local time ahead of
@@ -29612,7 +30175,7 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
return 1;
}
-#ifdef DUK_USE_TRACEBACKS
+#if defined(DUK_USE_TRACEBACKS)
/*
* Traceback handling
@@ -29633,11 +30196,12 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
#define DUK__OUTPUT_TYPE_FILENAME 0
#define DUK__OUTPUT_TYPE_LINENUMBER 1
-DUK_LOCAL duk_ret_t duk__traceback_getter_helper(duk_context *ctx, duk_small_int_t output_type) {
+DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t output_type) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_idx_t idx_td;
duk_small_int_t i; /* traceback depth fits into 16 bits */
duk_small_int_t t; /* stack type fits into 16 bits */
+ duk_small_int_t count_func = 0; /* traceback depth ensures fits into 16 bits */
const char *str_tailcalled = " tailcalled";
const char *str_strict = " strict";
const char *str_construct = " construct";
@@ -29683,6 +30247,8 @@ DUK_LOCAL duk_ret_t duk__traceback_getter_helper(duk_context *ctx, duk_small_int
* Ecmascript/native function call or lightfunc call
*/
+ count_func++;
+
/* [ ... v1(func) v2(pc+flags) ] */
h_func = duk_get_hobject(ctx, -2); /* NULL for lightfunc */
@@ -29698,11 +30264,16 @@ DUK_LOCAL duk_ret_t duk__traceback_getter_helper(duk_context *ctx, duk_small_int
/* [ ... v1 v2 name filename ] */
- if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
- return 1;
- } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
- duk_push_int(ctx, line);
- return 1;
+ /* When looking for .fileName/.lineNumber, blame first
+ * function which has a .fileName.
+ */
+ if (duk_is_string(ctx, -1)) {
+ if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
+ return 1;
+ } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
+ duk_push_int(ctx, line);
+ return 1;
+ }
}
h_name = duk_get_hstring(ctx, -2); /* may be NULL */
@@ -29752,6 +30323,9 @@ DUK_LOCAL duk_ret_t duk__traceback_getter_helper(duk_context *ctx, duk_small_int
/* [ ... v1(filename) v2(line+flags) ] */
+ /* When looking for .fileName/.lineNumber, blame compilation
+ * or C call site unless flagged not to do so.
+ */
if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) {
if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
duk_pop(ctx);
@@ -29773,7 +30347,7 @@ DUK_LOCAL duk_ret_t duk__traceback_getter_helper(duk_context *ctx, duk_small_int
}
}
- if (i >= DUK_USE_TRACEBACK_DEPTH * 2) {
+ if (count_func >= DUK_USE_TRACEBACK_DEPTH) {
/* Possibly truncated; there is no explicit truncation
* marker so this is the best we can do.
*/
@@ -29796,20 +30370,20 @@ DUK_LOCAL duk_ret_t duk__traceback_getter_helper(duk_context *ctx, duk_small_int
}
}
-/* XXX: output type could be encoded into native function 'magic' value to
- * save space.
+/* XXX: Output type could be encoded into native function 'magic' value to
+ * save space. For setters the stridx could be encoded into 'magic'.
*/
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
- return duk__traceback_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK);
+ return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK);
}
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
- return duk__traceback_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME);
+ return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME);
}
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
- return duk__traceback_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER);
+ return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER);
}
#undef DUK__OUTPUT_TYPE_TRACEBACK
@@ -29849,14 +30423,43 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx
#endif /* DUK_USE_TRACEBACKS */
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_nop_setter(duk_context *ctx) {
- /* Attempt to write 'stack', 'fileName', 'lineNumber' is a silent no-op.
- * User can use Object.defineProperty() to override this behavior.
+DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t stridx_key) {
+ /* Attempt to write 'stack', 'fileName', 'lineNumber' works as if
+ * user code called Object.defineProperty() to create an overriding
+ * own property. This allows user code to overwrite .fileName etc
+ * intuitively as e.g. "err.fileName = 'dummy'" as one might expect.
+ * See https://github.com/svaarala/duktape/issues/387.
*/
- DUK_ASSERT_TOP(ctx, 1); /* fixed arg count */
- DUK_UNREF(ctx);
+
+ DUK_ASSERT_TOP(ctx, 1); /* fixed arg count: value */
+
+ duk_push_this(ctx);
+ duk_push_hstring_stridx(ctx, (duk_small_int_t) stridx_key);
+ duk_dup(ctx, 0);
+
+ /* [ ... obj key value ] */
+
+ DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T",
+ duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1)));
+
+ duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE |
+ DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE |
+ DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/
+ DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE);
return 0;
}
+
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx) {
+ return duk__error_setter_helper(ctx, DUK_STRIDX_STACK);
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx) {
+ return duk__error_setter_helper(ctx, DUK_STRIDX_FILE_NAME);
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx) {
+ return duk__error_setter_helper(ctx, DUK_STRIDX_LINE_NUMBER);
+}
#line 1 "duk_bi_function.c"
/*
* Function built-ins
@@ -30300,7 +30903,7 @@ typedef struct {
const duk_uint8_t *p_end;
} duk__transform_context;
-typedef void (*duk__transform_callback)(duk__transform_context *tfm_ctx, void *udata, duk_codepoint_t cp);
+typedef void (*duk__transform_callback)(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp);
/* XXX: refactor and share with other code */
DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p, duk_small_int_t n) {
@@ -30320,7 +30923,7 @@ DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p, duk_small
return t;
}
-DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback callback, void *udata) {
+DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback callback, const void *udata) {
duk_hthread *thr = (duk_hthread *) ctx;
duk__transform_context tfm_ctx_alloc;
duk__transform_context *tfm_ctx = &tfm_ctx_alloc;
@@ -30348,12 +30951,12 @@ DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback ca
return 1;
}
-DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ctx, void *udata, duk_codepoint_t cp) {
+DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
duk_uint8_t xutf8_buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
duk_small_int_t len;
duk_codepoint_t cp1, cp2;
duk_small_int_t i, t;
- const duk_uint8_t *unescaped_table = (duk_uint8_t *) udata;
+ const duk_uint8_t *unescaped_table = (const duk_uint8_t *) udata;
/* UTF-8 encoded bytes escaped as %xx%xx%xx... -> 3 * nbytes.
* Codepoint range is restricted so this is a slightly too large
@@ -30410,8 +31013,8 @@ DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ct
DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input");
}
-DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, void *udata, duk_codepoint_t cp) {
- const duk_uint8_t *reserved_table = (duk_uint8_t *) udata;
+DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
+ const duk_uint8_t *reserved_table = (const duk_uint8_t *) udata;
duk_small_uint_t utf8_blen;
duk_codepoint_t min_cp;
duk_small_int_t t; /* must be signed */
@@ -30549,7 +31152,7 @@ DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ct
}
#ifdef DUK_USE_SECTION_B
-DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, void *udata, duk_codepoint_t cp) {
+DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
DUK_UNREF(udata);
DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 6);
@@ -30588,7 +31191,7 @@ DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, v
DUK_ERROR(tfm_ctx->thr, DUK_ERR_TYPE_ERROR, "invalid input");
}
-DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, void *udata, duk_codepoint_t cp) {
+DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
duk_small_int_t t;
DUK_UNREF(udata);
@@ -30634,6 +31237,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
duk_hobject *outer_var_env;
duk_bool_t this_to_global = 1;
duk_small_uint_t comp_flags;
+ duk_int_t level = -2;
DUK_ASSERT_TOP(ctx, 1);
DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */
@@ -30653,15 +31257,26 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
return 1; /* return arg as-is */
}
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ /* NOTE: level is used only by the debugger and should never be present
+ * for an Ecmascript eval().
+ */
+ DUK_ASSERT(level == -2); /* by default, use caller's environment */
+ if (duk_get_top(ctx) >= 2 && duk_is_number(ctx, 1)) {
+ level = duk_get_int(ctx, 1);
+ }
+ DUK_ASSERT(level <= -2); /* This is guaranteed by debugger code. */
+#endif
+
/* [ source ] */
comp_flags = DUK_JS_COMPILE_FLAG_EVAL;
act_eval = thr->callstack + thr->callstack_top - 1; /* this function */
- if (thr->callstack_top >= 2) {
+ if (thr->callstack_top >= (duk_size_t) -level) {
/* Have a calling activation, check for direct eval (otherwise
* assume indirect eval.
*/
- act_caller = thr->callstack + thr->callstack_top - 2; /* caller */
+ act_caller = thr->callstack + thr->callstack_top + level; /* caller */
if ((act_caller->flags & DUK_ACT_FLAG_STRICT) &&
(act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL)) {
/* Only direct eval inherits strictness from calling code
@@ -30691,14 +31306,14 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
act = thr->callstack + thr->callstack_top - 1; /* this function */
if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
DUK_ASSERT(thr->callstack_top >= 2);
- act = thr->callstack + thr->callstack_top - 2; /* caller */
+ act = thr->callstack + thr->callstack_top + level; /* caller */
if (act->lex_env == NULL) {
DUK_ASSERT(act->var_env == NULL);
DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
/* this may have side effects, so re-lookup act */
duk_js_init_activation_environment_records_delayed(thr, act);
- act = thr->callstack + thr->callstack_top - 2;
+ act = thr->callstack + thr->callstack_top + level;
}
DUK_ASSERT(act->lex_env != NULL);
DUK_ASSERT(act->var_env != NULL);
@@ -30713,7 +31328,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
"var_env and lex_env to a fresh env, "
"this_binding to caller's this_binding"));
- act = thr->callstack + thr->callstack_top - 2; /* caller */
+ act = thr->callstack + thr->callstack_top + level; /* caller */
act_lex_env = act->lex_env;
act = NULL; /* invalidated */
@@ -30764,7 +31379,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
} else {
duk_tval *tv;
DUK_ASSERT(thr->callstack_top >= 2);
- act = thr->callstack + thr->callstack_top - 2; /* caller */
+ act = thr->callstack + thr->callstack_top + level; /* caller */
tv = thr->valstack + act->idx_bottom - 1; /* this is just beneath bottom */
DUK_ASSERT(tv >= thr->valstack);
duk_push_tval(ctx, tv);
@@ -30789,44 +31404,39 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
*/
DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) {
- duk_bool_t strip_prefix;
duk_int32_t radix;
duk_small_uint_t s2n_flags;
DUK_ASSERT_TOP(ctx, 2);
duk_to_string(ctx, 0);
- strip_prefix = 1;
radix = duk_to_int32(ctx, 1);
+
+ s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
+ DUK_S2N_FLAG_ALLOW_GARBAGE |
+ DUK_S2N_FLAG_ALLOW_PLUS |
+ DUK_S2N_FLAG_ALLOW_MINUS |
+ DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
+ DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
+
+ /* Specification stripPrefix maps to DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT.
+ *
+ * Don't autodetect octals (from leading zeroes), require user code to
+ * provide an explicit radix 8 for parsing octal. See write-up from Mozilla:
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#ECMAScript_5_Removes_Octal_Interpretation
+ */
+
if (radix != 0) {
if (radix < 2 || radix > 36) {
goto ret_nan;
}
- /* For octal, setting strip_prefix=0 is not necessary, as zero
- * is tolerated anyway:
- *
- * parseInt('123', 8) === parseInt('0123', 8) with or without strip_prefix
- * parseInt('123', 16) === parseInt('0x123', 16) requires strip_prefix = 1
- */
if (radix != 16) {
- strip_prefix = 0;
+ s2n_flags &= ~DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
}
} else {
radix = 10;
}
- s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
- DUK_S2N_FLAG_ALLOW_GARBAGE |
- DUK_S2N_FLAG_ALLOW_PLUS |
- DUK_S2N_FLAG_ALLOW_MINUS |
- DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
-#ifdef DUK_USE_OCTAL_SUPPORT
- (strip_prefix ? (DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT | DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT) : 0)
-#else
- (strip_prefix ? DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT : 0)
-#endif
- ;
-
duk_dup(ctx, 0);
duk_numconv_parse(ctx, radix, s2n_flags);
return 1;
@@ -30882,28 +31492,28 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx) {
*/
DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (void *) duk__decode_uri_reserved_table);
+ return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table);
}
DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (void *) duk__decode_uri_component_reserved_table);
+ return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_component_reserved_table);
}
DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (void *) duk__encode_uriunescaped_table);
+ return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uriunescaped_table);
}
DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (void *) duk__encode_uricomponent_unescaped_table);
+ return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table);
}
#ifdef DUK_USE_SECTION_B
DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_escape, (void *) NULL);
+ return duk__transform_helper(ctx, duk__transform_callback_escape, (const void *) NULL);
}
DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_unescape, (void *) NULL);
+ return duk__transform_helper(ctx, duk__transform_callback_unescape, (const void *) NULL);
}
#else /* DUK_USE_SECTION_B */
DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) {
@@ -30974,13 +31584,13 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
}
if (sz_buf <= sizeof(buf_stack)) {
- buf = (const duk_uint8_t *) buf_stack;
+ p = (duk_uint8_t *) buf_stack;
} else {
- buf = (const duk_uint8_t *) duk_push_fixed_buffer(ctx, sz_buf);
- DUK_ASSERT(buf != NULL);
+ p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, sz_buf);
+ DUK_ASSERT(p != NULL);
}
- p = (duk_uint8_t *) buf;
+ buf = (const duk_uint8_t *) p;
for (i = 0; i < nargs; i++) {
p_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &sz_str);
DUK_ASSERT(p_str != NULL);
@@ -31474,9 +32084,10 @@ DUK_LOCAL_DECL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *p);
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 duk_bool_t duk__enc_key_quotes_needed(duk_hstring *h_key);
+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_hstring **h_stepback, duk_hstring **h_indent, duk_idx_t *entry_top);
-DUK_LOCAL_DECL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_hstring **h_stepback, duk_hstring **h_indent, duk_idx_t *entry_top);
+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_value1(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder);
@@ -31486,6 +32097,14 @@ DUK_LOCAL_DECL void duk__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);
#endif
+#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
+DUK_LOCAL_DECL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
+DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr);
+#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
+DUK_LOCAL_DECL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj);
+#endif
+#endif
+DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth);
/*
* Helper tables
@@ -31700,7 +32319,7 @@ DUK_LOCAL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx,
DUK_LOCAL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx) {
duk_hstring *h;
- duk_uint8_t *p;
+ const duk_uint8_t *p;
duk_uint8_t x, y;
/* First character has already been eaten and checked by the caller.
@@ -31713,7 +32332,7 @@ DUK_LOCAL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t st
h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
DUK_ASSERT(h != NULL);
- p = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + 1;
+ p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + 1;
DUK_ASSERT(*(js_ctx->p - 1) == *(p - 1)); /* first character has been matched */
for (;;) {
@@ -31996,12 +32615,26 @@ DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
duk_hthread *thr = js_ctx->thr;
duk_context *ctx = (duk_context *) thr;
const duk_uint8_t *p;
+ duk_uint8_t *buf;
+ duk_size_t src_len;
duk_small_int_t x;
/* Caller has already eaten the first character ('|') which we don't need. */
p = js_ctx->p;
+ /* XXX: Would be nice to share the fast path loop from duk_hex_decode()
+ * and avoid creating a temporary buffer. However, there are some
+ * differences which prevent trivial sharing:
+ *
+ * - Pipe char detection
+ * - EOF detection
+ * - Unknown length of input and output
+ *
+ * The best approach here would be a bufwriter and a reasonaly sized
+ * safe inner loop (e.g. 64 output bytes at a time).
+ */
+
for (;;) {
x = *p;
@@ -32017,8 +32650,12 @@ DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
p++;
}
- duk_push_lstring(ctx, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p));
+ src_len = (duk_size_t) (p - js_ctx->p);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_len);
+ DUK_ASSERT(buf != NULL);
+ DUK_MEMCPY((void *) buf, (const void *) js_ctx->p, src_len);
duk_hex_decode(ctx, -1);
+
js_ctx->p = p + 1; /* skip '|' */
/* [ ... buf ] */
@@ -32052,8 +32689,8 @@ DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) {
x = *p;
DUK_DDD(DUK_DDDPRINT("parse_number: p_start=%p, p=%p, p_end=%p, x=%ld",
- (void *) p_start, (void *) p,
- (void *) js_ctx->p_end, (long) x));
+ (const void *) p_start, (const void *) p,
+ (const void *) js_ctx->p_end, (long) x));
#if defined(DUK_USE_JSON_DECNUMBER_FASTPATH)
/* This fast path is pretty marginal in practice.
@@ -32552,7 +33189,8 @@ DUK_LOCAL duk_bool_t duk__enc_key_quotes_needed(duk_hstring *h_key) {
p = p_start;
DUK_DDD(DUK_DDDPRINT("duk__enc_key_quotes_needed: h_key=%!O, p_start=%p, p_end=%p, p=%p",
- (duk_heaphdr *) h_key, (void *) p_start, (void *) p_end, (void *) p));
+ (duk_heaphdr *) h_key, (const void *) p_start,
+ (const void *) p_end, (const void *) p));
/* Since we only accept ASCII characters, there is no need for
* actual decoding. A non-ASCII character will be >= 0x80 which
@@ -32583,6 +33221,17 @@ DUK_LOCAL duk_bool_t duk__enc_key_quotes_needed(duk_hstring *h_key) {
return 0;
}
+DUK_LOCAL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k) {
+ /* XXX: could reimplement so that we start emitting the key without
+ * quotes and backtrack if we hit a problem character.
+ */
+ if (js_ctx->flag_avoid_key_quotes && !duk__enc_key_quotes_needed(k)) {
+ DUK__EMIT_HSTR(js_ctx, k);
+ } else {
+ duk__enc_quote_string(js_ctx, k);
+ }
+}
+
/* The Quote(value) operation: quote a string.
*
* Stack policy: [ ] -> [ ].
@@ -32757,7 +33406,7 @@ DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
* it would otherwise serialize to '0', not '-0'.
*/
if (DUK_UNLIKELY(c == DUK_FP_ZERO && s != 0 &&
- (js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible))) {
+ (js_ctx->flag_ext_custom_or_compatible))) {
duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_ZERO); /* '-0' */
} else
#endif /* DUK_USE_JX || DUK_USE_JC */
@@ -32814,35 +33463,306 @@ DUK_LOCAL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv) {
}
#endif
-/* Shared entry handling for object/array serialization: indent/stepback,
- * loop detection.
+#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_uint8_t *q;
+ duk_uint16_t *q16;
+ duk_small_uint_t x;
+ duk_size_t i, len_safe;
+#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
+ duk_bool_t shift_dst;
+#endif
+
+ /* Unlike in duk_hex_encode() 'dst' is not necessarily aligned by 2.
+ * For platforms where unaligned accesses are not allowed, shift 'dst'
+ * ahead by 1 byte to get alignment and then DUK_MEMMOVE() the result
+ * in place. The faster encoding loop makes up the difference.
+ * There's always space for one extra byte because a terminator always
+ * follows the hex data and that's been accounted for by the caller.
+ */
+
+#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
+ q16 = (duk_uint16_t *) (void *) dst;
+#else
+ shift_dst = (duk_bool_t) (((duk_uintptr_t) dst) & 0x01U);
+ if (shift_dst) {
+ DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst not aligned -> step to dst + 1"));
+ q16 = (duk_uint16_t *) (void *) (dst + 1);
+ } else {
+ DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst is aligned"));
+ q16 = (duk_uint16_t *) (void *) dst;
+ }
+ DUK_ASSERT((((duk_uintptr_t) q16) & 0x01U) == 0);
+#endif
+
+ len_safe = src_len & ~0x03U;
+ for (i = 0; i < len_safe; i += 4) {
+ q16[0] = duk_hex_enctab[src[i]];
+ q16[1] = duk_hex_enctab[src[i + 1]];
+ q16[2] = duk_hex_enctab[src[i + 2]];
+ q16[3] = duk_hex_enctab[src[i + 3]];
+ q16 += 4;
+ }
+ q = (duk_uint8_t *) q16;
+
+#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
+ if (shift_dst) {
+ q--;
+ DUK_MEMMOVE((void *) dst, (const void *) (dst + 1), 2 * len_safe);
+ DUK_ASSERT(dst + 2 * len_safe == q);
+ }
+#endif
+
+ for (; i < src_len; i++) {
+ x = src[i];
+ *q++ = duk_lc_digits[x >> 4];
+ *q++ = duk_lc_digits[x & 0x0f];
+ }
+
+ 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) {
+ const duk_uint8_t *p;
+ const duk_uint8_t *p_end;
+ duk_uint8_t *q;
+ duk_small_uint_t x;
+
+ p = src;
+ p_end = src + src_len;
+ q = dst;
+ while (p != p_end) {
+ x = *p++;
+ *q++ = duk_lc_digits[x >> 4];
+ *q++ = duk_lc_digits[x & 0x0f];
+ }
+
+ return q;
+}
+#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_hthread *thr;
+ duk_uint8_t *q;
+ duk_size_t space;
+
+ thr = js_ctx->thr;
+
+ DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */
+ DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible);
+
+ /* Buffer values are encoded in (lowercase) hex to make the
+ * binary data readable. Base64 or similar would be more
+ * compact but less readable, and the point of JX/JC
+ * variants is to be as useful to a programmer as possible.
+ */
+
+ /* The #ifdef clutter here needs to handle the three cases:
+ * (1) JX+JC, (2) JX only, (3) JC only.
+ */
+
+ /* Note: space must cater for both JX and JC. */
+ space = 9 + buf_len * 2 + 2;
+ DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7ffffffeUL);
+ DUK_ASSERT((space - 2) / 2 >= buf_len); /* overflow not possible, buffer limits */
+ q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space);
+
+#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
+ if (js_ctx->flag_ext_custom)
+#endif
+#if defined(DUK_USE_JX)
+ {
+ *q++ = DUK_ASC_PIPE;
+ q = duk__enc_buffer_data_hex(buf_data, buf_len, q);
+ *q++ = DUK_ASC_PIPE;
+
+ }
+#endif
+#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
+ else
+#endif
+#if defined(DUK_USE_JC)
+ {
+ 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_ASC_DOUBLEQUOTE;
+ *q++ = DUK_ASC_RCURLY;
+ }
+#endif
+
+ DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
+}
+
+DUK_LOCAL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
+ duk__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_JX) || defined(DUK_USE_JC)
+DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
+ char buf[64]; /* XXX: how to figure correct size? */
+ const char *fmt;
+
+ DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */
+ DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible);
+
+ DUK_MEMZERO(buf, sizeof(buf));
+
+ /* The #ifdef clutter here needs to handle the three cases:
+ * (1) JX+JC, (2) JX only, (3) JC only.
+ */
+#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
+ if (js_ctx->flag_ext_custom)
+#endif
+#if defined(DUK_USE_JX)
+ {
+ fmt = ptr ? "(%p)" : "(null)";
+ }
+#endif
+#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
+ else
+#endif
+#if defined(DUK_USE_JC)
+ {
+ DUK_ASSERT(js_ctx->flag_ext_compatible);
+ fmt = ptr ? "{\"_ptr\":\"%p\"}" : "{\"_ptr\":\"null\"}";
+ }
+#endif
+
+ /* When ptr == NULL, the format argument is unused. */
+ DUK_SNPRINTF(buf, sizeof(buf) - 1, fmt, ptr); /* must not truncate */
+ DUK__EMIT_CSTR(js_ctx, buf);
+}
+#endif /* DUK_USE_JX || DUK_USE_JC */
+
+#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
+#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
+DUK_LOCAL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj) {
+ DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+
+ if (h_bufobj->buf == NULL || !DUK_HBUFFEROBJECT_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_uint8_t *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj),
+ (duk_size_t) h_bufobj->length);
+ }
+}
+#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */
+#endif /* DUK_USE_JX || DUK_USE_JC */
+
+/* Indent helper. Calling code relies on js_ctx->recursion_depth also being
+ * directly related to indent depth.
*/
-DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_hstring **h_stepback, duk_hstring **h_indent, duk_idx_t *entry_top) {
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
+ DUK_ASSERT(js_ctx->h_gap != NULL);
+ DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */
+
+ DUK__EMIT_1(js_ctx, 0x0a);
+ while (depth-- > 0) {
+ DUK__EMIT_HSTR(js_ctx, js_ctx->h_gap);
+ }
+}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
+ const duk_uint8_t *gap_data;
+ duk_size_t gap_len;
+ duk_size_t avail_bytes; /* bytes of indent available for copying */
+ duk_size_t need_bytes; /* bytes of indent still needed */
+ duk_uint8_t *p_start;
+ duk_uint8_t *p;
+
+ DUK_ASSERT(js_ctx->h_gap != NULL);
+ DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */
+
+ DUK__EMIT_1(js_ctx, 0x0a);
+ if (DUK_UNLIKELY(depth == 0)) {
+ return;
+ }
+
+ /* To handle deeper indents efficiently, make use of copies we've
+ * already emitted. In effect we can emit a sequence of 1, 2, 4,
+ * 8, etc copies, and then finish the last run. Byte counters
+ * avoid multiply with gap_len on every loop.
+ */
+
+ gap_data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(js_ctx->h_gap);
+ gap_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap);
+ DUK_ASSERT(gap_len > 0);
+
+ need_bytes = gap_len * depth;
+ p = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, need_bytes);
+ p_start = p;
+
+ DUK_MEMCPY((void *) p, (const void *) gap_data, (size_t) gap_len);
+ p += gap_len;
+ avail_bytes = gap_len;
+ DUK_ASSERT(need_bytes >= gap_len);
+ need_bytes -= gap_len;
+
+ while (need_bytes >= avail_bytes) {
+ DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) avail_bytes);
+ p += avail_bytes;
+ need_bytes -= avail_bytes;
+ avail_bytes <<= 1;
+ }
+
+ DUK_ASSERT(need_bytes < avail_bytes); /* need_bytes may be zero */
+ DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) need_bytes);
+ p += need_bytes;
+ /*avail_bytes += need_bytes*/
+
+ DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, p);
+}
+#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_context *ctx = (duk_context *) js_ctx->thr;
duk_hobject *h_target;
+ duk_uint_fast32_t i, n;
*entry_top = duk_get_top(ctx);
duk_require_stack(ctx, DUK_JSON_ENC_REQSTACK);
- /* loop check */
+ /* Loop check using a hybrid approach: a fixed-size visited[] array
+ * with overflow in a loop check object.
+ */
h_target = duk_get_hobject(ctx, -1); /* object or array */
DUK_ASSERT(h_target != NULL);
- /* XXX: this check is very expensive, perhaps use a small
- * array to make it faster for at least reasonably shallow
- * objects?
- */
- duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
- duk_dup_top(ctx); /* -> [ ... voidp voidp ] */
- if (duk_has_prop(ctx, js_ctx->idx_loop)) {
- DUK_ERROR((duk_hthread *) ctx, DUK_ERR_TYPE_ERROR, DUK_STR_CYCLIC_INPUT);
+ n = js_ctx->recursion_depth;
+ if (DUK_UNLIKELY(n > DUK_JSON_ENC_LOOPARRAY)) {
+ n = DUK_JSON_ENC_LOOPARRAY;
+ }
+ for (i = 0; i < n; i++) {
+ if (DUK_UNLIKELY(js_ctx->visiting[i] == h_target)) {
+ DUK_DD(DUK_DDPRINT("slow path loop detect"));
+ DUK_ERROR(js_ctx->thr, DUK_ERR_TYPE_ERROR, DUK_STR_CYCLIC_INPUT);
+ }
+ }
+ if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
+ js_ctx->visiting[js_ctx->recursion_depth] = h_target;
+ } else {
+ duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
+ duk_dup_top(ctx); /* -> [ ... voidp voidp ] */
+ if (duk_has_prop(ctx, js_ctx->idx_loop)) {
+ DUK_ERROR((duk_hthread *) ctx, DUK_ERR_TYPE_ERROR, DUK_STR_CYCLIC_INPUT);
+ }
+ duk_push_true(ctx); /* -> [ ... voidp true ] */
+ duk_put_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
}
- duk_push_true(ctx); /* -> [ ... voidp true ] */
- duk_put_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
- /* c recursion check */
+ /* C recursion check. */
DUK_ASSERT(js_ctx->recursion_depth >= 0);
DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
@@ -32851,71 +33771,34 @@ DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_hstring **h_s
}
js_ctx->recursion_depth++;
- /* figure out indent and stepback */
-
- *h_indent = NULL;
- *h_stepback = NULL;
- if (js_ctx->h_gap != NULL) {
- DUK_ASSERT(js_ctx->h_indent != NULL);
-
- *h_stepback = js_ctx->h_indent;
- duk_push_hstring(ctx, js_ctx->h_indent);
- duk_push_hstring(ctx, js_ctx->h_gap);
- duk_concat(ctx, 2);
- js_ctx->h_indent = duk_get_hstring(ctx, -1);
- *h_indent = js_ctx->h_indent;
- DUK_ASSERT(js_ctx->h_indent != NULL);
-
- /* The new indent string is left at value stack top, and will
- * be popped by the shared exit handler.
- */
- } else {
- DUK_ASSERT(js_ctx->h_indent == NULL);
- }
-
DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
(long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop)));
}
/* Shared exit handling for object/array serialization. */
-DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_hstring **h_stepback, duk_hstring **h_indent, duk_idx_t *entry_top) {
+DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
duk_context *ctx = (duk_context *) js_ctx->thr;
duk_hobject *h_target;
- DUK_UNREF(h_indent);
-
- if (js_ctx->h_gap != NULL) {
- DUK_ASSERT(js_ctx->h_indent != NULL);
- DUK_ASSERT(*h_stepback != NULL);
- DUK_ASSERT(*h_indent != NULL);
-
- js_ctx->h_indent = *h_stepback; /* previous js_ctx->h_indent */
-
- /* Note: we don't need to pop anything because the duk_set_top()
- * at the end will take care of it.
- */
- } else {
- DUK_ASSERT(js_ctx->h_indent == NULL);
- DUK_ASSERT(*h_stepback == NULL);
- DUK_ASSERT(*h_indent == NULL);
- }
-
- /* c recursion check */
+ /* C recursion check. */
DUK_ASSERT(js_ctx->recursion_depth > 0);
DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
js_ctx->recursion_depth--;
- /* loop check */
+ /* Loop check. */
h_target = duk_get_hobject(ctx, *entry_top - 1); /* original target at entry_top - 1 */
DUK_ASSERT(h_target != NULL);
- /* XXX: this check is very expensive */
- duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
- duk_del_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
+ if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
+ /* Previous entry was inside visited[], nothing to do. */
+ } else {
+ duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
+ duk_del_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
+ }
- /* restore stack top after unbalanced code paths */
+ /* Restore stack top after unbalanced code paths. */
duk_set_top(ctx, *entry_top);
DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
@@ -32928,8 +33811,6 @@ DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_hstring **h_st
*/
DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_hstring *h_stepback;
- duk_hstring *h_indent;
duk_hstring *h_key;
duk_idx_t entry_top;
duk_idx_t idx_obj;
@@ -32940,7 +33821,7 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
- duk__enc_objarr_entry(js_ctx, &h_stepback, &h_indent, &entry_top);
+ duk__enc_objarr_entry(js_ctx, &entry_top);
idx_obj = entry_top - 1;
@@ -32991,21 +33872,16 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
} else {
DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
}
- if (h_indent != NULL) {
- DUK__EMIT_1(js_ctx, 0x0a);
- DUK__EMIT_HSTR(js_ctx, h_indent);
+ if (js_ctx->h_gap != NULL) {
+ DUK_ASSERT(js_ctx->recursion_depth >= 1);
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
}
h_key = duk_get_hstring(ctx, -2);
DUK_ASSERT(h_key != NULL);
- if (js_ctx->flag_avoid_key_quotes && !duk__enc_key_quotes_needed(h_key)) {
- /* emit key as is */
- DUK__EMIT_HSTR(js_ctx, h_key);
- } else {
- duk__enc_quote_string(js_ctx, h_key);
- }
+ duk__enc_key_autoquote(js_ctx, h_key);
- if (h_indent != NULL) {
+ if (js_ctx->h_gap != NULL) {
DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
} else {
DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
@@ -33017,15 +33893,14 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
}
if (!first) {
- if (h_stepback != NULL) {
- DUK_ASSERT(h_indent != NULL);
- DUK__EMIT_1(js_ctx, 0x0a);
- DUK__EMIT_HSTR(js_ctx, h_stepback);
+ if (js_ctx->h_gap != NULL) {
+ DUK_ASSERT(js_ctx->recursion_depth >= 1);
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
}
}
DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
- duk__enc_objarr_exit(js_ctx, &h_stepback, &h_indent, &entry_top);
+ duk__enc_objarr_exit(js_ctx, &entry_top);
DUK_ASSERT_TOP(ctx, entry_top);
}
@@ -33036,8 +33911,6 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
*/
DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_hstring *h_stepback;
- duk_hstring *h_indent;
duk_idx_t entry_top;
duk_idx_t idx_arr;
duk_bool_t undef;
@@ -33046,7 +33919,7 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
DUK_DDD(DUK_DDDPRINT("duk__enc_array: array=%!T",
(duk_tval *) duk_get_tval(ctx, -1)));
- duk__enc_objarr_entry(js_ctx, &h_stepback, &h_indent, &entry_top);
+ duk__enc_objarr_entry(js_ctx, &entry_top);
idx_arr = entry_top - 1;
@@ -33056,16 +33929,16 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_arr);
for (i = 0; i < arr_len; i++) {
- DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, h_indent=%!O, h_stepback=%!O, index=%ld, arr_len=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_arr), (duk_heaphdr *) h_indent,
- (duk_heaphdr *) h_stepback, (long) i, (long) arr_len));
+ DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, index=%ld, arr_len=%ld",
+ (duk_tval *) duk_get_tval(ctx, idx_arr),
+ (long) i, (long) arr_len));
if (i > 0) {
DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
}
- if (h_indent != NULL) {
- DUK__EMIT_1(js_ctx, 0x0a);
- DUK__EMIT_HSTR(js_ctx, h_indent);
+ if (js_ctx->h_gap != NULL) {
+ DUK_ASSERT(js_ctx->recursion_depth >= 1);
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
}
/* XXX: duk_push_uint_string() */
@@ -33082,15 +33955,14 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
}
if (arr_len > 0) {
- if (h_stepback != NULL) {
- DUK_ASSERT(h_indent != NULL);
- DUK__EMIT_1(js_ctx, 0x0a);
- DUK__EMIT_HSTR(js_ctx, h_stepback);
+ if (js_ctx->h_gap != NULL) {
+ DUK_ASSERT(js_ctx->recursion_depth >= 1);
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
}
}
DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
- duk__enc_objarr_exit(js_ctx, &h_stepback, &h_indent, &entry_top);
+ duk__enc_objarr_exit(js_ctx, &entry_top);
DUK_ASSERT_TOP(ctx, entry_top);
}
@@ -33290,35 +34162,7 @@ DUK_LOCAL void duk__enc_value2(duk_json_enc_ctx *js_ctx) {
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
/* When JX/JC not in use, duk__enc_value1 will block pointer values. */
case DUK_TAG_POINTER: {
- char buf[64]; /* XXX: how to figure correct size? */
- const char *fmt;
- void *ptr = DUK_TVAL_GET_POINTER(tv);
-
- DUK_MEMZERO(buf, sizeof(buf));
-
- /* The #ifdef clutter here needs to handle the three cases:
- * (1) JX+JC, (2) JX only, (3) JC only.
- */
-#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
- if (js_ctx->flag_ext_custom)
-#endif
-#if defined(DUK_USE_JX)
- {
- fmt = ptr ? "(%p)" : "(null)";
- }
-#endif
-#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
- else
-#endif
-#if defined(DUK_USE_JC)
- {
- fmt = ptr ? "{\"_ptr\":\"%p\"}" : "{\"_ptr\":\"null\"}";
- }
-#endif
-
- /* When ptr == NULL, the format argument is unused. */
- DUK_SNPRINTF(buf, sizeof(buf) - 1, fmt, ptr); /* must not truncate */
- DUK__EMIT_CSTR(js_ctx, buf);
+ duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
break;
}
#endif /* DUK_USE_JX || DUK_USE_JC */
@@ -33350,59 +34194,7 @@ DUK_LOCAL void duk__enc_value2(duk_json_enc_ctx *js_ctx) {
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
/* When JX/JC not in use, duk__enc_value1 will block buffer values. */
case DUK_TAG_BUFFER: {
- /* Buffer values are encoded in (lowercase) hex to make the
- * binary data readable. Base64 or similar would be more
- * compact but less readable, and the point of JX/JC
- * variants is to be as useful to a programmer as possible.
- */
-
- /* The #ifdef clutter here needs to handle the three cases:
- * (1) JX+JC, (2) JX only, (3) JC only.
- */
-#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
- if (js_ctx->flag_ext_custom)
-#endif
-#if defined(DUK_USE_JX)
- {
- duk_uint8_t *p, *p_end;
- duk_small_uint_t x;
- duk_hbuffer *h;
- duk_uint8_t *q;
- duk_size_t space;
-
- h = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h != NULL);
- p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h);
- p_end = p + DUK_HBUFFER_GET_SIZE(h);
-
- space = 1 + DUK_HBUFFER_GET_SIZE(h) * 2 + 1;
- DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7ffffffeUL);
- DUK_ASSERT((space - 2) / 2 == DUK_HBUFFER_GET_SIZE(h)); /* overflow not possible, buffer limits */
- q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space);
-
- *q++ = DUK_ASC_PIPE;
- while (p < p_end) {
- x = *p++;
- *q++ = duk_lc_digits[(x >> 4) & 0x0f];
- *q++ = duk_lc_digits[x & 0x0f];
- }
- *q++ = DUK_ASC_PIPE;
-
- DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
- }
-#endif
-#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
- else
-#endif
-#if defined(DUK_USE_JC)
- {
- DUK_ASSERT(js_ctx->flag_ext_compatible);
- duk_hex_encode(ctx, -1);
- DUK__EMIT_CSTR(js_ctx, "{\"_buf\":");
- duk__enc_quote_string(js_ctx, duk_require_hstring(ctx, -1));
- DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
- }
-#endif
+ duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv));
break;
}
#endif /* DUK_USE_JX || DUK_USE_JC */
@@ -33464,6 +34256,11 @@ DUK_LOCAL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv) {
/*
* JSON.stringify() fast path
+ *
+ * Otherwise supports full JSON, JX, and JC features, but bails out on any
+ * possible side effect which might change the value being serialized. The
+ * fast path can take advantage of the fact that the value being serialized
+ * is unchanged so that we can walk directly through property tables etc.
*/
#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
@@ -33474,19 +34271,22 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
DUK_ASSERT(js_ctx != NULL);
DUK_ASSERT(js_ctx->thr != NULL);
-#if defined(DUK_USE_JX)
- DUK_ASSERT(js_ctx->flag_ext_custom == 0);
-#endif
-#if defined(DUK_USE_JC)
- DUK_ASSERT(js_ctx->flag_ext_compatible == 0);
-#endif
restart_match:
DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
case DUK_TAG_UNDEFINED: {
+#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
+ if (js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible) {
+ DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
+ break;
+ } else {
+ goto emit_undefined;
+ }
+#else
goto emit_undefined;
+#endif
}
case DUK_TAG_NULL: {
DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
@@ -33509,7 +34309,8 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
duk_hobject *obj;
duk_tval *tv_val;
duk_bool_t emitted = 0;
- duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef, c_object;
+ duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef,
+ c_func, c_bufobj, c_object;
/* For objects JSON.stringify() only looks for own, enumerable
* properties which is nice for the fast path here.
@@ -33526,12 +34327,16 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
* execution time for input data with a lot of small objects!).
*/
- obj = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(obj != NULL);
+ /* XXX: for real world code, could just ignore array inheritance
+ * and only look at array own properties.
+ */
/* We rely on a few object flag / class number relationships here,
* assert for them.
*/
+
+ obj = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(obj != NULL);
DUK_ASSERT_HOBJECT_VALID(obj);
/* Once recursion depth is increased, exit path must decrease
@@ -33546,7 +34351,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
}
for (i = 0, n = (duk_uint_fast32_t) js_ctx->recursion_depth; i < n; i++) {
- if (js_ctx->visiting[i] == obj) {
+ if (DUK_UNLIKELY(js_ctx->visiting[i] == obj)) {
DUK_DD(DUK_DDPRINT("fast path loop detect"));
DUK_ERROR(js_ctx->thr, DUK_ERR_TYPE_ERROR, DUK_STR_CYCLIC_INPUT);
}
@@ -33566,6 +34371,9 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
* If an object is a Proxy we also can't avoid side effects
* so abandon.
*/
+ /* XXX: non-callable .toJSON() doesn't need to cause an abort
+ * but does at the moment, probably not worth fixing.
+ */
if (duk_hobject_hasprop_raw(js_ctx->thr, obj, DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr)) ||
DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) {
DUK_DD(DUK_DDPRINT("object has a .toJSON property or object is a Proxy, abort fast path"));
@@ -33577,15 +34385,38 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
* should be in order of relevancy.
*/
+ /* XXX: move masks to js_ctx? they don't change during one
+ * fast path invocation.
+ */
DUK_ASSERT(DUK_HOBJECT_CLASS_MAX <= 31);
- c_all = DUK_HOBJECT_CMASK_ALL;
- c_array = DUK_HOBJECT_CMASK_ARRAY;
- c_unbox = DUK_HOBJECT_CMASK_NUMBER |
- DUK_HOBJECT_CMASK_STRING |
- DUK_HOBJECT_CMASK_BOOLEAN;
- c_undef = DUK_HOBJECT_CMASK_FUNCTION |
- DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS;
- c_object = c_all & ~(c_array | c_unbox | c_undef);
+#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
+ if (js_ctx->flag_ext_custom_or_compatible) {
+ c_all = DUK_HOBJECT_CMASK_ALL;
+ c_array = DUK_HOBJECT_CMASK_ARRAY;
+ c_unbox = DUK_HOBJECT_CMASK_NUMBER |
+ DUK_HOBJECT_CMASK_STRING |
+ DUK_HOBJECT_CMASK_BOOLEAN |
+ DUK_HOBJECT_CMASK_POINTER;
+ c_func = DUK_HOBJECT_CMASK_FUNCTION;
+ c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS;
+ c_undef = 0;
+ c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef);
+ }
+ else
+#endif
+ {
+ c_all = DUK_HOBJECT_CMASK_ALL;
+ c_array = DUK_HOBJECT_CMASK_ARRAY;
+ c_unbox = DUK_HOBJECT_CMASK_NUMBER |
+ DUK_HOBJECT_CMASK_STRING |
+ DUK_HOBJECT_CMASK_BOOLEAN;
+ c_func = 0;
+ c_bufobj = 0;
+ c_undef = DUK_HOBJECT_CMASK_FUNCTION |
+ DUK_HOBJECT_CMASK_POINTER |
+ DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS;
+ c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef);
+ }
c_bit = DUK_HOBJECT_GET_CLASS_MASK(obj);
if (c_bit & c_object) {
@@ -33626,8 +34457,16 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(js_ctx->thr->heap, obj, i);
prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
- duk__enc_quote_string(js_ctx, k);
- DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
+ 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__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
+ } else {
+ duk__enc_key_autoquote(js_ctx, k);
+ DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
+ }
+
if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) {
DUK_DD(DUK_DDPRINT("prop value not supported, rewind key and colon"));
DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size);
@@ -33643,7 +34482,12 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
*/
if (emitted) {
+ DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
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 - 1);
+ }
}
DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
} else if (c_bit & c_array) {
@@ -33675,6 +34519,10 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i);
+ if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
+ }
+
if (DUK_UNLIKELY(DUK_TVAL_IS_UNUSED(tv_val))) {
/* Gap in array; check for inherited property,
* bail out if one exists. This should be enough
@@ -33710,11 +34558,16 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
}
if (emitted) {
+ DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
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 - 1);
+ }
}
DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
} else if (c_bit & c_unbox) {
- /* These three boxed types are required to go through
+ /* Certain boxed types are required to go through
* automatic unboxing. Rely on internal value being
* sane (to avoid infinite recursion).
*/
@@ -33726,21 +34579,22 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
DUK_ASSERT(tv_internal != NULL);
DUK_ASSERT(DUK_TVAL_IS_STRING(tv_internal) ||
DUK_TVAL_IS_NUMBER(tv_internal) ||
- DUK_TVAL_IS_BOOLEAN(tv_internal));
+ DUK_TVAL_IS_BOOLEAN(tv_internal) ||
+ DUK_TVAL_IS_POINTER(tv_internal));
- /* XXX: for JX/JC, special handling for Pointer, and Buffer? */
tv = tv_internal;
+ DUK_ASSERT(js_ctx->recursion_depth > 0);
+ js_ctx->recursion_depth--; /* required to keep recursion depth correct */
goto restart_match;
+#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
+ } else if (c_bit & c_func) {
+ DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
+ } else if (c_bit & c_bufobj) {
+ duk__enc_bufferobject(js_ctx, (duk_hbufferobject *) obj);
+#endif
} else {
DUK_ASSERT((c_bit & c_undef) != 0);
- /* Function objects are treated as "undefined" by JSON.
- *
- * The slow path replaces a buffer object automatically with
- * the binary data which then gets treated like "undefined".
- * Since we don't support buffers here now, treat as "undefined".
- */
-
/* Must decrease recursion depth before returning. */
DUK_ASSERT(js_ctx->recursion_depth > 0);
DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
@@ -33754,13 +34608,34 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
break;
}
case DUK_TAG_BUFFER: {
+#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
+ if (js_ctx->flag_ext_custom_or_compatible) {
+ duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv));
+ break;
+ } else {
+ goto emit_undefined;
+ }
+#else
goto emit_undefined;
+#endif
}
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));
+ break;
+ } else {
+ goto emit_undefined;
+ }
+#else
goto emit_undefined;
+#endif
}
case DUK_TAG_LIGHTFUNC: {
/* A lightfunc might also inherit a .toJSON() so just bail out. */
+ /* XXX: Could just lookup .toJSON() and continue in fast path,
+ * as it would almost never be defined.
+ */
DUK_DD(DUK_DDPRINT("value is a lightfunc, abort fast path"));
goto abort_fastpath;
}
@@ -33868,12 +34743,15 @@ void duk_bi_json_parse_helper(duk_context *ctx,
*/
js_ctx->flags = flags;
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
#endif
-#ifdef DUK_USE_JC
+#if defined(DUK_USE_JC)
js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
#endif
+#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
+ js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
+#endif
h_text = duk_to_hstring(ctx, idx_value); /* coerce in-place */
DUK_ASSERT(h_text != NULL);
@@ -33882,9 +34760,9 @@ void duk_bi_json_parse_helper(duk_context *ctx,
* valid and points to the string NUL terminator (which is always
* guaranteed for duk_hstrings.
*/
- js_ctx->p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text);
+ js_ctx->p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text);
js_ctx->p = js_ctx->p_start;
- js_ctx->p_end = ((duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text)) +
+ js_ctx->p_end = ((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text)) +
DUK_HSTRING_GET_BYTELEN(h_text);
DUK_ASSERT(*(js_ctx->p_end) == 0x00);
@@ -33969,7 +34847,6 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
#ifdef DUK_USE_EXPLICIT_NULL_INIT
js_ctx->h_replacer = NULL;
js_ctx->h_gap = NULL;
- js_ctx->h_indent = NULL;
#endif
js_ctx->idx_proplist = -1;
@@ -33986,6 +34863,9 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
#ifdef DUK_USE_JC
js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
#endif
+#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
+ js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
+#endif
/* The #ifdef clutter here handles the JX/JC enable/disable
* combinations properly.
@@ -34131,15 +35011,9 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
/* if gap is empty, behave as if not given at all */
if (DUK_HSTRING_GET_CHARLEN(js_ctx->h_gap) == 0) {
js_ctx->h_gap = NULL;
- } else {
- /* set 'indent' only if it will actually increase */
- js_ctx->h_indent = DUK_HTHREAD_STRING_EMPTY_STRING(thr);
}
}
- DUK_ASSERT((js_ctx->h_gap == NULL && js_ctx->h_indent == NULL) ||
- (js_ctx->h_gap != NULL && js_ctx->h_indent != NULL));
-
/* [ ... buf loop (proplist) (gap) ] */
/*
@@ -34148,15 +35022,8 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
*/
#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
- /* For now fast path is limited to plain JSON (no JX/JC). This would
- * be easy to fix but must go through value type handling in the fast
- * path.
- */
- if (flags == 0 &&
- js_ctx->h_replacer == NULL &&
- js_ctx->idx_proplist == -1 &&
- js_ctx->h_gap == NULL &&
- js_ctx->h_indent == NULL) {
+ if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */
+ js_ctx->idx_proplist == -1) { /* proplist is very rare */
duk_int_t pcall_rc;
#ifdef DUK_USE_MARK_AND_SWEEP
duk_small_uint_t prev_mark_and_sweep_base_flags;
@@ -34206,7 +35073,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
* kept because we'll probably need at least as much as we've
* allocated so far.
*/
- DUK_DD(DUK_DDPRINT("fast path failed, serialize using slow path instead"));
+ DUK_D(DUK_DPRINT("fast path failed, serialize using slow path instead"));
DUK_BW_RESET_SIZE(thr, &js_ctx->bw);
js_ctx->recursion_depth = 0;
}
@@ -34221,13 +35088,12 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING);
DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, "
- "proplist=%!T, gap=%!O, indent=%!O, holder=%!T",
+ "proplist=%!T, gap=%!O, holder=%!T",
(unsigned long) js_ctx->flags,
(duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
(duk_heaphdr *) js_ctx->h_replacer,
(duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
(duk_heaphdr *) js_ctx->h_gap,
- (duk_heaphdr *) js_ctx->h_indent,
(duk_tval *) duk_get_tval(ctx, -1)));
/* serialize the wrapper with empty string key */
@@ -34241,28 +35107,20 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
undef = duk__enc_value1(js_ctx, idx_holder); /* [ ... holder key ] -> [ ... holder key val ] */
DUK_DDD(DUK_DDDPRINT("after: flags=0x%08lx, loop=%!T, replacer=%!O, "
- "proplist=%!T, gap=%!O, indent=%!O, holder=%!T",
+ "proplist=%!T, gap=%!O, holder=%!T",
(unsigned long) js_ctx->flags,
(duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
(duk_heaphdr *) js_ctx->h_replacer,
(duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
(duk_heaphdr *) js_ctx->h_gap,
- (duk_heaphdr *) js_ctx->h_indent,
(duk_tval *) duk_get_tval(ctx, -3)));
if (undef) {
- /*
- * Result is undefined
- */
-
+ /* Result is undefined. */
duk_push_undefined(ctx);
} else {
- /*
- * Finish and convert buffer to result string
- */
-
+ /* Finish and convert buffer to result string. */
duk__enc_value2(js_ctx); /* [ ... key val ] -> [ ... ] */
-
DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
}
@@ -34560,18 +35418,18 @@ DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx) {
DUK_ASSERT(buf != NULL);
p = buf;
- DUK_MEMCPY((void *) p, (void *) date_buf, date_len);
+ DUK_MEMCPY((void *) p, (const void *) date_buf, (size_t) date_len);
p += date_len;
*p++ = (duk_uint8_t) DUK_ASC_SPACE;
q = duk__log_level_strings + (entry_lev * 3);
- DUK_MEMCPY((void *) p, (void *) q, (duk_size_t) 3);
+ DUK_MEMCPY((void *) p, (const void *) q, (size_t) 3);
p += 3;
*p++ = (duk_uint8_t) DUK_ASC_SPACE;
arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, -2, &arg_len);
- DUK_MEMCPY((void *) p, (const void *) arg_str, arg_len);
+ DUK_MEMCPY((void *) p, (const void *) arg_str, (size_t) arg_len);
p += arg_len;
*p++ = (duk_uint8_t) DUK_ASC_COLON;
@@ -34581,7 +35439,7 @@ DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx) {
arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &arg_len);
DUK_ASSERT(arg_str != NULL);
- DUK_MEMCPY((void *) p, (const void *) arg_str, arg_len);
+ DUK_MEMCPY((void *) p, (const void *) arg_str, (size_t) arg_len);
p += arg_len;
}
DUK_ASSERT(buf + tot_len == p);
@@ -35692,6 +36550,12 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) {
}
}
+ /* XXX: missing trap result validation for non-configurable target keys
+ * (must be present), for non-extensible target all target keys must be
+ * present and no extra keys can be present.
+ * http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
+ */
+
/* XXX: for Object.keys() the [[OwnPropertyKeys]] result (trap result)
* should be filtered so that only enumerable keys remain. Enumerability
* should be checked with [[GetOwnProperty]] on the original object
@@ -35725,31 +36589,8 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) {
}
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
duk_push_this(ctx);
- duk_push_string(ctx, "[object ");
-
- if (duk_is_undefined(ctx, -2)) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_UNDEFINED);
- } else if (duk_is_null(ctx, -2)) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_NULL);
- } else {
- duk_hobject *h_this;
- duk_hstring *h_classname;
-
- duk_to_object(ctx, -2);
- h_this = duk_get_hobject(ctx, -2);
- DUK_ASSERT(h_this != NULL);
-
- h_classname = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h_this);
- DUK_ASSERT(h_classname != NULL);
-
- duk_push_hstring(ctx, h_classname);
- }
-
- duk_push_string(ctx, "]");
- duk_concat(ctx, 3);
+ duk_to_object_class_string_top(ctx);
return 1;
}
@@ -36534,7 +37375,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx)
if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) {
DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */
- if (DUK_MEMCMP(p, q_start, (duk_size_t) q_blen) == 0) {
+ if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
duk_push_int(ctx, cpos);
return 1;
}
@@ -36744,7 +37585,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
while (p <= p_end) {
DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
- if (DUK_MEMCMP((void *) p, (void *) q_start, (size_t) q_blen) == 0) {
+ if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
duk_dup(ctx, 0);
h_match = duk_get_hstring(ctx, -1);
DUK_ASSERT(h_match != NULL);
@@ -37129,7 +37970,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
while (p <= p_end) {
DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
DUK_ASSERT(q_blen > 0); /* no issues with empty memcmp() */
- if (DUK_MEMCMP((void *) p, (void *) q_start, (duk_size_t) q_blen) == 0) {
+ if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
/* never an empty match, so step 13.c.iii can't be triggered */
goto found;
}
@@ -37440,9 +38281,9 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx)
prefix_len = (h1_len <= h2_len ? h1_len : h2_len);
/* Zero size compare not an issue with DUK_MEMCMP. */
- rc = (duk_small_int_t) DUK_MEMCMP((const char *) DUK_HSTRING_GET_DATA(h1),
- (const char *) DUK_HSTRING_GET_DATA(h2),
- prefix_len);
+ rc = (duk_small_int_t) DUK_MEMCMP((const void *) DUK_HSTRING_GET_DATA(h1),
+ (const void *) DUK_HSTRING_GET_DATA(h2),
+ (size_t) prefix_len);
if (rc < 0) {
ret = -1;
@@ -37639,6 +38480,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
/* lj value1: value */
DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top);
DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[1]); /* side effects */
+ DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1);
thr->heap->lj.iserror = is_error;
@@ -37755,6 +38597,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
/* lj value1: value */
DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[0]); /* side effects */
+ DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1);
thr->heap->lj.iserror = is_error;
@@ -37792,7 +38635,7 @@ DUK_INTERNAL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx) {
#ifdef DUK_USE_DEBUG
-DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, duk_uint8_t *buffer, duk_size_t length) {
+DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length) {
duk_size_t avail;
duk_size_t copylen;
@@ -37808,11 +38651,11 @@ DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, duk_uint8_t *buffer, duk
}
DUK_INTERNAL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x) {
- duk_fb_put_bytes(fb, &x, 1);
+ duk_fb_put_bytes(fb, (const duk_uint8_t *) &x, 1);
}
DUK_INTERNAL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x) {
- duk_fb_put_bytes(fb, (duk_uint8_t *) x, (duk_size_t) DUK_STRLEN(x));
+ duk_fb_put_bytes(fb, (const duk_uint8_t *) x, (duk_size_t) DUK_STRLEN(x));
}
DUK_INTERNAL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...) {
@@ -39169,24 +40012,46 @@ typedef union {
* Detach handling
*/
-#define DUK__SET_CONN_BROKEN(thr) do { \
+#define DUK__SET_CONN_BROKEN(thr,reason) do { \
/* For now shared handler is fine. */ \
- duk_debug_do_detach((thr)->heap); \
+ duk__debug_do_detach1((thr)->heap, (reason)); \
} while (0)
-DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) {
- /* Can be called muliple times with no harm. */
+DUK_LOCAL void duk__debug_do_detach1(duk_heap *heap, duk_int_t reason) {
+ /* Can be called multiple times with no harm. Mark the transport
+ * bad (dbg_read_cb == NULL) and clear state except for the detached
+ * callback and the udata field. The detached callback is delayed
+ * to the message loop so that it can be called between messages;
+ * this avoids corner cases related to immediate debugger reattach
+ * inside the detached callback.
+ */
+
+ if (heap->dbg_detaching) {
+ return;
+ }
+
+ DUK_D(DUK_DPRINT("debugger transport detaching, marking transport broken"));
+
+ heap->dbg_detaching = 1; /* prevent multiple in-progress detaches */
+
+ if (heap->dbg_write_cb != NULL) {
+ duk_hthread *thr;
+
+ thr = heap->heap_thread;
+ DUK_ASSERT(thr != NULL);
+
+ duk_debug_write_notify(thr, DUK_DBG_CMD_DETACHING);
+ duk_debug_write_int(thr, reason);
+ duk_debug_write_eom(thr);
+ }
heap->dbg_read_cb = NULL;
heap->dbg_write_cb = NULL;
heap->dbg_peek_cb = NULL;
heap->dbg_read_flush_cb = NULL;
heap->dbg_write_flush_cb = NULL;
- if (heap->dbg_detached_cb) {
- heap->dbg_detached_cb(heap->dbg_udata);
- }
- heap->dbg_detached_cb = NULL;
- heap->dbg_udata = NULL;
+ /* heap->dbg_detached_cb: keep */
+ /* heap->dbg_udata: keep */
heap->dbg_processing = 0;
heap->dbg_paused = 0;
heap->dbg_state_dirty = 0;
@@ -39195,6 +40060,7 @@ DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) {
heap->dbg_step_thread = NULL;
heap->dbg_step_csindex = 0;
heap->dbg_step_startline = 0;
+ heap->dbg_have_next_byte = 0;
/* Ensure there are no stale active breakpoint pointers.
* Breakpoint list is currently kept - we could empty it
@@ -39206,6 +40072,34 @@ DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) {
heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
}
+DUK_LOCAL void duk__debug_do_detach2(duk_heap *heap) {
+ duk_debug_detached_function detached_cb;
+ void *detached_udata;
+
+ /* Safe to call multiple times. */
+
+ detached_cb = heap->dbg_detached_cb;
+ detached_udata = heap->dbg_udata;
+ heap->dbg_detached_cb = NULL;
+ heap->dbg_udata = NULL;
+
+ if (detached_cb) {
+ /* Careful here: state must be wiped before the call
+ * so that we can cleanly handle a re-attach from
+ * inside the callback.
+ */
+ DUK_D(DUK_DPRINT("detached during message loop, delayed call to detached_cb"));
+ detached_cb(detached_udata);
+ }
+
+ heap->dbg_detaching = 0;
+}
+
+DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) {
+ duk__debug_do_detach1(heap, 0);
+ duk__debug_do_detach2(heap);
+}
+
/*
* Debug connection peek and flush primitives
*/
@@ -39295,6 +40189,21 @@ DUK_INTERNAL void duk_debug_skip_byte(duk_hthread *thr) {
* Debug connection read primitives
*/
+/* Peek ahead in the stream one byte. */
+DUK_INTERNAL uint8_t duk_debug_peek_byte(duk_hthread *thr) {
+ /* It is important not to call this if the last byte read was an EOM.
+ * Reading ahead in this scenario would cause unnecessary blocking if
+ * another message is not available.
+ */
+
+ duk_uint8_t x;
+
+ x = duk_debug_read_byte(thr);
+ thr->heap->dbg_have_next_byte = 1;
+ thr->heap->dbg_next_byte = x;
+ return x;
+}
+
/* Read fully. */
DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length) {
duk_heap *heap;
@@ -39311,7 +40220,12 @@ DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_
goto fail;
}
+ /* NOTE: length may be zero */
p = data;
+ if (length >= 1 && heap->dbg_have_next_byte) {
+ heap->dbg_have_next_byte = 0;
+ *p++ = heap->dbg_next_byte;
+ }
for (;;) {
left = (duk_size_t) ((data + length) - p);
if (left == 0) {
@@ -39324,8 +40238,9 @@ DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_
#endif
got = heap->dbg_read_cb(heap->dbg_udata, (char *) p, left);
if (got == 0 || got > left) {
+ heap->dbg_write_cb = NULL; /* squelch further writes */
DUK_D(DUK_DPRINT("connection error during read, return zero data"));
- DUK__SET_CONN_BROKEN(thr);
+ DUK__SET_CONN_BROKEN(thr, 1);
goto fail;
}
p += got;
@@ -39337,28 +40252,10 @@ DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_
}
DUK_INTERNAL duk_uint8_t duk_debug_read_byte(duk_hthread *thr) {
- duk_heap *heap;
- duk_size_t got;
duk_uint8_t x;
- DUK_ASSERT(thr != NULL);
- heap = thr->heap;
- DUK_ASSERT(heap != NULL);
-
- if (heap->dbg_read_cb == NULL) {
- DUK_D(DUK_DPRINT("attempt to read 1 bytes in detached state, return zero data"));
- return 0;
- }
-
x = 0; /* just in case callback is broken and won't write 'x' */
- DUK_ASSERT(heap->dbg_read_cb != NULL);
- got = heap->dbg_read_cb(heap->dbg_udata, (char *) (&x), 1);
- if (got != 1) {
- DUK_D(DUK_DPRINT("connection error during read, return zero data"));
- DUK__SET_CONN_BROKEN(thr);
- return 0;
- }
-
+ duk_debug_read_bytes(thr, &x, 1);
return x;
}
@@ -39405,7 +40302,7 @@ DUK_INTERNAL duk_int32_t duk_debug_read_int(duk_hthread *thr) {
}
DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
- DUK__SET_CONN_BROKEN(thr);
+ DUK__SET_CONN_BROKEN(thr, 1);
return 0;
}
@@ -39450,7 +40347,7 @@ DUK_INTERNAL duk_hstring *duk_debug_read_hstring(duk_hthread *thr) {
fail:
DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
- DUK__SET_CONN_BROKEN(thr);
+ DUK__SET_CONN_BROKEN(thr, 1);
duk_push_hstring_stridx(thr, DUK_STRIDX_EMPTY_STRING); /* always push some string */
return duk_require_hstring(ctx, -1);
}
@@ -39466,9 +40363,9 @@ DUK_LOCAL duk_hbuffer *duk__debug_read_hbuffer_raw(duk_hthread *thr, duk_uint32_
return duk_require_hbuffer(ctx, -1);
}
-DUK_LOCAL const void *duk__debug_read_pointer_raw(duk_hthread *thr) {
+DUK_LOCAL void *duk__debug_read_pointer_raw(duk_hthread *thr) {
duk_small_uint_t x;
- volatile duk__ptr_union pu;
+ duk__ptr_union pu;
DUK_ASSERT(thr != NULL);
@@ -39480,12 +40377,12 @@ DUK_LOCAL const void *duk__debug_read_pointer_raw(duk_hthread *thr) {
#if defined(DUK_USE_INTEGER_LE)
duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
#endif
- return (const void *) pu.p;
+ return (void *) pu.p;
fail:
DUK_D(DUK_DPRINT("debug connection error: failed to decode pointer"));
- DUK__SET_CONN_BROKEN(thr);
- return (const void *) NULL;
+ DUK__SET_CONN_BROKEN(thr, 1);
+ return (void *) NULL;
}
DUK_LOCAL duk_double_t duk__debug_read_double_raw(duk_hthread *thr) {
@@ -39568,9 +40465,9 @@ DUK_INTERNAL void duk_debug_read_tval(duk_hthread *thr) {
DUK_D(DUK_DPRINT("reading object values unimplemented"));
goto fail;
case 0x1c: {
- const void *ptr;
+ void *ptr;
ptr = duk__debug_read_pointer_raw(thr);
- duk_push_pointer(thr, (void *) ptr);
+ duk_push_pointer(thr, ptr);
break;
}
case 0x1d:
@@ -39592,7 +40489,7 @@ DUK_INTERNAL void duk_debug_read_tval(duk_hthread *thr) {
fail:
DUK_D(DUK_DPRINT("debug connection error: failed to decode tval"));
- DUK__SET_CONN_BROKEN(thr);
+ DUK__SET_CONN_BROKEN(thr, 1);
}
/*
@@ -39636,8 +40533,9 @@ DUK_INTERNAL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *dat
#endif
got = heap->dbg_write_cb(heap->dbg_udata, (const char *) p, left);
if (got == 0 || got > left) {
+ heap->dbg_write_cb = NULL; /* squelch further writes */
DUK_D(DUK_DPRINT("connection error during write"));
- DUK__SET_CONN_BROKEN(thr);
+ DUK__SET_CONN_BROKEN(thr, 1);
return;
}
p += got;
@@ -39661,7 +40559,7 @@ DUK_INTERNAL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x) {
got = heap->dbg_write_cb(heap->dbg_udata, (const char *) (&x), 1);
if (got != 1) {
DUK_D(DUK_DPRINT("connection error during write"));
- DUK__SET_CONN_BROKEN(thr);
+ DUK__SET_CONN_BROKEN(thr, 1);
}
}
@@ -39775,9 +40673,9 @@ DUK_INTERNAL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h) {
(h != NULL ? (duk_size_t) DUK_HBUFFER_GET_SIZE(h) : 0));
}
-DUK_LOCAL void duk__debug_write_pointer_raw(duk_hthread *thr, const void *ptr, duk_uint8_t ibyte) {
+DUK_LOCAL void duk__debug_write_pointer_raw(duk_hthread *thr, void *ptr, duk_uint8_t ibyte) {
duk_uint8_t buf[2];
- volatile duk__ptr_union pu;
+ duk__ptr_union pu;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(sizeof(ptr) >= 1 && sizeof(ptr) <= 16);
@@ -39793,19 +40691,19 @@ DUK_LOCAL void duk__debug_write_pointer_raw(duk_hthread *thr, const void *ptr, d
duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
}
-DUK_INTERNAL void duk_debug_write_pointer(duk_hthread *thr, const void *ptr) {
+DUK_INTERNAL void duk_debug_write_pointer(duk_hthread *thr, void *ptr) {
duk__debug_write_pointer_raw(thr, ptr, 0x1c);
}
#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
DUK_INTERNAL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h) {
- duk__debug_write_pointer_raw(thr, (const void *) h, 0x1e);
+ duk__debug_write_pointer_raw(thr, (void *) h, 0x1e);
}
#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
DUK_INTERNAL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj) {
duk_uint8_t buf[3];
- volatile duk__ptr_union pu;
+ duk__ptr_union pu;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(sizeof(obj) >= 1 && sizeof(obj) <= 16);
@@ -39847,7 +40745,7 @@ DUK_INTERNAL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv) {
duk_debug_write_byte(thr, DUK_TVAL_GET_BOOLEAN(tv) ? 0x18 : 0x19);
break;
case DUK_TAG_POINTER:
- duk_debug_write_pointer(thr, (const void *) DUK_TVAL_GET_POINTER(tv));
+ duk_debug_write_pointer(thr, (void *) DUK_TVAL_GET_POINTER(tv));
break;
case DUK_TAG_LIGHTFUNC:
DUK_TVAL_GET_LIGHTFUNC(tv, lf_func, lf_flags);
@@ -40113,7 +41011,7 @@ DUK_LOCAL duk_bool_t duk__debug_skip_dvalue(duk_hthread *thr) {
return 0;
fail:
- DUK__SET_CONN_BROKEN(thr);
+ DUK__SET_CONN_BROKEN(thr, 1);
return 1; /* Pretend like we got EOM */
}
@@ -40128,6 +41026,10 @@ DUK_LOCAL void duk__debug_skip_to_eom(duk_hthread *thr) {
/*
* Process incoming debug requests
+ *
+ * Individual request handlers can push temporaries on the value stack and
+ * rely on duk__debug_process_message() to restore the value stack top
+ * automatically.
*/
DUK_LOCAL void duk__debug_handle_basic_info(duk_hthread *thr, duk_heap *heap) {
@@ -40217,7 +41119,6 @@ DUK_LOCAL void duk__debug_handle_list_break(duk_hthread *thr, duk_heap *heap) {
}
DUK_LOCAL void duk__debug_handle_add_break(duk_hthread *thr, duk_heap *heap) {
- duk_context *ctx = (duk_context *) thr;
duk_hstring *filename;
duk_uint32_t linenumber;
duk_small_int_t idx;
@@ -40235,7 +41136,6 @@ DUK_LOCAL void duk__debug_handle_add_break(duk_hthread *thr, duk_heap *heap) {
} else {
duk_debug_write_error_eom(thr, DUK_DBG_ERR_TOOMANY, "no space for breakpoint");
}
- duk_pop(ctx);
}
DUK_LOCAL void duk__debug_handle_del_break(duk_hthread *thr, duk_heap *heap) {
@@ -40257,16 +41157,27 @@ DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) {
duk_context *ctx = (duk_context *) thr;
duk_hstring *str;
duk_bool_t rc;
+ duk_int32_t level;
DUK_UNREF(heap);
DUK_D(DUK_DPRINT("debug command GetVar"));
str = duk_debug_read_hstring(thr); /* push to stack */
DUK_ASSERT(str != NULL);
+ if (duk_debug_peek_byte(thr) != DUK_DBG_MARKER_EOM) {
+ level = duk_debug_read_int(thr); /* optional callstack level */
+ if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
+ DUK_D(DUK_DPRINT("invalid callstack level for GetVar"));
+ duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
+ return;
+ }
+ } else {
+ level = -1;
+ }
if (thr->callstack_top > 0) {
rc = duk_js_getvar_activation(thr,
- thr->callstack + thr->callstack_top - 1,
+ thr->callstack + thr->callstack_top + level,
str,
0);
} else {
@@ -40283,12 +41194,10 @@ DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) {
duk_debug_write_int(thr, 1);
DUK_ASSERT(duk_get_tval(ctx, -2) != NULL);
duk_debug_write_tval(thr, duk_get_tval(ctx, -2));
- duk_pop_2(ctx);
} else {
duk_debug_write_int(thr, 0);
duk_debug_write_unused(thr);
}
- duk_pop(ctx);
duk_debug_write_eom(thr);
}
@@ -40296,6 +41205,7 @@ DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
duk_context *ctx = (duk_context *) thr;
duk_hstring *str;
duk_tval *tv;
+ duk_int32_t level;
DUK_UNREF(heap);
DUK_D(DUK_DPRINT("debug command PutVar"));
@@ -40305,17 +41215,26 @@ DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
duk_debug_read_tval(thr); /* push to stack */
tv = duk_get_tval(ctx, -1);
DUK_ASSERT(tv != NULL);
+ if (duk_debug_peek_byte(thr) != DUK_DBG_MARKER_EOM) {
+ level = duk_debug_read_int(thr); /* optional callstack level */
+ if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
+ DUK_D(DUK_DPRINT("invalid callstack level for PutVar"));
+ duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
+ return;
+ }
+ } else {
+ level = -1;
+ }
if (thr->callstack_top > 0) {
duk_js_putvar_activation(thr,
- thr->callstack + thr->callstack_top - 1,
+ thr->callstack + thr->callstack_top + level,
str,
tv,
0);
} else {
DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore putvar"));
}
- duk_pop_2(ctx);
/* XXX: Current putvar implementation doesn't have a success flag,
* add one and send to debug client?
@@ -40376,15 +41295,28 @@ DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap
DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) {
duk_context *ctx = (duk_context *) thr;
duk_activation *curr_act;
+ duk_int32_t level;
duk_hstring *varname;
DUK_UNREF(heap);
- duk_debug_write_reply(thr);
- if (thr->callstack_top == 0) {
- goto callstack_empty;
+ if (duk_debug_peek_byte(thr) != DUK_DBG_MARKER_EOM) {
+ level = duk_debug_read_int(thr); /* optional callstack level */
+ if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
+ DUK_D(DUK_DPRINT("invalid callstack level for GetLocals"));
+ duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
+ return;
+ }
+ duk_debug_write_reply(thr);
+ } else {
+ duk_debug_write_reply(thr);
+ if (thr->callstack_top == 0) {
+ goto callstack_empty;
+ }
+ level = -1;
}
- curr_act = thr->callstack + thr->callstack_top - 1;
+
+ curr_act = thr->callstack + thr->callstack_top + level;
/* XXX: several nice-to-have improvements here:
* - Use direct reads avoiding value stack operations
@@ -40406,11 +41338,9 @@ DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) {
duk_debug_write_tval(thr, duk_get_tval(ctx, -2));
duk_pop_3(ctx); /* -> [ ... func varmap enum ] */
}
- duk_pop(ctx);
} else {
DUK_D(DUK_DPRINT("varmap is not an object in GetLocals, ignore"));
}
- duk_pop_2(ctx);
callstack_empty:
duk_debug_write_eom(thr);
@@ -40418,51 +41348,62 @@ DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) {
DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
duk_context *ctx = (duk_context *) thr;
-
duk_small_uint_t call_flags;
duk_int_t call_ret;
duk_small_int_t eval_err;
-#if defined(DUK_USE_ASSERTIONS)
- duk_idx_t entry_top;
-#endif
+ duk_int32_t level;
DUK_UNREF(heap);
DUK_D(DUK_DPRINT("debug command Eval"));
- /* The eval code must be executed within the current (topmost)
- * activation. For now, use global object eval() function, with
- * the eval considered a 'direct call to eval'.
+ /* The eval code is executed within the lexical environment of a specified
+ * activation. For now, use global object eval() function, with the eval
+ * considered a 'direct call to eval'.
+ *
+ * Callstack level for debug commands only affects scope -- the callstack
+ * as seen by, e.g. Duktape.act() will be the same regardless.
*/
-#if defined(DUK_USE_ASSERTIONS)
- entry_top = duk_get_top(ctx);
-#endif
-
- duk_push_c_function(ctx, duk_bi_global_object_eval, 1 /*nargs*/);
+ /* nargs == 2 so we can pass a callstack level to eval(). */
+ duk_push_c_function(ctx, duk_bi_global_object_eval, 2 /*nargs*/);
duk_push_undefined(ctx); /* 'this' binding shouldn't matter here */
+
(void) duk_debug_read_hstring(thr);
+ if (duk_debug_peek_byte(thr) != DUK_DBG_MARKER_EOM) {
+ level = duk_debug_read_int(thr); /* optional callstack level */
+ if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
+ DUK_D(DUK_DPRINT("invalid callstack level for Eval"));
+ duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
+ return;
+ }
+ }
+ else {
+ level = -1;
+ }
+ DUK_ASSERT(level < 0 && -level <= (duk_int32_t) thr->callstack_top);
+ duk_push_int(ctx, level - 1); /* compensate for eval() call */
- /* [ ... eval "eval" eval_input ] */
+ /* [ ... eval "eval" eval_input level ] */
call_flags = DUK_CALL_FLAG_PROTECTED;
- if (thr->callstack_top >= 1) {
+ if (thr->callstack_top >= (duk_size_t) -level) {
duk_activation *act;
duk_hobject *fun;
- act = thr->callstack + thr->callstack_top - 1;
+ act = thr->callstack + thr->callstack_top + level;
fun = DUK_ACT_GET_FUNC(act);
if (fun != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(fun)) {
/* Direct eval requires that there's a current
* activation and it is an Ecmascript function.
* When Eval is executed from e.g. cooperate API
- * call we'll need to an indirect eval instead.
+ * call we'll need to do an indirect eval instead.
*/
call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
}
}
- call_ret = duk_handle_call(thr, 1 /*num_stack_args*/, call_flags);
+ call_ret = duk_handle_call(thr, 2 /*num_stack_args*/, call_flags);
if (call_ret == DUK_EXEC_SUCCESS) {
eval_err = 0;
@@ -40483,9 +41424,6 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
DUK_ASSERT(duk_get_tval(ctx, -1) != NULL);
duk_debug_write_tval(thr, duk_get_tval(ctx, -1));
duk_debug_write_eom(thr);
- duk_pop(ctx);
-
- DUK_ASSERT(duk_get_top(ctx) == entry_top);
}
DUK_LOCAL void duk__debug_handle_detach(duk_hthread *thr, duk_heap *heap) {
@@ -40496,7 +41434,7 @@ DUK_LOCAL void duk__debug_handle_detach(duk_hthread *thr, duk_heap *heap) {
duk_debug_write_eom(thr);
DUK_D(DUK_DPRINT("debug connection detached, mark broken"));
- DUK__SET_CONN_BROKEN(thr);
+ DUK__SET_CONN_BROKEN(thr, 0); /* not an error */
}
#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
@@ -40716,17 +41654,24 @@ DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap)
duk_debug_write_eom(thr);
}
+/* Process one debug message. Automatically restore value stack top to its
+ * entry value, so that individual message handlers don't need exact value
+ * stack handling which is convenient.
+ */
DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
duk_context *ctx = (duk_context *) thr;
duk_heap *heap;
duk_uint8_t x;
duk_int32_t cmd;
+ duk_idx_t entry_top;
DUK_ASSERT(thr != NULL);
heap = thr->heap;
DUK_ASSERT(heap != NULL);
DUK_UNREF(ctx);
+ entry_top = duk_get_top(ctx);
+
x = duk_debug_read_byte(thr);
switch (x) {
case DUK_DBG_MARKER_REQUEST: {
@@ -40787,6 +41732,10 @@ DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
break;
}
case DUK_DBG_CMD_DETACH: {
+ /* The actual detached_cb call is postponed to message loop so
+ * we don't need any special precautions here (just skip to EOM
+ * on the already closed connection).
+ */
duk__debug_handle_detach(thr, heap);
break;
}
@@ -40825,11 +41774,15 @@ DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
}
} /* switch initial byte */
+ DUK_ASSERT(duk_get_top(ctx) >= entry_top);
+ duk_set_top(ctx, entry_top);
duk__debug_skip_to_eom(thr);
return;
fail:
- DUK__SET_CONN_BROKEN(thr);
+ DUK_ASSERT(duk_get_top(ctx) >= entry_top);
+ duk_set_top(ctx, entry_top);
+ DUK__SET_CONN_BROKEN(thr, 1);
return;
}
@@ -40939,6 +41892,17 @@ DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t
}
duk__debug_process_message(thr);
+
+ if (thr->heap->dbg_read_cb == NULL) {
+ /* Became detached during message handling (perhaps because
+ * of an error or by an explicit Detach). Call detached
+ * callback here, between messages, to avoid confusing the
+ * broken connection and a possible replacement (which may
+ * be provided by an instant reattach inside the detached
+ * callback).
+ */
+ duk__debug_do_detach2(thr->heap);
+ }
if (thr->heap->dbg_state_dirty) {
/* Executed something that may have affected status,
* resend.
@@ -41025,8 +41989,8 @@ DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_
move_size = sizeof(duk_breakpoint) * (heap->dbg_breakpoint_count - breakpoint_index - 1);
if (move_size > 0) {
DUK_MEMMOVE((void *) b,
- (void *) (b + 1),
- move_size);
+ (const void *) (b + 1),
+ (size_t) move_size);
}
heap->dbg_breakpoint_count--;
heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
@@ -41201,10 +42165,10 @@ DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_c
#endif /* DUK_USE_ERRTHROW || DUK_USE_ERRCREATE */
/*
- * Add tracedata to an error on the stack top.
+ * Add ._Tracedata to an error on the stack top.
*/
-#ifdef DUK_USE_TRACEBACKS
+#if defined(DUK_USE_TRACEBACKS)
DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) {
duk_context *ctx = (duk_context *) thr;
duk_small_uint_t depth;
@@ -41232,8 +42196,8 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack,
duk_push_array(ctx); /* XXX: specify array size, as we know it */
arr_idx = 0;
- /* compiler SyntaxErrors (and other errors) come first; blame the source
- * code file/line primarily.
+ /* Compiler SyntaxErrors (and other errors) come first, and are
+ * blamed by default (not flagged "noblame").
*/
if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
duk_push_hstring(ctx, thr->compile_ctx->h_filename);
@@ -41245,7 +42209,7 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack,
arr_idx++;
}
- /* filename/line from C macros (__FILE__, __LINE__) are added as an
+ /* Filename/line from C macros (__FILE__, __LINE__) are added as an
* entry with a special format: (string, number). The number contains
* the line and flags.
*/
@@ -41258,7 +42222,9 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack,
/* XXX: using duk_put_prop_index() would cause obscure error cases when Array.prototype
* has write-protected array index named properties. This was seen as DoubleErrors
* in e.g. some test262 test cases. Using duk_xdef_prop_index() is better but heavier.
- * The best fix is to fill in the tracedata directly into the array part.
+ * The best fix is to fill in the tracedata directly into the array part. There are
+ * no side effect concerns if the array part is allocated directly and only INCREFs
+ * happen after that.
*/
/* [ ... error arr ] */
@@ -41329,34 +42295,22 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack,
}
#endif /* DUK_USE_TRACEBACKS */
-#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
-DUK_LOCAL void duk__err_augment_builtin_throw(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_int_t noblame_fileline, duk_hobject *obj) {
- duk_context *ctx = (duk_context *) thr;
-#ifdef DUK_USE_ASSERTIONS
+/*
+ * Add .fileName and .lineNumber to an error on the stack top.
+ */
+
+#if !defined(DUK_USE_TRACEBACKS)
+DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) {
+ duk_context *ctx;
+#if defined(DUK_USE_ASSERTIONS)
duk_int_t entry_top;
#endif
-#ifdef DUK_USE_ASSERTIONS
+ ctx = (duk_context *) thr;
+#if defined(DUK_USE_ASSERTIONS)
entry_top = duk_get_top(ctx);
#endif
- DUK_ASSERT(obj != NULL);
- DUK_UNREF(obj); /* unreferenced w/o tracebacks */
- DUK_UNREF(ctx); /* unreferenced w/ tracebacks */
-
-#ifdef DUK_USE_TRACEBACKS
- /*
- * If tracebacks are enabled, the '_Tracedata' property is the only
- * thing we need: 'fileName' and 'lineNumber' are virtual properties
- * which use '_Tracedata'.
- */
-
- if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_TRACEDATA(thr))) {
- DUK_DDD(DUK_DDDPRINT("error value already has a '_Tracedata' property, not modifying it"));
- } else {
- duk__add_traceback(thr, thr_callstack, c_filename, c_line, noblame_fileline);
- }
-#else
/*
* If tracebacks are disabled, 'fileName' and 'lineNumber' are added
* as plain own properties. Since Error.prototype has accessors of
@@ -41366,33 +42320,49 @@ DUK_LOCAL void duk__err_augment_builtin_throw(duk_hthread *thr, duk_hthread *thr
*/
if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
- /* Compiler SyntaxError (or other error) gets the primary blame. */
- duk_push_hstring(ctx, thr->compile_ctx->h_filename);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
+ /* Compiler SyntaxError (or other error) gets the primary blame.
+ * Currently no flag to prevent blaming.
+ */
duk_push_uint(ctx, (duk_uint_t) thr->compile_ctx->curr_token.start_line);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
+ duk_push_hstring(ctx, thr->compile_ctx->h_filename);
} else if (c_filename && !noblame_fileline) {
- /* XXX: file/line is disabled in minimal builds, so disable this too
- * when appropriate.
+ /* C call site gets blamed next, unless flagged not to do so.
+ * XXX: file/line is disabled in minimal builds, so disable this
+ * too when appropriate.
*/
- duk_push_string(ctx, c_filename);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
duk_push_int(ctx, c_line);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
- } else if (thr_callstack->callstack_top > 0) {
- duk_activation *act;
- duk_hobject *func;
+ duk_push_string(ctx, c_filename);
+ } else {
+ /* Finally, blame the innermost callstack entry which has a
+ * .fileName property.
+ */
+ duk_small_uint_t depth;
+ duk_int_t i, i_min;
+ duk_uint32_t ecma_line;
- act = thr_callstack->callstack + thr_callstack->callstack_top - 1;
- DUK_ASSERT(act >= thr_callstack->callstack && act < thr_callstack->callstack + thr_callstack->callstack_size);
- func = DUK_ACT_GET_FUNC(act);
- if (func) {
+ depth = DUK_USE_TRACEBACK_DEPTH;
+ i_min = (thr_callstack->callstack_top > (duk_size_t) depth ? (duk_int_t) (thr_callstack->callstack_top - depth) : 0);
+ DUK_ASSERT(i_min >= 0);
+
+ DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
+ for (i = (duk_int_t) (thr_callstack->callstack_top - 1); i >= i_min; i--) {
+ duk_activation *act;
+ duk_hobject *func;
duk_uint32_t pc;
- /* PC points to next instruction, find offending PC. Note that
+ act = thr_callstack->callstack + i;
+ DUK_ASSERT(act >= thr_callstack->callstack && act < thr_callstack->callstack + thr_callstack->callstack_size);
+
+ func = DUK_ACT_GET_FUNC(act);
+ if (func == NULL) {
+ /* Lightfunc, not blamed now. */
+ continue;
+ }
+
+ /* PC points to next instruction, find offending PC,
* PC == 0 for native code.
*/
- pc = duk_hthread_get_act_prev_pc(thr, act);
+ pc = duk_hthread_get_act_prev_pc(thr, act); /* thr argument only used for thr->heap, so specific thread doesn't matter */
DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
act = NULL; /* invalidated by pushes, so get out of the way */
@@ -41402,31 +42372,126 @@ DUK_LOCAL void duk__err_augment_builtin_throw(duk_hthread *thr, duk_hthread *thr
/* [ ... error func ] */
duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
+ if (!duk_is_string(ctx, -1)) {
+ duk_pop_2(ctx);
+ continue;
+ }
+
+ /* [ ... error func fileName ] */
+ ecma_line = 0;
#if defined(DUK_USE_PC2LINE)
if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- duk_uint32_t ecma_line;
-#if 0
- duk_push_u32(ctx, pc);
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_PC, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAGS_NO_OVERWRITE);
-#endif
- ecma_line = duk_hobject_pc2line_query(ctx, -1, (duk_uint_fast32_t) pc);
- if (ecma_line > 0) {
- duk_push_u32(ctx, (duk_uint32_t) ecma_line); /* -> [ ... error func line ] */
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
- }
+ ecma_line = duk_hobject_pc2line_query(ctx, -2, (duk_uint_fast32_t) pc);
} else {
/* Native function, no relevant lineNumber. */
}
#endif /* DUK_USE_PC2LINE */
+ duk_push_u32(ctx, ecma_line);
- duk_pop(ctx);
+ /* [ ... error func fileName lineNumber ] */
+
+ duk_replace(ctx, -3);
+
+ /* [ ... error lineNumber fileName ] */
+ goto define_props;
}
+
+ /* No activation matches, use undefined for both .fileName and
+ * .lineNumber (matches what we do with a _Tracedata based
+ * no-match lookup.
+ */
+ duk_push_undefined(ctx);
+ duk_push_undefined(ctx);
}
-#endif /* DUK_USE_TRACEBACKS */
-#ifdef DUK_USE_ASSERTIONS
+ define_props:
+ /* [ ... error lineNumber fileName ] */
+#if defined(DUK_USE_ASSERTIONS)
+ DUK_ASSERT(duk_get_top(ctx) == entry_top + 2);
+#endif
+ duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
+ duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
+}
+#endif /* !DUK_USE_TRACEBACKS */
+
+/*
+ * Add line number to a compiler error.
+ */
+
+DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) {
+ duk_context *ctx;
+
+ /* Append a "(line NNN)" to the "message" property of any error
+ * thrown during compilation. Usually compilation errors are
+ * SyntaxErrors but they can also be out-of-memory errors and
+ * the like.
+ */
+
+ /* [ ... error ] */
+
+ ctx = (duk_context *) thr;
+ DUK_ASSERT(duk_is_object(ctx, -1));
+
+ if (!(thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL)) {
+ return;
+ }
+
+ DUK_DDD(DUK_DDDPRINT("compile error, before adding line info: %!T",
+ (duk_tval *) duk_get_tval(ctx, -1)));
+
+ if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_MESSAGE)) {
+ duk_push_sprintf(ctx, " (line %ld)", (long) thr->compile_ctx->curr_token.start_line);
+ duk_concat(ctx, 2);
+ duk_put_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE);
+ } else {
+ duk_pop(ctx);
+ }
+
+ DUK_DDD(DUK_DDDPRINT("compile error, after adding line info: %!T",
+ (duk_tval *) duk_get_tval(ctx, -1)));
+}
+
+/*
+ * Augment an error being created using Duktape specific properties
+ * like _Tracedata or .fileName/.lineNumber.
+ */
+
+#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
+DUK_LOCAL void duk__err_augment_builtin_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_int_t noblame_fileline, duk_hobject *obj) {
+ duk_context *ctx = (duk_context *) thr;
+#if defined(DUK_USE_ASSERTIONS)
+ duk_int_t entry_top;
+#endif
+
+#if defined(DUK_USE_ASSERTIONS)
+ entry_top = duk_get_top(ctx);
+#endif
+ DUK_ASSERT(obj != NULL);
+
+ DUK_UNREF(obj); /* unreferenced w/o tracebacks */
+ DUK_UNREF(ctx); /* unreferenced w/o asserts */
+
+ duk__add_compiler_error_line(thr);
+
+#if defined(DUK_USE_TRACEBACKS)
+ /* If tracebacks are enabled, the '_Tracedata' property is the only
+ * thing we need: 'fileName' and 'lineNumber' are virtual properties
+ * which use '_Tracedata'.
+ */
+ if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_TRACEDATA(thr))) {
+ DUK_DDD(DUK_DDDPRINT("error value already has a '_Tracedata' property, not modifying it"));
+ } else {
+ duk__add_traceback(thr, thr_callstack, c_filename, c_line, noblame_fileline);
+ }
+#else
+ /* Without tracebacks the concrete .fileName and .lineNumber need
+ * to be added directly.
+ */
+ duk__add_fileline(thr, thr_callstack, c_filename, c_line, noblame_fileline);
+#endif
+
+#if defined(DUK_USE_ASSERTIONS)
DUK_ASSERT(duk_get_top(ctx) == entry_top);
#endif
}
@@ -41487,7 +42552,7 @@ DUK_INTERNAL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *th
}
if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
DUK_DDD(DUK_DDDPRINT("error meets criteria, built-in augment"));
- duk__err_augment_builtin_throw(thr, thr_callstack, c_filename, c_line, noblame_fileline, obj);
+ duk__err_augment_builtin_create(thr, thr_callstack, c_filename, c_line, noblame_fileline, obj);
} else {
DUK_DDD(DUK_DDDPRINT("error does not meet criteria, no built-in augment"));
}
@@ -41554,7 +42619,8 @@ DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
* catcher. Protected calls or finally blocks aren't considered catching.
*/
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
+#if defined(DUK_USE_DEBUGGER_SUPPORT) && \
+ (defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT))
DUK_LOCAL duk_bool_t duk__have_active_catcher(duk_hthread *thr) {
/*
* XXX: As noted above, a protected API call won't be counted as a
@@ -41578,7 +42644,7 @@ DUK_LOCAL duk_bool_t duk__have_active_catcher(duk_hthread *thr) {
}
return 0;
}
-#endif /* DUK_USE_DEBUGGER_SUPPORT */
+#endif /* DUK_USE_DEBUGGER_SUPPORT && (DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) */
/*
* Get prototype object for an integer error code.
@@ -42231,7 +43297,7 @@ DUK_LOCAL void duk__free_allocated(duk_heap *heap) {
}
}
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_LOCAL void duk__free_refzero_list(duk_heap *heap) {
duk_heaphdr *curr;
duk_heaphdr *next;
@@ -42247,7 +43313,7 @@ DUK_LOCAL void duk__free_refzero_list(duk_heap *heap) {
}
#endif
-#ifdef DUK_USE_MARK_AND_SWEEP
+#if defined(DUK_USE_MARK_AND_SWEEP)
DUK_LOCAL void duk__free_markandsweep_finalize_list(duk_heap *heap) {
duk_heaphdr *curr;
duk_heaphdr *next;
@@ -42271,16 +43337,17 @@ DUK_LOCAL void duk__free_stringtable(duk_heap *heap) {
DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) {
duk_hthread *thr;
duk_heaphdr *curr;
-#ifdef DUK_USE_DEBUG
- duk_size_t count_obj = 0;
-#endif
+ duk_uint_t round_no;
+ duk_size_t count_all;
+ duk_size_t count_finalized;
+ duk_size_t curr_limit;
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->heap_thread != NULL);
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */
#endif
-#ifdef DUK_USE_MARK_AND_SWEEP
+#if defined(DUK_USE_MARK_AND_SWEEP)
DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep not running -> must be empty */
#endif
@@ -42290,30 +43357,74 @@ DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) {
thr = heap->heap_thread;
DUK_ASSERT(thr != NULL);
- curr = heap->heap_allocated;
- while (curr) {
- if (DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT) {
- /* Only objects in heap_allocated may have finalizers. Check that
- * the object itself has a _Finalizer property so that we don't
- * execute finalizers for e.g. Proxy objects.
- */
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(curr != NULL);
+ /* Prevent mark-and-sweep for the pending finalizers, also prevents
+ * refzero handling from moving objects away from the heap_allocated
+ * list.
+ */
+ DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
+ DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap);
- if (duk_hobject_hasprop_raw(thr, (duk_hobject *) curr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
- duk_hobject_run_finalizer(thr, (duk_hobject *) curr);
+ curr_limit = 0; /* suppress warning, not used */
+ for (round_no = 0; ; round_no++) {
+ curr = heap->heap_allocated;
+ count_all = 0;
+ count_finalized = 0;
+ while (curr) {
+ count_all++;
+ if (DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT) {
+ /* Only objects in heap_allocated may have finalizers. Check that
+ * the object itself has a _Finalizer property (own or inherited)
+ * so that we don't execute finalizers for e.g. Proxy objects.
+ */
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(curr != NULL);
+
+ if (duk_hobject_hasprop_raw(thr, (duk_hobject *) curr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
+ if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) {
+ DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)); /* maps to finalizer 2nd argument */
+ duk_hobject_run_finalizer(thr, (duk_hobject *) curr);
+ count_finalized++;
+ }
+ }
}
-#ifdef DUK_USE_DEBUG
- count_obj++;
-#endif
+ curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
+ }
+
+ /* Each round of finalizer execution may spawn new finalizable objects
+ * which is normal behavior for some applications. Allow multiple
+ * rounds of finalization, but use a shrinking limit based on the
+ * first round to detect the case where a runaway finalizer creates
+ * an unbounded amount of new finalizable objects. Finalizer rescue
+ * is not supported: the semantics are unclear because most of the
+ * objects being finalized here are already reachable. The finalizer
+ * is given a boolean to indicate that rescue is not possible.
+ *
+ * See discussion in: https://github.com/svaarala/duktape/pull/473
+ */
+
+ if (round_no == 0) {
+ /* Cannot wrap: each object is at least 8 bytes so count is
+ * at most 1/8 of that.
+ */
+ curr_limit = count_all * 2;
+ } else {
+ curr_limit = (curr_limit * 3) / 4; /* Decrease by 25% every round */
+ }
+ DUK_D(DUK_DPRINT("finalizer round %ld complete, %ld objects, tried to execute %ld finalizers, current limit is %ld",
+ (long) round_no, (long) count_all, (long) count_finalized, (long) curr_limit));
+
+ if (count_finalized == 0) {
+ DUK_D(DUK_DPRINT("no more finalizable objects, forced finalization finished"));
+ break;
+ }
+ if (count_finalized >= curr_limit) {
+ DUK_D(DUK_DPRINT("finalizer count above limit, potentially runaway finalizer; skip remaining finalizers"));
+ break;
}
- curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
}
- /* Note: count includes all objects, not only those with an actual finalizer. */
-#ifdef DUK_USE_DEBUG
- DUK_D(DUK_DPRINT("checked %ld objects for finalizers before freeing heap", (long) count_obj));
-#endif
+ DUK_ASSERT(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
+ DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap);
}
DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
@@ -42327,6 +43438,9 @@ DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
/* Detach a debugger if attached (can be called multiple times)
* safely.
*/
+ /* XXX: Add a flag to reject an attempt to re-attach? Otherwise
+ * the detached callback may immediately reattach.
+ */
duk_debug_do_detach(heap);
#endif
@@ -42334,18 +43448,30 @@ DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
* objects, and regardless of whether or not mark-and-sweep is
* enabled. This gives finalizers the chance to free any native
* resources like file handles, allocations made outside Duktape,
- * etc.
+ * etc. This is quite tricky to get right, so that all finalizer
+ * guarantees are honored.
*
* XXX: this perhaps requires an execution time limit.
*/
DUK_D(DUK_DPRINT("execute finalizers before freeing heap"));
-#ifdef DUK_USE_MARK_AND_SWEEP
- /* run mark-and-sweep a few times just in case (unreachable
- * object finalizers run already here)
- */
+#if defined(DUK_USE_MARK_AND_SWEEP)
+ /* Run mark-and-sweep a few times just in case (unreachable object
+ * finalizers run already here). The last round must rescue objects
+ * from the previous round without running any more finalizers. This
+ * ensures rescued objects get their FINALIZED flag cleared so that
+ * their finalizer is called once more in forced finalization to
+ * satisfy finalizer guarantees. However, we don't want to run any
+ * more finalizer because that'd required one more loop, and so on.
+ */
+ DUK_D(DUK_DPRINT("forced gc #1 in heap destruction"));
duk_heap_mark_and_sweep(heap, 0);
+ DUK_D(DUK_DPRINT("forced gc #2 in heap destruction"));
duk_heap_mark_and_sweep(heap, 0);
+ DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)"));
+ duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_SKIP_FINALIZERS); /* skip finalizers; queue finalizable objects to heap_allocated */
#endif
+
+ DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* rescue no longer supported */
duk__free_run_finalizers(heap);
/* Note: heap->heap_thread, heap->curr_thread, and heap->heap_object
@@ -42355,12 +43481,12 @@ DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
DUK_D(DUK_DPRINT("freeing heap objects of heap: %p", (void *) heap));
duk__free_allocated(heap);
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_D(DUK_DPRINT("freeing refzero list of heap: %p", (void *) heap));
duk__free_refzero_list(heap);
#endif
-#ifdef DUK_USE_MARK_AND_SWEEP
+#if defined(DUK_USE_MARK_AND_SWEEP)
DUK_D(DUK_DPRINT("freeing mark-and-sweep finalize list of heap: %p", (void *) heap));
duk__free_markandsweep_finalize_list(heap);
#endif
@@ -42507,7 +43633,7 @@ DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) {
return 1;
}
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
#define DUK__DUMPSZ(t) do { \
DUK_D(DUK_DPRINT("" #t "=%ld", (long) sizeof(t))); \
} while (0)
@@ -42521,18 +43647,18 @@ DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) {
DUK_D(DUK_DPRINT(t "=[%ld,%ld]=[%lf,%lf]", \
(long) (a), (long) (b), \
(double) (a), (double) (b))); \
- } while(0)
+ } while (0)
#define DUK__DUMPLM_UNSIGNED_RAW(t,a,b) do { \
DUK_D(DUK_DPRINT(t "=[%lu,%lu]=[%lf,%lf]", \
(unsigned long) (a), (unsigned long) (b), \
(double) (a), (double) (b))); \
- } while(0)
+ } while (0)
#define DUK__DUMPLM_SIGNED(t) do { \
DUK__DUMPLM_SIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
- } while(0)
+ } while (0)
#define DUK__DUMPLM_UNSIGNED(t) do { \
DUK__DUMPLM_UNSIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
- } while(0)
+ } while (0)
DUK_LOCAL void duk__dump_type_sizes(void) {
DUK_D(DUK_DPRINT("sizeof()"));
@@ -42694,19 +43820,27 @@ DUK_LOCAL void duk__dump_type_limits(void) {
DUK_LOCAL void duk__dump_misc_options(void) {
DUK_D(DUK_DPRINT("DUK_VERSION: %ld", (long) DUK_VERSION));
DUK_D(DUK_DPRINT("DUK_GIT_DESCRIBE: %s", DUK_GIT_DESCRIBE));
+ DUK_D(DUK_DPRINT("OS string: %s", DUK_USE_OS_STRING));
+ DUK_D(DUK_DPRINT("architecture string: %s", DUK_USE_ARCH_STRING));
+ DUK_D(DUK_DPRINT("compiler string: %s", DUK_USE_COMPILER_STRING));
#if defined(DUK_USE_PACKED_TVAL)
DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: yes"));
#else
DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: no"));
#endif
+#if defined(DUK_USE_VARIADIC_MACROS)
+ DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: yes"));
+#else
+ DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: no"));
+#endif
#if defined(DUK_USE_INTEGER_LE)
- DUK_D(DUK_DPRINT("Integer endianness: little"));
+ DUK_D(DUK_DPRINT("integer endianness: little"));
#elif defined(DUK_USE_INTEGER_ME)
- DUK_D(DUK_DPRINT("Integer endianness: mixed"));
+ DUK_D(DUK_DPRINT("integer endianness: mixed"));
#elif defined(DUK_USE_INTEGER_BE)
- DUK_D(DUK_DPRINT("Integer endianness: big"));
+ DUK_D(DUK_DPRINT("integer endianness: big"));
#else
- DUK_D(DUK_DPRINT("Integer endianness: ???"));
+ DUK_D(DUK_DPRINT("integer endianness: ???"));
#endif
#if defined(DUK_USE_DOUBLE_LE)
DUK_D(DUK_DPRINT("IEEE double endianness: little"));
@@ -42737,7 +43871,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
* Debug dump type sizes
*/
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
duk__dump_misc_options();
duk__dump_type_sizes();
duk__dump_type_limits();
@@ -42746,7 +43880,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
/*
* If selftests enabled, run them as early as possible
*/
-#ifdef DUK_USE_SELF_TESTS
+#if defined(DUK_USE_SELF_TESTS)
DUK_D(DUK_DPRINT("running self tests"));
duk_selftest_run_tests();
DUK_D(DUK_DPRINT("self tests passed"));
@@ -42756,7 +43890,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
* Computed values (e.g. INFINITY)
*/
-#ifdef DUK_USE_COMPUTED_NAN
+#if defined(DUK_USE_COMPUTED_NAN)
do {
/* Workaround for some exotic platforms where NAN is missing
* and the expression (0.0 / 0.0) does NOT result in a NaN.
@@ -42772,7 +43906,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
} while (0);
#endif
-#ifdef DUK_USE_COMPUTED_INFINITY
+#if defined(DUK_USE_COMPUTED_INFINITY)
do {
/* Similar workaround for INFINITY. */
volatile double dbl1 = 1.0;
@@ -42799,14 +43933,14 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
DUK_MEMZERO(res, sizeof(*res));
/* explicit NULL inits */
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
res->heap_udata = NULL;
res->heap_allocated = NULL;
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
res->refzero_list = NULL;
res->refzero_list_tail = NULL;
#endif
-#ifdef DUK_USE_MARK_AND_SWEEP
+#if defined(DUK_USE_MARK_AND_SWEEP)
res->finalize_list = NULL;
#endif
res->heap_thread = NULL;
@@ -42869,8 +44003,11 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
*/
res->hash_seed = (duk_uint32_t) (duk_intptr_t) res;
res->rnd_state = (duk_uint32_t) (duk_intptr_t) res;
+#if !defined(DUK_USE_STRHASH_DENSE)
+ res->hash_seed ^= 5381; /* Bernstein hash init value is normally 5381; XOR it in in case pointer low bits are 0 */
+#endif
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
res->lj.jmpbuf_ptr = NULL;
#endif
DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */
@@ -42888,7 +44025,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
#if defined(DUK_USE_STRTAB_CHAIN)
DUK_MEMZERO(res->strtable, sizeof(duk_strtab_entry) * DUK_STRTAB_CHAIN_SIZE);
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
{
duk_small_uint_t i;
for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
@@ -42919,7 +44056,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
}
#endif /* DUK_USE_HEAPPTR16 */
res->st_size = DUK_STRTAB_INITIAL_SIZE;
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
{
duk_small_uint_t i;
DUK_ASSERT(res->st_size == DUK_STRTAB_INITIAL_SIZE);
@@ -42944,7 +44081,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
* Init stringcache
*/
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
{
duk_small_uint_t i;
for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
@@ -43014,11 +44151,23 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
#line 1 "duk_heap_hashstring.c"
/*
* String hash computation (interning).
+ *
+ * String hashing is performance critical because a string hash is computed
+ * for all new strings which are candidates to be added to the string table.
+ * However, strings actually added to the string table go through a codepoint
+ * length calculation which dominates performance because it goes through
+ * every byte of the input string (but only for strings added).
+ *
+ * The string hash algorithm should be fast, but on the other hand provide
+ * good enough hashes to ensure both string table and object property table
+ * hash tables work reasonably well (i.e., there aren't too many collisions
+ * with real world inputs). Unless the hash is cryptographic, it's always
+ * possible to craft inputs with maximal hash collisions.
*/
/* include removed: duk_internal.h */
-/* constants for duk_hashstring() */
+#if defined(DUK_USE_STRHASH_DENSE)
#define DUK__STRHASH_SHORTSTRING 4096L
#define DUK__STRHASH_MEDIUMSTRING (256L * 1024L)
#define DUK__STRHASH_BLOCKSIZE 256L
@@ -43026,25 +44175,21 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
duk_uint32_t hash;
- /*
- * Sampling long strings by byte skipping (like Lua does) is potentially
- * a cache problem. Here we do 'block skipping' instead for long strings:
- * hash an initial part, and then sample the rest of the string with
- * reasonably sized chunks.
- *
- * Skip should depend on length and bound the total time to roughly
- * logarithmic.
+ /* Use Murmurhash2 directly for short strings, and use "block skipping"
+ * for long strings: hash an initial part and then sample the rest of
+ * the string with reasonably sized chunks. An initial offset for the
+ * sampling is computed based on a hash of the initial part of the string;
+ * this is done to (usually) avoid the case where all long strings have
+ * certain offset ranges which are never sampled.
*
- * With current values:
+ * Skip should depend on length and bound the total time to roughly
+ * logarithmic. With current values:
*
- * 1M string => 256 * 241 = 61696 bytes (0.06M) of hashing
- * 1G string => 256 * 16321 = 4178176 bytes (3.98M) of hashing
+ * 1M string => 256 * 241 = 61696 bytes (0.06M) of hashing
+ * 1G string => 256 * 16321 = 4178176 bytes (3.98M) of hashing
*
- * After an initial part has been hashed, an offset is applied before
- * starting the sampling. The initial offset is computed from the
- * hash of the initial part of the string. The idea is to avoid the
- * case that all long strings have certain offset ranges that are never
- * sampled.
+ * XXX: It would be better to compute the skip offset more "smoothly"
+ * instead of having a few boundary values.
*/
/* note: mixing len into seed improves hashing when skipping */
@@ -43082,6 +44227,44 @@ DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t
#endif
return hash;
}
+
+#undef DUK__STRHASH_SHORTSTRING
+#undef DUK__STRHASH_MEDIUMSTRING
+#undef DUK__STRHASH_BLOCKSIZE
+#else /* DUK_USE_STRHASH_DENSE */
+DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
+ duk_uint32_t hash;
+ duk_size_t step;
+ duk_size_t off;
+
+ /* Slightly modified "Bernstein hash" from:
+ *
+ * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
+ *
+ * Modifications: string skipping and reverse direction similar to
+ * Lua 5.1.5, and different hash initializer.
+ *
+ * The reverse direction ensures last byte it always included in the
+ * hash which is a good default as changing parts of the string are
+ * more often in the suffix than in the prefix.
+ */
+
+ hash = heap->hash_seed ^ ((duk_uint32_t) len); /* Bernstein hash init value is normally 5381 */
+ step = (len >> DUK_USE_STRHASH_SKIP_SHIFT) + 1;
+ for (off = len; off >= step; off -= step) {
+ DUK_ASSERT(off >= 1); /* off >= step, and step >= 1 */
+ hash = (hash * 33) + str[off - 1];
+ }
+
+#if defined(DUK_USE_STRHASH16)
+ /* Truncate to 16 bits here, so that a computed hash can be compared
+ * against a hash stored in a 16-bit field.
+ */
+ hash &= 0x0000ffffUL;
+#endif
+ return hash;
+}
+#endif /* DUK_USE_STRHASH_DENSE */
#line 1 "duk_heap_markandsweep.c"
/*
* Mark-and-sweep garbage collection.
@@ -43940,7 +45123,7 @@ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_
* Run (object) finalizers in the "to be finalized" work list.
*/
-DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap) {
+DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags) {
duk_heaphdr *curr;
duk_heaphdr *next;
#ifdef DUK_USE_DEBUG
@@ -43963,13 +45146,22 @@ DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap) {
DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
- /* run the finalizer */
- duk_hobject_run_finalizer(thr, (duk_hobject *) curr); /* must never longjmp */
-
- /* mark FINALIZED, for next mark-and-sweep (will collect unless has become reachable;
- * prevent running finalizer again if reachable)
- */
- DUK_HEAPHDR_SET_FINALIZED(curr);
+ if (DUK_LIKELY((flags & DUK_MS_FLAG_SKIP_FINALIZERS) == 0)) {
+ /* Run the finalizer, duk_hobject_run_finalizer() sets FINALIZED.
+ * Next mark-and-sweep will collect the object unless it has
+ * become reachable (i.e. rescued). FINALIZED prevents the
+ * finalizer from being executed again before that.
+ */
+ duk_hobject_run_finalizer(thr, (duk_hobject *) curr); /* must never longjmp */
+ DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr));
+ } else {
+ /* Used during heap destruction: don't actually run finalizers
+ * because we're heading into forced finalization. Instead,
+ * queue finalizable objects back to the heap_allocated list.
+ */
+ DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing"));
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
+ }
/* queue back to heap_allocated */
next = DUK_HEAPHDR_GET_NEXT(heap, curr);
@@ -44406,7 +45598,7 @@ DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t
if (flags & DUK_MS_FLAG_NO_FINALIZERS) {
DUK_D(DUK_DPRINT("finalizer run skipped because DUK_MS_FLAG_NO_FINALIZERS is set"));
} else {
- duk__run_object_finalizers(heap);
+ duk__run_object_finalizers(heap, flags);
}
/*
@@ -45210,10 +46402,9 @@ DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) {
* objects and must be safe (not throw any errors, ever).
*/
- /* XXX: If object has FINALIZED, it was finalized by mark-and-sweep on
- * its previous run. Any point in running finalizer again here? If
- * finalization semantics is changed so that finalizer is only run once,
- * checking for FINALIZED would happen here.
+ /* An object may have FINALIZED here if it was finalized by mark-and-sweep
+ * on a previous run and refcount then decreased to zero. We won't run the
+ * finalizer again here.
*/
/* A finalizer is looked up from the object and up its prototype chain
@@ -45226,6 +46417,7 @@ DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) {
DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */
duk_hobject_run_finalizer(thr, obj); /* must never longjmp */
+ DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); /* duk_hobject_run_finalizer() sets */
DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */
DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */
@@ -45266,6 +46458,9 @@ DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) {
if (rescued) {
/* yes -> move back to heap allocated */
DUK_DD(DUK_DDPRINT("object rescued during refcount finalization: %p", (void *) h1));
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(h1));
+ DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1));
+ DUK_HEAPHDR_CLEAR_FINALIZED(h1);
DUK_HEAPHDR_SET_PREV(heap, h1, NULL);
DUK_HEAPHDR_SET_NEXT(heap, h1, heap->heap_allocated);
heap->heap_allocated = h1;
@@ -45319,22 +46514,25 @@ DUK_INTERNAL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) {
heap = thr->heap;
DUK_DDD(DUK_DDDPRINT("refzero %p: %!O", (void *) h, (duk_heaphdr *) h));
-#ifdef DUK_USE_MARK_AND_SWEEP
/*
* If mark-and-sweep is running, don't process 'refzero' situations at all.
* They may happen because mark-and-sweep needs to finalize refcounts for
* each object it sweeps. Otherwise the target objects of swept objects
* would have incorrect refcounts.
*
+ * This check must be enabled also when mark-and-sweep support has been
+ * disabled: the flag is also used in heap destruction when running
+ * finalizers for remaining objects, and the flag prevents objects from
+ * being moved around in heap linked lists.
+ *
* Note: mark-and-sweep could use a separate decref handler to avoid coming
* here at all. However, mark-and-sweep may also call finalizers, which
* can do arbitrary operations and would use this decref variant anyway.
*/
- if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
+ if (DUK_UNLIKELY(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap))) {
DUK_DDD(DUK_DDDPRINT("refzero handling suppressed when mark-and-sweep running, object: %p", (void *) h));
return;
}
-#endif
switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
case DUK_HTYPE_STRING:
@@ -45531,9 +46729,13 @@ DUK_INTERNAL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h
/*
* String scanning helpers
+ *
+ * All bytes other than UTF-8 continuation bytes ([0x80,0xbf]) are
+ * considered to contribute a character. This must match how string
+ * character length is computed.
*/
-DUK_LOCAL duk_uint8_t *duk__scan_forwards(duk_uint8_t *p, duk_uint8_t *q, duk_uint_fast32_t n) {
+DUK_LOCAL const duk_uint8_t *duk__scan_forwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
while (n > 0) {
for (;;) {
p++;
@@ -45549,7 +46751,7 @@ DUK_LOCAL duk_uint8_t *duk__scan_forwards(duk_uint8_t *p, duk_uint8_t *q, duk_ui
return p;
}
-DUK_LOCAL duk_uint8_t *duk__scan_backwards(duk_uint8_t *p, duk_uint8_t *q, duk_uint_fast32_t n) {
+DUK_LOCAL const duk_uint8_t *duk__scan_backwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
while (n > 0) {
for (;;) {
p--;
@@ -45584,9 +46786,9 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
duk_small_int_t i;
duk_bool_t use_cache;
duk_uint_fast32_t dist_start, dist_end, dist_sce;
- duk_uint8_t *p_start;
- duk_uint8_t *p_end;
- duk_uint8_t *p_found;
+ const duk_uint8_t *p_start;
+ const duk_uint8_t *p_end;
+ const duk_uint8_t *p_found;
if (char_offset > DUK_HSTRING_GET_CHARLEN(h)) {
goto error;
@@ -45653,8 +46855,8 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
dist_end = DUK_HSTRING_GET_CHARLEN(h) - char_offset;
dist_sce = 0; DUK_UNREF(dist_sce); /* initialize for debug prints, needed if sce==NULL */
- p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
- p_end = (duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h));
+ p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
+ p_end = (const duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h));
p_found = NULL;
if (sce) {
@@ -45765,7 +46967,7 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
tmp = *sce;
DUK_MEMMOVE((void *) (&heap->strcache[1]),
- (void *) (&heap->strcache[0]),
+ (const void *) (&heap->strcache[0]),
(size_t) (((char *) sce) - ((char *) &heap->strcache[0])));
heap->strcache[0] = tmp;
@@ -46040,7 +47242,7 @@ DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk
duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
DUK_ASSERT(h != NULL);
if (DUK_HSTRING_GET_BYTELEN(h) == blen &&
- DUK_MEMCMP(str, DUK_HSTRING_GET_DATA(h), blen) == 0) {
+ DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
return h;
}
}
@@ -46053,7 +47255,7 @@ DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk
duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[i]);
DUK_ASSERT(h != NULL);
if (DUK_HSTRING_GET_BYTELEN(h) == blen &&
- DUK_MEMCMP(str, DUK_HSTRING_GET_DATA(h), blen) == 0) {
+ DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
return h;
}
}
@@ -46078,7 +47280,7 @@ DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk
if (e->listlen == 0) {
if (e->u.str != NULL &&
DUK_HSTRING_GET_BYTELEN(e->u.str) == blen &&
- DUK_MEMCMP(str, DUK_HSTRING_GET_DATA(e->u.str), blen) == 0) {
+ DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e->u.str), (size_t) blen) == 0) {
return e->u.str;
}
} else {
@@ -46087,7 +47289,7 @@ DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk
for (i = 0, n = e->listlen; i < n; i++) {
if (lst[i] != NULL &&
DUK_HSTRING_GET_BYTELEN(lst[i]) == blen &&
- DUK_MEMCMP(str, DUK_HSTRING_GET_DATA(lst[i]), blen) == 0) {
+ DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(lst[i]), (size_t) blen) == 0) {
return lst[i];
}
}
@@ -46339,7 +47541,7 @@ DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_hstri
return NULL;
}
if (e != DUK__DELETED_MARKER(heap) && DUK_HSTRING_GET_BYTELEN(e) == blen) {
- if (DUK_MEMCMP(str, DUK_HSTRING_GET_DATA(e), blen) == 0) {
+ if (DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e), (size_t) blen) == 0) {
DUK_DDD(DUK_DDDPRINT("find matching hit: %ld (step %ld, size %ld)",
(long) i, (long) step, (long) size));
return e;
@@ -47241,7 +48443,7 @@ DUK_LOCAL void duk__sort_array_indices(duk_hthread *thr, duk_hobject *h_obj) {
(long) (p_curr - p_insert), (void *) h_curr));
DUK_MEMMOVE((void *) (p_insert + 1),
- (void *) p_insert,
+ (const void *) p_insert,
(size_t) ((p_curr - p_insert) * sizeof(duk_hstring *)));
*p_insert = h_curr;
/* keep val_highest */
@@ -47747,7 +48949,10 @@ DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_sma
/* include removed: duk_internal.h */
DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx) {
+ duk_hthread *thr;
+
DUK_ASSERT(ctx != NULL);
+ thr = (duk_hthread *) ctx;
DUK_DDD(DUK_DDDPRINT("protected finalization helper running"));
@@ -47765,9 +48970,10 @@ DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx) {
DUK_DDD(DUK_DDDPRINT("-> no finalizer or finalizer not callable"));
return 0;
}
- duk_dup(ctx, -2); /* -> [... obj finalizer obj] */
+ duk_dup(ctx, -2);
+ duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap));
DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling finalizer"));
- duk_call(ctx, 1); /* -> [... obj retval] */
+ duk_call(ctx, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */
DUK_DDD(DUK_DDDPRINT("finalizer finished successfully"));
return 0;
@@ -47800,6 +49006,20 @@ DUK_INTERNAL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj)
* may trigger an error (getter may throw one, for instance).
*/
+ if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) {
+ DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj));
+ return;
+ }
+ DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */
+ if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) {
+ /* This shouldn't happen; call sites should avoid looking up
+ * _Finalizer "through" a Proxy, but ignore if we come here
+ * with a Proxy to avoid finalizer re-entry.
+ */
+ DUK_D(DUK_DPRINT("object is a proxy, skip finalizer call"));
+ return;
+ }
+
/* XXX: use a NULL error handler for the finalizer call? */
DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling wrapped finalize helper"));
@@ -49469,6 +50689,11 @@ DUK_INTERNAL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap,
DUK_ASSERT(heap != NULL);
DUK_ASSERT(obj != NULL);
+ /* This is not strictly necessary, but avoids compiler warnings; e.g.
+ * gcc won't reliably detect that no uninitialized data is read below.
+ */
+ DUK_MEMZERO((void *) &tv, sizeof(duk_tval));
+
if (duk_hobject_get_internal_value(heap, obj, &tv)) {
duk_hstring *h;
DUK_ASSERT(DUK_TVAL_IS_STRING(&tv));
@@ -50367,7 +51592,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
case DUK_TAG_NULL: {
/* Note: unconditional throw */
DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject"));
+#if defined(DUK_USE_PARANOID_ERRORS)
DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_BASE);
+#else
+ DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "cannot read property %s of %s",
+ duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
+#endif
return 0;
}
@@ -51402,7 +52632,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
/* Note: unconditional throw */
DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject (object=%!iT)",
(duk_tval *) tv_obj));
+#if defined(DUK_USE_PARANOID_ERRORS)
DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_BASE);
+#else
+ DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
+ duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
+#endif
return 0;
}
@@ -52159,7 +53394,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
fail_base_primitive:
DUK_DDD(DUK_DDDPRINT("result: error, base primitive"));
if (throw_flag) {
+#if defined(DUK_USE_PARANOID_ERRORS)
DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_BASE);
+#else
+ DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
+ duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
+#endif
}
duk_pop(ctx); /* remove key */
return 0;
@@ -52521,7 +53761,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
fail_invalid_base_uncond:
/* Note: unconditional throw */
DUK_ASSERT(duk_get_top(ctx) == entry_top);
+#if defined(DUK_USE_PARANOID_ERRORS)
DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_BASE);
+#else
+ DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "cannot delete property %s of %s",
+ duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
+#endif
return 0;
fail_proxy_rejected:
@@ -54041,7 +55286,8 @@ DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
p = p_start + boff;
DUK_DDD(DUK_DDDPRINT("p_start=%p, p_end=%p, p=%p",
- (void *) p_start, (void *) p_end, (void *) p));
+ (const void *) p_start, (const void *) p_end,
+ (const void *) p));
/* This may throw an error though not for valid E5 strings. */
cp = duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
@@ -54476,9 +55722,6 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
duk_c_function c_func_getter;
duk_c_function c_func_setter;
- /* XXX: this is a bit awkward because there is no exposed helper
- * in the API style, only this internal helper.
- */
DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, stridx=%ld, getteridx=%ld, setteridx=%ld, flags=0x%04lx",
(long) i, (long) stridx, (long) natidx_getter, (long) natidx_setter, (unsigned long) prop_flags));
@@ -54487,7 +55730,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
duk_push_c_function_noconstruct_noexotic(ctx, c_func_getter, 0); /* always 0 args */
duk_push_c_function_noconstruct_noexotic(ctx, c_func_setter, 1); /* always 1 arg */
- /* XXX: magic for getter/setter? */
+ /* XXX: magic for getter/setter? use duk_def_prop()? */
prop_flags |= DUK_PROPDESC_FLAG_ACCESSOR; /* accessor flag not encoded explicitly */
duk_hobject_define_accessor_internal(thr,
@@ -54683,9 +55926,6 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
#else
"?"
#endif
-#if defined(DUK_USE_BYTEORDER_FORCED)
- "f"
-#endif
" "
/* Packed or unpacked tval */
#if defined(DUK_USE_PACKED_TVAL)
@@ -56124,7 +57364,12 @@ duk_hobject *duk__nonbound_func_lookup(duk_context *ctx,
return func;
not_callable_error:
+ DUK_ASSERT(tv_func != NULL);
+#if defined(DUK_USE_PARANOID_ERRORS)
DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_CALLABLE);
+#else
+ DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_push_string_tval_readable(ctx, tv_func));
+#endif
DUK_UNREACHABLE();
return NULL; /* never executed */
}
@@ -56245,7 +57490,7 @@ duk_int_t duk_handle_call(duk_hthread *thr,
duk_instr_t **entry_ptr_curr_pc;
volatile duk_bool_t need_setjmp;
duk_jmpbuf * volatile old_jmpbuf_ptr = NULL; /* ptr is volatile (not the target) */
- volatile duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
+ duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
duk_idx_t idx_args; /* valstack index of start of args (arg1) (relative to entry valstack_bottom) */
duk_idx_t nargs; /* # argument registers target function wants (< 0 => "as is") */
duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => "as is") */
@@ -56341,7 +57586,7 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* call the fatal error handler.
*/
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
}
/*
@@ -56806,7 +58051,7 @@ duk_int_t duk_handle_call(duk_hthread *thr,
duk_error_throw_from_negative_rc(thr, rc);
DUK_UNREACHABLE();
} else if (rc > 1) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, "c function returned invalid rc");
+ DUK_ERROR_API(thr, "c function returned invalid rc");
}
DUK_ASSERT(rc == 0 || rc == 1);
@@ -57201,7 +58446,7 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
* call the fatal error handler.
*/
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
}
/* setjmp catchpoint setup */
@@ -57353,7 +58598,7 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
DUK_ASSERT(rc >= 0);
if (duk_get_top(ctx) < rc) {
- DUK_ERROR(thr, DUK_ERR_API_ERROR, "not enough stack values for safe_call rc");
+ DUK_ERROR_API(thr, "not enough stack values for safe_call rc");
}
duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc);
@@ -57536,7 +58781,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
if (idx_func < 0 || idx_args < 0) {
/* XXX: assert? compiler is responsible for this never happening */
- DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
}
/*
@@ -58093,7 +59338,7 @@ DUK_LOCAL_DECL duk_bool_t duk__nud_object_literal_key_check(duk_compiler_ctx *co
/* statement parsing */
DUK_LOCAL_DECL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
-DUK_LOCAL_DECL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
+DUK_LOCAL_DECL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags);
DUK_LOCAL_DECL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
DUK_LOCAL_DECL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
DUK_LOCAL_DECL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
@@ -58185,11 +59430,11 @@ DUK_LOCAL const duk_uint8_t duk__token_lbp[] = {
DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TRY */
DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TYPEOF */
DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VAR */
+ DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONST */
DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VOID */
DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WHILE */
DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WITH */
DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CLASS */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONST */
DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ENUM */
DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXPORT */
DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXTENDS */
@@ -61681,9 +62926,17 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
case DUK_TOK_PERIOD: {
/* Property access expressions are critical for correct LHS ordering,
* see comments in duk__expr()!
+ *
+ * A conservative approach would be to use duk__ivalue_totempconst()
+ * for 'left'. However, allowing a reg-bound variable seems safe here
+ * and is nice because "foo.bar" is a common expression. If the ivalue
+ * is used in an expression a GETPROP will occur before any changes to
+ * the base value can occur. If the ivalue is used as an assignment
+ * LHS, the assignment code will ensure the base value is safe from
+ * RHS mutation.
*/
- /* XXX: this now coerces an identifier into a GETVAR to a temp, which
+ /* XXX: This now coerces an identifier into a GETVAR to a temp, which
* causes an extra LDREG in call setup. It's sufficient to coerce to a
* unary ivalue?
*/
@@ -61714,13 +62967,22 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
/* XXX: optimize temp reg use */
/* XXX: similar coercion issue as in DUK_TOK_PERIOD */
-
/* XXX: coerce to regs? it might be better for enumeration use, where the
* same PROP ivalue is used multiple times. Or perhaps coerce PROP further
* there?
*/
+ /* XXX: for simple cases like x['y'] an unnecessary LDREG is
+ * emitted for the base value; could avoid it if we knew that
+ * the key expression is safe (e.g. just a single literal).
+ */
- duk__ivalue_toplain(comp_ctx, left);
+ /* The 'left' value must not be a register bound variable
+ * because it may be mutated during the rest of the expression
+ * and E5.1 Section 11.2.1 specifies the order of evaluation
+ * so that the base value is evaluated first.
+ * See: test-bug-nested-prop-mutate.js.
+ */
+ duk__ivalue_totempconst(comp_ctx, left);
duk__expr_toplain(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, ']' terminates */
duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET);
@@ -62558,8 +63820,9 @@ DUK_LOCAL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx) {
*/
#define DUK__EXPR_RBP_MASK 0xff
-#define DUK__EXPR_FLAG_REJECT_IN (1 << 8)
-#define DUK__EXPR_FLAG_ALLOW_EMPTY (1 << 9)
+#define DUK__EXPR_FLAG_REJECT_IN (1 << 8) /* reject 'in' token (used for for-in) */
+#define DUK__EXPR_FLAG_ALLOW_EMPTY (1 << 9) /* allow empty expression */
+#define DUK__EXPR_FLAG_REQUIRE_INIT (1 << 10) /* require initializer for var/const */
/* main expression parser function */
DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
@@ -62833,6 +64096,11 @@ DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
(duk_regconst_t) reg_val,
rc_varname);
}
+ } else {
+ if (expr_flags & DUK__EXPR_FLAG_REQUIRE_INIT) {
+ /* Used for minimal 'const': initializer required. */
+ goto syntax_error;
+ }
}
duk_pop(ctx); /* pop varname */
@@ -62846,7 +64114,7 @@ DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, DUK_STR_INVALID_VAR_DECLARATION);
}
-DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
+DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags) {
duk_reg_t reg_varbind;
duk_regconst_t rc_varname;
@@ -62854,7 +64122,7 @@ DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
for (;;) {
/* rc_varname and reg_varbind are ignored here */
- duk__parse_var_decl(comp_ctx, res, 0, &reg_varbind, &rc_varname);
+ duk__parse_var_decl(comp_ctx, res, 0 | expr_flags, &reg_varbind, &rc_varname);
if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
break;
@@ -64135,9 +65403,15 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
stmt_flags = 0;
break;
}
+ case DUK_TOK_CONST: {
+ DUK_DDD(DUK_DDDPRINT("constant declaration statement"));
+ duk__parse_var_stmt(comp_ctx, res, DUK__EXPR_FLAG_REQUIRE_INIT /*expr_flags*/);
+ stmt_flags = DUK__HAS_TERM;
+ break;
+ }
case DUK_TOK_VAR: {
DUK_DDD(DUK_DDDPRINT("variable declaration statement"));
- duk__parse_var_stmt(comp_ctx, res);
+ duk__parse_var_stmt(comp_ctx, res, 0 /*expr_flags*/);
stmt_flags = DUK__HAS_TERM;
break;
}
@@ -65644,37 +66918,9 @@ DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer
prev_ctx = thr->compile_ctx;
thr->compile_ctx = &comp_stk.comp_ctx_alloc; /* for duk_error_augment.c */
safe_rc = duk_safe_call(ctx, duk__js_compile_raw, 2 /*nargs*/, 1 /*nret*/);
- thr->compile_ctx = prev_ctx;
+ thr->compile_ctx = prev_ctx; /* must restore reliably before returning */
if (safe_rc != DUK_EXEC_SUCCESS) {
- /* Append a "(line NNN)" to the "message" property of any
- * error thrown during compilation. Usually compilation
- * errors are SyntaxErrors but they can also be out-of-memory
- * errors and the like.
- *
- * Source file/line are added to tracedata directly by
- * duk_error_augment.c based on thr->compile_ctx.
- */
-
- /* [ ... error ] */
-
- DUK_DDD(DUK_DDDPRINT("compile error, before adding line info: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
- if (duk_is_object(ctx, -1)) {
- /* XXX: Now that fileName and lineNumber are set, this is
- * unnecessary. Remove in Duktape 1.3.0?
- */
-
- if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_MESSAGE)) {
- duk_push_sprintf(ctx, " (line %ld)", (long) comp_stk.comp_ctx_alloc.curr_token.start_line);
- duk_concat(ctx, 2);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE);
- } else {
- duk_pop(ctx);
- }
- }
- DUK_DDD(DUK_DDDPRINT("compile error, after adding line info: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
duk_throw(ctx);
}
@@ -70732,7 +71978,7 @@ DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, d
DUK_ASSERT(len_x == len_y);
DUK_ASSERT(len_x == 0 || buf_x != NULL);
DUK_ASSERT(len_y == 0 || buf_y != NULL);
- return (DUK_MEMCMP(buf_x, buf_y, len_x) == 0) ? 1 : 0;
+ return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0;
}
}
case DUK_TAG_LIGHTFUNC: {
@@ -70811,20 +72057,20 @@ DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, d
duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
duk_size_t len_x = DUK_HSTRING_GET_BYTELEN(h_x);
duk_size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
- void *buf_x;
- void *buf_y;
+ const void *buf_x;
+ const void *buf_y;
if (len_x != len_y) {
return 0;
}
- buf_x = (void *) DUK_HSTRING_GET_DATA(h_x);
- buf_y = (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y);
+ buf_x = (const void *) DUK_HSTRING_GET_DATA(h_x);
+ buf_y = (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y);
/* if len_x == len_y == 0, buf_x and/or buf_y may
* be NULL, but that's OK.
*/
DUK_ASSERT(len_x == len_y);
DUK_ASSERT(len_x == 0 || buf_x != NULL);
DUK_ASSERT(len_y == 0 || buf_y != NULL);
- return (DUK_MEMCMP(buf_x, buf_y, len_x) == 0) ? 1 : 0;
+ return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0;
}
/* Boolean/any -> coerce boolean to number and try again. If boolean is
@@ -70887,19 +72133,12 @@ DUK_INTERNAL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const
prefix_len = (len1 <= len2 ? len1 : len2);
- /* XXX: this special case can now be removed with DUK_MEMCMP */
- /* memcmp() should return zero (equal) for zero length, but avoid
- * it because there are some platform specific bugs. Don't use
- * strncmp() because it stops comparing at a NUL.
+ /* DUK_MEMCMP() is guaranteed to return zero (equal) for zero length
+ * inputs so no zero length check is needed.
*/
-
- if (prefix_len == 0) {
- rc = 0;
- } else {
- rc = DUK_MEMCMP((const char *) buf1,
- (const char *) buf2,
- prefix_len);
- }
+ rc = DUK_MEMCMP((const void *) buf1,
+ (const void *) buf2,
+ (size_t) prefix_len);
if (rc < 0) {
return -1;
@@ -73781,7 +75020,7 @@ DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count
keep_bytes = DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint) - count_bytes;
DUK_MEMMOVE((void *) lex_ctx->window,
(const void *) ((duk_uint8_t *) lex_ctx->window + count_bytes),
- (duk_size_t) keep_bytes);
+ (size_t) keep_bytes);
cp = (duk_lexer_codepoint *) ((duk_uint8_t *) lex_ctx->window + keep_bytes);
cp_end = lex_ctx->window + DUK_LEXER_WINDOW_SIZE;
@@ -75496,7 +76735,7 @@ DUK_LOCAL void duk__bi_copy(duk__bigint *x, duk__bigint *y) {
if (n == 0) {
return;
}
- DUK_MEMCPY((void *) x->v, (void *) y->v, (size_t) (sizeof(duk_uint32_t) * n));
+ DUK_MEMCPY((void *) x->v, (const void *) y->v, (size_t) (sizeof(duk_uint32_t) * n));
}
DUK_LOCAL void duk__bi_set_small(duk__bigint *x, duk_uint32_t v) {
@@ -76058,7 +77297,7 @@ DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x
}
len = (duk_size_t) ((buf + 32) - p);
- DUK_MEMMOVE((void *) buf, (void *) p, (size_t) len);
+ DUK_MEMMOVE((void *) buf, (const void *) p, (size_t) len);
return len;
}
@@ -76527,7 +77766,7 @@ DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify
if (p == &nc_ctx->digits[0]) {
DUK_DDD(DUK_DDDPRINT("carry propagated to first digit -> special case handling"));
DUK_MEMMOVE((void *) (&nc_ctx->digits[1]),
- (void *) (&nc_ctx->digits[0]),
+ (const void *) (&nc_ctx->digits[0]),
(size_t) (sizeof(char) * nc_ctx->count));
nc_ctx->digits[0] = 1; /* don't increase 'count' */
nc_ctx->k++; /* position of highest digit changed */
@@ -77298,7 +78537,7 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
DUK_DDD(DUK_DDDPRINT("parse digits: p=%p, ch='%c' (%ld), expt=%ld, expt_adj=%ld, "
"dig_whole=%ld, dig_frac=%ld, dig_expt=%ld, dig_lzero=%ld, dig_prec=%ld",
- (void *) p, (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : '?'), (long) ch,
+ (const void *) p, (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : '?'), (long) ch,
(long) expt, (long) expt_adj, (long) dig_whole, (long) dig_frac,
(long) dig_expt, (long) dig_lzero, (long) dig_prec));
DUK__BI_PRINT("f", &nc_ctx->f);
@@ -79420,9 +80659,9 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
DUK_MEMZERO(&re_ctx, sizeof(re_ctx));
re_ctx.thr = thr;
- re_ctx.input = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
+ re_ctx.input = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
re_ctx.input_end = re_ctx.input + DUK_HSTRING_GET_BYTELEN(h_input);
- re_ctx.bytecode = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_bytecode);
+ re_ctx.bytecode = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_bytecode);
re_ctx.bytecode_end = re_ctx.bytecode + DUK_HSTRING_GET_BYTELEN(h_bytecode);
re_ctx.saved = NULL;
re_ctx.recursion_limit = DUK_USE_REGEXP_EXECUTOR_RECLIMIT;
@@ -79519,8 +80758,8 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
DUK_ASSERT(re_ctx.recursion_depth == 0);
DUK_DDD(DUK_DDDPRINT("attempt match at char offset %ld; %p [%p,%p]",
- (long) char_offset, (void *) sp, (void *) re_ctx.input,
- (void *) re_ctx.input_end));
+ (long) char_offset, (const void *) sp,
+ (const void *) re_ctx.input, (const void *) re_ctx.input_end));
/*
* Note:
@@ -79627,7 +80866,7 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
duk_hstring *h_saved;
duk_push_lstring(ctx,
- (char *) re_ctx.saved[i],
+ (const char *) re_ctx.saved[i],
(duk_size_t) (re_ctx.saved[i+1] - re_ctx.saved[i]));
h_saved = duk_get_hstring(ctx, -1);
DUK_ASSERT(h_saved != NULL);
@@ -79719,15 +80958,15 @@ DUK_INTERNAL void duk_regexp_match_force_global(duk_hthread *thr) {
/* include removed: duk_internal.h */
-#ifdef DUK_USE_COMPUTED_NAN
+#if defined(DUK_USE_COMPUTED_NAN)
DUK_INTERNAL double duk_computed_nan;
#endif
-#ifdef DUK_USE_COMPUTED_INFINITY
+#if defined(DUK_USE_COMPUTED_INFINITY)
DUK_INTERNAL double duk_computed_infinity;
#endif
-#ifdef DUK_USE_REPL_FPCLASSIFY
+#if defined(DUK_USE_REPL_FPCLASSIFY)
DUK_INTERNAL int duk_repl_fpclassify(double x) {
duk_double_union u;
duk_uint_fast16_t expt;
@@ -79759,7 +80998,7 @@ DUK_INTERNAL int duk_repl_fpclassify(double x) {
}
#endif
-#ifdef DUK_USE_REPL_SIGNBIT
+#if defined(DUK_USE_REPL_SIGNBIT)
DUK_INTERNAL int duk_repl_signbit(double x) {
duk_double_union u;
u.d = x;
@@ -79767,7 +81006,7 @@ DUK_INTERNAL int duk_repl_signbit(double x) {
}
#endif
-#ifdef DUK_USE_REPL_ISFINITE
+#if defined(DUK_USE_REPL_ISFINITE)
DUK_INTERNAL int duk_repl_isfinite(double x) {
int c = DUK_FPCLASSIFY(x);
if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
@@ -79778,14 +81017,14 @@ DUK_INTERNAL int duk_repl_isfinite(double x) {
}
#endif
-#ifdef DUK_USE_REPL_ISNAN
+#if defined(DUK_USE_REPL_ISNAN)
DUK_INTERNAL int duk_repl_isnan(double x) {
int c = DUK_FPCLASSIFY(x);
return (c == DUK_FP_NAN);
}
#endif
-#ifdef DUK_USE_REPL_ISINF
+#if defined(DUK_USE_REPL_ISINF)
DUK_INTERNAL int duk_repl_isinf(double x) {
int c = DUK_FPCLASSIFY(x);
return (c == DUK_FP_INFINITE);
@@ -79811,13 +81050,13 @@ typedef union {
} duk__test_double_union;
#define DUK__DBLUNION_CMP_TRUE(a,b) do { \
- if (DUK_MEMCMP((void *) (a), (void *) (b), sizeof(duk__test_double_union)) != 0) { \
+ if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) != 0) { \
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares false (expected true)"); \
} \
} while (0)
#define DUK__DBLUNION_CMP_FALSE(a,b) do { \
- if (DUK_MEMCMP((void *) (a), (void *) (b), sizeof(duk__test_double_union)) == 0) { \
+ if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) == 0) { \
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares true (expected false)"); \
} \
} while (0)
@@ -79877,7 +81116,11 @@ DUK_LOCAL void duk__selftest_packed_tval(void) {
DUK_LOCAL void duk__selftest_twos_complement(void) {
volatile int test;
test = -1;
- if (((duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) {
+
+ /* Note that byte order doesn't affect this test: all bytes in
+ * 'test' will be 0xFF for two's complement.
+ */
+ if (((volatile duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) {
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: two's complement arithmetic");
}
}
@@ -79998,15 +81241,12 @@ DUK_LOCAL void duk__selftest_double_aliasing(void) {
* It's not an issue because the failure should only affect packed
* duk_tval representation, which is not used with Emscripten.
*/
-#if defined(DUK_USE_NO_DOUBLE_ALIASING_SELFTEST)
-#if defined(DUK_USE_PACKED_TVAL)
-#error inconsistent defines: skipping double aliasing selftest when using packed duk_tval
-#endif
+#if !defined(DUK_USE_PACKED_TVAL)
+ DUK_D(DUK_DPRINT("skip double aliasing self test when duk_tval is not packed"));
return;
#endif
- /* Test signaling NaN and alias assignment in all
- * endianness combinations.
+ /* Test signaling NaN and alias assignment in all endianness combinations.
*/
/* little endian */
@@ -80033,7 +81273,7 @@ DUK_LOCAL void duk__selftest_double_aliasing(void) {
*/
DUK_LOCAL void duk__selftest_double_zero_sign(void) {
- volatile duk__test_double_union a, b;
+ duk__test_double_union a, b;
a.d = 0.0;
b.d = -a.d;
@@ -80587,7 +81827,7 @@ const duk_uint8_t duk_unicode_caseconv_lc[616] = {
141,2,101,2,2,97,0,52,129,131,128,
};
-/* FIXME: CONDITIONAL */
+#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
/*
* Automatically generated by extract_caseconv.py, do not edit!
*/
@@ -85876,6 +87116,7 @@ const duk_uint16_t duk_unicode_re_canon_lookup[65536] = {
65522,65523,65524,65525,65526,65527,65528,65529,65530,65531,65532,65533,
65534,65535,
};
+#endif
#line 1 "duk_util_bitdecoder.c"
/*
* Bitstream decoder.
@@ -86105,7 +87346,7 @@ DUK_INTERNAL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw
p_base = bw->p_base;
DUK_MEMCPY((void *) bw->p,
(const void *) (p_base + src_off),
- (duk_size_t) len);
+ (size_t) len);
bw->p += len;
}
@@ -86138,10 +87379,10 @@ DUK_INTERNAL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *b
DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
DUK_MEMMOVE((void *) (p_base + dst_off + len),
(const void *) (p_base + dst_off),
- (duk_size_t) move_sz);
+ (size_t) move_sz);
DUK_MEMCPY((void *) (p_base + dst_off),
(const void *) buf,
- (duk_size_t) len);
+ (size_t) len);
bw->p += len;
}
@@ -86186,10 +87427,10 @@ DUK_INTERNAL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *b
DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
DUK_MEMMOVE((void *) (p_base + dst_off + len),
(const void *) (p_base + dst_off),
- (duk_size_t) move_sz);
+ (size_t) move_sz);
DUK_MEMCPY((void *) (p_base + dst_off),
(const void *) (p_base + src_off),
- (duk_size_t) len);
+ (size_t) len);
bw->p += len;
}
@@ -86223,7 +87464,7 @@ DUK_INTERNAL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter
move_sz = buf_sz - off;
p_dst = p_base + off + len;
p_src = p_base + off;
- DUK_MEMMOVE((void *) p_dst, (const void *) p_src, move_sz);
+ DUK_MEMMOVE((void *) p_dst, (const void *) p_src, (size_t) move_sz);
return p_src; /* point to start of 'reserved area' */
}
@@ -86257,7 +87498,7 @@ DUK_INTERNAL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *b
move_sz = (duk_size_t) (bw->p - p_src);
DUK_MEMMOVE((void *) p_dst,
(const void *) p_src,
- move_sz);
+ (size_t) move_sz);
bw->p -= len;
}
@@ -86278,7 +87519,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p)
duk_uint16_t x;
} u;
- DUK_MEMCPY((void *) u.b, (const void *) (*p), 2);
+ DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 2);
u.x = DUK_NTOH16(u.x);
*p += 2;
return u.x;
@@ -86290,7 +87531,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p)
duk_uint32_t x;
} u;
- DUK_MEMCPY((void *) u.b, (const void *) (*p), 4);
+ DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4);
u.x = DUK_NTOH32(u.x);
*p += 4;
return u.x;
@@ -86303,10 +87544,10 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_raw_read_double_be(duk_uint8_t *
duk_uint32_t x;
} u;
- DUK_MEMCPY((void *) u.b, (const void *) (*p), 4);
+ DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4);
u.x = DUK_NTOH32(u.x);
du.ui[DUK_DBL_IDX_UI0] = u.x;
- DUK_MEMCPY((void *) u.b, (const void *) (*p + 4), 4);
+ DUK_MEMCPY((void *) u.b, (const void *) (*p + 4), (size_t) 4);
u.x = DUK_NTOH32(u.x);
du.ui[DUK_DBL_IDX_UI1] = u.x;
*p += 8;
@@ -86321,7 +87562,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u16_be(duk_uint8_t **p, duk_ui
} u;
u.x = DUK_HTON16(val);
- DUK_MEMCPY((void *) (*p), (const void *) u.b, 2);
+ DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 2);
*p += 2;
}
@@ -86332,7 +87573,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u32_be(duk_uint8_t **p, duk_ui
} u;
u.x = DUK_HTON32(val);
- DUK_MEMCPY((void *) (*p), (const void *) u.b, 4);
+ DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4);
*p += 4;
}
@@ -86346,10 +87587,10 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk
du.d = val;
u.x = du.ui[DUK_DBL_IDX_UI0];
u.x = DUK_HTON32(u.x);
- DUK_MEMCPY((void *) (*p), (const void *) u.b, 4);
+ DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4);
u.x = du.ui[DUK_DBL_IDX_UI1];
u.x = DUK_HTON32(u.x);
- DUK_MEMCPY((void *) (*p + 4), (const void *) u.b, 4);
+ DUK_MEMCPY((void *) (*p + 4), (const void *) u.b, (size_t) 4);
*p += 8;
}
#line 1 "duk_util_hashbytes.c"
@@ -86364,6 +87605,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk
/* include removed: duk_internal.h */
+#if defined(DUK_USE_STRHASH_DENSE)
/* 'magic' constants for Murmurhash2 */
#define DUK__MAGIC_M ((duk_uint32_t) 0x5bd1e995UL)
#define DUK__MAGIC_R 24
@@ -86378,7 +87620,7 @@ DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t
* OK as long as it is consistent for a build.
*/
#ifdef DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS
- duk_uint32_t k = *((duk_uint32_t *) (void *) data);
+ duk_uint32_t k = *((const duk_uint32_t *) (const void *) data);
#else
duk_uint32_t k = ((duk_uint32_t) data[0]) |
(((duk_uint32_t) data[1]) << 8) |
@@ -86408,6 +87650,7 @@ DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t
return h;
}
+#endif /* DUK_USE_STRHASH_DENSE */
#line 1 "duk_util_tinyrandom.c"
/*
* A tiny random number generator.
@@ -86472,4 +87715,3 @@ DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
return t;
}
-#endif