diff --git a/scripts/debug.js b/scripts/debug.js index 128cbe6..35e7931 100644 --- a/scripts/debug.js +++ b/scripts/debug.js @@ -1,5 +1,3 @@ -var debug = {}; - debug.build = function(fn) { fn(); } debug.fn_break = function(fn,obj = globalThis) { @@ -211,13 +209,6 @@ debug.api.print_doc = function(name) return mdoc; } -debug.kill = function() -{ - assert = function() {}; - debug.build = function() {}; - debug.fn_break = function() {}; -} - return { debug, Gizmos, diff --git a/scripts/engine.js b/scripts/engine.js index d841d8a..33b67e6 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -73,12 +73,17 @@ Resources.replstrs = function (path) { var stem = path.dir(); // remove console statements - script = Resources.rm_fn(/console\.(spam|info|warn|error)/, script); - script = Resources.rm_fn(/profile\.(cache|frame|endcache|endframe)/, script); - script = Resources.rm_fn(/assert/, script); - //script = script.replace(/console\.(.*?)\(.*?\)/g, ''); - //script = script.replace(/assert\(.*?\)/g, ''); - + if (!console.enabled) + script = Resources.rm_fn(/console\.(spam|info|warn|error)/, script); + + if (!profile.enabled) + script = Resources.rm_fn(/profile\.(cache|frame|endcache|endframe)/, script); + + if (!debug.enabled) { + script = Resources.rm_fn(/assert/, script); + script = Resources.rm_fn(/debug\.(build|fn_break)/, script); + } + script = script.replace(regexp, function (str) { var newstr = Resources.replpath(str.trimchr('"'), path); return `"${newstr}"`; @@ -255,15 +260,22 @@ function stripped_use (file, env = {}, script) { function bare_use(file) { var script = io.slurp(file); + if (!script) return; script = `(function() { var self = this; ${script}; })`; Object.assign(globalThis, os.eval(file, script).call(globalThis)); } -profile.enabled = false; +globalThis.debug = {}; + +profile.enabled = true; +console.enabled = true; +debug.enabled = true; bare_use("scripts/base.js"); bare_use("scripts/profile.js"); +bare_use("preconfig.js"); + if (!profile.enabled) use = stripped_use; diff --git a/scripts/profile.js b/scripts/profile.js index fa67687..706b754 100644 --- a/scripts/profile.js +++ b/scripts/profile.js @@ -1,4 +1,4 @@ -var t_units = ["ns", "us", "ms", "s", "m", "h"]; +var t_units = ["ns", "us", "ms", "s", "ks", "Ms"]; profile.cpu = function(fn, times = 1, q = "unnamed") { var start = profile.now(); @@ -100,6 +100,7 @@ profile.best_t = function (t) { t /= 1000; qq++; } + return `${t.toPrecision(4)} ${t_units[qq]}`; }; diff --git a/source/engine/jsffi.c b/source/engine/jsffi.c index b868451..713be1c 100644 --- a/source/engine/jsffi.c +++ b/source/engine/jsffi.c @@ -1320,7 +1320,7 @@ int iiihandle(JSRuntime *rt, void *data) JSC_CCALL(profile_gather, int count = js2number(argv[0]); instr_v = JS_DupValue(js, argv[1]); - JS_SetInterruptHandler(rt, iiihandle, NULL, count); + JS_SetInterruptHandler(rt, iiihandle, NULL); ) JSC_CCALL(profile_gather_rate, @@ -1328,7 +1328,7 @@ JSC_CCALL(profile_gather_rate, ) JSC_CCALL(profile_gather_stop, - JS_SetInterruptHandler(rt,NULL,NULL,10000); + JS_SetInterruptHandler(rt,NULL,NULL); ) static const JSCFunctionListEntry js_profile_funcs[] = { diff --git a/source/engine/thirdparty/quickjs/cutils.h b/source/engine/thirdparty/quickjs/cutils.h index 11246e3..f079e5c 100644 --- a/source/engine/thirdparty/quickjs/cutils.h +++ b/source/engine/thirdparty/quickjs/cutils.h @@ -51,6 +51,12 @@ #define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member))) #endif +#if !defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define minimum_length(n) static n +#else +#define minimum_length(n) n +#endif + typedef int BOOL; #ifndef FALSE diff --git a/source/engine/thirdparty/quickjs/libbf.c b/source/engine/thirdparty/quickjs/libbf.c index dee394a..05d62ed 100644 --- a/source/engine/thirdparty/quickjs/libbf.c +++ b/source/engine/thirdparty/quickjs/libbf.c @@ -136,6 +136,7 @@ static inline slimb_t ceil_div(slimb_t a, slimb_t b) return a / b; } +#ifdef USE_BF_DEC /* b must be >= 1 */ static inline slimb_t floor_div(slimb_t a, slimb_t b) { @@ -145,6 +146,7 @@ static inline slimb_t floor_div(slimb_t a, slimb_t b) return (a - b + 1) / b; } } +#endif /* return r = a modulo b (0 <= r <= b - 1. b must be >= 1 */ static inline limb_t smod(slimb_t a, slimb_t b) diff --git a/source/engine/thirdparty/quickjs/libregexp.c b/source/engine/thirdparty/quickjs/libregexp.c index d73a19f..a2d56a7 100644 --- a/source/engine/thirdparty/quickjs/libregexp.c +++ b/source/engine/thirdparty/quickjs/libregexp.c @@ -30,6 +30,7 @@ #include "cutils.h" #include "libregexp.h" +#include "libunicode.h" /* TODO: @@ -141,32 +142,6 @@ static const uint16_t char_range_s[] = { 0xFEFF, 0xFEFF + 1, }; -BOOL lre_is_space(int c) -{ - int i, n, low, high; - n = (countof(char_range_s) - 1) / 2; - for(i = 0; i < n; i++) { - low = char_range_s[2 * i + 1]; - if (c < low) - return FALSE; - high = char_range_s[2 * i + 2]; - if (c < high) - return TRUE; - } - return FALSE; -} - -uint32_t const lre_id_start_table_ascii[4] = { - /* $ A-Z _ a-z */ - 0x00000000, 0x00000010, 0x87FFFFFE, 0x07FFFFFE -}; - -uint32_t const lre_id_continue_table_ascii[4] = { - /* $ 0-9 A-Z _ a-z */ - 0x00000000, 0x03FF0010, 0x87FFFFFE, 0x07FFFFFE -}; - - static const uint16_t char_range_w[] = { 4, 0x0030, 0x0039 + 1, @@ -186,7 +161,7 @@ typedef enum { CHAR_RANGE_W, } CharRangeEnum; -static const uint16_t *char_range_table[] = { +static const uint16_t * const char_range_table[] = { char_range_d, char_range_s, char_range_w, @@ -1513,15 +1488,13 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) if (dbuf_error(&s->byte_code)) goto out_of_memory; - /* the spec tells that if there is no advance when - running the atom after the first quant_min times, - then there is no match. We remove this test when we - are sure the atom always advances the position. */ - add_zero_advance_check = re_need_check_advance(s->byte_code.buf + last_atom_start, - s->byte_code.size - last_atom_start); - } else { - add_zero_advance_check = FALSE; } + /* the spec tells that if there is no advance when + running the atom after the first quant_min times, + then there is no match. We remove this test when we + are sure the atom always advances the position. */ + add_zero_advance_check = re_need_check_advance(s->byte_code.buf + last_atom_start, + s->byte_code.size - last_atom_start); { int len, pos; diff --git a/source/engine/thirdparty/quickjs/libregexp.h b/source/engine/thirdparty/quickjs/libregexp.h index 757b277..7af7ece 100644 --- a/source/engine/thirdparty/quickjs/libregexp.h +++ b/source/engine/thirdparty/quickjs/libregexp.h @@ -25,10 +25,7 @@ #define LIBREGEXP_H #include - -#include "libunicode.h" - -#define LRE_BOOL int /* for documentation purposes */ +#include #define LRE_FLAG_GLOBAL (1 << 0) #define LRE_FLAG_IGNORECASE (1 << 1) @@ -50,43 +47,9 @@ int lre_exec(uint8_t **capture, int cbuf_type, void *opaque); int lre_parse_escape(const uint8_t **pp, int allow_utf16); -LRE_BOOL lre_is_space(int c); -/* must be provided by the user */ -LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size); +/* must be provided by the user, return non zero if overflow */ +int lre_check_stack_overflow(void *opaque, size_t alloca_size); void *lre_realloc(void *opaque, void *ptr, size_t size); -/* JS identifier test */ -extern uint32_t const lre_id_start_table_ascii[4]; -extern uint32_t const lre_id_continue_table_ascii[4]; - -static inline int lre_js_is_ident_first(int c) -{ - if ((uint32_t)c < 128) { - return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1; - } else { -#ifdef CONFIG_ALL_UNICODE - return lre_is_id_start(c); -#else - return !lre_is_space(c); -#endif - } -} - -static inline int lre_js_is_ident_next(int c) -{ - if ((uint32_t)c < 128) { - return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1; - } else { - /* ZWNJ and ZWJ are accepted in identifiers */ -#ifdef CONFIG_ALL_UNICODE - return lre_is_id_continue(c) || c == 0x200C || c == 0x200D; -#else - return !lre_is_space(c) || c == 0x200C || c == 0x200D; -#endif - } -} - -#undef LRE_BOOL - #endif /* LIBREGEXP_H */ diff --git a/source/engine/thirdparty/quickjs/libunicode-table.h b/source/engine/thirdparty/quickjs/libunicode-table.h index 513ed94..72d495e 100644 --- a/source/engine/thirdparty/quickjs/libunicode-table.h +++ b/source/engine/thirdparty/quickjs/libunicode-table.h @@ -189,9 +189,13 @@ static const uint8_t unicode_prop_Cased1_table[196] = { }; static const uint8_t unicode_prop_Cased1_index[21] = { - 0xb9, 0x02, 0xe0, 0xc0, 0x1d, 0x20, 0xe5, 0x2c, - 0x20, 0xb1, 0x07, 0x21, 0xc1, 0xd6, 0x21, 0x4a, - 0xf1, 0x01, 0x8a, 0xf1, 0x01, + 0xb9, 0x02, 0xe0, // 002B9 at 39 + 0xc0, 0x1d, 0x20, // 01DC0 at 65 + 0xe5, 0x2c, 0x20, // 02CE5 at 97 + 0xb1, 0x07, 0x21, // 107B1 at 129 + 0xc1, 0xd6, 0x21, // 1D6C1 at 161 + 0x4a, 0xf1, 0x01, // 1F14A at 192 + 0x8a, 0xf1, 0x01, // 1F18A at 224 (upper bound) }; static const uint8_t unicode_prop_Case_Ignorable_table[737] = { @@ -291,15 +295,29 @@ static const uint8_t unicode_prop_Case_Ignorable_table[737] = { }; static const uint8_t unicode_prop_Case_Ignorable_index[69] = { - 0xbe, 0x05, 0x00, 0xfe, 0x07, 0x00, 0x52, 0x0a, - 0xa0, 0xc1, 0x0b, 0x00, 0x82, 0x0d, 0x00, 0x3f, - 0x10, 0x80, 0xd4, 0x17, 0x40, 0xcf, 0x1a, 0x20, - 0xf5, 0x1c, 0x00, 0x80, 0x20, 0x00, 0x16, 0xa0, - 0x00, 0xc6, 0xa8, 0x00, 0xc2, 0xaa, 0x60, 0x56, - 0xfe, 0x20, 0xb1, 0x07, 0x01, 0x75, 0x10, 0x01, - 0xeb, 0x12, 0x21, 0x41, 0x16, 0x01, 0x5c, 0x1a, - 0x01, 0x43, 0x1f, 0x01, 0x2e, 0xcf, 0x41, 0x25, - 0xe0, 0x01, 0xf0, 0x01, 0x0e, + 0xbe, 0x05, 0x00, // 005BE at 32 + 0xfe, 0x07, 0x00, // 007FE at 64 + 0x52, 0x0a, 0xa0, // 00A52 at 101 + 0xc1, 0x0b, 0x00, // 00BC1 at 128 + 0x82, 0x0d, 0x00, // 00D82 at 160 + 0x3f, 0x10, 0x80, // 0103F at 196 + 0xd4, 0x17, 0x40, // 017D4 at 226 + 0xcf, 0x1a, 0x20, // 01ACF at 257 + 0xf5, 0x1c, 0x00, // 01CF5 at 288 + 0x80, 0x20, 0x00, // 02080 at 320 + 0x16, 0xa0, 0x00, // 0A016 at 352 + 0xc6, 0xa8, 0x00, // 0A8C6 at 384 + 0xc2, 0xaa, 0x60, // 0AAC2 at 419 + 0x56, 0xfe, 0x20, // 0FE56 at 449 + 0xb1, 0x07, 0x01, // 107B1 at 480 + 0x75, 0x10, 0x01, // 11075 at 512 + 0xeb, 0x12, 0x21, // 112EB at 545 + 0x41, 0x16, 0x01, // 11641 at 576 + 0x5c, 0x1a, 0x01, // 11A5C at 608 + 0x43, 0x1f, 0x01, // 11F43 at 640 + 0x2e, 0xcf, 0x41, // 1CF2E at 674 + 0x25, 0xe0, 0x01, // 1E025 at 704 + 0xf0, 0x01, 0x0e, // E01F0 at 736 (upper bound) }; static const uint8_t unicode_prop_ID_Start_table[1100] = { @@ -444,20 +462,41 @@ static const uint8_t unicode_prop_ID_Start_table[1100] = { }; static const uint8_t unicode_prop_ID_Start_index[105] = { - 0xf6, 0x03, 0x20, 0xa6, 0x07, 0x00, 0xa9, 0x09, - 0x20, 0xb1, 0x0a, 0x00, 0xba, 0x0b, 0x20, 0x3b, - 0x0d, 0x20, 0xc7, 0x0e, 0x20, 0x49, 0x12, 0x00, - 0x9b, 0x16, 0x00, 0xac, 0x19, 0x00, 0xc0, 0x1d, - 0x80, 0x80, 0x20, 0x20, 0x70, 0x2d, 0x00, 0x00, - 0x32, 0x00, 0xda, 0xa7, 0x00, 0x4c, 0xaa, 0x20, - 0xc7, 0xd7, 0x20, 0xfc, 0xfd, 0x20, 0x9d, 0x02, - 0x21, 0x96, 0x05, 0x01, 0xf3, 0x08, 0x01, 0xb3, - 0x0c, 0x21, 0x73, 0x11, 0x61, 0x34, 0x13, 0x01, - 0x1b, 0x17, 0x21, 0x8a, 0x1a, 0x01, 0x34, 0x1f, - 0x21, 0xbf, 0x6a, 0x01, 0x23, 0xb1, 0xa1, 0xad, - 0xd4, 0x01, 0x6f, 0xd7, 0x01, 0xff, 0xe7, 0x61, - 0x5e, 0xee, 0x01, 0xe1, 0xeb, 0x22, 0xb0, 0x23, - 0x03, + 0xf6, 0x03, 0x20, // 003F6 at 33 + 0xa6, 0x07, 0x00, // 007A6 at 64 + 0xa9, 0x09, 0x20, // 009A9 at 97 + 0xb1, 0x0a, 0x00, // 00AB1 at 128 + 0xba, 0x0b, 0x20, // 00BBA at 161 + 0x3b, 0x0d, 0x20, // 00D3B at 193 + 0xc7, 0x0e, 0x20, // 00EC7 at 225 + 0x49, 0x12, 0x00, // 01249 at 256 + 0x9b, 0x16, 0x00, // 0169B at 288 + 0xac, 0x19, 0x00, // 019AC at 320 + 0xc0, 0x1d, 0x80, // 01DC0 at 356 + 0x80, 0x20, 0x20, // 02080 at 385 + 0x70, 0x2d, 0x00, // 02D70 at 416 + 0x00, 0x32, 0x00, // 03200 at 448 + 0xda, 0xa7, 0x00, // 0A7DA at 480 + 0x4c, 0xaa, 0x20, // 0AA4C at 513 + 0xc7, 0xd7, 0x20, // 0D7C7 at 545 + 0xfc, 0xfd, 0x20, // 0FDFC at 577 + 0x9d, 0x02, 0x21, // 1029D at 609 + 0x96, 0x05, 0x01, // 10596 at 640 + 0xf3, 0x08, 0x01, // 108F3 at 672 + 0xb3, 0x0c, 0x21, // 10CB3 at 705 + 0x73, 0x11, 0x61, // 11173 at 739 + 0x34, 0x13, 0x01, // 11334 at 768 + 0x1b, 0x17, 0x21, // 1171B at 801 + 0x8a, 0x1a, 0x01, // 11A8A at 832 + 0x34, 0x1f, 0x21, // 11F34 at 865 + 0xbf, 0x6a, 0x01, // 16ABF at 896 + 0x23, 0xb1, 0xa1, // 1B123 at 933 + 0xad, 0xd4, 0x01, // 1D4AD at 960 + 0x6f, 0xd7, 0x01, // 1D76F at 992 + 0xff, 0xe7, 0x61, // 1E7FF at 1027 + 0x5e, 0xee, 0x01, // 1EE5E at 1056 + 0xe1, 0xeb, 0x22, // 2EBE1 at 1089 + 0xb0, 0x23, 0x03, // 323B0 at 1120 (upper bound) }; static const uint8_t unicode_prop_ID_Continue1_table[660] = { @@ -547,14 +586,27 @@ static const uint8_t unicode_prop_ID_Continue1_table[660] = { }; static const uint8_t unicode_prop_ID_Continue1_index[63] = { - 0xfa, 0x06, 0x00, 0x70, 0x09, 0x00, 0xf0, 0x0a, - 0x40, 0x57, 0x0c, 0x00, 0xf0, 0x0d, 0x60, 0xc7, - 0x0f, 0x20, 0xea, 0x17, 0x40, 0x05, 0x1b, 0x00, - 0x41, 0x20, 0x00, 0x0c, 0xa8, 0x80, 0x37, 0xaa, - 0x20, 0x50, 0xfe, 0x20, 0x3a, 0x0d, 0x21, 0x74, - 0x11, 0x01, 0x5a, 0x14, 0x21, 0x44, 0x19, 0x81, - 0x5a, 0x1d, 0xa1, 0xf5, 0x6a, 0x21, 0x45, 0xd2, - 0x41, 0xaf, 0xe2, 0x21, 0xf0, 0x01, 0x0e, + 0xfa, 0x06, 0x00, // 006FA at 32 + 0x70, 0x09, 0x00, // 00970 at 64 + 0xf0, 0x0a, 0x40, // 00AF0 at 98 + 0x57, 0x0c, 0x00, // 00C57 at 128 + 0xf0, 0x0d, 0x60, // 00DF0 at 163 + 0xc7, 0x0f, 0x20, // 00FC7 at 193 + 0xea, 0x17, 0x40, // 017EA at 226 + 0x05, 0x1b, 0x00, // 01B05 at 256 + 0x41, 0x20, 0x00, // 02041 at 288 + 0x0c, 0xa8, 0x80, // 0A80C at 324 + 0x37, 0xaa, 0x20, // 0AA37 at 353 + 0x50, 0xfe, 0x20, // 0FE50 at 385 + 0x3a, 0x0d, 0x21, // 10D3A at 417 + 0x74, 0x11, 0x01, // 11174 at 448 + 0x5a, 0x14, 0x21, // 1145A at 481 + 0x44, 0x19, 0x81, // 11944 at 516 + 0x5a, 0x1d, 0xa1, // 11D5A at 549 + 0xf5, 0x6a, 0x21, // 16AF5 at 577 + 0x45, 0xd2, 0x41, // 1D245 at 610 + 0xaf, 0xe2, 0x21, // 1E2AF at 641 + 0xf0, 0x01, 0x0e, // E01F0 at 672 (upper bound) }; #ifdef CONFIG_ALL_UNICODE @@ -676,17 +728,35 @@ static const uint8_t unicode_cc_table[899] = { }; static const uint8_t unicode_cc_index[87] = { - 0x4d, 0x03, 0x00, 0x97, 0x05, 0x20, 0xc6, 0x05, - 0x00, 0xe7, 0x06, 0x00, 0x45, 0x07, 0x00, 0x9c, - 0x08, 0x00, 0x4d, 0x09, 0x00, 0x3c, 0x0b, 0x00, - 0x3d, 0x0d, 0x00, 0x36, 0x0f, 0x00, 0x38, 0x10, - 0x20, 0x3a, 0x19, 0x00, 0xcb, 0x1a, 0x20, 0xd3, - 0x1c, 0x00, 0xcf, 0x1d, 0x00, 0xe2, 0x20, 0x00, - 0x2e, 0x30, 0x20, 0x2b, 0xa9, 0x20, 0xed, 0xab, - 0x00, 0x39, 0x0a, 0x01, 0x51, 0x0f, 0x01, 0x73, - 0x11, 0x01, 0x75, 0x13, 0x01, 0x2b, 0x17, 0x21, - 0x3f, 0x1c, 0x21, 0x9e, 0xbc, 0x21, 0x08, 0xe0, - 0x01, 0x44, 0xe9, 0x01, 0x4b, 0xe9, 0x01, + 0x4d, 0x03, 0x00, // 0034D at 32 + 0x97, 0x05, 0x20, // 00597 at 65 + 0xc6, 0x05, 0x00, // 005C6 at 96 + 0xe7, 0x06, 0x00, // 006E7 at 128 + 0x45, 0x07, 0x00, // 00745 at 160 + 0x9c, 0x08, 0x00, // 0089C at 192 + 0x4d, 0x09, 0x00, // 0094D at 224 + 0x3c, 0x0b, 0x00, // 00B3C at 256 + 0x3d, 0x0d, 0x00, // 00D3D at 288 + 0x36, 0x0f, 0x00, // 00F36 at 320 + 0x38, 0x10, 0x20, // 01038 at 353 + 0x3a, 0x19, 0x00, // 0193A at 384 + 0xcb, 0x1a, 0x20, // 01ACB at 417 + 0xd3, 0x1c, 0x00, // 01CD3 at 448 + 0xcf, 0x1d, 0x00, // 01DCF at 480 + 0xe2, 0x20, 0x00, // 020E2 at 512 + 0x2e, 0x30, 0x20, // 0302E at 545 + 0x2b, 0xa9, 0x20, // 0A92B at 577 + 0xed, 0xab, 0x00, // 0ABED at 608 + 0x39, 0x0a, 0x01, // 10A39 at 640 + 0x51, 0x0f, 0x01, // 10F51 at 672 + 0x73, 0x11, 0x01, // 11173 at 704 + 0x75, 0x13, 0x01, // 11375 at 736 + 0x2b, 0x17, 0x21, // 1172B at 769 + 0x3f, 0x1c, 0x21, // 11C3F at 801 + 0x9e, 0xbc, 0x21, // 1BC9E at 833 + 0x08, 0xe0, 0x01, // 1E008 at 864 + 0x44, 0xe9, 0x01, // 1E944 at 896 + 0x4b, 0xe9, 0x01, // 1E94B at 928 (upper bound) }; static const uint32_t unicode_decomp_table1[699] = { @@ -4484,3 +4554,4 @@ static const uint16_t unicode_prop_len_table[] = { }; #endif /* CONFIG_ALL_UNICODE */ +/* 62 tables / 32261 bytes, 5 index / 345 bytes */ diff --git a/source/engine/thirdparty/quickjs/libunicode.c b/source/engine/thirdparty/quickjs/libunicode.c index 4200252..c80d2f3 100644 --- a/source/engine/thirdparty/quickjs/libunicode.c +++ b/source/engine/thirdparty/quickjs/libunicode.c @@ -262,11 +262,7 @@ int lre_canonicalize(uint32_t c, BOOL is_unicode) static uint32_t get_le24(const uint8_t *ptr) { -#if defined(__x86__) || defined(__x86_64__) - return *(uint16_t *)ptr | (ptr[2] << 16); -#else return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16); -#endif } #define UNICODE_INDEX_BLOCK_LEN 32 @@ -317,6 +313,14 @@ static BOOL lre_is_in_table(uint32_t c, const uint8_t *table, return FALSE; /* outside the table */ p = table + pos; bit = 0; + /* Compressed run length encoding: + 00..3F: 2 packed lengths: 3-bit + 3-bit + 40..5F: 5-bits plus extra byte for length + 60..7F: 5-bits plus 2 extra bytes for length + 80..FF: 7-bit length + lengths must be incremented to get character count + Ranges alternate between false and true return value. + */ for(;;) { b = *p++; if (b < 64) { @@ -833,6 +837,13 @@ static int unicode_get_cc(uint32_t c) if (pos < 0) return 0; p = unicode_cc_table + pos; + /* Compressed run length encoding: + - 2 high order bits are combining class type + - 0:0, 1:230, 2:extra byte linear progression, 3:extra byte + - 00..2F: range length (add 1) + - 30..37: 3-bit range-length + 1 extra byte + - 38..3F: 3-bit range-length + 2 extra byte + */ for(;;) { b = *p++; type = b >> 6; @@ -1185,6 +1196,15 @@ static int unicode_general_category1(CharRange *cr, uint32_t gc_mask) p = unicode_gc_table; p_end = unicode_gc_table + countof(unicode_gc_table); c = 0; + /* Compressed range encoding: + initial byte: + bits 0..4: category number (special case 31) + bits 5..7: range length (add 1) + special case bits 5..7 == 7: read an extra byte + - 00..7F: range length (add 7 + 1) + - 80..BF: 6-bits plus extra byte for range length (add 7 + 128) + - C0..FF: 6-bits plus 2 extra bytes for range length (add 7 + 128 + 16384) + */ while (p < p_end) { b = *p++; n = b >> 5; @@ -1238,6 +1258,14 @@ static int unicode_prop1(CharRange *cr, int prop_idx) p_end = p + unicode_prop_len_table[prop_idx]; c = 0; bit = 0; + /* Compressed range encoding: + 00..3F: 2 packed lengths: 3-bit + 3-bit + 40..5F: 5-bits plus extra byte for length + 60..7F: 5-bits plus 2 extra bytes for length + 80..FF: 7-bit length + lengths must be incremented to get character count + Ranges alternate between false and true return value. + */ while (p < p_end) { c0 = c; b = *p++; @@ -1786,3 +1814,97 @@ int unicode_prop(CharRange *cr, const char *prop_name) } #endif /* CONFIG_ALL_UNICODE */ + +/*---- lre codepoint categorizing functions ----*/ + +#define S UNICODE_C_SPACE +#define D UNICODE_C_DIGIT +#define X UNICODE_C_XDIGIT +#define U UNICODE_C_UPPER +#define L UNICODE_C_LOWER +#define _ UNICODE_C_UNDER +#define d UNICODE_C_DOLLAR + +uint8_t const lre_ctype_bits[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, S, S, S, S, S, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + + S, 0, 0, 0, d, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + X|D, X|D, X|D, X|D, X|D, X|D, X|D, X|D, + X|D, X|D, 0, 0, 0, 0, 0, 0, + + 0, X|U, X|U, X|U, X|U, X|U, X|U, U, + U, U, U, U, U, U, U, U, + U, U, U, U, U, U, U, U, + U, U, U, 0, 0, 0, 0, _, + + 0, X|L, X|L, X|L, X|L, X|L, X|L, L, + L, L, L, L, L, L, L, L, + L, L, L, L, L, L, L, L, + L, L, L, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + + S, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +#undef S +#undef D +#undef X +#undef U +#undef L +#undef _ +#undef d + +/* code point ranges for Zs,Zl or Zp property */ +static const uint16_t char_range_s[] = { + 10, + 0x0009, 0x000D + 1, + 0x0020, 0x0020 + 1, + 0x00A0, 0x00A0 + 1, + 0x1680, 0x1680 + 1, + 0x2000, 0x200A + 1, + /* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */ + /* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */ + 0x2028, 0x2029 + 1, + 0x202F, 0x202F + 1, + 0x205F, 0x205F + 1, + 0x3000, 0x3000 + 1, + /* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */ + 0xFEFF, 0xFEFF + 1, +}; + +BOOL lre_is_space_non_ascii(uint32_t c) +{ + size_t i, n; + + n = countof(char_range_s); + for(i = 5; i < n; i += 2) { + uint32_t low = char_range_s[i]; + uint32_t high = char_range_s[i + 1]; + if (c < low) + return FALSE; + if (c < high) + return TRUE; + } + return FALSE; +} diff --git a/source/engine/thirdparty/quickjs/libunicode.h b/source/engine/thirdparty/quickjs/libunicode.h index f416157..cc2f244 100644 --- a/source/engine/thirdparty/quickjs/libunicode.h +++ b/source/engine/thirdparty/quickjs/libunicode.h @@ -24,27 +24,13 @@ #ifndef LIBUNICODE_H #define LIBUNICODE_H -#include - -#define LRE_BOOL int /* for documentation purposes */ +#include /* define it to include all the unicode tables (40KB larger) */ #define CONFIG_ALL_UNICODE #define LRE_CC_RES_LEN_MAX 3 -typedef enum { - UNICODE_NFC, - UNICODE_NFD, - UNICODE_NFKC, - UNICODE_NFKD, -} UnicodeNormalizationEnum; - -int lre_case_conv(uint32_t *res, uint32_t c, int conv_type); -int lre_canonicalize(uint32_t c, LRE_BOOL is_unicode); -LRE_BOOL lre_is_cased(uint32_t c); -LRE_BOOL lre_is_case_ignorable(uint32_t c); - /* char ranges */ typedef struct { @@ -102,12 +88,14 @@ int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len, int cr_invert(CharRange *cr); -int cr_regexp_canonicalize(CharRange *cr, LRE_BOOL is_unicode); +int cr_regexp_canonicalize(CharRange *cr, int is_unicode); -#ifdef CONFIG_ALL_UNICODE - -LRE_BOOL lre_is_id_start(uint32_t c); -LRE_BOOL lre_is_id_continue(uint32_t c); +typedef enum { + UNICODE_NFC, + UNICODE_NFD, + UNICODE_NFKC, + UNICODE_NFKD, +} UnicodeNormalizationEnum; int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, UnicodeNormalizationEnum n_type, @@ -115,13 +103,80 @@ int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, /* Unicode character range functions */ -int unicode_script(CharRange *cr, - const char *script_name, LRE_BOOL is_ext); +int unicode_script(CharRange *cr, const char *script_name, int is_ext); int unicode_general_category(CharRange *cr, const char *gc_name); int unicode_prop(CharRange *cr, const char *prop_name); -#endif /* CONFIG_ALL_UNICODE */ +int lre_case_conv(uint32_t *res, uint32_t c, int conv_type); +int lre_canonicalize(uint32_t c, int is_unicode); -#undef LRE_BOOL +/* Code point type categories */ +enum { + UNICODE_C_SPACE = (1 << 0), + UNICODE_C_DIGIT = (1 << 1), + UNICODE_C_UPPER = (1 << 2), + UNICODE_C_LOWER = (1 << 3), + UNICODE_C_UNDER = (1 << 4), + UNICODE_C_DOLLAR = (1 << 5), + UNICODE_C_XDIGIT = (1 << 6), +}; +extern uint8_t const lre_ctype_bits[256]; + +/* zero or non-zero return value */ +int lre_is_cased(uint32_t c); +int lre_is_case_ignorable(uint32_t c); +int lre_is_id_start(uint32_t c); +int lre_is_id_continue(uint32_t c); + +static inline int lre_is_space_byte(uint8_t c) { + return lre_ctype_bits[c] & UNICODE_C_SPACE; +} + +static inline int lre_is_id_start_byte(uint8_t c) { + return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER | + UNICODE_C_UNDER | UNICODE_C_DOLLAR); +} + +static inline int lre_is_id_continue_byte(uint8_t c) { + return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER | + UNICODE_C_UNDER | UNICODE_C_DOLLAR | + UNICODE_C_DIGIT); +} + +int lre_is_space_non_ascii(uint32_t c); + +static inline int lre_is_space(uint32_t c) { + if (c < 256) + return lre_is_space_byte(c); + else + return lre_is_space_non_ascii(c); +} + +static inline int lre_js_is_ident_first(uint32_t c) { + if (c < 128) { + return lre_is_id_start_byte(c); + } else { +#ifdef CONFIG_ALL_UNICODE + return lre_is_id_start(c); +#else + return !lre_is_space_non_ascii(c); +#endif + } +} + +static inline int lre_js_is_ident_next(uint32_t c) { + if (c < 128) { + return lre_is_id_continue_byte(c); + } else { + /* ZWNJ and ZWJ are accepted in identifiers */ + if (c >= 0x200C && c <= 0x200D) + return TRUE; +#ifdef CONFIG_ALL_UNICODE + return lre_is_id_continue(c); +#else + return !lre_is_space_non_ascii(c); +#endif + } +} #endif /* LIBUNICODE_H */ diff --git a/source/engine/thirdparty/quickjs/quickjs.c b/source/engine/thirdparty/quickjs/quickjs.c index ce2544d..abf9eb5 100644 --- a/source/engine/thirdparty/quickjs/quickjs.c +++ b/source/engine/thirdparty/quickjs/quickjs.c @@ -34,7 +34,7 @@ #include #if defined(__APPLE__) #include -#elif defined(__linux__) +#elif defined(__linux__) || defined(__GLIBC__) #include #elif defined(__FreeBSD__) #include @@ -44,6 +44,7 @@ #include "list.h" #include "quickjs.h" #include "libregexp.h" +#include "libunicode.h" #include "libbf.h" #define OPTIMIZE 1 @@ -111,22 +112,6 @@ void quickjs_set_dumpout(FILE *f) //#define DUMP_PROMISE //#define DUMP_READ_OBJECT -#ifdef DUMP -//#define DUMP_FREE -#define DUMP_MEM -//#define DUMP_CLOSURE -#define DUMP_GC -//#define DUMP_GC_FREE -#define DUMP_LEAKS 1 -//#define DUMP_OBJECTS -#define DUMP_CLOSURE -//#define DUMP_OBJECTS -//#define DUMP_ATOMS -//#define DUMP_SHAPES -//#define DUMP_MODULE_RESOLVE -//#define DUMP_PROMISE -#endif - /* test the GC by forcing it before each object allocation */ //#define FORCE_GC_AT_MALLOC @@ -429,7 +414,7 @@ typedef enum { /* must be large enough to have a negligible runtime cost and small enough to call the interrupt callback often. */ -static int JS_INTERRUPT_COUNTER_INIT = 1000; +static int JS_INTERRUPT_COUNTER_INIT = 10000; struct JSContext { JSGCObjectHeader header; /* must come first */ @@ -990,6 +975,7 @@ struct JSObject { } u; /* byte sizes: 40/48/72 */ }; + enum { __JS_ATOM_NULL = JS_ATOM_NULL, #define DEF(name, str) JS_ATOM_ ## name, @@ -1125,6 +1111,12 @@ static void js_operator_set_finalizer(JSRuntime *rt, JSValue val); static void js_operator_set_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); #endif + +#define HINT_STRING 0 +#define HINT_NUMBER 1 +#define HINT_NONE 2 +#define HINT_FORCE_ORDINARY (1 << 4) // don't try Symbol.toPrimitive +static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint); static JSValue JS_ToStringFree(JSContext *ctx, JSValue val); static int JS_ToBoolFree(JSContext *ctx, JSValue val); static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val); @@ -1146,7 +1138,7 @@ typedef enum JSStrictEqModeEnum { static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, JSStrictEqModeEnum eq_mode); -static BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2); +static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2); static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2); static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2); static JSValue JS_ToObject(JSContext *ctx, JSValueConst val); @@ -1189,9 +1181,10 @@ static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx); static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj); static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj, JSValueConst proto_val, BOOL throw_flag); + +static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, int throw_exception); static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj); static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj); -static int js_proxy_isArray(JSContext *ctx, JSValueConst obj); static int JS_CreateProperty(JSContext *ctx, JSObject *p, JSAtom prop, JSValueConst val, JSValueConst getter, JSValueConst setter, @@ -1290,7 +1283,6 @@ static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); -void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag); static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int is_map); @@ -1311,8 +1303,8 @@ static void js_trigger_gc(JSRuntime *rt, size_t size) #endif if (force_gc) { #ifdef DUMP_GC - fprintf(dumpout, "GC: size=%" PRIu64 "\n", - (uint64_t)rt->malloc_state.malloc_size); + fprintf(dumpout, dumpout, "GC: size=%" PRIu64 "\n", + (uint64_t)rt->malloc_state.malloc_size); #endif JS_RunGC(rt); rt->malloc_gc_threshold = rt->malloc_state.malloc_size + @@ -1695,7 +1687,7 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) rt->stack_size = JS_DEFAULT_STACK_SIZE; JS_UpdateStackTop(rt); - rt->current_exception = JS_NULL; + rt->current_exception = JS_UNINITIALIZED; return rt; fail: @@ -1722,7 +1714,7 @@ static size_t js_def_malloc_usable_size(const void *ptr) return _msize((void *)ptr); #elif defined(EMSCRIPTEN) return 0; -#elif defined(__linux__) +#elif defined(__linux__) || defined(__GLIBC__) return malloc_usable_size((void *)ptr); #else /* change this to `return 0;` if compilation fails */ @@ -1818,11 +1810,10 @@ void JS_SetInterruptRate(int count) JS_INTERRUPT_COUNTER_INIT = count; } -void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque, int count) +void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque) { rt->interrupt_handler = cb; rt->interrupt_opaque = opaque; - JS_INTERRUPT_COUNTER_INIT = count; } void JS_SetCanBlock(JSRuntime *rt, BOOL can_block) @@ -1996,7 +1987,7 @@ void JS_FreeRuntime(JSRuntime *rt) p = list_entry(el, JSGCObjectHeader, link); if (p->ref_count != 0) { if (!header_done) { - fprintf(dumpout, "Object leaks:\n"); + fprintf(dumpout, dumpout, "Object leaks:\n"); JS_DumpObjectHeader(rt); header_done = TRUE; } @@ -2516,13 +2507,13 @@ static uint32_t hash_string(const JSString *str, uint32_t h) static __maybe_unused void JS_DumpChar(JSRuntime *rt, int c, int sep) { if (c == sep || c == '\\') { - putc('\\', dumpout); - putc(c, dumpout); + putchar('\\'); + putchar(c); } else if (c >= ' ' && c <= 126) { - putc(c, dumpout); + putchar(c); } else if (c == '\n') { - putc('\\', dumpout); - putc('n', dumpout); + putchar('\\'); + putchar('n'); } else { fprintf(dumpout, "\\u%04x", c); } @@ -2538,11 +2529,11 @@ static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p) } fprintf(dumpout, "%d", p->header.ref_count); sep = (p->header.ref_count == 1) ? '\"' : '\''; - putc(sep, dumpout); + putchar(sep); for(i = 0; i < p->len; i++) { JS_DumpChar(rt, string_get(p, i), sep); } - putc(sep, dumpout); + putchar(sep); } static __maybe_unused void JS_DumpAtoms(JSRuntime *rt) @@ -3316,23 +3307,23 @@ static __maybe_unused void print_atom(JSContext *ctx, JSAtom atom) if (i > 0 && p[i] == '\0') { fprintf(dumpout, "%s", p); } else { - putc('"', dumpout); + putchar('"'); fprintf(dumpout, "%.*s", i, p); for (; p[i]; i++) { int c = (unsigned char)p[i]; if (c == '\"' || c == '\\') { - putc('\\', dumpout); - putc(c, dumpout); + putchar('\\'); + putchar(c); } else if (c >= ' ' && c <= 126) { - putc(c, dumpout); + putchar(c); } else if (c == '\n') { - putc('\\', dumpout); - putc('n', dumpout); + putchar('\\'); + putchar('n'); } else { fprintf(dumpout, "\\u%04x", c); } } - putc('\"', dumpout); + putchar('\"'); } } @@ -6271,7 +6262,7 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt) { - fprintf(fp, "QuickJS memory usage -- " + fprintf(dumpout, fp, "QuickJS memory usage -- " #ifdef CONFIG_BIGNUM "BigNum " #endif @@ -6297,14 +6288,14 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt) unsigned int size1 = js_malloc_usable_size_rt(rt, p); if (size1 >= size) { usage_size_ok = 1; - fprintf(fp, " %3u + %-2u %s\n", + fprintf(dumpout, fp, " %3u + %-2u %s\n", size, size1 - size, object_types[i].name); } js_free_rt(rt, p); } } if (!usage_size_ok) { - fprintf(fp, " malloc_usable_size unavailable\n"); + fprintf(dumpout, fp, " malloc_usable_size unavailable\n"); } { int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 }; @@ -6318,82 +6309,82 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt) obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++; } } - fprintf(fp, "\n" "JSObject classes\n"); + fprintf(dumpout, fp, "\n" "JSObject classes\n"); if (obj_classes[0]) - fprintf(fp, " %5d %2.0d %s\n", obj_classes[0], 0, "none"); + fprintf(dumpout, fp, " %5d %2.0d %s\n", obj_classes[0], 0, "none"); for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) { if (obj_classes[class_id] && class_id < rt->class_count) { char buf[ATOM_GET_STR_BUF_SIZE]; - fprintf(fp, " %5d %2.0d %s\n", obj_classes[class_id], class_id, + fprintf(dumpout, fp, " %5d %2.0d %s\n", obj_classes[class_id], class_id, JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name)); } } if (obj_classes[JS_CLASS_INIT_COUNT]) - fprintf(fp, " %5d %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other"); + fprintf(dumpout, fp, " %5d %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other"); } - fprintf(fp, "\n"); + fprintf(dumpout, fp, "\n"); } #endif - fprintf(fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE"); + fprintf(dumpout, fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE"); if (s->malloc_count) { - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per block)\n", + fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per block)\n", "memory allocated", s->malloc_count, s->malloc_size, (double)s->malloc_size / s->malloc_count); - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%d overhead, %0.1f average slack)\n", + fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%d overhead, %0.1f average slack)\n", "memory used", s->memory_used_count, s->memory_used_size, MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) / s->memory_used_count)); } if (s->atom_count) { - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per atom)\n", + fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per atom)\n", "atoms", s->atom_count, s->atom_size, (double)s->atom_size / s->atom_count); } if (s->str_count) { - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per string)\n", + fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per string)\n", "strings", s->str_count, s->str_size, (double)s->str_size / s->str_count); } if (s->obj_count) { - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n", + fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n", "objects", s->obj_count, s->obj_size, (double)s->obj_size / s->obj_count); - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n", + fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n", " properties", s->prop_count, s->prop_size, (double)s->prop_count / s->obj_count); - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per shape)\n", + fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per shape)\n", " shapes", s->shape_count, s->shape_size, (double)s->shape_size / s->shape_count); } if (s->js_func_count) { - fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n", + fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64"\n", "bytecode functions", s->js_func_count, s->js_func_size); - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n", + fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n", " bytecode", s->js_func_count, s->js_func_code_size, (double)s->js_func_code_size / s->js_func_count); if (s->js_func_pc2line_count) { - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n", + fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n", " pc2line", s->js_func_pc2line_count, s->js_func_pc2line_size, (double)s->js_func_pc2line_size / s->js_func_pc2line_count); } } if (s->c_func_count) { - fprintf(fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count); + fprintf(dumpout, fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count); } if (s->array_count) { - fprintf(fp, "%-20s %8"PRId64"\n", "arrays", s->array_count); + fprintf(dumpout, fp, "%-20s %8"PRId64"\n", "arrays", s->array_count); if (s->fast_array_count) { - fprintf(fp, "%-20s %8"PRId64"\n", " fast arrays", s->fast_array_count); - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per fast array)\n", + fprintf(dumpout, fp, "%-20s %8"PRId64"\n", " fast arrays", s->fast_array_count); + fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per fast array)\n", " elements", s->fast_array_elements, s->fast_array_elements * (int)sizeof(JSValue), (double)s->fast_array_elements / s->fast_array_count); } } if (s->binary_object_count) { - fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n", + fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64"\n", "binary objects", s->binary_object_count, s->binary_object_size); } } @@ -6418,10 +6409,15 @@ JSValue JS_GetException(JSContext *ctx) JSValue val; JSRuntime *rt = ctx->rt; val = rt->current_exception; - rt->current_exception = JS_NULL; + rt->current_exception = JS_UNINITIALIZED; return val; } +JS_BOOL JS_HasException(JSContext *ctx) +{ + return !JS_IsUninitialized(ctx->rt->current_exception); +} + static void dbuf_put_leb128(DynBuf *s, uint32_t v) { uint32_t a; @@ -9876,12 +9872,6 @@ void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id) return p; } -#define HINT_STRING 0 -#define HINT_NUMBER 1 -#define HINT_NONE 2 -/* don't try Symbol.toPrimitive */ -#define HINT_FORCE_ORDINARY (1 << 4) - static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint) { int i; @@ -12131,15 +12121,14 @@ static __maybe_unused void JS_PrintValue(JSContext *ctx, } /* return -1 if exception (proxy case) or TRUE/FALSE */ +// TODO: should take flags to make proxy resolution and exceptions optional int JS_IsArray(JSContext *ctx, JSValueConst val) { - JSObject *p; + if (js_resolve_proxy(ctx, &val, TRUE)) + return -1; if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) { - p = JS_VALUE_GET_OBJ(val); - if (unlikely(p->class_id == JS_CLASS_PROXY)) - return js_proxy_isArray(ctx, val); - else - return p->class_id == JS_CLASS_ARRAY; + JSObject *p = JS_VALUE_GET_OBJ(val); + return p->class_id == JS_CLASS_ARRAY; } else { return FALSE; } @@ -14261,7 +14250,7 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, goto exception; } } - res = js_strict_eq(ctx, op1, op2); + res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT); } else if (tag1 == JS_TAG_BOOL) { op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1)); goto redo; @@ -14579,9 +14568,16 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, return res; } -static BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2) +static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2) { - return js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT); + return js_strict_eq2(ctx, + JS_DupValue(ctx, op1), JS_DupValue(ctx, op2), + JS_EQ_STRICT); +} + +BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2) +{ + return js_strict_eq(ctx, op1, op2); } static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2) @@ -14591,6 +14587,11 @@ static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2) JS_EQ_SAME_VALUE); } +BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2) +{ + return js_same_value(ctx, op1, op2); +} + static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2) { return js_strict_eq2(ctx, @@ -14598,11 +14599,16 @@ static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op JS_EQ_SAME_VALUE_ZERO); } +BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2) +{ + return js_same_value_zero(ctx, op1, op2); +} + static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp, BOOL is_neq) { BOOL res; - res = js_strict_eq(ctx, sp[-2], sp[-1]); + res = js_strict_eq2(ctx, sp[-2], sp[-1], JS_EQ_STRICT); sp[-2] = JS_NewBool(ctx, res ^ is_neq); return 0; } @@ -15326,7 +15332,7 @@ static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj, if (is_exception_pending) { ex_obj = ctx->rt->current_exception; - ctx->rt->current_exception = JS_NULL; + ctx->rt->current_exception = JS_UNINITIALIZED; res = -1; } else { ex_obj = JS_UNDEFINED; @@ -18679,7 +18685,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JS_IteratorClose(ctx, sp[-1], TRUE); } else { *sp++ = rt->current_exception; - rt->current_exception = JS_NULL; + rt->current_exception = JS_UNINITIALIZED; pc = b->byte_code_buf + pos; goto restart; } @@ -21215,8 +21221,7 @@ static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c) for(;;) { buf[ident_pos++] = c; c = *p; - if (c >= 128 || - !((lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1)) + if (c >= 128 || !lre_is_id_continue_byte(c)) break; p++; if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) { @@ -21428,9 +21433,29 @@ static __exception int json_next_token(JSParseState *s) return -1; } -/* only used for ':' and '=>', 'let' or 'function' look-ahead. *pp is - only set if TOK_IMPORT is returned */ -/* XXX: handle all unicode cases */ +static int match_identifier(const uint8_t *p, const char *s) { + uint32_t c; + while (*s) { + if ((uint8_t)*s++ != *p++) + return 0; + } + c = *p; + if (c >= 128) + c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); + return !lre_js_is_ident_next(c); +} + +/* simple_next_token() is used to check for the next token in simple cases. + It is only used for ':' and '=>', 'let' or 'function' look-ahead. + (*pp) is only set if TOK_IMPORT is returned for JS_DetectModule() + Whitespace and comments are skipped correctly. + Then the next token is analyzed, only for specific words. + Return values: + - '\n' if !no_line_terminator + - TOK_ARROW, TOK_IN, TOK_IMPORT, TOK_OF, TOK_EXPORT, TOK_FUNCTION + - TOK_IDENT is returned for other identifiers and keywords + - otherwise the next character or unicode codepoint is returned. + */ static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator) { const uint8_t *p; @@ -21474,33 +21499,42 @@ static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator) if (*p == '>') return TOK_ARROW; break; - default: - if (lre_js_is_ident_first(c)) { - if (c == 'i') { - if (p[0] == 'n' && !lre_js_is_ident_next(p[1])) { - return TOK_IN; - } - if (p[0] == 'm' && p[1] == 'p' && p[2] == 'o' && - p[3] == 'r' && p[4] == 't' && - !lre_js_is_ident_next(p[5])) { - *pp = p + 5; - return TOK_IMPORT; - } - } else if (c == 'o' && *p == 'f' && !lre_js_is_ident_next(p[1])) { - return TOK_OF; - } else if (c == 'e' && - p[0] == 'x' && p[1] == 'p' && p[2] == 'o' && - p[3] == 'r' && p[4] == 't' && - !lre_js_is_ident_next(p[5])) { - *pp = p + 5; - return TOK_EXPORT; - } else if (c == 'f' && p[0] == 'u' && p[1] == 'n' && - p[2] == 'c' && p[3] == 't' && p[4] == 'i' && - p[5] == 'o' && p[6] == 'n' && !lre_js_is_ident_next(p[7])) { - return TOK_FUNCTION; - } - return TOK_IDENT; + case 'i': + if (match_identifier(p, "n")) + return TOK_IN; + if (match_identifier(p, "mport")) { + *pp = p + 5; + return TOK_IMPORT; } + return TOK_IDENT; + case 'o': + if (match_identifier(p, "f")) + return TOK_OF; + return TOK_IDENT; + case 'e': + if (match_identifier(p, "xport")) + return TOK_EXPORT; + return TOK_IDENT; + case 'f': + if (match_identifier(p, "unction")) + return TOK_FUNCTION; + return TOK_IDENT; + case '\\': + if (*p == 'u') { + if (lre_js_is_ident_first(lre_parse_escape(&p, TRUE))) + return TOK_IDENT; + } + break; + default: + if (c >= 128) { + c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p); + if (no_line_terminator && (c == CP_PS || c == CP_LS)) + return '\n'; + } + if (lre_is_space(c)) + continue; + if (lre_js_is_ident_first(c)) + return TOK_IDENT; break; } return c; @@ -22378,7 +22412,8 @@ static int __exception js_parse_property_name(JSParseState *s, if (next_token(s)) goto fail1; if (s->token.val == ':' || s->token.val == ',' || - s->token.val == '}' || s->token.val == '(') { + s->token.val == '}' || s->token.val == '(' || + s->token.val == '=') { is_non_reserved_ident = TRUE; goto ident_found; } @@ -22394,7 +22429,8 @@ static int __exception js_parse_property_name(JSParseState *s, if (next_token(s)) goto fail1; if (s->token.val == ':' || s->token.val == ',' || - s->token.val == '}' || s->token.val == '(') { + s->token.val == '}' || s->token.val == '(' || + s->token.val == '=') { is_non_reserved_ident = TRUE; goto ident_found; } @@ -23078,7 +23114,12 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, goto fail; continue; } - is_static = (s->token.val == TOK_STATIC); + is_static = FALSE; + if (s->token.val == TOK_STATIC) { + int next = peek_token(s, TRUE); + if (!(next == ';' || next == '}' || next == '(' || next == '=')) + is_static = TRUE; + } prop_type = -1; if (is_static) { if (next_token(s)) @@ -26238,7 +26279,6 @@ static int is_let(JSParseState *s, int decl_mask) int res = FALSE; if (token_is_pseudo_keyword(s, JS_ATOM_let)) { -#if 1 JSParsePos pos; js_parse_get_pos(s, &pos); for (;;) { @@ -26271,12 +26311,6 @@ static int is_let(JSParseState *s, int decl_mask) if (js_parse_seek_token(s, &pos)) { res = -1; } -#else - int tok = peek_token(s, TRUE); - if (tok == '{' || tok == TOK_IDENT || peek_token(s, FALSE) == '[') { - res = TRUE; - } -#endif } return res; } @@ -33973,6 +34007,8 @@ static __exception int js_parse_function_decl2(JSParseState *s, goto fail; } if (fd->has_parameter_expressions) { + if (js_parse_check_duplicate_parameter(s, name)) + goto fail; if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0) goto fail; } @@ -35656,7 +35692,7 @@ static void __attribute__((format(printf, 2, 3))) bc_read_trace(BCReaderState *s fprintf(dumpout, "%*s", 32 + s->level * 2 - n, ""); } va_start(ap, fmt); - vf(stdout, fmt, ap); + vfprintf(dumpout, stdout, fmt, ap); va_end(ap); if (strchr(fmt, '{')) s->level++; @@ -35923,11 +35959,10 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag) uint8_t v8; int32_t e; uint32_t len; - limb_t l, i, n, j; + limb_t l, i, n; JSBigFloat *p; limb_t v; bf_t *a; - int bpos, d; p = js_new_bf(s->ctx); if (!p) @@ -35977,39 +36012,23 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag) JS_ThrowInternalError(s->ctx, "invalid bignum length"); goto fail; } - if (tag != BC_TAG_BIG_DECIMAL) - l = (len + sizeof(limb_t) - 1) / sizeof(limb_t); - else +#ifdef CONFIG_BIGNUM + if (tag == BC_TAG_BIG_DECIMAL) { l = (len + LIMB_DIGITS - 1) / LIMB_DIGITS; + } else +#endif + { + l = (len + sizeof(limb_t) - 1) / sizeof(limb_t); + } if (bf_resize(a, l)) { JS_ThrowOutOfMemory(s->ctx); goto fail; } - if (tag != BC_TAG_BIG_DECIMAL) { - n = len & (sizeof(limb_t) - 1); - if (n != 0) { - v = 0; - for(i = 0; i < n; i++) { - if (bc_get_u8(s, &v8)) - goto fail; - v |= (limb_t)v8 << ((sizeof(limb_t) - n + i) * 8); - } - a->tab[0] = v; - i = 1; - } else { - i = 0; - } - for(; i < l; i++) { -#if LIMB_BITS == 32 - if (bc_get_u32(s, &v)) - goto fail; -#else - if (bc_get_u64(s, &v)) - goto fail; -#endif - a->tab[i] = v; - } - } else { +#ifdef CONFIG_BIGNUM + if (tag == BC_TAG_BIG_DECIMAL) { + limb_t j; + int bpos, d; + bpos = 0; for(i = 0; i < l; i++) { if (i == 0 && (n = len % LIMB_DIGITS) != 0) { @@ -36036,6 +36055,32 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag) } a->tab[i] = v; } + } else +#endif /* CONFIG_BIGNUM */ + { + n = len & (sizeof(limb_t) - 1); + if (n != 0) { + v = 0; + for(i = 0; i < n; i++) { + if (bc_get_u8(s, &v8)) + goto fail; + v |= (limb_t)v8 << ((sizeof(limb_t) - n + i) * 8); + } + a->tab[0] = v; + i = 1; + } else { + i = 0; + } + for(; i < l; i++) { +#if LIMB_BITS == 32 + if (bc_get_u32(s, &v)) + goto fail; +#else + if (bc_get_u64(s, &v)) + goto fail; +#endif + a->tab[i] = v; + } } } bc_read_trace(s, "}\n"); @@ -37087,12 +37132,10 @@ static JSValue js_global_isNaN(JSContext *ctx, JSValueConst this_val, static JSValue js_global_isFinite(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - BOOL res; double d; if (unlikely(JS_ToFloat64(ctx, &d, argv[0]))) return JS_EXCEPTION; - res = isfinite(d); - return JS_NewBool(ctx, res); + return JS_NewBool(ctx, isfinite(d)); } /* Object class */ @@ -37486,13 +37529,13 @@ static JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst t } else { if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, desc.value), flags) < 0 || JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable, - JS_NewBool(ctx, (desc.flags & JS_PROP_WRITABLE) != 0), flags) < 0) + JS_NewBool(ctx, desc.flags & JS_PROP_WRITABLE), flags) < 0) goto exception1; } if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable, - JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0), flags) < 0 + JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE), flags) < 0 || JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable, - JS_NewBool(ctx, (desc.flags & JS_PROP_CONFIGURABLE) != 0), flags) < 0) + JS_NewBool(ctx, desc.flags & JS_PROP_CONFIGURABLE), flags) < 0) goto exception1; js_free_desc(ctx, &desc); } @@ -38240,7 +38283,7 @@ static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_ if (has_prop < 0) goto exception; if (has_prop) { - res = JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0); + res = JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE); js_free_desc(ctx, &desc); } else { res = JS_FALSE; @@ -38475,7 +38518,9 @@ static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen, if (js_get_length32(ctx, &len, array_arg)) return NULL; if (len > JS_MAX_LOCAL_VARS) { - JS_ThrowInternalError(ctx, "too many arguments"); + // XXX: check for stack overflow? + JS_ThrowRangeError(ctx, "too many arguments in function call (only %d allowed)", + JS_MAX_LOCAL_VARS); return NULL; } /* avoid allocating 0 bytes */ @@ -39239,7 +39284,7 @@ static JSValue js_array_with(JSContext *ctx, JSValueConst this_val, idx = len + idx; if (idx < 0 || idx >= len) { - JS_ThrowRangeError(ctx, "out of bound"); + JS_ThrowRangeError(ctx, "invalid array index: %" PRId64, idx); goto exception; } @@ -39648,9 +39693,10 @@ static JSValue js_array_includes(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { JSValue obj, val; - int64_t len, n, res; + int64_t len, n; JSValue *arrp; uint32_t count; + int res; obj = JS_ToObject(ctx, this_val); if (js_get_length64(ctx, &len, obj)) @@ -39782,10 +39828,10 @@ static JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val, } enum { - special_find, - special_findIndex, - special_findLast, - special_findLastIndex, + ArrayFind, + ArrayFindIndex, + ArrayFindLast, + ArrayFindLastIndex, }; static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, @@ -39811,14 +39857,13 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, if (argc > 1) this_arg = argv[1]; - if (mode == special_findLast || mode == special_findLastIndex) { + k = 0; + dir = 1; + end = len; + if (mode == ArrayFindLast || mode == ArrayFindLastIndex) { k = len - 1; dir = -1; end = -1; - } else { - k = 0; - dir = 1; - end = len; } // TODO(bnoordhuis) add fast path for fast arrays @@ -39836,7 +39881,7 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, if (JS_IsException(res)) goto exception; if (JS_ToBoolFree(ctx, res)) { - if (mode == special_findIndex || mode == special_findLastIndex) { + if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) { JS_FreeValue(ctx, val); JS_FreeValue(ctx, obj); return index_val; @@ -39850,7 +39895,7 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, index_val); } JS_FreeValue(ctx, obj); - if (mode == special_findIndex || mode == special_findLastIndex) + if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) return JS_NewInt32(ctx, -1); else return JS_UNDEFINED; @@ -40877,10 +40922,10 @@ static const JSCFunctionListEntry js_array_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce ), JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight ), JS_CFUNC_DEF("fill", 1, js_array_fill ), - JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, special_find ), - JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, special_findIndex ), - JS_CFUNC_MAGIC_DEF("findLast", 1, js_array_find, special_findLast ), - JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_array_find, special_findLastIndex ), + JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, ArrayFind ), + JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, ArrayFindIndex ), + JS_CFUNC_MAGIC_DEF("findLast", 1, js_array_find, ArrayFindLast ), + JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_array_find, ArrayFindLastIndex ), JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ), JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ), JS_CFUNC_DEF("includes", 1, js_array_includes ), @@ -41860,7 +41905,7 @@ static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val, ret = js_is_regexp(ctx, argv[0]); if (ret) { if (ret > 0) - JS_ThrowTypeError(ctx, "regex not supported"); + JS_ThrowTypeError(ctx, "regexp not supported"); goto fail; } v = JS_ToString(ctx, argv[0]); @@ -42422,7 +42467,7 @@ static JSValue js_string_pad(JSContext *ctx, JSValueConst this_val, } } if (n > JS_STRING_LEN_MAX) { - JS_ThrowInternalError(ctx, "string too long"); + JS_ThrowRangeError(ctx, "invalid string length"); goto fail2; } if (string_buffer_init(ctx, b, n)) @@ -42484,8 +42529,9 @@ static JSValue js_string_repeat(JSContext *ctx, JSValueConst this_val, len = p->len; if (len == 0 || n == 1) return str; + // XXX: potential arithmetic overflow if (val * len > JS_STRING_LEN_MAX) { - JS_ThrowInternalError(ctx, "string too long"); + JS_ThrowRangeError(ctx, "invalid string length"); goto fail; } if (string_buffer_init2(ctx, b, n * len, p->is_wide_char)) @@ -43795,7 +43841,7 @@ static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mas } flags = lre_get_flags(re->bytecode->u.str8); - return JS_NewBool(ctx, (flags & mask) != 0); + return JS_NewBool(ctx, flags & mask); } static JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val) @@ -45096,7 +45142,7 @@ static JSValue json_parse_value(JSParseState *s) case TOK_IDENT: if (s->token.u.ident.atom == JS_ATOM_false || s->token.u.ident.atom == JS_ATOM_true) { - val = JS_NewBool(ctx, (s->token.u.ident.atom == JS_ATOM_true)); + val = JS_NewBool(ctx, s->token.u.ident.atom == JS_ATOM_true); } else if (s->token.u.ident.atom == JS_ATOM_null) { val = JS_NULL; } else { @@ -45108,7 +45154,7 @@ static JSValue json_parse_value(JSParseState *s) default: def_token: if (s->token.val == TOK_EOF) { - js_parse_error(s, "unexpected end of input"); + js_parse_error(s, "Unexpected end of JSON input"); } else { js_parse_error(s, "unexpected token: '%.*s'", (int)(s->buf_ptr - s->token.ptr), s->token.ptr); @@ -45275,22 +45321,27 @@ static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc, JSValue v; JSValueConst args[2]; - if (JS_IsObject(val) || - JS_IsBigInt(ctx, val) /* XXX: probably useless */ + /* check for object.toJSON method */ + /* ECMA specifies this is done only for Object and BigInt */ + /* we do it for BigFloat and BigDecimal as an extension */ + if (JS_IsObject(val) || JS_IsBigInt(ctx, val) +#ifdef CONFIG_BIGNUM + || JS_IsBigFloat(val) || JS_IsBigDecimal(val) +#endif ) { - JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON); - if (JS_IsException(f)) + JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON); + if (JS_IsException(f)) + goto exception; + if (JS_IsFunction(ctx, f)) { + v = JS_CallFree(ctx, f, val, 1, &key); + JS_FreeValue(ctx, val); + val = v; + if (JS_IsException(val)) goto exception; - if (JS_IsFunction(ctx, f)) { - v = JS_CallFree(ctx, f, val, 1, &key); - JS_FreeValue(ctx, val); - val = v; - if (JS_IsException(val)) - goto exception; - } else { - JS_FreeValue(ctx, f); - } + } else { + JS_FreeValue(ctx, f); } + } if (!JS_IsUndefined(jsc->replacer_func)) { args[0] = key; @@ -45309,12 +45360,13 @@ static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc, case JS_TAG_STRING: case JS_TAG_INT: case JS_TAG_FLOAT64: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: -#endif case JS_TAG_BOOL: case JS_TAG_NULL: case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM + case JS_TAG_BIG_FLOAT: + case JS_TAG_BIG_DECIMAL: +#endif case JS_TAG_EXCEPTION: return val; default: @@ -45344,36 +45396,29 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, tab = JS_UNDEFINED; prop = JS_UNDEFINED; - switch (JS_VALUE_GET_NORM_TAG(val)) { - case JS_TAG_OBJECT: + if (JS_IsObject(val)) { p = JS_VALUE_GET_OBJ(val); cl = p->class_id; if (cl == JS_CLASS_STRING) { val = JS_ToStringFree(ctx, val); if (JS_IsException(val)) goto exception; - val = JS_ToQuotedStringFree(ctx, val); - if (JS_IsException(val)) - goto exception; - return string_buffer_concat_value_free(jsc->b, val); + goto concat_primitive; } else if (cl == JS_CLASS_NUMBER) { val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) goto exception; - return string_buffer_concat_value_free(jsc->b, val); - } else if (cl == JS_CLASS_BOOLEAN) { - ret = string_buffer_concat_value(jsc->b, p->u.object_data); - JS_FreeValue(ctx, val); - return ret; - } else + goto concat_primitive; + } else if (cl == JS_CLASS_BOOLEAN || cl == JS_CLASS_BIG_INT #ifdef CONFIG_BIGNUM - if (cl == JS_CLASS_BIG_FLOAT) { - return string_buffer_concat_value_free(jsc->b, val); - } else + || cl == JS_CLASS_BIG_FLOAT + || cl == JS_CLASS_BIG_DECIMAL #endif - if (cl == JS_CLASS_BIG_INT) { - JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify"); - goto exception; + ) + { + /* This will thow the same error as for the primitive object */ + set_value(ctx, &val, JS_DupValue(ctx, p->u.object_data)); + goto concat_primitive; } v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val); if (JS_IsException(v)) @@ -45486,6 +45531,9 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, JS_FreeValue(ctx, indent1); JS_FreeValue(ctx, prop); return 0; + } + concat_primitive: + switch (JS_VALUE_GET_NORM_TAG(val)) { case JS_TAG_STRING: val = JS_ToQuotedStringFree(ctx, val); if (JS_IsException(val)) @@ -45497,15 +45545,17 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, } goto concat_value; case JS_TAG_INT: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: -#endif case JS_TAG_BOOL: case JS_TAG_NULL: concat_value: return string_buffer_concat_value_free(jsc->b, val); case JS_TAG_BIG_INT: - JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify"); +#ifdef CONFIG_BIGNUM + case JS_TAG_BIG_FLOAT: + case JS_TAG_BIG_DECIMAL: +#endif + /* reject big numbers: use toJSON method to override */ + JS_ThrowTypeError(ctx, "Do not know how to serialize a BigInt"); goto exception; default: JS_FreeValue(ctx, val); @@ -46112,8 +46162,10 @@ static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom, if (JS_IsException(ret)) return JS_EXCEPTION; res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom); - if (res < 0) + if (res < 0) { + JS_FreeValue(ctx, ret); return JS_EXCEPTION; + } if (res) { if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) { if (!js_same_value(ctx, desc.value, ret)) { @@ -46212,17 +46264,17 @@ static JSValue js_create_desc(JSContext *ctx, JSValueConst val, } if (flags & JS_PROP_HAS_WRITABLE) { JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable, - JS_NewBool(ctx, (flags & JS_PROP_WRITABLE) != 0), + JS_NewBool(ctx, flags & JS_PROP_WRITABLE), JS_PROP_C_W_E); } if (flags & JS_PROP_HAS_ENUMERABLE) { JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable, - JS_NewBool(ctx, (flags & JS_PROP_ENUMERABLE) != 0), + JS_NewBool(ctx, flags & JS_PROP_ENUMERABLE), JS_PROP_C_W_E); } if (flags & JS_PROP_HAS_CONFIGURABLE) { JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable, - JS_NewBool(ctx, (flags & JS_PROP_CONFIGURABLE) != 0), + JS_NewBool(ctx, flags & JS_PROP_CONFIGURABLE), JS_PROP_C_W_E); } return ret; @@ -46674,20 +46726,35 @@ static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj, return ret; } -static int js_proxy_isArray(JSContext *ctx, JSValueConst obj) -{ - JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY); - if (!s) - return FALSE; - if (js_check_stack_overflow(ctx->rt, 0)) { - JS_ThrowStackOverflow(ctx); - return -1; +/* `js_resolve_proxy`: resolve the proxy chain + `*pval` is updated with to ultimate proxy target + `throw_exception` controls whether exceptions are thown or not + - return -1 in case of error + - otherwise return 0 + */ +static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, BOOL throw_exception) { + int depth = 0; + JSObject *p; + JSProxyData *s; + + while (JS_VALUE_GET_TAG(*pval) == JS_TAG_OBJECT) { + p = JS_VALUE_GET_OBJ(*pval); + if (p->class_id != JS_CLASS_PROXY) + break; + if (depth++ > 1000) { + if (throw_exception) + JS_ThrowStackOverflow(ctx); + return -1; + } + s = p->u.opaque; + if (s->is_revoked) { + if (throw_exception) + JS_ThrowTypeErrorRevokedProxy(ctx); + return -1; + } + *pval = s->target; } - if (s->is_revoked) { - JS_ThrowTypeErrorRevokedProxy(ctx); - return -1; - } - return JS_IsArray(ctx, s->target); + return 0; } static const JSClassExoticMethods js_proxy_exotic_methods = { @@ -47316,7 +47383,7 @@ static JSValue js_map_has(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; key = map_normalize_key(ctx, argv[0]); mr = map_find_record(ctx, s, key); - return JS_NewBool(ctx, (mr != NULL)); + return JS_NewBool(ctx, mr != NULL); } static JSValue js_map_delete(JSContext *ctx, JSValueConst this_val, @@ -49432,6 +49499,7 @@ static const JSCFunctionListEntry js_global_funcs[] = { JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0 ), JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ), JS_PROP_UNDEFINED_DEF("undefined", 0 ), + JS_PROP_STRING_DEF("[Symbol.toStringTag]", "global", JS_PROP_CONFIGURABLE ), }; /* Date */ @@ -49512,7 +49580,7 @@ static char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; static char const day_names[] = "SunMonTueWedThuFriSat"; static __exception int get_date_fields(JSContext *ctx, JSValueConst obj, - double fields[9], int is_local, int force) + double fields[minimum_length(9)], int is_local, int force) { double dval; int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0; @@ -49525,7 +49593,7 @@ static __exception int get_date_fields(JSContext *ctx, JSValueConst obj, return FALSE; /* NaN */ d = 0; /* initialize all fields to 0 */ } else { - d = dval; + d = dval; /* assuming -8.64e15 <= dval <= -8.64e15 */ if (is_local) { tz = -getTimezoneOffset(d); d += tz * 60000; @@ -49573,7 +49641,7 @@ static double time_clip(double t) { /* The spec mandates the use of 'double' and it specifies the order of the operations */ -static double set_date_fields(double fields[], int is_local) { +static double set_date_fields(double fields[minimum_length(7)], int is_local) { double y, m, dt, ym, mn, day, h, s, milli, time, tv; int yi, mi, i; int64_t days; @@ -49677,9 +49745,9 @@ static JSValue set_date_field(JSContext *ctx, JSValueConst this_val, res = FALSE; fields[first_field + i] = trunc(a); } - if (res && argc > 0) { + if (res && argc > 0) d = set_date_fields(fields, is_local); - } + return JS_SetThisTimeValue(ctx, this_val, d); } @@ -49884,7 +49952,7 @@ static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { // UTC(y, mon, d, h, m, s, ms) - double fields[9] = { 0, 0, 1, 0, 0, 0, 0, 0, 0 }; + double fields[] = { 0, 0, 1, 0, 0, 0, 0 }; int i, n; double a; @@ -49964,14 +50032,15 @@ static BOOL string_get_digits(const uint8_t *sp, int *pp, int *pval, static BOOL string_get_milliseconds(const uint8_t *sp, int *pp, int *pval) { /* parse optional fractional part as milliseconds and truncate. */ /* spec does not indicate which rounding should be used */ - int mul = 1000, ms = 0, c, p_start, p = *pp; + int mul = 100, ms = 0, c, p_start, p = *pp; c = sp[p]; if (c == '.' || c == ',') { p++; p_start = p; while ((c = sp[p]) >= '0' && c <= '9') { - ms += (c - '0') * (mul /= 10); + ms += (c - '0') * mul; + mul /= 10; p++; if (p - p_start == 9) break; @@ -49985,7 +50054,11 @@ static BOOL string_get_milliseconds(const uint8_t *sp, int *pp, int *pval) { return TRUE; } -static BOOL string_get_timezone(const uint8_t *sp, int *pp, int *tzp, BOOL strict) { +static uint8_t upper_ascii(uint8_t c) { + return c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c; +} + +static BOOL string_get_tzoffset(const uint8_t *sp, int *pp, int *tzp, BOOL strict) { int tz = 0, sgn, hh, mm, p = *pp; sgn = sp[p++]; @@ -50023,10 +50096,6 @@ static BOOL string_get_timezone(const uint8_t *sp, int *pp, int *tzp, BOOL stric return TRUE; } -static uint8_t upper_ascii(uint8_t c) { - return c >= 'a' && c <= 'z' ? c - 'a' + 'Z' : c; -} - static BOOL string_match(const uint8_t *sp, int *pp, const char *s) { int p = *pp; while (*s != '\0') { @@ -50119,15 +50188,51 @@ static BOOL js_date_parse_isostring(const uint8_t *sp, int fields[9], BOOL *is_l /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */ if (sp[p]) { *is_local = FALSE; - if (!string_get_timezone(sp, &p, &fields[8], TRUE)) + if (!string_get_tzoffset(sp, &p, &fields[8], TRUE)) return FALSE; } /* error if extraneous characters */ return sp[p] == '\0'; } +static struct { + char name[6]; + int16_t offset; +} const js_tzabbr[] = { + { "GMT", 0 }, // Greenwich Mean Time + { "UTC", 0 }, // Coordinated Universal Time + { "UT", 0 }, // Universal Time + { "Z", 0 }, // Zulu Time + { "EDT", -4 * 60 }, // Eastern Daylight Time + { "EST", -5 * 60 }, // Eastern Standard Time + { "CDT", -5 * 60 }, // Central Daylight Time + { "CST", -6 * 60 }, // Central Standard Time + { "MDT", -6 * 60 }, // Mountain Daylight Time + { "MST", -7 * 60 }, // Mountain Standard Time + { "PDT", -7 * 60 }, // Pacific Daylight Time + { "PST", -8 * 60 }, // Pacific Standard Time + { "WET", +0 * 60 }, // Western European Time + { "WEST", +1 * 60 }, // Western European Summer Time + { "CET", +1 * 60 }, // Central European Time + { "CEST", +2 * 60 }, // Central European Summer Time + { "EET", +2 * 60 }, // Eastern European Time + { "EEST", +3 * 60 }, // Eastern European Summer Time +}; + +static BOOL string_get_tzabbr(const uint8_t *sp, int *pp, int *offset) { + for (size_t i = 0; i < countof(js_tzabbr); i++) { + if (string_match(sp, pp, js_tzabbr[i].name)) { + *offset = js_tzabbr[i].offset; + return TRUE; + } + } + return FALSE; +} + /* parse toString, toUTCString and other formats */ -static BOOL js_date_parse_otherstring(const uint8_t *sp, int fields[9], BOOL *is_local) { +static BOOL js_date_parse_otherstring(const uint8_t *sp, + int fields[minimum_length(9)], + BOOL *is_local) { int c, i, val, p = 0, p_start; int num[3]; BOOL has_year = FALSE; @@ -50147,7 +50252,7 @@ static BOOL js_date_parse_otherstring(const uint8_t *sp, int fields[9], BOOL *is while (string_skip_spaces(sp, &p)) { p_start = p; if ((c = sp[p]) == '+' || c == '-') { - if (has_time && string_get_timezone(sp, &p, &fields[8], FALSE)) { + if (has_time && string_get_tzoffset(sp, &p, &fields[8], FALSE)) { *is_local = FALSE; } else { p++; @@ -50193,11 +50298,6 @@ static BOOL js_date_parse_otherstring(const uint8_t *sp, int fields[9], BOOL *is has_mon = TRUE; string_skip_until(sp, &p, "0123456789 -/("); } else - if (c == 'Z') { - *is_local = FALSE; - p++; - continue; - } else if (has_time && string_match(sp, &p, "PM")) { if (fields[3] < 12) fields[3] += 12; @@ -50208,34 +50308,7 @@ static BOOL js_date_parse_otherstring(const uint8_t *sp, int fields[9], BOOL *is fields[3] -= 12; continue; } else - if (string_match(sp, &p, "GMT") - || string_match(sp, &p, "UTC") - || string_match(sp, &p, "UT")) { - *is_local = FALSE; - continue; - } else - if (string_match(sp, &p, "EDT")) { - fields[8] = -4 * 60; - *is_local = FALSE; - continue; - } else - if (string_match(sp, &p, "EST") || string_match(sp, &p, "CDT")) { - fields[8] = -5 * 60; - *is_local = FALSE; - continue; - } else - if (string_match(sp, &p, "CST") || string_match(sp, &p, "MDT")) { - fields[8] = -6 * 60; - *is_local = FALSE; - continue; - } else - if (string_match(sp, &p, "MST") || string_match(sp, &p, "PDT")) { - fields[8] = -7 * 60; - *is_local = FALSE; - continue; - } else - if (string_match(sp, &p, "PST")) { - fields[8] = -8 * 60; + if (string_get_tzabbr(sp, &p, &fields[8])) { *is_local = FALSE; continue; } else @@ -50378,9 +50451,7 @@ static JSValue js_date_Symbol_toPrimitive(JSContext *ctx, JSValueConst this_val, } switch (hint) { case JS_ATOM_number: -#ifdef CONFIG_BIGNUM case JS_ATOM_integer: -#endif hint_num = HINT_NUMBER; break; case JS_ATOM_string: @@ -50404,6 +50475,7 @@ static JSValue js_date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val, if (isnan(v)) return JS_NAN; else + /* assuming -8.64e15 <= v <= -8.64e15 */ return JS_NewInt64(ctx, getTimezoneOffset((int64_t)trunc(v))); } @@ -50542,6 +50614,15 @@ static const JSCFunctionListEntry js_date_proto_funcs[] = { JS_CFUNC_DEF("toJSON", 1, js_date_toJSON ), }; +JSValue JS_NewDate(JSContext *ctx, double epoch_ms) +{ + JSValue obj = js_create_from_ctor(ctx, JS_UNDEFINED, JS_CLASS_DATE); + if (JS_IsException(obj)) + return JS_EXCEPTION; + JS_SetObjectData(ctx, obj, __JS_NewFloat64(ctx, time_clip(epoch_ms))); + return obj; +} + void JS_AddIntrinsicDate(JSContext *ctx) { JSValueConst obj; @@ -50892,7 +50973,7 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val) } if (!bf_is_finite(a)) { JS_FreeValue(ctx, val); - val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to bigint"); + val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to BigInt"); } else { JSValue val1 = JS_NewBigInt(ctx); bf_t *r; @@ -50910,7 +50991,7 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val) val = JS_ThrowOutOfMemory(ctx); } else if (ret & BF_ST_INEXACT) { JS_FreeValue(ctx, val1); - val = JS_ThrowRangeError(ctx, "cannot convert to bigint: not an integer"); + val = JS_ThrowRangeError(ctx, "cannot convert to BigInt: not an integer"); } else { val = JS_CompactBigInt(ctx, val1); } @@ -50938,7 +51019,7 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val) case JS_TAG_UNDEFINED: default: JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert to bigint"); + return JS_ThrowTypeError(ctx, "cannot convert to BigInt"); } return val; } @@ -50964,7 +51045,7 @@ static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val) return JS_DupValue(ctx, p->u.object_data); } } - return JS_ThrowTypeError(ctx, "not a bigint"); + return JS_ThrowTypeError(ctx, "not a BigInt"); } static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val, @@ -52005,9 +52086,9 @@ static JSValue js_float_env_proto_get_status(JSContext *ctx, JSValueConst this_v case FE_RNDMODE: return JS_NewInt32(ctx, fe->flags & BF_RND_MASK); case FE_SUBNORMAL: - return JS_NewBool(ctx, (fe->flags & BF_FLAG_SUBNORMAL) != 0); + return JS_NewBool(ctx, fe->flags & BF_FLAG_SUBNORMAL); default: - return JS_NewBool(ctx, (fe->status & magic) != 0); + return JS_NewBool(ctx, fe->status & magic); } } @@ -52730,11 +52811,13 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) JS_NewGlobalCConstructor2(ctx, obj1, "Error", ctx->class_proto[JS_CLASS_ERROR]); + /* Used to squelch a -Wcast-function-type warning. */ + JSCFunctionType ft = { .generic_magic = js_error_constructor }; for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) { JSValue func_obj; int n_args; n_args = 1 + (i == JS_AGGREGATE_ERROR); - func_obj = JS_NewCFunction3(ctx, (JSCFunction *)js_error_constructor, + func_obj = JS_NewCFunction3(ctx, ft.generic, native_error_name[i], n_args, JS_CFUNC_constructor_or_func_magic, i, obj1); JS_NewGlobalCConstructor2(ctx, func_obj, native_error_name[i], @@ -52761,7 +52844,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) /* XXX: create auto_initializer */ { /* initialize Array.prototype[Symbol.unscopables] */ - char const unscopables[] = + static const char unscopables[] = "copyWithin" "\0" "entries" "\0" "fill" "\0" @@ -53359,6 +53442,16 @@ static JSValue js_typed_array_get_byteOffset(JSContext *ctx, return JS_NewInt32(ctx, ta->offset); } +JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv, + JSTypedArrayEnum type) +{ + if (type < JS_TYPED_ARRAY_UINT8C || type > JS_TYPED_ARRAY_FLOAT64) + return JS_ThrowRangeError(ctx, "invalid typed array type"); + + return js_typed_array_constructor(ctx, JS_UNDEFINED, argc, argv, + JS_CLASS_UINT8C_ARRAY + type); +} + /* Return the buffer associated to the typed array or an exception if it is not a typed array or if the buffer is detached. pbyte_offset, pbyte_length or pbytes_per_element can be NULL. */ @@ -53520,7 +53613,7 @@ static JSValue js_typed_array_with(JSContext *ctx, JSValueConst this_val, if (idx < 0) idx = len + idx; if (idx < 0 || idx >= len) - return JS_ThrowRangeError(ctx, "out of bound"); + return JS_ThrowRangeError(ctx, "invalid array index"); val = JS_ToPrimitive(ctx, argv[1], HINT_NUMBER); if (JS_IsException(val)) @@ -53914,14 +54007,13 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, if (argc > 1) this_arg = argv[1]; - if (mode == special_findLast || mode == special_findLastIndex) { + k = 0; + dir = 1; + end = len; + if (mode == ArrayFindLast || mode == ArrayFindLastIndex) { k = len - 1; dir = -1; end = -1; - } else { - k = 0; - dir = 1; - end = len; } for(; k != end; k += dir) { @@ -53936,7 +54028,7 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, if (JS_IsException(res)) goto exception; if (JS_ToBoolFree(ctx, res)) { - if (mode == special_findIndex || mode == special_findLastIndex) { + if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) { JS_FreeValue(ctx, val); return index_val; } else { @@ -53945,7 +54037,7 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, } JS_FreeValue(ctx, val); } - if (mode == special_findIndex || mode == special_findLastIndex) + if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) return JS_NewInt32(ctx, -1); else return JS_UNDEFINED; @@ -54789,10 +54881,10 @@ static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce | special_TA ), JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight | special_TA ), JS_CFUNC_DEF("fill", 1, js_typed_array_fill ), - JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, special_find ), - JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, special_findIndex ), - JS_CFUNC_MAGIC_DEF("findLast", 1, js_typed_array_find, special_findLast ), - JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_typed_array_find, special_findLastIndex ), + JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, ArrayFind ), + JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, ArrayFindIndex ), + JS_CFUNC_MAGIC_DEF("findLast", 1, js_typed_array_find, ArrayFindLast ), + JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_typed_array_find, ArrayFindLastIndex ), JS_CFUNC_DEF("reverse", 0, js_typed_array_reverse ), JS_CFUNC_DEF("toReversed", 0, js_typed_array_toReversed ), JS_CFUNC_DEF("slice", 2, js_typed_array_slice ), @@ -55153,7 +55245,8 @@ static JSValue js_dataview_getValue(JSContext *ctx, { JSTypedArray *ta; JSArrayBuffer *abuf; - int is_swap, size; + BOOL littleEndian, is_swap; + int size; uint8_t *ptr; uint32_t v; uint64_t pos; @@ -55164,9 +55257,8 @@ static JSValue js_dataview_getValue(JSContext *ctx, size = 1 << typed_array_size_log2(class_id); if (JS_ToIndex(ctx, &pos, argv[0])) return JS_EXCEPTION; - is_swap = TRUE; - if (argc > 1) - is_swap = !JS_ToBool(ctx, argv[1]); + littleEndian = argc > 1 && JS_ToBool(ctx, argv[1]); + is_swap = littleEndian ^ !is_be(); abuf = ta->buffer->u.array_buffer; if (abuf->detached) return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); @@ -55251,7 +55343,8 @@ static JSValue js_dataview_setValue(JSContext *ctx, { JSTypedArray *ta; JSArrayBuffer *abuf; - int is_swap, size; + BOOL littleEndian, is_swap; + int size; uint8_t *ptr; uint64_t v64; uint32_t v; @@ -55290,9 +55383,8 @@ static JSValue js_dataview_setValue(JSContext *ctx, v64 = u.u64; } } - is_swap = TRUE; - if (argc > 2) - is_swap = !JS_ToBool(ctx, argv[2]); + littleEndian = argc > 2 && JS_ToBool(ctx, argv[2]); + is_swap = littleEndian ^ !is_be(); abuf = ta->buffer->u.array_buffer; if (abuf->detached) return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); @@ -55858,6 +55950,8 @@ void JS_AddIntrinsicTypedArrays(JSContext *ctx) countof(js_typed_array_base_funcs)); JS_SetConstructor(ctx, typed_array_base_func, typed_array_base_proto); + /* Used to squelch a -Wcast-function-type warning. */ + JSCFunctionType ft = { .generic_magic = js_typed_array_constructor }; for(i = JS_CLASS_UINT8C_ARRAY; i < JS_CLASS_UINT8C_ARRAY + JS_TYPED_ARRAY_COUNT; i++) { JSValue func_obj; char buf[ATOM_GET_STR_BUF_SIZE]; @@ -55870,7 +55964,7 @@ void JS_AddIntrinsicTypedArrays(JSContext *ctx) 0); name = JS_AtomGetStr(ctx, buf, sizeof(buf), JS_ATOM_Uint8ClampedArray + i - JS_CLASS_UINT8C_ARRAY); - func_obj = JS_NewCFunction3(ctx, (JSCFunction *)js_typed_array_constructor, + func_obj = JS_NewCFunction3(ctx, ft.generic, name, 3, JS_CFUNC_constructor_magic, i, typed_array_base_func); JS_NewGlobalCConstructor2(ctx, func_obj, name, ctx->class_proto[i]); diff --git a/source/engine/thirdparty/quickjs/quickjs.h b/source/engine/thirdparty/quickjs/quickjs.h index 1b81906..81a6b95 100644 --- a/source/engine/thirdparty/quickjs/quickjs.h +++ b/source/engine/thirdparty/quickjs/quickjs.h @@ -92,6 +92,7 @@ typedef struct JSRefCountHeader { } JSRefCountHeader; void quickjs_set_dumpout(FILE *f); +void JS_SetInterruptRate(int count); #define JS_FLOAT64_NAN NAN @@ -635,7 +636,9 @@ static inline JS_BOOL JS_IsObject(JSValueConst v) JSValue JS_Throw(JSContext *ctx, JSValue obj); JSValue JS_GetException(JSContext *ctx); +JS_BOOL JS_HasException(JSContext *ctx); JS_BOOL JS_IsError(JSContext *ctx, JSValueConst val); +void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, JS_BOOL flag); void JS_ResetUncatchableError(JSContext *ctx); JSValue JS_NewError(JSContext *ctx); JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...); @@ -684,6 +687,10 @@ static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v) return (JSValue)v; } +JS_BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2); +JS_BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2); +JS_BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2); + int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */ int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val); static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val) @@ -726,6 +733,8 @@ JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val) JSValue JS_NewArray(JSContext *ctx); int JS_IsArray(JSContext *ctx, JSValueConst val); +JSValue JS_NewDate(JSContext *ctx, double epoch_ms); + JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValueConst receiver, JS_BOOL throw_ref_error); @@ -824,6 +833,23 @@ JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len, JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len); void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj); uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj); + +typedef enum JSTypedArrayEnum { + JS_TYPED_ARRAY_UINT8C = 0, + JS_TYPED_ARRAY_INT8, + JS_TYPED_ARRAY_UINT8, + JS_TYPED_ARRAY_INT16, + JS_TYPED_ARRAY_UINT16, + JS_TYPED_ARRAY_INT32, + JS_TYPED_ARRAY_UINT32, + JS_TYPED_ARRAY_BIG_INT64, + JS_TYPED_ARRAY_BIG_UINT64, + JS_TYPED_ARRAY_FLOAT32, + JS_TYPED_ARRAY_FLOAT64, +} JSTypedArrayEnum; + +JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv, + JSTypedArrayEnum array_type); JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj, size_t *pbyte_offset, size_t *pbyte_length, @@ -855,8 +881,7 @@ void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTrac /* return != 0 if the JS code needs to be interrupted */ typedef int JSInterruptHandler(JSRuntime *rt, void *opaque); -void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque, int count); -void JS_SetInterruptRate(int count); +void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque); /* if can_block is TRUE, Atomics.wait() can be used */ void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block); /* set the [IsHTMLDDA] internal slot */