From 736bbbed715d6db1eec2a9947b86787d8f9e680e Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Wed, 22 Mar 2017 15:35:19 +0000 Subject: Duktape 2.X: Update to Duktape 2.0.2. Note that DUK_OPT_XXX feature selection has been removed. This means we can't use `DUK_OPT_HAVE_CUSTOM_H`, so we need another way to tell duktape about our custom header. This means assembling our own duktape distribution with a duktape "tools/configure.py" invocation. Instructions for updating duktape have been added to NetSurf's `Docs/` directory. See: https://github.com/svaarala/duktape/blob/master/doc/release-notes-v2-0.rst#duk_opt_xxx-feature-option-support-removed --- Docs/updating-duktape.md | 29 + content/handlers/javascript/duktape/duk_config.h | 1349 +- content/handlers/javascript/duktape/duktape.c | 43618 ++++++++++++--------- content/handlers/javascript/duktape/duktape.h | 937 +- 4 files changed, 24906 insertions(+), 21027 deletions(-) create mode 100644 Docs/updating-duktape.md diff --git a/Docs/updating-duktape.md b/Docs/updating-duktape.md new file mode 100644 index 000000000..a3e5a79b1 --- /dev/null +++ b/Docs/updating-duktape.md @@ -0,0 +1,29 @@ +Updating Duktape +================ + +1. Fetch the [latest release](http://duktape.org/download.html) archive. + +2. Extract it somewhere. + +3. That extracts to a `duktape-[VERSION]` directory. + +4. We need to tell duktape about our `duk_custom.h` header: + + 1. Change into the `duktape-[VERSION]` directory. + + 2. Run the following command: + + python2 tools/configure.py \ + --output-directory /tmp/output \ + --source-directory src-input \ + --config-metadata config \ + --fixup-line '#include "duk_custom.h"' + + 3. This generates a suitable set of duktape + sources in `/tmp/output` + +5. Replace the `duktape.c`, `duktape.h` and + `duk_config.h` files in the netsurf source + tree (in `content/handlers/javascript/duktape`) + with those generated in `/tmp/output`. + diff --git a/content/handlers/javascript/duktape/duk_config.h b/content/handlers/javascript/duktape/duk_config.h index f9c95ae33..1b31a0b16 100644 --- a/content/handlers/javascript/duktape/duk_config.h +++ b/content/handlers/javascript/duktape/duk_config.h @@ -1,12 +1,13 @@ /* * duk_config.h configuration header generated by genconfig.py. * - * Git commit: 17e3d86cf8b4788bd0d37658f833ab440ce43a1c - * Git describe: v1.6.0 - * Git branch: HEAD + * Git commit: external + * Git describe: external + * Git branch: external * * Supported platforms: * - Mac OSX, iPhone, Darwin + * - Orbis * - OpenBSD * - Generic BSD * - Atari ST TOS @@ -18,6 +19,8 @@ * - Emscripten * - Linux * - Solaris + * - AIX + * - HPUX * - Generic POSIX * - Cygwin * - Generic UNIX @@ -60,20 +63,24 @@ */ /* DLL build detection */ -#if defined(DUK_OPT_DLL_BUILD) -#define DUK_F_DLL_BUILD -#elif defined(DUK_OPT_NO_DLL_BUILD) -#undef DUK_F_DLL_BUILD -#else /* not configured for DLL build */ #undef DUK_F_DLL_BUILD -#endif /* Apple OSX, iOS */ #if defined(__APPLE__) #define DUK_F_APPLE #endif +/* FreeBSD */ +#if defined(__FreeBSD__) || defined(__FreeBSD) +#define DUK_F_FREEBSD +#endif + +/* Orbis (PS4) variant */ +#if defined(DUK_F_FREEBSD) && defined(__ORBIS__) +#define DUK_F_ORBIS +#endif + /* OpenBSD */ #if defined(__OpenBSD__) || defined(__OpenBSD) #define DUK_F_OPENBSD @@ -84,11 +91,6 @@ #define DUK_F_NETBSD #endif -/* FreeBSD */ -#if defined(__FreeBSD__) || defined(__FreeBSD) -#define DUK_F_FREEBSD -#endif - /* BSD variant */ #if defined(DUK_F_FREEBSD) || defined(DUK_F_NETBSD) || defined(DUK_F_OPENBSD) || \ defined(__bsdi__) || defined(__DragonFly__) @@ -170,6 +172,28 @@ /* illumos / Solaris */ #if defined(__sun) && defined(__SVR4) #define DUK_F_SUN +#if defined(__SUNPRO_C) && (__SUNPRO_C < 0x550) +#define DUK_F_OLD_SOLARIS +/* Defines _ILP32 / _LP64 required by DUK_F_X86/DUK_F_X64. Platforms + * are processed before architectures, so this happens before the + * DUK_F_X86/DUK_F_X64 detection is emitted. + */ +#include +#endif +#endif + +/* AIX */ +#if defined(_AIX) +/* defined(__xlc__) || defined(__IBMC__): works but too wide */ +#define DUK_F_AIX +#endif + +/* HPUX */ +#if defined(__hpux) +#define DUK_F_HPUX +#if defined(__ia64) +#define DUK_F_HPUX_ITANIUM +#endif #endif /* POSIX */ @@ -188,17 +212,6 @@ #define DUK_F_UNIX #endif -/* stdint.h not available */ -#if defined(DUK_F_WINDOWS) && defined(_MSC_VER) -#if (_MSC_VER < 1700) -/* VS2012+ has stdint.h, < VS2012 does not (but it's available for download). */ -#define DUK_F_NO_STDINT_H -#endif -#endif -#if !defined(DUK_F_NO_STDINT_H) && (defined(DUK_F_TOS) || defined(DUK_F_BCC)) -#define DUK_F_NO_STDINT_H -#endif - /* C++ */ #undef DUK_F_CPP #if defined(__cplusplus) @@ -208,6 +221,9 @@ /* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers), * define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32. * https://sites.google.com/site/x32abi/ + * + * With DUK_F_OLD_SOLARIS the header must be included + * before this. */ #if defined(__amd64__) || defined(__amd64) || \ defined(__x86_64__) || defined(__x86_64) || \ @@ -230,9 +246,9 @@ #endif /* ARM */ -#if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM) +#if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM) || defined(__aarch64__) #define DUK_F_ARM -#if defined(__LP64__) || defined(_LP64) || defined(__arm64) || defined(__arm64__) +#if defined(__LP64__) || defined(_LP64) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) #define DUK_F_ARM64 #else #define DUK_F_ARM32 @@ -334,9 +350,8 @@ #define DUK_F_VBCC #endif -/* Atari Mint */ -#if defined(__MINT__) -#define DUK_F_MINT +#if defined(ANDROID) || defined(__ANDROID__) +#define DUK_F_ANDROID #endif /* @@ -380,6 +395,20 @@ #define DUK_JMPBUF_TYPE jmp_buf #define DUK_SETJMP(jb) _setjmp((jb)) #define DUK_LONGJMP(jb) _longjmp((jb), 1) +#elif defined(DUK_F_ORBIS) +/* --- Orbis --- */ +/* Orbis = PS4 */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_S +/* no parsing (not an error) */ +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "orbis" #elif defined(DUK_F_OPENBSD) /* --- OpenBSD --- */ /* http://www.monkey.org/openbsd/archive/ports/0401/msg00089.html */ @@ -436,7 +465,7 @@ #define DUK_USE_DATE_PRS_STRPTIME #define DUK_USE_DATE_FMT_STRFTIME #include -#ifndef UINTPTR_MAX +#if !defined(UINTPTR_MAX) #define UINTPTR_MAX UINT_MAX #endif #else @@ -531,13 +560,13 @@ #elif defined(DUK_F_EMSCRIPTEN) /* --- Emscripten --- */ #if defined(DUK_COMPILING_DUKTAPE) -#ifndef _POSIX_C_SOURCE +#if !defined(_POSIX_C_SOURCE) #define _POSIX_C_SOURCE 200809L #endif -#ifndef _GNU_SOURCE +#if !defined(_GNU_SOURCE) #define _GNU_SOURCE /* e.g. getdate_r */ #endif -#ifndef _XOPEN_SOURCE +#if !defined(_XOPEN_SOURCE) #define _XOPEN_SOURCE /* e.g. strptime */ #endif #endif /* DUK_COMPILING_DUKTAPE */ @@ -562,13 +591,13 @@ #elif defined(DUK_F_LINUX) /* --- Linux --- */ #if defined(DUK_COMPILING_DUKTAPE) -#ifndef _POSIX_C_SOURCE +#if !defined(_POSIX_C_SOURCE) #define _POSIX_C_SOURCE 200809L #endif -#ifndef _GNU_SOURCE +#if !defined(_GNU_SOURCE) #define _GNU_SOURCE /* e.g. getdate_r */ #endif -#ifndef _XOPEN_SOURCE +#if !defined(_XOPEN_SOURCE) #define _XOPEN_SOURCE /* e.g. strptime */ #endif #endif /* DUK_COMPILING_DUKTAPE */ @@ -598,12 +627,50 @@ #define DUK_USE_DATE_FMT_STRFTIME #include +#if defined(DUK_F_OLD_SOLARIS) +/* Old Solaris with no endian.h, stdint.h */ +#define DUK_F_NO_STDINT_H +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#else /* DUK_F_OLD_SOLARIS */ #include +#endif /* DUK_F_OLD_SOLARIS */ + #include #include #include #define DUK_USE_OS_STRING "solaris" +#elif defined(DUK_F_AIX) +/* --- AIX --- */ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include + +#define DUK_USE_OS_STRING "aix" +#elif defined(DUK_F_HPUX) +/* --- HPUX --- */ +#define DUK_F_NO_STDINT_H +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include + +#define DUK_USE_OS_STRING "hpux" #elif defined(DUK_F_POSIX) /* --- Generic POSIX --- */ #define DUK_USE_DATE_NOW_GETTIMEOFDAY @@ -887,6 +954,11 @@ #define DUK_USE_BRANCH_HINTS #define DUK_LIKELY(x) __builtin_expect((x), 1) #define DUK_UNLIKELY(x) __builtin_expect((x), 0) +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_unpredictable) +#define DUK_UNPREDICTABLE(x) __builtin_unpredictable((x)) +#endif +#endif #if defined(DUK_F_C99) || defined(DUK_F_CPP11) #define DUK_NOINLINE __attribute__((noinline)) @@ -995,6 +1067,7 @@ #define DUK_LIKELY(x) __builtin_expect((x), 1) #define DUK_UNLIKELY(x) __builtin_expect((x), 0) #endif +/* XXX: equivalent of clang __builtin_unpredictable? */ #if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 30101) @@ -1181,6 +1254,9 @@ #define DUK_SNPRINTF _snprintf #define DUK_VSNPRINTF _vsnprintf #endif + +/* Avoid warning when doing DUK_UNREF(some_function). */ +#define DUK_UNREF(x) do { __pragma(warning(suppress:4100 4101 4550 4551)) (x); } while (0) #elif defined(DUK_F_EMSCRIPTEN) /* --- Emscripten --- */ #define DUK_NORETURN(decl) decl __attribute__((noreturn)) @@ -1194,6 +1270,11 @@ #define DUK_USE_BRANCH_HINTS #define DUK_LIKELY(x) __builtin_expect((x), 1) #define DUK_UNLIKELY(x) __builtin_expect((x), 0) +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_unpredictable) +#define DUK_UNPREDICTABLE(x) __builtin_unpredictable((x)) +#endif +#endif #if defined(DUK_F_C99) || defined(DUK_F_CPP11) #define DUK_NOINLINE __attribute__((noinline)) @@ -1401,10 +1482,14 @@ #if defined(DUK_F_X86) || defined(DUK_F_X32) || \ defined(DUK_F_M68K) || defined(DUK_F_PPC32) || \ defined(DUK_F_BCC) || \ - (defined(__WORDSIZE) && (__WORDSIZE == 32)) + (defined(__WORDSIZE) && (__WORDSIZE == 32)) || \ + ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ + defined(DUK_F_HPUX)) && defined(_ILP32)) #define DUK_F_32BIT_PTRS #elif defined(DUK_F_X64) || \ - (defined(__WORDSIZE) && (__WORDSIZE == 64)) + (defined(__WORDSIZE) && (__WORDSIZE == 64)) || \ + ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ + defined(DUK_F_HPUX)) && defined(_LP64)) #define DUK_F_64BIT_PTRS #else /* not sure, not needed with C99 anyway */ @@ -1912,6 +1997,11 @@ typedef struct duk_hthread duk_context; * Fill-ins for platform, architecture, and compiler */ +/* An abort()-like primitive is needed by the default fatal error handler. */ +#if !defined(DUK_ABORT) +#define DUK_ABORT abort +#endif + #if !defined(DUK_SETJMP) #define DUK_JMPBUF_TYPE jmp_buf #define DUK_SETJMP(jb) setjmp((jb)) @@ -1925,17 +2015,6 @@ typedef struct duk_hthread duk_context; #define DUK_LONGJMP(jb) siglongjmp((jb), 1) #endif -typedef FILE duk_file; -#if !defined(DUK_STDIN) -#define DUK_STDIN stdin -#endif -#if !defined(DUK_STDOUT) -#define DUK_STDOUT stdout -#endif -#if !defined(DUK_STDERR) -#define DUK_STDERR stderr -#endif - /* Special naming to avoid conflict with e.g. DUK_FREE() in duk_heap.h * (which is unfortunately named). May sometimes need replacement, e.g. * some compilers don't handle zero length or NULL correctly in realloc(). @@ -2002,12 +2081,6 @@ typedef FILE duk_file; #if !defined(DUK_STRNCMP) #define DUK_STRNCMP strncmp #endif -#if !defined(DUK_PRINTF) -#define DUK_PRINTF printf -#endif -#if !defined(DUK_FPRINTF) -#define DUK_FPRINTF fprintf -#endif #if !defined(DUK_SPRINTF) #define DUK_SPRINTF sprintf #endif @@ -2028,46 +2101,9 @@ typedef FILE duk_file; #if !defined(DUK_VSSCANF) #define DUK_VSSCANF vsscanf #endif -#if !defined(DUK_FOPEN) -#define DUK_FOPEN fopen -#endif -#if !defined(DUK_FCLOSE) -#define DUK_FCLOSE fclose -#endif -#if !defined(DUK_FREAD) -#define DUK_FREAD fread -#endif -#if !defined(DUK_FWRITE) -#define DUK_FWRITE fwrite -#endif -#if !defined(DUK_FSEEK) -#define DUK_FSEEK fseek -#endif -#if !defined(DUK_FTELL) -#define DUK_FTELL ftell -#endif -#if !defined(DUK_FFLUSH) -#define DUK_FFLUSH fflush -#endif -#if !defined(DUK_FPUTC) -#define DUK_FPUTC fputc -#endif #if !defined(DUK_MEMZERO) #define DUK_MEMZERO(p,n) DUK_MEMSET((p), 0, (n)) #endif -#if !defined(DUK_ABORT) -#define DUK_ABORT abort -#endif -#if !defined(DUK_EXIT) -#define DUK_EXIT exit -#endif - -#if !defined(DUK_DOUBLE_2TO32) -#define DUK_DOUBLE_2TO32 4294967296.0 -#endif -#if !defined(DUK_DOUBLE_2TO31) -#define DUK_DOUBLE_2TO31 2147483648.0 -#endif #if !defined(DUK_DOUBLE_INFINITY) #undef DUK_USE_COMPUTED_INFINITY @@ -2076,7 +2112,8 @@ typedef FILE duk_file; #define DUK_DOUBLE_INFINITY (__builtin_inf()) #elif defined(INFINITY) #define DUK_DOUBLE_INFINITY ((double) INFINITY) -#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ + !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) #define DUK_DOUBLE_INFINITY (1.0 / 0.0) #else /* In VBCC (1.0 / 0.0) results in a warning and 0.0 instead of infinity. @@ -2092,7 +2129,8 @@ typedef FILE duk_file; #undef DUK_USE_COMPUTED_NAN #if defined(NAN) #define DUK_DOUBLE_NAN NAN -#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ + !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) #define DUK_DOUBLE_NAN (0.0 / 0.0) #else /* In VBCC (0.0 / 0.0) results in a warning and 0.0 instead of NaN. @@ -2141,6 +2179,9 @@ typedef FILE duk_file; * To be safe, use replacements. */ #define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_AIX) +/* Older versions may be missing isnan(), etc. */ +#define DUK_F_USE_REPL_ALL #endif #if defined(DUK_F_USE_REPL_ALL) @@ -2176,29 +2217,6 @@ typedef FILE duk_file; #undef DUK_F_USE_REPL_ALL #endif -/* Some math functions are C99 only. This is also an issue with some - * embedded environments using uclibc where uclibc has been configured - * not to provide some functions. For now, use replacements whenever - * using uclibc. - */ -#undef DUK_USE_MATH_FMIN -#undef DUK_USE_MATH_FMAX -#undef DUK_USE_MATH_ROUND -#if defined(DUK_F_UCLIBC) -/* uclibc may be missing these */ -#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC) -/* vbcc + AmigaOS may be missing these */ -#elif defined(DUK_F_MINT) -/* mint clib is missing these */ -#elif !defined(DUK_F_C99) && !defined(DUK_F_CPP11) -/* build is not C99 or C++11, play it safe */ -#else -/* C99 or C++11, no known issues */ -#define DUK_USE_MATH_FMIN -#define DUK_USE_MATH_FMAX -#define DUK_USE_MATH_ROUND -#endif - /* These functions don't currently need replacement but are wrapped for * completeness. Because these are used as function pointers, they need * to be defined as concrete C functions (not macros). @@ -2206,12 +2224,6 @@ typedef FILE duk_file; #if !defined(DUK_FABS) #define DUK_FABS fabs #endif -#if !defined(DUK_FMIN) -#define DUK_FMIN fmin -#endif -#if !defined(DUK_FMAX) -#define DUK_FMAX fmax -#endif #if !defined(DUK_FLOOR) #define DUK_FLOOR floor #endif @@ -2255,13 +2267,42 @@ typedef FILE duk_file; #define DUK_SQRT sqrt #endif +/* The functions below exist only in C99/C++11 or later and need a workaround + * for platforms that don't include them. MSVC isn't detected as C99, but + * these functions also exist in MSVC 2013 and later so include a clause for + * that too. Android doesn't have log2; disable all of these for Android. + */ +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11) || (defined(_MSC_VER) && (_MSC_VER >= 1800))) && !defined(DUK_F_ANDROID) +#if !defined(DUK_CBRT) +#define DUK_CBRT cbrt +#endif +#if !defined(DUK_LOG2) +#define DUK_LOG2 log2 +#endif +#if !defined(DUK_LOG10) +#define DUK_LOG10 log10 +#endif +#if !defined(DUK_TRUNC) +#define DUK_TRUNC trunc +#endif +#endif /* DUK_F_C99 etc */ + /* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics, - * see test-bug-netbsd-math-pow.js. Use NetBSD specific workaround. - * (This might be a wider problem; if so, generalize the define name.) + * see test-bug-netbsd-math-pow.js. MinGW has similar (but different) + * issues, see test-bug-mingw-math-issues.js. Enable pow() workarounds + * for these targets. + */ +#undef DUK_USE_POW_WORKAROUNDS +#if defined(DUK_F_NETBSD) || defined(DUK_F_MINGW) +#define DUK_USE_POW_WORKAROUNDS +#endif + +/* Similar workarounds for atan2() semantics issues. MinGW issues are + * documented in test-bug-mingw-math-issues.js. */ -#undef DUK_USE_POW_NETBSD_WORKAROUND -#if defined(DUK_F_NETBSD) -#define DUK_USE_POW_NETBSD_WORKAROUND +#undef DUK_USE_ATAN2_WORKAROUNDS +#if defined(DUK_F_MINGW) +#define DUK_USE_ATAN2_WORKAROUNDS #endif /* Rely as little as possible on compiler behavior for NaN comparison, @@ -2304,25 +2345,6 @@ typedef FILE duk_file; * byte order for doubles is referred to as "mixed endian". */ -/* For custom platforms allow user to define byteorder explicitly. - * Since endianness headers are not standardized, this is a useful - * workaround for custom platforms for which endianness detection - * is not directly supported. Perhaps custom hardware is used and - * user cannot submit upstream patches. - */ -#if defined(DUK_OPT_FORCE_BYTEORDER) -#undef DUK_USE_BYTEORDER -#if (DUK_OPT_FORCE_BYTEORDER == 1) -#define DUK_USE_BYTEORDER 1 -#elif (DUK_OPT_FORCE_BYTEORDER == 2) -#define DUK_USE_BYTEORDER 2 -#elif (DUK_OPT_FORCE_BYTEORDER == 3) -#define DUK_USE_BYTEORDER 3 -#else -#error invalid DUK_OPT_FORCE_BYTEORDER value -#endif -#endif /* DUK_OPT_FORCE_BYTEORDER */ - /* GCC and Clang provide endianness defines as built-in predefines, with * leading and trailing double underscores (e.g. __BYTE_ORDER__). See * output of "make gccpredefs" and "make clangpredefs". Clang doesn't @@ -2425,18 +2447,6 @@ typedef FILE duk_file; #define DUK_USE_ALIGN_BY 8 #endif -/* User forced alignment to 4 or 8. */ -#if defined(DUK_OPT_FORCE_ALIGN) -#undef DUK_USE_ALIGN_BY -#if (DUK_OPT_FORCE_ALIGN == 4) -#define DUK_USE_ALIGN_BY 4 -#elif (DUK_OPT_FORCE_ALIGN == 8) -#define DUK_USE_ALIGN_BY 8 -#else -#error invalid DUK_OPT_FORCE_ALIGN value -#endif -#endif - /* Compiler specific hackery needed to force struct size to match aligment, * see e.g. duk_hbuffer.h. * @@ -2479,9 +2489,8 @@ typedef FILE duk_file; #endif #if !defined(DUK_CAUSE_SEGFAULT) -/* This is optionally used by panic handling to cause the program to segfault - * (instead of e.g. abort()) on panic. Valgrind will then indicate the C - * call stack leading to the panic. +/* This can be used for testing; valgrind will then indicate the C call stack + * leading to the call site. */ #define DUK_CAUSE_SEGFAULT() do { *((volatile duk_uint32_t *) NULL) = (duk_uint32_t) 0xdeadbeefUL; } while (0) #endif @@ -2517,6 +2526,9 @@ typedef FILE duk_file; #if !defined(DUK_UNLIKELY) #define DUK_UNLIKELY(x) (x) #endif +#if !defined(DUK_UNPREDICTABLE) +#define DUK_UNPREDICTABLE(x) (x) +#endif #if !defined(DUK_NOINLINE) #define DUK_NOINLINE /*nop*/ @@ -2656,14 +2668,6 @@ typedef FILE duk_file; #undef DUK_F_PACKED_TVAL_POSSIBLE #endif /* DUK_F_PACKED_TVAL_PROVIDED */ - -/* Feature option forcing. */ -#if defined(DUK_OPT_NO_PACKED_TVAL) -#undef DUK_USE_PACKED_TVAL -#elif defined(DUK_OPT_PACKED_TVAL) -#undef DUK_USE_PACKED_TVAL -#define DUK_USE_PACKED_TVAL -#endif /* Object property allocation layout has implications for memory and code * footprint and generated code size/speed. The best layout also depends * on whether the platform has alignment requirements or benefits from @@ -2694,852 +2698,170 @@ typedef FILE duk_file; #endif /* - * Feature option handling + * Autogenerated defaults */ -#if !defined(DUK_USE_ALIGN_BY) -#if defined(DUK_OPT_FORCE_ALIGN) -#define DUK_USE_ALIGN_BY DUK_OPT_FORCE_ALIGN -#else -#define DUK_USE_ALIGN_BY 8 -#endif -#endif - -#if defined(DUK_OPT_ASSERTIONS) -#define DUK_USE_ASSERTIONS -#elif defined(DUK_OPT_NO_ASSERTIONS) -#undef DUK_USE_ASSERTIONS -#else +#define DUK_USE_ARRAY_BUILTIN +#define DUK_USE_ARRAY_FASTPATH +#define DUK_USE_ARRAY_PROP_FASTPATH #undef DUK_USE_ASSERTIONS -#endif - -#if defined(DUK_OPT_AUGMENT_ERRORS) -#define DUK_USE_AUGMENT_ERROR_CREATE -#elif defined(DUK_OPT_NO_AUGMENT_ERRORS) -#undef DUK_USE_AUGMENT_ERROR_CREATE -#else #define DUK_USE_AUGMENT_ERROR_CREATE -#endif - -#if defined(DUK_OPT_AUGMENT_ERRORS) -#define DUK_USE_AUGMENT_ERROR_THROW -#elif defined(DUK_OPT_NO_AUGMENT_ERRORS) -#undef DUK_USE_AUGMENT_ERROR_THROW -#else #define DUK_USE_AUGMENT_ERROR_THROW -#endif - -#if defined(DUK_OPT_BROWSER_LIKE) -#define DUK_USE_BROWSER_LIKE -#elif defined(DUK_OPT_NO_BROWSER_LIKE) -#undef DUK_USE_BROWSER_LIKE -#else -#define DUK_USE_BROWSER_LIKE -#endif - -#if defined(DUK_OPT_BUFFEROBJECT_SUPPORT) -#define DUK_USE_BUFFEROBJECT_SUPPORT -#elif defined(DUK_OPT_NO_BUFFEROBJECT_SUPPORT) -#undef DUK_USE_BUFFEROBJECT_SUPPORT -#else +#define DUK_USE_AVOID_PLATFORM_FUNCPTRS +#define DUK_USE_BASE64_FASTPATH +#define DUK_USE_BOOLEAN_BUILTIN #define DUK_USE_BUFFEROBJECT_SUPPORT -#endif - -#if defined(DUK_OPT_BUFLEN16) -#define DUK_USE_BUFLEN16 -#elif defined(DUK_OPT_NO_BUFLEN16) -#undef DUK_USE_BUFLEN16 -#else #undef DUK_USE_BUFLEN16 -#endif - -#if defined(DUK_OPT_BYTECODE_DUMP_SUPPORT) -#define DUK_USE_BYTECODE_DUMP_SUPPORT -#elif defined(DUK_OPT_NO_BYTECODE_DUMP_SUPPORT) -#undef DUK_USE_BYTECODE_DUMP_SUPPORT -#else #define DUK_USE_BYTECODE_DUMP_SUPPORT -#endif - -#if defined(DUK_OPT_COMMONJS_MODULES) -#define DUK_USE_COMMONJS_MODULES -#elif defined(DUK_OPT_NO_COMMONJS_MODULES) -#undef DUK_USE_COMMONJS_MODULES -#else #define DUK_USE_COMMONJS_MODULES -#endif - -#if defined(DUK_OPT_CPP_EXCEPTIONS) -#define DUK_USE_CPP_EXCEPTIONS -#elif defined(DUK_OPT_NO_CPP_EXCEPTIONS) -#undef DUK_USE_CPP_EXCEPTIONS -#else +#define DUK_USE_COMPILER_RECLIMIT 2500 +#define DUK_USE_COROUTINE_SUPPORT #undef DUK_USE_CPP_EXCEPTIONS -#endif - -#if defined(DUK_OPT_DATAPTR16) -#define DUK_USE_DATAPTR16 -#elif defined(DUK_OPT_NO_DATAPTR16) -#undef DUK_USE_DATAPTR16 -#else #undef DUK_USE_DATAPTR16 -#endif - -#if defined(DUK_OPT_DATAPTR_DEC16) -#define DUK_USE_DATAPTR_DEC16(udata,ptr) DUK_OPT_DATAPTR_DEC16((udata),(ptr)) -#else #undef DUK_USE_DATAPTR_DEC16 -#endif - -#if defined(DUK_OPT_DATAPTR_ENC16) -#define DUK_USE_DATAPTR_ENC16(udata,ptr) DUK_OPT_DATAPTR_ENC16((udata),(ptr)) -#else #undef DUK_USE_DATAPTR_ENC16 -#endif - -#if defined(DUK_OPT_DDDPRINT) -#define DUK_USE_DDDPRINT -#elif defined(DUK_OPT_NO_DDDPRINT) -#undef DUK_USE_DDDPRINT -#else -#undef DUK_USE_DDDPRINT -#endif - -#if defined(DUK_OPT_DDPRINT) -#define DUK_USE_DDPRINT -#elif defined(DUK_OPT_NO_DDPRINT) -#undef DUK_USE_DDPRINT -#else -#undef DUK_USE_DDPRINT -#endif - -#if defined(DUK_OPT_DEBUG) -#define DUK_USE_DEBUG -#elif defined(DUK_OPT_NO_DEBUG) -#undef DUK_USE_DEBUG -#else +#define DUK_USE_DATE_BUILTIN +#undef DUK_USE_DATE_FORMAT_STRING +#undef DUK_USE_DATE_GET_LOCAL_TZOFFSET +#undef DUK_USE_DATE_GET_NOW +#undef DUK_USE_DATE_PARSE_STRING +#undef DUK_USE_DATE_PRS_GETDATE #undef DUK_USE_DEBUG -#endif - -#if defined(DUK_OPT_DEBUGGER_DUMPHEAP) -#define DUK_USE_DEBUGGER_DUMPHEAP -#elif defined(DUK_OPT_NO_DEBUGGER_DUMPHEAP) #undef DUK_USE_DEBUGGER_DUMPHEAP -#else -#undef DUK_USE_DEBUGGER_DUMPHEAP -#endif - -#if defined(DUK_OPT_DEBUGGER_FWD_LOGGING) -#define DUK_USE_DEBUGGER_FWD_LOGGING -#elif defined(DUK_OPT_NO_DEBUGGER_FWD_LOGGING) -#undef DUK_USE_DEBUGGER_FWD_LOGGING -#else -#undef DUK_USE_DEBUGGER_FWD_LOGGING -#endif - -#if defined(DUK_OPT_DEBUGGER_FWD_PRINTALERT) -#define DUK_USE_DEBUGGER_FWD_PRINTALERT -#elif defined(DUK_OPT_NO_DEBUGGER_FWD_PRINTALERT) -#undef DUK_USE_DEBUGGER_FWD_PRINTALERT -#else -#undef DUK_USE_DEBUGGER_FWD_PRINTALERT -#endif - -#if defined(DUK_OPT_DEBUGGER_INSPECT) -#define DUK_USE_DEBUGGER_INSPECT -#elif defined(DUK_OPT_NO_DEBUGGER_INSPECT) -#undef DUK_USE_DEBUGGER_INSPECT -#else #undef DUK_USE_DEBUGGER_INSPECT -#endif - -#if defined(DUK_OPT_DEBUGGER_PAUSE_UNCAUGHT) -#define DUK_USE_DEBUGGER_PAUSE_UNCAUGHT -#elif defined(DUK_OPT_NO_DEBUGGER_PAUSE_UNCAUGHT) -#undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT -#else #undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT -#endif - -#if defined(DUK_OPT_DEBUGGER_SUPPORT) -#define DUK_USE_DEBUGGER_SUPPORT -#elif defined(DUK_OPT_NO_DEBUGGER_SUPPORT) -#undef DUK_USE_DEBUGGER_SUPPORT -#else #undef DUK_USE_DEBUGGER_SUPPORT -#endif - -#if defined(DUK_OPT_DEBUGGER_THROW_NOTIFY) -#define DUK_USE_DEBUGGER_THROW_NOTIFY -#elif defined(DUK_OPT_NO_DEBUGGER_THROW_NOTIFY) -#undef DUK_USE_DEBUGGER_THROW_NOTIFY -#else #define DUK_USE_DEBUGGER_THROW_NOTIFY -#endif - -#if defined(DUK_OPT_DEBUGGER_TRANSPORT_TORTURE) -#define DUK_USE_DEBUGGER_TRANSPORT_TORTURE -#elif defined(DUK_OPT_NO_DEBUGGER_TRANSPORT_TORTURE) -#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE -#else #undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE -#endif - -#if defined(DUK_OPT_DEBUG_BUFSIZE) -#define DUK_USE_DEBUG_BUFSIZE DUK_OPT_DEBUG_BUFSIZE -#else #define DUK_USE_DEBUG_BUFSIZE 65536L -#endif - -#if defined(DUK_OPT_REFERENCE_COUNTING) -#define DUK_USE_DOUBLE_LINKED_HEAP -#elif defined(DUK_OPT_NO_REFERENCE_COUNTING) -#undef DUK_USE_DOUBLE_LINKED_HEAP -#else +#define DUK_USE_DEBUG_LEVEL 0 +#undef DUK_USE_DEBUG_WRITE #define DUK_USE_DOUBLE_LINKED_HEAP -#endif - -#if defined(DUK_OPT_DPRINT) -#define DUK_USE_DPRINT -#elif defined(DUK_OPT_NO_DPRINT) -#undef DUK_USE_DPRINT -#else -#undef DUK_USE_DPRINT -#endif - -#if defined(DUK_OPT_DPRINT_COLORS) -#define DUK_USE_DPRINT_COLORS -#elif defined(DUK_OPT_NO_DPRINT_COLORS) -#undef DUK_USE_DPRINT_COLORS -#else -#undef DUK_USE_DPRINT_COLORS -#endif - -#if defined(DUK_OPT_DPRINT_RDTSC) -#define DUK_USE_DPRINT_RDTSC -#elif defined(DUK_OPT_NO_DPRINT_RDTSC) -#undef DUK_USE_DPRINT_RDTSC -#else -#undef DUK_USE_DPRINT_RDTSC -#endif - -#if defined(DUK_OPT_AUGMENT_ERRORS) -#define DUK_USE_ERRCREATE -#elif defined(DUK_OPT_NO_AUGMENT_ERRORS) -#undef DUK_USE_ERRCREATE -#else +#define DUK_USE_DUKTAPE_BUILTIN +#define DUK_USE_ENCODING_BUILTINS #define DUK_USE_ERRCREATE -#endif - -#if defined(DUK_OPT_AUGMENT_ERRORS) -#define DUK_USE_ERRTHROW -#elif defined(DUK_OPT_NO_AUGMENT_ERRORS) -#undef DUK_USE_ERRTHROW -#else #define DUK_USE_ERRTHROW -#endif - -#if defined(DUK_OPT_ES6_OBJECT_PROTO_PROPERTY) -#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY -#elif defined(DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY) -#undef DUK_USE_ES6_OBJECT_PROTO_PROPERTY -#else +#define DUK_USE_ES6 #define DUK_USE_ES6_OBJECT_PROTO_PROPERTY -#endif - -#if defined(DUK_OPT_ES6_OBJECT_SETPROTOTYPEOF) #define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF -#elif defined(DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF) -#undef DUK_USE_ES6_OBJECT_SETPROTOTYPEOF -#else -#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF -#endif - -#if defined(DUK_OPT_ES6_PROXY) #define DUK_USE_ES6_PROXY -#elif defined(DUK_OPT_NO_ES6_PROXY) -#undef DUK_USE_ES6_PROXY -#else -#define DUK_USE_ES6_PROXY -#endif - -#if defined(DUK_OPT_ES6_REGEXP_BRACES) -#define DUK_USE_ES6_REGEXP_BRACES -#elif defined(DUK_OPT_NO_ES6_REGEXP_BRACES) -#undef DUK_USE_ES6_REGEXP_BRACES -#else -#define DUK_USE_ES6_REGEXP_BRACES -#endif - +#define DUK_USE_ES6_REGEXP_SYNTAX +#define DUK_USE_ES6_UNICODE_ESCAPE +#define DUK_USE_ES7_EXP_OPERATOR +#define DUK_USE_ESBC_LIMITS +#define DUK_USE_ESBC_MAX_BYTES 2147418112L +#define DUK_USE_ESBC_MAX_LINENUMBER 2147418112L +#undef DUK_USE_EXEC_FUN_LOCAL #undef DUK_USE_EXEC_INDIRECT_BOUND_CHECK -#if defined(DUK_OPT_DEBUG) || defined(DUK_OPT_ASSERTIONS) -/* Enabled with debug/assertions just so that any issues can be caught. */ -#define DUK_USE_EXEC_INDIRECT_BOUND_CHECK -#endif - +#undef DUK_USE_EXEC_PREFER_SIZE +#define DUK_USE_EXEC_REGCONST_OPTIMIZE #undef DUK_USE_EXEC_TIMEOUT_CHECK -#if defined(DUK_OPT_EXEC_TIMEOUT_CHECK) -#define DUK_USE_EXEC_TIMEOUT_CHECK(udata) DUK_OPT_EXEC_TIMEOUT_CHECK((udata)) -#endif - +#undef DUK_USE_EXPLICIT_NULL_INIT #undef DUK_USE_EXTSTR_FREE -#if defined(DUK_OPT_EXTERNAL_STRINGS) && defined(DUK_OPT_EXTSTR_FREE) -#define DUK_USE_EXTSTR_FREE(udata,ptr) DUK_OPT_EXTSTR_FREE((udata), (ptr)) -#endif - #undef DUK_USE_EXTSTR_INTERN_CHECK -#if defined(DUK_OPT_EXTERNAL_STRINGS) && defined(DUK_OPT_EXTSTR_INTERN_CHECK) -#define DUK_USE_EXTSTR_INTERN_CHECK(udata,ptr,len) DUK_OPT_EXTSTR_INTERN_CHECK((udata), (ptr), (len)) -#endif - -/* Support for 48-bit signed integer duk_tval with transparent semantics. */ #undef DUK_USE_FASTINT -#if defined(DUK_OPT_FASTINT) -#if !defined(DUK_F_HAVE_64BIT) -#error DUK_OPT_FASTINT requires 64-bit integer type support at the moment -#endif -#define DUK_USE_FASTINT -#endif - -#if defined(DUK_OPT_FILE_IO) -#define DUK_USE_FILE_IO -#elif defined(DUK_OPT_NO_FILE_IO) -#undef DUK_USE_FILE_IO -#else -#define DUK_USE_FILE_IO -#endif - -#if defined(DUK_OPT_FUNCPTR16) -#define DUK_USE_FUNCPTR16 -#elif defined(DUK_OPT_NO_FUNCPTR16) -#undef DUK_USE_FUNCPTR16 -#else +#define DUK_USE_FAST_REFCOUNT_DEFAULT +#undef DUK_USE_FATAL_HANDLER +#define DUK_USE_FINALIZER_SUPPORT #undef DUK_USE_FUNCPTR16 -#endif - -#if defined(DUK_OPT_FUNCPTR_DEC16) -#define DUK_USE_FUNCPTR_DEC16(udata,ptr) DUK_OPT_FUNCPTR_DEC16((udata),(ptr)) -#else #undef DUK_USE_FUNCPTR_DEC16 -#endif - -#if defined(DUK_OPT_FUNCPTR_ENC16) -#define DUK_USE_FUNCPTR_ENC16(udata,ptr) DUK_OPT_FUNCPTR_ENC16((udata),(ptr)) -#else #undef DUK_USE_FUNCPTR_ENC16 -#endif - -#if defined(DUK_OPT_GC_TORTURE) -#define DUK_USE_GC_TORTURE -#elif defined(DUK_OPT_NO_GC_TORTURE) -#undef DUK_USE_GC_TORTURE -#else +#define DUK_USE_FUNCTION_BUILTIN +#define DUK_USE_FUNC_FILENAME_PROPERTY +#define DUK_USE_FUNC_NAME_PROPERTY #undef DUK_USE_GC_TORTURE -#endif - -#if defined(DUK_OPT_HEAPPTR16) -#define DUK_USE_HEAPPTR16 -#elif defined(DUK_OPT_NO_HEAPPTR16) -#undef DUK_USE_HEAPPTR16 -#else +#undef DUK_USE_GET_RANDOM_DOUBLE +#define DUK_USE_GLOBAL_BUILTIN #undef DUK_USE_HEAPPTR16 -#endif - -#if defined(DUK_OPT_HEAPPTR_DEC16) -#define DUK_USE_HEAPPTR_DEC16(udata,ptr) DUK_OPT_HEAPPTR_DEC16((udata),(ptr)) -#else #undef DUK_USE_HEAPPTR_DEC16 -#endif - -#if defined(DUK_OPT_HEAPPTR_ENC16) -#define DUK_USE_HEAPPTR_ENC16(udata,ptr) DUK_OPT_HEAPPTR_ENC16((udata),(ptr)) -#else #undef DUK_USE_HEAPPTR_ENC16 -#endif - -/* For now, hash part is dropped if and only if 16-bit object fields are used. */ +#define DUK_USE_HEX_FASTPATH #define DUK_USE_HOBJECT_HASH_PART -#if defined(DUK_OPT_OBJSIZES16) -#undef DUK_USE_HOBJECT_HASH_PART -#endif - -#if defined(DUK_OPT_HSTRING_CLEN) -#define DUK_USE_HSTRING_CLEN -#elif defined(DUK_OPT_NO_HSTRING_CLEN) -#undef DUK_USE_HSTRING_CLEN -#else +#define DUK_USE_HSTRING_ARRIDX #define DUK_USE_HSTRING_CLEN -#endif - -#if defined(DUK_OPT_EXTERNAL_STRINGS) -#define DUK_USE_HSTRING_EXTDATA -#elif defined(DUK_OPT_NO_EXTERNAL_STRINGS) #undef DUK_USE_HSTRING_EXTDATA -#else -#undef DUK_USE_HSTRING_EXTDATA -#endif - -#if defined(DUK_OPT_INTERRUPT_COUNTER) -#define DUK_USE_INTERRUPT_COUNTER -#elif defined(DUK_OPT_NO_INTERRUPT_COUNTER) -#undef DUK_USE_INTERRUPT_COUNTER -#else +#define DUK_USE_IDCHAR_FASTPATH #undef DUK_USE_INTERRUPT_COUNTER -#endif - -#if defined(DUK_OPT_JC) -#define DUK_USE_JC -#elif defined(DUK_OPT_NO_JC) -#undef DUK_USE_JC -#else +#undef DUK_USE_INTERRUPT_DEBUG_FIXUP #define DUK_USE_JC -#endif - -#if defined(DUK_OPT_JSON_STRINGIFY_FASTPATH) -#define DUK_USE_JSON_STRINGIFY_FASTPATH -#elif defined(DUK_OPT_NO_JSON_STRINGIFY_FASTPATH) -#undef DUK_USE_JSON_STRINGIFY_FASTPATH -#else +#define DUK_USE_JSON_BUILTIN +#define DUK_USE_JSON_DECNUMBER_FASTPATH +#define DUK_USE_JSON_DECSTRING_FASTPATH +#define DUK_USE_JSON_DEC_RECLIMIT 1000 +#define DUK_USE_JSON_EATWHITE_FASTPATH +#define DUK_USE_JSON_ENC_RECLIMIT 1000 +#define DUK_USE_JSON_QUOTESTRING_FASTPATH #undef DUK_USE_JSON_STRINGIFY_FASTPATH -#endif - -#if defined(DUK_OPT_JX) -#define DUK_USE_JX -#elif defined(DUK_OPT_NO_JX) -#undef DUK_USE_JX -#else +#define DUK_USE_JSON_SUPPORT #define DUK_USE_JX -#endif - -#if defined(DUK_OPT_LIGHTFUNC_BUILTINS) -#define DUK_USE_LIGHTFUNC_BUILTINS -#elif defined(DUK_OPT_NO_LIGHTFUNC_BUILTINS) -#undef DUK_USE_LIGHTFUNC_BUILTINS -#else +#define DUK_USE_LEXER_SLIDING_WINDOW #undef DUK_USE_LIGHTFUNC_BUILTINS -#endif - -#if defined(DUK_OPT_MARK_AND_SWEEP) -#define DUK_USE_MARK_AND_SWEEP -#elif defined(DUK_OPT_NO_MARK_AND_SWEEP) -#undef DUK_USE_MARK_AND_SWEEP -#else -#define DUK_USE_MARK_AND_SWEEP -#endif - -#if defined(DUK_OPT_MS_STRINGTABLE_RESIZE) -#define DUK_USE_MS_STRINGTABLE_RESIZE -#elif defined(DUK_OPT_NO_MS_STRINGTABLE_RESIZE) -#undef DUK_USE_MS_STRINGTABLE_RESIZE -#else +#undef DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE +#define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256 +#define DUK_USE_MATH_BUILTIN #define DUK_USE_MS_STRINGTABLE_RESIZE -#endif - -#if defined(DUK_OPT_NONSTD_ARRAY_CONCAT_TRAILER) -#define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER -#elif defined(DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER) -#undef DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER -#else +#define DUK_USE_NATIVE_CALL_RECLIMIT 1000 #define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER -#endif - -#if defined(DUK_OPT_NONSTD_ARRAY_MAP_TRAILER) -#define DUK_USE_NONSTD_ARRAY_MAP_TRAILER -#elif defined(DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER) -#undef DUK_USE_NONSTD_ARRAY_MAP_TRAILER -#else #define DUK_USE_NONSTD_ARRAY_MAP_TRAILER -#endif - -#if defined(DUK_OPT_NONSTD_ARRAY_SPLICE_DELCOUNT) -#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT -#elif defined(DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT) -#undef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT -#else #define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT -#endif - -#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY) -#define DUK_USE_NONSTD_FUNC_CALLER_PROPERTY -#elif defined(DUK_OPT_NO_NONSTD_FUNC_CALLER_PROPERTY) #undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY -#else -#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY -#endif - -#if defined(DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY) -#define DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY -#elif defined(DUK_OPT_NO_NONSTD_FUNC_SOURCE_PROPERTY) #undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY -#else -#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY -#endif - -#if defined(DUK_OPT_NONSTD_FUNC_STMT) -#define DUK_USE_NONSTD_FUNC_STMT -#elif defined(DUK_OPT_NO_NONSTD_FUNC_STMT) -#undef DUK_USE_NONSTD_FUNC_STMT -#else #define DUK_USE_NONSTD_FUNC_STMT -#endif - -#if defined(DUK_OPT_NONSTD_ACCESSOR_KEY_ARGUMENT) #define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT -#elif defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT) -#undef DUK_USE_NONSTD_GETTER_KEY_ARGUMENT -#else -#define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT -#endif - -#if defined(DUK_OPT_NONSTD_JSON_ESC_U2028_U2029) #define DUK_USE_NONSTD_JSON_ESC_U2028_U2029 -#elif defined(DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029) -#undef DUK_USE_NONSTD_JSON_ESC_U2028_U2029 -#else -#define DUK_USE_NONSTD_JSON_ESC_U2028_U2029 -#endif - -#if defined(DUK_OPT_NONSTD_REGEXP_DOLLAR_ESCAPE) -#define DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE -#elif defined(DUK_OPT_NO_NONSTD_REGEXP_DOLLAR_ESCAPE) -#undef DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE -#else -#define DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE -#endif - -#if defined(DUK_OPT_NONSTD_ACCESSOR_KEY_ARGUMENT) -#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT -#elif defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT) -#undef DUK_USE_NONSTD_SETTER_KEY_ARGUMENT -#else #define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT -#endif - -#if defined(DUK_OPT_NONSTD_STRING_FROMCHARCODE_32BIT) -#define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT -#elif defined(DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT) -#undef DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT -#else #define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT -#endif - -#if defined(DUK_OPT_OBJSIZES16) -#define DUK_USE_OBJSIZES16 -#elif defined(DUK_OPT_NO_OBJSIZES16) +#define DUK_USE_NUMBER_BUILTIN +#define DUK_USE_OBJECT_BUILTIN #undef DUK_USE_OBJSIZES16 -#else -#undef DUK_USE_OBJSIZES16 -#endif - -#if defined(DUK_OPT_OCTAL_SUPPORT) -#define DUK_USE_OCTAL_SUPPORT -#elif defined(DUK_OPT_NO_OCTAL_SUPPORT) -#undef DUK_USE_OCTAL_SUPPORT -#else -#define DUK_USE_OCTAL_SUPPORT -#endif - -#if defined(DUK_OPT_PACKED_TVAL) -#define DUK_USE_PACKED_TVAL -#elif defined(DUK_OPT_NO_PACKED_TVAL) -#undef DUK_USE_PACKED_TVAL -#else -/* Already provided above */ -#endif - -#undef DUK_USE_PANIC_ABORT -#if !defined(DUK_OPT_SEGFAULT_ON_PANIC) -#define DUK_USE_PANIC_ABORT -#endif - -#undef DUK_USE_PANIC_HANDLER -#if defined(DUK_OPT_PANIC_HANDLER) -#define DUK_USE_PANIC_HANDLER(code,msg) DUK_OPT_PANIC_HANDLER((code),(msg)) -#endif - -#undef DUK_USE_PANIC_SEGFAULT -#if defined(DUK_OPT_SEGFAULT_ON_PANIC) -#define DUK_USE_PANIC_SEGFAULT -#endif - -#if defined(DUK_OPT_PARANOID_ERRORS) -#define DUK_USE_PARANOID_ERRORS -#elif defined(DUK_OPT_NO_PARANOID_ERRORS) #undef DUK_USE_PARANOID_ERRORS -#else -#undef DUK_USE_PARANOID_ERRORS -#endif - -#if defined(DUK_OPT_PC2LINE) #define DUK_USE_PC2LINE -#elif defined(DUK_OPT_NO_PC2LINE) -#undef DUK_USE_PC2LINE -#else -#define DUK_USE_PC2LINE -#endif - -#if defined(DUK_OPT_REFCOUNT16) -#define DUK_USE_REFCOUNT16 -#elif defined(DUK_OPT_NO_REFCOUNT16) -#undef DUK_USE_REFCOUNT16 -#else +#undef DUK_USE_PREFER_SIZE +#define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS #undef DUK_USE_REFCOUNT16 -#endif - -#if defined(DUK_OPT_REFERENCE_COUNTING) -#define DUK_USE_REFERENCE_COUNTING -#elif defined(DUK_OPT_NO_REFERENCE_COUNTING) -#undef DUK_USE_REFERENCE_COUNTING -#else #define DUK_USE_REFERENCE_COUNTING -#endif - -#if defined(DUK_OPT_REGEXP_CANON_WORKAROUND) -#define DUK_USE_REGEXP_CANON_WORKAROUND -#elif defined(DUK_OPT_NO_REGEXP_CANON_WORKAROUND) -#undef DUK_USE_REGEXP_CANON_WORKAROUND -#else +#define DUK_USE_REFLECT_BUILTIN +#undef DUK_USE_REFZERO_FINALIZER_TORTURE #undef DUK_USE_REGEXP_CANON_WORKAROUND -#endif - -#if defined(DUK_OPT_REGEXP_SUPPORT) -#define DUK_USE_REGEXP_SUPPORT -#elif defined(DUK_OPT_NO_REGEXP_SUPPORT) -#undef DUK_USE_REGEXP_SUPPORT -#else +#define DUK_USE_REGEXP_COMPILER_RECLIMIT 10000 +#define DUK_USE_REGEXP_EXECUTOR_RECLIMIT 10000 #define DUK_USE_REGEXP_SUPPORT -#endif - -#if defined(DUK_OPT_ROM_GLOBAL_CLONE) -#define DUK_USE_ROM_GLOBAL_CLONE -#elif defined(DUK_OPT_NO_ROM_GLOBAL_CLONE) #undef DUK_USE_ROM_GLOBAL_CLONE -#else -#undef DUK_USE_ROM_GLOBAL_CLONE -#endif - -#if defined(DUK_OPT_ROM_GLOBAL_INHERIT) -#define DUK_USE_ROM_GLOBAL_INHERIT -#elif defined(DUK_OPT_NO_ROM_GLOBAL_INHERIT) -#undef DUK_USE_ROM_GLOBAL_INHERIT -#else #undef DUK_USE_ROM_GLOBAL_INHERIT -#endif - -#if defined(DUK_OPT_ROM_OBJECTS) -#define DUK_USE_ROM_OBJECTS -#elif defined(DUK_OPT_NO_ROM_OBJECTS) #undef DUK_USE_ROM_OBJECTS -#else -#undef DUK_USE_ROM_OBJECTS -#endif - -#if defined(DUK_OPT_ROM_STRINGS) -#define DUK_USE_ROM_STRINGS -#elif defined(DUK_OPT_NO_ROM_STRINGS) -#undef DUK_USE_ROM_STRINGS -#else +#define DUK_USE_ROM_PTRCOMP_FIRST 63488L #undef DUK_USE_ROM_STRINGS -#endif - -#if defined(DUK_OPT_SECTION_B) -#define DUK_USE_SECTION_B -#elif defined(DUK_OPT_NO_SECTION_B) -#undef DUK_USE_SECTION_B -#else #define DUK_USE_SECTION_B -#endif - -#if defined(DUK_OPT_SELF_TESTS) -#define DUK_USE_SELF_TESTS -#elif defined(DUK_OPT_NO_SELF_TESTS) #undef DUK_USE_SELF_TESTS -#else -#undef DUK_USE_SELF_TESTS -#endif - -#if defined(DUK_OPT_SHUFFLE_TORTURE) -#define DUK_USE_SHUFFLE_TORTURE -#elif defined(DUK_OPT_NO_SHUFFLE_TORTURE) #undef DUK_USE_SHUFFLE_TORTURE -#else -#undef DUK_USE_SHUFFLE_TORTURE -#endif - -#if defined(DUK_OPT_SOURCE_NONBMP) -#define DUK_USE_SOURCE_NONBMP -#elif defined(DUK_OPT_NO_SOURCE_NONBMP) -#undef DUK_USE_SOURCE_NONBMP -#else #define DUK_USE_SOURCE_NONBMP -#endif - -#if defined(DUK_OPT_STRHASH16) -#define DUK_USE_STRHASH16 -#elif defined(DUK_OPT_NO_STRHASH16) #undef DUK_USE_STRHASH16 -#else -#undef DUK_USE_STRHASH16 -#endif - -#if defined(DUK_OPT_STRICT_DECL) -#define DUK_USE_STRICT_DECL -#elif defined(DUK_OPT_NO_STRICT_DECL) -#undef DUK_USE_STRICT_DECL -#else +#undef DUK_USE_STRHASH_DENSE +#define DUK_USE_STRHASH_SKIP_SHIFT 5 #define DUK_USE_STRICT_DECL -#endif - -#if defined(DUK_OPT_STRICT_UTF8_SOURCE) -#define DUK_USE_STRICT_UTF8_SOURCE -#elif defined(DUK_OPT_NO_STRICT_UTF8_SOURCE) #undef DUK_USE_STRICT_UTF8_SOURCE -#else -#undef DUK_USE_STRICT_UTF8_SOURCE -#endif - -#if defined(DUK_OPT_STRLEN16) -#define DUK_USE_STRLEN16 -#elif defined(DUK_OPT_NO_STRLEN16) -#undef DUK_USE_STRLEN16 -#else +#define DUK_USE_STRING_BUILTIN #undef DUK_USE_STRLEN16 -#endif - #undef DUK_USE_STRTAB_CHAIN -#if defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE) -#define DUK_USE_STRTAB_CHAIN -#endif - #undef DUK_USE_STRTAB_CHAIN_SIZE -#if defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE) -/* Low memory algorithm: separate chaining using arrays, fixed size hash */ -#define DUK_USE_STRTAB_CHAIN_SIZE DUK_OPT_STRTAB_CHAIN_SIZE -#endif - -#undef DUK_USE_STRTAB_PROBE -#if !(defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE)) #define DUK_USE_STRTAB_PROBE -#endif - -#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY) -#undef DUK_USE_TAILCALL -#else +#undef DUK_USE_SYMBOL_BUILTIN #define DUK_USE_TAILCALL -#endif - -#if defined(DUK_OPT_TARGET_INFO) -#define DUK_USE_TARGET_INFO DUK_OPT_TARGET_INFO -#else #define DUK_USE_TARGET_INFO "unknown" -#endif - -#if defined(DUK_OPT_NO_AUGMENT_ERRORS) -#undef DUK_USE_TRACEBACKS -#elif defined(DUK_OPT_NO_TRACEBACKS) -#undef DUK_USE_TRACEBACKS -#else #define DUK_USE_TRACEBACKS -#endif - -#if defined(DUK_OPT_TRACEBACK_DEPTH) -#define DUK_USE_TRACEBACK_DEPTH DUK_OPT_TRACEBACK_DEPTH -#else -#define DUK_USE_TRACEBACK_DEPTH 10 -#endif - -#if defined(DUK_OPT_DECLARE) -#define DUK_USE_USER_DECLARE() DUK_OPT_DECLARE -#else +#define DUK_USE_TRACEBACK_DEPTH 10 #define DUK_USE_USER_DECLARE() /* no user declarations */ -#endif - -/* User provided InitJS. */ -#undef DUK_USE_USER_INITJS -#if defined(DUK_OPT_USER_INITJS) -#define DUK_USE_USER_INITJS (DUK_OPT_USER_INITJS) -#endif - -#if defined(DUK_OPT_VERBOSE_ERRORS) -#define DUK_USE_VERBOSE_ERRORS -#elif defined(DUK_OPT_NO_VERBOSE_ERRORS) -#undef DUK_USE_VERBOSE_ERRORS -#else +#undef DUK_USE_VALSTACK_UNSAFE #define DUK_USE_VERBOSE_ERRORS -#endif - -#if defined(DUK_OPT_VOLUNTARY_GC) -#define DUK_USE_VOLUNTARY_GC -#elif defined(DUK_OPT_NO_VOLUNTARY_GC) -#undef DUK_USE_VOLUNTARY_GC -#else +#define DUK_USE_VERBOSE_EXECUTOR_ERRORS #define DUK_USE_VOLUNTARY_GC -#endif - -#if defined(DUK_OPT_ZERO_BUFFER_DATA) -#define DUK_USE_ZERO_BUFFER_DATA -#elif defined(DUK_OPT_NO_ZERO_BUFFER_DATA) -#undef DUK_USE_ZERO_BUFFER_DATA -#else #define DUK_USE_ZERO_BUFFER_DATA -#endif - -/* - * Autogenerated defaults - */ - -#define DUK_USE_AVOID_PLATFORM_FUNCPTRS -#define DUK_USE_BASE64_FASTPATH -#define DUK_USE_BUILTIN_INITJS -#define DUK_USE_COMPILER_RECLIMIT 2500 -#undef DUK_USE_DATE_FORMAT_STRING -#undef DUK_USE_DATE_GET_LOCAL_TZOFFSET -#undef DUK_USE_DATE_GET_NOW -#undef DUK_USE_DATE_PARSE_STRING -#undef DUK_USE_DATE_PRS_GETDATE -#define DUK_USE_ESBC_LIMITS -#define DUK_USE_ESBC_MAX_BYTES 2147418112L -#define DUK_USE_ESBC_MAX_LINENUMBER 2147418112L -#undef DUK_USE_EXEC_FUN_LOCAL -#undef DUK_USE_EXPLICIT_NULL_INIT -#define DUK_USE_FAST_REFCOUNT_DEFAULT -#define DUK_USE_HEX_FASTPATH -#define DUK_USE_IDCHAR_FASTPATH -#undef DUK_USE_INTERRUPT_DEBUG_FIXUP -#define DUK_USE_JSON_DECNUMBER_FASTPATH -#define DUK_USE_JSON_DECSTRING_FASTPATH -#define DUK_USE_JSON_DEC_RECLIMIT 1000 -#define DUK_USE_JSON_EATWHITE_FASTPATH -#define DUK_USE_JSON_ENC_RECLIMIT 1000 -#define DUK_USE_JSON_QUOTESTRING_FASTPATH -#define DUK_USE_LEXER_SLIDING_WINDOW -#undef DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE -#define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256 -#define DUK_USE_MATH_BUILTIN -#define DUK_USE_NATIVE_CALL_RECLIMIT 1000 -#undef DUK_USE_PANIC_EXIT -#undef DUK_USE_PREFER_SIZE -#define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS -#undef DUK_USE_REFZERO_FINALIZER_TORTURE -#define DUK_USE_REGEXP_COMPILER_RECLIMIT 10000 -#define DUK_USE_REGEXP_EXECUTOR_RECLIMIT 10000 -#define DUK_USE_ROM_PTRCOMP_FIRST 63488L -#undef DUK_USE_STRHASH_DENSE -#define DUK_USE_STRHASH_SKIP_SHIFT 5 -#undef DUK_USE_VALSTACK_UNSAFE -#define DUK_USE_VERBOSE_EXECUTOR_ERRORS /* - * Alternative customization header - * - * If you want to modify the final DUK_USE_xxx flags directly (without - * using the available DUK_OPT_xxx flags), define DUK_OPT_HAVE_CUSTOM_H - * and tweak the final flags there. + * Fixups */ -#if defined(DUK_OPT_HAVE_CUSTOM_H) #include "duk_custom.h" -#endif /* * You may add overriding #define/#undef directives below for @@ -3602,183 +2924,6 @@ typedef FILE duk_file; #endif /* DUK_COMPILING_DUKTAPE */ -/* - * Checks for config option consistency (DUK_USE_xxx) - */ - -#if defined(DUK_USE_32BIT_PTRS) -#error unsupported config option used (option has been removed): DUK_USE_32BIT_PTRS -#endif -#if defined(DUK_USE_ALIGN_4) -#error unsupported config option used (option has been removed): DUK_USE_ALIGN_4 -#endif -#if defined(DUK_USE_ALIGN_8) -#error unsupported config option used (option has been removed): DUK_USE_ALIGN_8 -#endif -#if defined(DUK_USE_BYTEORDER_FORCED) -#error unsupported config option used (option has been removed): DUK_USE_BYTEORDER_FORCED -#endif -#if defined(DUK_USE_DATAPTR_DEC16) && !defined(DUK_USE_DATAPTR16) -#error config option DUK_USE_DATAPTR_DEC16 requires option DUK_USE_DATAPTR16 (which is missing) -#endif -#if defined(DUK_USE_DATAPTR_ENC16) && !defined(DUK_USE_DATAPTR16) -#error config option DUK_USE_DATAPTR_ENC16 requires option DUK_USE_DATAPTR16 (which is missing) -#endif -#if defined(DUK_USE_DEBUGGER_SUPPORT) && !defined(DUK_USE_INTERRUPT_COUNTER) -#error config option DUK_USE_DEBUGGER_SUPPORT requires option DUK_USE_INTERRUPT_COUNTER (which is missing) -#endif -#if defined(DUK_USE_DEEP_C_STACK) -#error unsupported config option used (option has been removed): DUK_USE_DEEP_C_STACK -#endif -#if defined(DUK_USE_DOUBLE_BE) -#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_BE -#endif -#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_LE) -#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_LE (which is also defined) -#endif -#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_ME) -#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_ME (which is also defined) -#endif -#if defined(DUK_USE_DOUBLE_LE) -#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_LE -#endif -#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_BE) -#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_BE (which is also defined) -#endif -#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_ME) -#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_ME (which is also defined) -#endif -#if defined(DUK_USE_DOUBLE_ME) -#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_ME -#endif -#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_LE) -#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_LE (which is also defined) -#endif -#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_BE) -#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_BE (which is also defined) -#endif -#if defined(DUK_USE_DPRINT) && !defined(DUK_USE_DEBUG) -#error config option DUK_USE_DPRINT requires option DUK_USE_DEBUG (which is missing) -#endif -#if defined(DUK_USE_ESBC_MAX_BYTES) && !defined(DUK_USE_ESBC_LIMITS) -#error config option DUK_USE_ESBC_MAX_BYTES requires option DUK_USE_ESBC_LIMITS (which is missing) -#endif -#if defined(DUK_USE_ESBC_MAX_LINENUMBER) && !defined(DUK_USE_ESBC_LIMITS) -#error config option DUK_USE_ESBC_MAX_LINENUMBER requires option DUK_USE_ESBC_LIMITS (which is missing) -#endif -#if defined(DUK_USE_EXEC_TIMEOUT_CHECK) && !defined(DUK_USE_INTERRUPT_COUNTER) -#error config option DUK_USE_EXEC_TIMEOUT_CHECK requires option DUK_USE_INTERRUPT_COUNTER (which is missing) -#endif -#if defined(DUK_USE_EXTSTR_FREE) && !defined(DUK_USE_HSTRING_EXTDATA) -#error config option DUK_USE_EXTSTR_FREE requires option DUK_USE_HSTRING_EXTDATA (which is missing) -#endif -#if defined(DUK_USE_EXTSTR_INTERN_CHECK) && !defined(DUK_USE_HSTRING_EXTDATA) -#error config option DUK_USE_EXTSTR_INTERN_CHECK requires option DUK_USE_HSTRING_EXTDATA (which is missing) -#endif -#if defined(DUK_USE_FULL_TVAL) -#error unsupported config option used (option has been removed): DUK_USE_FULL_TVAL -#endif -#if defined(DUK_USE_FUNCPTR_DEC16) && !defined(DUK_USE_FUNCPTR16) -#error config option DUK_USE_FUNCPTR_DEC16 requires option DUK_USE_FUNCPTR16 (which is missing) -#endif -#if defined(DUK_USE_FUNCPTR_ENC16) && !defined(DUK_USE_FUNCPTR16) -#error config option DUK_USE_FUNCPTR_ENC16 requires option DUK_USE_FUNCPTR16 (which is missing) -#endif -#if defined(DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS) -#error unsupported config option used (option has been removed): DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS -#endif -#if defined(DUK_USE_HEAPPTR16) && defined(DUK_USE_DEBUG) -#error config option DUK_USE_HEAPPTR16 conflicts with option DUK_USE_DEBUG (which is also defined) -#endif -#if defined(DUK_USE_HEAPPTR_DEC16) && !defined(DUK_USE_HEAPPTR16) -#error config option DUK_USE_HEAPPTR_DEC16 requires option DUK_USE_HEAPPTR16 (which is missing) -#endif -#if defined(DUK_USE_HEAPPTR_ENC16) && !defined(DUK_USE_HEAPPTR16) -#error config option DUK_USE_HEAPPTR_ENC16 requires option DUK_USE_HEAPPTR16 (which is missing) -#endif -#if defined(DUK_USE_INTEGER_BE) -#error unsupported config option used (option has been removed): DUK_USE_INTEGER_BE -#endif -#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_LE) -#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_LE (which is also defined) -#endif -#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_ME) -#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_ME (which is also defined) -#endif -#if defined(DUK_USE_INTEGER_LE) -#error unsupported config option used (option has been removed): DUK_USE_INTEGER_LE -#endif -#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_BE) -#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_BE (which is also defined) -#endif -#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_ME) -#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_ME (which is also defined) -#endif -#if defined(DUK_USE_INTEGER_ME) -#error unsupported config option used (option has been removed): DUK_USE_INTEGER_ME -#endif -#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_LE) -#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_LE (which is also defined) -#endif -#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_BE) -#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_BE (which is also defined) -#endif -#if defined(DUK_USE_NO_DOUBLE_ALIASING_SELFTEST) -#error unsupported config option used (option has been removed): DUK_USE_NO_DOUBLE_ALIASING_SELFTEST -#endif -#if defined(DUK_USE_PACKED_TVAL_POSSIBLE) -#error unsupported config option used (option has been removed): DUK_USE_PACKED_TVAL_POSSIBLE -#endif -#if defined(DUK_USE_RDTSC) -#error unsupported config option used (option has been removed): DUK_USE_RDTSC -#endif -#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_STRINGS) -#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_STRINGS (which is missing) -#endif -#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_OBJECTS) -#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_OBJECTS (which is missing) -#endif -#if defined(DUK_USE_ROM_GLOBAL_CLONE) && defined(DUK_USE_ROM_GLOBAL_INHERIT) -#error config option DUK_USE_ROM_GLOBAL_CLONE conflicts with option DUK_USE_ROM_GLOBAL_INHERIT (which is also defined) -#endif -#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_STRINGS) -#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_STRINGS (which is missing) -#endif -#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_OBJECTS) -#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_OBJECTS (which is missing) -#endif -#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && defined(DUK_USE_ROM_GLOBAL_CLONE) -#error config option DUK_USE_ROM_GLOBAL_INHERIT conflicts with option DUK_USE_ROM_GLOBAL_CLONE (which is also defined) -#endif -#if defined(DUK_USE_ROM_OBJECTS) && !defined(DUK_USE_ROM_STRINGS) -#error config option DUK_USE_ROM_OBJECTS requires option DUK_USE_ROM_STRINGS (which is missing) -#endif -#if defined(DUK_USE_ROM_STRINGS) && !defined(DUK_USE_ROM_OBJECTS) -#error config option DUK_USE_ROM_STRINGS requires option DUK_USE_ROM_OBJECTS (which is missing) -#endif -#if defined(DUK_USE_SETJMP) -#error unsupported config option used (option has been removed): DUK_USE_SETJMP -#endif -#if defined(DUK_USE_SIGSETJMP) -#error unsupported config option used (option has been removed): DUK_USE_SIGSETJMP -#endif -#if defined(DUK_USE_STRTAB_CHAIN_SIZE) && !defined(DUK_USE_STRTAB_CHAIN) -#error config option DUK_USE_STRTAB_CHAIN_SIZE requires option DUK_USE_STRTAB_CHAIN (which is missing) -#endif -#if defined(DUK_USE_TAILCALL) && defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) -#error config option DUK_USE_TAILCALL conflicts with option DUK_USE_NONSTD_FUNC_CALLER_PROPERTY (which is also defined) -#endif -#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) -#error unsupported config option used (option has been removed): DUK_USE_UNALIGNED_ACCESSES_POSSIBLE -#endif -#if defined(DUK_USE_UNDERSCORE_SETJMP) -#error unsupported config option used (option has been removed): DUK_USE_UNDERSCORE_SETJMP -#endif - -#if defined(DUK_USE_CPP_EXCEPTIONS) && !defined(__cplusplus) -#error DUK_USE_CPP_EXCEPTIONS enabled but not compiling with a C++ compiler -#endif - /* * Convert DUK_USE_BYTEORDER, from whatever source, into currently used * internal defines. If detection failed, #error out. diff --git a/content/handlers/javascript/duktape/duktape.c b/content/handlers/javascript/duktape/duktape.c index b64383b11..a3457a83b 100644 --- a/content/handlers/javascript/duktape/duktape.c +++ b/content/handlers/javascript/duktape/duktape.c @@ -1,10 +1,8 @@ -/* Omit from static analysis. */ -#ifndef __clang_analyzer__ /* - * Single source autogenerated distributable for Duktape 1.6.0. + * Single source autogenerated distributable for Duktape 2.0.2. * - * Git commit 17e3d86cf8b4788bd0d37658f833ab440ce43a1c (v1.6.0). - * Git branch HEAD. + * Git commit external (external). + * Git branch external. * * See Duktape AUTHORS.rst and LICENSE.txt for copyright and * licensing information. @@ -18,7 +16,7 @@ * * (http://opensource.org/licenses/MIT) * -* Copyright (c) 2013-2016 by Duktape authors (see AUTHORS.rst) +* Copyright (c) 2013-2017 by Duktape authors (see AUTHORS.rst) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -38,6 +36,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + /* AUTHORS.rst */ /* * =============== @@ -71,6 +70,18 @@ * * Ren\u00e9 Hollander * * Julien Hamaide (https://github.com/crazyjul) * * Sebastian G\u00f6tte (https://github.com/jaseg) +* * Tomasz Magulski (https://github.com/magul) +* * \D. Bohdan (https://github.com/dbohdan) +* * Ond\u0159ej Jirman (https://github.com/megous) +* * Sa\u00fal Ibarra Corretg\u00e9 +* * Jeremy HU +* * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr) +* * Harold Brenes (https://github.com/harold-b) +* * Oliver Crow (https://github.com/ocrow) +* * Jakub Ch\u0142api\u0144ski (https://github.com/jchlapinski) +* * Brett Vickers (https://github.com/beevik) +* * Dominik Okwieka (https://github.com/okitec) +* * Remko Tron\u00e7on (https://el-tramo.be) * * Other contributions * =================== @@ -108,12 +119,21 @@ * * Michael Drake (https://github.com/tlsa) * * https://github.com/chris-y * * Laurent Zubiaur (https://github.com/lzubiaur) -* * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr) +* * Neil Kolban (https://github.com/nkolban) * * If you are accidentally missing from this list, send me an e-mail * (``sami.vaarala@iki.fi``) and I'll fix the omission. */ -#line 1 "duk_internal.h" + +/* + * Replacements for missing platform functions. + * + * Unlike the originals, fpclassify() and signbit() replacements don't + * work on any floating point types, only doubles. The C typing here + * mimics the standard prototypes. + */ + +/* #include duk_internal.h */ /* * Top-level include file to be used for all (internal) source files. * @@ -121,7 +141,7 @@ * have not been designed to be individually included. */ -#ifndef DUK_INTERNAL_H_INCLUDED +#if !defined(DUK_INTERNAL_H_INCLUDED) #define DUK_INTERNAL_H_INCLUDED /* @@ -143,9 +163,7 @@ /* * User declarations, e.g. prototypes for user functions used by Duktape - * macros. Concretely, if DUK_USE_PANIC_HANDLER is used and the macro - * value calls a user function, it needs to be declared for Duktape - * compilation to avoid warnings. + * macros. */ DUK_USE_USER_DECLARE() @@ -159,8 +177,8 @@ DUK_USE_USER_DECLARE() * dependencies. */ -#line 1 "duk_replacements.h" -#ifndef DUK_REPLACEMENTS_H_INCLUDED +/* #include duk_replacements.h */ +#if !defined(DUK_REPLACEMENTS_H_INCLUDED) #define DUK_REPLACEMENTS_H_INCLUDED #if !defined(DUK_SINGLE_FILE) @@ -170,6 +188,8 @@ DUK_INTERNAL_DECL double duk_computed_infinity; #if defined(DUK_USE_COMPUTED_NAN) DUK_INTERNAL_DECL double duk_computed_nan; #endif +#endif /* !DUK_SINGLE_FILE */ + #if defined(DUK_USE_REPL_FPCLASSIFY) DUK_INTERNAL_DECL int duk_repl_fpclassify(double x); #endif @@ -185,10 +205,9 @@ DUK_INTERNAL_DECL int duk_repl_isnan(double x); #if defined(DUK_USE_REPL_ISINF) DUK_INTERNAL_DECL int duk_repl_isinf(double x); #endif -#endif /* !DUK_SINGLE_FILE */ #endif /* DUK_REPLACEMENTS_H_INCLUDED */ -#line 1 "duk_jmpbuf.h" +/* #include duk_jmpbuf.h */ /* * Wrapper for jmp_buf. * @@ -199,7 +218,7 @@ DUK_INTERNAL_DECL int duk_repl_isinf(double x); * http://en.wikipedia.org/wiki/Setjmp.h#Member_types */ -#ifndef DUK_JMPBUF_H_INCLUDED +#if !defined(DUK_JMPBUF_H_INCLUDED) #define DUK_JMPBUF_H_INCLUDED #if defined(DUK_USE_CPP_EXCEPTIONS) @@ -213,7 +232,7 @@ struct duk_jmpbuf { #endif #endif /* DUK_JMPBUF_H_INCLUDED */ -#line 1 "duk_exception.h" +/* #include duk_exception.h */ /* * Exception for Duktape internal throws when C++ exceptions are used * for long control transfers. @@ -222,7 +241,7 @@ struct duk_jmpbuf { * that user code would accidentally catch this exception. */ -#ifndef DUK_EXCEPTION_H_INCLUDED +#if !defined(DUK_EXCEPTION_H_INCLUDED) #define DUK_EXCEPTION_H_INCLUDED #if defined(DUK_USE_CPP_EXCEPTIONS) @@ -232,12 +251,12 @@ class duk_internal_exception { #endif #endif /* DUK_EXCEPTION_H_INCLUDED */ -#line 1 "duk_forwdecl.h" +/* #include duk_forwdecl.h */ /* * Forward declarations for all Duktape structures. */ -#ifndef DUK_FORWDECL_H_INCLUDED +#if !defined(DUK_FORWDECL_H_INCLUDED) #define DUK_FORWDECL_H_INCLUDED /* @@ -253,13 +272,14 @@ struct duk_jmpbuf; /* duk_tval intentionally skipped */ struct duk_heaphdr; struct duk_heaphdr_string; +struct duk_harray; struct duk_hstring; struct duk_hstring_external; struct duk_hobject; -struct duk_hcompiledfunction; -struct duk_hnativefunction; +struct duk_hcompfunc; +struct duk_hnatfunc; struct duk_hthread; -struct duk_hbufferobject; +struct duk_hbufobj; struct duk_hbuffer; struct duk_hbuffer_fixed; struct duk_hbuffer_dynamic; @@ -278,7 +298,7 @@ struct duk_strcache; struct duk_ljstate; struct duk_strtab_entry; -#ifdef DUK_USE_DEBUG +#if defined(DUK_USE_DEBUG) struct duk_fixedbuffer; #endif @@ -308,12 +328,13 @@ typedef struct duk_jmpbuf duk_jmpbuf; /* duk_tval intentionally skipped */ typedef struct duk_heaphdr duk_heaphdr; typedef struct duk_heaphdr_string duk_heaphdr_string; +typedef struct duk_harray duk_harray; typedef struct duk_hstring duk_hstring; typedef struct duk_hstring_external duk_hstring_external; typedef struct duk_hobject duk_hobject; -typedef struct duk_hcompiledfunction duk_hcompiledfunction; -typedef struct duk_hnativefunction duk_hnativefunction; -typedef struct duk_hbufferobject duk_hbufferobject; +typedef struct duk_hcompfunc duk_hcompfunc; +typedef struct duk_hnatfunc duk_hnatfunc; +typedef struct duk_hbufobj duk_hbufobj; typedef struct duk_hthread duk_hthread; typedef struct duk_hbuffer duk_hbuffer; typedef struct duk_hbuffer_fixed duk_hbuffer_fixed; @@ -333,7 +354,7 @@ typedef struct duk_strcache duk_strcache; typedef struct duk_ljstate duk_ljstate; typedef struct duk_strtab_entry duk_strtab_entry; -#ifdef DUK_USE_DEBUG +#if defined(DUK_USE_DEBUG) typedef struct duk_fixedbuffer duk_fixedbuffer; #endif @@ -355,7 +376,7 @@ typedef struct duk_re_matcher_ctx duk_re_matcher_ctx; typedef struct duk_re_compiler_ctx duk_re_compiler_ctx; #endif /* DUK_FORWDECL_H_INCLUDED */ -#line 1 "duk_tval.h" +/* #include duk_tval.h */ /* * Tagged type definition (duk_tval) and accessor macros. * @@ -368,15 +389,13 @@ typedef struct duk_re_compiler_ctx duk_re_compiler_ctx; * 64-bit environments (it usually pads to 16 bytes per value). * * Selecting the tagged type format involves many trade-offs (memory - * use, size and performance of generated code, portability, etc), - * see doc/types.rst for a detailed discussion (especially of how the - * IEEE double format is used to pack tagged values). + * use, size and performance of generated code, portability, etc). * * NB: because macro arguments are often expressions, macros should * avoid evaluating their argument more than once. */ -#ifndef DUK_TVAL_H_INCLUDED +#if !defined(DUK_TVAL_H_INCLUDED) #define DUK_TVAL_H_INCLUDED /* sanity */ @@ -393,10 +412,17 @@ typedef struct duk_re_compiler_ctx duk_re_compiler_ctx; /* use duk_double_union as duk_tval directly */ typedef union duk_double_union duk_tval; +typedef struct { + duk_uint16_t a; + duk_uint16_t b; + duk_uint16_t c; + duk_uint16_t d; +} duk_tval_unused; /* tags */ #define DUK_TAG_NORMALIZED_NAN 0x7ff8UL /* the NaN variant we use */ /* avoid tag 0xfff0, no risk of confusion with negative infinity */ +#define DUK_TAG_MIN 0xfff1UL #if defined(DUK_USE_FASTINT) #define DUK_TAG_FASTINT 0xfff1UL /* embed: integer value */ #endif @@ -410,195 +436,226 @@ typedef union duk_double_union duk_tval; #define DUK_TAG_STRING 0xfff8UL /* embed: duk_hstring ptr */ #define DUK_TAG_OBJECT 0xfff9UL /* embed: duk_hobject ptr */ #define DUK_TAG_BUFFER 0xfffaUL /* embed: duk_hbuffer ptr */ +#define DUK_TAG_MAX 0xfffaUL /* for convenience */ #define DUK_XTAG_BOOLEAN_FALSE 0xfff50000UL #define DUK_XTAG_BOOLEAN_TRUE 0xfff50001UL +#define DUK_TVAL_IS_VALID_TAG(tv) \ + (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN) + +/* DUK_TVAL_UNUSED initializer for duk_tval_unused, works for any endianness. */ +#define DUK_TVAL_UNUSED_INITIALIZER() \ + { DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED } + /* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */ #if defined(DUK_USE_64BIT_OPS) #if defined(DUK_USE_DOUBLE_ME) -#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \ - (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \ +#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \ + (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \ } while (0) #else -#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \ - (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \ +#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \ + (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \ } while (0) #endif #else /* DUK_USE_64BIT_OPS */ -#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \ - (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \ - (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \ +#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \ + duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \ } while (0) #endif /* DUK_USE_64BIT_OPS */ #if defined(DUK_USE_64BIT_OPS) /* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */ #if defined(DUK_USE_DOUBLE_ME) -#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \ - (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \ - ((duk_uint64_t) (flags)) | \ - (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \ +#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ + (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \ + ((duk_uint64_t) (flags)) | \ + (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \ } while (0) #else -#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \ - (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \ - (((duk_uint64_t) (flags)) << 32) | \ - ((duk_uint64_t) (duk_uint32_t) (fp)); \ +#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ + (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \ + (((duk_uint64_t) (flags)) << 32) | \ + ((duk_uint64_t) (duk_uint32_t) (fp)); \ } while (0) #endif #else /* DUK_USE_64BIT_OPS */ -#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \ - (v)->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \ - (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \ +#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \ + duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \ } while (0) #endif /* DUK_USE_64BIT_OPS */ #if defined(DUK_USE_FASTINT) /* Note: masking is done for 'i' to deal with negative numbers correctly */ #if defined(DUK_USE_DOUBLE_ME) -#define DUK__TVAL_SET_FASTINT(v,i) do { \ - (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \ - (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ +#define DUK__TVAL_SET_I48(tv,i) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \ + duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ } while (0) -#define DUK__TVAL_SET_FASTINT_U32(v,i) do { \ - (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \ - (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ +#define DUK__TVAL_SET_U32(tv,i) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \ + duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ } while (0) #else -#define DUK__TVAL_SET_FASTINT(v,i) do { \ - (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & 0x0000ffffffffffffULL); \ +#define DUK__TVAL_SET_I48(tv,i) do { \ + (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & 0x0000ffffffffffffULL); \ } while (0) -#define DUK__TVAL_SET_FASTINT_U32(v,i) do { \ - (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \ +#define DUK__TVAL_SET_U32(tv,i) do { \ + (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \ } while (0) #endif -#define DUK__TVAL_SET_FASTINT_I32(v,i) do { \ +/* This needs to go through a cast because sign extension is needed. */ +#define DUK__TVAL_SET_I32(tv,i) do { \ duk_int64_t duk__tmp = (duk_int64_t) (i); \ - DUK_TVAL_SET_FASTINT((v), duk__tmp); \ + DUK_TVAL_SET_I48((tv), duk__tmp); \ } while (0) -/* XXX: clumsy sign extend and masking of 16 topmost bits */ +/* XXX: Clumsy sign extend and masking of 16 topmost bits. */ #if defined(DUK_USE_DOUBLE_ME) -#define DUK__TVAL_GET_FASTINT(v) (((duk_int64_t) ((((duk_uint64_t) (v)->ui[DUK_DBL_IDX_UI0]) << 32) | ((duk_uint64_t) (v)->ui[DUK_DBL_IDX_UI1]))) << 16 >> 16) +#define DUK__TVAL_GET_FASTINT(tv) (((duk_int64_t) ((((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI0]) << 32) | ((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI1]))) << 16 >> 16) #else -#define DUK__TVAL_GET_FASTINT(v) ((((duk_int64_t) (v)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16) +#define DUK__TVAL_GET_FASTINT(tv) ((((duk_int64_t) (tv)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16) #endif -#define DUK__TVAL_GET_FASTINT_U32(v) ((v)->ui[DUK_DBL_IDX_UI1]) -#define DUK__TVAL_GET_FASTINT_I32(v) ((duk_int32_t) (v)->ui[DUK_DBL_IDX_UI1]) +#define DUK__TVAL_GET_FASTINT_U32(tv) ((tv)->ui[DUK_DBL_IDX_UI1]) +#define DUK__TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) (tv)->ui[DUK_DBL_IDX_UI1]) #endif /* DUK_USE_FASTINT */ -#define DUK_TVAL_SET_UNDEFINED(v) do { \ - (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \ +#define DUK_TVAL_SET_UNDEFINED(tv) do { \ + (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \ } while (0) -#define DUK_TVAL_SET_UNUSED(v) do { \ - (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \ +#define DUK_TVAL_SET_UNUSED(tv) do { \ + (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \ } while (0) -#define DUK_TVAL_SET_NULL(v) do { \ - (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \ +#define DUK_TVAL_SET_NULL(tv) do { \ + (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \ } while (0) -#define DUK_TVAL_SET_BOOLEAN(v,val) DUK_DBLUNION_SET_HIGH32((v), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val))) +#define DUK_TVAL_SET_BOOLEAN(tv,val) DUK_DBLUNION_SET_HIGH32((tv), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val))) -#define DUK_TVAL_SET_NAN(v) DUK_DBLUNION_SET_NAN_FULL((v)) +#define DUK_TVAL_SET_NAN(tv) DUK_DBLUNION_SET_NAN_FULL((tv)) /* Assumes that caller has normalized NaNs, otherwise trouble ahead. */ #if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_DOUBLE(v,d) do { \ +#define DUK_TVAL_SET_DOUBLE(tv,d) do { \ duk_double_t duk__dblval; \ duk__dblval = (d); \ DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \ - DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \ + DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \ } while (0) -#define DUK_TVAL_SET_FASTINT(v,i) DUK__TVAL_SET_FASTINT((v), (i)) -#define DUK_TVAL_SET_FASTINT_I32(v,i) DUK__TVAL_SET_FASTINT_I32((v), (i)) -#define DUK_TVAL_SET_FASTINT_U32(v,i) DUK__TVAL_SET_FASTINT_U32((v), (i)) -#define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) duk_tval_set_number_chkfast((v), (d)) -#define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d)) -#define DUK_TVAL_CHKFAST_INPLACE(v) do { \ +#define DUK_TVAL_SET_I48(tv,i) DUK__TVAL_SET_I48((tv), (i)) +#define DUK_TVAL_SET_I32(tv,i) DUK__TVAL_SET_I32((tv), (i)) +#define DUK_TVAL_SET_U32(tv,i) DUK__TVAL_SET_U32((tv), (i)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) duk_tval_set_number_chkfast_fast((tv), (d)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) duk_tval_set_number_chkfast_slow((tv), (d)) +#define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) +#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \ duk_tval *duk__tv; \ duk_double_t duk__d; \ - duk__tv = (v); \ + duk__tv = (tv); \ if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ - DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \ + DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \ } \ } while (0) -#else -#define DUK_TVAL_SET_DOUBLE(v,d) do { \ +#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \ + duk_tval *duk__tv; \ + duk_double_t duk__d; \ + duk__tv = (tv); \ + if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ + duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ + DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \ + } \ + } while (0) +#else /* DUK_USE_FASTINT */ +#define DUK_TVAL_SET_DOUBLE(tv,d) do { \ duk_double_t duk__dblval; \ duk__dblval = (d); \ DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \ - DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \ + DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \ } while (0) -#define DUK_TVAL_SET_FASTINT(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i)) /* XXX: fast int-to-double */ -#define DUK_TVAL_SET_FASTINT_I32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i)) -#define DUK_TVAL_SET_FASTINT_U32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i)) -#define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) DUK_TVAL_SET_DOUBLE((v), (d)) -#define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d)) -#define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0) -#endif +#define DUK_TVAL_SET_I48(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) /* XXX: fast int-to-double */ +#define DUK_TVAL_SET_I32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) +#define DUK_TVAL_SET_U32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) +#define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) +#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0) +#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0) +#endif /* DUK_USE_FASTINT */ + +#define DUK_TVAL_SET_FASTINT(tv,i) DUK_TVAL_SET_I48((tv), (i)) /* alias */ -#define DUK_TVAL_SET_LIGHTFUNC(v,fp,flags) DUK__TVAL_SET_LIGHTFUNC((v), (fp), (flags)) -#define DUK_TVAL_SET_STRING(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_STRING) -#define DUK_TVAL_SET_OBJECT(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_OBJECT) -#define DUK_TVAL_SET_BUFFER(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_BUFFER) -#define DUK_TVAL_SET_POINTER(v,p) DUK__TVAL_SET_TAGGEDPOINTER((v), (p), DUK_TAG_POINTER) +#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) DUK__TVAL_SET_LIGHTFUNC((tv), (fp), (flags)) +#define DUK_TVAL_SET_STRING(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_STRING) +#define DUK_TVAL_SET_OBJECT(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_OBJECT) +#define DUK_TVAL_SET_BUFFER(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_BUFFER) +#define DUK_TVAL_SET_POINTER(tv,p) DUK__TVAL_SET_TAGGEDPOINTER((tv), (p), DUK_TAG_POINTER) -#define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0) +#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0) /* getters */ -#define DUK_TVAL_GET_BOOLEAN(v) ((int) (v)->us[DUK_DBL_IDX_US1]) +#define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_int_t) (tv)->us[DUK_DBL_IDX_US1]) #if defined(DUK_USE_FASTINT) -#define DUK_TVAL_GET_DOUBLE(v) ((v)->d) -#define DUK_TVAL_GET_FASTINT(v) DUK__TVAL_GET_FASTINT((v)) -#define DUK_TVAL_GET_FASTINT_U32(v) DUK__TVAL_GET_FASTINT_U32((v)) -#define DUK_TVAL_GET_FASTINT_I32(v) DUK__TVAL_GET_FASTINT_I32((v)) -#define DUK_TVAL_GET_NUMBER(v) duk_tval_get_number_packed((v)) +#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d) +#define DUK_TVAL_GET_FASTINT(tv) DUK__TVAL_GET_FASTINT((tv)) +#define DUK_TVAL_GET_FASTINT_U32(tv) DUK__TVAL_GET_FASTINT_U32((tv)) +#define DUK_TVAL_GET_FASTINT_I32(tv) DUK__TVAL_GET_FASTINT_I32((tv)) +#define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_packed((tv)) #else -#define DUK_TVAL_GET_NUMBER(v) ((v)->d) -#define DUK_TVAL_GET_DOUBLE(v) ((v)->d) +#define DUK_TVAL_GET_NUMBER(tv) ((tv)->d) +#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d) #endif -#define DUK_TVAL_GET_LIGHTFUNC(v,out_fp,out_flags) do { \ - (out_flags) = (v)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \ - (out_fp) = (duk_c_function) (v)->ui[DUK_DBL_IDX_UI1]; \ +#define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \ + (out_flags) = (tv)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \ + (out_fp) = (duk_c_function) (tv)->ui[DUK_DBL_IDX_UI1]; \ } while (0) -#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(v) ((duk_c_function) ((v)->ui[DUK_DBL_IDX_UI1])) -#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(v) (((int) (v)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL) -#define DUK_TVAL_GET_STRING(v) ((duk_hstring *) (v)->vp[DUK_DBL_IDX_VP1]) -#define DUK_TVAL_GET_OBJECT(v) ((duk_hobject *) (v)->vp[DUK_DBL_IDX_VP1]) -#define DUK_TVAL_GET_BUFFER(v) ((duk_hbuffer *) (v)->vp[DUK_DBL_IDX_VP1]) -#define DUK_TVAL_GET_POINTER(v) ((void *) (v)->vp[DUK_DBL_IDX_VP1]) -#define DUK_TVAL_GET_HEAPHDR(v) ((duk_heaphdr *) (v)->vp[DUK_DBL_IDX_VP1]) +#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((duk_c_function) ((tv)->ui[DUK_DBL_IDX_UI1])) +#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) (((duk_small_int_t) (tv)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL) +#define DUK_TVAL_GET_STRING(tv) ((duk_hstring *) (tv)->vp[DUK_DBL_IDX_VP1]) +#define DUK_TVAL_GET_OBJECT(tv) ((duk_hobject *) (tv)->vp[DUK_DBL_IDX_VP1]) +#define DUK_TVAL_GET_BUFFER(tv) ((duk_hbuffer *) (tv)->vp[DUK_DBL_IDX_VP1]) +#define DUK_TVAL_GET_POINTER(tv) ((void *) (tv)->vp[DUK_DBL_IDX_VP1]) +#define DUK_TVAL_GET_HEAPHDR(tv) ((duk_heaphdr *) (tv)->vp[DUK_DBL_IDX_VP1]) /* decoding */ -#define DUK_TVAL_GET_TAG(v) ((duk_small_uint_t) (v)->us[DUK_DBL_IDX_US0]) - -#define DUK_TVAL_IS_UNDEFINED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNDEFINED) -#define DUK_TVAL_IS_UNUSED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNUSED) -#define DUK_TVAL_IS_NULL(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_NULL) -#define DUK_TVAL_IS_BOOLEAN(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BOOLEAN) -#define DUK_TVAL_IS_BOOLEAN_TRUE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE) -#define DUK_TVAL_IS_BOOLEAN_FALSE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE) -#define DUK_TVAL_IS_LIGHTFUNC(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_LIGHTFUNC) -#define DUK_TVAL_IS_STRING(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_STRING) -#define DUK_TVAL_IS_OBJECT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_OBJECT) -#define DUK_TVAL_IS_BUFFER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BUFFER) -#define DUK_TVAL_IS_POINTER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_POINTER) +#define DUK_TVAL_GET_TAG(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US0]) + +#define DUK_TVAL_IS_UNDEFINED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNDEFINED) +#define DUK_TVAL_IS_UNUSED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNUSED) +#define DUK_TVAL_IS_NULL(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_NULL) +#define DUK_TVAL_IS_BOOLEAN(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BOOLEAN) +#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE) +#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE) +#define DUK_TVAL_IS_LIGHTFUNC(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_LIGHTFUNC) +#define DUK_TVAL_IS_STRING(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_STRING) +#define DUK_TVAL_IS_OBJECT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_OBJECT) +#define DUK_TVAL_IS_BUFFER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BUFFER) +#define DUK_TVAL_IS_POINTER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_POINTER) #if defined(DUK_USE_FASTINT) /* 0xfff0 is -Infinity */ -#define DUK_TVAL_IS_DOUBLE(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL) -#define DUK_TVAL_IS_FASTINT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_FASTINT) -#define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff1UL) +#define DUK_TVAL_IS_DOUBLE(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL) +#define DUK_TVAL_IS_FASTINT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_FASTINT) +#define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff1UL) #else -#define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL) -#define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v)) +#define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL) +#define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv)) #endif /* This is performance critical because it appears in every DECREF. */ -#define DUK_TVAL_IS_HEAP_ALLOCATED(v) (DUK_TVAL_GET_TAG((v)) >= DUK_TAG_STRING) +#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) (DUK_TVAL_GET_TAG((tv)) >= DUK_TAG_STRING) #if defined(DUK_USE_FASTINT) DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_packed(duk_tval *tv); @@ -633,8 +690,8 @@ struct duk_tval_struct { void *voidptr; duk_hstring *hstring; duk_hobject *hobject; - duk_hcompiledfunction *hcompiledfunction; - duk_hnativefunction *hnativefunction; + duk_hcompfunc *hcompfunc; + duk_hnatfunc *hnatfunc; duk_hthread *hthread; duk_hbuffer *hbuffer; duk_heaphdr *heaphdr; @@ -642,7 +699,22 @@ struct duk_tval_struct { } v; }; -#define DUK__TAG_NUMBER 0 /* not exposed */ +typedef struct { + duk_small_uint_t t; + duk_small_uint_t v_extra; + /* The rest of the fields don't matter except for debug dumps and such + * for which a partial initializer may trigger out-ot-bounds memory + * reads. Include a double field which is usually as large or larger + * than pointers (not always however). + */ + duk_double_t d; +} duk_tval_unused; + +#define DUK_TVAL_UNUSED_INITIALIZER() \ + { DUK_TAG_UNUSED, 0, 0.0 } + +#define DUK_TAG_MIN 0 +#define DUK_TAG_NUMBER 0 /* DUK_TAG_NUMBER only defined for non-packed duk_tval */ #if defined(DUK_USE_FASTINT) #define DUK_TAG_FASTINT 1 #endif @@ -655,8 +727,12 @@ struct duk_tval_struct { #define DUK_TAG_STRING 8 /* first heap allocated, match bit boundary */ #define DUK_TAG_OBJECT 9 #define DUK_TAG_BUFFER 10 +#define DUK_TAG_MAX 10 -/* DUK__TAG_NUMBER is intentionally first, as it is the default clause in code +#define DUK_TVAL_IS_VALID_TAG(tv) \ + (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN) + +/* DUK_TAG_NUMBER is intentionally first, as it is the default clause in code * to support the 8-byte representation. Further, it is a non-heap-allocated * type so it should come before DUK_TAG_STRING. Finally, it should not break * the tag value ranges covered by case-clauses in a switch-case. @@ -664,103 +740,156 @@ struct duk_tval_struct { /* setters */ #define DUK_TVAL_SET_UNDEFINED(tv) do { \ - (tv)->t = DUK_TAG_UNDEFINED; \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_UNDEFINED; \ } while (0) #define DUK_TVAL_SET_UNUSED(tv) do { \ - (tv)->t = DUK_TAG_UNUSED; \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_UNUSED; \ } while (0) #define DUK_TVAL_SET_NULL(tv) do { \ - (tv)->t = DUK_TAG_NULL; \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_NULL; \ } while (0) #define DUK_TVAL_SET_BOOLEAN(tv,val) do { \ - (tv)->t = DUK_TAG_BOOLEAN; \ - (tv)->v.i = (val); \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_BOOLEAN; \ + duk__tv->v.i = (val); \ } while (0) #if defined(DUK_USE_FASTINT) #define DUK_TVAL_SET_DOUBLE(tv,val) do { \ - (tv)->t = DUK__TAG_NUMBER; \ - (tv)->v.d = (val); \ + duk_tval *duk__tv; \ + duk_double_t duk__dblval; \ + duk__dblval = (val); \ + DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_NUMBER; \ + duk__tv->v.d = duk__dblval; \ } while (0) -#define DUK_TVAL_SET_FASTINT(tv,val) do { \ - (tv)->t = DUK_TAG_FASTINT; \ - (tv)->v.fi = (val); \ +#define DUK_TVAL_SET_I48(tv,val) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_FASTINT; \ + duk__tv->v.fi = (val); \ } while (0) -#define DUK_TVAL_SET_FASTINT_U32(tv,val) do { \ - (tv)->t = DUK_TAG_FASTINT; \ - (tv)->v.fi = (duk_int64_t) (val); \ +#define DUK_TVAL_SET_U32(tv,val) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_FASTINT; \ + duk__tv->v.fi = (duk_int64_t) (val); \ } while (0) -#define DUK_TVAL_SET_FASTINT_I32(tv,val) do { \ - (tv)->t = DUK_TAG_FASTINT; \ - (tv)->v.fi = (duk_int64_t) (val); \ +#define DUK_TVAL_SET_I32(tv,val) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_FASTINT; \ + duk__tv->v.fi = (duk_int64_t) (val); \ } while (0) -#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \ - duk_tval_set_number_chkfast((tv), (d)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \ + duk_tval_set_number_chkfast_fast((tv), (d)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \ + duk_tval_set_number_chkfast_slow((tv), (d)) #define DUK_TVAL_SET_NUMBER(tv,val) \ DUK_TVAL_SET_DOUBLE((tv), (val)) -#define DUK_TVAL_CHKFAST_INPLACE(v) do { \ +#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \ duk_tval *duk__tv; \ duk_double_t duk__d; \ - duk__tv = (v); \ + duk__tv = (tv); \ if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ - DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \ + DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \ } \ } while (0) -#else +#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \ + duk_tval *duk__tv; \ + duk_double_t duk__d; \ + duk__tv = (tv); \ + if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ + duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ + DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \ + } \ + } while (0) +#else /* DUK_USE_FASTINT */ #define DUK_TVAL_SET_DOUBLE(tv,d) \ DUK_TVAL_SET_NUMBER((tv), (d)) -#define DUK_TVAL_SET_FASTINT(tv,val) \ +#define DUK_TVAL_SET_I48(tv,val) \ DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) /* XXX: fast int-to-double */ -#define DUK_TVAL_SET_FASTINT_U32(tv,val) \ +#define DUK_TVAL_SET_U32(tv,val) \ DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) -#define DUK_TVAL_SET_FASTINT_I32(tv,val) \ +#define DUK_TVAL_SET_I32(tv,val) \ DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) #define DUK_TVAL_SET_NUMBER(tv,val) do { \ - (tv)->t = DUK__TAG_NUMBER; \ - (tv)->v.d = (val); \ + duk_tval *duk__tv; \ + duk_double_t duk__dblval; \ + duk__dblval = (val); \ + DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_NUMBER; \ + duk__tv->v.d = duk__dblval; \ } while (0) -#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \ +#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \ DUK_TVAL_SET_NUMBER((tv), (d)) -#define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0) +#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \ + DUK_TVAL_SET_NUMBER((tv), (d)) +#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0) +#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0) #endif /* DUK_USE_FASTINT */ +#define DUK_TVAL_SET_FASTINT(tv,i) \ + DUK_TVAL_SET_I48((tv), (i)) /* alias */ + #define DUK_TVAL_SET_POINTER(tv,hptr) do { \ - (tv)->t = DUK_TAG_POINTER; \ - (tv)->v.voidptr = (hptr); \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_POINTER; \ + duk__tv->v.voidptr = (hptr); \ } while (0) #define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ - (tv)->t = DUK_TAG_LIGHTFUNC; \ - (tv)->v_extra = (flags); \ - (tv)->v.lightfunc = (duk_c_function) (fp); \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_LIGHTFUNC; \ + duk__tv->v_extra = (flags); \ + duk__tv->v.lightfunc = (duk_c_function) (fp); \ } while (0) #define DUK_TVAL_SET_STRING(tv,hptr) do { \ - (tv)->t = DUK_TAG_STRING; \ - (tv)->v.hstring = (hptr); \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_STRING; \ + duk__tv->v.hstring = (hptr); \ } while (0) #define DUK_TVAL_SET_OBJECT(tv,hptr) do { \ - (tv)->t = DUK_TAG_OBJECT; \ - (tv)->v.hobject = (hptr); \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_OBJECT; \ + duk__tv->v.hobject = (hptr); \ } while (0) #define DUK_TVAL_SET_BUFFER(tv,hptr) do { \ - (tv)->t = DUK_TAG_BUFFER; \ - (tv)->v.hbuffer = (hptr); \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_BUFFER; \ + duk__tv->v.hbuffer = (hptr); \ } while (0) #define DUK_TVAL_SET_NAN(tv) do { \ /* in non-packed representation we don't care about which NaN is used */ \ - (tv)->t = DUK__TAG_NUMBER; \ - (tv)->v.d = DUK_DOUBLE_NAN; \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_NUMBER; \ + duk__tv->v.d = DUK_DOUBLE_NAN; \ } while (0) -#define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0) +#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0) /* getters */ #define DUK_TVAL_GET_BOOLEAN(tv) ((tv)->v.i) @@ -805,13 +934,13 @@ struct duk_tval_struct { #define DUK_TVAL_IS_BOOLEAN_TRUE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0)) #define DUK_TVAL_IS_BOOLEAN_FALSE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0)) #if defined(DUK_USE_FASTINT) -#define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK__TAG_NUMBER) +#define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK_TAG_NUMBER) #define DUK_TVAL_IS_FASTINT(tv) ((tv)->t == DUK_TAG_FASTINT) -#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER || \ +#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER || \ (tv)->t == DUK_TAG_FASTINT) #else -#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER) -#define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v)) +#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER) +#define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv)) #endif /* DUK_USE_FASTINT */ #define DUK_TVAL_IS_POINTER(tv) ((tv)->t == DUK_TAG_POINTER) #define DUK_TVAL_IS_LIGHTFUNC(tv) ((tv)->t == DUK_TAG_LIGHTFUNC) @@ -842,13 +971,18 @@ DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv * Convenience (independent of representation) */ -#define DUK_TVAL_SET_BOOLEAN_TRUE(v) DUK_TVAL_SET_BOOLEAN(v, 1) -#define DUK_TVAL_SET_BOOLEAN_FALSE(v) DUK_TVAL_SET_BOOLEAN(v, 0) +#define DUK_TVAL_SET_BOOLEAN_TRUE(tv) DUK_TVAL_SET_BOOLEAN((tv), 1) +#define DUK_TVAL_SET_BOOLEAN_FALSE(tv) DUK_TVAL_SET_BOOLEAN((tv), 0) + +#define DUK_TVAL_STRING_IS_SYMBOL(tv) \ + DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING((tv))) /* Lightfunc flags packing and unpacking. */ -/* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss## */ +/* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss##. + * Avoid signed shifts due to portability limitations. + */ #define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \ - ((((duk_int32_t) (lf_flags)) << 16) >> 24) + ((duk_int32_t) (duk_int8_t) (((duk_uint16_t) (lf_flags)) >> 8)) #define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \ (((lf_flags) >> 4) & 0x0f) #define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \ @@ -870,20 +1004,21 @@ DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv #define DUK_FASTINT_MAX 0x7fffffffffffLL #define DUK_FASTINT_BITS 48 -DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x); +DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x); +DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x); #endif #endif /* DUK_TVAL_H_INCLUDED */ -#line 1 "duk_builtins.h" +/* #include duk_builtins.h */ /* * Automatically generated by genbuiltins.py, do not edit! */ -#ifndef DUK_BUILTINS_H_INCLUDED +#if !defined(DUK_BUILTINS_H_INCLUDED) #define DUK_BUILTINS_H_INCLUDED #if defined(DUK_USE_ROM_STRINGS) -#error ROM support not enabled, rerun make_dist.py with --rom-support +#error ROM support not enabled, rerun configure.py with --rom-support #else /* DUK_USE_ROM_STRINGS */ #define DUK_STRIDX_UC_UNDEFINED 0 /* 'Undefined' */ #define DUK_HEAP_STRING_UC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_UNDEFINED) @@ -891,102 +1026,102 @@ DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x) #define DUK_STRIDX_UC_NULL 1 /* 'Null' */ #define DUK_HEAP_STRING_UC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NULL) #define DUK_HTHREAD_STRING_UC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NULL) -#define DUK_STRIDX_UC_ARGUMENTS 2 /* 'Arguments' */ +#define DUK_STRIDX_UC_SYMBOL 2 /* 'Symbol' */ +#define DUK_HEAP_STRING_UC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_SYMBOL) +#define DUK_HTHREAD_STRING_UC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_SYMBOL) +#define DUK_STRIDX_UC_ARGUMENTS 3 /* 'Arguments' */ #define DUK_HEAP_STRING_UC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS) #define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS) -#define DUK_STRIDX_UC_OBJECT 3 /* 'Object' */ +#define DUK_STRIDX_UC_OBJECT 4 /* 'Object' */ #define DUK_HEAP_STRING_UC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT) #define DUK_HTHREAD_STRING_UC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT) -#define DUK_STRIDX_UC_FUNCTION 4 /* 'Function' */ +#define DUK_STRIDX_UC_FUNCTION 5 /* 'Function' */ #define DUK_HEAP_STRING_UC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION) #define DUK_HTHREAD_STRING_UC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION) -#define DUK_STRIDX_ARRAY 5 /* 'Array' */ +#define DUK_STRIDX_ARRAY 6 /* 'Array' */ #define DUK_HEAP_STRING_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY) #define DUK_HTHREAD_STRING_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY) -#define DUK_STRIDX_UC_STRING 6 /* 'String' */ +#define DUK_STRIDX_UC_STRING 7 /* 'String' */ #define DUK_HEAP_STRING_UC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING) #define DUK_HTHREAD_STRING_UC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING) -#define DUK_STRIDX_UC_BOOLEAN 7 /* 'Boolean' */ +#define DUK_STRIDX_UC_BOOLEAN 8 /* 'Boolean' */ #define DUK_HEAP_STRING_UC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN) #define DUK_HTHREAD_STRING_UC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN) -#define DUK_STRIDX_UC_NUMBER 8 /* 'Number' */ +#define DUK_STRIDX_UC_NUMBER 9 /* 'Number' */ #define DUK_HEAP_STRING_UC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER) #define DUK_HTHREAD_STRING_UC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER) -#define DUK_STRIDX_DATE 9 /* 'Date' */ +#define DUK_STRIDX_DATE 10 /* 'Date' */ #define DUK_HEAP_STRING_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATE) #define DUK_HTHREAD_STRING_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATE) -#define DUK_STRIDX_REG_EXP 10 /* 'RegExp' */ +#define DUK_STRIDX_REG_EXP 11 /* 'RegExp' */ #define DUK_HEAP_STRING_REG_EXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP) #define DUK_HTHREAD_STRING_REG_EXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP) -#define DUK_STRIDX_UC_ERROR 11 /* 'Error' */ +#define DUK_STRIDX_UC_ERROR 12 /* 'Error' */ #define DUK_HEAP_STRING_UC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR) #define DUK_HTHREAD_STRING_UC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR) -#define DUK_STRIDX_MATH 12 /* 'Math' */ +#define DUK_STRIDX_MATH 13 /* 'Math' */ #define DUK_HEAP_STRING_MATH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH) #define DUK_HTHREAD_STRING_MATH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH) -#define DUK_STRIDX_JSON 13 /* 'JSON' */ +#define DUK_STRIDX_JSON 14 /* 'JSON' */ #define DUK_HEAP_STRING_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON) #define DUK_HTHREAD_STRING_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON) -#define DUK_STRIDX_EMPTY_STRING 14 /* '' */ +#define DUK_STRIDX_EMPTY_STRING 15 /* '' */ #define DUK_HEAP_STRING_EMPTY_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING) #define DUK_HTHREAD_STRING_EMPTY_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING) -#define DUK_STRIDX_ARRAY_BUFFER 15 /* 'ArrayBuffer' */ +#define DUK_STRIDX_ARRAY_BUFFER 16 /* 'ArrayBuffer' */ #define DUK_HEAP_STRING_ARRAY_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY_BUFFER) #define DUK_HTHREAD_STRING_ARRAY_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY_BUFFER) -#define DUK_STRIDX_DATA_VIEW 16 /* 'DataView' */ +#define DUK_STRIDX_DATA_VIEW 17 /* 'DataView' */ #define DUK_HEAP_STRING_DATA_VIEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA_VIEW) #define DUK_HTHREAD_STRING_DATA_VIEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA_VIEW) -#define DUK_STRIDX_INT8_ARRAY 17 /* 'Int8Array' */ +#define DUK_STRIDX_INT8_ARRAY 18 /* 'Int8Array' */ #define DUK_HEAP_STRING_INT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT8_ARRAY) #define DUK_HTHREAD_STRING_INT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT8_ARRAY) -#define DUK_STRIDX_UINT8_ARRAY 18 /* 'Uint8Array' */ +#define DUK_STRIDX_UINT8_ARRAY 19 /* 'Uint8Array' */ #define DUK_HEAP_STRING_UINT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_ARRAY) #define DUK_HTHREAD_STRING_UINT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_ARRAY) -#define DUK_STRIDX_UINT8_CLAMPED_ARRAY 19 /* 'Uint8ClampedArray' */ +#define DUK_STRIDX_UINT8_CLAMPED_ARRAY 20 /* 'Uint8ClampedArray' */ #define DUK_HEAP_STRING_UINT8_CLAMPED_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_CLAMPED_ARRAY) #define DUK_HTHREAD_STRING_UINT8_CLAMPED_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_CLAMPED_ARRAY) -#define DUK_STRIDX_INT16_ARRAY 20 /* 'Int16Array' */ +#define DUK_STRIDX_INT16_ARRAY 21 /* 'Int16Array' */ #define DUK_HEAP_STRING_INT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT16_ARRAY) #define DUK_HTHREAD_STRING_INT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT16_ARRAY) -#define DUK_STRIDX_UINT16_ARRAY 21 /* 'Uint16Array' */ +#define DUK_STRIDX_UINT16_ARRAY 22 /* 'Uint16Array' */ #define DUK_HEAP_STRING_UINT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT16_ARRAY) #define DUK_HTHREAD_STRING_UINT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT16_ARRAY) -#define DUK_STRIDX_INT32_ARRAY 22 /* 'Int32Array' */ +#define DUK_STRIDX_INT32_ARRAY 23 /* 'Int32Array' */ #define DUK_HEAP_STRING_INT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT32_ARRAY) #define DUK_HTHREAD_STRING_INT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT32_ARRAY) -#define DUK_STRIDX_UINT32_ARRAY 23 /* 'Uint32Array' */ +#define DUK_STRIDX_UINT32_ARRAY 24 /* 'Uint32Array' */ #define DUK_HEAP_STRING_UINT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT32_ARRAY) #define DUK_HTHREAD_STRING_UINT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT32_ARRAY) -#define DUK_STRIDX_FLOAT32_ARRAY 24 /* 'Float32Array' */ +#define DUK_STRIDX_FLOAT32_ARRAY 25 /* 'Float32Array' */ #define DUK_HEAP_STRING_FLOAT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT32_ARRAY) #define DUK_HTHREAD_STRING_FLOAT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT32_ARRAY) -#define DUK_STRIDX_FLOAT64_ARRAY 25 /* 'Float64Array' */ +#define DUK_STRIDX_FLOAT64_ARRAY 26 /* 'Float64Array' */ #define DUK_HEAP_STRING_FLOAT64_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT64_ARRAY) #define DUK_HTHREAD_STRING_FLOAT64_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT64_ARRAY) -#define DUK_STRIDX_GLOBAL 26 /* 'global' */ +#define DUK_STRIDX_GLOBAL 27 /* 'global' */ #define DUK_HEAP_STRING_GLOBAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL) #define DUK_HTHREAD_STRING_GLOBAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL) -#define DUK_STRIDX_OBJ_ENV 27 /* 'ObjEnv' */ +#define DUK_STRIDX_OBJ_ENV 28 /* 'ObjEnv' */ #define DUK_HEAP_STRING_OBJ_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV) #define DUK_HTHREAD_STRING_OBJ_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV) -#define DUK_STRIDX_DEC_ENV 28 /* 'DecEnv' */ +#define DUK_STRIDX_DEC_ENV 29 /* 'DecEnv' */ #define DUK_HEAP_STRING_DEC_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV) #define DUK_HTHREAD_STRING_DEC_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV) -#define DUK_STRIDX_UC_BUFFER 29 /* 'Buffer' */ +#define DUK_STRIDX_UC_BUFFER 30 /* 'Buffer' */ #define DUK_HEAP_STRING_UC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER) #define DUK_HTHREAD_STRING_UC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER) -#define DUK_STRIDX_UC_POINTER 30 /* 'Pointer' */ +#define DUK_STRIDX_UC_POINTER 31 /* 'Pointer' */ #define DUK_HEAP_STRING_UC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER) #define DUK_HTHREAD_STRING_UC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER) -#define DUK_STRIDX_UC_THREAD 31 /* 'Thread' */ +#define DUK_STRIDX_UC_THREAD 32 /* 'Thread' */ #define DUK_HEAP_STRING_UC_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD) #define DUK_HTHREAD_STRING_UC_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD) -#define DUK_STRIDX_EVAL 32 /* 'eval' */ +#define DUK_STRIDX_EVAL 33 /* 'eval' */ #define DUK_HEAP_STRING_EVAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL) #define DUK_HTHREAD_STRING_EVAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL) -#define DUK_STRIDX_DEFINE_PROPERTY 33 /* 'defineProperty' */ -#define DUK_HEAP_STRING_DEFINE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFINE_PROPERTY) -#define DUK_HTHREAD_STRING_DEFINE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFINE_PROPERTY) #define DUK_STRIDX_VALUE 34 /* 'value' */ #define DUK_HEAP_STRING_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE) #define DUK_HTHREAD_STRING_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE) @@ -1029,9 +1164,9 @@ DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x) #define DUK_STRIDX_LAST_INDEX 47 /* 'lastIndex' */ #define DUK_HEAP_STRING_LAST_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX) #define DUK_HTHREAD_STRING_LAST_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX) -#define DUK_STRIDX_ESCAPED_EMPTY_REGEXP 48 /* '(?:)' */ -#define DUK_HEAP_STRING_ESCAPED_EMPTY_REGEXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ESCAPED_EMPTY_REGEXP) -#define DUK_HTHREAD_STRING_ESCAPED_EMPTY_REGEXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ESCAPED_EMPTY_REGEXP) +#define DUK_STRIDX_FLAGS 48 /* 'flags' */ +#define DUK_HEAP_STRING_FLAGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLAGS) +#define DUK_HTHREAD_STRING_FLAGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLAGS) #define DUK_STRIDX_INDEX 49 /* 'index' */ #define DUK_HEAP_STRING_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX) #define DUK_HTHREAD_STRING_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX) @@ -1053,30 +1188,30 @@ DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x) #define DUK_STRIDX_LC_STRING 55 /* 'string' */ #define DUK_HEAP_STRING_LC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING) #define DUK_HTHREAD_STRING_LC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING) -#define DUK_STRIDX_LC_OBJECT 56 /* 'object' */ +#define DUK_STRIDX_LC_SYMBOL 56 /* 'symbol' */ +#define DUK_HEAP_STRING_LC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_SYMBOL) +#define DUK_HTHREAD_STRING_LC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_SYMBOL) +#define DUK_STRIDX_LC_OBJECT 57 /* 'object' */ #define DUK_HEAP_STRING_LC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT) #define DUK_HTHREAD_STRING_LC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT) -#define DUK_STRIDX_LC_UNDEFINED 57 /* 'undefined' */ +#define DUK_STRIDX_LC_UNDEFINED 58 /* 'undefined' */ #define DUK_HEAP_STRING_LC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_UNDEFINED) #define DUK_HTHREAD_STRING_LC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_UNDEFINED) -#define DUK_STRIDX_NAN 58 /* 'NaN' */ +#define DUK_STRIDX_NAN 59 /* 'NaN' */ #define DUK_HEAP_STRING_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN) #define DUK_HTHREAD_STRING_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN) -#define DUK_STRIDX_INFINITY 59 /* 'Infinity' */ +#define DUK_STRIDX_INFINITY 60 /* 'Infinity' */ #define DUK_HEAP_STRING_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY) #define DUK_HTHREAD_STRING_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY) -#define DUK_STRIDX_MINUS_INFINITY 60 /* '-Infinity' */ +#define DUK_STRIDX_MINUS_INFINITY 61 /* '-Infinity' */ #define DUK_HEAP_STRING_MINUS_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY) #define DUK_HTHREAD_STRING_MINUS_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY) -#define DUK_STRIDX_MINUS_ZERO 61 /* '-0' */ +#define DUK_STRIDX_MINUS_ZERO 62 /* '-0' */ #define DUK_HEAP_STRING_MINUS_ZERO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO) #define DUK_HTHREAD_STRING_MINUS_ZERO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO) -#define DUK_STRIDX_COMMA 62 /* ',' */ +#define DUK_STRIDX_COMMA 63 /* ',' */ #define DUK_HEAP_STRING_COMMA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA) #define DUK_HTHREAD_STRING_COMMA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA) -#define DUK_STRIDX_SPACE 63 /* ' ' */ -#define DUK_HEAP_STRING_SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPACE) -#define DUK_HTHREAD_STRING_SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPACE) #define DUK_STRIDX_NEWLINE_4SPACE 64 /* '\n ' */ #define DUK_HEAP_STRING_NEWLINE_4SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_4SPACE) #define DUK_HTHREAD_STRING_NEWLINE_4SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_4SPACE) @@ -1095,388 +1230,316 @@ DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x) #define DUK_STRIDX_CALLER 69 /* 'caller' */ #define DUK_HEAP_STRING_CALLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER) #define DUK_HTHREAD_STRING_CALLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER) -#define DUK_STRIDX_HAS 70 /* 'has' */ -#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS) -#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS) +#define DUK_STRIDX_DELETE_PROPERTY 70 /* 'deleteProperty' */ +#define DUK_HEAP_STRING_DELETE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY) +#define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY) #define DUK_STRIDX_GET 71 /* 'get' */ #define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET) #define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET) -#define DUK_STRIDX_DELETE_PROPERTY 72 /* 'deleteProperty' */ -#define DUK_HEAP_STRING_DELETE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY) -#define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY) -#define DUK_STRIDX_ENUMERATE 73 /* 'enumerate' */ -#define DUK_HEAP_STRING_ENUMERATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERATE) -#define DUK_HTHREAD_STRING_ENUMERATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERATE) -#define DUK_STRIDX_OWN_KEYS 74 /* 'ownKeys' */ +#define DUK_STRIDX_HAS 72 /* 'has' */ +#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS) +#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS) +#define DUK_STRIDX_OWN_KEYS 73 /* 'ownKeys' */ #define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS) #define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS) -#define DUK_STRIDX_SET_PROTOTYPE_OF 75 /* 'setPrototypeOf' */ +#define DUK_STRIDX_SET_PROTOTYPE_OF 74 /* 'setPrototypeOf' */ #define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF) #define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF) -#define DUK_STRIDX___PROTO__ 76 /* '__proto__' */ +#define DUK_STRIDX___PROTO__ 75 /* '__proto__' */ #define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__) #define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__) -#define DUK_STRIDX_REQUIRE 77 /* 'require' */ -#define DUK_HEAP_STRING_REQUIRE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REQUIRE) -#define DUK_HTHREAD_STRING_REQUIRE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REQUIRE) -#define DUK_STRIDX_ID 78 /* 'id' */ -#define DUK_HEAP_STRING_ID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ID) -#define DUK_HTHREAD_STRING_ID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ID) -#define DUK_STRIDX_EXPORTS 79 /* 'exports' */ -#define DUK_HEAP_STRING_EXPORTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORTS) -#define DUK_HTHREAD_STRING_EXPORTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORTS) -#define DUK_STRIDX_FILENAME 80 /* 'filename' */ -#define DUK_HEAP_STRING_FILENAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILENAME) -#define DUK_HTHREAD_STRING_FILENAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILENAME) -#define DUK_STRIDX_TO_STRING 81 /* 'toString' */ +#define DUK_STRIDX_TO_STRING 76 /* 'toString' */ #define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING) #define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING) -#define DUK_STRIDX_TO_JSON 82 /* 'toJSON' */ +#define DUK_STRIDX_TO_JSON 77 /* 'toJSON' */ #define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON) #define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON) -#define DUK_STRIDX_TYPE 83 /* 'type' */ +#define DUK_STRIDX_TYPE 78 /* 'type' */ #define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE) #define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE) -#define DUK_STRIDX_DATA 84 /* 'data' */ +#define DUK_STRIDX_DATA 79 /* 'data' */ #define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA) #define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA) -#define DUK_STRIDX_LENGTH 85 /* 'length' */ +#define DUK_STRIDX_LENGTH 80 /* 'length' */ #define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH) #define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH) -#define DUK_STRIDX_BYTE_LENGTH 86 /* 'byteLength' */ -#define DUK_HEAP_STRING_BYTE_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTE_LENGTH) -#define DUK_HTHREAD_STRING_BYTE_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTE_LENGTH) -#define DUK_STRIDX_BYTE_OFFSET 87 /* 'byteOffset' */ -#define DUK_HEAP_STRING_BYTE_OFFSET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTE_OFFSET) -#define DUK_HTHREAD_STRING_BYTE_OFFSET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTE_OFFSET) -#define DUK_STRIDX_BYTES_PER_ELEMENT 88 /* 'BYTES_PER_ELEMENT' */ -#define DUK_HEAP_STRING_BYTES_PER_ELEMENT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTES_PER_ELEMENT) -#define DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTES_PER_ELEMENT) -#define DUK_STRIDX_SET 89 /* 'set' */ +#define DUK_STRIDX_SET 81 /* 'set' */ #define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET) #define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET) -#define DUK_STRIDX_STACK 90 /* 'stack' */ +#define DUK_STRIDX_STACK 82 /* 'stack' */ #define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK) #define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK) -#define DUK_STRIDX_PC 91 /* 'pc' */ +#define DUK_STRIDX_PC 83 /* 'pc' */ #define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC) #define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC) -#define DUK_STRIDX_LINE_NUMBER 92 /* 'lineNumber' */ +#define DUK_STRIDX_LINE_NUMBER 84 /* 'lineNumber' */ #define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER) #define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER) -#define DUK_STRIDX_INT_TRACEDATA 93 /* '\xffTracedata' */ +#define DUK_STRIDX_INT_TRACEDATA 85 /* '\xffTracedata' */ #define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA) #define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA) -#define DUK_STRIDX_NAME 94 /* 'name' */ +#define DUK_STRIDX_NAME 86 /* 'name' */ #define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME) #define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME) -#define DUK_STRIDX_FILE_NAME 95 /* 'fileName' */ +#define DUK_STRIDX_FILE_NAME 87 /* 'fileName' */ #define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME) #define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME) -#define DUK_STRIDX_LC_BUFFER 96 /* 'buffer' */ -#define DUK_HEAP_STRING_LC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BUFFER) -#define DUK_HTHREAD_STRING_LC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BUFFER) -#define DUK_STRIDX_LC_POINTER 97 /* 'pointer' */ +#define DUK_STRIDX_LC_POINTER 88 /* 'pointer' */ #define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER) #define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER) -#define DUK_STRIDX_INT_VALUE 98 /* '\xffValue' */ +#define DUK_STRIDX_INT_VALUE 89 /* '\xffValue' */ #define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE) #define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE) -#define DUK_STRIDX_INT_NEXT 99 /* '\xffNext' */ +#define DUK_STRIDX_INT_NEXT 90 /* '\xffNext' */ #define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT) #define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT) -#define DUK_STRIDX_INT_BYTECODE 100 /* '\xffBytecode' */ +#define DUK_STRIDX_INT_BYTECODE 91 /* '\xffBytecode' */ #define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE) #define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE) -#define DUK_STRIDX_INT_FORMALS 101 /* '\xffFormals' */ +#define DUK_STRIDX_INT_FORMALS 92 /* '\xffFormals' */ #define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS) #define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS) -#define DUK_STRIDX_INT_VARMAP 102 /* '\xffVarmap' */ +#define DUK_STRIDX_INT_VARMAP 93 /* '\xffVarmap' */ #define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP) #define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP) -#define DUK_STRIDX_INT_LEXENV 103 /* '\xffLexenv' */ -#define DUK_HEAP_STRING_INT_LEXENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_LEXENV) -#define DUK_HTHREAD_STRING_INT_LEXENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_LEXENV) -#define DUK_STRIDX_INT_VARENV 104 /* '\xffVarenv' */ -#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV) -#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV) -#define DUK_STRIDX_INT_SOURCE 105 /* '\xffSource' */ +#define DUK_STRIDX_INT_SOURCE 94 /* '\xffSource' */ #define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE) #define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE) -#define DUK_STRIDX_INT_PC2LINE 106 /* '\xffPc2line' */ +#define DUK_STRIDX_INT_PC2LINE 95 /* '\xffPc2line' */ #define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE) #define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE) -#define DUK_STRIDX_INT_ARGS 107 /* '\xffArgs' */ +#define DUK_STRIDX_INT_ARGS 96 /* '\xffArgs' */ #define DUK_HEAP_STRING_INT_ARGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_ARGS) #define DUK_HTHREAD_STRING_INT_ARGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_ARGS) -#define DUK_STRIDX_INT_MAP 108 /* '\xffMap' */ +#define DUK_STRIDX_INT_MAP 97 /* '\xffMap' */ #define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP) #define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP) -#define DUK_STRIDX_INT_FINALIZER 109 /* '\xffFinalizer' */ +#define DUK_STRIDX_INT_VARENV 98 /* '\xffVarenv' */ +#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV) +#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV) +#define DUK_STRIDX_INT_FINALIZER 99 /* '\xffFinalizer' */ #define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER) #define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER) -#define DUK_STRIDX_INT_HANDLER 110 /* '\xffHandler' */ +#define DUK_STRIDX_INT_HANDLER 100 /* '\xffHandler' */ #define DUK_HEAP_STRING_INT_HANDLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_HANDLER) #define DUK_HTHREAD_STRING_INT_HANDLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_HANDLER) -#define DUK_STRIDX_INT_CALLEE 111 /* '\xffCallee' */ +#define DUK_STRIDX_INT_CALLEE 101 /* '\xffCallee' */ #define DUK_HEAP_STRING_INT_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_CALLEE) #define DUK_HTHREAD_STRING_INT_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_CALLEE) -#define DUK_STRIDX_INT_THREAD 112 /* '\xffThread' */ +#define DUK_STRIDX_INT_THREAD 102 /* '\xffThread' */ #define DUK_HEAP_STRING_INT_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THREAD) #define DUK_HTHREAD_STRING_INT_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THREAD) -#define DUK_STRIDX_INT_REGBASE 113 /* '\xffRegbase' */ +#define DUK_STRIDX_INT_REGBASE 103 /* '\xffRegbase' */ #define DUK_HEAP_STRING_INT_REGBASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_REGBASE) #define DUK_HTHREAD_STRING_INT_REGBASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_REGBASE) -#define DUK_STRIDX_INT_TARGET 114 /* '\xffTarget' */ +#define DUK_STRIDX_INT_TARGET 104 /* '\xffTarget' */ #define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET) #define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET) -#define DUK_STRIDX_INT_THIS 115 /* '\xffThis' */ +#define DUK_STRIDX_INT_THIS 105 /* '\xffThis' */ #define DUK_HEAP_STRING_INT_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS) #define DUK_HTHREAD_STRING_INT_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS) -#define DUK_STRIDX_COMPILE 116 /* 'compile' */ +#define DUK_STRIDX_COMPILE 106 /* 'compile' */ #define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE) #define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE) -#define DUK_STRIDX_INPUT 117 /* 'input' */ +#define DUK_STRIDX_INPUT 107 /* 'input' */ #define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT) #define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT) -#define DUK_STRIDX_ERR_CREATE 118 /* 'errCreate' */ +#define DUK_STRIDX_ERR_CREATE 108 /* 'errCreate' */ #define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE) #define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE) -#define DUK_STRIDX_ERR_THROW 119 /* 'errThrow' */ +#define DUK_STRIDX_ERR_THROW 109 /* 'errThrow' */ #define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW) #define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW) -#define DUK_STRIDX_MOD_SEARCH 120 /* 'modSearch' */ -#define DUK_HEAP_STRING_MOD_SEARCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MOD_SEARCH) -#define DUK_HTHREAD_STRING_MOD_SEARCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MOD_SEARCH) -#define DUK_STRIDX_MOD_LOADED 121 /* 'modLoaded' */ -#define DUK_HEAP_STRING_MOD_LOADED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MOD_LOADED) -#define DUK_HTHREAD_STRING_MOD_LOADED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MOD_LOADED) -#define DUK_STRIDX_ENV 122 /* 'env' */ +#define DUK_STRIDX_ENV 110 /* 'env' */ #define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV) #define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV) -#define DUK_STRIDX_HEX 123 /* 'hex' */ +#define DUK_STRIDX_HEX 111 /* 'hex' */ #define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX) #define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX) -#define DUK_STRIDX_BASE64 124 /* 'base64' */ +#define DUK_STRIDX_BASE64 112 /* 'base64' */ #define DUK_HEAP_STRING_BASE64(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64) #define DUK_HTHREAD_STRING_BASE64(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64) -#define DUK_STRIDX_JX 125 /* 'jx' */ +#define DUK_STRIDX_JX 113 /* 'jx' */ #define DUK_HEAP_STRING_JX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX) #define DUK_HTHREAD_STRING_JX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX) -#define DUK_STRIDX_JC 126 /* 'jc' */ +#define DUK_STRIDX_JC 114 /* 'jc' */ #define DUK_HEAP_STRING_JC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC) #define DUK_HTHREAD_STRING_JC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC) -#define DUK_STRIDX_RESUME 127 /* 'resume' */ +#define DUK_STRIDX_RESUME 115 /* 'resume' */ #define DUK_HEAP_STRING_RESUME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RESUME) #define DUK_HTHREAD_STRING_RESUME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RESUME) -#define DUK_STRIDX_FMT 128 /* 'fmt' */ -#define DUK_HEAP_STRING_FMT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FMT) -#define DUK_HTHREAD_STRING_FMT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FMT) -#define DUK_STRIDX_RAW 129 /* 'raw' */ -#define DUK_HEAP_STRING_RAW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RAW) -#define DUK_HTHREAD_STRING_RAW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RAW) -#define DUK_STRIDX_LC_TRACE 130 /* 'trace' */ -#define DUK_HEAP_STRING_LC_TRACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_TRACE) -#define DUK_HTHREAD_STRING_LC_TRACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_TRACE) -#define DUK_STRIDX_LC_DEBUG 131 /* 'debug' */ -#define DUK_HEAP_STRING_LC_DEBUG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_DEBUG) -#define DUK_HTHREAD_STRING_LC_DEBUG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_DEBUG) -#define DUK_STRIDX_LC_INFO 132 /* 'info' */ -#define DUK_HEAP_STRING_LC_INFO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_INFO) -#define DUK_HTHREAD_STRING_LC_INFO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_INFO) -#define DUK_STRIDX_LC_WARN 133 /* 'warn' */ -#define DUK_HEAP_STRING_LC_WARN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_WARN) -#define DUK_HTHREAD_STRING_LC_WARN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_WARN) -#define DUK_STRIDX_LC_ERROR 134 /* 'error' */ -#define DUK_HEAP_STRING_LC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ERROR) -#define DUK_HTHREAD_STRING_LC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ERROR) -#define DUK_STRIDX_LC_FATAL 135 /* 'fatal' */ -#define DUK_HEAP_STRING_LC_FATAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FATAL) -#define DUK_HTHREAD_STRING_LC_FATAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FATAL) -#define DUK_STRIDX_LC_N 136 /* 'n' */ -#define DUK_HEAP_STRING_LC_N(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_N) -#define DUK_HTHREAD_STRING_LC_N(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_N) -#define DUK_STRIDX_LC_L 137 /* 'l' */ -#define DUK_HEAP_STRING_LC_L(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_L) -#define DUK_HTHREAD_STRING_LC_L(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_L) -#define DUK_STRIDX_CLOG 138 /* 'clog' */ -#define DUK_HEAP_STRING_CLOG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLOG) -#define DUK_HTHREAD_STRING_CLOG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLOG) -#define DUK_STRIDX_TO_LOG_STRING 139 /* 'toLogString' */ -#define DUK_HEAP_STRING_TO_LOG_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOG_STRING) -#define DUK_HTHREAD_STRING_TO_LOG_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOG_STRING) -#define DUK_STRIDX_JSON_EXT_UNDEFINED 140 /* '{"_undef":true}' */ +#define DUK_STRIDX_JSON_EXT_UNDEFINED 116 /* '{"_undef":true}' */ #define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED) #define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED) -#define DUK_STRIDX_JSON_EXT_NAN 141 /* '{"_nan":true}' */ +#define DUK_STRIDX_JSON_EXT_NAN 117 /* '{"_nan":true}' */ #define DUK_HEAP_STRING_JSON_EXT_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN) #define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN) -#define DUK_STRIDX_JSON_EXT_POSINF 142 /* '{"_inf":true}' */ +#define DUK_STRIDX_JSON_EXT_POSINF 118 /* '{"_inf":true}' */ #define DUK_HEAP_STRING_JSON_EXT_POSINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF) #define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF) -#define DUK_STRIDX_JSON_EXT_NEGINF 143 /* '{"_ninf":true}' */ +#define DUK_STRIDX_JSON_EXT_NEGINF 119 /* '{"_ninf":true}' */ #define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF) #define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF) -#define DUK_STRIDX_JSON_EXT_FUNCTION1 144 /* '{"_func":true}' */ +#define DUK_STRIDX_JSON_EXT_FUNCTION1 120 /* '{"_func":true}' */ #define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1) #define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1) -#define DUK_STRIDX_JSON_EXT_FUNCTION2 145 /* '{_func:true}' */ +#define DUK_STRIDX_JSON_EXT_FUNCTION2 121 /* '{_func:true}' */ #define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2) #define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2) -#define DUK_STRIDX_BREAK 146 /* 'break' */ +#define DUK_STRIDX_BREAK 122 /* 'break' */ #define DUK_HEAP_STRING_BREAK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK) #define DUK_HTHREAD_STRING_BREAK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK) -#define DUK_STRIDX_CASE 147 /* 'case' */ +#define DUK_STRIDX_CASE 123 /* 'case' */ #define DUK_HEAP_STRING_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE) #define DUK_HTHREAD_STRING_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE) -#define DUK_STRIDX_CATCH 148 /* 'catch' */ +#define DUK_STRIDX_CATCH 124 /* 'catch' */ #define DUK_HEAP_STRING_CATCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH) #define DUK_HTHREAD_STRING_CATCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH) -#define DUK_STRIDX_CONTINUE 149 /* 'continue' */ +#define DUK_STRIDX_CONTINUE 125 /* 'continue' */ #define DUK_HEAP_STRING_CONTINUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE) #define DUK_HTHREAD_STRING_CONTINUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE) -#define DUK_STRIDX_DEBUGGER 150 /* 'debugger' */ +#define DUK_STRIDX_DEBUGGER 126 /* 'debugger' */ #define DUK_HEAP_STRING_DEBUGGER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER) #define DUK_HTHREAD_STRING_DEBUGGER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER) -#define DUK_STRIDX_DEFAULT 151 /* 'default' */ +#define DUK_STRIDX_DEFAULT 127 /* 'default' */ #define DUK_HEAP_STRING_DEFAULT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT) #define DUK_HTHREAD_STRING_DEFAULT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT) -#define DUK_STRIDX_DELETE 152 /* 'delete' */ +#define DUK_STRIDX_DELETE 128 /* 'delete' */ #define DUK_HEAP_STRING_DELETE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE) #define DUK_HTHREAD_STRING_DELETE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE) -#define DUK_STRIDX_DO 153 /* 'do' */ +#define DUK_STRIDX_DO 129 /* 'do' */ #define DUK_HEAP_STRING_DO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO) #define DUK_HTHREAD_STRING_DO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO) -#define DUK_STRIDX_ELSE 154 /* 'else' */ +#define DUK_STRIDX_ELSE 130 /* 'else' */ #define DUK_HEAP_STRING_ELSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE) #define DUK_HTHREAD_STRING_ELSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE) -#define DUK_STRIDX_FINALLY 155 /* 'finally' */ +#define DUK_STRIDX_FINALLY 131 /* 'finally' */ #define DUK_HEAP_STRING_FINALLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY) #define DUK_HTHREAD_STRING_FINALLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY) -#define DUK_STRIDX_FOR 156 /* 'for' */ +#define DUK_STRIDX_FOR 132 /* 'for' */ #define DUK_HEAP_STRING_FOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR) #define DUK_HTHREAD_STRING_FOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR) -#define DUK_STRIDX_LC_FUNCTION 157 /* 'function' */ +#define DUK_STRIDX_LC_FUNCTION 133 /* 'function' */ #define DUK_HEAP_STRING_LC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION) #define DUK_HTHREAD_STRING_LC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION) -#define DUK_STRIDX_IF 158 /* 'if' */ +#define DUK_STRIDX_IF 134 /* 'if' */ #define DUK_HEAP_STRING_IF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF) #define DUK_HTHREAD_STRING_IF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF) -#define DUK_STRIDX_IN 159 /* 'in' */ +#define DUK_STRIDX_IN 135 /* 'in' */ #define DUK_HEAP_STRING_IN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN) #define DUK_HTHREAD_STRING_IN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN) -#define DUK_STRIDX_INSTANCEOF 160 /* 'instanceof' */ +#define DUK_STRIDX_INSTANCEOF 136 /* 'instanceof' */ #define DUK_HEAP_STRING_INSTANCEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF) #define DUK_HTHREAD_STRING_INSTANCEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF) -#define DUK_STRIDX_NEW 161 /* 'new' */ +#define DUK_STRIDX_NEW 137 /* 'new' */ #define DUK_HEAP_STRING_NEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW) #define DUK_HTHREAD_STRING_NEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW) -#define DUK_STRIDX_RETURN 162 /* 'return' */ +#define DUK_STRIDX_RETURN 138 /* 'return' */ #define DUK_HEAP_STRING_RETURN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN) #define DUK_HTHREAD_STRING_RETURN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN) -#define DUK_STRIDX_SWITCH 163 /* 'switch' */ +#define DUK_STRIDX_SWITCH 139 /* 'switch' */ #define DUK_HEAP_STRING_SWITCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH) #define DUK_HTHREAD_STRING_SWITCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH) -#define DUK_STRIDX_THIS 164 /* 'this' */ +#define DUK_STRIDX_THIS 140 /* 'this' */ #define DUK_HEAP_STRING_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS) #define DUK_HTHREAD_STRING_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS) -#define DUK_STRIDX_THROW 165 /* 'throw' */ +#define DUK_STRIDX_THROW 141 /* 'throw' */ #define DUK_HEAP_STRING_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW) #define DUK_HTHREAD_STRING_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW) -#define DUK_STRIDX_TRY 166 /* 'try' */ +#define DUK_STRIDX_TRY 142 /* 'try' */ #define DUK_HEAP_STRING_TRY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY) #define DUK_HTHREAD_STRING_TRY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY) -#define DUK_STRIDX_TYPEOF 167 /* 'typeof' */ +#define DUK_STRIDX_TYPEOF 143 /* 'typeof' */ #define DUK_HEAP_STRING_TYPEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF) #define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF) -#define DUK_STRIDX_VAR 168 /* 'var' */ +#define DUK_STRIDX_VAR 144 /* 'var' */ #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_STRIDX_CONST 169 /* 'const' */ +#define DUK_STRIDX_CONST 145 /* 'const' */ #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_STRIDX_VOID 170 /* 'void' */ +#define DUK_STRIDX_VOID 146 /* 'void' */ #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_STRIDX_WHILE 171 /* 'while' */ +#define DUK_STRIDX_WHILE 147 /* 'while' */ #define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE) #define DUK_HTHREAD_STRING_WHILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE) -#define DUK_STRIDX_WITH 172 /* 'with' */ +#define DUK_STRIDX_WITH 148 /* 'with' */ #define DUK_HEAP_STRING_WITH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH) #define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH) -#define DUK_STRIDX_CLASS 173 /* 'class' */ +#define DUK_STRIDX_CLASS 149 /* 'class' */ #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_STRIDX_ENUM 174 /* 'enum' */ +#define DUK_STRIDX_ENUM 150 /* 'enum' */ #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_STRIDX_EXPORT 175 /* 'export' */ +#define DUK_STRIDX_EXPORT 151 /* 'export' */ #define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT) #define DUK_HTHREAD_STRING_EXPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT) -#define DUK_STRIDX_EXTENDS 176 /* 'extends' */ +#define DUK_STRIDX_EXTENDS 152 /* 'extends' */ #define DUK_HEAP_STRING_EXTENDS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS) #define DUK_HTHREAD_STRING_EXTENDS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS) -#define DUK_STRIDX_IMPORT 177 /* 'import' */ +#define DUK_STRIDX_IMPORT 153 /* 'import' */ #define DUK_HEAP_STRING_IMPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT) #define DUK_HTHREAD_STRING_IMPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT) -#define DUK_STRIDX_SUPER 178 /* 'super' */ +#define DUK_STRIDX_SUPER 154 /* 'super' */ #define DUK_HEAP_STRING_SUPER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER) #define DUK_HTHREAD_STRING_SUPER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER) -#define DUK_STRIDX_LC_NULL 179 /* 'null' */ +#define DUK_STRIDX_LC_NULL 155 /* 'null' */ #define DUK_HEAP_STRING_LC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL) #define DUK_HTHREAD_STRING_LC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL) -#define DUK_STRIDX_TRUE 180 /* 'true' */ +#define DUK_STRIDX_TRUE 156 /* 'true' */ #define DUK_HEAP_STRING_TRUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE) #define DUK_HTHREAD_STRING_TRUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE) -#define DUK_STRIDX_FALSE 181 /* 'false' */ +#define DUK_STRIDX_FALSE 157 /* 'false' */ #define DUK_HEAP_STRING_FALSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE) #define DUK_HTHREAD_STRING_FALSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE) -#define DUK_STRIDX_IMPLEMENTS 182 /* 'implements' */ +#define DUK_STRIDX_IMPLEMENTS 158 /* 'implements' */ #define DUK_HEAP_STRING_IMPLEMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS) #define DUK_HTHREAD_STRING_IMPLEMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS) -#define DUK_STRIDX_INTERFACE 183 /* 'interface' */ +#define DUK_STRIDX_INTERFACE 159 /* 'interface' */ #define DUK_HEAP_STRING_INTERFACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE) #define DUK_HTHREAD_STRING_INTERFACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE) -#define DUK_STRIDX_LET 184 /* 'let' */ +#define DUK_STRIDX_LET 160 /* 'let' */ #define DUK_HEAP_STRING_LET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET) #define DUK_HTHREAD_STRING_LET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET) -#define DUK_STRIDX_PACKAGE 185 /* 'package' */ +#define DUK_STRIDX_PACKAGE 161 /* 'package' */ #define DUK_HEAP_STRING_PACKAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE) #define DUK_HTHREAD_STRING_PACKAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE) -#define DUK_STRIDX_PRIVATE 186 /* 'private' */ +#define DUK_STRIDX_PRIVATE 162 /* 'private' */ #define DUK_HEAP_STRING_PRIVATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE) #define DUK_HTHREAD_STRING_PRIVATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE) -#define DUK_STRIDX_PROTECTED 187 /* 'protected' */ +#define DUK_STRIDX_PROTECTED 163 /* 'protected' */ #define DUK_HEAP_STRING_PROTECTED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED) #define DUK_HTHREAD_STRING_PROTECTED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED) -#define DUK_STRIDX_PUBLIC 188 /* 'public' */ +#define DUK_STRIDX_PUBLIC 164 /* 'public' */ #define DUK_HEAP_STRING_PUBLIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC) #define DUK_HTHREAD_STRING_PUBLIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC) -#define DUK_STRIDX_STATIC 189 /* 'static' */ +#define DUK_STRIDX_STATIC 165 /* 'static' */ #define DUK_HEAP_STRING_STATIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC) #define DUK_HTHREAD_STRING_STATIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC) -#define DUK_STRIDX_YIELD 190 /* 'yield' */ +#define DUK_STRIDX_YIELD 166 /* 'yield' */ #define DUK_HEAP_STRING_YIELD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD) #define DUK_HTHREAD_STRING_YIELD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD) -#define DUK_HEAP_NUM_STRINGS 191 -#define DUK_STRIDX_START_RESERVED 146 -#define DUK_STRIDX_START_STRICT_RESERVED 182 -#define DUK_STRIDX_END_RESERVED 191 /* exclusive endpoint */ +#define DUK_HEAP_NUM_STRINGS 167 +#define DUK_STRIDX_START_RESERVED 122 +#define DUK_STRIDX_START_STRICT_RESERVED 158 +#define DUK_STRIDX_END_RESERVED 167 /* exclusive endpoint */ /* To convert a heap stridx to a token number, subtract * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED. */ #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[1049]; +DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[921]; #endif /* !DUK_SINGLE_FILE */ #define DUK_STRDATA_MAX_STRLEN 17 -#define DUK_STRDATA_DATA_LENGTH 1049 +#define DUK_STRDATA_DATA_LENGTH 921 #endif /* DUK_USE_ROM_STRINGS */ #if defined(DUK_USE_ROM_OBJECTS) -#error ROM support not enabled, rerun make_dist.py with --rom-support -#else +#error RAM support not enabled, rerun configure.py with --ram-support +#else /* DUK_USE_ROM_OBJECTS */ DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor(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); @@ -1488,15 +1551,15 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_eval(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx); @@ -1508,12 +1571,11 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_escape(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_require(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_assign(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx); @@ -1521,6 +1583,7 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_con DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx); @@ -1547,6 +1610,7 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *c DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_code_point(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx); @@ -1561,6 +1625,7 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_repeat(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx); @@ -1581,7 +1646,9 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_tostring(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_flags(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_shared_getter(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_stack_setter(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx); @@ -1591,6 +1658,7 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_max(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_min(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_random(duk_context *ctx); @@ -1606,16 +1674,21 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_yield(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_resume(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_current(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_delete_property(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_get(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_has(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_set(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_set(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_allocplain(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_plainof(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx); @@ -1626,15 +1699,13 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx); #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149]; -#endif /* !DUK_SINGLE_FILE */ -#if defined(DUK_USE_BUILTIN_INITJS) -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[204]; +DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[164]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTIN_INITJS_DATA_LENGTH 204 -#endif /* DUK_USE_BUILTIN_INITJS */ #define DUK_BIDX_GLOBAL 0 #define DUK_BIDX_GLOBAL_ENV 1 #define DUK_BIDX_OBJECT_CONSTRUCTOR 2 @@ -1670,79 +1741,96 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[204]; #define DUK_BIDX_MATH 32 #define DUK_BIDX_JSON 33 #define DUK_BIDX_TYPE_ERROR_THROWER 34 -#define DUK_BIDX_PROXY_CONSTRUCTOR 35 -#define DUK_BIDX_DUKTAPE 36 -#define DUK_BIDX_THREAD_CONSTRUCTOR 37 -#define DUK_BIDX_THREAD_PROTOTYPE 38 -#define DUK_BIDX_BUFFER_CONSTRUCTOR 39 -#define DUK_BIDX_BUFFER_PROTOTYPE 40 -#define DUK_BIDX_POINTER_CONSTRUCTOR 41 -#define DUK_BIDX_POINTER_PROTOTYPE 42 -#define DUK_BIDX_LOGGER_CONSTRUCTOR 43 -#define DUK_BIDX_LOGGER_PROTOTYPE 44 -#define DUK_BIDX_DOUBLE_ERROR 45 -#define DUK_BIDX_ARRAYBUFFER_CONSTRUCTOR 46 -#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 47 -#define DUK_BIDX_DATAVIEW_CONSTRUCTOR 48 -#define DUK_BIDX_DATAVIEW_PROTOTYPE 49 -#define DUK_BIDX_TYPEDARRAY_PROTOTYPE 50 -#define DUK_BIDX_INT8ARRAY_CONSTRUCTOR 51 -#define DUK_BIDX_INT8ARRAY_PROTOTYPE 52 -#define DUK_BIDX_UINT8ARRAY_CONSTRUCTOR 53 -#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 54 -#define DUK_BIDX_UINT8CLAMPEDARRAY_CONSTRUCTOR 55 -#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 56 -#define DUK_BIDX_INT16ARRAY_CONSTRUCTOR 57 -#define DUK_BIDX_INT16ARRAY_PROTOTYPE 58 -#define DUK_BIDX_UINT16ARRAY_CONSTRUCTOR 59 -#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 60 -#define DUK_BIDX_INT32ARRAY_CONSTRUCTOR 61 -#define DUK_BIDX_INT32ARRAY_PROTOTYPE 62 -#define DUK_BIDX_UINT32ARRAY_CONSTRUCTOR 63 -#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 64 -#define DUK_BIDX_FLOAT32ARRAY_CONSTRUCTOR 65 -#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 66 -#define DUK_BIDX_FLOAT64ARRAY_CONSTRUCTOR 67 -#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 68 -#define DUK_BIDX_NODEJS_BUFFER_CONSTRUCTOR 69 -#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 70 -#define DUK_NUM_BUILTINS 71 -#define DUK_NUM_BIDX_BUILTINS 71 -#define DUK_NUM_ALL_BUILTINS 71 +#define DUK_BIDX_DUKTAPE 35 +#define DUK_BIDX_THREAD_CONSTRUCTOR 36 +#define DUK_BIDX_THREAD_PROTOTYPE 37 +#define DUK_BIDX_POINTER_CONSTRUCTOR 38 +#define DUK_BIDX_POINTER_PROTOTYPE 39 +#define DUK_BIDX_DOUBLE_ERROR 40 +#define DUK_BIDX_PROXY_CONSTRUCTOR 41 +#define DUK_BIDX_REFLECT 42 +#define DUK_BIDX_SYMBOL_PROTOTYPE 43 +#define DUK_BIDX_ARRAYBUFFER_CONSTRUCTOR 44 +#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 45 +#define DUK_BIDX_DATAVIEW_CONSTRUCTOR 46 +#define DUK_BIDX_DATAVIEW_PROTOTYPE 47 +#define DUK_BIDX_TYPEDARRAY_CONSTRUCTOR 48 +#define DUK_BIDX_TYPEDARRAY_PROTOTYPE 49 +#define DUK_BIDX_INT8ARRAY_CONSTRUCTOR 50 +#define DUK_BIDX_INT8ARRAY_PROTOTYPE 51 +#define DUK_BIDX_UINT8ARRAY_CONSTRUCTOR 52 +#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 53 +#define DUK_BIDX_UINT8CLAMPEDARRAY_CONSTRUCTOR 54 +#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 55 +#define DUK_BIDX_INT16ARRAY_CONSTRUCTOR 56 +#define DUK_BIDX_INT16ARRAY_PROTOTYPE 57 +#define DUK_BIDX_UINT16ARRAY_CONSTRUCTOR 58 +#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 59 +#define DUK_BIDX_INT32ARRAY_CONSTRUCTOR 60 +#define DUK_BIDX_INT32ARRAY_PROTOTYPE 61 +#define DUK_BIDX_UINT32ARRAY_CONSTRUCTOR 62 +#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 63 +#define DUK_BIDX_FLOAT32ARRAY_CONSTRUCTOR 64 +#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 65 +#define DUK_BIDX_FLOAT64ARRAY_CONSTRUCTOR 66 +#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 67 +#define DUK_BIDX_NODEJS_BUFFER_CONSTRUCTOR 68 +#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 69 +#define DUK_BIDX_TEXTENCODER_CONSTRUCTOR 70 +#define DUK_BIDX_TEXTENCODER_PROTOTYPE 71 +#define DUK_BIDX_TEXTDECODER_CONSTRUCTOR 72 +#define DUK_BIDX_TEXTDECODER_PROTOTYPE 73 +#define DUK_NUM_BUILTINS 74 +#define DUK_NUM_BIDX_BUILTINS 74 +#define DUK_NUM_ALL_BUILTINS 74 #if defined(DUK_USE_DOUBLE_LE) #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833]; +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3790]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3833 +#define DUK_BUILTINS_DATA_LENGTH 3790 #elif defined(DUK_USE_DOUBLE_BE) #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833]; +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3790]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3833 +#define DUK_BUILTINS_DATA_LENGTH 3790 #elif defined(DUK_USE_DOUBLE_ME) #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833]; +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3790]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3833 +#define DUK_BUILTINS_DATA_LENGTH 3790 #else #error invalid endianness defines #endif #endif /* DUK_USE_ROM_OBJECTS */ #endif /* DUK_BUILTINS_H_INCLUDED */ -#line 52 "duk_internal.h" -#line 1 "duk_util.h" +/* #include duk_util.h */ /* * Utilities */ -#ifndef DUK_UTIL_H_INCLUDED +#if !defined(DUK_UTIL_H_INCLUDED) #define DUK_UTIL_H_INCLUDED #define DUK_UTIL_MIN_HASH_PRIME 17 /* must match genhashsizes.py */ #define DUK_UTIL_GET_HASH_PROBE_STEP(hash) (duk_util_probe_steps[(hash) & 0x1f]) +#if defined(DUK_USE_GET_RANDOM_DOUBLE) +#define DUK_UTIL_GET_RANDOM_DOUBLE(thr) DUK_USE_GET_RANDOM_DOUBLE((thr)->heap_udata) +#else +#define DUK_UTIL_GET_RANDOM_DOUBLE(thr) duk_util_tinyrandom_get_double(thr) +#endif + +/* + * Some useful constants + */ + +#define DUK_DOUBLE_2TO32 4294967296.0 +#define DUK_DOUBLE_2TO31 2147483648.0 +#define DUK_DOUBLE_LOG2E 1.4426950408889634 +#define DUK_DOUBLE_LOG10E 0.4342944819032518 + /* * Endian conversion */ @@ -1773,6 +1861,8 @@ struct duk_bitdecoder_ctx { duk_small_int_t currbits; }; +#define DUK_BD_BITPACKED_STRING_MAXLEN 256 + /* * Bitstream encoder */ @@ -2225,15 +2315,19 @@ DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_s DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size); #endif -DUK_INTERNAL_DECL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits); -DUK_INTERNAL_DECL duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx); -DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value); +DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits); +DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx); +DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value); +DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx); +DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out); DUK_INTERNAL_DECL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits); DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx); -DUK_INTERNAL_DECL duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n); +#if !defined(DUK_USE_GET_RANDOM_DOUBLE) DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr); +#endif DUK_INTERNAL_DECL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf); DUK_INTERNAL_DECL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size); @@ -2250,483 +2344,672 @@ DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_b DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); /* No duk_bw_remove_ensure_slice(), functionality would be identical. */ -DUK_INTERNAL_DECL DUK_INLINE duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p); -DUK_INTERNAL_DECL DUK_INLINE duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p); -DUK_INTERNAL_DECL DUK_INLINE duk_double_t duk_raw_read_double_be(duk_uint8_t **p); -DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val); -DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val); -DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val); +DUK_INTERNAL_DECL duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p); +DUK_INTERNAL_DECL duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p); +DUK_INTERNAL_DECL duk_double_t duk_raw_read_double_be(duk_uint8_t **p); +DUK_INTERNAL_DECL void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val); +DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val); +DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val); #if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */ -DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len); -#endif +DUK_INTERNAL_DECL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len); +#endif + +DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival); +DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival); +DUK_INTERNAL_DECL duk_bool_t duk_double_is_anyinf(duk_double_t x); +DUK_INTERNAL_DECL duk_bool_t duk_double_is_posinf(duk_double_t x); +DUK_INTERNAL_DECL duk_bool_t duk_double_is_neginf(duk_double_t x); +DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan(duk_double_t x); +DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x); +DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x); +DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x); +DUK_INTERNAL_DECL duk_small_uint_t duk_double_signbit(duk_double_t x); +DUK_INTERNAL_DECL duk_double_t duk_double_trunc_towards_zero(duk_double_t x); +DUK_INTERNAL_DECL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y); +DUK_INTERNAL_DECL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y); +DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y); #endif /* DUK_UTIL_H_INCLUDED */ -#line 1 "duk_strings.h" +/* #include duk_strings.h */ /* - * Shared error messages: declarations and macros + * Shared string macros. * - * Error messages are accessed through macros with fine-grained, explicit - * error message distinctions. Concrete error messages are selected by the - * macros and multiple macros can map to the same concrete string to save - * on code footprint. This allows flexible footprint/verbosity tuning with - * minimal code impact. There are a few limitations to this approach: - * (1) switching between plain messages and format strings doesn't work - * conveniently, and (2) conditional strings are a bit awkward to handle. + * Using shared macros helps minimize strings data size because it's easy + * to check if an existing string could be used. String constants don't + * need to be all defined here; defining a string here makes sense if there's + * a high chance the string could be reused. Also, using macros allows + * a call site express the exact string needed, but the macro may map to an + * approximate string to reduce unique string count. Macros can also be + * more easily tuned for low memory targets than #if defined()s throughout + * the code base. * * Because format strings behave differently in the call site (they need to - * be followed by format arguments), they have a special prefix (DUK_STR_FMT_ - * and duk_str_fmt_). + * be followed by format arguments), they use a special prefix DUK_STR_FMT_. * * On some compilers using explicit shared strings is preferable; on others * it may be better to use straight literals because the compiler will combine * them anyway, and such strings won't end up unnecessarily in a symbol table. */ -#ifndef DUK_ERRMSG_H_INCLUDED +#if !defined(DUK_ERRMSG_H_INCLUDED) #define DUK_ERRMSG_H_INCLUDED -#define DUK_STR_INTERNAL_ERROR duk_str_internal_error -#define DUK_STR_INVALID_COUNT duk_str_invalid_count -#define DUK_STR_INVALID_CALL_ARGS duk_str_invalid_call_args -#define DUK_STR_NOT_CONSTRUCTABLE duk_str_not_constructable -#define DUK_STR_NOT_CALLABLE duk_str_not_callable -#define DUK_STR_NOT_EXTENSIBLE duk_str_not_extensible -#define DUK_STR_NOT_WRITABLE duk_str_not_writable -#define DUK_STR_NOT_CONFIGURABLE duk_str_not_configurable - -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const char *duk_str_internal_error; -DUK_INTERNAL_DECL const char *duk_str_invalid_count; -DUK_INTERNAL_DECL const char *duk_str_invalid_call_args; -DUK_INTERNAL_DECL const char *duk_str_not_constructable; -DUK_INTERNAL_DECL const char *duk_str_not_callable; -DUK_INTERNAL_DECL const char *duk_str_not_extensible; -DUK_INTERNAL_DECL const char *duk_str_not_writable; -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_call_args -#define DUK_STR_PUSH_BEYOND_ALLOC_STACK duk_str_push_beyond_alloc_stack -#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_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 -#define DUK_STR_STRING_TOO_LONG duk_str_string_too_long -#define DUK_STR_BUFFER_TOO_LONG duk_str_buffer_too_long -#define DUK_STR_SPRINTF_TOO_LONG duk_str_sprintf_too_long -#define DUK_STR_ALLOC_FAILED duk_str_alloc_failed -#define DUK_STR_POP_TOO_MANY duk_str_pop_too_many -#define DUK_STR_WRONG_BUFFER_TYPE duk_str_wrong_buffer_type -#define DUK_STR_ENCODE_FAILED duk_str_encode_failed -#define DUK_STR_DECODE_FAILED duk_str_decode_failed -#define DUK_STR_NO_SOURCECODE duk_str_no_sourcecode -#define DUK_STR_CONCAT_RESULT_TOO_LONG duk_str_concat_result_too_long -#define DUK_STR_UNIMPLEMENTED duk_str_unimplemented -#define DUK_STR_UNSUPPORTED duk_str_unsupported -#define DUK_STR_ARRAY_LENGTH_OVER_2G duk_str_array_length_over_2g - -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const char *duk_str_invalid_context; -DUK_INTERNAL_DECL const char *duk_str_push_beyond_alloc_stack; -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_defaultvalue_coerce_failed; -DUK_INTERNAL_DECL const char *duk_str_number_outside_range; -DUK_INTERNAL_DECL const char *duk_str_not_object_coercible; -DUK_INTERNAL_DECL const char *duk_str_string_too_long; -DUK_INTERNAL_DECL const char *duk_str_buffer_too_long; -DUK_INTERNAL_DECL const char *duk_str_sprintf_too_long; -DUK_INTERNAL_DECL const char *duk_str_alloc_failed; -DUK_INTERNAL_DECL const char *duk_str_pop_too_many; -DUK_INTERNAL_DECL const char *duk_str_wrong_buffer_type; -DUK_INTERNAL_DECL const char *duk_str_encode_failed; -DUK_INTERNAL_DECL const char *duk_str_decode_failed; -DUK_INTERNAL_DECL const char *duk_str_no_sourcecode; -DUK_INTERNAL_DECL const char *duk_str_concat_result_too_long; -DUK_INTERNAL_DECL const char *duk_str_unimplemented; -DUK_INTERNAL_DECL const char *duk_str_unsupported; -DUK_INTERNAL_DECL const char *duk_str_array_length_over_2g; -#endif /* !DUK_SINGLE_FILE */ - -#define DUK_STR_FMT_PTR duk_str_fmt_ptr -#define DUK_STR_FMT_INVALID_JSON duk_str_fmt_invalid_json -#define DUK_STR_JSONDEC_RECLIMIT duk_str_jsondec_reclimit -#define DUK_STR_JSONENC_RECLIMIT duk_str_jsonenc_reclimit -#define DUK_STR_CYCLIC_INPUT duk_str_cyclic_input - -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const char *duk_str_fmt_ptr; -DUK_INTERNAL_DECL const char *duk_str_fmt_invalid_json; -DUK_INTERNAL_DECL const char *duk_str_jsondec_reclimit; -DUK_INTERNAL_DECL const char *duk_str_jsonenc_reclimit; -DUK_INTERNAL_DECL const char *duk_str_cyclic_input; -#endif /* !DUK_SINGLE_FILE */ - -#define DUK_STR_PROXY_REVOKED duk_str_proxy_revoked -#define DUK_STR_INVALID_BASE duk_str_invalid_base -#define DUK_STR_STRICT_CALLER_READ duk_str_strict_caller_read -#define DUK_STR_PROXY_REJECTED duk_str_proxy_rejected -#define DUK_STR_INVALID_ARRAY_LENGTH duk_str_invalid_array_length -#define DUK_STR_ARRAY_LENGTH_WRITE_FAILED duk_str_array_length_write_failed -#define DUK_STR_ARRAY_LENGTH_NOT_WRITABLE duk_str_array_length_not_writable -#define DUK_STR_SETTER_UNDEFINED duk_str_setter_undefined -#define DUK_STR_REDEFINE_VIRT_PROP duk_str_redefine_virt_prop -#define DUK_STR_INVALID_DESCRIPTOR duk_str_invalid_descriptor -#define DUK_STR_PROPERTY_IS_VIRTUAL duk_str_property_is_virtual - -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const char *duk_str_proxy_revoked; -DUK_INTERNAL_DECL const char *duk_str_invalid_base; -DUK_INTERNAL_DECL const char *duk_str_strict_caller_read; -DUK_INTERNAL_DECL const char *duk_str_proxy_rejected; -DUK_INTERNAL_DECL const char *duk_str_invalid_array_length; -DUK_INTERNAL_DECL const char *duk_str_array_length_write_failed; -DUK_INTERNAL_DECL const char *duk_str_array_length_not_writable; -DUK_INTERNAL_DECL const char *duk_str_setter_undefined; -DUK_INTERNAL_DECL const char *duk_str_redefine_virt_prop; -DUK_INTERNAL_DECL const char *duk_str_invalid_descriptor; -DUK_INTERNAL_DECL const char *duk_str_property_is_virtual; -#endif /* !DUK_SINGLE_FILE */ - -#define DUK_STR_PARSE_ERROR duk_str_parse_error -#define DUK_STR_DUPLICATE_LABEL duk_str_duplicate_label -#define DUK_STR_INVALID_LABEL duk_str_invalid_label -#define DUK_STR_INVALID_ARRAY_LITERAL duk_str_invalid_array_literal -#define DUK_STR_INVALID_OBJECT_LITERAL duk_str_invalid_object_literal -#define DUK_STR_INVALID_VAR_DECLARATION duk_str_invalid_var_declaration -#define DUK_STR_CANNOT_DELETE_IDENTIFIER duk_str_cannot_delete_identifier -#define DUK_STR_INVALID_EXPRESSION duk_str_invalid_expression -#define DUK_STR_INVALID_LVALUE duk_str_invalid_lvalue -#define DUK_STR_EXPECTED_IDENTIFIER duk_str_expected_identifier -#define DUK_STR_EMPTY_EXPR_NOT_ALLOWED duk_str_empty_expr_not_allowed -#define DUK_STR_INVALID_FOR duk_str_invalid_for -#define DUK_STR_INVALID_SWITCH duk_str_invalid_switch -#define DUK_STR_INVALID_BREAK_CONT_LABEL duk_str_invalid_break_cont_label -#define DUK_STR_INVALID_RETURN duk_str_invalid_return -#define DUK_STR_INVALID_TRY duk_str_invalid_try -#define DUK_STR_INVALID_THROW duk_str_invalid_throw -#define DUK_STR_WITH_IN_STRICT_MODE duk_str_with_in_strict_mode -#define DUK_STR_FUNC_STMT_NOT_ALLOWED duk_str_func_stmt_not_allowed -#define DUK_STR_UNTERMINATED_STMT duk_str_unterminated_stmt -#define DUK_STR_INVALID_ARG_NAME duk_str_invalid_arg_name -#define DUK_STR_INVALID_FUNC_NAME duk_str_invalid_func_name -#define DUK_STR_INVALID_GETSET_NAME duk_str_invalid_getset_name -#define DUK_STR_FUNC_NAME_REQUIRED duk_str_func_name_required - -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const char *duk_str_parse_error; -DUK_INTERNAL_DECL const char *duk_str_duplicate_label; -DUK_INTERNAL_DECL const char *duk_str_invalid_label; -DUK_INTERNAL_DECL const char *duk_str_invalid_array_literal; -DUK_INTERNAL_DECL const char *duk_str_invalid_object_literal; -DUK_INTERNAL_DECL const char *duk_str_invalid_var_declaration; -DUK_INTERNAL_DECL const char *duk_str_cannot_delete_identifier; -DUK_INTERNAL_DECL const char *duk_str_invalid_expression; -DUK_INTERNAL_DECL const char *duk_str_invalid_lvalue; -DUK_INTERNAL_DECL const char *duk_str_expected_identifier; -DUK_INTERNAL_DECL const char *duk_str_empty_expr_not_allowed; -DUK_INTERNAL_DECL const char *duk_str_invalid_for; -DUK_INTERNAL_DECL const char *duk_str_invalid_switch; -DUK_INTERNAL_DECL const char *duk_str_invalid_break_cont_label; -DUK_INTERNAL_DECL const char *duk_str_invalid_return; -DUK_INTERNAL_DECL const char *duk_str_invalid_try; -DUK_INTERNAL_DECL const char *duk_str_invalid_throw; -DUK_INTERNAL_DECL const char *duk_str_with_in_strict_mode; -DUK_INTERNAL_DECL const char *duk_str_func_stmt_not_allowed; -DUK_INTERNAL_DECL const char *duk_str_unterminated_stmt; -DUK_INTERNAL_DECL const char *duk_str_invalid_arg_name; -DUK_INTERNAL_DECL const char *duk_str_invalid_func_name; -DUK_INTERNAL_DECL const char *duk_str_invalid_getset_name; -DUK_INTERNAL_DECL const char *duk_str_func_name_required; -#endif /* !DUK_SINGLE_FILE */ +/* Mostly API and built-in method related */ +#define DUK_STR_INTERNAL_ERROR "internal error" +#define DUK_STR_UNSUPPORTED "unsupported" +#define DUK_STR_INVALID_COUNT "invalid count" +#define DUK_STR_INVALID_ARGS "invalid args" +#define DUK_STR_INVALID_STATE "invalid state" +#define DUK_STR_INVALID_INPUT "invalid input" +#define DUK_STR_INVALID_LENGTH "invalid length" +#define DUK_STR_NOT_CONSTRUCTABLE "not constructable" +#define DUK_STR_CONSTRUCT_ONLY "constructor requires 'new'" +#define DUK_STR_NOT_CALLABLE "not callable" +#define DUK_STR_NOT_EXTENSIBLE "not extensible" +#define DUK_STR_NOT_WRITABLE "not writable" +#define DUK_STR_NOT_CONFIGURABLE "not configurable" +#define DUK_STR_INVALID_CONTEXT "invalid context" +#define DUK_STR_INVALID_INDEX "invalid args" +#define DUK_STR_PUSH_BEYOND_ALLOC_STACK "cannot push beyond allocated stack" +#define DUK_STR_NOT_UNDEFINED "unexpected type" +#define DUK_STR_NOT_NULL "unexpected type" +#define DUK_STR_NOT_BOOLEAN "unexpected type" +#define DUK_STR_NOT_NUMBER "unexpected type" +#define DUK_STR_NOT_STRING "unexpected type" +#define DUK_STR_NOT_OBJECT "unexpected type" +#define DUK_STR_NOT_POINTER "unexpected type" +#define DUK_STR_NOT_BUFFER "not buffer" /* still in use with verbose messages */ +#define DUK_STR_UNEXPECTED_TYPE "unexpected type" +#define DUK_STR_NOT_THREAD "unexpected type" +#define DUK_STR_NOT_COMPFUNC "unexpected type" +#define DUK_STR_NOT_NATFUNC "unexpected type" +#define DUK_STR_NOT_C_FUNCTION "unexpected type" +#define DUK_STR_NOT_FUNCTION "unexpected type" +#define DUK_STR_NOT_REGEXP "unexpected type" +#define DUK_STR_TOPRIMITIVE_FAILED "coercion to primitive failed" +#define DUK_STR_NUMBER_OUTSIDE_RANGE "number outside range" +#define DUK_STR_NOT_OBJECT_COERCIBLE "not object coercible" +#define DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL "cannot number coerce Symbol" +#define DUK_STR_CANNOT_STRING_COERCE_SYMBOL "cannot string coerce Symbol" +#define DUK_STR_STRING_TOO_LONG "string too long" +#define DUK_STR_BUFFER_TOO_LONG "buffer too long" +#define DUK_STR_ALLOC_FAILED "alloc failed" +#define DUK_STR_WRONG_BUFFER_TYPE "wrong buffer type" +#define DUK_STR_ENCODE_FAILED "encode failed" +#define DUK_STR_DECODE_FAILED "decode failed" +#define DUK_STR_NO_SOURCECODE "no sourcecode" +#define DUK_STR_RESULT_TOO_LONG "result too long" -#define DUK_STR_INVALID_QUANTIFIER_NO_ATOM duk_str_invalid_quantifier_no_atom -#define DUK_STR_INVALID_QUANTIFIER_VALUES duk_str_invalid_quantifier_values -#define DUK_STR_QUANTIFIER_TOO_MANY_COPIES duk_str_quantifier_too_many_copies -#define DUK_STR_UNEXPECTED_CLOSING_PAREN duk_str_unexpected_closing_paren -#define DUK_STR_UNEXPECTED_END_OF_PATTERN duk_str_unexpected_end_of_pattern -#define DUK_STR_UNEXPECTED_REGEXP_TOKEN duk_str_unexpected_regexp_token -#define DUK_STR_INVALID_REGEXP_FLAGS duk_str_invalid_regexp_flags -#define DUK_STR_INVALID_BACKREFS duk_str_invalid_backrefs +/* JSON */ +#define DUK_STR_FMT_PTR "%p" +#define DUK_STR_FMT_INVALID_JSON "invalid json (at offset %ld)" +#define DUK_STR_JSONDEC_RECLIMIT "json decode recursion limit" +#define DUK_STR_JSONENC_RECLIMIT "json encode recursion limit" +#define DUK_STR_CYCLIC_INPUT "cyclic input" -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const char *duk_str_invalid_quantifier_no_atom; -DUK_INTERNAL_DECL const char *duk_str_invalid_quantifier_values; -DUK_INTERNAL_DECL const char *duk_str_quantifier_too_many_copies; -DUK_INTERNAL_DECL const char *duk_str_unexpected_closing_paren; -DUK_INTERNAL_DECL const char *duk_str_unexpected_end_of_pattern; -DUK_INTERNAL_DECL const char *duk_str_unexpected_regexp_token; -DUK_INTERNAL_DECL const char *duk_str_invalid_regexp_flags; -DUK_INTERNAL_DECL const char *duk_str_invalid_backrefs; -#endif /* !DUK_SINGLE_FILE */ +/* Object property access */ +#define DUK_STR_PROXY_REVOKED "proxy revoked" +#define DUK_STR_INVALID_BASE "invalid base value" +#define DUK_STR_STRICT_CALLER_READ "cannot read strict 'caller'" +#define DUK_STR_PROXY_REJECTED "proxy rejected" +#define DUK_STR_INVALID_ARRAY_LENGTH "invalid array length" +#define DUK_STR_SETTER_UNDEFINED "setter undefined" +#define DUK_STR_INVALID_DESCRIPTOR "invalid descriptor" + +/* Proxy */ +#define DUK_STR_INVALID_TRAP_RESULT "invalid trap result" + +/* Variables */ + +/* Lexer */ +#define DUK_STR_INVALID_ESCAPE "invalid escape" +#define DUK_STR_UNTERMINATED_STRING "unterminated string" +#define DUK_STR_UNTERMINATED_COMMENT "unterminated comment" +#define DUK_STR_UNTERMINATED_REGEXP "unterminated regexp" +#define DUK_STR_TOKEN_LIMIT "token limit" +#define DUK_STR_REGEXP_SUPPORT_DISABLED "regexp support disabled" +#define DUK_STR_INVALID_NUMBER_LITERAL "invalid number literal" +#define DUK_STR_INVALID_TOKEN "invalid token" -#define DUK_STR_VALSTACK_LIMIT duk_str_valstack_limit -#define DUK_STR_CALLSTACK_LIMIT duk_str_callstack_limit -#define DUK_STR_CATCHSTACK_LIMIT duk_str_catchstack_limit -#define DUK_STR_PROTOTYPE_CHAIN_LIMIT duk_str_prototype_chain_limit -#define DUK_STR_BOUND_CHAIN_LIMIT duk_str_bound_chain_limit -#define DUK_STR_C_CALLSTACK_LIMIT duk_str_c_callstack_limit -#define DUK_STR_COMPILER_RECURSION_LIMIT duk_str_compiler_recursion_limit -#define DUK_STR_BYTECODE_LIMIT duk_str_bytecode_limit -#define DUK_STR_REG_LIMIT duk_str_reg_limit -#define DUK_STR_TEMP_LIMIT duk_str_temp_limit -#define DUK_STR_CONST_LIMIT duk_str_const_limit -#define DUK_STR_FUNC_LIMIT duk_str_func_limit -#define DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT duk_str_regexp_compiler_recursion_limit -#define DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT duk_str_regexp_executor_recursion_limit -#define DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT duk_str_regexp_executor_step_limit +/* Compiler */ +#define DUK_STR_PARSE_ERROR "parse error" +#define DUK_STR_DUPLICATE_LABEL "duplicate label" +#define DUK_STR_INVALID_LABEL "invalid label" +#define DUK_STR_INVALID_ARRAY_LITERAL "invalid array literal" +#define DUK_STR_INVALID_OBJECT_LITERAL "invalid object literal" +#define DUK_STR_INVALID_VAR_DECLARATION "invalid variable declaration" +#define DUK_STR_CANNOT_DELETE_IDENTIFIER "cannot delete identifier" +#define DUK_STR_INVALID_EXPRESSION "invalid expression" +#define DUK_STR_INVALID_LVALUE "invalid lvalue" +#define DUK_STR_EXPECTED_IDENTIFIER "expected identifier" +#define DUK_STR_EMPTY_EXPR_NOT_ALLOWED "empty expression not allowed" +#define DUK_STR_INVALID_FOR "invalid for statement" +#define DUK_STR_INVALID_SWITCH "invalid switch statement" +#define DUK_STR_INVALID_BREAK_CONT_LABEL "invalid break/continue label" +#define DUK_STR_INVALID_RETURN "invalid return" +#define DUK_STR_INVALID_TRY "invalid try" +#define DUK_STR_INVALID_THROW "invalid throw" +#define DUK_STR_WITH_IN_STRICT_MODE "with in strict mode" +#define DUK_STR_FUNC_STMT_NOT_ALLOWED "function statement not allowed" +#define DUK_STR_UNTERMINATED_STMT "unterminated statement" +#define DUK_STR_INVALID_ARG_NAME "invalid argument name" +#define DUK_STR_INVALID_FUNC_NAME "invalid function name" +#define DUK_STR_INVALID_GETSET_NAME "invalid getter/setter name" +#define DUK_STR_FUNC_NAME_REQUIRED "function name required" -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const char *duk_str_valstack_limit; -DUK_INTERNAL_DECL const char *duk_str_callstack_limit; -DUK_INTERNAL_DECL const char *duk_str_catchstack_limit; -DUK_INTERNAL_DECL const char *duk_str_prototype_chain_limit; -DUK_INTERNAL_DECL const char *duk_str_bound_chain_limit; -DUK_INTERNAL_DECL const char *duk_str_c_callstack_limit; -DUK_INTERNAL_DECL const char *duk_str_compiler_recursion_limit; -DUK_INTERNAL_DECL const char *duk_str_bytecode_limit; -DUK_INTERNAL_DECL const char *duk_str_reg_limit; -DUK_INTERNAL_DECL const char *duk_str_temp_limit; -DUK_INTERNAL_DECL const char *duk_str_const_limit; -DUK_INTERNAL_DECL const char *duk_str_func_limit; -DUK_INTERNAL_DECL const char *duk_str_regexp_compiler_recursion_limit; -DUK_INTERNAL_DECL const char *duk_str_regexp_executor_recursion_limit; -DUK_INTERNAL_DECL const char *duk_str_regexp_executor_step_limit; -#endif /* !DUK_SINGLE_FILE */ +/* Regexp */ +#define DUK_STR_INVALID_QUANTIFIER "invalid regexp quantifier" +#define DUK_STR_INVALID_QUANTIFIER_NO_ATOM "quantifier without preceding atom" +#define DUK_STR_INVALID_QUANTIFIER_VALUES "quantifier values invalid (qmin > qmax)" +#define DUK_STR_QUANTIFIER_TOO_MANY_COPIES "quantifier requires too many atom copies" +#define DUK_STR_UNEXPECTED_CLOSING_PAREN "unexpected closing parenthesis" +#define DUK_STR_UNEXPECTED_END_OF_PATTERN "unexpected end of pattern" +#define DUK_STR_UNEXPECTED_REGEXP_TOKEN "unexpected token in regexp" +#define DUK_STR_INVALID_REGEXP_FLAGS "invalid regexp flags" +#define DUK_STR_INVALID_REGEXP_ESCAPE "invalid regexp escape" +#define DUK_STR_INVALID_BACKREFS "invalid backreference(s)" +#define DUK_STR_INVALID_REGEXP_CHARACTER "invalid regexp character" +#define DUK_STR_UNTERMINATED_CHARCLASS "unterminated character class" +#define DUK_STR_INVALID_RANGE "invalid range" -#if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const char *duk_str_anon; -#endif /* !DUK_SINGLE_FILE */ +/* Limits */ +#define DUK_STR_VALSTACK_LIMIT "valstack limit" +#define DUK_STR_CALLSTACK_LIMIT "callstack limit" +#define DUK_STR_CATCHSTACK_LIMIT "catchstack limit" +#define DUK_STR_PROTOTYPE_CHAIN_LIMIT "prototype chain limit" +#define DUK_STR_BOUND_CHAIN_LIMIT "function call bound chain limit" +#define DUK_STR_C_CALLSTACK_LIMIT "C call stack depth limit" +#define DUK_STR_COMPILER_RECURSION_LIMIT "compiler recursion limit" +#define DUK_STR_BYTECODE_LIMIT "bytecode limit" +#define DUK_STR_REG_LIMIT "register limit" +#define DUK_STR_TEMP_LIMIT "temp limit" +#define DUK_STR_CONST_LIMIT "const limit" +#define DUK_STR_FUNC_LIMIT "function limit" +#define DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT "regexp compiler recursion limit" +#define DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT "regexp executor recursion limit" +#define DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT "regexp step limit" #endif /* DUK_ERRMSG_H_INCLUDED */ -#line 1 "duk_js_bytecode.h" +/* #include duk_js_bytecode.h */ /* * Ecmascript bytecode */ -#ifndef DUK_JS_BYTECODE_H_INCLUDED +#if !defined(DUK_JS_BYTECODE_H_INCLUDED) #define DUK_JS_BYTECODE_H_INCLUDED /* - * Logical instruction layout - * ========================== + * Bytecode instruction layout + * =========================== + * + * Instructions are unsigned 32-bit integers divided as follows: * * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! ! * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0! - * +---------------------------------------------------+-----------+ - * ! C ! B ! A ! OP ! - * +---------------------------------------------------+-----------+ + * +-----------------------------------------------+---------------+ + * ! C ! B ! A ! OP ! + * +-----------------------------------------------+---------------+ * - * OP (6 bits): opcode (DUK_OP_*), access should be fastest - * A (8 bits): typically a target register number - * B (9 bits): typically first source register/constant number - * C (9 bits): typically second source register/constant number + * OP (8 bits): opcode (DUK_OP_*), access should be fastest + * consecutive opcodes allocated when opcode needs flags + * A (8 bits): typically a target register number + * B (8 bits): typically first source register/constant number + * C (8 bits): typically second source register/constant number * * Some instructions combine BC or ABC together for larger parameter values. - * Signed integers (e.g. jump offsets) are encoded as unsigned, with an opcode - * specific bias. B and C may denote a register or a constant, see - * DUK_BC_ISREG() and DUK_BC_ISCONST(). + * Signed integers (e.g. jump offsets) are encoded as unsigned, with an + * opcode specific bias. + * + * Some opcodes have flags which are handled by allocating consecutive + * opcodes to make space for 1-N flags. Flags can also be e.g. in the 'A' + * field when there's room for the specific opcode. + * + * For example, if three flags were needed, they could be allocated from + * the opcode field as follows: + * + * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! ! + * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0! + * +-----------------------------------------------+---------------+ + * ! C ! B ! A ! OP !Z!Y!X! + * +-----------------------------------------------+---------------+ + * + * Some opcodes accept a reg/const argument which is handled by allocating + * flags in the OP field, see DUK_BC_ISREG() and DUK_BC_ISCONST(). The + * following convention is shared by most opcodes, so that the compiler + * can handle reg/const flagging without opcode specific code paths: + * + * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! ! + * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0! + * +-----------------------------------------------+---------------+ + * ! C ! B ! A ! OP !Y!X! + * +-----------------------------------------------+---------------+ + * + * X 1=B is const, 0=B is reg + * Y 1=C is const, 0=C is reg + * + * In effect OP, OP + 1, OP + 2, and OP + 3 are allocated from the + * 8-bit opcode space for a single logical opcode. The base opcode + * number should be divisible by 4. If the opcode is called 'FOO' + * the following opcode constants would be defined: + * + * DUK_OP_FOO 100 // base opcode number + * DUK_OP_FOO_RR 100 // FOO, B=reg, C=reg + * DUK_OP_FOO_CR 101 // FOO, B=const, C=reg + * DUK_OP_FOO_RC 102 // FOO, B=reg, C=const + * DUK_OP_FOO_CC 103 // FOO, B=const, C=const + * + * If only B or C is a reg/const, the unused opcode combinations can be + * used for other opcodes (which take no reg/const argument). However, + * such opcode values are initially reserved, at least while opcode space + * is available. For example, if 'BAR' uses B for a register field and + * C is a reg/const: * - * Note: macro naming is a bit misleading, e.g. "ABC" in macro name but - * the field layout is logically "CBA". + * DUK_OP_BAR 116 // base opcode number + * DUK_OP_BAR_RR 116 // BAR, B=reg, C=reg + * DUK_OP_BAR_CR_UNUSED 117 // unused, could be repurposed + * DUK_OP_BAR_RC 118 // BAR, B=reg, C=const + * DUK_OP_BAR_CC_UNUSED 119 // unused, could be repurposed + * + * Macro naming is a bit misleading, e.g. "ABC" in macro name but the + * field layout is concretely "CBA" in the register. */ typedef duk_uint32_t duk_instr_t; -#define DUK_DEC_OP(x) ((x) & 0x3fUL) -#define DUK_DEC_A(x) (((x) >> 6) & 0xffUL) -#define DUK_DEC_B(x) (((x) >> 14) & 0x1ffUL) -#define DUK_DEC_C(x) (((x) >> 23) & 0x1ffUL) -#define DUK_DEC_BC(x) (((x) >> 14) & 0x3ffffUL) -#define DUK_DEC_ABC(x) (((x) >> 6) & 0x3ffffffUL) +#define DUK_BC_SHIFT_OP 0 +#define DUK_BC_SHIFT_A 8 +#define DUK_BC_SHIFT_B 16 +#define DUK_BC_SHIFT_C 24 +#define DUK_BC_SHIFT_BC DUK_BC_SHIFT_B +#define DUK_BC_SHIFT_ABC DUK_BC_SHIFT_A + +#define DUK_BC_UNSHIFTED_MASK_OP 0xffUL +#define DUK_BC_UNSHIFTED_MASK_A 0xffUL +#define DUK_BC_UNSHIFTED_MASK_B 0xffUL +#define DUK_BC_UNSHIFTED_MASK_C 0xffUL +#define DUK_BC_UNSHIFTED_MASK_BC 0xffffUL +#define DUK_BC_UNSHIFTED_MASK_ABC 0xffffffUL + +#define DUK_BC_SHIFTED_MASK_OP (DUK_BC_UNSHIFTED_MASK_OP << DUK_BC_SHIFT_OP) +#define DUK_BC_SHIFTED_MASK_A (DUK_BC_UNSHIFTED_MASK_A << DUK_BC_SHIFT_A) +#define DUK_BC_SHIFTED_MASK_B (DUK_BC_UNSHIFTED_MASK_B << DUK_BC_SHIFT_B) +#define DUK_BC_SHIFTED_MASK_C (DUK_BC_UNSHIFTED_MASK_C << DUK_BC_SHIFT_C) +#define DUK_BC_SHIFTED_MASK_BC (DUK_BC_UNSHIFTED_MASK_BC << DUK_BC_SHIFT_BC) +#define DUK_BC_SHIFTED_MASK_ABC (DUK_BC_UNSHIFTED_MASK_ABC << DUK_BC_SHIFT_ABC) + +#define DUK_DEC_OP(x) ((x) & 0xffUL) +#define DUK_DEC_A(x) (((x) >> 8) & 0xffUL) +#define DUK_DEC_B(x) (((x) >> 16) & 0xffUL) +#define DUK_DEC_C(x) (((x) >> 24) & 0xffUL) +#define DUK_DEC_BC(x) (((x) >> 16) & 0xffffUL) +#define DUK_DEC_ABC(x) (((x) >> 8) & 0xffffffUL) #define DUK_ENC_OP(op) ((duk_instr_t) (op)) #define DUK_ENC_OP_ABC(op,abc) ((duk_instr_t) ( \ - (((duk_instr_t) (abc)) << 6) | \ + (((duk_instr_t) (abc)) << 8) | \ ((duk_instr_t) (op)) \ )) #define DUK_ENC_OP_A_BC(op,a,bc) ((duk_instr_t) ( \ - (((duk_instr_t) (bc)) << 14) | \ - (((duk_instr_t) (a)) << 6) | \ + (((duk_instr_t) (bc)) << 16) | \ + (((duk_instr_t) (a)) << 8) | \ ((duk_instr_t) (op)) \ )) #define DUK_ENC_OP_A_B_C(op,a,b,c) ((duk_instr_t) ( \ - (((duk_instr_t) (c)) << 23) | \ - (((duk_instr_t) (b)) << 14) | \ - (((duk_instr_t) (a)) << 6) | \ + (((duk_instr_t) (c)) << 24) | \ + (((duk_instr_t) (b)) << 16) | \ + (((duk_instr_t) (a)) << 8) | \ ((duk_instr_t) (op)) \ )) -#define DUK_ENC_OP_A_B(op,a,b) DUK_ENC_OP_A_B_C(op,a,b,0) -#define DUK_ENC_OP_A(op,a) DUK_ENC_OP_A_B_C(op,a,0,0) +#define DUK_ENC_OP_A_B(op,a,b) DUK_ENC_OP_A_B_C((op),(a),(b),0) +#define DUK_ENC_OP_A(op,a) DUK_ENC_OP_A_B_C((op),(a),0,0) +#define DUK_ENC_OP_BC(op,bc) DUK_ENC_OP_A_BC((op),0,(bc)) + +/* Get opcode base value with B/C reg/const flags cleared. */ +#define DUK_BC_NOREGCONST_OP(op) ((op) & 0xfc) /* Constants should be signed so that signed arithmetic involving them * won't cause values to be coerced accidentally to unsigned. */ #define DUK_BC_OP_MIN 0 -#define DUK_BC_OP_MAX 0x3fL +#define DUK_BC_OP_MAX 0xffL #define DUK_BC_A_MIN 0 #define DUK_BC_A_MAX 0xffL #define DUK_BC_B_MIN 0 -#define DUK_BC_B_MAX 0x1ffL +#define DUK_BC_B_MAX 0xffL #define DUK_BC_C_MIN 0 -#define DUK_BC_C_MAX 0x1ffL +#define DUK_BC_C_MAX 0xffL #define DUK_BC_BC_MIN 0 -#define DUK_BC_BC_MAX 0x3ffffL +#define DUK_BC_BC_MAX 0xffffL #define DUK_BC_ABC_MIN 0 -#define DUK_BC_ABC_MAX 0x3ffffffL -#define DUK_BC_EXTRAOP_MIN DUK_BC_A_MIN -#define DUK_BC_EXTRAOP_MAX DUK_BC_A_MAX +#define DUK_BC_ABC_MAX 0xffffffL + +/* Masks for B/C reg/const indicator in opcode field. */ +#define DUK_BC_REGCONST_B (0x01UL) +#define DUK_BC_REGCONST_C (0x02UL) + +/* Misc. masks for opcode field. */ +#define DUK_BC_INCDECP_FLAG_DEC (0x04UL) +#define DUK_BC_INCDECP_FLAG_POST (0x08UL) +/* Opcodes. */ #define DUK_OP_LDREG 0 #define DUK_OP_STREG 1 #define DUK_OP_LDCONST 2 #define DUK_OP_LDINT 3 #define DUK_OP_LDINTX 4 -#define DUK_OP_MPUTOBJ 5 -#define DUK_OP_MPUTOBJI 6 -#define DUK_OP_MPUTARR 7 -#define DUK_OP_MPUTARRI 8 -#define DUK_OP_NEW 9 -#define DUK_OP_NEWI 10 -#define DUK_OP_REGEXP 11 -#define DUK_OP_CSREG 12 -#define DUK_OP_CSREGI 13 -#define DUK_OP_GETVAR 14 -#define DUK_OP_PUTVAR 15 -#define DUK_OP_DECLVAR 16 -#define DUK_OP_DELVAR 17 -#define DUK_OP_CSVAR 18 -#define DUK_OP_CSVARI 19 -#define DUK_OP_CLOSURE 20 -#define DUK_OP_GETPROP 21 -#define DUK_OP_PUTPROP 22 -#define DUK_OP_DELPROP 23 -#define DUK_OP_CSPROP 24 -#define DUK_OP_CSPROPI 25 -#define DUK_OP_ADD 26 -#define DUK_OP_SUB 27 -#define DUK_OP_MUL 28 -#define DUK_OP_DIV 29 -#define DUK_OP_MOD 30 -#define DUK_OP_BAND 31 -#define DUK_OP_BOR 32 -#define DUK_OP_BXOR 33 -#define DUK_OP_BASL 34 -#define DUK_OP_BLSR 35 -#define DUK_OP_BASR 36 -#define DUK_OP_EQ 37 -#define DUK_OP_NEQ 38 -#define DUK_OP_SEQ 39 -#define DUK_OP_SNEQ 40 -#define DUK_OP_GT 41 -#define DUK_OP_GE 42 -#define DUK_OP_LT 43 +#define DUK_OP_LDTHIS 5 +#define DUK_OP_LDUNDEF 6 +#define DUK_OP_LDNULL 7 +#define DUK_OP_LDTRUE 8 +#define DUK_OP_LDFALSE 9 +#define DUK_OP_BNOT 10 +#define DUK_OP_LNOT 11 +#define DUK_OP_UNM 12 +#define DUK_OP_UNP 13 +#define DUK_OP_TYPEOF 14 +#define DUK_OP_TYPEOFID 15 +#define DUK_OP_EQ 16 +#define DUK_OP_EQ_RR 16 +#define DUK_OP_EQ_CR 17 +#define DUK_OP_EQ_RC 18 +#define DUK_OP_EQ_CC 19 +#define DUK_OP_NEQ 20 +#define DUK_OP_NEQ_RR 20 +#define DUK_OP_NEQ_CR 21 +#define DUK_OP_NEQ_RC 22 +#define DUK_OP_NEQ_CC 23 +#define DUK_OP_SEQ 24 +#define DUK_OP_SEQ_RR 24 +#define DUK_OP_SEQ_CR 25 +#define DUK_OP_SEQ_RC 26 +#define DUK_OP_SEQ_CC 27 +#define DUK_OP_SNEQ 28 +#define DUK_OP_SNEQ_RR 28 +#define DUK_OP_SNEQ_CR 29 +#define DUK_OP_SNEQ_RC 30 +#define DUK_OP_SNEQ_CC 31 +#define DUK_OP_GT 32 +#define DUK_OP_GT_RR 32 +#define DUK_OP_GT_CR 33 +#define DUK_OP_GT_RC 34 +#define DUK_OP_GT_CC 35 +#define DUK_OP_GE 36 +#define DUK_OP_GE_RR 36 +#define DUK_OP_GE_CR 37 +#define DUK_OP_GE_RC 38 +#define DUK_OP_GE_CC 39 +#define DUK_OP_LT 40 +#define DUK_OP_LT_RR 40 +#define DUK_OP_LT_CR 41 +#define DUK_OP_LT_RC 42 +#define DUK_OP_LT_CC 43 #define DUK_OP_LE 44 -#define DUK_OP_IF 45 -#define DUK_OP_JUMP 46 -#define DUK_OP_RETURN 47 -#define DUK_OP_CALL 48 -#define DUK_OP_CALLI 49 -#define DUK_OP_TRYCATCH 50 -#define DUK_OP_EXTRA 51 -#define DUK_OP_PREINCR 52 /* pre/post opcode values have constraints, */ -#define DUK_OP_PREDECR 53 /* see duk_js_executor.c */ -#define DUK_OP_POSTINCR 54 -#define DUK_OP_POSTDECR 55 -#define DUK_OP_PREINCV 56 -#define DUK_OP_PREDECV 57 -#define DUK_OP_POSTINCV 58 -#define DUK_OP_POSTDECV 59 -#define DUK_OP_PREINCP 60 -#define DUK_OP_PREDECP 61 -#define DUK_OP_POSTINCP 62 -#define DUK_OP_POSTDECP 63 -#define DUK_OP_NONE 64 /* dummy value used as marker */ - -/* DUK_OP_EXTRA, sub-operation in A */ -#define DUK_EXTRAOP_NOP 0 -#define DUK_EXTRAOP_INVALID 1 -#define DUK_EXTRAOP_LDTHIS 2 -#define DUK_EXTRAOP_LDUNDEF 3 -#define DUK_EXTRAOP_LDNULL 4 -#define DUK_EXTRAOP_LDTRUE 5 -#define DUK_EXTRAOP_LDFALSE 6 -#define DUK_EXTRAOP_NEWOBJ 7 -#define DUK_EXTRAOP_NEWARR 8 -#define DUK_EXTRAOP_SETALEN 9 -#define DUK_EXTRAOP_TYPEOF 10 -#define DUK_EXTRAOP_TYPEOFID 11 -#define DUK_EXTRAOP_INITENUM 12 -#define DUK_EXTRAOP_NEXTENUM 13 -#define DUK_EXTRAOP_INITSET 14 -#define DUK_EXTRAOP_INITSETI 15 -#define DUK_EXTRAOP_INITGET 16 -#define DUK_EXTRAOP_INITGETI 17 -#define DUK_EXTRAOP_ENDTRY 18 -#define DUK_EXTRAOP_ENDCATCH 19 -#define DUK_EXTRAOP_ENDFIN 20 -#define DUK_EXTRAOP_THROW 21 -#define DUK_EXTRAOP_INVLHS 22 -#define DUK_EXTRAOP_UNM 23 -#define DUK_EXTRAOP_UNP 24 -#define DUK_EXTRAOP_DEBUGGER 25 -#define DUK_EXTRAOP_BREAK 26 -#define DUK_EXTRAOP_CONTINUE 27 -#define DUK_EXTRAOP_BNOT 28 -#define DUK_EXTRAOP_LNOT 29 -#define DUK_EXTRAOP_INSTOF 30 -#define DUK_EXTRAOP_IN 31 -#define DUK_EXTRAOP_LABEL 32 -#define DUK_EXTRAOP_ENDLABEL 33 - -/* DUK_OP_CALL flags in A */ -#define DUK_BC_CALL_FLAG_TAILCALL (1 << 0) -#define DUK_BC_CALL_FLAG_EVALCALL (1 << 1) - +#define DUK_OP_LE_RR 44 +#define DUK_OP_LE_CR 45 +#define DUK_OP_LE_RC 46 +#define DUK_OP_LE_CC 47 +#define DUK_OP_IFTRUE 48 +#define DUK_OP_IFTRUE_R 48 +#define DUK_OP_IFTRUE_C 49 +#define DUK_OP_IFFALSE 50 +#define DUK_OP_IFFALSE_R 50 +#define DUK_OP_IFFALSE_C 51 +#define DUK_OP_ADD 52 +#define DUK_OP_ADD_RR 52 +#define DUK_OP_ADD_CR 53 +#define DUK_OP_ADD_RC 54 +#define DUK_OP_ADD_CC 55 +#define DUK_OP_SUB 56 +#define DUK_OP_SUB_RR 56 +#define DUK_OP_SUB_CR 57 +#define DUK_OP_SUB_RC 58 +#define DUK_OP_SUB_CC 59 +#define DUK_OP_MUL 60 +#define DUK_OP_MUL_RR 60 +#define DUK_OP_MUL_CR 61 +#define DUK_OP_MUL_RC 62 +#define DUK_OP_MUL_CC 63 +#define DUK_OP_DIV 64 +#define DUK_OP_DIV_RR 64 +#define DUK_OP_DIV_CR 65 +#define DUK_OP_DIV_RC 66 +#define DUK_OP_DIV_CC 67 +#define DUK_OP_MOD 68 +#define DUK_OP_MOD_RR 68 +#define DUK_OP_MOD_CR 69 +#define DUK_OP_MOD_RC 70 +#define DUK_OP_MOD_CC 71 +#define DUK_OP_EXP 72 +#define DUK_OP_EXP_RR 72 +#define DUK_OP_EXP_CR 73 +#define DUK_OP_EXP_RC 74 +#define DUK_OP_EXP_CC 75 +#define DUK_OP_BAND 76 +#define DUK_OP_BAND_RR 76 +#define DUK_OP_BAND_CR 77 +#define DUK_OP_BAND_RC 78 +#define DUK_OP_BAND_CC 79 +#define DUK_OP_BOR 80 +#define DUK_OP_BOR_RR 80 +#define DUK_OP_BOR_CR 81 +#define DUK_OP_BOR_RC 82 +#define DUK_OP_BOR_CC 83 +#define DUK_OP_BXOR 84 +#define DUK_OP_BXOR_RR 84 +#define DUK_OP_BXOR_CR 85 +#define DUK_OP_BXOR_RC 86 +#define DUK_OP_BXOR_CC 87 +#define DUK_OP_BASL 88 +#define DUK_OP_BASL_RR 88 +#define DUK_OP_BASL_CR 89 +#define DUK_OP_BASL_RC 90 +#define DUK_OP_BASL_CC 91 +#define DUK_OP_BLSR 92 +#define DUK_OP_BLSR_RR 92 +#define DUK_OP_BLSR_CR 93 +#define DUK_OP_BLSR_RC 94 +#define DUK_OP_BLSR_CC 95 +#define DUK_OP_BASR 96 +#define DUK_OP_BASR_RR 96 +#define DUK_OP_BASR_CR 97 +#define DUK_OP_BASR_RC 98 +#define DUK_OP_BASR_CC 99 +#define DUK_OP_INSTOF 100 +#define DUK_OP_INSTOF_RR 100 +#define DUK_OP_INSTOF_CR 101 +#define DUK_OP_INSTOF_RC 102 +#define DUK_OP_INSTOF_CC 103 +#define DUK_OP_IN 104 +#define DUK_OP_IN_RR 104 +#define DUK_OP_IN_CR 105 +#define DUK_OP_IN_RC 106 +#define DUK_OP_IN_CC 107 +#define DUK_OP_GETPROP 108 +#define DUK_OP_GETPROP_RR 108 +#define DUK_OP_GETPROP_CR 109 +#define DUK_OP_GETPROP_RC 110 +#define DUK_OP_GETPROP_CC 111 +#define DUK_OP_PUTPROP 112 +#define DUK_OP_PUTPROP_RR 112 +#define DUK_OP_PUTPROP_CR 113 +#define DUK_OP_PUTPROP_RC 114 +#define DUK_OP_PUTPROP_CC 115 +#define DUK_OP_DELPROP 116 +#define DUK_OP_DELPROP_RR 116 +#define DUK_OP_DELPROP_CR_UNUSED 117 /* unused now */ +#define DUK_OP_DELPROP_RC 118 +#define DUK_OP_DELPROP_CC_UNUSED 119 /* unused now */ +#define DUK_OP_PREINCR 120 /* pre/post opcode values have constraints, */ +#define DUK_OP_PREDECR 121 /* see duk_js_executor.c and duk_js_compiler.c. */ +#define DUK_OP_POSTINCR 122 +#define DUK_OP_POSTDECR 123 +#define DUK_OP_PREINCV 124 +#define DUK_OP_PREDECV 125 +#define DUK_OP_POSTINCV 126 +#define DUK_OP_POSTDECV 127 +#define DUK_OP_PREINCP 128 /* pre/post inc/dec prop opcodes have constraints */ +#define DUK_OP_PREINCP_RR 128 +#define DUK_OP_PREINCP_CR 129 +#define DUK_OP_PREINCP_RC 130 +#define DUK_OP_PREINCP_CC 131 +#define DUK_OP_PREDECP 132 +#define DUK_OP_PREDECP_RR 132 +#define DUK_OP_PREDECP_CR 133 +#define DUK_OP_PREDECP_RC 134 +#define DUK_OP_PREDECP_CC 135 +#define DUK_OP_POSTINCP 136 +#define DUK_OP_POSTINCP_RR 136 +#define DUK_OP_POSTINCP_CR 137 +#define DUK_OP_POSTINCP_RC 138 +#define DUK_OP_POSTINCP_CC 139 +#define DUK_OP_POSTDECP 140 +#define DUK_OP_POSTDECP_RR 140 +#define DUK_OP_POSTDECP_CR 141 +#define DUK_OP_POSTDECP_RC 142 +#define DUK_OP_POSTDECP_CC 143 +#define DUK_OP_DECLVAR 144 +#define DUK_OP_DECLVAR_RR 144 +#define DUK_OP_DECLVAR_CR 145 +#define DUK_OP_DECLVAR_RC 146 +#define DUK_OP_DECLVAR_CC 147 +#define DUK_OP_REGEXP 148 +#define DUK_OP_REGEXP_RR 148 +#define DUK_OP_REGEXP_CR 149 +#define DUK_OP_REGEXP_RC 150 +#define DUK_OP_REGEXP_CC 151 +#define DUK_OP_CSVAR 152 +#define DUK_OP_CSVAR_RR 152 +#define DUK_OP_CSVAR_CR 153 +#define DUK_OP_CSVAR_RC 154 +#define DUK_OP_CSVAR_CC 155 +#define DUK_OP_CLOSURE 156 +#define DUK_OP_GETVAR 157 +#define DUK_OP_PUTVAR 158 +#define DUK_OP_DELVAR 159 +#define DUK_OP_JUMP 160 +#define DUK_OP_RETREG 161 +#define DUK_OP_RETUNDEF 162 +#define DUK_OP_RETCONST 163 +#define DUK_OP_RETCONSTN 164 /* return const without incref (e.g. number) */ +#define DUK_OP_LABEL 165 +#define DUK_OP_ENDLABEL 166 +#define DUK_OP_BREAK 167 +#define DUK_OP_CONTINUE 168 +#define DUK_OP_TRYCATCH 169 +#define DUK_OP_ENDTRY 170 +#define DUK_OP_ENDCATCH 171 +#define DUK_OP_ENDFIN 172 +#define DUK_OP_THROW 173 +#define DUK_OP_CSREG 174 +#define DUK_OP_EVALCALL 175 +#define DUK_OP_CALL 176 /* must be even */ +#define DUK_OP_TAILCALL 177 /* must be odd */ +#define DUK_OP_NEW 178 +#define DUK_OP_NEWOBJ 179 +#define DUK_OP_NEWARR 180 +#define DUK_OP_MPUTOBJ 181 +#define DUK_OP_MPUTOBJI 182 +#define DUK_OP_INITSET 183 +#define DUK_OP_INITGET 184 +#define DUK_OP_MPUTARR 185 +#define DUK_OP_MPUTARRI 186 +#define DUK_OP_SETALEN 187 +#define DUK_OP_INITENUM 188 +#define DUK_OP_NEXTENUM 189 +#define DUK_OP_INVLHS 190 +#define DUK_OP_DEBUGGER 191 +#define DUK_OP_NOP 192 +#define DUK_OP_INVALID 193 +#define DUK_OP_UNUSED194 194 +#define DUK_OP_UNUSED195 195 +#define DUK_OP_UNUSED196 196 +#define DUK_OP_UNUSED197 197 +#define DUK_OP_UNUSED198 198 +#define DUK_OP_UNUSED199 199 +#define DUK_OP_UNUSED200 200 +#define DUK_OP_UNUSED201 201 +#define DUK_OP_UNUSED202 202 +#define DUK_OP_UNUSED203 203 +#define DUK_OP_UNUSED204 204 +#define DUK_OP_UNUSED205 205 +#define DUK_OP_UNUSED206 206 +#define DUK_OP_UNUSED207 207 +#define DUK_OP_UNUSED208 208 +#define DUK_OP_UNUSED209 209 +#define DUK_OP_UNUSED210 210 +#define DUK_OP_UNUSED211 211 +#define DUK_OP_UNUSED212 212 +#define DUK_OP_UNUSED213 213 +#define DUK_OP_UNUSED214 214 +#define DUK_OP_UNUSED215 215 +#define DUK_OP_UNUSED216 216 +#define DUK_OP_UNUSED217 217 +#define DUK_OP_UNUSED218 218 +#define DUK_OP_UNUSED219 219 +#define DUK_OP_UNUSED220 220 +#define DUK_OP_UNUSED221 221 +#define DUK_OP_UNUSED222 222 +#define DUK_OP_UNUSED223 223 +#define DUK_OP_UNUSED224 224 +#define DUK_OP_UNUSED225 225 +#define DUK_OP_UNUSED226 226 +#define DUK_OP_UNUSED227 227 +#define DUK_OP_UNUSED228 228 +#define DUK_OP_UNUSED229 229 +#define DUK_OP_UNUSED230 230 +#define DUK_OP_UNUSED231 231 +#define DUK_OP_UNUSED232 232 +#define DUK_OP_UNUSED233 233 +#define DUK_OP_UNUSED234 234 +#define DUK_OP_UNUSED235 235 +#define DUK_OP_UNUSED236 236 +#define DUK_OP_UNUSED237 237 +#define DUK_OP_UNUSED238 238 +#define DUK_OP_UNUSED239 239 +#define DUK_OP_UNUSED240 240 +#define DUK_OP_UNUSED241 241 +#define DUK_OP_UNUSED242 242 +#define DUK_OP_UNUSED243 243 +#define DUK_OP_UNUSED244 244 +#define DUK_OP_UNUSED245 245 +#define DUK_OP_UNUSED246 246 +#define DUK_OP_UNUSED247 247 +#define DUK_OP_UNUSED248 248 +#define DUK_OP_UNUSED249 249 +#define DUK_OP_UNUSED250 250 +#define DUK_OP_UNUSED251 251 +#define DUK_OP_UNUSED252 252 +#define DUK_OP_UNUSED253 253 +#define DUK_OP_UNUSED254 254 +#define DUK_OP_UNUSED255 255 +#define DUK_OP_NONE 256 /* dummy value used as marker (doesn't fit in 8-bit field) */ + +/* XXX: Allocate flags from opcode field? Would take 16 opcode slots + * but avoids shuffling in more cases. Maybe not worth it. + */ /* DUK_OP_TRYCATCH flags in A */ #define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1 << 0) #define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1 << 1) #define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1 << 2) #define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1 << 3) -/* DUK_OP_RETURN flags in A */ -#define DUK_BC_RETURN_FLAG_HAVE_RETVAL (1 << 0) - /* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags (DUK_PROPDESC_FLAG_XXX) */ #define DUK_BC_DECLVAR_FLAG_UNDEF_VALUE (1 << 4) /* use 'undefined' for value automatically */ #define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 5) /* function declaration */ -/* misc constants and helper macros */ -#define DUK_BC_REGLIMIT 256 /* if B/C is >= this value, refers to a const */ -#define DUK_BC_ISREG(x) ((x) < DUK_BC_REGLIMIT) -#define DUK_BC_ISCONST(x) ((x) >= DUK_BC_REGLIMIT) -#define DUK_BC_LDINT_BIAS (1L << 17) -#define DUK_BC_LDINTX_SHIFT 18 -#define DUK_BC_JUMP_BIAS (1L << 25) +/* Misc constants and helper macros. */ +#define DUK_BC_LDINT_BIAS (1L << 15) +#define DUK_BC_LDINTX_SHIFT 16 +#define DUK_BC_JUMP_BIAS (1L << 23) #endif /* DUK_JS_BYTECODE_H_INCLUDED */ -#line 1 "duk_lexer.h" +/* #include duk_lexer.h */ /* * Lexer defines. */ -#ifndef DUK_LEXER_H_INCLUDED +#if !defined(DUK_LEXER_H_INCLUDED) #define DUK_LEXER_H_INCLUDED typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct); @@ -2754,8 +3037,7 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo #define DUK_LEXER_SETPOINT(ctx,pt) duk_lexer_setpoint((ctx), (pt)) -#define DUK_LEXER_GETPOINT(ctx,pt) do { (pt)->offset = (ctx)->window[0].offset; \ - (pt)->line = (ctx)->window[0].line; } while (0) +#define DUK_LEXER_GETPOINT(ctx,pt) duk_lexer_getpoint((ctx), (pt)) /* currently 6 characters of lookup are actually needed (duk_lexer.c) */ #define DUK_LEXER_WINDOW_SIZE 6 @@ -2859,41 +3141,43 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo #define DUK_TOK_MUL 68 #define DUK_TOK_DIV 69 #define DUK_TOK_MOD 70 -#define DUK_TOK_INCREMENT 71 -#define DUK_TOK_DECREMENT 72 -#define DUK_TOK_ALSHIFT 73 /* named "arithmetic" because result is signed */ -#define DUK_TOK_ARSHIFT 74 -#define DUK_TOK_RSHIFT 75 -#define DUK_TOK_BAND 76 -#define DUK_TOK_BOR 77 -#define DUK_TOK_BXOR 78 -#define DUK_TOK_LNOT 79 -#define DUK_TOK_BNOT 80 -#define DUK_TOK_LAND 81 -#define DUK_TOK_LOR 82 -#define DUK_TOK_QUESTION 83 -#define DUK_TOK_COLON 84 -#define DUK_TOK_EQUALSIGN 85 -#define DUK_TOK_ADD_EQ 86 -#define DUK_TOK_SUB_EQ 87 -#define DUK_TOK_MUL_EQ 88 -#define DUK_TOK_DIV_EQ 89 -#define DUK_TOK_MOD_EQ 90 -#define DUK_TOK_ALSHIFT_EQ 91 -#define DUK_TOK_ARSHIFT_EQ 92 -#define DUK_TOK_RSHIFT_EQ 93 -#define DUK_TOK_BAND_EQ 94 -#define DUK_TOK_BOR_EQ 95 -#define DUK_TOK_BXOR_EQ 96 +#define DUK_TOK_EXP 71 +#define DUK_TOK_INCREMENT 72 +#define DUK_TOK_DECREMENT 73 +#define DUK_TOK_ALSHIFT 74 /* named "arithmetic" because result is signed */ +#define DUK_TOK_ARSHIFT 75 +#define DUK_TOK_RSHIFT 76 +#define DUK_TOK_BAND 77 +#define DUK_TOK_BOR 78 +#define DUK_TOK_BXOR 79 +#define DUK_TOK_LNOT 80 +#define DUK_TOK_BNOT 81 +#define DUK_TOK_LAND 82 +#define DUK_TOK_LOR 83 +#define DUK_TOK_QUESTION 84 +#define DUK_TOK_COLON 85 +#define DUK_TOK_EQUALSIGN 86 +#define DUK_TOK_ADD_EQ 87 +#define DUK_TOK_SUB_EQ 88 +#define DUK_TOK_MUL_EQ 89 +#define DUK_TOK_DIV_EQ 90 +#define DUK_TOK_MOD_EQ 91 +#define DUK_TOK_EXP_EQ 92 +#define DUK_TOK_ALSHIFT_EQ 93 +#define DUK_TOK_ARSHIFT_EQ 94 +#define DUK_TOK_RSHIFT_EQ 95 +#define DUK_TOK_BAND_EQ 96 +#define DUK_TOK_BOR_EQ 97 +#define DUK_TOK_BXOR_EQ 98 /* literals (E5 Section 7.8), except null, true, false, which are treated * like reserved words (above). */ -#define DUK_TOK_NUMBER 97 -#define DUK_TOK_STRING 98 -#define DUK_TOK_REGEXP 99 +#define DUK_TOK_NUMBER 99 +#define DUK_TOK_STRING 100 +#define DUK_TOK_REGEXP 101 -#define DUK_TOK_MAXVAL 99 /* inclusive */ +#define DUK_TOK_MAXVAL 101 /* inclusive */ /* Convert heap string index to a token (reserved words) */ #define DUK_STRIDX_TO_TOK(x) ((x) - DUK_STRIDX_START_RESERVED + DUK_TOK_START_RESERVED) @@ -3052,12 +3336,12 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo #define DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD 8 #define DUK_RETOK_ATOM_PERIOD 9 #define DUK_RETOK_ATOM_CHAR 10 -#define DUK_RETOK_ATOM_DIGIT 11 -#define DUK_RETOK_ATOM_NOT_DIGIT 12 -#define DUK_RETOK_ATOM_WHITE 13 -#define DUK_RETOK_ATOM_NOT_WHITE 14 -#define DUK_RETOK_ATOM_WORD_CHAR 15 -#define DUK_RETOK_ATOM_NOT_WORD_CHAR 16 +#define DUK_RETOK_ATOM_DIGIT 11 /* assumptions in regexp compiler */ +#define DUK_RETOK_ATOM_NOT_DIGIT 12 /* -""- */ +#define DUK_RETOK_ATOM_WHITE 13 /* -""- */ +#define DUK_RETOK_ATOM_NOT_WHITE 14 /* -""- */ +#define DUK_RETOK_ATOM_WORD_CHAR 15 /* -""- */ +#define DUK_RETOK_ATOM_NOT_WORD_CHAR 16 /* -""- */ #define DUK_RETOK_ATOM_BACKREFERENCE 17 #define DUK_RETOK_ATOM_START_CAPTURE_GROUP 18 #define DUK_RETOK_ATOM_START_NONCAPTURE_GROUP 19 @@ -3141,6 +3425,7 @@ struct duk_lexer_ctx { DUK_INTERNAL_DECL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx); +DUK_INTERNAL_DECL void duk_lexer_getpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt); DUK_INTERNAL_DECL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt); DUK_INTERNAL_DECL @@ -3148,18 +3433,18 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx, duk_token *out_token, duk_bool_t strict_mode, duk_bool_t regexp_mode); -#ifdef DUK_USE_REGEXP_SUPPORT +#if defined(DUK_USE_REGEXP_SUPPORT) DUK_INTERNAL_DECL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token); DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata); #endif /* DUK_USE_REGEXP_SUPPORT */ #endif /* DUK_LEXER_H_INCLUDED */ -#line 1 "duk_js_compiler.h" +/* #include duk_js_compiler.h */ /* * Ecmascript compiler. */ -#ifndef DUK_JS_COMPILER_H_INCLUDED +#if !defined(DUK_JS_COMPILER_H_INCLUDED) #define DUK_JS_COMPILER_H_INCLUDED /* ecmascript compiler limits */ @@ -3182,16 +3467,18 @@ DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_ #define DUK_IVAL_NONE 0 /* no value */ #define DUK_IVAL_PLAIN 1 /* register, constant, or value */ #define DUK_IVAL_ARITH 2 /* binary arithmetic; DUK_OP_ADD, DUK_OP_EQ, other binary ops */ -#define DUK_IVAL_ARITH_EXTRAOP 3 /* binary arithmetic using extraops; DUK_EXTRAOP_INSTOF etc */ -#define DUK_IVAL_PROP 4 /* property access */ -#define DUK_IVAL_VAR 5 /* variable access */ +#define DUK_IVAL_PROP 3 /* property access */ +#define DUK_IVAL_VAR 4 /* variable access */ #define DUK_ISPEC_NONE 0 /* no value */ #define DUK_ISPEC_VALUE 1 /* value resides in 'valstack_idx' */ #define DUK_ISPEC_REGCONST 2 /* value resides in a register or constant */ -/* bit mask which indicates that a regconst is a constant instead of a register */ -#define DUK_JS_CONST_MARKER 0x80000000UL +/* Bit mask which indicates that a regconst is a constant instead of a register. + * Chosen so that when a regconst is cast to duk_int32_t, all consts are + * negative values. + */ +#define DUK_REGCONST_CONST_MARKER 0x80000000UL /* type to represent a reg/const reference during compilation */ typedef duk_uint32_t duk_regconst_t; @@ -3215,7 +3502,7 @@ typedef struct { /* XXX: can be optimized for smaller footprint esp. on 32-bit environments */ duk_small_uint_t t; /* DUK_IVAL_XXX */ - duk_small_uint_t op; /* bytecode opcode (or extraop) for binary ops */ + duk_small_uint_t op; /* bytecode opcode for binary ops */ duk_ispec x1; duk_ispec x2; } duk_ivalue; @@ -3261,7 +3548,7 @@ typedef struct { */ } duk_labelinfo; -/* Compiling state of one function, eventually converted to duk_hcompiledfunction */ +/* Compiling state of one function, eventually converted to duk_hcompfunc */ struct duk_compiler_func { /* These pointers are at the start of the struct so that they pack * nicely. Mixing pointers and integer values is bad on some @@ -3285,7 +3572,7 @@ struct duk_compiler_func { duk_hobject *h_argnames; /* array of formal argument names (-> _Formals) */ duk_hobject *h_varmap; /* variable map for pass 2 (identifier -> register number or null (unmapped)) */ - /* value stack indices for tracking objects */ + /* Value stack indices for tracking objects. */ /* code_idx: not needed */ duk_idx_t consts_idx; duk_idx_t funcs_idx; @@ -3295,24 +3582,24 @@ struct duk_compiler_func { duk_idx_t argnames_idx; duk_idx_t varmap_idx; - /* temp reg handling */ + /* Temp reg handling. */ duk_reg_t temp_first; /* first register that is a temporary (below: variables) */ duk_reg_t temp_next; /* next temporary register to allocate */ duk_reg_t temp_max; /* highest value of temp_reg (temp_max - 1 is highest used reg) */ - /* shuffle registers if large number of regs/consts */ + /* Shuffle registers if large number of regs/consts. */ duk_reg_t shuffle1; duk_reg_t shuffle2; duk_reg_t shuffle3; - /* stats for current expression being parsed */ + /* Stats for current expression being parsed. */ duk_int_t nud_count; duk_int_t led_count; duk_int_t paren_level; /* parenthesis count, 0 = top level */ duk_bool_t expr_lhs; /* expression is left-hand-side compatible */ duk_bool_t allow_in; /* current paren level allows 'in' token */ - /* misc */ + /* Misc. */ duk_int_t stmt_next; /* statement id allocation (running counter) */ duk_int_t label_next; /* label id allocation (running counter) */ duk_int_t catch_depth; /* catch stack depth */ @@ -3321,26 +3608,28 @@ struct duk_compiler_func { duk_int_t num_formals; /* number of formal arguments */ duk_reg_t reg_stmt_value; /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - duk_int_t min_line; /* XXX: typing (duk_hcompiledfunction has duk_uint32_t) */ + duk_int_t min_line; /* XXX: typing (duk_hcompfunc has duk_uint32_t) */ duk_int_t max_line; #endif - /* status booleans */ - duk_bool_t is_function; /* is an actual function (not global/eval code) */ - duk_bool_t is_eval; /* is eval code */ - duk_bool_t is_global; /* is global code */ - duk_bool_t is_setget; /* is a setter/getter */ - duk_bool_t is_decl; /* is a function declaration (as opposed to function expression) */ - duk_bool_t is_strict; /* function is strict */ - duk_bool_t is_notail; /* function must not be tail called */ - duk_bool_t in_directive_prologue; /* parsing in "directive prologue", recognize directives */ - duk_bool_t in_scanning; /* parsing in "scanning" phase (first pass) */ - duk_bool_t may_direct_eval; /* function may call direct eval */ - duk_bool_t id_access_arguments; /* function refers to 'arguments' identifier */ - duk_bool_t id_access_slow; /* function makes one or more slow path accesses */ - duk_bool_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */ - duk_bool_t needs_shuffle; /* function needs shuffle registers */ - duk_bool_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */ + /* Status booleans. */ + duk_uint8_t is_function; /* is an actual function (not global/eval code) */ + duk_uint8_t is_eval; /* is eval code */ + duk_uint8_t is_global; /* is global code */ + duk_uint8_t is_namebinding; /* needs a name binding */ + duk_uint8_t is_constructable; /* result is constructable */ + duk_uint8_t is_setget; /* is a setter/getter */ + duk_uint8_t is_strict; /* function is strict */ + duk_uint8_t is_notail; /* function must not be tail called */ + duk_uint8_t in_directive_prologue; /* parsing in "directive prologue", recognize directives */ + duk_uint8_t in_scanning; /* parsing in "scanning" phase (first pass) */ + duk_uint8_t may_direct_eval; /* function may call direct eval */ + duk_uint8_t id_access_arguments; /* function refers to 'arguments' identifier */ + duk_uint8_t id_access_slow; /* function makes one or more slow path accesses that won't match own static variables */ + duk_uint8_t id_access_slow_own; /* function makes one or more slow path accesses that may match own static variables */ + duk_uint8_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */ + duk_uint8_t needs_shuffle; /* function needs shuffle registers */ + duk_uint8_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */ }; struct duk_compiler_ctx { @@ -3382,12 +3671,12 @@ struct duk_compiler_ctx { DUK_INTERNAL_DECL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags); #endif /* DUK_JS_COMPILER_H_INCLUDED */ -#line 1 "duk_regexp.h" +/* #include duk_regexp.h */ /* * Regular expression structs, constants, and bytecode defines. */ -#ifndef DUK_REGEXP_H_INCLUDED +#if !defined(DUK_REGEXP_H_INCLUDED) #define DUK_REGEXP_H_INCLUDED /* maximum bytecode copies for {n,m} quantifiers */ @@ -3459,19 +3748,21 @@ struct duk_re_compiler_ctx { * Prototypes */ +#if defined(DUK_USE_REGEXP_SUPPORT) DUK_INTERNAL_DECL void duk_regexp_compile(duk_hthread *thr); DUK_INTERNAL_DECL void duk_regexp_create_instance(duk_hthread *thr); DUK_INTERNAL_DECL void duk_regexp_match(duk_hthread *thr); DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hacky helper for String.prototype.split() */ +#endif #endif /* DUK_REGEXP_H_INCLUDED */ -#line 1 "duk_heaphdr.h" +/* #include duk_heaphdr.h */ /* * Heap header definition and assorted macros, including ref counting. * Access all fields through the accessor macros. */ -#ifndef DUK_HEAPHDR_H_INCLUDED +#if !defined(DUK_HEAPHDR_H_INCLUDED) #define DUK_HEAPHDR_H_INCLUDED /* @@ -3548,6 +3839,8 @@ struct duk_heaphdr_string { #else duk_size_t h_refcount; #endif +#else + duk_uint16_t h_strextra16; #endif }; @@ -3569,11 +3862,11 @@ struct duk_heaphdr_string { #define DUK_HEAPHDR_FLAG_FINALIZED DUK_HEAPHDR_HEAP_FLAG(3) /* mark-and-sweep: finalized (on previous pass) */ #define DUK_HEAPHDR_FLAG_READONLY DUK_HEAPHDR_HEAP_FLAG(4) /* read-only object, in code section */ -#define DUK_HTYPE_MIN 1 -#define DUK_HTYPE_STRING 1 -#define DUK_HTYPE_OBJECT 2 -#define DUK_HTYPE_BUFFER 3 -#define DUK_HTYPE_MAX 3 +#define DUK_HTYPE_MIN 0 +#define DUK_HTYPE_STRING 0 +#define DUK_HTYPE_OBJECT 1 +#define DUK_HTYPE_BUFFER 2 +#define DUK_HTYPE_MAX 2 #if defined(DUK_USE_HEAPPTR16) #define DUK_HEAPHDR_GET_NEXT(heap,h) \ @@ -3620,7 +3913,7 @@ struct duk_heaphdr_string { #define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount) /* result: updated refcount */ #endif #else -/* refcount macros not defined without refcounting, caller must #ifdef now */ +/* refcount macros not defined without refcounting, caller must #if defined() now */ #endif /* DUK_USE_REFERENCE_COUNTING */ /* @@ -3629,19 +3922,22 @@ struct duk_heaphdr_string { */ #define DUK_HEAPHDR_GET_FLAGS_RAW(h) ((h)->h_flags) - +#define DUK_HEAPHDR_SET_FLAGS_RAW(h,val) do { \ + (h)->h_flags = (val); } \ + } #define DUK_HEAPHDR_GET_FLAGS(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK) #define DUK_HEAPHDR_SET_FLAGS(h,val) do { \ (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) | (val); \ } while (0) - #define DUK_HEAPHDR_GET_TYPE(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_TYPE_MASK) #define DUK_HEAPHDR_SET_TYPE(h,val) do { \ (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_TYPE_MASK)) | (val); \ } while (0) +/* Comparison for type >= DUK_HTYPE_MIN skipped; because DUK_HTYPE_MIN is zero + * and the comparison is unsigned, it's always true and generates warnings. + */ #define DUK_HEAPHDR_HTYPE_VALID(h) ( \ - DUK_HEAPHDR_GET_TYPE((h)) >= DUK_HTYPE_MIN && \ DUK_HEAPHDR_GET_TYPE((h)) <= DUK_HTYPE_MAX \ ) @@ -3687,7 +3983,7 @@ struct duk_heaphdr_string { #define DUK_HEAPHDR_SET_FLAG_RANGE(h,m,n,v) do { \ (h)->h_flags = \ - ((h)->h_flags & (~(((1 << (n)) - 1) << (m)))) \ + ((h)->h_flags & (~(((1UL << (n)) - 1UL) << (m)))) \ | ((v) << (m)); \ } while (0) @@ -3705,6 +4001,17 @@ struct duk_heaphdr_string { #define DUK_HEAPHDR_STRING_INIT_NULLS(h) /* currently nop */ +/* + * Type tests + */ + +#define DUK_HEAPHDR_IS_OBJECT(h) \ + (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_OBJECT) +#define DUK_HEAPHDR_IS_STRING(h) \ + (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_STRING) +#define DUK_HEAPHDR_IS_BUFFER(h) \ + (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_BUFFER) + /* * Assert helpers */ @@ -3733,7 +4040,7 @@ struct duk_heaphdr_string { * it is not required for INCREF, but it is included just in case. * * Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not - * defined without DUK_USE_REFERENCE_COUNTING, so caller must #ifdef + * defined without DUK_USE_REFERENCE_COUNTING, so caller must #if defined() * around them. */ @@ -3781,6 +4088,19 @@ struct duk_heaphdr_string { } \ } \ } while (0) +#define DUK_TVAL_DECREF_NORZ_FAST(thr,tv) do { \ + duk_tval *duk__tv = (tv); \ + DUK_ASSERT(duk__tv != NULL); \ + if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ + duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ + DUK_ASSERT(duk__h != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ + if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ + duk_heaphdr_refzero_norz((thr), duk__h); \ + } \ + } \ + } while (0) #define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \ duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ DUK_ASSERT(duk__h != NULL); \ @@ -3789,79 +4109,181 @@ struct duk_heaphdr_string { DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ } \ } while (0) -#define DUK_HEAPHDR_DECREF_FAST(thr,h) do { \ +#define DUK_HEAPHDR_DECREF_FAST_RAW(thr,h,rzcall,rzcast) do { \ duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ DUK_ASSERT(duk__h != NULL); \ DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ - duk_heaphdr_refzero((thr), duk__h); \ + (rzcall)((thr), (rzcast) duk__h); \ } \ } \ } while (0) +#define DUK_HEAPHDR_DECREF_FAST(thr,h) \ + DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *) +#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) \ + DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *) /* Slow variants, call to a helper to reduce code size. * Can be used explicitly when size is always more important than speed. */ -#define DUK_TVAL_INCREF_SLOW(thr,tv) do { \ - duk_tval_incref((tv)); \ - } while (0) -#define DUK_TVAL_DECREF_SLOW(thr,tv) do { \ - duk_tval_decref((thr), (tv)); \ - } while (0) -#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { \ - duk_heaphdr_incref((duk_heaphdr *) (h)); \ - } while (0) -#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { \ - duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); \ - } while (0) +#define DUK_TVAL_INCREF_SLOW(thr,tv) do { duk_tval_incref((tv)); } while (0) +#define DUK_TVAL_DECREF_SLOW(thr,tv) do { duk_tval_decref((thr), (tv)); } while (0) +#define DUK_TVAL_DECREF_NORZ_SLOW(thr,tv) do { duk_tval_decref_norz((thr), (tv)); } while (0) +#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) +#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HSTRING_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) +#define DUK_HSTRING_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HBUFFER_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) +#define DUK_HBUFFER_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HOBJECT_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) +#define DUK_HOBJECT_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) /* Default variants. Selection depends on speed/size preference. * Concretely: with gcc 4.8.1 -Os x64 the difference in final binary * is about +1kB for _FAST variants. */ #if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) +/* XXX: It would be nice to specialize for specific duk_hobject subtypes + * but current refzero queue handling prevents that. + */ #define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv)) #define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv)) +#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_FAST((thr),(tv)) #define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h)) -#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST((thr),(h)) +#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *) +#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *) +#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) +#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) /* no 'norz' variant */ +#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) +#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) +#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) +#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) /* no 'norz' variant */ +#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) +#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) +#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HNATFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) +#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) +#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) +#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) +#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) +#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) #else #define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv)) #define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv)) +#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_SLOW((thr),(tv)) #define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h)) #define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h)) -#endif - -/* Casting convenience. */ +#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_NORZ_SLOW((thr),(h)) #define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h)) +#define DUK_HSTRING_DECREF(thr,h) DUK_HSTRING_DECREF_SLOW((thr),(h)) +#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HSTRING_DECREF_NORZ_SLOW((thr),(h)) #define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h)) +#define DUK_HOBJECT_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(h)) +#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(h)) #define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h)) -#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HNATIVEFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HNATIVEFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HBUFFEROBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HBUFFEROBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HBUFFER_DECREF(thr,h) DUK_HBUFFER_DECREF_SLOW((thr),(h)) +#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HBUFFER_DECREF_NORZ_SLOW((thr),(h)) +#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HNATFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HBUFOB_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) #define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HTHREAD_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) +#endif /* Convenience for some situations; the above macros don't allow NULLs - * for performance reasons. + * for performance reasons. Macros cover only actually needed cases. */ -#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \ +#define DUK_HEAPHDR_INCREF_ALLOWNULL(thr,h) do { \ if ((h) != NULL) { \ DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \ } \ } while (0) -#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \ +#define DUK_HEAPHDR_DECREF_ALLOWNULL(thr,h) do { \ if ((h) != NULL) { \ DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \ } \ } while (0) +#define DUK_HEAPHDR_DECREF_NORZ_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HEAPHDR_DECREF_NORZ((thr), (duk_heaphdr *) (h)); \ + } \ + } while (0) +#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HOBJECT_INCREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HOBJECT_DECREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HOBJECT_DECREF_NORZ((thr), (h)); \ + } \ + } while (0) +#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HBUFFER_INCREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HBUFFER_DECREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HBUFFER_DECREF_NORZ((thr), (h)); \ + } \ + } while (0) +#define DUK_HTHREAD_INCREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HTHREAD_INCREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HTHREAD_DECREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HTHREAD_DECREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HTHREAD_DECREF_NORZ((thr), (h)); \ + } \ + } while (0) + +/* Free pending refzero entries; quick check to avoid call because often + * the queue is empty. + */ +#define DUK_REFZERO_CHECK_FAST(thr) do { \ + if ((thr)->heap->refzero_list != NULL) { \ + duk_refzero_free_pending((thr)); \ + } \ + } while (0) +#define DUK_REFZERO_CHECK_SLOW(thr) do { \ + duk_refzero_free_pending((thr)); \ + } while (0) /* * Macros to set a duk_tval and update refcount of the target (decref the @@ -3876,6 +4298,13 @@ struct duk_heaphdr_string { DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ } while (0) +#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_UNDEFINED(tv__dst); \ + DUK_TVAL_DECREF_NORZ((thr), &tv__tmp); \ + } while (0) + #define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \ duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ @@ -3906,7 +4335,7 @@ struct duk_heaphdr_string { #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \ + DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ } while (0) #define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ @@ -3922,22 +4351,22 @@ struct duk_heaphdr_string { DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ } while (0) #if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ +#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \ + DUK_TVAL_SET_I48(tv__dst, (newval)); \ DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ } while (0) -#define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ +#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \ + DUK_TVAL_SET_I32(tv__dst, (newval)); \ DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ } while (0) -#define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ +#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \ + DUK_TVAL_SET_U32(tv__dst, (newval)); \ DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ } while (0) #else @@ -4019,6 +4448,7 @@ struct duk_heaphdr_string { /* XXX: no optimized variants yet */ #define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 +#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0 #define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 #define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 #define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 @@ -4027,14 +4457,15 @@ struct duk_heaphdr_string { #define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 #define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 #if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_FASTINT_UPDREF_ALT0 -#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0 -#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0 +#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0 +#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0 +#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0 #else -#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */ -#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF -#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */ +#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF #endif /* DUK_USE_FASTINT */ +#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */ #define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 #define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 #define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 @@ -4055,34 +4486,76 @@ struct duk_heaphdr_string { #else /* DUK_USE_REFERENCE_COUNTING */ +#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) 0 +#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 0 + #define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */ #define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF_NORZ_FAST(thr,v) do {} while (0) /* nop */ #define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */ #define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF_NORZ_SLOW(thr,v) do {} while (0) /* nop */ #define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */ #define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF_NORZ(thr,v) do {} while (0) /* nop */ #define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */ #define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ #define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */ #define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ #define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */ #define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_INCREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_INCREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ #define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */ #define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_INCREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_INCREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ #define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */ #define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_INCREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_INCREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ #define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */ #define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HNATIVEFUNCTION_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HNATIVEFUNCTION_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFEROBJECT_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFEROBJECT_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_NORZ(thr,h) do {} while (0) /* nop */ + +#define DUK_HCOMPFUNC_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HCOMPFUNC_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HNATFUNC_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HNATFUNC_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HNATFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFOBJ_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFOBJ_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) do {} while (0) /* nop */ #define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */ #define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HTHREAD_DECREF_NORZ(thr,h) do {} while (0) /* nop */ #define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ #define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */ + +#define DUK_REFZERO_CHECK_FAST(thr) do {} while (0) /* nop */ +#define DUK_REFZERO_CHECK_SLOW(thr) do {} while (0) /* nop */ #define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \ duk_tval *tv__dst; tv__dst = (tvptr_dst); \ @@ -4115,7 +4588,7 @@ struct duk_heaphdr_string { } while (0) #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \ + DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ DUK_UNREF((thr)); \ } while (0) #define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ @@ -4129,19 +4602,19 @@ struct duk_heaphdr_string { DUK_UNREF((thr)); \ } while (0) #if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ +#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \ + DUK_TVAL_SET_I48(tv__dst, (newval)); \ DUK_UNREF((thr)); \ } while (0) -#define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ +#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \ + DUK_TVAL_SET_I32(tv__dst, (newval)); \ DUK_UNREF((thr)); \ } while (0) -#define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ +#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \ + DUK_TVAL_SET_U32(tv__dst, (newval)); \ DUK_UNREF((thr)); \ } while (0) #else @@ -4187,6 +4660,7 @@ struct duk_heaphdr_string { } while (0) #define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 +#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 #define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 #define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 #define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 @@ -4195,14 +4669,15 @@ struct duk_heaphdr_string { #define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 #define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 #if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_FASTINT_UPDREF_ALT0 -#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0 -#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0 +#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0 +#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0 +#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0 #else -#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */ -#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF -#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */ +#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF #endif /* DUK_USE_FASTINT */ +#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */ #define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 #define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 #define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 @@ -4216,13 +4691,13 @@ struct duk_heaphdr_string { #endif /* DUK_USE_REFERENCE_COUNTING */ #endif /* DUK_HEAPHDR_H_INCLUDED */ -#line 1 "duk_api_internal.h" +/* #include duk_api_internal.h */ /* * Internal API calls which have (stack and other) semantics similar * to the public API. */ -#ifndef DUK_API_INTERNAL_H_INCLUDED +#if !defined(DUK_API_INTERNAL_H_INCLUDED) #define DUK_API_INTERNAL_H_INCLUDED /* duk_push_sprintf constants */ @@ -4247,12 +4722,27 @@ duk_bool_t duk_valstack_resize_raw(duk_context *ctx, duk_size_t min_new_size, duk_small_uint_t flags); +DUK_INTERNAL_DECL void duk_dup_0(duk_context *ctx); +DUK_INTERNAL_DECL void duk_dup_1(duk_context *ctx); +DUK_INTERNAL_DECL void duk_dup_2(duk_context *ctx); +/* duk_dup_m1() would be same as duk_dup_top() */ +DUK_INTERNAL_DECL void duk_dup_m2(duk_context *ctx); +DUK_INTERNAL_DECL void duk_dup_m3(duk_context *ctx); +DUK_INTERNAL_DECL void duk_dup_m4(duk_context *ctx); + +DUK_INTERNAL_DECL void duk_remove_m2(duk_context *ctx); + +DUK_INTERNAL_DECL duk_int_t duk_get_type_tval(duk_tval *tv); +DUK_INTERNAL_DECL duk_uint_t duk_get_type_mask_tval(duk_tval *tv); + #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); +DUK_INTERNAL_DECL const char *duk_get_type_name(duk_context *ctx, duk_idx_t idx); #endif +DUK_INTERNAL_DECL duk_small_uint_t duk_get_class_number(duk_context *ctx, duk_idx_t idx); -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 duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_tval *duk_get_tval_or_unused(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t idx); DUK_INTERNAL_DECL void duk_push_tval(duk_context *ctx, duk_tval *tv); /* Push the current 'this' binding; throw TypeError if binding is not object @@ -4266,6 +4756,8 @@ DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_context *ct /* duk_push_this() + CheckObjectCoercible() + duk_to_string() */ DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx); +DUK_INTERNAL_DECL duk_hstring *duk_push_uint_to_hstring(duk_context *ctx, duk_uint_t i); + /* Get a borrowed duk_tval pointer to the current 'this' binding. Caller must * make sure there's an active callstack entry. Note that the returned pointer * is unstable with regards to side effects. @@ -4292,105 +4784,200 @@ 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 */ -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); -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); +DUK_INTERNAL_DECL duk_bool_t duk_is_string_notsymbol(duk_context *ctx, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum); +DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hstring *duk_get_hstring_notsymbol(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL const char *duk_get_string_notsymbol(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_context *ctx, duk_idx_t idx); -#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); -#endif -DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag, duk_bool_t *out_found); + +DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t idx, duk_small_uint_t classnum); + +DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_promote_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask); +DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_promote_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask); +DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_accept_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask); +#define duk_require_hobject_promote_lfunc(ctx,idx) \ + duk_require_hobject_promote_mask((ctx), (idx), DUK_TYPE_MASK_LIGHTFUNC) +#define duk_get_hobject_promote_lfunc(ctx,idx) \ + duk_get_hobject_promote_mask((ctx), (idx), DUK_TYPE_MASK_LIGHTFUNC) #if 0 /*unused*/ -DUK_INTERNAL_DECL void *duk_get_voidptr(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL void *duk_get_voidptr(duk_context *ctx, duk_idx_t idx); #endif -DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL duk_hstring *duk_known_hstring(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hobject *duk_known_hobject(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hbuffer *duk_known_hbuffer(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hcompfunc *duk_known_hcompfunc(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hnatfunc *duk_known_hnatfunc(duk_context *ctx, duk_idx_t idx); + +DUK_INTERNAL_DECL duk_double_t duk_to_number_tval(duk_context *ctx, duk_tval *tv); + +DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_m1(duk_context *ctx); +DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_acceptsymbol(duk_context *ctx, duk_idx_t idx); + +DUK_INTERNAL_DECL duk_hobject *duk_to_hobject(duk_context *ctx, duk_idx_t idx); + +DUK_INTERNAL_DECL duk_double_t duk_to_number_m1(duk_context *ctx); +DUK_INTERNAL_DECL duk_double_t duk_to_number_m2(duk_context *ctx); + #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); +DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t idx); #endif +DUK_INTERNAL_DECL void duk_push_class_string_tval(duk_context *ctx, duk_tval *tv); -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); -DUK_INTERNAL_DECL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval); +DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t idx, 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 idx, duk_int_t minval, duk_int_t maxval); +DUK_INTERNAL_DECL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t idx, duk_int_t minval, duk_int_t maxval); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t idx); #endif +DUK_INTERNAL_DECL duk_hstring *duk_to_property_key_hstring(duk_context *ctx, duk_idx_t idx); -DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index); -DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index); -DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index); -DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index); -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); - -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_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hstring *duk_require_hstring_notsymbol(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL const char *duk_require_lstring_notsymbol(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len); +DUK_INTERNAL_DECL const char *duk_require_string_notsymbol(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hcompfunc *duk_require_hcompfunc(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL duk_hnatfunc *duk_require_hnatfunc(duk_context *ctx, duk_idx_t idx); -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); +DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t idx, duk_small_uint_t classnum); DUK_INTERNAL_DECL void duk_push_hstring(duk_context *ctx, duk_hstring *h); -DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx); +DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_context *ctx, duk_small_uint_t stridx); +DUK_INTERNAL_DECL void duk_push_hstring_empty(duk_context *ctx); DUK_INTERNAL_DECL void duk_push_hobject(duk_context *ctx, duk_hobject *h); DUK_INTERNAL_DECL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h); #define duk_push_hthread(ctx,h) \ duk_push_hobject((ctx), (duk_hobject *) (h)) -#define duk_push_hcompiledfunction(ctx,h) \ - duk_push_hobject((ctx), (duk_hobject *) (h)) -#define duk_push_hnativefunction(ctx,h) \ +#define duk_push_hnatfunc(ctx,h) \ duk_push_hobject((ctx), (duk_hobject *) (h)) DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx); -DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx); -DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto); -DUK_INTERNAL_DECL duk_idx_t duk_push_object_internal(duk_context *ctx); -DUK_INTERNAL_DECL duk_idx_t duk_push_compiledfunction(duk_context *ctx); +DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx); +DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto); +DUK_INTERNAL_DECL duk_hcompfunc *duk_push_hcompfunc(duk_context *ctx); DUK_INTERNAL_DECL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs); DUK_INTERNAL_DECL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs); +/* XXX: duk_push_harray() and duk_push_hcompfunc() are inconsistent with + * duk_push_hobject() etc which don't create a new value. + */ +DUK_INTERNAL_DECL duk_harray *duk_push_harray(duk_context *ctx); +DUK_INTERNAL_DECL duk_harray *duk_push_harray_with_size(duk_context *ctx, duk_uint32_t size); + DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz); +DUK_INTERNAL_DECL void duk_push_lightfunc_name_raw(duk_context *ctx, duk_c_function func, duk_small_uint_t lf_flags); 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_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL_DECL duk_hbufobj *duk_push_bufobj_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx); +#endif + +DUK_INTERNAL_DECL void *duk_push_fixed_buffer_nozero(duk_context *ctx, duk_size_t len); +DUK_INTERNAL_DECL void *duk_push_fixed_buffer_zero(duk_context *ctx, duk_size_t len); -#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_readable(duk_context *ctx, duk_idx_t idx); DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv); +DUK_INTERNAL_DECL const char *duk_push_string_tval_readable_error(duk_context *ctx, duk_tval *tv); + +/* The duk_xxx_prop_stridx_short() variants expect their arguments to be short + * enough to be packed into a single 32-bit integer argument. Argument limits + * vary per call; typically 16 bits are assigned to the signed value stack index + * and the stridx. In practice these work well for footprint with constant + * arguments and such call sites are also easiest to verify to be correct. + */ + +DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [val] */ +DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args); +#define duk_get_prop_stridx_short(ctx,obj_idx,stridx) \ + (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \ + DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \ + duk_get_prop_stridx_short_raw((ctx), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx)))) +DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop); /* [] -> [] */ + +DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [val] -> [] */ +DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args); +#define duk_put_prop_stridx_short(ctx,obj_idx,stridx) \ + (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \ + DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \ + duk_put_prop_stridx_short_raw((ctx), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx)))) + +DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */ +#if 0 /* Too few call sites to be useful. */ +DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args); +#define duk_del_prop_stridx_short(ctx,obj_idx,stridx) \ + (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \ + DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \ + duk_del_prop_stridx_short_raw((ctx), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx)))) +#endif +#define duk_del_prop_stridx_short(ctx,obj_idx,stridx) \ + duk_del_prop_stridx((ctx), (obj_idx), (stridx)) + +DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */ +#if 0 /* Too few call sites to be useful. */ +DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args); +#define duk_has_prop_stridx_short(ctx,obj_idx,stridx) \ + (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \ + DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \ + duk_has_prop_stridx_short_raw((ctx), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx)))) +#endif +#define duk_has_prop_stridx_short(ctx,obj_idx,stridx) \ + duk_has_prop_stridx((ctx), (obj_idx), (stridx)) + +DUK_INTERNAL_DECL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t desc_flags); /* [key val] -> [] */ + +DUK_INTERNAL_DECL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags); /* [val] -> [] */ + +/* XXX: Because stridx and desc_flags have a limited range, this call could + * always pack stridx and desc_flags into a single argument. + */ +DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags); /* [val] -> [] */ +DUK_INTERNAL_DECL void duk_xdef_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args); +#define duk_xdef_prop_stridx_short(ctx,obj_idx,stridx,desc_flags) \ + (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x80L && (duk_int_t) (obj_idx) <= 0x7fL), \ + DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \ + DUK_ASSERT_EXPR((duk_int_t) (desc_flags) >= 0 && (duk_int_t) (desc_flags) <= 0xffL), \ + duk_xdef_prop_stridx_short_raw((ctx), (((duk_uint_t) (obj_idx)) << 24) + (((duk_uint_t) (stridx)) << 8) + (duk_uint_t) (desc_flags))) + +#define duk_xdef_prop_wec(ctx,obj_idx) \ + duk_xdef_prop((ctx), (obj_idx), DUK_PROPDESC_FLAGS_WEC) +#define duk_xdef_prop_index_wec(ctx,obj_idx,arr_idx) \ + duk_xdef_prop_index((ctx), (obj_idx), (arr_idx), DUK_PROPDESC_FLAGS_WEC) +#define duk_xdef_prop_stridx_wec(ctx,obj_idx,stridx) \ + duk_xdef_prop_stridx((ctx), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC) +#define duk_xdef_prop_stridx_short_wec(ctx,obj_idx,stridx) \ + duk_xdef_prop_stridx_short((ctx), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC) + +DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags); /* [] -> [] */ + +DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */ + +DUK_INTERNAL_DECL void duk_pack(duk_context *ctx, duk_idx_t count); +#if 0 +DUK_INTERNAL_DECL void duk_unpack(duk_context *ctx); #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); /* [] -> [] */ -DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [] */ - -DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_bool_t *out_has_prop); /* [] -> [] */ +DUK_INTERNAL_DECL void duk_require_constructor_call(duk_context *ctx); +DUK_INTERNAL_DECL void duk_require_constructable(duk_context *ctx, duk_idx_t idx); +DUK_INTERNAL_DECL void duk_push_symbol_descriptive_string(duk_context *ctx, duk_hstring *h); -DUK_INTERNAL_DECL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags); /* [key val] -> [] */ -DUK_INTERNAL_DECL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index, duk_small_uint_t desc_flags); /* [val] -> [] */ -DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags); /* [val] -> [] */ -DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags); /* [] -> [] */ -DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags); /* [] -> [] */ +DUK_INTERNAL_DECL void duk_resolve_nonbound_function(duk_context *ctx); -/* These are macros for now, but could be separate functions to reduce code - * footprint (check call site count before refactoring). - */ -#define duk_xdef_prop_wec(ctx,obj_index) \ - duk_xdef_prop((ctx), (obj_index), DUK_PROPDESC_FLAGS_WEC) -#define duk_xdef_prop_index_wec(ctx,obj_index,arr_index) \ - duk_xdef_prop_index((ctx), (obj_index), (arr_index), DUK_PROPDESC_FLAGS_WEC) -#define duk_xdef_prop_stridx_wec(ctx,obj_index,stridx) \ - duk_xdef_prop_stridx((ctx), (obj_index), (stridx), DUK_PROPDESC_FLAGS_WEC) +DUK_INTERNAL_DECL duk_idx_t duk_get_top_require_min(duk_context *ctx, duk_idx_t min_top); +DUK_INTERNAL_DECL duk_idx_t duk_get_top_index_unsafe(duk_context *ctx); +DUK_INTERNAL_DECL void duk_pop_unsafe(duk_context *ctx); -/* Set object 'length'. */ -DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t length); +DUK_INTERNAL_DECL void duk_compact_m1(duk_context *ctx); /* Raw internal valstack access macros: access is unsafe so call site * must have a guarantee that the index is valid. When that is the case, @@ -4398,9 +4985,9 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz * Both 'ctx' and 'idx' are evaluted multiple times, but only for asserts. */ #define DUK_ASSERT_VALID_NEGIDX(ctx,idx) \ - (DUK_ASSERT_EXPR((idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx)))) + (DUK_ASSERT_EXPR((duk_int_t) (idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx)))) #define DUK_ASSERT_VALID_POSIDX(ctx,idx) \ - (DUK_ASSERT_EXPR((idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx)))) + (DUK_ASSERT_EXPR((duk_int_t) (idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx)))) #define DUK_GET_TVAL_NEGIDX(ctx,idx) \ (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_top + (idx)) #define DUK_GET_TVAL_POSIDX(ctx,idx) \ @@ -4410,8 +4997,12 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz #define DUK_GET_HOBJECT_POSIDX(ctx,idx) \ (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_bottom + (idx))) +#define DUK_GET_THIS_TVAL_PTR(thr) \ + (DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \ + (thr)->valstack_bottom - 1) + #endif /* DUK_API_INTERNAL_H_INCLUDED */ -#line 1 "duk_hstring.h" +/* #include duk_hstring.h */ /* * Heap string representation. * @@ -4428,7 +5019,7 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz * really a practical issue. */ -#ifndef DUK_HSTRING_H_INCLUDED +#if !defined(DUK_HSTRING_H_INCLUDED) #define DUK_HSTRING_H_INCLUDED /* Impose a maximum string length for now. Restricted artificially to @@ -4454,15 +5045,17 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz #define DUK_HSTRING_FLAG_ASCII DUK_HEAPHDR_USER_FLAG(0) /* string is ASCII, clen == blen */ #define DUK_HSTRING_FLAG_ARRIDX DUK_HEAPHDR_USER_FLAG(1) /* string is a valid array index */ -#define DUK_HSTRING_FLAG_INTERNAL DUK_HEAPHDR_USER_FLAG(2) /* string is internal */ -#define DUK_HSTRING_FLAG_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(3) /* string is a reserved word (non-strict) */ -#define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(4) /* string is a reserved word (strict) */ -#define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(5) /* string is 'eval' or 'arguments' */ -#define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(6) /* string data is external (duk_hstring_external) */ +#define DUK_HSTRING_FLAG_SYMBOL DUK_HEAPHDR_USER_FLAG(2) /* string is a symbol (invalid utf-8) */ +#define DUK_HSTRING_FLAG_HIDDEN DUK_HEAPHDR_USER_FLAG(3) /* string is a hidden symbol (implies symbol, Duktape 1.x internal string) */ +#define DUK_HSTRING_FLAG_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(4) /* string is a reserved word (non-strict) */ +#define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(5) /* string is a reserved word (strict) */ +#define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(6) /* string is 'eval' or 'arguments' */ +#define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(7) /* string data is external (duk_hstring_external) */ #define DUK_HSTRING_HAS_ASCII(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII) #define DUK_HSTRING_HAS_ARRIDX(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX) -#define DUK_HSTRING_HAS_INTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL) +#define DUK_HSTRING_HAS_SYMBOL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL) +#define DUK_HSTRING_HAS_HIDDEN(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN) #define DUK_HSTRING_HAS_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD) #define DUK_HSTRING_HAS_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD) #define DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS) @@ -4470,7 +5063,8 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz #define DUK_HSTRING_SET_ASCII(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII) #define DUK_HSTRING_SET_ARRIDX(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX) -#define DUK_HSTRING_SET_INTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL) +#define DUK_HSTRING_SET_SYMBOL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL) +#define DUK_HSTRING_SET_HIDDEN(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN) #define DUK_HSTRING_SET_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD) #define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD) #define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS) @@ -4478,7 +5072,8 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz #define DUK_HSTRING_CLEAR_ASCII(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII) #define DUK_HSTRING_CLEAR_ARRIDX(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX) -#define DUK_HSTRING_CLEAR_INTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL) +#define DUK_HSTRING_CLEAR_SYMBOL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL) +#define DUK_HSTRING_CLEAR_HIDDEN(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN) #define DUK_HSTRING_CLEAR_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD) #define DUK_HSTRING_CLEAR_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD) #define DUK_HSTRING_CLEAR_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS) @@ -4548,15 +5143,20 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz /* marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest valid) */ #define DUK_HSTRING_NO_ARRAY_INDEX (0xffffffffUL) -/* get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX); +#if defined(DUK_USE_HSTRING_ARRIDX) +#define DUK_HSTRING_GET_ARRIDX_FAST(h) ((h)->arridx) +#define DUK_HSTRING_GET_ARRIDX_SLOW(h) ((h)->arridx) +#else +/* Get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX); * avoids helper call if string has no array index value. */ #define DUK_HSTRING_GET_ARRIDX_FAST(h) \ (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_string_helper((h)) : DUK_HSTRING_NO_ARRAY_INDEX) -/* slower but more compact variant */ +/* Slower but more compact variant. */ #define DUK_HSTRING_GET_ARRIDX_SLOW(h) \ (duk_js_to_arrayindex_string_helper((h))) +#endif /* * Misc @@ -4581,6 +5181,11 @@ struct duk_hstring { duk_uint32_t hash; #endif + /* precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX) */ +#if defined(DUK_USE_HSTRING_ARRIDX) + duk_uarridx_t arridx; +#endif + /* length in bytes (not counting NUL term) */ #if defined(DUK_USE_STRLEN16) /* placed in duk_heaphdr_string */ @@ -4624,14 +5229,14 @@ struct duk_hstring_external { * Prototypes */ -DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos); +DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware); #if !defined(DUK_USE_HSTRING_CLEN) DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); #endif #endif /* DUK_HSTRING_H_INCLUDED */ -#line 1 "duk_hobject.h" +/* #include duk_hobject.h */ /* * Heap object representation. * @@ -4663,23 +5268,27 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); * parts are resized together, and makes property access a bit complicated. */ -#ifndef DUK_HOBJECT_H_INCLUDED +#if !defined(DUK_HOBJECT_H_INCLUDED) #define DUK_HOBJECT_H_INCLUDED -/* Object flag. There are currently 26 flag bits available. Make sure +/* Object flag. There are currently 25 flag bits available. Make sure * this stays in sync with debugger object inspection code. */ + +/* XXX: some flags are object subtype specific (e.g. common to all function + * subtypes, duk_harray, etc) and could be reused for different subtypes. + */ #define DUK_HOBJECT_FLAG_EXTENSIBLE DUK_HEAPHDR_USER_FLAG(0) /* object is extensible */ #define DUK_HOBJECT_FLAG_CONSTRUCTABLE DUK_HEAPHDR_USER_FLAG(1) /* object is constructable */ -#define DUK_HOBJECT_FLAG_BOUND DUK_HEAPHDR_USER_FLAG(2) /* object established using Function.prototype.bind() */ -#define DUK_HOBJECT_FLAG_COMPILEDFUNCTION DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompiledfunction) */ -#define DUK_HOBJECT_FLAG_NATIVEFUNCTION DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnativefunction) */ -#define DUK_HOBJECT_FLAG_BUFFEROBJECT DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufferobject) (always exotic) */ +#define DUK_HOBJECT_FLAG_BOUNDFUNC DUK_HEAPHDR_USER_FLAG(2) /* object established using Function.prototype.bind() */ +#define DUK_HOBJECT_FLAG_COMPFUNC DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompfunc) */ +#define DUK_HOBJECT_FLAG_NATFUNC DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnatfunc) */ +#define DUK_HOBJECT_FLAG_BUFOBJ DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufobj) (always exotic) */ #define DUK_HOBJECT_FLAG_THREAD DUK_HEAPHDR_USER_FLAG(7) /* object is a thread (duk_hthread) */ #define DUK_HOBJECT_FLAG_ARRAY_PART DUK_HEAPHDR_USER_FLAG(8) /* object has an array part (a_size may still be 0) */ #define DUK_HOBJECT_FLAG_STRICT DUK_HEAPHDR_USER_FLAG(9) /* function: function object is strict */ #define DUK_HOBJECT_FLAG_NOTAIL DUK_HEAPHDR_USER_FLAG(10) /* function: function must not be tail called */ -#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompiledfunction) */ +#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompfunc) */ #define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(12) /* function: create binding for func name (function templates only, used for named function expressions) */ #define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(13) /* function: create an arguments object on function call */ #define DUK_HOBJECT_FLAG_ENVRECCLOSED DUK_HEAPHDR_USER_FLAG(14) /* envrec: (declarative) record is closed */ @@ -4708,26 +5317,27 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); #define DUK_HOBJECT_CLASS_AS_FLAGS(v) (((duk_uint_t) (v)) << DUK_HOBJECT_FLAG_CLASS_BASE) /* E5 Section 8.6.2 + custom classes */ -#define DUK_HOBJECT_CLASS_UNUSED 0 -#define DUK_HOBJECT_CLASS_ARGUMENTS 1 +#define DUK_HOBJECT_CLASS_NONE 0 +#define DUK_HOBJECT_CLASS_OBJECT 1 #define DUK_HOBJECT_CLASS_ARRAY 2 -#define DUK_HOBJECT_CLASS_BOOLEAN 3 -#define DUK_HOBJECT_CLASS_DATE 4 -#define DUK_HOBJECT_CLASS_ERROR 5 -#define DUK_HOBJECT_CLASS_FUNCTION 6 -#define DUK_HOBJECT_CLASS_JSON 7 -#define DUK_HOBJECT_CLASS_MATH 8 -#define DUK_HOBJECT_CLASS_NUMBER 9 -#define DUK_HOBJECT_CLASS_OBJECT 10 +#define DUK_HOBJECT_CLASS_FUNCTION 3 +#define DUK_HOBJECT_CLASS_ARGUMENTS 4 +#define DUK_HOBJECT_CLASS_BOOLEAN 5 +#define DUK_HOBJECT_CLASS_DATE 6 +#define DUK_HOBJECT_CLASS_ERROR 7 +#define DUK_HOBJECT_CLASS_JSON 8 +#define DUK_HOBJECT_CLASS_MATH 9 +#define DUK_HOBJECT_CLASS_NUMBER 10 #define DUK_HOBJECT_CLASS_REGEXP 11 #define DUK_HOBJECT_CLASS_STRING 12 #define DUK_HOBJECT_CLASS_GLOBAL 13 -#define DUK_HOBJECT_CLASS_OBJENV 14 /* custom */ -#define DUK_HOBJECT_CLASS_DECENV 15 /* custom */ -#define DUK_HOBJECT_CLASS_BUFFER 16 /* custom; implies DUK_HOBJECT_IS_BUFFEROBJECT */ +#define DUK_HOBJECT_CLASS_SYMBOL 14 +#define DUK_HOBJECT_CLASS_OBJENV 15 /* custom */ +#define DUK_HOBJECT_CLASS_DECENV 16 /* custom */ #define DUK_HOBJECT_CLASS_POINTER 17 /* custom */ #define DUK_HOBJECT_CLASS_THREAD 18 /* custom; implies DUK_HOBJECT_IS_THREAD */ -#define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFFEROBJECT */ +#define DUK_HOBJECT_CLASS_BUFOBJ_MIN 19 +#define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFOBJ */ #define DUK_HOBJECT_CLASS_DATAVIEW 20 #define DUK_HOBJECT_CLASS_INT8ARRAY 21 #define DUK_HOBJECT_CLASS_UINT8ARRAY 22 @@ -4738,11 +5348,12 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); #define DUK_HOBJECT_CLASS_UINT32ARRAY 27 #define DUK_HOBJECT_CLASS_FLOAT32ARRAY 28 #define DUK_HOBJECT_CLASS_FLOAT64ARRAY 29 +#define DUK_HOBJECT_CLASS_BUFOBJ_MAX 29 #define DUK_HOBJECT_CLASS_MAX 29 -/* class masks */ +/* Class masks. */ #define DUK_HOBJECT_CMASK_ALL ((1UL << (DUK_HOBJECT_CLASS_MAX + 1)) - 1UL) -#define DUK_HOBJECT_CMASK_UNUSED (1UL << DUK_HOBJECT_CLASS_UNUSED) +#define DUK_HOBJECT_CMASK_NONE (1UL << DUK_HOBJECT_CLASS_NONE) #define DUK_HOBJECT_CMASK_ARGUMENTS (1UL << DUK_HOBJECT_CLASS_ARGUMENTS) #define DUK_HOBJECT_CMASK_ARRAY (1UL << DUK_HOBJECT_CLASS_ARRAY) #define DUK_HOBJECT_CMASK_BOOLEAN (1UL << DUK_HOBJECT_CLASS_BOOLEAN) @@ -4756,9 +5367,9 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); #define DUK_HOBJECT_CMASK_REGEXP (1UL << DUK_HOBJECT_CLASS_REGEXP) #define DUK_HOBJECT_CMASK_STRING (1UL << DUK_HOBJECT_CLASS_STRING) #define DUK_HOBJECT_CMASK_GLOBAL (1UL << DUK_HOBJECT_CLASS_GLOBAL) +#define DUK_HOBJECT_CMASK_SYMBOL (1UL << DUK_HOBJECT_CLASS_SYMBOL) #define DUK_HOBJECT_CMASK_OBJENV (1UL << DUK_HOBJECT_CLASS_OBJENV) #define DUK_HOBJECT_CMASK_DECENV (1UL << DUK_HOBJECT_CLASS_DECENV) -#define DUK_HOBJECT_CMASK_BUFFER (1UL << DUK_HOBJECT_CLASS_BUFFER) #define DUK_HOBJECT_CMASK_POINTER (1UL << DUK_HOBJECT_CLASS_POINTER) #define DUK_HOBJECT_CMASK_THREAD (1UL << DUK_HOBJECT_CLASS_THREAD) #define DUK_HOBJECT_CMASK_ARRAYBUFFER (1UL << DUK_HOBJECT_CLASS_ARRAYBUFFER) @@ -4773,9 +5384,8 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); #define DUK_HOBJECT_CMASK_FLOAT32ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT32ARRAY) #define DUK_HOBJECT_CMASK_FLOAT64ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT64ARRAY) -#define DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS \ - (DUK_HOBJECT_CMASK_BUFFER | \ - DUK_HOBJECT_CMASK_ARRAYBUFFER | \ +#define DUK_HOBJECT_CMASK_ALL_BUFOBJS \ + (DUK_HOBJECT_CMASK_ARRAYBUFFER | \ DUK_HOBJECT_CMASK_DATAVIEW | \ DUK_HOBJECT_CMASK_INT8ARRAY | \ DUK_HOBJECT_CMASK_UINT8ARRAY | \ @@ -4790,42 +5400,49 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); #define DUK_HOBJECT_IS_OBJENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_OBJENV) #define DUK_HOBJECT_IS_DECENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DECENV) #define DUK_HOBJECT_IS_ENV(h) (DUK_HOBJECT_IS_OBJENV((h)) || DUK_HOBJECT_IS_DECENV((h))) -#define DUK_HOBJECT_IS_ARRAY(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAY) -#define DUK_HOBJECT_IS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION) -#define DUK_HOBJECT_IS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION) -#define DUK_HOBJECT_IS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT) +#define DUK_HOBJECT_IS_ARRAY(h) DUK_HOBJECT_HAS_EXOTIC_ARRAY((h)) /* Rely on class Array <=> exotic Array */ +#define DUK_HOBJECT_IS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC) +#define DUK_HOBJECT_IS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC) +#define DUK_HOBJECT_IS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC) +#define DUK_HOBJECT_IS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) #define DUK_HOBJECT_IS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) #define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ - DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \ - DUK_HOBJECT_FLAG_NATIVEFUNCTION) + DUK_HOBJECT_FLAG_COMPFUNC | \ + DUK_HOBJECT_FLAG_NATFUNC) #define DUK_HOBJECT_IS_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ - DUK_HOBJECT_FLAG_BOUND | \ - DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \ - DUK_HOBJECT_FLAG_NATIVEFUNCTION) + DUK_HOBJECT_FLAG_BOUNDFUNC | \ + DUK_HOBJECT_FLAG_COMPFUNC | \ + DUK_HOBJECT_FLAG_NATFUNC) #define DUK_HOBJECT_IS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ - DUK_HOBJECT_FLAG_BOUND | \ - DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \ - DUK_HOBJECT_FLAG_NATIVEFUNCTION) + DUK_HOBJECT_FLAG_BOUNDFUNC | \ + DUK_HOBJECT_FLAG_COMPFUNC | \ + DUK_HOBJECT_FLAG_NATFUNC) -/* object has any exotic behavior(s) */ +/* Object has any exotic behavior(s). */ #define DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \ DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS | \ DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \ DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC | \ - DUK_HOBJECT_FLAG_BUFFEROBJECT | \ + DUK_HOBJECT_FLAG_BUFOBJ | \ DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) - #define DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS) +/* Object has any virtual properties (not counting Proxy behavior). */ +#define DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \ + DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \ + DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC | \ + DUK_HOBJECT_FLAG_BUFOBJ) +#define DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS) + #define DUK_HOBJECT_HAS_EXTENSIBLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE) #define DUK_HOBJECT_HAS_CONSTRUCTABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE) -#define DUK_HOBJECT_HAS_BOUND(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND) -#define DUK_HOBJECT_HAS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION) -#define DUK_HOBJECT_HAS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION) -#define DUK_HOBJECT_HAS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT) +#define DUK_HOBJECT_HAS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC) +#define DUK_HOBJECT_HAS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC) +#define DUK_HOBJECT_HAS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC) +#define DUK_HOBJECT_HAS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) #define DUK_HOBJECT_HAS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) #define DUK_HOBJECT_HAS_ARRAY_PART(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART) #define DUK_HOBJECT_HAS_STRICT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT) @@ -4842,10 +5459,10 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); #define DUK_HOBJECT_SET_EXTENSIBLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE) #define DUK_HOBJECT_SET_CONSTRUCTABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE) -#define DUK_HOBJECT_SET_BOUND(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND) -#define DUK_HOBJECT_SET_COMPILEDFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION) -#define DUK_HOBJECT_SET_NATIVEFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION) -#define DUK_HOBJECT_SET_BUFFEROBJECT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT) +#define DUK_HOBJECT_SET_BOUNDFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC) +#define DUK_HOBJECT_SET_COMPFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC) +#define DUK_HOBJECT_SET_NATFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC) +#define DUK_HOBJECT_SET_BUFOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) #define DUK_HOBJECT_SET_THREAD(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) #define DUK_HOBJECT_SET_ARRAY_PART(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART) #define DUK_HOBJECT_SET_STRICT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT) @@ -4862,10 +5479,10 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); #define DUK_HOBJECT_CLEAR_EXTENSIBLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE) #define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE) -#define DUK_HOBJECT_CLEAR_BOUND(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND) -#define DUK_HOBJECT_CLEAR_COMPILEDFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION) -#define DUK_HOBJECT_CLEAR_NATIVEFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION) -#define DUK_HOBJECT_CLEAR_BUFFEROBJECT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT) +#define DUK_HOBJECT_CLEAR_BOUNDFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC) +#define DUK_HOBJECT_CLEAR_COMPFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC) +#define DUK_HOBJECT_CLEAR_NATFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC) +#define DUK_HOBJECT_CLEAR_BUFOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) #define DUK_HOBJECT_CLEAR_THREAD(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) #define DUK_HOBJECT_CLEAR_ARRAY_PART(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART) #define DUK_HOBJECT_CLEAR_STRICT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT) @@ -4880,7 +5497,9 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); #define DUK_HOBJECT_CLEAR_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC) #define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) -/* flags used for property attributes in duk_propdesc and packed flags */ +/* Flags used for property attributes in duk_propdesc and packed flags. + * Must fit into 8 bits. + */ #define DUK_PROPDESC_FLAG_WRITABLE (1 << 0) /* E5 Section 8.6.1 */ #define DUK_PROPDESC_FLAG_ENUMERABLE (1 << 1) /* E5 Section 8.6.1 */ #define DUK_PROPDESC_FLAG_CONFIGURABLE (1 << 2) /* E5 Section 8.6.1 */ @@ -4893,12 +5512,12 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); DUK_PROPDESC_FLAG_CONFIGURABLE | \ DUK_PROPDESC_FLAG_ACCESSOR) -/* additional flags which are passed in the same flags argument as property +/* Additional flags which are passed in the same flags argument as property * flags but are not stored in object properties. */ #define DUK_PROPDESC_FLAG_NO_OVERWRITE (1 << 4) /* internal define property: skip write silently if exists */ -/* convenience */ +/* Convenience defines for property attributes. */ #define DUK_PROPDESC_FLAGS_NONE 0 #define DUK_PROPDESC_FLAGS_W (DUK_PROPDESC_FLAG_WRITABLE) #define DUK_PROPDESC_FLAGS_E (DUK_PROPDESC_FLAG_ENUMERABLE) @@ -4910,7 +5529,7 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); DUK_PROPDESC_FLAG_ENUMERABLE | \ DUK_PROPDESC_FLAG_CONFIGURABLE) -/* flags for duk_hobject_get_own_propdesc() and variants */ +/* Flags for duk_hobject_get_own_propdesc() and variants. */ #define DUK_GETDESC_FLAG_PUSH_VALUE (1 << 0) /* push value to stack */ #define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1 << 1) /* don't throw for prototype loop */ @@ -4924,9 +5543,8 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); DUK_ASSERT((h) != NULL); \ DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE((h)) || \ DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FUNCTION); \ - DUK_ASSERT(!DUK_HOBJECT_IS_BUFFEROBJECT((h)) || \ - (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_BUFFER || \ - DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAYBUFFER || \ + DUK_ASSERT(!DUK_HOBJECT_IS_BUFOBJ((h)) || \ + (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAYBUFFER || \ DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DATAVIEW || \ DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT8ARRAY || \ DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8ARRAY || \ @@ -4937,6 +5555,9 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT32ARRAY || \ DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT32ARRAY || \ DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT64ARRAY)); \ + /* Object is an Array <=> object has exotic array behavior */ \ + DUK_ASSERT((DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAY && DUK_HOBJECT_HAS_EXOTIC_ARRAY((h))) || \ + (DUK_HOBJECT_GET_CLASS_NUMBER((h)) != DUK_HOBJECT_CLASS_ARRAY && !DUK_HOBJECT_HAS_EXOTIC_ARRAY((h)))); \ } while (0) /* @@ -5418,7 +6039,7 @@ struct duk_hobject { #if defined(DUK_USE_HEAPPTR16) /* Located in duk_heaphdr h_extra16. Subclasses of duk_hobject (like - * duk_hcompiledfunction) are not free to use h_extra16 for this reason. + * duk_hcompfunc) are not free to use h_extra16 for this reason. */ #else duk_uint8_t *props; @@ -5465,11 +6086,22 @@ DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobj #if 0 /* unused */ DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags); #endif -DUK_INTERNAL_DECL duk_hcompiledfunction *duk_hcompiledfunction_alloc(duk_heap *heap, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hnativefunction *duk_hnativefunction_alloc(duk_heap *heap, duk_uint_t hobject_flags); -DUK_INTERNAL duk_hbufferobject *duk_hbufferobject_alloc(duk_heap *heap, duk_uint_t hobject_flags); +DUK_INTERNAL_DECL duk_harray *duk_harray_alloc(duk_heap *heap, duk_uint_t hobject_flags); +DUK_INTERNAL_DECL duk_hcompfunc *duk_hcompfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags); +DUK_INTERNAL_DECL duk_hnatfunc *duk_hnatfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags); +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL_DECL duk_hbufobj *duk_hbufobj_alloc(duk_heap *heap, duk_uint_t hobject_flags); +#endif DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags); +/* resize */ +DUK_INTERNAL_DECL void duk_hobject_realloc_props(duk_hthread *thr, + duk_hobject *obj, + duk_uint32_t new_e_size, + duk_uint32_t new_a_size, + duk_uint32_t new_h_size, + duk_bool_t abandon_array); + /* low-level property functions */ DUK_INTERNAL_DECL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx); DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key); @@ -5496,10 +6128,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobje DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key); DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags); DUK_INTERNAL_DECL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags); -DUK_INTERNAL_DECL void duk_hobject_define_accessor_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_hobject *getter, duk_hobject *setter, duk_small_uint_t propflags); -DUK_INTERNAL_DECL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length); /* XXX: duk_uarridx_t? */ -DUK_INTERNAL_DECL void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj); -DUK_INTERNAL_DECL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj); /* XXX: duk_uarridx_t? */ +DUK_INTERNAL_DECL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj); /* helpers for defineProperty() and defineProperties() */ DUK_INTERNAL_DECL @@ -5510,16 +6139,17 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx, duk_hobject **out_getter, duk_hobject **out_setter); DUK_INTERNAL_DECL -void duk_hobject_define_property_helper(duk_context *ctx, - duk_uint_t defprop_flags, - duk_hobject *obj, - duk_hstring *key, - duk_idx_t idx_value, - duk_hobject *get, - duk_hobject *set); +duk_bool_t duk_hobject_define_property_helper(duk_context *ctx, + duk_uint_t defprop_flags, + duk_hobject *obj, + duk_hstring *key, + duk_idx_t idx_value, + duk_hobject *get, + duk_hobject *set, + duk_bool_t throw_flag); /* Object built-in methods */ -DUK_INTERNAL_DECL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_context *ctx); +DUK_INTERNAL_DECL void duk_hobject_object_get_own_property_descriptor(duk_context *ctx, duk_idx_t obj_idx); DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze); DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen); DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags); @@ -5531,7 +6161,7 @@ DUK_INTERNAL_DECL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *h /* hobject management functions */ DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj); -/* ES6 proxy */ +/* ES2015 proxy */ #if defined(DUK_USE_ES6_PROXY) DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler); DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj); @@ -5546,7 +6176,9 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_b DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p); /* finalization */ +#if defined(DUK_USE_FINALIZER_SUPPORT) DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj); +#endif /* pc2line */ #if defined(DUK_USE_PC2LINE) @@ -5557,8 +6189,16 @@ DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, /* misc */ DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop); +#if !defined(DUK_USE_OBJECT_BUILTIN) +/* These declarations are needed when related built-in is disabled and + * genbuiltins.py won't automatically emit the declerations. + */ +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx); +#endif + #endif /* DUK_HOBJECT_H_INCLUDED */ -#line 1 "duk_hcompiledfunction.h" +/* #include duk_hcompfunc.h */ /* * Heap compiled function (Ecmascript function) representation. * @@ -5566,8 +6206,8 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *t * bytecode, constants, and inner functions. */ -#ifndef DUK_HCOMPILEDFUNCTION_H_INCLUDED -#define DUK_HCOMPILEDFUNCTION_H_INCLUDED +#if !defined(DUK_HCOMPFUNC_H_INCLUDED) +#define DUK_HCOMPFUNC_H_INCLUDED /* * Field accessor macros @@ -5576,37 +6216,52 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *t /* XXX: casts could be improved, especially for GET/SET DATA */ #if defined(DUK_USE_HEAPPTR16) -#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \ +#define DUK_HCOMPFUNC_GET_DATA(heap,h) \ ((duk_hbuffer_fixed *) (void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->data16)) -#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \ +#define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \ (h)->data16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ } while (0) -#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h) \ +#define DUK_HCOMPFUNC_GET_FUNCS(heap,h) \ ((duk_hobject **) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->funcs16))) -#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v) do { \ +#define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \ (h)->funcs16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ } while (0) -#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h) \ +#define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) \ ((duk_instr_t *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->bytecode16))) -#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v) do { \ +#define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \ (h)->bytecode16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ } while (0) +#define DUK_HCOMPFUNC_GET_LEXENV(heap,h) \ + ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->lex_env16))) +#define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \ + (h)->lex_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ + } while (0) +#define DUK_HCOMPFUNC_GET_VARENV(heap,h) \ + ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->var_env16))) +#define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \ + (h)->var_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ + } while (0) #else -#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \ - ((duk_hbuffer_fixed *) (void *) (h)->data) -#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \ +#define DUK_HCOMPFUNC_GET_DATA(heap,h) ((duk_hbuffer_fixed *) (void *) (h)->data) +#define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \ (h)->data = (duk_hbuffer *) (v); \ } while (0) -#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h) \ - ((h)->funcs) -#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v) do { \ +#define DUK_HCOMPFUNC_GET_FUNCS(heap,h) ((h)->funcs) +#define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \ (h)->funcs = (v); \ } while (0) -#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h) \ - ((h)->bytecode) -#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v) do { \ +#define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) ((h)->bytecode) +#define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \ (h)->bytecode = (v); \ } while (0) +#define DUK_HCOMPFUNC_GET_LEXENV(heap,h) ((h)->lex_env) +#define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \ + (h)->lex_env = (v); \ + } while (0) +#define DUK_HCOMPFUNC_GET_VARENV(heap,h) ((h)->var_env) +#define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \ + (h)->var_env = (v); \ + } while (0) #endif /* @@ -5614,71 +6269,71 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *t */ /* Note: assumes 'data' is always a fixed buffer */ -#define DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE(heap,h) \ - DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h))) +#define DUK_HCOMPFUNC_GET_BUFFER_BASE(heap,h) \ + DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h))) -#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap,h) \ - ((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE((heap), (h))) +#define DUK_HCOMPFUNC_GET_CONSTS_BASE(heap,h) \ + ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_BUFFER_BASE((heap), (h))) -#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap,h) \ - DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h)) +#define DUK_HCOMPFUNC_GET_FUNCS_BASE(heap,h) \ + DUK_HCOMPFUNC_GET_FUNCS((heap), (h)) -#define DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(heap,h) \ - DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h)) +#define DUK_HCOMPFUNC_GET_CODE_BASE(heap,h) \ + DUK_HCOMPFUNC_GET_BYTECODE((heap), (h)) -#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap,h) \ - ((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h))) +#define DUK_HCOMPFUNC_GET_CONSTS_END(heap,h) \ + ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_FUNCS((heap), (h))) -#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap,h) \ - ((duk_hobject **) (void *) DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h))) +#define DUK_HCOMPFUNC_GET_FUNCS_END(heap,h) \ + ((duk_hobject **) (void *) DUK_HCOMPFUNC_GET_BYTECODE((heap), (h))) -/* XXX: double evaluation of DUK_HCOMPILEDFUNCTION_GET_DATA() */ -#define DUK_HCOMPILEDFUNCTION_GET_CODE_END(heap,h) \ - ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h))) + \ - DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA((heap), h)))) +/* XXX: double evaluation of DUK_HCOMPFUNC_GET_DATA() */ +#define DUK_HCOMPFUNC_GET_CODE_END(heap,h) \ + ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h))) + \ + DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA((heap), h)))) -#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(heap,h) \ +#define DUK_HCOMPFUNC_GET_CONSTS_SIZE(heap,h) \ ( \ (duk_size_t) \ ( \ - ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END((heap), (h))) - \ - ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE((heap), (h))) \ + ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_END((heap), (h))) - \ + ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_BASE((heap), (h))) \ ) \ ) -#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(heap,h) \ +#define DUK_HCOMPFUNC_GET_FUNCS_SIZE(heap,h) \ ( \ (duk_size_t) \ ( \ - ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END((heap), (h))) - \ - ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE((heap), (h))) \ + ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_END((heap), (h))) - \ + ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_BASE((heap), (h))) \ ) \ ) -#define DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(heap,h) \ +#define DUK_HCOMPFUNC_GET_CODE_SIZE(heap,h) \ ( \ (duk_size_t) \ ( \ - ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_END((heap),(h))) - \ - ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE((heap),(h))) \ + ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_END((heap),(h))) - \ + ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_BASE((heap),(h))) \ ) \ ) -#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(heap,h) \ - ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval))) +#define DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap,h) \ + ((duk_size_t) (DUK_HCOMPFUNC_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval))) -#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(heap,h) \ - ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *))) +#define DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap,h) \ + ((duk_size_t) (DUK_HCOMPFUNC_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *))) -#define DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(heap,h) \ - ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t))) +#define DUK_HCOMPFUNC_GET_CODE_COUNT(heap,h) \ + ((duk_size_t) (DUK_HCOMPFUNC_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t))) /* * Main struct */ -struct duk_hcompiledfunction { +struct duk_hcompfunc { /* shared object part */ duk_hobject obj; @@ -5725,6 +6380,17 @@ struct duk_hcompiledfunction { duk_instr_t *bytecode; #endif + /* Lexenv: lexical environment of closure, NULL for templates. + * Varenv: variable environment of closure, NULL for templates. + */ +#if defined(DUK_USE_HEAPPTR16) + duk_uint16_t lex_env16; + duk_uint16_t var_env16; +#else + duk_hobject *lex_env; + duk_hobject *var_env; +#endif + /* * 'nregs' registers are allocated on function entry, at most 'nargs' * are initialized to arguments, and the rest to undefined. Arguments @@ -5780,8 +6446,6 @@ struct duk_hcompiledfunction { * _Formals: [ "arg1", "arg2" ], * _Source: "function func(arg1, arg2) { ... }", * _Pc2line: , - * _Varenv: , - * _Lexenv: * } * * More detailed description of these properties can be found @@ -5797,19 +6461,19 @@ struct duk_hcompiledfunction { #endif }; -#endif /* DUK_HCOMPILEDFUNCTION_H_INCLUDED */ -#line 1 "duk_hnativefunction.h" +#endif /* DUK_HCOMPFUNC_H_INCLUDED */ +/* #include duk_hnatfunc.h */ /* * Heap native function representation. */ -#ifndef DUK_HNATIVEFUNCTION_H_INCLUDED -#define DUK_HNATIVEFUNCTION_H_INCLUDED +#if !defined(DUK_HNATFUNC_H_INCLUDED) +#define DUK_HNATFUNC_H_INCLUDED -#define DUK_HNATIVEFUNCTION_NARGS_VARARGS ((duk_int16_t) -1) -#define DUK_HNATIVEFUNCTION_NARGS_MAX ((duk_int16_t) 0x7fff) +#define DUK_HNATFUNC_NARGS_VARARGS ((duk_int16_t) -1) +#define DUK_HNATFUNC_NARGS_MAX ((duk_int16_t) 0x7fff) -struct duk_hnativefunction { +struct duk_hnatfunc { /* shared object part */ duk_hobject obj; @@ -5830,42 +6494,44 @@ struct duk_hnativefunction { */ }; -#endif /* DUK_HNATIVEFUNCTION_H_INCLUDED */ -#line 1 "duk_hbufferobject.h" +#endif /* DUK_HNATFUNC_H_INCLUDED */ +/* #include duk_hbufobj.h */ /* * Heap Buffer object representation. Used for all Buffer variants. */ -#ifndef DUK_HBUFFEROBJECT_H_INCLUDED -#define DUK_HBUFFEROBJECT_H_INCLUDED +#if !defined(DUK_HBUFOBJ_H_INCLUDED) +#define DUK_HBUFOBJ_H_INCLUDED + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) /* All element accessors are host endian now (driven by TypedArray spec). */ -#define DUK_HBUFFEROBJECT_ELEM_UINT8 0 -#define DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED 1 -#define DUK_HBUFFEROBJECT_ELEM_INT8 2 -#define DUK_HBUFFEROBJECT_ELEM_UINT16 3 -#define DUK_HBUFFEROBJECT_ELEM_INT16 4 -#define DUK_HBUFFEROBJECT_ELEM_UINT32 5 -#define DUK_HBUFFEROBJECT_ELEM_INT32 6 -#define DUK_HBUFFEROBJECT_ELEM_FLOAT32 7 -#define DUK_HBUFFEROBJECT_ELEM_FLOAT64 8 -#define DUK_HBUFFEROBJECT_ELEM_MAX 8 - -#define DUK_ASSERT_HBUFFEROBJECT_VALID(h) do { \ +#define DUK_HBUFOBJ_ELEM_UINT8 0 +#define DUK_HBUFOBJ_ELEM_UINT8CLAMPED 1 +#define DUK_HBUFOBJ_ELEM_INT8 2 +#define DUK_HBUFOBJ_ELEM_UINT16 3 +#define DUK_HBUFOBJ_ELEM_INT16 4 +#define DUK_HBUFOBJ_ELEM_UINT32 5 +#define DUK_HBUFOBJ_ELEM_INT32 6 +#define DUK_HBUFOBJ_ELEM_FLOAT32 7 +#define DUK_HBUFOBJ_ELEM_FLOAT64 8 +#define DUK_HBUFOBJ_ELEM_MAX 8 + +#define DUK_ASSERT_HBUFOBJ_VALID(h) do { \ DUK_ASSERT((h) != NULL); \ DUK_ASSERT((h)->shift <= 3); \ - DUK_ASSERT((h)->elem_type <= DUK_HBUFFEROBJECT_ELEM_MAX); \ - DUK_ASSERT(((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8) || \ - ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) || \ - ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT8) || \ - ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT16) || \ - ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT16) || \ - ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT32) || \ - ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT32) || \ - ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT32) || \ - ((h)->shift == 3 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT64)); \ - DUK_ASSERT((h)->is_view == 0 || (h)->is_view == 1); \ - DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) (h))); \ + DUK_ASSERT((h)->elem_type <= DUK_HBUFOBJ_ELEM_MAX); \ + DUK_ASSERT(((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT8) || \ + ((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT8CLAMPED) || \ + ((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT8) || \ + ((h)->shift == 1 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT16) || \ + ((h)->shift == 1 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT16) || \ + ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT32) || \ + ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT32) || \ + ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_FLOAT32) || \ + ((h)->shift == 3 && (h)->elem_type == DUK_HBUFOBJ_ELEM_FLOAT64)); \ + DUK_ASSERT((h)->is_typedarray == 0 || (h)->is_typedarray == 1); \ + DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) (h))); \ if ((h)->buf == NULL) { \ DUK_ASSERT((h)->offset == 0); \ DUK_ASSERT((h)->length == 0); \ @@ -5881,58 +6547,64 @@ struct duk_hnativefunction { /* Get the current data pointer (caller must ensure buf != NULL) as a * duk_uint8_t ptr. */ -#define DUK_HBUFFEROBJECT_GET_SLICE_BASE(heap,h) \ +#define DUK_HBUFOBJ_GET_SLICE_BASE(heap,h) \ (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ (((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR((heap), (h)->buf)) + (h)->offset)) /* True if slice is full, i.e. offset is zero and length covers the entire - * buffer. This status may change independently of the duk_hbufferobject if - * the underlying buffer is dynamic and changes without the hbufferobject + * buffer. This status may change independently of the duk_hbufobj if + * the underlying buffer is dynamic and changes without the hbufobj * being changed. */ -#define DUK_HBUFFEROBJECT_FULL_SLICE(h) \ +#define DUK_HBUFOBJ_FULL_SLICE(h) \ (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ ((h)->offset == 0 && (h)->length == DUK_HBUFFER_GET_SIZE((h)->buf))) /* Validate that the whole slice [0,length[ is contained in the underlying * buffer. Caller must ensure 'buf' != NULL. */ -#define DUK_HBUFFEROBJECT_VALID_SLICE(h) \ +#define DUK_HBUFOBJ_VALID_SLICE(h) \ (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ ((h)->offset + (h)->length <= DUK_HBUFFER_GET_SIZE((h)->buf))) /* Validate byte read/write for virtual 'offset', i.e. check that the * offset, taking into account h->offset, is within the underlying * buffer size. This is a safety check which is needed to ensure - * that even a misconfigured duk_hbufferobject never causes memory - * unsafe behavior (e.g. if an underlying dynamic buffer changes - * after being setup). Caller must ensure 'buf' != NULL. + * that even a misconfigured duk_hbufobj never causes memory unsafe + * behavior (e.g. if an underlying dynamic buffer changes after being + * setup). Caller must ensure 'buf' != NULL. */ -#define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_INCL(h,off) \ +#define DUK_HBUFOBJ_VALID_BYTEOFFSET_INCL(h,off) \ (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ ((h)->offset + (off) < DUK_HBUFFER_GET_SIZE((h)->buf))) -#define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h,off) \ +#define DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h,off) \ (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ ((h)->offset + (off) <= DUK_HBUFFER_GET_SIZE((h)->buf))) /* Clamp an input byte length (already assumed to be within the nominal - * duk_hbufferobject 'length') to the current dynamic buffer limits to - * yield a byte length limit that's safe for memory accesses. This value - * can be invalidated by any side effect because it may trigger a user + * duk_hbufobj 'length') to the current dynamic buffer limits to yield + * a byte length limit that's safe for memory accesses. This value can + * be invalidated by any side effect because it may trigger a user * callback that resizes the underlying buffer. */ -#define DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h,len) \ +#define DUK_HBUFOBJ_CLAMP_BYTELENGTH(h,len) \ (DUK_ASSERT_EXPR((h) != NULL), \ - duk_hbufferobject_clamp_bytelength((h), (len))) + duk_hbufobj_clamp_bytelength((h), (len))) + +/* Typed arrays have virtual indices, ArrayBuffer and DataView do not. */ +#define DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h) ((h)->is_typedarray) -struct duk_hbufferobject { +struct duk_hbufobj { /* Shared object part. */ duk_hobject obj; /* Underlying buffer (refcounted), may be NULL. */ duk_hbuffer *buf; + /* .buffer reference to an ArrayBuffer, may be NULL. */ + duk_hobject *buf_prop; + /* Slice and accessor information. * * Because the underlying buffer may be dynamic, these may be @@ -5955,17 +6627,18 @@ struct duk_hbufferobject { * 3 = double */ duk_uint8_t elem_type; /* element type */ - duk_uint8_t is_view; + duk_uint8_t is_typedarray; }; -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL_DECL duk_uint_t duk_hbufferobject_clamp_bytelength(duk_hbufferobject *h_bufobj, duk_uint_t len); -#endif -DUK_INTERNAL_DECL void duk_hbufferobject_push_validated_read(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size); -DUK_INTERNAL_DECL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size); +DUK_INTERNAL_DECL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len); +DUK_INTERNAL_DECL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf); +DUK_INTERNAL_DECL void duk_hbufobj_push_validated_read(duk_context *ctx, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size); +DUK_INTERNAL_DECL void duk_hbufobj_validated_write(duk_context *ctx, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size); +DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_context *ctx, duk_idx_t idx); -#endif /* DUK_HBUFFEROBJECT_H_INCLUDED */ -#line 1 "duk_hthread.h" +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ +#endif /* DUK_HBUFOBJ_H_INCLUDED */ +/* #include duk_hthread.h */ /* * Heap thread object representation. * @@ -5973,7 +6646,7 @@ DUK_INTERNAL_DECL void duk_hbufferobject_validated_write(duk_context *ctx, duk_h * which mostly operate on the topmost frame of the value stack. */ -#ifndef DUK_HTHREAD_H_INCLUDED +#if !defined(DUK_HTHREAD_H_INCLUDED) #define DUK_HTHREAD_H_INCLUDED /* @@ -6149,6 +6822,26 @@ DUK_INTERNAL_DECL void duk_hbufferobject_validated_write(duk_context *ctx, duk_h DUK_ASSERT_CTX_VSSIZE((ctx)); \ } while (0) +/* + * Assertion helpers. + */ + +#define DUK_ASSERT_STRIDX_VALID(val) \ + DUK_ASSERT((duk_uint_t) (val) < DUK_HEAP_NUM_STRINGS) + +#define DUK_ASSERT_BIDX_VALID(val) \ + DUK_ASSERT((duk_uint_t) (val) < DUK_NUM_BUILTINS) + +/* + * Misc + */ + +/* Fast access to 'this' binding. Assumes there's a call in progress. */ +#define DUK_HTHREAD_THIS_PTR(thr) \ + (DUK_ASSERT_EXPR((thr) != NULL), \ + DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \ + (thr)->valstack_bottom - 1) + /* * Struct defines */ @@ -6163,7 +6856,7 @@ struct duk_activation { duk_hobject *func; /* borrowed: function being executed; for bound function calls, this is the final, real function, NULL for lightfuncs */ duk_hobject *var_env; /* current variable environment (may be NULL if delayed) */ duk_hobject *lex_env; /* current lexical environment (may be NULL if delayed) */ -#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY +#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) /* Previous value of 'func' caller, restored when unwound. Only in use * when 'func' is non-strict. */ @@ -6346,7 +7039,55 @@ DUK_INTERNAL_DECL void duk_hthread_sync_currpc(duk_hthread *thr); DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr); #endif /* DUK_HTHREAD_H_INCLUDED */ -#line 1 "duk_hbuffer.h" +/* #include duk_harray.h */ +/* + * Heap Array object representation. Used for actual Array instances. + * + * All objects with the exotic array behavior (which must coincide with having + * internal class array) MUST be duk_harrays. No other object can be a + * duk_harray. However, duk_harrays may not always have an array part. + */ + +#if !defined(DUK_HARRAY_H_INCLUDED) +#define DUK_HARRAY_H_INCLUDED + +#define DUK_ASSERT_HARRAY_VALID(h) do { \ + DUK_ASSERT((h) != NULL); \ + DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) (h))); \ + DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY((duk_hobject *) (h))); \ + } while (0) + +#define DUK_HARRAY_LENGTH_WRITABLE(h) (!(h)->length_nonwritable) +#define DUK_HARRAY_LENGTH_NONWRITABLE(h) ((h)->length_nonwritable) +#define DUK_HARRAY_SET_LENGTH_WRITABLE(h) do { (h)->length_nonwritable = 0; } while (0) +#define DUK_HARRAY_SET_LENGTH_NONWRITABLE(h) do { (h)->length_nonwritable = 1; } while (0) + +struct duk_harray { + /* Shared object part. */ + duk_hobject obj; + + /* Array .length. + * + * At present Array .length may be smaller, equal, or even larger + * than the allocated underlying array part. Fast path code must + * always take this into account carefully. + */ + duk_uint32_t length; + + /* Array .length property attributes. The property is always + * non-enumerable and non-configurable. It's initially writable + * but per Object.defineProperty() rules it can be made non-writable + * even if it is non-configurable. Thus we need to track the + * writability explicitly. + * + * XXX: this field to be eliminated and moved into duk_hobject + * flags field to save space. + */ + duk_bool_t length_nonwritable; +}; + +#endif /* DUK_HARRAY_H_INCLUDED */ +/* #include duk_hbuffer.h */ /* * Heap buffer representation. * @@ -6358,7 +7099,7 @@ DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr); * The data pointer for a variable size buffer of zero size may be NULL. */ -#ifndef DUK_HBUFFER_H_INCLUDED +#if !defined(DUK_HBUFFER_H_INCLUDED) #define DUK_HBUFFER_H_INCLUDED /* @@ -6675,7 +7416,7 @@ DUK_INTERNAL_DECL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf); #endif /* DUK_HBUFFER_H_INCLUDED */ -#line 1 "duk_heap.h" +/* #include duk_heap.h */ /* * Heap structure. * @@ -6683,7 +7424,7 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic * * strings for one or more threads. */ -#ifndef DUK_HEAP_H_INCLUDED +#if !defined(DUK_HEAP_H_INCLUDED) #define DUK_HEAP_H_INCLUDED /* alloc function typedefs in duktape.h */ @@ -6698,6 +7439,7 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic * #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_FLAG_DEBUGGER_PAUSED (1 << 6) /* debugger is paused: talk with debug client until step/resume */ #define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits)) #define DUK__HEAP_SET_FLAGS(heap,bits) do { \ @@ -6713,6 +7455,7 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic * #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_HAS_DEBUGGER_PAUSED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED) #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) @@ -6720,6 +7463,7 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic * #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_SET_DEBUGGER_PAUSED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED) #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) @@ -6727,6 +7471,7 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic * #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) +#define DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED) /* * Longjmp types, also double as identifying continuation type for a rethrow (in 'finally') @@ -6785,7 +7530,6 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic * * GC is skipped because there is no thread do it with yet (happens * only during init phases). */ -#if defined(DUK_USE_MARK_AND_SWEEP) #if defined(DUK_USE_REFERENCE_COUNTING) #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 12800L /* 50x heap size */ #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L @@ -6795,7 +7539,6 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic * #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L #endif -#endif /* Stringcache is used for speeding up char-offset-to-byte-offset * translations for non-ASCII strings. @@ -6953,16 +7696,16 @@ struct duk_breakpoint { (heap)->dbg_step_startline = 0; \ } while (0) #define DUK_HEAP_SET_PAUSED(heap) do { \ - (heap)->dbg_paused = 1; \ + DUK_HEAP_SET_DEBUGGER_PAUSED(heap); \ (heap)->dbg_state_dirty = 1; \ DUK_HEAP_CLEAR_STEP_STATE((heap)); \ } while (0) #define DUK_HEAP_CLEAR_PAUSED(heap) do { \ - (heap)->dbg_paused = 0; \ + DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); \ (heap)->dbg_state_dirty = 1; \ DUK_HEAP_CLEAR_STEP_STATE((heap)); \ } while (0) -#define DUK_HEAP_IS_PAUSED(heap) ((heap)->dbg_paused) +#define DUK_HEAP_IS_PAUSED(heap) (DUK_HEAP_HAS_DEBUGGER_PAUSED((heap))) #endif /* DUK_USE_DEBUGGER_SUPPORT */ /* @@ -7029,7 +7772,7 @@ struct duk_heap { duk_free_function free_func; /* Heap udata, used for allocator functions but also for other heap - * level callbacks like pointer compression, etc. + * level callbacks like fatal function, pointer compression, etc. */ void *heap_udata; @@ -7058,7 +7801,6 @@ struct duk_heap { duk_heaphdr *refzero_list_tail; #endif -#if defined(DUK_USE_MARK_AND_SWEEP) /* mark-and-sweep control */ #if defined(DUK_USE_VOLUNTARY_GC) duk_int_t mark_and_sweep_trigger_counter; @@ -7070,7 +7812,6 @@ struct duk_heap { /* work list for objects to be finalized (by mark-and-sweep) */ duk_heaphdr *finalize_list; -#endif /* longjmp state */ duk_ljstate lj; @@ -7095,7 +7836,20 @@ struct duk_heap { duk_uint32_t hash_seed; /* rnd_state for duk_util_tinyrandom.c */ - duk_uint32_t rnd_state; +#if !defined(DUK_USE_GET_RANDOM_DOUBLE) +#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS) + duk_uint32_t rnd_state; /* State for Shamir's three-op algorithm */ +#else + duk_uint64_t rnd_state[2]; /* State for xoroshiro128+ */ +#endif +#endif + + /* counter for unique local symbol creation */ + /* XXX: When 64-bit types are available, it would be more efficient to + * use a duk_uint64_t at least for incrementing but maybe also for + * string formatting in the Symbol constructor. + */ + duk_uint32_t sym_counter[2]; /* For manual debugging: instruction count based on executor and * interrupt counter book-keeping. Inspect debug logs to see how @@ -7121,7 +7875,6 @@ struct duk_heap { /* debugger state, only relevant when attached */ duk_bool_t dbg_processing; /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */ - 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 */ @@ -7190,9 +7943,9 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, void *heap_udata, duk_fatal_function fatal_func); DUK_INTERNAL_DECL void duk_heap_free(duk_heap *heap); -DUK_INTERNAL_DECL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h); -DUK_INTERNAL_DECL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h); -DUK_INTERNAL_DECL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h); +DUK_INTERNAL_DECL void duk_free_hobject(duk_heap *heap, duk_hobject *h); +DUK_INTERNAL_DECL void duk_free_hbuffer(duk_heap *heap, duk_hbuffer *h); +DUK_INTERNAL_DECL void duk_free_hstring(duk_heap *heap, duk_hstring *h); DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr); DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr); @@ -7216,7 +7969,7 @@ DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *t #if defined(DUK_USE_REFERENCE_COUNTING) DUK_INTERNAL_DECL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h); #endif -#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_MS_STRINGTABLE_RESIZE) +#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) DUK_INTERNAL_DECL void duk_heap_force_strtab_resize(duk_heap *heap); #endif DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap); @@ -7224,7 +7977,6 @@ DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap); DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap); #endif - DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h); DUK_INTERNAL_DECL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset); @@ -7240,40 +7992,43 @@ DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize); DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr); -#ifdef DUK_USE_REFERENCE_COUNTING -#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv); -#endif -#if 0 /* unused */ -DUK_INTERNAL_DECL void duk_tval_incref_allownull(duk_tval *tv); +#if defined(DUK_USE_REFERENCE_COUNTING) +DUK_INTERNAL_DECL void duk_refzero_free_pending(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr); +#if 0 /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */ +DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h); +DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h); +DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h); +DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h); +DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h); +DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h); #endif +DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h); +#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) +DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h); /* no 'norz' variant */ +DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h); /* no 'norz' variant */ +DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h); +DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h); +#else +DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv); DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv); -#if 0 /* unused */ -DUK_INTERNAL_DECL void duk_tval_decref_allownull(duk_hthread *thr, duk_tval *tv); -#endif -#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT) +DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv); DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h); -#endif -#if 0 /* unused */ -DUK_INTERNAL_DECL void duk_heaphdr_incref_allownull(duk_heaphdr *h); -#endif DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr); -#else -/* no refcounting */ +DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h); #endif +#else /* DUK_USE_REFERENCE_COUNTING */ +/* no refcounting */ +#endif /* DUK_USE_REFERENCE_COUNTING */ -#if defined(DUK_USE_MARK_AND_SWEEP) DUK_INTERNAL_DECL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags); -#endif DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len); #endif /* DUK_HEAP_H_INCLUDED */ -#line 1 "duk_debugger.h" -#ifndef DUK_DEBUGGER_H_INCLUDED +/* #include duk_debugger.h */ +#if !defined(DUK_DEBUGGER_H_INCLUDED) #define DUK_DEBUGGER_H_INCLUDED /* Debugger protocol version is defined in the public API header. */ @@ -7314,9 +8069,9 @@ DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uin /* Commands and notifys initiated by Duktape. */ #define DUK_DBG_CMD_STATUS 0x01 -#define DUK_DBG_CMD_PRINT 0x02 -#define DUK_DBG_CMD_ALERT 0x03 -#define DUK_DBG_CMD_LOG 0x04 +#define DUK_DBG_CMD_UNUSED_2 0x02 /* Duktape 1.x: print notify */ +#define DUK_DBG_CMD_UNUSED_3 0x03 /* Duktape 1.x: alert notify */ +#define DUK_DBG_CMD_UNUSED_4 0x04 /* Duktape 1.x: log notify */ #define DUK_DBG_CMD_THROW 0x05 #define DUK_DBG_CMD_DETACHING 0x06 #define DUK_DBG_CMD_APPNOTIFY 0x07 @@ -7348,7 +8103,8 @@ DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uin /* The low 8 bits map directly to duk_hobject.h DUK_PROPDESC_FLAG_xxx. * The remaining flags are specific to the debugger. */ -#define DUK_DBG_PROPFLAG_INTERNAL (1 << 8) +#define DUK_DBG_PROPFLAG_SYMBOL (1 << 8) +#define DUK_DBG_PROPFLAG_HIDDEN (1 << 9) #if defined(DUK_USE_DEBUGGER_SUPPORT) DUK_INTERNAL_DECL void duk_debug_do_detach(duk_heap *heap); @@ -7417,7 +8173,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s #endif #endif /* DUK_DEBUGGER_H_INCLUDED */ -#line 1 "duk_debug.h" +/* #include duk_debug.h */ /* * Debugging macros, DUK_DPRINT() and its variants in particular. * @@ -7440,24 +8196,24 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s * works poorly with threading. */ -#ifndef DUK_DEBUG_H_INCLUDED +#if !defined(DUK_DEBUG_H_INCLUDED) #define DUK_DEBUG_H_INCLUDED -#ifdef DUK_USE_DEBUG +#if defined(DUK_USE_DEBUG) -#if defined(DUK_USE_DPRINT) +#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0) #define DUK_D(x) x #else #define DUK_D(x) do { } while (0) /* omit */ #endif -#if defined(DUK_USE_DDPRINT) +#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) #define DUK_DD(x) x #else #define DUK_DD(x) do { } while (0) /* omit */ #endif -#if defined(DUK_USE_DDDPRINT) +#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) #define DUK_DDD(x) x #else #define DUK_DDD(x) do { } while (0) /* omit */ @@ -7467,26 +8223,26 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s * Exposed debug macros: debugging enabled */ -#define DUK_LEVEL_DEBUG 1 -#define DUK_LEVEL_DDEBUG 2 -#define DUK_LEVEL_DDDEBUG 3 - -#ifdef DUK_USE_VARIADIC_MACROS +#if defined(DUK_USE_VARIADIC_MACROS) /* Note: combining __FILE__, __LINE__, and __func__ into fmt would be * possible compile time, but waste some space with shared function names. */ -#define DUK__DEBUG_LOG(lev,...) duk_debug_log((duk_small_int_t) (lev), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, DUK_FUNC_MACRO, __VA_ARGS__); +#define DUK__DEBUG_LOG(lev,...) duk_debug_log((duk_int_t) (lev), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, DUK_FUNC_MACRO, __VA_ARGS__); +#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0) #define DUK_DPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__) +#else +#define DUK_DPRINT(...) +#endif -#ifdef DUK_USE_DDPRINT +#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) #define DUK_DDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__) #else #define DUK_DDPRINT(...) #endif -#ifdef DUK_USE_DDDPRINT +#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) #define DUK_DDDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__) #else #define DUK_DDDPRINT(...) @@ -7496,11 +8252,10 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s #define DUK__DEBUG_STASH(lev) \ (void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FILE_MACRO), \ - duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \ - (void) DUK_SNPRINTF(duk_debug_line_stash, DUK_DEBUG_STASH_SIZE, "%ld", (long) DUK_LINE_MACRO), \ - duk_debug_line_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \ + (void) (duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \ + (void) (duk_debug_line_stash = (duk_int_t) DUK_LINE_MACRO), \ (void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FUNC_MACRO), \ - duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \ + (void) (duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \ (void) (duk_debug_level_stash = (lev)) /* Without variadic macros resort to comma expression trickery to handle debug @@ -7509,19 +8264,19 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s * statement from the compiler. */ -#ifdef DUK_USE_DPRINT +#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0) #define DUK_DPRINT DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log /* args go here in parens */ #else #define DUK_DPRINT 0 && /* args go here as a comma expression in parens */ #endif -#ifdef DUK_USE_DDPRINT +#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) #define DUK_DDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log /* args go here in parens */ #else #define DUK_DDPRINT 0 && /* args */ #endif -#ifdef DUK_USE_DDDPRINT +#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) #define DUK_DDDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log /* args go here in parens */ #else #define DUK_DDDPRINT 0 && /* args */ @@ -7539,7 +8294,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s #define DUK_DD(x) do { } while (0) /* omit */ #define DUK_DDD(x) do { } while (0) /* omit */ -#ifdef DUK_USE_VARIADIC_MACROS +#if defined(DUK_USE_VARIADIC_MACROS) #define DUK_DPRINT(...) #define DUK_DDPRINT(...) @@ -7559,7 +8314,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s * Structs */ -#ifdef DUK_USE_DEBUG +#if defined(DUK_USE_DEBUG) struct duk_fixedbuffer { duk_uint8_t *buffer; duk_size_t length; @@ -7572,23 +8327,23 @@ struct duk_fixedbuffer { * Prototypes */ -#ifdef DUK_USE_DEBUG +#if defined(DUK_USE_DEBUG) DUK_INTERNAL_DECL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap); #if 0 /*unused*/ DUK_INTERNAL_DECL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...); #endif DUK_INTERNAL_DECL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size); -#ifdef DUK_USE_VARIADIC_MACROS -DUK_INTERNAL_DECL void duk_debug_log(duk_small_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...); +#if defined(DUK_USE_VARIADIC_MACROS) +DUK_INTERNAL_DECL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...); #else /* DUK_USE_VARIADIC_MACROS */ /* parameter passing, not thread safe */ #define DUK_DEBUG_STASH_SIZE 128 #if !defined(DUK_SINGLE_FILE) DUK_INTERNAL_DECL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE]; -DUK_INTERNAL_DECL char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE]; +DUK_INTERNAL_DECL duk_int_t duk_debug_line_stash; DUK_INTERNAL_DECL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE]; -DUK_INTERNAL_DECL duk_small_int_t duk_debug_level_stash; +DUK_INTERNAL_DECL duk_int_t duk_debug_level_stash; #endif DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...); #endif /* DUK_USE_VARIADIC_MACROS */ @@ -7603,22 +8358,23 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb); #endif /* DUK_USE_DEBUG */ #endif /* DUK_DEBUG_H_INCLUDED */ -#line 1 "duk_error.h" +/* #include duk_error.h */ /* * Error handling macros, assertion macro, error codes. * - * There are three level of 'errors': + * There are three types of 'errors': * - * 1. Ordinary errors, relative to a thread, cause a longjmp, catchable. - * 2. Fatal errors, relative to a heap, cause fatal handler to be called. - * 3. Panic errors, unrelated to a heap and cause a process exit. + * 1. Ordinary errors relative to a thread, cause a longjmp, catchable. + * 2. Fatal errors relative to a heap, cause fatal handler to be called. + * 3. Fatal errors without context, cause the default (not heap specific) + * fatal handler to be called. * - * Panics are used by the default fatal error handler and by debug code - * such as assertions. By providing a proper fatal error handler, user - * code can avoid panics in non-debug builds. + * Fatal errors without context are used by debug code such as assertions. + * By providing a fatal error handler for a Duktape heap, user code can + * avoid fatal errors without context in non-debug builds. */ -#ifndef DUK_ERROR_H_INCLUDED +#if !defined(DUK_ERROR_H_INCLUDED) #define DUK_ERROR_H_INCLUDED /* @@ -7733,66 +8489,231 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb); #endif /* DUK_USE_VERBOSE_ERRORS */ /* - * Fatal error + * Fatal error without context * - * There are no fatal error macros at the moment. There are so few call - * sites that the fatal error handler is called directly. + * The macro is an expression to make it compatible with DUK_ASSERT_EXPR(). */ +#define DUK_FATAL_WITHOUT_CONTEXT(msg) \ + duk_default_fatal_handler(NULL, (msg)) + /* - * Panic error + * Error throwing helpers * - * Panic errors are not relative to either a heap or a thread, and cause - * DUK_PANIC() macro to be invoked. Unless a user provides DUK_USE_PANIC_HANDLER, - * DUK_PANIC() calls a helper which prints out the error and causes a process - * exit. + * 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. Adding macros here only makes sense if there + * are enough call sites to get concrete benefits. * - * The user can override the macro to provide custom handling. A macro is - * used to allow the user to have inline panic handling if desired (without - * causing a potentially risky function call). + * DUK_ERROR_xxx() macros are generic and can be used anywhere. * - * Panics are only used in debug code such as assertions, and by the default - * fatal error handler. + * DUK_DCERROR_xxx() macros can only be used in Duktape/C functions where + * the "return DUK_RET_xxx;" shorthand is available for low memory targets. + * The DUK_DCERROR_xxx() macros always either throw or perform a + * 'return DUK_RET_xxx' from the calling function. */ -#if defined(DUK_USE_PANIC_HANDLER) -/* already defined, good */ -#define DUK_PANIC(code,msg) DUK_USE_PANIC_HANDLER((code),(msg)) -#else -#define DUK_PANIC(code,msg) duk_default_panic_handler((code),(msg)) -#endif /* DUK_USE_PANIC_HANDLER */ +#if defined(DUK_USE_VERBOSE_ERRORS) +/* Verbose errors with key/value summaries (non-paranoid) or without key/value + * summaries (paranoid, for some security sensitive environments), the paranoid + * vs. non-paranoid distinction affects only a few specific errors. + */ +#if defined(DUK_USE_PARANOID_ERRORS) +#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \ + duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \ + } while (0) +#else /* DUK_USE_PARANOID_ERRORS */ +#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \ + duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \ + } while (0) +#endif /* DUK_USE_PARANOID_ERRORS */ + +#define DUK_ERROR_INTERNAL(thr) do { \ + duk_err_error_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ + } while (0) +#define DUK_ERROR_ALLOC_FAILED(thr) do { \ + duk_err_error_alloc_failed((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ + } while (0) +#define DUK_ERROR_UNSUPPORTED(thr) do { \ + DUK_ERROR((thr), DUK_ERR_ERROR, DUK_STR_UNSUPPORTED); \ + } while (0) +#define DUK_ERROR_ERROR(thr,msg) do { \ + duk_err_error((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \ + } while (0) +#define DUK_ERROR_RANGE_INDEX(thr,idx) do { \ + duk_err_range_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx)); \ + } while (0) +#define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \ + duk_err_range_push_beyond((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ + } while (0) +#define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \ + DUK_ERROR_RANGE((thr), DUK_STR_INVALID_ARGS); \ + } while (0) +#define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \ + DUK_ERROR_RANGE_INVALID_ARGS((thr)); \ + return 0; \ + } while (0) +#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \ + DUK_ERROR_RANGE((thr), DUK_STR_INVALID_COUNT); \ + } while (0) +#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \ + DUK_ERROR_RANGE((thr), DUK_STR_INVALID_LENGTH); \ + } while (0) +#define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \ + DUK_ERROR_RANGE_INVALID_LENGTH((thr)); \ + return 0; \ + } while (0) +#define DUK_ERROR_RANGE(thr,msg) do { \ + duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \ + } while (0) +#define DUK_ERROR_EVAL(thr,msg) do { \ + DUK_ERROR((thr), DUK_ERR_EVAL_ERROR, (msg)); \ + } while (0) +#define DUK_ERROR_REFERENCE(thr,msg) do { \ + DUK_ERROR((thr), DUK_ERR_REFERENCE_ERROR, (msg)); \ + } while (0) +#define DUK_ERROR_SYNTAX(thr,msg) do { \ + DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \ + } while (0) +#define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \ + duk_err_type_invalid_args((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ + } while (0) +#define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \ + DUK_ERROR_TYPE_INVALID_ARGS((thr)); \ + return 0; \ + } while (0) +#define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \ + duk_err_type_invalid_state((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ + } while (0) +#define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \ + DUK_ERROR_TYPE_INVALID_STATE((thr)); \ + return 0; \ + } while (0) +#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \ + duk_err_type_invalid_trap_result((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ + } while (0) +#define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \ + DUK_ERROR_TYPE((thr), DUK_STR_INVALID_TRAP_RESULT); \ + } while (0) +#define DUK_ERROR_TYPE(thr,msg) do { \ + DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \ + } while (0) +#define DUK_ERROR_URI(thr,msg) do { \ + DUK_ERROR((thr), DUK_ERR_URI_ERROR, (msg)); \ + } while (0) +#else /* DUK_USE_VERBOSE_ERRORS */ +/* Non-verbose errors for low memory targets: no file, line, or message. */ + +#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \ + duk_err_type((thr)); \ + } while (0) + +#define DUK_ERROR_INTERNAL(thr) do { \ + duk_err_error((thr)); \ + } while (0) +#define DUK_ERROR_ALLOC_FAILED(thr) do { \ + duk_err_error((thr)); \ + } while (0) +#define DUK_ERROR_UNSUPPORTED(thr) do { \ + duk_err_error((thr)); \ + } while (0) +#define DUK_ERROR_ERROR(thr,msg) do { \ + duk_err_error((thr)); \ + } while (0) +#define DUK_ERROR_RANGE_INDEX(thr,idx) do { \ + duk_err_range((thr)); \ + } while (0) +#define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \ + duk_err_range((thr)); \ + } while (0) +#define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \ + duk_err_range((thr)); \ + } while (0) +#define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \ + DUK_UNREF((thr)); \ + return DUK_RET_RANGE_ERROR; \ + } while (0) +#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \ + duk_err_range((thr)); \ + } while (0) +#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \ + duk_err_range((thr)); \ + } while (0) +#define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \ + DUK_UNREF((thr)); \ + return DUK_RET_RANGE_ERROR; \ + } while (0) +#define DUK_ERROR_RANGE(thr,msg) do { \ + duk_err_range((thr)); \ + } while (0) +#define DUK_ERROR_EVAL(thr,msg) do { \ + duk_err_eval((thr)); \ + } while (0) +#define DUK_ERROR_REFERENCE(thr,msg) do { \ + duk_err_reference((thr)); \ + } while (0) +#define DUK_ERROR_SYNTAX(thr,msg) do { \ + duk_err_syntax((thr)); \ + } while (0) +#define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \ + duk_err_type((thr)); \ + } while (0) +#define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \ + DUK_UNREF((thr)); \ + return DUK_RET_TYPE_ERROR; \ + } while (0) +#define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \ + duk_err_type((thr)); \ + } while (0) +#define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \ + duk_err_type((thr)); \ + } while (0) +#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \ + duk_err_type((thr)); \ + } while (0) +#define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \ + DUK_UNREF((thr)); \ + return DUK_RET_TYPE_ERROR; \ + } while (0) +#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \ + duk_err_type((thr)); \ + } while (0) +#define DUK_ERROR_TYPE(thr,msg) do { \ + duk_err_type((thr)); \ + } while (0) +#define DUK_ERROR_URI(thr,msg) do { \ + duk_err_uri((thr)); \ + } while (0) +#endif /* DUK_USE_VERBOSE_ERRORS */ /* - * Assert macro: failure causes panic. + * Assert macro: failure causes a fatal error. + * + * NOTE: since the assert macro doesn't take a heap/context argument, there's + * no way to look up a heap/context specific fatal error handler which may have + * been given by the application. Instead, assertion failures always use the + * internal default fatal error handler; it can be replaced via duk_config.h + * and then applies to all Duktape heaps. */ #if defined(DUK_USE_ASSERTIONS) -/* the message should be a compile time constant without formatting (less risk); +/* 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 * builds. */ #define DUK_ASSERT(x) do { \ if (!(x)) { \ - DUK_PANIC(DUK_ERR_ASSERTION_ERROR, \ - "assertion failed: " #x \ + DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \ " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"); \ } \ } while (0) -/* Assertion compatible inside a comma expression, evaluates to void. - * Currently not compatible with DUK_USE_PANIC_HANDLER() which may have - * a statement block. - */ -#if defined(DUK_USE_PANIC_HANDLER) -/* XXX: resolve macro definition issue or call through a helper function? */ -#define DUK_ASSERT_EXPR(x) ((void) 0) -#else +/* Assertion compatible inside a comma expression, evaluates to void. */ #define DUK_ASSERT_EXPR(x) \ - ((void) ((x) ? 0 : (DUK_PANIC(DUK_ERR_ASSERTION_ERROR, \ - "assertion failed: " #x \ + ((void) ((x) ? 0 : (DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \ " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"), 0))) -#endif #else /* DUK_USE_ASSERTIONS */ @@ -7837,6 +8758,9 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb); #define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) /* nop */ #endif +#define DUK_ASSERT_VS_SPACE(thr) \ + DUK_ASSERT(thr->valstack_top < thr->valstack_end) + /* * Helper for valstack space * @@ -7857,126 +8781,6 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb); #define DUK_ASSERT_VALSTACK_SPACE(thr,n) /* no valstack space check */ #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. Adding macros here only makes sense if there - * are enough call sites to get concrete benefits. - */ - -#if defined(DUK_USE_VERBOSE_ERRORS) -/* Verbose errors with key/value summaries (non-paranoid) or without key/value - * summaries (paranoid, for some security sensitive environments), the paranoid - * vs. non-paranoid distinction affects only a few specific errors. - */ -#if defined(DUK_USE_PARANOID_ERRORS) -#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \ - duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index), (expectname)); \ - } while (0) -#else /* DUK_USE_PARANOID_ERRORS */ -#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \ - duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index), (expectname)); \ - } while (0) -#endif /* DUK_USE_PARANOID_ERRORS */ - -#define DUK_ERROR_UNIMPLEMENTED(thr,msg) do { \ - DUK_ERROR((thr), DUK_ERR_UNIMPLEMENTED_ERROR, (msg)); \ - } while (0) -#define DUK_ERROR_UNIMPLEMENTED_DEFMSG(thr) do { \ - duk_err_unimplemented_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ - } while (0) -#define DUK_ERROR_UNSUPPORTED(thr,msg) do { \ - DUK_ERROR((thr), DUK_ERR_UNSUPPORTED_ERROR, (msg)); \ - } while (0) -#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT) -#define DUK_ERROR_UNSUPPORTED_DEFMSG(thr) do { \ - duk_err_unsupported_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ - } while (0) -#endif -#define DUK_ERROR_INTERNAL(thr,msg) do { \ - duk_err_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \ - } while (0) -#define DUK_ERROR_INTERNAL_DEFMSG(thr) do { \ - duk_err_internal_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ - } while (0) -#define DUK_ERROR_ALLOC(thr,msg) do { \ - duk_err_alloc((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \ - } while (0) -#define DUK_ERROR_ALLOC_DEFMSG(thr) do { \ - DUK_ERROR_ALLOC((thr), DUK_STR_ALLOC_FAILED); \ - } while (0) -/* DUK_ERR_ASSERTION_ERROR: no macros needed */ -#define DUK_ERROR_API_INDEX(thr,index) do { \ - duk_err_api_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index)); \ - } while (0) -#define DUK_ERROR_API(thr,msg) do { \ - duk_err_api((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \ - } while (0) -/* DUK_ERR_UNCAUGHT_ERROR: no macros needed */ -/* DUK_ERR_ERROR: no macros needed */ -/* DUK_ERR_EVAL: no macros needed */ -#define DUK_ERROR_RANGE(thr,msg) do { \ - duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \ - } while (0) -/* DUK_ERR_REFERENCE_ERROR: no macros needed */ -#define DUK_ERROR_SYNTAX(thr,msg) do { \ - DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \ - } while (0) -#define DUK_ERROR_TYPE(thr,msg) do { \ - DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \ - } while (0) -/* DUK_ERR_URI_ERROR: no macros needed */ -#else /* DUK_USE_VERBOSE_ERRORS */ -/* Non-verbose errors for low memory targets: no file, line, or message. */ - -#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \ - duk_err_type((thr)); \ - } while (0) - -#define DUK_ERROR_UNIMPLEMENTED(thr,msg) do { \ - duk_err_unimplemented((thr)); \ - } while (0) -#define DUK_ERROR_UNIMPLEMENTED_DEFMSG(thr) do { \ - duk_err_unimplemented((thr)); \ - } while (0) -#define DUK_ERROR_UNSUPPORTED(thr,msg) do { \ - duk_err_unsupported((thr)); \ - } while (0) -#define DUK_ERROR_UNSUPPORTED_DEFMSG(thr) do { \ - duk_err_unsupported((thr)); \ - } while (0) -#define DUK_ERROR_INTERNAL(thr,msg) do { \ - duk_err_internal((thr)); \ - } while (0) -#define DUK_ERROR_INTERNAL_DEFMSG(thr) do { \ - duk_err_internal((thr)); \ - } while (0) -#define DUK_ERROR_ALLOC(thr,msg) do { \ - duk_err_alloc((thr)); \ - } while (0) -#define DUK_ERROR_ALLOC_DEFMSG(thr) do { \ - duk_err_alloc((thr)); \ - } while (0) -#define DUK_ERROR_API_INDEX(thr,index) do { \ - duk_err_api((thr)); \ - } while (0) -#define DUK_ERROR_API(thr,msg) do { \ - duk_err_api((thr)); \ - } while (0) -#define DUK_ERROR_RANGE(thr,msg) do { \ - duk_err_range((thr)); \ - } while (0) -#define DUK_ERROR_SYNTAX(thr,msg) do { \ - duk_err_syntax((thr)); \ - } while (0) -#define DUK_ERROR_TYPE(thr,msg) do { \ - duk_err_type((thr)); \ - } while (0) -#endif /* DUK_USE_VERBOSE_ERRORS */ - /* * Prototypes */ @@ -8005,50 +8809,44 @@ DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr); #if defined(DUK_USE_VERBOSE_ERRORS) #if defined(DUK_USE_PARANOID_ERRORS) -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name)); #else -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name)); #endif -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber)); DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unimplemented_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber)); -#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT) -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unsupported_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber)); -#endif -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_alloc(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber)); #else /* DUK_VERBOSE_ERRORS */ +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr)); DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_eval(duk_hthread *thr)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_reference(duk_hthread *thr)); DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_syntax(duk_hthread *thr)); DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type(duk_hthread *thr)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(duk_hthread *thr)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unimplemented(duk_hthread *thr)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unsupported(duk_hthread *thr)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal(duk_hthread *thr)); -DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_alloc(duk_hthread *thr)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_uri(duk_hthread *thr)); #endif /* DUK_VERBOSE_ERRORS */ 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)); - -#if !defined(DUK_USE_PANIC_HANDLER) -DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_panic_handler(duk_errcode_t code, const char *msg)); -#endif +DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(void *udata, const char *msg)); DUK_INTERNAL_DECL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type); DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t err_code); #endif /* DUK_ERROR_H_INCLUDED */ -#line 1 "duk_unicode.h" +/* #include duk_unicode.h */ /* * Unicode helpers */ -#ifndef DUK_UNICODE_H_INCLUDED +#if !defined(DUK_UNICODE_H_INCLUDED) #define DUK_UNICODE_H_INCLUDED /* @@ -8211,25 +9009,34 @@ DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, d #define DUK_ASC_TILDE 0x7e #define DUK_ASC_DEL 0x7f +/* + * Miscellaneous + */ + +/* Uppercase A is 0x41, lowercase a is 0x61; OR 0x20 to convert uppercase + * to lowercase. + */ +#define DUK_LOWERCASE_CHAR_ASCII(x) ((x) | 0x20) + /* * Unicode tables */ -#ifdef DUK_USE_SOURCE_NONBMP +#if defined(DUK_USE_SOURCE_NONBMP) /* * Automatically generated by extract_chars.py, do not edit! */ -extern const duk_uint8_t duk_unicode_ids_noa[791]; +extern const duk_uint8_t duk_unicode_ids_noa[1036]; #else /* * Automatically generated by extract_chars.py, do not edit! */ -extern const duk_uint8_t duk_unicode_ids_noabmp[611]; +extern const duk_uint8_t duk_unicode_ids_noabmp[625]; #endif -#ifdef DUK_USE_SOURCE_NONBMP +#if defined(DUK_USE_SOURCE_NONBMP) /* * Automatically generated by extract_chars.py, do not edit! */ @@ -8243,26 +9050,26 @@ extern const duk_uint8_t duk_unicode_ids_m_let_noa[42]; extern const duk_uint8_t duk_unicode_ids_m_let_noabmp[24]; #endif -#ifdef DUK_USE_SOURCE_NONBMP +#if defined(DUK_USE_SOURCE_NONBMP) /* * Automatically generated by extract_chars.py, do not edit! */ -extern const duk_uint8_t duk_unicode_idp_m_ids_noa[397]; +extern const duk_uint8_t duk_unicode_idp_m_ids_noa[530]; #else /* * Automatically generated by extract_chars.py, do not edit! */ -extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348]; +extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[357]; #endif /* * Automatically generated by extract_caseconv.py, do not edit! */ -extern const duk_uint8_t duk_unicode_caseconv_uc[1288]; -extern const duk_uint8_t duk_unicode_caseconv_lc[616]; +extern const duk_uint8_t duk_unicode_caseconv_uc[1386]; +extern const duk_uint8_t duk_unicode_caseconv_lc[680]; #if defined(DUK_USE_REGEXP_CANON_WORKAROUND) /* @@ -8307,16 +9114,18 @@ DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_ DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp); DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp); DUK_INTERNAL_DECL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase); +#if defined(DUK_USE_REGEXP_SUPPORT) DUK_INTERNAL_DECL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp); DUK_INTERNAL_DECL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp); +#endif #endif /* DUK_UNICODE_H_INCLUDED */ -#line 1 "duk_json.h" +/* #include duk_json.h */ /* * Defines for JSON, especially duk_bi_json.c. */ -#ifndef DUK_JSON_H_INCLUDED +#if !defined(DUK_JSON_H_INCLUDED) #define DUK_JSON_H_INCLUDED /* Encoding/decoding flags */ @@ -8380,12 +9189,12 @@ typedef struct { } duk_json_dec_ctx; #endif /* DUK_JSON_H_INCLUDED */ -#line 1 "duk_js.h" +/* #include duk_js.h */ /* * Ecmascript execution, support primitives. */ -#ifndef DUK_JS_H_INCLUDED +#if !defined(DUK_JS_H_INCLUDED) #define DUK_JS_H_INCLUDED /* Flags for call handling. */ @@ -8400,8 +9209,8 @@ typedef struct { #define DUK_EQUALS_FLAG_STRICT (1 << 1) /* use strict equality instead of non-strict equality */ /* Flags for duk_js_compare_helper(). */ -#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1 << 0) /* eval left argument first */ -#define DUK_COMPARE_FLAG_NEGATE (1 << 1) /* negate result */ +#define DUK_COMPARE_FLAG_NEGATE (1 << 0) /* negate result */ +#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1 << 1) /* eval left argument first */ /* conversions, coercions, comparison, etc */ DUK_INTERNAL_DECL duk_bool_t duk_js_toboolean(duk_tval *tv); @@ -8422,7 +9231,11 @@ DUK_INTERNAL_DECL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuf DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags); DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y); DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y); -DUK_INTERNAL_DECL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x); +DUK_INTERNAL_DECL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x); + +/* arithmetic */ +DUK_INTERNAL_DECL double duk_js_arith_pow(double x, double y); +DUK_INTERNAL_DECL double duk_js_arith_mod(double x, double y); #define duk_js_equals(thr,tv_x,tv_y) \ duk_js_equals_helper((thr), (tv_x), (tv_y), 0) @@ -8465,7 +9278,7 @@ DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hob DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom); DUK_INTERNAL_DECL void duk_js_push_closure(duk_hthread *thr, - duk_hcompiledfunction *fun_temp, + duk_hcompfunc *fun_temp, duk_hobject *outer_var_env, duk_hobject *outer_lex_env, duk_bool_t add_auto_proto); @@ -8473,22 +9286,22 @@ void duk_js_push_closure(duk_hthread *thr, /* call handling */ DUK_INTERNAL_DECL duk_int_t duk_handle_call_protected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags); DUK_INTERNAL_DECL void duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags); -DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call(duk_hthread *thr, duk_safe_call_function func, duk_idx_t num_stack_args, duk_idx_t num_stack_res); +DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call(duk_hthread *thr, duk_safe_call_function func, void *udata, duk_idx_t num_stack_args, duk_idx_t num_stack_res); DUK_INTERNAL_DECL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags); /* bytecode execution */ DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr); #endif /* DUK_JS_H_INCLUDED */ -#line 1 "duk_numconv.h" -#ifndef DUK_NUMCONV_H_INCLUDED -#define DUK_NUMCONV_H_INCLUDED - +/* #include duk_numconv.h */ /* * Number-to-string conversion. The semantics of these is very tightly * bound with the Ecmascript semantics required for call sites. */ +#if !defined(DUK_NUMCONV_H_INCLUDED) +#define DUK_NUMCONV_H_INCLUDED + /* Output a specified number of digits instead of using the shortest * form. Used for toPrecision() and toFixed(). */ @@ -8558,10 +9371,20 @@ DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr); */ #define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT (1 << 11) -/* Allow automatic detection of octal base, overrides radix - * argument and forces integer mode. +/* Allow automatic detection of legacy octal base ("0n"), + * overrides radix argument and forces integer mode. + */ +#define DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT (1 << 12) + +/* Allow automatic detection of ES2015 octal base ("0o123"), + * overrides radix argument and forces integer mode. + */ +#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1 << 13) + +/* Allow automatic detection of ES2015 binary base ("0b10001"), + * overrides radix argument and forces integer mode. */ -#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1 << 12) +#define DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT (1 << 14) /* * Prototypes @@ -8571,33 +9394,26 @@ DUK_INTERNAL_DECL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t r DUK_INTERNAL_DECL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags); #endif /* DUK_NUMCONV_H_INCLUDED */ -#line 1 "duk_bi_protos.h" +/* #include duk_bi_protos.h */ /* * Prototypes for built-in functions not automatically covered by the * header declarations emitted by genbuiltins.py. */ -#ifndef DUK_BUILTIN_PROTOS_H_INCLUDED +#if !defined(DUK_BUILTIN_PROTOS_H_INCLUDED) #define DUK_BUILTIN_PROTOS_H_INCLUDED -/* Buffer size needed for duk_bi_date_format_timeval(). +/* Buffer size needed for ISO 8601 formatting. * Accurate value is 32 + 1 for NUL termination: * >>> len('+123456-01-23T12:34:56.123+12:34') * 32 * Include additional space to be safe. */ -#define DUK_BI_DATE_ISO8601_BUFSIZE 48 - -/* Maximum length of CommonJS module identifier to resolve. Length includes - * both current module ID, requested (possibly relative) module ID, and a - * slash in between. - */ -#define DUK_BI_COMMONJS_MODULE_ID_LIMIT 256 +#define DUK_BI_DATE_ISO8601_BUFSIZE 40 /* Helpers exposed for internal use */ DUK_INTERNAL_DECL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags); DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags); -DUK_INTERNAL_DECL void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t *out_buf); 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); @@ -8612,7 +9428,7 @@ DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(duk_context *ctx); #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) +#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || 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) @@ -8640,33 +9456,31 @@ void duk_bi_json_stringify_helper(duk_context *ctx, duk_idx_t idx_space, duk_small_uint_t flags); +DUK_INTERNAL_DECL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_context *ctx); + +#if defined(DUK_USE_ES6_PROXY) +DUK_INTERNAL_DECL void duk_proxy_ownkeys_postprocess(duk_context *ctx, duk_hobject *h_proxy_target, duk_uint_t flags); +#endif + #endif /* DUK_BUILTIN_PROTOS_H_INCLUDED */ -#line 1 "duk_selftest.h" +/* #include duk_selftest.h */ /* * Selftest code */ -#ifndef DUK_SELFTEST_H_INCLUDED +#if !defined(DUK_SELFTEST_H_INCLUDED) #define DUK_SELFTEST_H_INCLUDED #if defined(DUK_USE_SELF_TESTS) -DUK_INTERNAL_DECL void duk_selftest_run_tests(void); +DUK_INTERNAL_DECL duk_uint_t duk_selftest_run_tests(duk_alloc_function alloc_func, + duk_realloc_function realloc_func, + duk_free_function free_func, + void *udata); #endif #endif /* DUK_SELFTEST_H_INCLUDED */ -#line 78 "duk_internal.h" #endif /* DUK_INTERNAL_H_INCLUDED */ -#line 1 "duk_replacements.c" -/* - * Replacements for missing platform functions. - * - * Unlike the originals, fpclassify() and signbit() replacements don't - * work on any floating point types, only doubles. The C typing here - * mimics the standard prototypes. - */ - -/* include removed: duk_internal.h */ #if defined(DUK_USE_COMPUTED_NAN) DUK_INTERNAL double duk_computed_nan; @@ -8740,130 +9554,13 @@ DUK_INTERNAL int duk_repl_isinf(double x) { return (c == DUK_FP_INFINITE); } #endif -#line 1 "duk_strings.c" -/* - * Shared error message strings - * - * To minimize code footprint, try to share error messages inside Duktape - * code. Modern compilers will do this automatically anyway, this is mostly - * for older compilers. - */ - -/* include removed: duk_internal.h */ - -/* Mostly API and built-in method related */ -DUK_INTERNAL const char *duk_str_internal_error = "internal error"; -DUK_INTERNAL const char *duk_str_invalid_count = "invalid count"; -DUK_INTERNAL const char *duk_str_invalid_call_args = "invalid call args"; -DUK_INTERNAL const char *duk_str_not_constructable = "not constructable"; -DUK_INTERNAL const char *duk_str_not_callable = "not callable"; -DUK_INTERNAL const char *duk_str_not_extensible = "not extensible"; -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_push_beyond_alloc_stack = "attempt to push beyond currently allocated stack"; -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_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"; -DUK_INTERNAL const char *duk_str_string_too_long = "string too long"; -DUK_INTERNAL const char *duk_str_buffer_too_long = "buffer too long"; -DUK_INTERNAL const char *duk_str_sprintf_too_long = "sprintf message too long"; -DUK_INTERNAL const char *duk_str_alloc_failed = "alloc failed"; -DUK_INTERNAL const char *duk_str_pop_too_many = "attempt to pop too many entries"; -DUK_INTERNAL const char *duk_str_wrong_buffer_type = "wrong buffer type"; -DUK_INTERNAL const char *duk_str_encode_failed = "encode failed"; -DUK_INTERNAL const char *duk_str_decode_failed = "decode failed"; -DUK_INTERNAL const char *duk_str_no_sourcecode = "no sourcecode"; -DUK_INTERNAL const char *duk_str_concat_result_too_long = "concat result too long"; -DUK_INTERNAL const char *duk_str_unimplemented = "unimplemented"; -DUK_INTERNAL const char *duk_str_unsupported = "unsupported"; -DUK_INTERNAL const char *duk_str_array_length_over_2g = "array length over 2G"; - -/* JSON */ -DUK_INTERNAL const char *duk_str_fmt_ptr = "%p"; -DUK_INTERNAL const char *duk_str_fmt_invalid_json = "invalid json (at offset %ld)"; -DUK_INTERNAL const char *duk_str_jsondec_reclimit = "json decode recursion limit"; -DUK_INTERNAL const char *duk_str_jsonenc_reclimit = "json encode recursion limit"; -DUK_INTERNAL const char *duk_str_cyclic_input = "cyclic input"; - -/* Object property access */ -DUK_INTERNAL const char *duk_str_proxy_revoked = "proxy revoked"; -DUK_INTERNAL const char *duk_str_invalid_base = "invalid base value"; -DUK_INTERNAL const char *duk_str_strict_caller_read = "attempt to read strict 'caller'"; -DUK_INTERNAL const char *duk_str_proxy_rejected = "proxy rejected"; -DUK_INTERNAL const char *duk_str_invalid_array_length = "invalid array length"; -DUK_INTERNAL const char *duk_str_array_length_write_failed = "array length write failed"; -DUK_INTERNAL const char *duk_str_array_length_not_writable = "array length non-writable"; -DUK_INTERNAL const char *duk_str_setter_undefined = "setter undefined"; -DUK_INTERNAL const char *duk_str_redefine_virt_prop = "attempt to redefine virtual property"; -DUK_INTERNAL const char *duk_str_invalid_descriptor = "invalid descriptor"; -DUK_INTERNAL const char *duk_str_property_is_virtual = "property is virtual"; - -/* Compiler */ -DUK_INTERNAL const char *duk_str_parse_error = "parse error"; -DUK_INTERNAL const char *duk_str_duplicate_label = "duplicate label"; -DUK_INTERNAL const char *duk_str_invalid_label = "invalid label"; -DUK_INTERNAL const char *duk_str_invalid_array_literal = "invalid array literal"; -DUK_INTERNAL const char *duk_str_invalid_object_literal = "invalid object literal"; -DUK_INTERNAL const char *duk_str_invalid_var_declaration = "invalid variable declaration"; -DUK_INTERNAL const char *duk_str_cannot_delete_identifier = "cannot delete identifier"; -DUK_INTERNAL const char *duk_str_invalid_expression = "invalid expression"; -DUK_INTERNAL const char *duk_str_invalid_lvalue = "invalid lvalue"; -DUK_INTERNAL const char *duk_str_expected_identifier = "expected identifier"; -DUK_INTERNAL const char *duk_str_empty_expr_not_allowed = "empty expression not allowed"; -DUK_INTERNAL const char *duk_str_invalid_for = "invalid for statement"; -DUK_INTERNAL const char *duk_str_invalid_switch = "invalid switch statement"; -DUK_INTERNAL const char *duk_str_invalid_break_cont_label = "invalid break/continue label"; -DUK_INTERNAL const char *duk_str_invalid_return = "invalid return"; -DUK_INTERNAL const char *duk_str_invalid_try = "invalid try"; -DUK_INTERNAL const char *duk_str_invalid_throw = "invalid throw"; -DUK_INTERNAL const char *duk_str_with_in_strict_mode = "with in strict mode"; -DUK_INTERNAL const char *duk_str_func_stmt_not_allowed = "function statement not allowed"; -DUK_INTERNAL const char *duk_str_unterminated_stmt = "unterminated statement"; -DUK_INTERNAL const char *duk_str_invalid_arg_name = "invalid argument name"; -DUK_INTERNAL const char *duk_str_invalid_func_name = "invalid function name"; -DUK_INTERNAL const char *duk_str_invalid_getset_name = "invalid getter/setter name"; -DUK_INTERNAL const char *duk_str_func_name_required = "function name required"; - -/* Regexp */ -DUK_INTERNAL const char *duk_str_invalid_quantifier_no_atom = "quantifier without preceding atom"; -DUK_INTERNAL const char *duk_str_invalid_quantifier_values = "quantifier values invalid (qmin > qmax)"; -DUK_INTERNAL const char *duk_str_quantifier_too_many_copies = "quantifier expansion requires too many atom copies"; -DUK_INTERNAL const char *duk_str_unexpected_closing_paren = "unexpected closing parenthesis"; -DUK_INTERNAL const char *duk_str_unexpected_end_of_pattern = "unexpected end of pattern"; -DUK_INTERNAL const char *duk_str_unexpected_regexp_token = "unexpected token in regexp"; -DUK_INTERNAL const char *duk_str_invalid_regexp_flags = "invalid regexp flags"; -DUK_INTERNAL const char *duk_str_invalid_backrefs = "invalid backreference(s)"; - -/* Limits */ -DUK_INTERNAL const char *duk_str_valstack_limit = "valstack limit"; -DUK_INTERNAL const char *duk_str_callstack_limit = "callstack limit"; -DUK_INTERNAL const char *duk_str_catchstack_limit = "catchstack limit"; -DUK_INTERNAL const char *duk_str_prototype_chain_limit = "prototype chain limit"; -DUK_INTERNAL const char *duk_str_bound_chain_limit = "function call bound chain limit"; -DUK_INTERNAL const char *duk_str_c_callstack_limit = "C call stack depth limit"; -DUK_INTERNAL const char *duk_str_compiler_recursion_limit = "compiler recursion limit"; -DUK_INTERNAL const char *duk_str_bytecode_limit = "bytecode limit"; -DUK_INTERNAL const char *duk_str_reg_limit = "register limit"; -DUK_INTERNAL const char *duk_str_temp_limit = "temp limit"; -DUK_INTERNAL const char *duk_str_const_limit = "const limit"; -DUK_INTERNAL const char *duk_str_func_limit = "function limit"; -DUK_INTERNAL const char *duk_str_regexp_compiler_recursion_limit = "regexp compiler recursion limit"; -DUK_INTERNAL const char *duk_str_regexp_executor_recursion_limit = "regexp executor recursion limit"; -DUK_INTERNAL const char *duk_str_regexp_executor_step_limit = "regexp step limit"; - -/* Misc */ -#line 1 "duk_debug_macros.c" /* * Debugging macro calls. */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ -#ifdef DUK_USE_DEBUG +#if defined(DUK_USE_DEBUG) /* * Debugging enabled @@ -8873,91 +9570,34 @@ DUK_INTERNAL const char *duk_str_regexp_executor_step_limit = "regexp step limit #include #include -#define DUK__DEBUG_BUFSIZE DUK_USE_DEBUG_BUFSIZE -DUK_LOCAL char duk__debug_buf[DUK__DEBUG_BUFSIZE]; - -DUK_LOCAL const char *duk__get_level_string(duk_small_int_t level) { - switch ((int) level) { - case DUK_LEVEL_DEBUG: - return "D"; - case DUK_LEVEL_DDEBUG: - return "DD"; - case DUK_LEVEL_DDDEBUG: - return "DDD"; - } - return "???"; -} - -#ifdef DUK_USE_DPRINT_COLORS - -/* http://en.wikipedia.org/wiki/ANSI_escape_code */ -#define DUK__TERM_REVERSE "\x1b[7m" -#define DUK__TERM_BRIGHT "\x1b[1m" -#define DUK__TERM_RESET "\x1b[0m" -#define DUK__TERM_BLUE "\x1b[34m" -#define DUK__TERM_RED "\x1b[31m" - -DUK_LOCAL const char *duk__get_term_1(duk_small_int_t level) { - DUK_UNREF(level); - return (const char *) DUK__TERM_RED; -} - -DUK_LOCAL const char *duk__get_term_2(duk_small_int_t level) { - switch ((int) level) { - case DUK_LEVEL_DEBUG: - return (const char *) (DUK__TERM_RESET DUK__TERM_BRIGHT); - case DUK_LEVEL_DDEBUG: - return (const char *) (DUK__TERM_RESET); - case DUK_LEVEL_DDDEBUG: - return (const char *) (DUK__TERM_RESET DUK__TERM_BLUE); - } - return (const char *) DUK__TERM_RESET; -} - -DUK_LOCAL const char *duk__get_term_3(duk_small_int_t level) { - DUK_UNREF(level); - return (const char *) DUK__TERM_RESET; -} - -#else - -DUK_LOCAL const char *duk__get_term_1(duk_small_int_t level) { - DUK_UNREF(level); - return (const char *) ""; -} - -DUK_LOCAL const char *duk__get_term_2(duk_small_int_t level) { - DUK_UNREF(level); - return (const char *) ""; -} - -DUK_LOCAL const char *duk__get_term_3(duk_small_int_t level) { - DUK_UNREF(level); - return (const char *) ""; -} +#if !defined(DUK_USE_DEBUG_WRITE) +#error debugging enabled (DUK_USE_DEBUG) but DUK_USE_DEBUG_WRITE not defined +#endif -#endif /* DUK_USE_DPRINT_COLORS */ +#define DUK__DEBUG_BUFSIZE DUK_USE_DEBUG_BUFSIZE -#ifdef DUK_USE_VARIADIC_MACROS +#if defined(DUK_USE_VARIADIC_MACROS) -DUK_INTERNAL void duk_debug_log(duk_small_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) { +DUK_INTERNAL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) { va_list ap; + long arg_level; + const char *arg_file; + long arg_line; + const char *arg_func; + const char *arg_msg; + char buf[DUK__DEBUG_BUFSIZE]; va_start(ap, fmt); - DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE); - duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap); + DUK_MEMZERO((void *) buf, (size_t) DUK__DEBUG_BUFSIZE); + duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap); - 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), - (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)); - DUK_FFLUSH(DUK_STDERR); + arg_level = (long) level; + arg_file = (const char *) file; + arg_line = (long) line; + arg_func = (const char *) func; + arg_msg = (const char *) buf; + DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg); va_end(ap); } @@ -8965,29 +9605,30 @@ DUK_INTERNAL void duk_debug_log(duk_small_int_t level, const char *file, duk_int #else /* DUK_USE_VARIADIC_MACROS */ DUK_INTERNAL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE]; -DUK_INTERNAL char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE]; +DUK_INTERNAL duk_int_t duk_debug_line_stash; DUK_INTERNAL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE]; -DUK_INTERNAL duk_small_int_t duk_debug_level_stash; +DUK_INTERNAL duk_int_t duk_debug_level_stash; DUK_INTERNAL void duk_debug_log(const char *fmt, ...) { va_list ap; - duk_small_int_t level = duk_debug_level_stash; + long arg_level; + const char *arg_file; + long arg_line; + const char *arg_func; + const char *arg_msg; + char buf[DUK__DEBUG_BUFSIZE]; va_start(ap, fmt); - DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE); - duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap); + DUK_MEMZERO((void *) buf, (size_t) DUK__DEBUG_BUFSIZE); + duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap); - 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), - (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)); - DUK_FFLUSH(DUK_STDERR); + arg_level = (long) duk_debug_level_stash; + arg_file = (const char *) duk_debug_file_stash; + arg_line = (long) duk_debug_line_stash; + arg_func = (const char *) duk_debug_func_stash; + arg_msg = (const char *) buf; + DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg); va_end(ap); } @@ -9001,75 +9642,72 @@ DUK_INTERNAL void duk_debug_log(const char *fmt, ...) { */ #endif /* DUK_USE_DEBUG */ -#line 1 "duk_builtins.c" + +/* automatic undefs */ +#undef DUK__DEBUG_BUFSIZE /* * Automatically generated by genbuiltins.py, do not edit! */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ #if defined(DUK_USE_ROM_STRINGS) -#error ROM support not enabled, rerun make_dist.py with --rom-support +#error ROM support not enabled, rerun configure.py with --rom-support #else /* DUK_USE_ROM_STRINGS */ -DUK_INTERNAL const duk_uint8_t duk_strings_data[1049] = { -79,104,209,144,168,105,6,78,182,139,90,122,8,154,140,35,103,35,117,193,73, -5,52,116,180,104,166,135,52,189,4,98,12,27,178,156,80,211,31,161,115,150, -64,52,221,109,24,18,68,157,24,38,67,118,36,55,73,119,151,164,140,93,18,117, -128,153,201,228,201,205,2,250,8,196,24,232,104,82,146,40,232,193,48,118, -168,37,147,212,54,127,113,208,70,32,194,187,68,54,127,113,208,70,32,196, -123,68,54,127,113,209,44,12,121,7,208,70,32,194,186,134,207,236,126,219, -160,140,65,133,246,136,108,254,199,237,186,8,196,24,87,80,217,253,159,217, -116,17,136,48,190,209,13,159,217,253,151,65,24,131,12,233,86,224,79,236, -254,203,160,140,65,134,116,171,112,39,246,223,105,208,70,32,193,140,183,4, -11,55,92,20,244,141,169,186,50,11,164,109,77,208,208,165,36,79,215,185,13, -153,34,110,204,241,32,6,66,84,11,112,200,84,52,157,124,92,242,70,120,45,64, -186,17,22,138,38,0,172,140,19,154,84,26,145,0,86,69,17,180,97,34,0,172,132, -75,144,215,77,221,91,132,5,147,178,156,80,211,30,160,93,9,215,21,115,119, -169,49,75,211,138,26,101,205,222,68,157,47,78,40,105,151,55,120,204,156, -189,56,161,166,52,157,72,136,138,65,154,232,147,162,4,136,150,81,115,66, -208,210,37,96,148,250,134,140,151,39,212,125,255,221,125,73,80,209,146,233, -124,93,55,79,15,34,196,230,202,113,160,166,232,157,132,148,128,98,28,46, -114,200,6,153,180,96,73,19,74,113,67,76,103,5,36,20,211,70,140,133,67,72, -49,245,160,235,81,212,52,168,106,39,132,253,111,80,210,161,168,158,5,245, -191,96,31,172,15,208,23,226,190,131,232,62,131,232,11,251,127,93,245,223, -93,251,172,234,27,80,45,3,250,14,140,19,34,65,19,81,132,108,228,97,1,107, -33,12,32,45,100,136,206,9,12,196,155,134,69,146,100,235,226,231,146,51,194, -72,218,48,145,4,200,119,89,189,81,49,39,72,147,235,226,233,186,120,121,58, -226,167,90,124,93,55,107,71,137,33,68,68,130,64,206,75,189,209,156,144,84, -44,141,3,8,137,187,178,156,80,211,26,110,242,100,230,146,120,121,8,48,76,6, -89,26,105,157,65,196,201,213,145,166,153,212,28,76,157,113,75,34,78,62,14, -38,73,105,228,142,136,178,48,141,152,228,73,150,83,0,148,39,137,75,67,73, -214,209,129,36,85,190,206,32,17,6,9,128,141,3,8,130,161,100,235,64,194,24, -52,41,73,19,189,200,108,201,19,111,181,2,232,66,239,173,37,230,157,244,56, -153,4,225,145,27,233,93,22,1,114,62,251,80,69,128,121,247,213,146,228,109, -79,190,212,17,35,106,125,246,78,164,68,68,111,175,23,217,45,13,33,119,208, -68,210,38,250,192,61,91,233,80,208,45,25,36,81,190,156,13,26,201,19,239, -162,2,214,66,31,125,153,226,64,13,27,236,72,96,130,68,62,251,48,68,196,153, -119,217,157,18,56,156,199,161,100,42,26,250,77,36,140,122,40,144,19,34,9, -24,246,103,139,172,150,56,125,145,1,17,29,44,112,250,183,0,100,24,200,218, -140,228,185,130,9,19,237,190,208,73,184,146,35,68,146,163,8,50,178,99,136, -44,89,196,2,33,70,64,208,196,67,74,226,88,17,105,73,24,186,37,40,38,5,133, -161,89,4,183,25,115,119,86,227,118,83,138,26,103,255,223,209,106,141,25,11, -244,95,117,56,208,159,250,223,251,250,45,52,13,250,47,186,156,104,79,253, -111,253,253,22,144,210,253,23,221,78,52,39,254,187,254,254,139,77,67,75, -244,95,117,56,208,159,250,239,251,250,45,22,141,23,209,125,212,227,66,127, -235,63,239,69,163,69,247,83,141,9,255,165,12,72,5,16,64,145,10,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,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, +DUK_INTERNAL const duk_uint8_t duk_strings_data[921] = { +79,40,209,144,168,105,6,78,54,139,89,185,44,48,46,90,120,8,154,140,35,103, +35,113,193,73,5,52,112,180,104,166,135,52,188,4,98,12,27,146,156,80,211,31, +129,115,150,64,52,220,109,24,18,68,156,24,38,67,114,36,55,9,119,151,132, +140,93,18,113,128,153,201,212,201,205,2,248,8,196,24,224,104,82,146,40,224, +193,48,114,168,37,147,196,54,123,28,4,98,12,43,148,67,103,177,192,70,32, +196,121,68,54,123,28,18,192,199,144,124,4,98,12,43,136,108,244,117,184,8, +196,24,95,40,134,207,71,91,128,140,65,133,113,13,158,158,151,1,24,131,11, +229,16,217,233,233,112,17,136,48,206,21,110,4,244,244,184,8,196,24,103,10, +183,2,122,218,156,4,98,12,24,203,112,64,179,113,193,79,8,218,155,131,32, +184,70,212,220,13,10,82,68,252,123,144,217,146,38,228,207,18,0,100,37,64, +178,212,11,161,17,104,162,96,10,200,193,57,165,65,169,16,5,100,81,27,70,18, +32,10,200,68,185,13,116,221,197,184,64,89,57,41,197,13,49,234,5,208,156, +113,87,55,118,147,20,187,56,161,166,92,221,212,73,210,236,226,134,153,115, +119,76,201,203,179,138,26,99,73,212,136,136,164,25,174,137,56,32,72,137, +101,23,52,45,13,34,86,9,79,136,104,201,114,149,96,52,138,134,140,151,75, +226,233,186,120,121,22,39,54,83,141,5,55,68,236,36,164,3,16,225,115,150,64, +52,205,163,2,72,154,83,138,26,99,75,12,11,150,103,5,36,20,211,70,140,133, +67,72,49,241,160,227,81,196,52,168,106,39,132,252,183,136,105,80,212,79,2, +249,110,128,126,88,95,133,109,237,237,237,151,235,127,46,249,119,203,190, +186,206,33,181,2,208,61,190,12,19,34,65,19,81,132,108,228,97,1,107,33,12, +32,45,100,139,134,69,146,100,227,226,231,146,51,192,204,73,140,224,145,221, +102,241,68,196,157,34,79,143,139,166,233,225,228,227,138,157,173,167,197, +211,118,214,210,38,238,74,113,67,76,105,187,169,147,154,73,225,228,32,193, +48,25,100,105,166,113,200,147,44,166,1,40,79,18,150,134,147,141,163,2,72, +171,115,147,136,4,65,130,96,35,64,194,32,168,89,56,208,48,135,123,144,217, +146,38,220,229,64,186,16,187,156,105,47,52,238,112,56,153,4,225,145,27,156, +43,162,192,46,71,220,229,65,22,1,231,220,228,157,72,136,136,220,227,197, +164,180,52,133,220,224,34,105,19,115,140,3,207,185,202,130,36,109,85,185, +194,161,160,90,50,72,163,115,135,3,70,178,68,251,156,16,22,178,16,251,156, +153,226,64,13,27,156,137,12,16,72,135,220,228,193,19,18,101,220,228,206, +137,28,78,99,208,178,21,13,125,38,146,70,60,20,72,9,145,4,140,121,51,197, +214,25,27,81,156,151,48,65,34,107,106,9,55,18,68,104,146,84,97,31,191,189, +181,70,140,133,222,249,212,227,66,125,245,187,251,219,77,3,119,190,117,56, +208,159,125,110,254,246,210,26,93,239,157,78,52,39,223,93,191,189,180,212, +52,187,223,58,156,104,79,190,187,127,123,104,180,104,183,190,117,56,208, +159,125,102,254,209,104,209,124,234,113,161,62,250,80,196,128,81,4,9,16, +162,4,196,116,9,205,154,27,66,32,100,13,12,98,68,227,33,65,69,204,195,34, +201,50,8,110,33,23,34,28,168,104,22,188,12,174,138,11,70,138,104,115,68, +130,137,13,82,27,41,129,162,35,138,54,146,198,137,39,72,180,210,178,38,35, +146,103,68,139,51,197,214,28,227,131,79,15,35,138,58,130,37,19,155,41,146, +174,64,203,99,161,100,37,145,51,148,75,4,164,66,54,140,49,46,247,70,103,37, +230,70,142,70,67,30,232,204,178,163,201,18,54,139,89,39,26,16,165,2,228,69, +33,143,89,24,70,206,73,67,102,72,148,2,32,214,73,157,224,18,128,98,29,241, +69,65,50,37,241,116,200,41,144,102,125,2,180,8,210,152,38,129,23,8,34,198, }; #endif /* DUK_USE_ROM_STRINGS */ #if defined(DUK_USE_ROM_OBJECTS) -#error ROM support not enabled, rerun make_dist.py with --rom-support +#error ROM support not enabled, rerun configure.py with --rom-support #else /* DUK_USE_ROM_OBJECTS */ -/* native functions: 149 */ -DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = { +/* native functions: 164 */ +DUK_INTERNAL const duk_c_function duk_bi_native_functions[164] = { + NULL, duk_bi_array_constructor, duk_bi_array_constructor_is_array, duk_bi_array_prototype_concat, @@ -9091,8 +9729,6 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = { duk_bi_boolean_constructor, duk_bi_boolean_prototype_tostring_shared, duk_bi_buffer_compare_shared, - duk_bi_buffer_constructor, - duk_bi_buffer_prototype_tostring_shared, duk_bi_buffer_readfield, duk_bi_buffer_slice_shared, duk_bi_buffer_writefield, @@ -9139,15 +9775,10 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = { duk_bi_global_object_is_nan, duk_bi_global_object_parse_float, duk_bi_global_object_parse_int, - duk_bi_global_object_print_helper, - duk_bi_global_object_require, duk_bi_global_object_unescape, duk_bi_json_object_parse, duk_bi_json_object_stringify, - duk_bi_logger_constructor, - duk_bi_logger_prototype_fmt, - duk_bi_logger_prototype_log_shared, - duk_bi_logger_prototype_raw, + duk_bi_math_object_hypot, duk_bi_math_object_max, duk_bi_math_object_min, duk_bi_math_object_onearg_shared, @@ -9171,10 +9802,12 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = { duk_bi_number_prototype_to_string, duk_bi_number_prototype_value_of, duk_bi_object_constructor, + duk_bi_object_constructor_assign, duk_bi_object_constructor_create, duk_bi_object_constructor_define_properties, duk_bi_object_constructor_define_property, duk_bi_object_constructor_get_own_property_descriptor, + duk_bi_object_constructor_is, duk_bi_object_constructor_is_extensible, duk_bi_object_constructor_is_sealed_frozen_shared, duk_bi_object_constructor_keys_shared, @@ -9191,12 +9824,19 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = { duk_bi_pointer_constructor, duk_bi_pointer_prototype_tostring_shared, duk_bi_proxy_constructor, + duk_bi_reflect_object_delete_property, + duk_bi_reflect_object_get, + duk_bi_reflect_object_has, + duk_bi_reflect_object_set, duk_bi_regexp_constructor, duk_bi_regexp_prototype_exec, + duk_bi_regexp_prototype_flags, + duk_bi_regexp_prototype_shared_getter, duk_bi_regexp_prototype_test, - duk_bi_regexp_prototype_to_string, + duk_bi_regexp_prototype_tostring, duk_bi_string_constructor, duk_bi_string_constructor_from_char_code, + duk_bi_string_constructor_from_code_point, duk_bi_string_prototype_caseconv_shared, duk_bi_string_prototype_char_at, duk_bi_string_prototype_char_code_at, @@ -9204,6 +9844,7 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = { duk_bi_string_prototype_indexof_shared, duk_bi_string_prototype_locale_compare, duk_bi_string_prototype_match, + duk_bi_string_prototype_repeat, duk_bi_string_prototype_replace, duk_bi_string_prototype_search, duk_bi_string_prototype_slice, @@ -9212,578 +9853,565 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = { duk_bi_string_prototype_substring, duk_bi_string_prototype_to_string, duk_bi_string_prototype_trim, + duk_bi_textdecoder_constructor, + duk_bi_textdecoder_prototype_decode, + duk_bi_textdecoder_prototype_shared_getter, + duk_bi_textencoder_constructor, + duk_bi_textencoder_prototype_encode, + duk_bi_textencoder_prototype_encoding_getter, duk_bi_thread_constructor, duk_bi_thread_current, duk_bi_thread_resume, duk_bi_thread_yield, duk_bi_type_error_thrower, + duk_bi_typedarray_buffer_getter, + duk_bi_typedarray_bytelength_getter, + duk_bi_typedarray_byteoffset_getter, duk_bi_typedarray_constructor, duk_bi_typedarray_set, + duk_bi_uint8array_allocplain, + duk_bi_uint8array_plainof, }; -#if defined(DUK_USE_BUILTIN_INITJS) -DUK_INTERNAL const duk_uint8_t duk_initjs_data[204] = { -40,102,117,110,99,116,105,111,110,40,100,44,97,41,123,102,117,110,99,116, -105,111,110,32,98,40,97,44,98,44,99,41,123,79,98,106,101,99,116,46,100,101, -102,105,110,101,80,114,111,112,101,114,116,121,40,97,44,98,44,123,118,97, -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,79,98,106, -101,99,116,46,99,114,101,97,116,101,40,110,117,108,108,41,41,125,41,40,116, -104,105,115,44,68,117,107,116,97,112,101,41,59,10,0, -}; -#endif /* DUK_USE_BUILTIN_INITJS */ #if defined(DUK_USE_DOUBLE_LE) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = { -105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6, -152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2, -240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75, -14,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99, -203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252, -176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86, -148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212, -243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105, -21,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70, -145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192, -158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26, -228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14, -202,3,255,254,32,234,0,0,0,0,0,0,7,195,248,119,0,0,0,0,0,0,3,193,252,57, -136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153, -40,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223, -200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231, -119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144, -138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12, -166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212, -19,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18, -17,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136, -100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151, -30,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246, -240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46, -236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199, -135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163, -208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31, -240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221, -82,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150, -158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157, -135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157, -217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203, -46,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238, -230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93, -205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249, -230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16, -237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114, -223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113, -119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5, -195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130, -135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80, -128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175, -61,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94, -123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65, -250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47, -102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8, -105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7, -183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66, -15,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0, -195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129, -202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101, -131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52, -133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50, -195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28, -121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225, -179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253, -242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151, -148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196, -122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211, -150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138, -48,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,31, -255,255,255,255,255,253,239,240,153,178,103,95,173,6,101,88,176,0,64,0,0,0, -0,0,0,3,168,0,0,0,0,0,0,31,15,241,26,19,233,201,169,38,180,91,242,103,70, -147,58,77,75,48,0,0,0,0,0,0,60,31,226,51,162,199,131,82,77,104,183,228,206, -141,38,116,154,150,96,0,0,0,0,0,0,120,127,128,15,248,192,70,40,0,0,0,0,0,0, -0,0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,248, -190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,167, -126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,64, -247,111,238,56,0,127,199,2,49,72,0,0,0,0,0,0,248,127,180,81,36,4,51,166, -248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105, -244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196, -195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77, -59,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32, -80,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156, -184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132, -0,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126, -238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33, -196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244, -171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62, -94,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122, -101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156, -43,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121, -113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223, -187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61, -251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231, -151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154, -121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217, -167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100, -43,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10, -231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205, -211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3, -208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19, -15,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60, -189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43, -224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229, -233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195, -200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144, -24,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0, -0,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159, -240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230, -115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45, -252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185, -111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221, -143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206, -238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53, -60,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85, -165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,105,87,20,139,10,191,5, -64,130,76,156,197,132,1,101,91,91,187,22,176,36,8,28,201,204,160,119,156, -253,127,33,23,115,31,193,102,79,142,202,44,15,232,34,182,84,113,95,115,248, -52,201,241,216,176,139,0,59,148,152,85,239,47,108,254,5,66,76,1,130,212,69, -79,178,16,148,8,61,58,52,170,49,190,202,6,105,219,251,52,245,7,49,252,22, -157,26,85,25,64,205,59,127,102,158,160,246,63,74,7,135,23,53,2,65,48,227, -223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,195, -211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,15, -47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0, -136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110, -88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0, -21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23, -134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0, -191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,0,0,0,0,90,98, -32,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144, -60,56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7, -147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3, -252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255, -167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67, -184,2,172,254,0,0,255,171,8,137,144,0,0,0,0,0,0,0,128,68,73,4,195,187,126, -226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31, -0,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45, -153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65, -163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31, -245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242, -244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8, -207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176, -186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157, -221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194, -179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50, -208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22, -195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146, -119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133, -115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163, -102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36, -0,4,43,79,224,139,16,0,0,0,0,0,0,60,15,192,101,253,152,0,5,109,252,17,98,0, -0,0,0,0,0,7,129,248,12,191,181,0,0,174,63,130,44,64,0,0,0,0,0,0,240,63,1, -151,246,224,0,21,215,240,69,136,0,0,0,0,0,0,0,8,0,50,254,228,0,2,188,254,8, -177,0,0,0,0,0,0,0,1,0,6,95,221,128,0,87,223,193,22,32,0,0,0,0,0,0,8,32,0, -203,251,208,0,11,3,248,34,196,0,0,0,0,0,0,1,4,0,25,127,126,0,1,97,127,4,88, -128,0,0,0,0,0,0,32,128,3,47,240,64,0,44,79,224,139,16,0,0,0,0,0,0,8,16,0, -101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221, -143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16, -124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171, -39,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149, -100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10, -40,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92, -57,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101, -50,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168, -95,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51, -101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47, -150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113, -108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0, -200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59, -186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121, -101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221, -209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76, -181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116, -98,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160, -2,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50, -213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209, -155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9, -67,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244, -203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81, -70,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247, -229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45, -89,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27, -10,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39, -119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174, -29,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130, -243,217,167,30,81,132,65,123,242,211,211,42,228,0, +DUK_INTERNAL const duk_uint8_t duk_builtins_data[3790] = { +144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191, +135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196, +52,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26, +98,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212, +132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78, +18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,224,59, +147,60,93,110,79,15,39,9,24,186,33,13,63,79,185,38,154,121,223,110,76,66, +53,116,1,120,248,186,248,136,67,76,196,200,134,186,137,177,13,31,192,174, +79,15,32,248,8,196,24,8,107,254,39,97,161,175,248,159,16,215,252,80,186,26, +255,138,57,136,107,254,41,100,33,175,248,167,170,134,191,226,166,138,26, +255,138,187,40,107,254,43,111,33,171,86,181,16,209,241,11,228,201,121,240, +141,19,134,72,196,52,123,168,95,38,75,207,131,32,156,50,70,33,195,3,152, +128,0,0,0,0,0,1,240,255,153,128,0,0,0,0,0,1,224,255,151,137,0,214,9,188,35, +131,12,225,196,56,177,78,60,99,147,28,229,200,57,162,120,74,129,124,36,98, +232,156,241,92,136,26,98,112,145,139,162,116,71,114,36,41,34,70,136,156,36, +98,232,157,49,124,150,27,48,95,132,140,93,19,170,39,147,195,201,194,70,46, +137,215,17,218,69,4,236,98,232,157,153,39,110,81,220,15,193,209,83,3,200, +119,130,241,241,117,240,120,80,252,137,10,178,10,103,134,180,122,9,135,136, +154,120,169,199,142,158,121,10,7,146,162,121,74,71,150,166,121,138,135,154, +170,121,202,199,158,23,201,146,243,225,26,39,12,145,61,16,190,76,151,159,6, +65,56,100,137,233,35,93,205,144,33,224,140,137,196,54,121,244,5,60,17,145, +56,85,184,19,207,16,21,18,227,65,198,231,72,16,137,112,168,106,38,76,225,2, +70,65,56,100,237,34,140,177,4,134,65,56,100,237,34,129,117,204,123,154,70, +207,46,64,146,52,78,25,59,72,163,48,65,34,52,78,25,59,72,160,93,115,30,230, +145,179,204,144,24,146,16,30,76,209,2,40,210,72,64,121,52,4,0,156,88,97,5, +194,96,227,18,124,124,93,55,79,15,39,28,94,49,38,159,154,136,96,196,159,29, +102,241,241,115,201,25,227,131,36,133,20,62,110,142,253,2,102,36,248,235, +55,143,139,158,72,207,28,104,24,73,112,201,3,2,82,65,155,187,94,6,20,72,9, +147,120,128,225,144,168,105,56,248,185,228,140,241,190,96,128,200,84,52, +156,124,92,242,70,104,36,183,168,4,145,0,190,41,1,139,18,19,36,226,146,17, +124,73,82,54,124,37,230,70,201,14,108,184,132,8,68,185,34,1,100,31,8,129,8, +151,11,23,100,141,225,18,12,68,184,75,204,141,146,2,178,112,72,8,162,98,92, +50,10,152,147,227,172,222,62,46,121,35,60,114,88,96,92,185,112,201,65,34, +92,4,1,147,81,159,141,205,32,234,121,96,97,57,64,97,121,128,14,56,37,199, +89,188,124,92,242,70,120,227,144,53,18,227,226,233,186,120,121,56,226,242, +8,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,36,136,48,64,114,0, +250,156,168,1,64,247,175,25,36,2,8,11,94,80,248,16,40,104,242,103,200,48, +193,3,162,92,4,98,12,41,14,66,40,106,101,1,132,130,8,24,78,104,129,54,62, +96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,178, +58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,129, +232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,201, +126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,132, +0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,46, +36,29,4,78,69,6,60,226,31,192,7,255,252,24,160,163,11,23,51,130,56,35,193, +56,100,238,31,6,150,46,103,4,225,147,143,114,27,62,233,241,200,137,182,133, +42,142,167,216,6,23,216,0,97,28,17,224,39,223,32,80,142,8,240,78,25,56,9, +248,8,22,39,12,156,123,144,217,240,19,240,18,6,19,154,32,79,194,124,14,134, +140,151,227,139,226,52,11,88,37,62,33,163,37,248,226,248,141,32,213,184,64, +89,56,39,49,224,137,60,100,5,96,38,35,249,8,15,18,61,96,17,60,200,6,145,1, +17,31,206,64,89,45,2,39,161,0,178,122,209,63,74,2,101,64,202,113,67,77,235, +64,92,221,197,186,196,143,4,9,19,188,1,25,187,139,112,128,178,113,110,177, +35,193,2,68,239,0,46,110,229,30,242,71,130,4,137,222,4,35,55,113,110,16,22, +78,81,239,36,120,32,72,157,224,64,147,138,25,237,0,52,72,242,2,126,82,3,74, +129,148,227,234,66,12,112,28,140,155,104,203,169,158,9,133,158,4,25,36,1, +61,96,47,181,80,46,132,129,255,255,255,255,255,255,222,254,39,172,67,118, +170,5,208,144,0,64,0,0,0,0,0,0,51,16,0,0,0,0,0,0,62,31,200,245,238,146,38, +138,147,105,13,42,26,137,226,0,0,0,0,0,0,7,131,249,30,180,134,4,209,82,109, +33,165,67,81,60,64,0,0,0,0,0,0,240,255,28,144,155,104,0,0,0,0,0,0,0,0,16, +117,59,130,48,155,98,48,187,144,3,205,220,42,46,65,237,72,27,55,112,151, +123,154,70,205,0,94,208,129,115,119,31,18,9,18,67,155,183,34,12,176,96,175, +4,100,74,228,3,237,38,43,31,192,109,117,171,0,228,164,219,72,0,0,0,0,0,0, +248,127,196,234,111,0,50,110,224,193,50,114,83,138,26,107,192,131,38,238, +77,12,39,37,56,161,166,188,11,132,188,12,74,110,226,220,32,44,156,24,38,78, +74,113,67,77,120,28,148,221,197,184,64,89,57,52,48,156,148,226,134,154,240, +64,195,94,8,56,123,193,11,85,116,140,45,240,3,152,147,228,208,194,95,0,89, +137,62,22,139,95,48,64,70,200,67,28,98,79,180,152,139,218,45,124,193,1,27, +33,16,65,137,62,49,205,153,236,132,81,102,36,251,73,137,157,115,102,123,33, +24,57,137,62,12,19,37,144,142,40,196,159,105,49,15,160,153,44,132,128,198, +36,248,48,98,200,73,18,98,79,180,152,135,208,98,200,74,16,98,79,135,117,35, +43,33,44,89,137,62,210,98,63,93,72,202,200,76,20,98,79,140,67,105,50,74, +200,77,26,98,79,180,152,153,212,54,147,36,172,132,225,70,36,249,34,9,205, +28,172,132,241,166,36,251,73,138,93,32,156,209,202,200,80,30,98,79,140,66, +214,137,16,78,104,229,100,40,146,49,39,218,76,76,234,22,180,72,130,115,71, +43,33,72,137,137,62,77,12,38,92,210,113,197,44,137,59,64,7,145,39,201,161, +132,184,64,249,18,124,98,22,180,72,130,115,71,43,101,76,148,137,62,210,98, +103,80,181,162,68,19,154,57,91,42,130,164,73,242,68,19,154,57,91,95,84,108, +137,62,210,98,151,72,39,52,114,182,190,176,169,18,124,98,27,73,146,86,223, +215,27,34,79,180,152,153,212,54,147,36,173,191,176,34,68,159,14,234,70,86, +231,217,23,34,79,180,152,143,215,82,50,183,62,208,121,18,124,24,38,75,101, +108,84,137,62,210,98,31,65,50,91,43,130,36,73,241,142,108,207,109,125,209, +114,36,251,73,137,157,115,102,123,107,239,11,145,39,194,209,107,230,8,8, +219,127,124,116,137,62,210,98,47,104,181,243,4,4,109,191,192,135,49,39,204, +16,17,178,24,32,242,36,249,130,2,54,203,7,6,104,14,76,131,140,144,0,0,0,0, +0,0,0,1,141,207,215,12,78,126,193,46,190,126,192,98,179,246,4,197,231,236, +10,193,9,114,11,172,64,73,146,83,236,145,169,237,1,6,120,14,78,129,179,40, +249,18,149,175,207,141,199,27,76,248,156,81,177,207,139,198,9,169,199,129, +58,136,19,202,11,179,20,240,149,2,248,72,197,209,200,148,162,117,48,39,148, +151,102,42,228,64,211,19,132,140,93,28,137,74,39,85,2,121,81,118,98,238,68, +133,36,72,209,19,132,140,93,28,137,74,39,87,2,121,89,118,98,190,75,13,152, +47,194,70,46,142,68,165,19,172,129,60,176,187,49,79,39,135,147,132,140,93, +28,137,74,39,91,2,121,105,118,98,142,210,40,39,99,23,71,34,82,135,8,128, +120,72,13,42,226,145,97,87,224,168,1,58,182,232,232,64,22,85,181,187,177, +107,2,64,7,213,183,74,7,121,207,215,242,17,119,49,248,94,173,198,210,36,15, +232,34,182,84,113,95,115,240,221,91,141,163,160,72,1,220,164,194,175,121, +123,103,224,186,244,64,24,45,68,84,251,33,9,64,15,217,66,51,209,218,210, +129,154,118,254,205,61,65,204,126,23,178,132,103,165,3,52,237,253,154,122, +131,216,252,167,224,121,44,48,46,95,203,166,238,74,113,67,77,201,128,219, +152,164,82,6,0,203,76,64,64,9,210,211,18,4,4,144,221,49,40,64,76,13,211,19, +5,4,192,221,45,66,1,4,24,207,76,82,2,8,136,94,152,156,24,157,45,49,64,6,75, +191,76,80,66,149,110,116,116,197,8,41,240,247,79,70,188,6,183,27,76,80,194, +45,198,210,211,20,144,171,113,180,116,52,197,40,27,1,125,34,240,27,16,221, +42,240,27,221,109,66,32,104,129,163,115,52,224,5,139,168,209,233,138,32,57, +33,186,98,138,18,80,140,244,197,24,28,192,221,49,71,11,56,209,162,211,20, +183,1,66,188,17,145,52,40,9,148,226,134,153,5,198,137,136,32,14,12,30,164, +140,144,230,192,0,0,0,0,128,136,211,64,182,120,43,135,126,16,68,52,174,195, +144,12,2,158,4,128,70,22,24,128,101,67,112,163,192,100,104,176,131,192,99, +32,176,99,192,226,115,30,1,79,4,68,28,16,54,0,0,41,254,232,116,62,204,7,21, +35,18,54,127,80,28,192,132,28,32,14,96,197,212,243,193,48,188,240,39,130, +236,224,175,131,117,2,178,112,145,139,163,145,131,114,70,46,142,218,27,182, +72,197,209,219,56,26,53,161,166,32,128,56,18,2,129,239,94,50,76,130,68,230, +202,113,160,167,146,94,163,134,66,161,164,227,226,231,146,51,198,249,147, +71,209,67,73,210,94,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15, +155,163,191,68,28,98,79,143,139,166,233,225,228,227,139,198,37,210,244,208, +24,137,112,151,153,27,36,5,100,224,146,105,184,100,196,95,18,84,141,159,9, +121,145,178,67,155,46,33,38,187,168,252,211,243,81,92,2,14,40,16,50,37,202, +160,150,154,67,152,148,20,28,76,156,89,26,105,158,63,232,16,44,150,129,18, +146,44,28,96,14,98,216,80,113,50,113,100,105,166,120,255,160,20,28,76,156, +113,75,34,78,63,236,3,6,133,41,35,31,242,18,195,152,147,226,27,61,138,41, +140,16,98,79,148,67,103,177,69,45,136,49,39,196,54,122,58,212,83,26,36,196, +159,40,134,207,71,90,138,92,16,98,79,136,108,244,244,168,166,56,73,137,62, +81,13,158,158,149,20,186,40,196,159,10,183,2,122,122,84,82,240,163,18,124, +42,220,9,235,106,81,75,225,228,73,241,13,158,197,54,198,8,145,39,202,33, +179,216,166,214,196,72,147,226,27,61,29,106,109,141,19,34,79,148,67,103, +163,173,77,174,8,145,39,196,54,122,122,84,219,28,38,68,159,40,134,207,79, +74,155,93,21,34,79,133,91,129,61,61,42,109,120,84,137,62,21,110,4,245,181, +41,181,248,56,224,28,24,80,113,50,113,100,105,166,120,255,160,20,28,76,156, +113,75,34,78,63,236,3,6,133,41,35,31,242,11,174,254,160,34,84,8,35,16,98, +146,38,55,32,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,0,0,0,0,30, +7,230,56,199,161,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,0,0,0,0, +30,7,230,55,36,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,0,0,0,0, +30,7,234,40,11,91,133,199,172,8,111,248,128,239,88,16,222,56,191,242,49, +198,69,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,240,63, +49,185,65,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,240, +63,49,198,77,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0, +240,63,49,185,97,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0, +0,0,64,49,198,85,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0, +0,0,64,49,185,129,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0, +0,0,0,64,49,198,93,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0, +0,0,0,64,49,185,161,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0, +0,0,0,16,64,49,198,101,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0, +0,0,0,0,16,64,49,185,193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0, +0,0,0,0,0,16,64,49,198,109,8,244,56,153,37,180,242,71,104,139,35,8,217,192, +0,0,0,0,0,0,16,64,49,185,225,8,244,56,153,37,180,242,71,104,139,35,8,217, +192,0,0,0,0,0,0,16,64,49,198,117,8,244,56,153,37,180,242,71,104,139,35,8, +217,192,0,0,0,0,0,0,16,64,49,186,1,8,244,56,153,37,180,242,71,104,139,35,8, +217,192,0,0,0,0,0,0,32,64,49,198,125,8,244,56,153,37,180,242,71,104,139,35, +8,217,192,0,0,0,0,0,0,32,64,32,232,130,0,97,57,162,4,245,72,10,68,184,70, +137,195,67,77,175,32,66,37,192,208,165,36,117,196,10,14,38,78,44,141,52, +207,169,64,56,156,199,130,36,160,141,146,52,38,32,76,72,1,246,136,235,103, +177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37, +20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142, +183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136, +235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20, +138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161, +37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208, +146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89, +58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214, +207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207, +161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,207, +98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,78, +209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,146, +155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,104, +142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,146, +155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,217, +233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,162, +137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,77, +156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,117, +179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,162, +100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,59,22, +53,91,0,2,21,11,94,181,128,196,133,0,185,80,32,56,156,199,130,36,160,72,16, +78,126,53,144,5,146,208,34,82,72,1,109,20,76,155,40,32,233,0,115,70,130,8, +209,56,104,105,187,252,193,3,17,162,112,201,242,18,65,211,0,230,149,132,17, +162,112,208,211,119,248,0,82,130,96,95,127,128,130,80,102,186,36,232,92, +206,255,1,80,48,200,39,12,158,241,64, }; #elif defined(DUK_USE_DOUBLE_BE) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = { -105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6, -152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2, -240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75, -14,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99, -203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252, -176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86, -148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212, -243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105, -21,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70, -145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192, -158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26, -228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14, -202,3,255,254,32,234,3,255,192,0,0,0,0,0,0,119,1,255,192,0,0,0,0,0,0,57, -136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153, -40,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223, -200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231, -119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144, -138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12, -166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212, -19,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18, -17,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136, -100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151, -30,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246, -240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46, -236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199, -135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163, -208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31, -240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221, -82,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150, -158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157, -135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157, -217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203, -46,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238, -230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93, -205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249, -230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16, -237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114, -223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113, -119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5, -195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130, -135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80, -128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175, -61,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94, -123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65, -250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47, -102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8, -105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7, -183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66, -15,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0, -195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129, -202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101, -131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52, -133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50, -195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28, -121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225, -179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253, -242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151, -148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196, -122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211, -150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138, -48,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,15, -253,255,255,255,255,255,255,240,153,178,103,95,173,6,101,88,176,0,0,0,0,0, -0,0,0,67,168,15,255,0,0,0,0,0,0,17,26,19,233,201,169,38,180,91,242,103,70, -147,58,77,75,48,31,252,0,0,0,0,0,0,34,51,162,199,131,82,77,104,183,228,206, -141,38,116,154,150,96,127,248,0,0,0,0,0,0,0,15,248,192,70,40,0,0,0,0,0,0,0, -0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,248, -190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,167, -126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,64, -247,111,238,56,0,127,199,2,49,72,127,248,0,0,0,0,0,0,180,81,36,4,51,166, -248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105, -244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196, -195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77, -59,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32, -80,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156, -184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132, -0,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126, -238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33, -196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244, -171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62, -94,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122, -101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156, -43,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121, -113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223, -187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61, -251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231, -151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154, -121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217, -167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100, -43,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10, -231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205, -211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3, -208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19, -15,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60, -189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43, -224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229, -233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195, -200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144, -24,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0, -0,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159, -240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230, -115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45, -252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185, -111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221, -143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206, -238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53, -60,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85, -165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,64,5,191,10,139,20,87, -105,130,76,156,197,132,4,0,38,187,27,187,85,81,104,28,201,204,160,31,243, -23,33,127,125,28,247,193,102,79,142,202,44,3,255,113,84,118,82,184,47,232, -52,201,241,216,176,139,0,255,111,45,236,84,155,148,58,5,66,76,4,0,146,31, -181,68,66,209,136,61,58,52,170,49,190,202,1,255,53,4,243,51,249,222,108,22, -157,26,85,25,64,63,246,160,158,102,127,59,205,74,7,135,23,53,2,65,48,227, -223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,195, -211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,15, -47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0, -136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110, -88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0, -21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23, -134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0, -191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,32,98,90,0,0,0,0, -0,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,60, -56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7, -147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3, -252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255, -167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67, -184,2,172,254,0,0,255,171,8,137,144,128,0,0,0,0,0,0,0,68,73,4,195,187,126, -226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31, -0,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45, -153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65, -163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31, -245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242, -244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8, -207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176, -186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157, -221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194, -179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50, -208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22, -195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146, -119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133, -115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163, -102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36, -0,4,43,79,224,139,16,15,252,0,0,0,0,0,0,0,101,253,152,0,5,109,252,17,98,1, -255,128,0,0,0,0,0,0,12,191,181,0,0,174,63,130,44,64,63,240,0,0,0,0,0,0,1, -151,246,224,0,21,215,240,69,136,8,0,0,0,0,0,0,0,0,50,254,228,0,2,188,254,8, -177,1,0,0,0,0,0,0,0,0,6,95,221,128,0,87,223,193,22,32,32,8,0,0,0,0,0,0,0, -203,251,208,0,11,3,248,34,196,4,1,0,0,0,0,0,0,0,25,127,126,0,1,97,127,4,88, -128,128,32,0,0,0,0,0,0,3,47,240,64,0,44,79,224,139,16,16,8,0,0,0,0,0,0,0, -101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221, -143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16, -124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171, -39,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149, -100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10, -40,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92, -57,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101, -50,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168, -95,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51, -101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47, -150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113, -108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0, -200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59, -186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121, -101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221, -209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76, -181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116, -98,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160, -2,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50, -213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209, -155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9, -67,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244, -203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81, -70,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247, -229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45, -89,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27, -10,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39, -119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174, -29,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130, -243,217,167,30,81,132,65,123,242,211,211,42,228,0, +DUK_INTERNAL const duk_uint8_t duk_builtins_data[3790] = { +144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191, +135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196, +52,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26, +98,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212, +132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78, +18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,224,59, +147,60,93,110,79,15,39,9,24,186,33,13,63,79,185,38,154,121,223,110,76,66, +53,116,1,120,248,186,248,136,67,76,196,200,134,186,137,177,13,31,192,174, +79,15,32,248,8,196,24,8,107,254,39,97,161,175,248,159,16,215,252,80,186,26, +255,138,57,136,107,254,41,100,33,175,248,167,170,134,191,226,166,138,26, +255,138,187,40,107,254,43,111,33,171,86,181,16,209,241,11,228,201,121,240, +141,19,134,72,196,52,123,168,95,38,75,207,131,32,156,50,70,33,195,3,152, +128,255,240,0,0,0,0,0,1,153,128,255,224,0,0,0,0,0,1,151,137,0,214,9,188,35, +131,12,225,196,56,177,78,60,99,147,28,229,200,57,162,120,74,129,124,36,98, +232,156,241,92,136,26,98,112,145,139,162,116,71,114,36,41,34,70,136,156,36, +98,232,157,49,124,150,27,48,95,132,140,93,19,170,39,147,195,201,194,70,46, +137,215,17,218,69,4,236,98,232,157,153,39,110,81,220,15,193,209,83,3,200, +119,130,241,241,117,240,120,80,252,137,10,178,10,103,134,180,122,9,135,136, +154,120,169,199,142,158,121,10,7,146,162,121,74,71,150,166,121,138,135,154, +170,121,202,199,158,23,201,146,243,225,26,39,12,145,61,16,190,76,151,159,6, +65,56,100,137,233,35,93,205,144,33,224,140,137,196,54,121,244,5,60,17,145, +56,85,184,19,207,16,21,18,227,65,198,231,72,16,137,112,168,106,38,76,225,2, +70,65,56,100,237,34,140,177,4,134,65,56,100,237,34,129,117,204,123,154,70, +207,46,64,146,52,78,25,59,72,163,48,65,34,52,78,25,59,72,160,93,115,30,230, +145,179,204,144,24,146,16,30,76,209,2,40,210,72,64,121,52,4,0,156,88,97,5, +194,96,227,18,124,124,93,55,79,15,39,28,94,49,38,159,154,136,96,196,159,29, +102,241,241,115,201,25,227,131,36,133,20,62,110,142,253,2,102,36,248,235, +55,143,139,158,72,207,28,104,24,73,112,201,3,2,82,65,155,187,94,6,20,72,9, +147,120,128,225,144,168,105,56,248,185,228,140,241,190,96,128,200,84,52, +156,124,92,242,70,104,36,183,168,4,145,0,190,41,1,139,18,19,36,226,146,17, +124,73,82,54,124,37,230,70,201,14,108,184,132,8,68,185,34,1,100,31,8,129,8, +151,11,23,100,141,225,18,12,68,184,75,204,141,146,2,178,112,72,8,162,98,92, +50,10,152,147,227,172,222,62,46,121,35,60,114,88,96,92,185,112,201,65,34, +92,4,1,147,81,159,141,205,32,234,121,96,97,57,64,97,121,128,14,56,37,199, +89,188,124,92,242,70,120,227,144,53,18,227,226,233,186,120,121,56,226,242, +8,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,36,136,48,64,114,0, +250,156,168,1,64,247,175,25,36,2,8,11,94,80,248,16,40,104,242,103,200,48, +193,3,162,92,4,98,12,41,14,66,40,106,101,1,132,130,8,24,78,104,129,54,62, +96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,178, +58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,129, +232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,201, +126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,132, +0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,46, +36,29,4,78,69,6,60,226,31,192,7,255,252,24,160,163,11,23,51,130,56,35,193, +56,100,238,31,6,150,46,103,4,225,147,143,114,27,62,233,241,200,137,182,133, +42,142,167,216,6,23,216,0,97,28,17,224,39,223,32,80,142,8,240,78,25,56,9, +248,8,22,39,12,156,123,144,217,240,19,240,18,6,19,154,32,79,194,124,14,134, +140,151,227,139,226,52,11,88,37,62,33,163,37,248,226,248,141,32,213,184,64, +89,56,39,49,224,137,60,100,5,96,38,35,249,8,15,18,61,96,17,60,200,6,145,1, +17,31,206,64,89,45,2,39,161,0,178,122,209,63,74,2,101,64,202,113,67,77,235, +64,92,221,197,186,196,143,4,9,19,188,1,25,187,139,112,128,178,113,110,177, +35,193,2,68,239,0,46,110,229,30,242,71,130,4,137,222,4,35,55,113,110,16,22, +78,81,239,36,120,32,72,157,224,64,147,138,25,237,0,52,72,242,2,126,82,3,74, +129,148,227,234,66,12,112,28,140,155,104,203,169,158,9,133,158,4,25,36,1, +61,96,47,181,80,46,132,128,255,223,255,255,255,255,255,254,39,172,67,118, +170,5,208,144,0,0,0,0,0,0,0,0,115,16,31,254,0,0,0,0,0,0,8,245,238,146,38, +138,147,105,13,42,26,137,226,3,255,128,0,0,0,0,0,1,30,180,134,4,209,82,109, +33,165,67,81,60,64,255,240,0,0,0,0,0,0,28,144,155,104,0,0,0,0,0,0,0,0,16, +117,59,130,48,155,98,48,187,144,3,205,220,42,46,65,237,72,27,55,112,151, +123,154,70,205,0,94,208,129,115,119,31,18,9,18,67,155,183,34,12,176,96,175, +4,100,74,228,3,237,38,43,31,192,109,117,171,0,228,164,219,72,127,248,0,0,0, +0,0,0,196,234,111,0,50,110,224,193,50,114,83,138,26,107,192,131,38,238,77, +12,39,37,56,161,166,188,11,132,188,12,74,110,226,220,32,44,156,24,38,78,74, +113,67,77,120,28,148,221,197,184,64,89,57,52,48,156,148,226,134,154,240,64, +195,94,8,56,123,193,11,85,116,140,45,240,3,152,147,228,208,194,95,0,89,137, +62,22,139,95,48,64,70,200,67,28,98,79,180,152,139,218,45,124,193,1,27,33, +16,65,137,62,49,205,153,236,132,81,102,36,251,73,137,157,115,102,123,33,24, +57,137,62,12,19,37,144,142,40,196,159,105,49,15,160,153,44,132,128,198,36, +248,48,98,200,73,18,98,79,180,152,135,208,98,200,74,16,98,79,135,117,35,43, +33,44,89,137,62,210,98,63,93,72,202,200,76,20,98,79,140,67,105,50,74,200, +77,26,98,79,180,152,153,212,54,147,36,172,132,225,70,36,249,34,9,205,28, +172,132,241,166,36,251,73,138,93,32,156,209,202,200,80,30,98,79,140,66,214, +137,16,78,104,229,100,40,146,49,39,218,76,76,234,22,180,72,130,115,71,43, +33,72,137,137,62,77,12,38,92,210,113,197,44,137,59,64,7,145,39,201,161,132, +184,64,249,18,124,98,22,180,72,130,115,71,43,101,76,148,137,62,210,98,103, +80,181,162,68,19,154,57,91,42,130,164,73,242,68,19,154,57,91,95,84,108,137, +62,210,98,151,72,39,52,114,182,190,176,169,18,124,98,27,73,146,86,223,215, +27,34,79,180,152,153,212,54,147,36,173,191,176,34,68,159,14,234,70,86,231, +217,23,34,79,180,152,143,215,82,50,183,62,208,121,18,124,24,38,75,101,108, +84,137,62,210,98,31,65,50,91,43,130,36,73,241,142,108,207,109,125,209,114, +36,251,73,137,157,115,102,123,107,239,11,145,39,194,209,107,230,8,8,219, +127,124,116,137,62,210,98,47,104,181,243,4,4,109,191,192,135,49,39,204,16, +17,178,24,32,242,36,249,130,2,54,203,7,6,104,14,76,131,140,144,0,0,0,0,0,0, +0,1,141,207,215,12,78,126,193,46,190,126,192,98,179,246,4,197,231,236,10, +193,9,114,11,172,64,73,146,83,236,145,169,237,1,6,120,14,78,129,179,40,249, +18,149,175,207,141,199,27,76,248,156,81,177,207,139,198,9,169,199,129,58, +136,19,202,11,179,20,240,149,2,248,72,197,209,200,148,162,117,48,39,148, +151,102,42,228,64,211,19,132,140,93,28,137,74,39,85,2,121,81,118,98,238,68, +133,36,72,209,19,132,140,93,28,137,74,39,87,2,121,89,118,98,190,75,13,152, +47,194,70,46,142,68,165,19,172,129,60,176,187,49,79,39,135,147,132,140,93, +28,137,74,39,91,2,121,105,118,98,142,210,40,39,99,23,71,34,82,135,8,128, +120,72,8,0,183,225,81,98,138,237,33,58,182,232,232,64,64,2,107,177,187,181, +85,22,7,213,183,74,1,255,49,114,23,247,209,207,120,94,173,198,210,36,3,255, +113,84,118,82,184,47,224,221,91,141,163,160,72,7,251,121,111,98,164,220, +161,192,186,244,64,64,9,33,251,84,68,45,24,15,217,66,51,209,218,210,128, +127,205,65,60,204,254,119,154,23,178,132,103,165,0,255,218,130,121,153,252, +239,52,167,224,121,44,48,46,95,203,166,238,74,113,67,77,201,128,219,152, +164,82,6,0,203,76,64,64,9,210,211,18,4,4,144,221,49,40,64,76,13,211,19,5,4, +192,221,45,66,1,4,24,207,76,82,2,8,136,94,152,156,24,157,45,49,64,6,75,191, +76,80,66,149,110,116,116,197,8,41,240,247,79,70,188,6,183,27,76,80,194,45, +198,210,211,20,144,171,113,180,116,52,197,40,27,1,125,34,240,27,16,221,42, +240,27,221,109,66,32,104,129,163,115,52,224,5,139,168,209,233,138,32,57,33, +186,98,138,18,80,140,244,197,24,28,192,221,49,71,11,56,209,162,211,20,183, +1,66,188,17,145,52,40,9,148,226,134,153,5,198,137,136,32,14,12,30,164,140, +144,230,192,64,211,136,128,0,0,0,0,182,120,43,135,126,16,68,52,174,195,144, +12,2,158,4,128,70,22,24,128,101,67,112,163,192,100,104,176,131,192,99,32, +176,99,192,226,115,30,1,79,4,68,28,16,54,0,0,41,254,232,116,62,204,7,21,35, +18,54,127,80,28,192,132,28,32,14,96,197,212,243,193,48,188,240,39,130,236, +224,175,131,117,2,178,112,145,139,163,145,131,114,70,46,142,218,27,182,72, +197,209,219,56,26,53,161,166,32,128,56,18,2,129,239,94,50,76,130,68,230, +202,113,160,167,146,94,163,134,66,161,164,227,226,231,146,51,198,249,147, +71,209,67,73,210,94,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15, +155,163,191,68,28,98,79,143,139,166,233,225,228,227,139,198,37,210,244,208, +24,137,112,151,153,27,36,5,100,224,146,105,184,100,196,95,18,84,141,159,9, +121,145,178,67,155,46,33,38,187,168,252,211,243,81,92,2,14,40,16,50,37,202, +160,150,154,67,152,148,20,28,76,156,89,26,105,158,63,232,16,44,150,129,18, +146,44,28,96,14,98,216,80,113,50,113,100,105,166,120,255,160,20,28,76,156, +113,75,34,78,63,236,3,6,133,41,35,31,242,18,195,152,147,226,27,61,138,41, +140,16,98,79,148,67,103,177,69,45,136,49,39,196,54,122,58,212,83,26,36,196, +159,40,134,207,71,90,138,92,16,98,79,136,108,244,244,168,166,56,73,137,62, +81,13,158,158,149,20,186,40,196,159,10,183,2,122,122,84,82,240,163,18,124, +42,220,9,235,106,81,75,225,228,73,241,13,158,197,54,198,8,145,39,202,33, +179,216,166,214,196,72,147,226,27,61,29,106,109,141,19,34,79,148,67,103, +163,173,77,174,8,145,39,196,54,122,122,84,219,28,38,68,159,40,134,207,79, +74,155,93,21,34,79,133,91,129,61,61,42,109,120,84,137,62,21,110,4,245,181, +41,181,248,56,224,28,24,80,113,50,113,100,105,166,120,255,160,20,28,76,156, +113,75,34,78,63,236,3,6,133,41,35,31,242,11,174,254,160,34,84,8,35,16,98, +146,38,55,32,33,30,135,19,36,182,158,72,237,17,100,97,27,56,7,254,0,0,0,0, +0,0,6,56,199,161,30,135,19,36,182,158,72,237,17,100,97,27,56,7,254,0,0,0,0, +0,0,6,55,36,33,30,135,19,36,182,158,72,237,17,100,97,27,56,7,254,0,0,0,0,0, +0,10,40,11,91,133,199,172,8,111,248,128,239,88,16,222,56,191,242,49,198,69, +8,244,56,153,37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0,49,185, +65,8,244,56,153,37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0,49, +198,77,8,244,56,153,37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0, +49,185,97,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0, +49,198,85,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0, +49,185,129,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0, +0,49,198,93,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0, +0,49,185,161,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0,0, +0,0,49,198,101,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0, +0,0,0,49,185,193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0, +0,0,0,0,49,198,109,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0, +0,0,0,0,0,49,185,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16, +0,0,0,0,0,0,49,198,117,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64, +16,0,0,0,0,0,0,49,186,1,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64, +32,0,0,0,0,0,0,49,198,125,8,244,56,153,37,180,242,71,104,139,35,8,217,192, +64,32,0,0,0,0,0,0,32,232,130,0,97,57,162,4,245,72,10,68,184,70,137,195,67, +77,175,32,66,37,192,208,165,36,117,196,10,14,38,78,44,141,52,207,169,64,56, +156,199,130,36,160,141,146,52,38,32,76,72,1,246,136,235,103,177,69,1,17,32, +7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37,20,65,145,32,7, +218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142,183,86,74,41,48, +92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136,235,103,167,165, +213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20,138,46,36,0,248, +134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161,37,20,170,46,36, +0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208,146,138,70,25,18, +0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89,58,18,81,72,226, +162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214,207,161,37,22,144, +38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207,161,37,22,176,42,209, +68,201,218,35,173,158,197,54,4,218,40,153,56,134,207,98,155,75,27,104,162, +100,237,17,214,207,71,91,171,37,54,65,182,138,38,78,209,29,108,244,117,186, +18,83,104,131,45,20,76,156,67,103,163,173,213,146,155,76,25,104,162,100, +226,27,61,29,110,132,148,218,160,219,69,19,39,104,142,182,122,122,93,89,41, +178,141,180,81,50,118,136,235,103,167,165,208,146,155,69,25,104,162,100, +226,27,61,61,46,172,148,218,104,203,69,19,39,16,217,233,233,116,36,166,213, +70,90,40,153,56,85,184,19,234,201,77,152,101,162,137,147,133,91,129,62,132, +148,218,48,219,69,19,39,6,234,5,100,234,201,77,156,109,162,137,147,131,117, +2,178,116,36,166,209,197,218,40,153,59,68,117,179,234,201,78,32,11,180,81, +50,118,136,235,103,208,146,156,72,21,104,162,100,226,27,62,172,148,226,128, +171,69,19,39,16,217,244,36,167,22,53,59,22,53,91,0,2,21,11,94,181,128,196, +133,0,185,80,32,56,156,199,130,36,160,72,16,78,126,53,144,5,146,208,34,82, +72,1,109,20,76,155,40,32,233,0,115,70,130,8,209,56,104,105,187,252,193,3, +17,162,112,201,242,18,65,211,0,230,149,132,17,162,112,208,211,119,248,0,82, +130,96,95,127,128,130,80,102,186,36,232,92,206,255,1,80,48,200,39,12,158, +241,64, }; #elif defined(DUK_USE_DOUBLE_ME) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = { -105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6, -152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2, -240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75, -14,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99, -203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252, -176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86, -148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212, -243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105, -21,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70, -145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192, -158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26, -228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14, -202,3,255,254,32,234,0,0,7,195,248,0,0,0,0,119,0,0,3,193,252,0,0,0,0,57, -136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153, -40,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223, -200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231, -119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144, -138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12, -166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212, -19,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18, -17,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136, -100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151, -30,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246, -240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46, -236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199, -135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163, -208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31, -240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221, -82,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150, -158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157, -135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157, -217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203, -46,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238, -230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93, -205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249, -230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16, -237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114, -223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113, -119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5, -195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130, -135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80, -128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175, -61,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94, -123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65, -250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47, -102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8, -105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7, -183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66, -15,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0, -195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129, -202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101, -131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52, -133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50, -195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28, -121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225, -179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253, -242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151, -148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196, -122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211, -150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138, -48,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,31, -255,253,239,255,255,255,255,240,153,178,103,95,173,6,101,88,176,0,0,0,0,0, -64,0,0,3,168,0,0,31,15,224,0,0,0,17,26,19,233,201,169,38,180,91,242,103,70, -147,58,77,75,48,0,0,60,31,192,0,0,0,34,51,162,199,131,82,77,104,183,228, -206,141,38,116,154,150,96,0,0,120,127,128,0,0,0,0,15,248,192,70,40,0,0,0,0, -0,0,0,0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166, -248,190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231, -167,126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127, -64,247,111,238,56,0,127,199,2,49,72,0,0,248,127,0,0,0,0,180,81,36,4,51,166, -248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105, -244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196, -195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77, -59,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32, -80,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156, -184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132, -0,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126, -238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33, -196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244, -171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62, -94,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122, -101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156, -43,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121, -113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223, -187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61, -251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231, -151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154, -121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217, -167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100, -43,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10, -231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205, -211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3, -208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19, -15,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60, -189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43, -224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229, -233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195, -200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144, -24,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0, -0,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159, -240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230, -115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45, -252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185, -111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221, -143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206, -238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53, -60,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85, -165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,10,191,5,64,105,87,20, -139,130,76,156,197,132,11,22,176,36,1,101,91,91,184,28,201,204,160,33,23, -115,31,247,156,253,127,65,102,79,142,202,44,4,113,95,115,255,232,34,182,88, -52,201,241,216,176,139,1,239,47,108,252,59,148,152,86,5,66,76,15,178,16, -148,1,130,212,69,72,61,58,52,170,49,190,202,4,245,7,49,254,105,219,251,52, -22,157,26,85,25,64,158,160,246,63,205,59,127,102,74,7,135,23,53,2,65,48, -227,223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5, -195,211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44, -15,47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0, -136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110, -88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0, -21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23, -134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0, -191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,90,98,32,0,0,0, -0,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,60, -56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7, -147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3, -252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255, -167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67, -184,2,172,254,0,0,255,171,8,137,144,0,0,0,128,0,0,0,0,68,73,4,195,187,126, -226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31, -0,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45, -153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65, -163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31, -245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242, -244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8, -207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176, -186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157, -221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194, -179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50, -208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22, -195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146, -119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133, -115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163, -102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36, -0,4,43,79,224,139,16,0,0,60,15,192,0,0,0,0,101,253,152,0,5,109,252,17,98,0, -0,7,129,248,0,0,0,0,12,191,181,0,0,174,63,130,44,64,0,0,240,63,0,0,0,0,1, -151,246,224,0,21,215,240,69,136,0,0,0,8,0,0,0,0,0,50,254,228,0,2,188,254,8, -177,0,0,0,1,0,0,0,0,0,6,95,221,128,0,87,223,193,22,32,0,0,8,32,0,0,0,0,0, -203,251,208,0,11,3,248,34,196,0,0,1,4,0,0,0,0,0,25,127,126,0,1,97,127,4,88, -128,0,0,32,128,0,0,0,0,3,47,240,64,0,44,79,224,139,16,0,0,8,16,0,0,0,0,0, -101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221, -143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16, -124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171, -39,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149, -100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10, -40,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92, -57,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101, -50,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168, -95,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51, -101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47, -150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113, -108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0, -200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59, -186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121, -101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221, -209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76, -181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116, -98,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160, -2,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50, -213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209, -155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9, -67,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244, -203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81, -70,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247, -229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45, -89,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27, -10,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39, -119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174, -29,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130, -243,217,167,30,81,132,65,123,242,211,211,42,228,0, +DUK_INTERNAL const duk_uint8_t duk_builtins_data[3790] = { +144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191, +135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196, +52,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26, +98,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212, +132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78, +18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,224,59, +147,60,93,110,79,15,39,9,24,186,33,13,63,79,185,38,154,121,223,110,76,66, +53,116,1,120,248,186,248,136,67,76,196,200,134,186,137,177,13,31,192,174, +79,15,32,248,8,196,24,8,107,254,39,97,161,175,248,159,16,215,252,80,186,26, +255,138,57,136,107,254,41,100,33,175,248,167,170,134,191,226,166,138,26, +255,138,187,40,107,254,43,111,33,171,86,181,16,209,241,11,228,201,121,240, +141,19,134,72,196,52,123,168,95,38,75,207,131,32,156,50,70,33,195,3,152, +128,0,1,240,254,0,0,0,1,153,128,0,1,224,254,0,0,0,1,151,137,0,214,9,188,35, +131,12,225,196,56,177,78,60,99,147,28,229,200,57,162,120,74,129,124,36,98, +232,156,241,92,136,26,98,112,145,139,162,116,71,114,36,41,34,70,136,156,36, +98,232,157,49,124,150,27,48,95,132,140,93,19,170,39,147,195,201,194,70,46, +137,215,17,218,69,4,236,98,232,157,153,39,110,81,220,15,193,209,83,3,200, +119,130,241,241,117,240,120,80,252,137,10,178,10,103,134,180,122,9,135,136, +154,120,169,199,142,158,121,10,7,146,162,121,74,71,150,166,121,138,135,154, +170,121,202,199,158,23,201,146,243,225,26,39,12,145,61,16,190,76,151,159,6, +65,56,100,137,233,35,93,205,144,33,224,140,137,196,54,121,244,5,60,17,145, +56,85,184,19,207,16,21,18,227,65,198,231,72,16,137,112,168,106,38,76,225,2, +70,65,56,100,237,34,140,177,4,134,65,56,100,237,34,129,117,204,123,154,70, +207,46,64,146,52,78,25,59,72,163,48,65,34,52,78,25,59,72,160,93,115,30,230, +145,179,204,144,24,146,16,30,76,209,2,40,210,72,64,121,52,4,0,156,88,97,5, +194,96,227,18,124,124,93,55,79,15,39,28,94,49,38,159,154,136,96,196,159,29, +102,241,241,115,201,25,227,131,36,133,20,62,110,142,253,2,102,36,248,235, +55,143,139,158,72,207,28,104,24,73,112,201,3,2,82,65,155,187,94,6,20,72,9, +147,120,128,225,144,168,105,56,248,185,228,140,241,190,96,128,200,84,52, +156,124,92,242,70,104,36,183,168,4,145,0,190,41,1,139,18,19,36,226,146,17, +124,73,82,54,124,37,230,70,201,14,108,184,132,8,68,185,34,1,100,31,8,129,8, +151,11,23,100,141,225,18,12,68,184,75,204,141,146,2,178,112,72,8,162,98,92, +50,10,152,147,227,172,222,62,46,121,35,60,114,88,96,92,185,112,201,65,34, +92,4,1,147,81,159,141,205,32,234,121,96,97,57,64,97,121,128,14,56,37,199, +89,188,124,92,242,70,120,227,144,53,18,227,226,233,186,120,121,56,226,242, +8,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,36,136,48,64,114,0, +250,156,168,1,64,247,175,25,36,2,8,11,94,80,248,16,40,104,242,103,200,48, +193,3,162,92,4,98,12,41,14,66,40,106,101,1,132,130,8,24,78,104,129,54,62, +96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,178, +58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,129, +232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,201, +126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,132, +0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,46, +36,29,4,78,69,6,60,226,31,192,7,255,252,24,160,163,11,23,51,130,56,35,193, +56,100,238,31,6,150,46,103,4,225,147,143,114,27,62,233,241,200,137,182,133, +42,142,167,216,6,23,216,0,97,28,17,224,39,223,32,80,142,8,240,78,25,56,9, +248,8,22,39,12,156,123,144,217,240,19,240,18,6,19,154,32,79,194,124,14,134, +140,151,227,139,226,52,11,88,37,62,33,163,37,248,226,248,141,32,213,184,64, +89,56,39,49,224,137,60,100,5,96,38,35,249,8,15,18,61,96,17,60,200,6,145,1, +17,31,206,64,89,45,2,39,161,0,178,122,209,63,74,2,101,64,202,113,67,77,235, +64,92,221,197,186,196,143,4,9,19,188,1,25,187,139,112,128,178,113,110,177, +35,193,2,68,239,0,46,110,229,30,242,71,130,4,137,222,4,35,55,113,110,16,22, +78,81,239,36,120,32,72,157,224,64,147,138,25,237,0,52,72,242,2,126,82,3,74, +129,148,227,234,66,12,112,28,140,155,104,203,169,158,9,133,158,4,25,36,1, +61,96,47,181,80,46,132,129,255,255,222,255,255,255,255,254,39,172,67,118, +170,5,208,144,0,0,0,0,0,64,0,0,51,16,0,0,62,31,192,0,0,0,8,245,238,146,38, +138,147,105,13,42,26,137,226,0,0,7,131,248,0,0,0,1,30,180,134,4,209,82,109, +33,165,67,81,60,64,0,0,240,255,0,0,0,0,28,144,155,104,0,0,0,0,0,0,0,0,16, +117,59,130,48,155,98,48,187,144,3,205,220,42,46,65,237,72,27,55,112,151, +123,154,70,205,0,94,208,129,115,119,31,18,9,18,67,155,183,34,12,176,96,175, +4,100,74,228,3,237,38,43,31,192,109,117,171,0,228,164,219,72,0,0,248,127,0, +0,0,0,196,234,111,0,50,110,224,193,50,114,83,138,26,107,192,131,38,238,77, +12,39,37,56,161,166,188,11,132,188,12,74,110,226,220,32,44,156,24,38,78,74, +113,67,77,120,28,148,221,197,184,64,89,57,52,48,156,148,226,134,154,240,64, +195,94,8,56,123,193,11,85,116,140,45,240,3,152,147,228,208,194,95,0,89,137, +62,22,139,95,48,64,70,200,67,28,98,79,180,152,139,218,45,124,193,1,27,33, +16,65,137,62,49,205,153,236,132,81,102,36,251,73,137,157,115,102,123,33,24, +57,137,62,12,19,37,144,142,40,196,159,105,49,15,160,153,44,132,128,198,36, +248,48,98,200,73,18,98,79,180,152,135,208,98,200,74,16,98,79,135,117,35,43, +33,44,89,137,62,210,98,63,93,72,202,200,76,20,98,79,140,67,105,50,74,200, +77,26,98,79,180,152,153,212,54,147,36,172,132,225,70,36,249,34,9,205,28, +172,132,241,166,36,251,73,138,93,32,156,209,202,200,80,30,98,79,140,66,214, +137,16,78,104,229,100,40,146,49,39,218,76,76,234,22,180,72,130,115,71,43, +33,72,137,137,62,77,12,38,92,210,113,197,44,137,59,64,7,145,39,201,161,132, +184,64,249,18,124,98,22,180,72,130,115,71,43,101,76,148,137,62,210,98,103, +80,181,162,68,19,154,57,91,42,130,164,73,242,68,19,154,57,91,95,84,108,137, +62,210,98,151,72,39,52,114,182,190,176,169,18,124,98,27,73,146,86,223,215, +27,34,79,180,152,153,212,54,147,36,173,191,176,34,68,159,14,234,70,86,231, +217,23,34,79,180,152,143,215,82,50,183,62,208,121,18,124,24,38,75,101,108, +84,137,62,210,98,31,65,50,91,43,130,36,73,241,142,108,207,109,125,209,114, +36,251,73,137,157,115,102,123,107,239,11,145,39,194,209,107,230,8,8,219, +127,124,116,137,62,210,98,47,104,181,243,4,4,109,191,192,135,49,39,204,16, +17,178,24,32,242,36,249,130,2,54,203,7,6,104,14,76,131,140,144,0,0,0,0,0,0, +0,1,141,207,215,12,78,126,193,46,190,126,192,98,179,246,4,197,231,236,10, +193,9,114,11,172,64,73,146,83,236,145,169,237,1,6,120,14,78,129,179,40,249, +18,149,175,207,141,199,27,76,248,156,81,177,207,139,198,9,169,199,129,58, +136,19,202,11,179,20,240,149,2,248,72,197,209,200,148,162,117,48,39,148, +151,102,42,228,64,211,19,132,140,93,28,137,74,39,85,2,121,81,118,98,238,68, +133,36,72,209,19,132,140,93,28,137,74,39,87,2,121,89,118,98,190,75,13,152, +47,194,70,46,142,68,165,19,172,129,60,176,187,49,79,39,135,147,132,140,93, +28,137,74,39,91,2,121,105,118,98,142,210,40,39,99,23,71,34,82,135,8,128, +120,72,1,87,224,168,13,42,226,145,97,58,182,232,232,64,177,107,2,64,22,85, +181,187,7,213,183,74,2,17,119,49,255,121,207,215,240,94,173,198,210,36,4, +113,95,115,255,232,34,182,80,221,91,141,163,160,72,15,121,123,103,225,220, +164,194,160,186,244,64,251,33,9,64,24,45,68,84,15,217,66,51,209,218,210, +129,61,65,204,127,154,118,254,204,23,178,132,103,165,2,122,131,216,255,52, +237,253,152,167,224,121,44,48,46,95,203,166,238,74,113,67,77,201,128,219, +152,164,82,6,0,203,76,64,64,9,210,211,18,4,4,144,221,49,40,64,76,13,211,19, +5,4,192,221,45,66,1,4,24,207,76,82,2,8,136,94,152,156,24,157,45,49,64,6,75, +191,76,80,66,149,110,116,116,197,8,41,240,247,79,70,188,6,183,27,76,80,194, +45,198,210,211,20,144,171,113,180,116,52,197,40,27,1,125,34,240,27,16,221, +42,240,27,221,109,66,32,104,129,163,115,52,224,5,139,168,209,233,138,32,57, +33,186,98,138,18,80,140,244,197,24,28,192,221,49,71,11,56,209,162,211,20, +183,1,66,188,17,145,52,40,9,148,226,134,153,5,198,137,136,32,14,12,30,164, +140,144,230,192,128,136,211,64,0,0,0,0,182,120,43,135,126,16,68,52,174,195, +144,12,2,158,4,128,70,22,24,128,101,67,112,163,192,100,104,176,131,192,99, +32,176,99,192,226,115,30,1,79,4,68,28,16,54,0,0,41,254,232,116,62,204,7,21, +35,18,54,127,80,28,192,132,28,32,14,96,197,212,243,193,48,188,240,39,130, +236,224,175,131,117,2,178,112,145,139,163,145,131,114,70,46,142,218,27,182, +72,197,209,219,56,26,53,161,166,32,128,56,18,2,129,239,94,50,76,130,68,230, +202,113,160,167,146,94,163,134,66,161,164,227,226,231,146,51,198,249,147, +71,209,67,73,210,94,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15, +155,163,191,68,28,98,79,143,139,166,233,225,228,227,139,198,37,210,244,208, +24,137,112,151,153,27,36,5,100,224,146,105,184,100,196,95,18,84,141,159,9, +121,145,178,67,155,46,33,38,187,168,252,211,243,81,92,2,14,40,16,50,37,202, +160,150,154,67,152,148,20,28,76,156,89,26,105,158,63,232,16,44,150,129,18, +146,44,28,96,14,98,216,80,113,50,113,100,105,166,120,255,160,20,28,76,156, +113,75,34,78,63,236,3,6,133,41,35,31,242,18,195,152,147,226,27,61,138,41, +140,16,98,79,148,67,103,177,69,45,136,49,39,196,54,122,58,212,83,26,36,196, +159,40,134,207,71,90,138,92,16,98,79,136,108,244,244,168,166,56,73,137,62, +81,13,158,158,149,20,186,40,196,159,10,183,2,122,122,84,82,240,163,18,124, +42,220,9,235,106,81,75,225,228,73,241,13,158,197,54,198,8,145,39,202,33, +179,216,166,214,196,72,147,226,27,61,29,106,109,141,19,34,79,148,67,103, +163,173,77,174,8,145,39,196,54,122,122,84,219,28,38,68,159,40,134,207,79, +74,155,93,21,34,79,133,91,129,61,61,42,109,120,84,137,62,21,110,4,245,181, +41,181,248,56,224,28,24,80,113,50,113,100,105,166,120,255,160,20,28,76,156, +113,75,34,78,63,236,3,6,133,41,35,31,242,11,174,254,160,34,84,8,35,16,98, +146,38,55,32,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,30,7,224,0, +0,0,6,56,199,161,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,30,7,224, +0,0,0,6,55,36,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,30,7,224, +0,0,0,10,40,11,91,133,199,172,8,111,248,128,239,88,16,222,56,191,242,49, +198,69,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0,0, +49,185,65,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0, +0,49,198,77,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0, +0,0,49,185,97,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0, +0,0,49,198,85,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0, +0,0,49,185,129,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0, +0,0,0,49,198,93,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0, +0,0,0,49,185,161,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64, +0,0,0,0,49,198,101,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16, +64,0,0,0,0,49,185,193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0, +16,64,0,0,0,0,49,198,109,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0, +0,16,64,0,0,0,0,49,185,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192, +0,0,16,64,0,0,0,0,49,198,117,8,244,56,153,37,180,242,71,104,139,35,8,217, +192,0,0,16,64,0,0,0,0,49,186,1,8,244,56,153,37,180,242,71,104,139,35,8,217, +192,0,0,32,64,0,0,0,0,49,198,125,8,244,56,153,37,180,242,71,104,139,35,8, +217,192,0,0,32,64,0,0,0,0,32,232,130,0,97,57,162,4,245,72,10,68,184,70,137, +195,67,77,175,32,66,37,192,208,165,36,117,196,10,14,38,78,44,141,52,207, +169,64,56,156,199,130,36,160,141,146,52,38,32,76,72,1,246,136,235,103,177, +69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37,20, +65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142,183, +86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136,235, +103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20,138,46, +36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161,37,20, +170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208,146,138, +70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89,58,18, +81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214,207,161, +37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207,161,37,22, +176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,207,98,155,75, +27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,78,209,29,108, +244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,146,155,76,25, +104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,104,142,182,122, +122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,146,155,69,25, +104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,217,233,233, +116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,162,137,147, +133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,77,156,109, +162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,117,179,234, +201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,162,100,226, +27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,59,22,53,91,0,2, +21,11,94,181,128,196,133,0,185,80,32,56,156,199,130,36,160,72,16,78,126,53, +144,5,146,208,34,82,72,1,109,20,76,155,40,32,233,0,115,70,130,8,209,56,104, +105,187,252,193,3,17,162,112,201,242,18,65,211,0,230,149,132,17,162,112, +208,211,119,248,0,82,130,96,95,127,128,130,80,102,186,36,232,92,206,255,1, +80,48,200,39,12,158,241,64, }; #else #error invalid endianness defines #endif #endif /* DUK_USE_ROM_OBJECTS */ -#line 1 "duk_error_macros.c" /* - * Error, fatal, and panic handling. + * Error and fatal handling. */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ #define DUK__ERRFMT_BUFSIZE 256 /* size for formatting buffers */ @@ -9817,69 +10445,72 @@ DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) { #if defined(DUK_USE_VERBOSE_ERRORS) #if defined(DUK_USE_PARANOID_ERRORS) -DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name) { +DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) { DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)", - expect_name, duk_get_type_name((duk_context *) thr, index), (long) index); + expect_name, duk_get_type_name((duk_context *) thr, idx), (long) idx); } #else -DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name) { +DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) { DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)", - expect_name, duk_push_string_readable((duk_context *) thr, index), (long) index); + expect_name, duk_push_string_readable((duk_context *) thr, idx), (long) idx); } #endif -DUK_INTERNAL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { - DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, message); +DUK_INTERNAL void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber) { + DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_INTERNAL_ERROR); } -DUK_INTERNAL void duk_err_api_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index) { - DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_API_ERROR, "invalid stack index %ld", (long) (index)); +DUK_INTERNAL void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber) { + DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_ALLOC_FAILED); } -DUK_INTERNAL void duk_err_api(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { - DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_API_ERROR, message); +DUK_INTERNAL void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { + DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, message); } -DUK_INTERNAL void duk_err_unimplemented_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) { - DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_UNIMPLEMENTED_ERROR, DUK_STR_UNIMPLEMENTED); +DUK_INTERNAL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { + DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, message); } -#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT) -DUK_INTERNAL void duk_err_unsupported_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) { - DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_UNSUPPORTED_ERROR, DUK_STR_UNSUPPORTED); +DUK_INTERNAL void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx) { + DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, "invalid stack index %ld", (long) (idx)); } -#endif -DUK_INTERNAL void duk_err_internal_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) { - DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_INTERNAL_ERROR, DUK_STR_INTERNAL_ERROR); +DUK_INTERNAL void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber) { + DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK); } -DUK_INTERNAL void duk_err_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { - DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_INTERNAL_ERROR, message); +DUK_INTERNAL void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber) { + DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_ARGS); } -DUK_INTERNAL void duk_err_alloc(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { - DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ALLOC_ERROR, message); +DUK_INTERNAL void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber) { + DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_STATE); +} +DUK_INTERNAL void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber) { + DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_TRAP_RESULT); } #else /* The file/line arguments are NULL and 0, they're ignored by DUK_ERROR_RAW() * when non-verbose errors are used. */ -DUK_INTERNAL void duk_err_type(duk_hthread *thr) { - DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_TYPE_ERROR, NULL); + +DUK_NORETURN(DUK_LOCAL_DECL void duk__err_shared(duk_hthread *thr, duk_uint_t code)); +DUK_LOCAL void duk__err_shared(duk_hthread *thr, duk_uint_t code) { + DUK_ERROR_RAW(thr, NULL, 0, code, NULL); } -DUK_INTERNAL void duk_err_api(duk_hthread *thr) { - DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_API_ERROR, NULL); +DUK_INTERNAL void duk_err_error(duk_hthread *thr) { + duk__err_shared(thr, DUK_ERR_ERROR); } DUK_INTERNAL void duk_err_range(duk_hthread *thr) { - DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_RANGE_ERROR, NULL); + duk__err_shared(thr, DUK_ERR_RANGE_ERROR); } -DUK_INTERNAL void duk_err_syntax(duk_hthread *thr) { - DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_SYNTAX_ERROR, NULL); +DUK_INTERNAL void duk_err_eval(duk_hthread *thr) { + duk__err_shared(thr, DUK_ERR_EVAL_ERROR); } -DUK_INTERNAL void duk_err_unimplemented(duk_hthread *thr) { - DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_UNIMPLEMENTED_ERROR, NULL); +DUK_INTERNAL void duk_err_reference(duk_hthread *thr) { + duk__err_shared(thr, DUK_ERR_REFERENCE_ERROR); } -DUK_INTERNAL void duk_err_unsupported(duk_hthread *thr) { - DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_UNSUPPORTED_ERROR, NULL); +DUK_INTERNAL void duk_err_syntax(duk_hthread *thr) { + duk__err_shared(thr, DUK_ERR_SYNTAX_ERROR); } -DUK_INTERNAL void duk_err_internal(duk_hthread *thr) { - DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_INTERNAL_ERROR, NULL); +DUK_INTERNAL void duk_err_type(duk_hthread *thr) { + duk__err_shared(thr, DUK_ERR_TYPE_ERROR); } -DUK_INTERNAL void duk_err_alloc(duk_hthread *thr) { - DUK_ERROR_RAW(thr, NULL, thr, DUK_ERR_ALLOC_ERROR, NULL); +DUK_INTERNAL void duk_err_uri(duk_hthread *thr) { + duk__err_shared(thr, DUK_ERR_URI_ERROR); } #endif @@ -9887,68 +10518,37 @@ DUK_INTERNAL void duk_err_alloc(duk_hthread *thr) { * Default fatal error handler */ -DUK_INTERNAL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg) { - DUK_UNREF(ctx); -#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 - /* omit print */ -#endif - DUK_D(DUK_DPRINT("default fatal handler called, code %ld -> calling DUK_PANIC()", (long) code)); - DUK_PANIC(code, msg); - DUK_UNREACHABLE(); -} - -/* - * Default panic handler - */ - -#if !defined(DUK_USE_PANIC_HANDLER) -DUK_INTERNAL void duk_default_panic_handler(duk_errcode_t code, const char *msg) { -#if defined(DUK_USE_FILE_IO) - DUK_FPRINTF(DUK_STDERR, "PANIC %ld: %s (" -#if defined(DUK_USE_PANIC_ABORT) - "calling abort" -#elif defined(DUK_USE_PANIC_EXIT) - "calling exit" -#elif defined(DUK_USE_PANIC_SEGFAULT) - "segfaulting on purpose" -#else -#error no DUK_USE_PANIC_xxx macro defined -#endif - ")\n", (long) code, (const char *) (msg ? msg : "null")); - DUK_FFLUSH(DUK_STDERR); -#else - /* omit print */ - DUK_UNREF(code); +DUK_INTERNAL void duk_default_fatal_handler(void *udata, const char *msg) { + DUK_UNREF(udata); DUK_UNREF(msg); -#endif -#if defined(DUK_USE_PANIC_ABORT) - DUK_ABORT(); -#elif defined(DUK_USE_PANIC_EXIT) - DUK_EXIT(-1); -#elif defined(DUK_USE_PANIC_SEGFAULT) - /* exit() afterwards to satisfy "noreturn" */ - DUK_CAUSE_SEGFAULT(); /* SCANBUILD: "Dereference of null pointer", normal */ - DUK_EXIT(-1); +#if defined(DUK_USE_FATAL_HANDLER) + /* duk_config.h provided a custom default fatal handler. */ + DUK_D(DUK_DPRINT("custom default fatal error handler called: %s", msg ? msg : "NULL")); + DUK_USE_FATAL_HANDLER(udata, msg); #else -#error no DUK_USE_PANIC_xxx macro defined + /* Default behavior is to abort() on error. There's no printout + * which makes this awkward, so it's always recommended to use an + * explicit fatal error handler. + */ + DUK_D(DUK_DPRINT("built-in default fatal error handler called: %s", msg ? msg : "NULL")); + DUK_ABORT(); #endif - DUK_UNREACHABLE(); + DUK_D(DUK_DPRINT("fatal error handler returned, enter forever loop")); + for (;;) { + /* Loop forever to ensure we don't return. */ + } } -#endif /* !DUK_USE_PANIC_HANDLER */ +/* automatic undefs */ #undef DUK__ERRFMT_BUFSIZE -#line 1 "duk_unicode_support.c" /* * Various Unicode help functions for character classification predicates, * case conversion, decoding, etc. */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ /* * Fast path tables @@ -10195,8 +10795,17 @@ DUK_INTERNAL duk_small_int_t duk_unicode_decode_xutf8(duk_hthread *thr, const du while (n > 0) { DUK_ASSERT(p >= ptr_start && p < ptr_end); - res = res << 6; - res += (duk_uint32_t) ((*p++) & 0x3f); + ch = (duk_uint_fast8_t) (*p++); +#if 0 + if (ch & 0xc0 != 0x80) { + /* not a continuation byte */ + p--; + *ptr = p; + *out_cp = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; + return 1; + } +#endif + res = (res << 6) + (duk_uint32_t) (ch & 0x3f); n--; } @@ -10215,7 +10824,7 @@ DUK_INTERNAL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, if (duk_unicode_decode_xutf8(thr, ptr, ptr_start, ptr_end, &cp)) { return cp; } - DUK_ERROR_INTERNAL(thr, "utf-8 decode failed"); /* XXX: 'internal error' is a bit of a misnomer */ + DUK_ERROR_INTERNAL(thr); DUK_UNREACHABLE(); return 0; } @@ -10230,7 +10839,7 @@ DUK_INTERNAL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, * chosen from several variants, based on x64 gcc -O2 testing. See: * https://github.com/svaarala/duktape/pull/422 * - * NOTE: must match src/dukutil.py:duk_unicode_unvalidated_utf8_length(). + * NOTE: must match tools/dukutil.py:duk_unicode_unvalidated_utf8_length(). */ #if defined(DUK_USE_PREFER_SIZE) @@ -10341,7 +10950,7 @@ DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *d * Used for slow path Unicode matching. */ -/* Must match src/extract_chars.py, generate_match_table3(). */ +/* Must match tools/extract_chars.py, generate_match_table3(). */ DUK_LOCAL duk_uint32_t duk__uni_decode_value(duk_bitdecoder_ctx *bd_ctx) { duk_uint32_t t; @@ -10412,7 +11021,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp) { * FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; * * It also specifies any Unicode category 'Zs' characters as white - * space. These can be extracted with the "src/extract_chars.py" script. + * space. These can be extracted with the "tools/extract_chars.py" script. * Current result: * * RAW OUTPUT: @@ -10519,7 +11128,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp) * * The "UnicodeLetter" alternative of the production allows letters * from various Unicode categories. These can be extracted with the - * "src/extract_chars.py" script. + * "tools/extract_chars.py" script. * * Because the result has hundreds of Unicode codepoint ranges, matching * for any values >= 0x80 are done using a very slow range-by-range scan @@ -10550,7 +11159,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp) /* Non-ASCII slow path (range-by-range linear comparison), very slow */ -#ifdef DUK_USE_SOURCE_NONBMP +#if defined(DUK_USE_SOURCE_NONBMP) if (duk__uni_range_match(duk_unicode_ids_noa, (duk_size_t) sizeof(duk_unicode_ids_noa), (duk_codepoint_t) cp)) { @@ -10616,7 +11225,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp) * The matching code reuses the "identifier start" tables, and then * consults a separate range set for characters in "identifier part" * but not in "identifier start". These can be extracted with the - * "src/extract_chars.py" script. + * "tools/extract_chars.py" script. * * UnicodeCombiningMark -> categories Mn, Mc * UnicodeDigit -> categories Nd @@ -10640,7 +11249,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp) /* Non-ASCII slow path (range-by-range linear comparison), very slow */ -#ifdef DUK_USE_SOURCE_NONBMP +#if defined(DUK_USE_SOURCE_NONBMP) if (duk__uni_range_match(duk_unicode_ids_noa, sizeof(duk_unicode_ids_noa), (duk_codepoint_t) cp) || @@ -10699,7 +11308,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) { /* Non-ASCII slow path (range-by-range linear comparison), very slow */ -#ifdef DUK_USE_SOURCE_NONBMP +#if defined(DUK_USE_SOURCE_NONBMP) if (duk__uni_range_match(duk_unicode_ids_noa, sizeof(duk_unicode_ids_noa), (duk_codepoint_t) cp) && @@ -10731,14 +11340,14 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) { /* * Complex case conversion helper which decodes a bit-packed conversion - * control stream generated by unicode/extract_caseconv.py. The conversion + * control stream generated by tools/extract_caseconv.py. The conversion * is very slow because it runs through the conversion data in a linear * fashion to save space (which is why ASCII characters have a special * fast path before arriving here). * * The particular bit counts etc have been determined experimentally to * be small but still sufficient, and must match the Python script - * (src/extract_caseconv.py). + * (tools/extract_caseconv.py). * * The return value is the case converted codepoint or -1 if the conversion * results in multiple characters (this is useful for regexp Canonicalization @@ -10798,7 +11407,7 @@ duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr, } /* 1:1 conversion */ - n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6); + n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7); DUK_DDD(DUK_DDDPRINT("checking 1:1 conversions (count %ld)", (long) n)); while (n--) { start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); @@ -10953,7 +11562,7 @@ DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_in const duk_uint8_t *p, *p_start, *p_end; duk_codepoint_t prev, curr, next; - h_input = duk_require_hstring(ctx, -1); + h_input = duk_require_hstring(ctx, -1); /* Accept symbols. */ DUK_ASSERT(h_input != NULL); bw = &bw_alloc; @@ -10973,7 +11582,7 @@ DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_in curr = next; next = -1; if (p < p_end) { - next = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); + next = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); } else { /* end of input and last char has been processed */ if (curr < 0) { @@ -11000,11 +11609,12 @@ DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_in } DUK_BW_COMPACT(thr, bw); - duk_to_string(ctx, -1); /* invalidates h_buf pointer */ - duk_remove(ctx, -2); + (void) duk_buffer_to_string(ctx, -1); /* Safe, output is encoded. */ + /* invalidates h_buf pointer */ + duk_remove_m2(ctx); } -#ifdef DUK_USE_REGEXP_SUPPORT +#if defined(DUK_USE_REGEXP_SUPPORT) /* * Canonicalize() abstract operation needed for canonicalization of individual @@ -11116,12 +11726,11 @@ DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = { }; #endif /* DUK_USE_REGEXP_SUPPORT */ -#line 1 "duk_util_misc.c" /* * Misc util stuff */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ /* * Lowercase digits for radix values 2 to 36. Also doubles as lowercase @@ -11339,7 +11948,189 @@ DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) { } } #endif -#line 1 "duk_util_hashprime.c" + +/* + * Miscellaneous coercion / clamping helpers. + */ + +/* Check whether a duk_double_t is a whole number in the 32-bit range (reject + * negative zero), and if so, return a duk_int32_t. + * For compiler use: don't allow negative zero as it will cause trouble with + * LDINT+LDINTX, positive zero is OK. + */ +DUK_INTERNAL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival) { + duk_int32_t t; + + t = (duk_int32_t) x; + if (!((duk_double_t) t == x)) { + return 0; + } + if (t == 0) { + duk_double_union du; + du.d = x; + if (DUK_DBLUNION_HAS_SIGNBIT(&du)) { + return 0; + } + } + *ival = t; + return 1; +} + +/* Check whether a duk_double_t is a whole number in the 32-bit range, and if + * so, return a duk_int32_t. + */ +DUK_INTERNAL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival) { + duk_int32_t t; + + t = (duk_int32_t) x; + if (!((duk_double_t) t == x)) { + return 0; + } + *ival = t; + return 1; +} + +/* + * IEEE double checks + */ + +DUK_INTERNAL duk_bool_t duk_double_is_anyinf(duk_double_t x) { + duk_double_union du; + du.d = x; + return DUK_DBLUNION_IS_ANYINF(&du); +} + +DUK_INTERNAL duk_bool_t duk_double_is_posinf(duk_double_t x) { + duk_double_union du; + du.d = x; + return DUK_DBLUNION_IS_POSINF(&du); +} + +DUK_INTERNAL duk_bool_t duk_double_is_neginf(duk_double_t x) { + duk_double_union du; + du.d = x; + return DUK_DBLUNION_IS_NEGINF(&du); +} + +DUK_INTERNAL duk_bool_t duk_double_is_nan(duk_double_t x) { + duk_double_union du; + du.d = x; + /* Assumes we're dealing with a Duktape internal NaN which is + * NaN normalized if duk_tval requires it. + */ + DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); + return DUK_DBLUNION_IS_NAN(&du); +} + +DUK_INTERNAL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x) { + duk_double_union du; + du.d = x; + /* Assumes we're dealing with a Duktape internal NaN which is + * NaN normalized if duk_tval requires it. + */ + DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); + return DUK_DBLUNION_IS_NAN(&du) || DUK_DBLUNION_IS_ANYZERO(&du); +} + +DUK_INTERNAL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x) { + duk_double_union du; + du.d = x; + /* If exponent is 0x7FF the argument is either a NaN or an + * infinity. We don't need to check any other fields. + */ +#if defined(DUK_USE_64BIT_OPS) +#if defined(DUK_USE_DOUBLE_ME) + return (du.ull[DUK_DBL_IDX_ULL0] & 0x000000007ff00000ULL) == 0x000000007ff00000ULL; +#else + return (du.ull[DUK_DBL_IDX_ULL0] & 0x7ff0000000000000ULL) == 0x7ff0000000000000ULL; +#endif +#else + return (du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL; +#endif +} + +DUK_INTERNAL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x) { + duk_double_union du; +#if defined(DUK_USE_64BIT_OPS) + duk_uint64_t t; +#else + duk_uint32_t t; +#endif + du.d = x; +#if defined(DUK_USE_64BIT_OPS) +#if defined(DUK_USE_DOUBLE_ME) + t = du.ull[DUK_DBL_IDX_ULL0] & 0x000000007ff00000ULL; + if (t == 0x0000000000000000ULL) { + t = du.ull[DUK_DBL_IDX_ULL0] & 0x0000000080000000ULL; + return t == 0; + } + if (t == 0x000000007ff00000UL) { + return 1; + } +#else + t = du.ull[DUK_DBL_IDX_ULL0] & 0x7ff0000000000000ULL; + if (t == 0x0000000000000000ULL) { + t = du.ull[DUK_DBL_IDX_ULL0] & 0x8000000000000000ULL; + return t == 0; + } + if (t == 0x7ff0000000000000ULL) { + return 1; + } +#endif +#else + t = du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL; + if (t == 0x00000000UL) { + return DUK_DBLUNION_IS_ANYZERO(&du); + } + if (t == 0x7ff00000UL) { + return 1; + } +#endif + return 0; +} + +DUK_INTERNAL duk_small_uint_t duk_double_signbit(duk_double_t x) { + duk_double_union du; + du.d = x; + return (duk_small_uint_t) DUK_DBLUNION_GET_SIGNBIT(&du); +} + +DUK_INTERNAL duk_double_t duk_double_trunc_towards_zero(duk_double_t x) { + /* XXX: optimize */ + duk_small_int_t s = duk_double_signbit(x); + x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */ + if (s) { + x = -x; + } + return x; +} + +DUK_INTERNAL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y) { + duk_double_union du1; + duk_double_union du2; + du1.d = x; + du2.d = y; + + return (((du1.ui[DUK_DBL_IDX_UI0] ^ du2.ui[DUK_DBL_IDX_UI0]) & 0x80000000UL) == 0); +} + +DUK_INTERNAL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y) { + /* Doesn't replicate fmin() behavior exactly: for fmin() if one + * argument is a NaN, the other argument should be returned. + * Duktape doesn't rely on this behavior so the replacement can + * be simplified. + */ + return (x < y ? x : y); +} + +DUK_INTERNAL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y) { + /* Doesn't replicate fmax() behavior exactly: for fmax() if one + * argument is a NaN, the other argument should be returned. + * Duktape doesn't rely on this behavior so the replacement can + * be simplified. + */ + return (x > y ? x : y); +} /* * Round a number upwards to a prime (not usually the nearest one). * @@ -11353,7 +12144,7 @@ DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) { * probe sequence steps in duk_hobject and duk_heap stringtable. */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ /* Awkward inclusion condition: drop out of compilation if not needed by any * call site: object hash part or probing stringtable. @@ -11397,7 +12188,7 @@ DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) { } /* prediction: portable variant using doubles if 64-bit values not available */ -#ifdef DUK_USE_64BIT_OPS +#if defined(DUK_USE_64BIT_OPS) curr = (duk_uint32_t) ((((duk_uint64_t) curr) * ((duk_uint64_t) DUK__HASH_SIZE_RATIO)) >> 10); #else /* 32-bit x 11-bit = 43-bit, fits accurately into a double */ @@ -11417,12 +12208,14 @@ DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) { } #endif /* DUK_USE_HOBJECT_HASH_PART || DUK_USE_STRTAB_PROBE */ -#line 1 "duk_hobject_class.c" + +/* automatic undefs */ +#undef DUK__HASH_SIZE_RATIO /* * Hobject Ecmascript [[Class]]. */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ #if (DUK_STRIDX_UC_ARGUMENTS > 255) #error constant too large @@ -11469,9 +12262,6 @@ DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) { #if (DUK_STRIDX_DEC_ENV > 255) #error constant too large #endif -#if (DUK_STRIDX_UC_BUFFER > 255) -#error constant too large -#endif #if (DUK_STRIDX_UC_POINTER > 255) #error constant too large #endif @@ -11517,23 +12307,23 @@ DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) { /* Note: assumes that these string indexes are 8-bit, genstrings.py must ensure that */ DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = { - DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */ - DUK_STRIDX_UC_ARGUMENTS, + DUK_STRIDX_EMPTY_STRING, /* NONE, intentionally empty */ + DUK_STRIDX_UC_OBJECT, DUK_STRIDX_ARRAY, + DUK_STRIDX_UC_FUNCTION, + DUK_STRIDX_UC_ARGUMENTS, DUK_STRIDX_UC_BOOLEAN, DUK_STRIDX_DATE, DUK_STRIDX_UC_ERROR, - DUK_STRIDX_UC_FUNCTION, DUK_STRIDX_JSON, DUK_STRIDX_MATH, DUK_STRIDX_UC_NUMBER, - DUK_STRIDX_UC_OBJECT, DUK_STRIDX_REG_EXP, DUK_STRIDX_UC_STRING, DUK_STRIDX_GLOBAL, + DUK_STRIDX_UC_SYMBOL, DUK_STRIDX_OBJ_ENV, DUK_STRIDX_DEC_ENV, - DUK_STRIDX_UC_BUFFER, DUK_STRIDX_UC_POINTER, DUK_STRIDX_UC_THREAD, DUK_STRIDX_ARRAY_BUFFER, @@ -11550,7 +12340,6 @@ DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = { DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */ DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */ }; -#line 1 "duk_alloc_default.c" /* * Default allocation functions. * @@ -11558,7 +12347,7 @@ DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = { * a NULL or a unique pointer which is a no-op for free. */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ #if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS) DUK_INTERNAL void *duk_default_alloc_function(void *udata, duk_size_t size) { @@ -11585,20 +12374,19 @@ DUK_INTERNAL void duk_default_free_function(void *udata, void *ptr) { DUK_ANSI_FREE(ptr); } #endif /* DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS */ -#line 1 "duk_api_buffer.c" /* * Buffer */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ -DUK_EXTERNAL void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size_t new_size) { +DUK_EXTERNAL void *duk_resize_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t new_size) { duk_hthread *thr = (duk_hthread *) ctx; duk_hbuffer_dynamic *h; DUK_ASSERT_CTX_VALID(ctx); - h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index); + h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, idx); DUK_ASSERT(h != NULL); if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) { @@ -11611,7 +12399,7 @@ DUK_EXTERNAL void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h); } -DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) { +DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { duk_hthread *thr = (duk_hthread *) ctx; duk_hbuffer_dynamic *h; void *ptr; @@ -11619,7 +12407,7 @@ DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_ DUK_ASSERT(ctx != NULL); - h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index); + h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, idx); DUK_ASSERT(h != NULL); if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) { @@ -11642,13 +12430,13 @@ DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_ return ptr; } -DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr, duk_size_t len) { +DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t idx, void *ptr, duk_size_t len) { duk_hthread *thr = (duk_hthread *) ctx; duk_hbuffer_external *h; DUK_ASSERT(ctx != NULL); - h = (duk_hbuffer_external *) duk_require_hbuffer(ctx, index); + h = (duk_hbuffer_external *) duk_require_hbuffer(ctx, idx); DUK_ASSERT(h != NULL); if (!DUK_HBUFFER_HAS_EXTERNAL(h)) { @@ -11659,7 +12447,6 @@ DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(thr->heap, h, ptr); DUK_HBUFFER_EXTERNAL_SET_SIZE(h, len); } -#line 1 "duk_api_bytecode.c" /* * Bytecode dump/load * @@ -11672,7 +12459,7 @@ DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr * validated which is not easy to do with indirect register references etc. */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ #if defined(DUK_USE_BYTECODE_DUMP_SUPPORT) @@ -11700,7 +12487,7 @@ DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_context *ctx, duk_uint8_t *p) { duk_uint8_t *buf; len = DUK_RAW_READ_U32_BE(p); - buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len); + buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, (duk_size_t) len); DUK_ASSERT(buf != NULL); DUK_MEMCPY((void *) buf, (const void *) p, (size_t) len); p += len; @@ -11867,19 +12654,22 @@ DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_b */ varname = DUK_TVAL_GET_STRING(tv_val); DUK_ASSERT(varname != NULL); + DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1); /* won't be confused with terminator */ DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p); p = duk__dump_hstring_raw(p, varname); } } + } else { + DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit empty list")); } p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Formals */ return p; } -static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) { +static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompfunc *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) { duk_hthread *thr; duk_tval *tv, *tv_end; duk_instr_t *ins, *ins_end; @@ -11900,29 +12690,29 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func "code=[%p,%p[ (%ld bytes, %ld items)", (void *) func, (void *) p, - (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func), - (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func), - (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(thr->heap, func), - (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func), - (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func), - (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func), - (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(thr->heap, func), - (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func), - (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func), - (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func), - (long) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(thr->heap, func), - (long) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func))); + (void *) DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func), + (void *) DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func), + (long) DUK_HCOMPFUNC_GET_CONSTS_SIZE(thr->heap, func), + (long) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func), + (void *) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func), + (void *) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func), + (long) DUK_HCOMPFUNC_GET_FUNCS_SIZE(thr->heap, func), + (long) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func), + (void *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func), + (void *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func), + (long) DUK_HCOMPFUNC_GET_CODE_SIZE(thr->heap, func), + (long) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func))); DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL); /* ensures no overflow */ - count_instr = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func); + count_instr = (duk_uint32_t) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func); p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3 * 4 + 2 * 2 + 3 * 4 + count_instr * 4, p); /* Fixed header info. */ tmp32 = count_instr; DUK_RAW_WRITE_U32_BE(p, tmp32); - tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func); + tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func); DUK_RAW_WRITE_U32_BE(p, tmp32); - tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func); + tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func); DUK_RAW_WRITE_U32_BE(p, tmp32); tmp16 = func->nregs; DUK_RAW_WRITE_U16_BE(p, tmp16); @@ -11937,14 +12727,14 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func DUK_RAW_WRITE_U32_BE(p, 0); DUK_RAW_WRITE_U32_BE(p, 0); #endif - tmp32 = ((duk_heaphdr *) func)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK; + tmp32 = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) func); /* masks flags, only duk_hobject flags */ DUK_RAW_WRITE_U32_BE(p, tmp32); /* Bytecode instructions: endian conversion needed unless * platform is big endian. */ - ins = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func); - ins_end = DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func); + ins = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func); + ins_end = DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func); DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr); #if defined(DUK_USE_INTEGER_BE) DUK_MEMCPY((void *) p, (const void *) ins, (size_t) (ins_end - ins)); @@ -11958,8 +12748,8 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func #endif /* Constants: variable size encoding. */ - tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func); - tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func); + tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func); + tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func); while (tv != tv_end) { /* constants are strings or numbers now */ DUK_ASSERT(DUK_TVAL_IS_STRING(tv) || @@ -11983,8 +12773,8 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func } /* Inner functions recursively. */ - fn = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func); - fn_end = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func); + fn = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func); + fn_end = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func); while (fn != fn_end) { /* XXX: This causes recursion up to inner function depth * which is normally not an issue, e.g. mark-and-sweep uses @@ -11992,11 +12782,13 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func * this would mean some sort of a work list or just refusing * to serialize deep functions. */ - DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(*fn)); - p = duk__dump_func(ctx, (duk_hcompiledfunction *) *fn, bw_ctx, p); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(*fn)); + p = duk__dump_func(ctx, (duk_hcompfunc *) *fn, bw_ctx, p); fn++; } + /* Lexenv and varenv are not dumped. */ + /* Object extra properties. * * There are some difference between function templates and functions. @@ -12005,9 +12797,15 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func */ p = duk__dump_uint32_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_LENGTH, (duk_uint32_t) func->nargs); +#if defined(DUK_USE_FUNC_NAME_PROPERTY) p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_NAME); +#endif +#if defined(DUK_USE_FUNC_FILENAME_PROPERTY) p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_FILE_NAME); +#endif +#if defined(DUK_USE_PC2LINE) p = duk__dump_buffer_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_INT_PC2LINE); +#endif p = duk__dump_varmap(thr, p, bw_ctx, (duk_hobject *) func); p = duk__dump_formals(thr, p, bw_ctx, (duk_hobject *) func); @@ -12032,7 +12830,7 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t *p_end) { duk_hthread *thr; - duk_hcompiledfunction *h_fun; + duk_hcompfunc *h_fun; duk_hbuffer *h_data; duk_size_t data_size; duk_uint32_t count_instr, count_const, count_funcs; @@ -12044,6 +12842,8 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t duk_idx_t idx_base; duk_tval *tv1; duk_uarridx_t arr_idx; + duk_hobject *func_env; + duk_bool_t need_pop; /* XXX: There's some overlap with duk_js_closure() here, but * seems difficult to share code. Ensure that the final function @@ -12078,13 +12878,13 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t /* Push function object, init flags etc. This must match * duk_js_push_closure() quite carefully. */ - duk_push_compiledfunction(ctx); - h_fun = duk_get_hcompiledfunction(ctx, -1); + h_fun = duk_push_hcompfunc(ctx); DUK_ASSERT(h_fun != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) h_fun)); - DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, h_fun) == NULL); - DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, h_fun) == NULL); - DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, h_fun) == NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) h_fun)); + DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun) == NULL); + DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, h_fun) == NULL); + DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, h_fun) == NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); h_fun->nregs = DUK_RAW_READ_U16_BE(p); h_fun->nargs = DUK_RAW_READ_U16_BE(p); @@ -12095,25 +12895,25 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t p += 8; /* skip line info */ #endif - /* duk_hcompiledfunction flags; quite version specific */ + /* duk_hcompfunc flags; quite version specific */ tmp32 = DUK_RAW_READ_U32_BE(p); - DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32); + DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32); /* masks flags to only change duk_hobject flags */ /* standard prototype */ DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &h_fun->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); /* assert just a few critical flags */ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h_fun) == DUK_HTYPE_OBJECT); - DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&h_fun->obj)); - DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(&h_fun->obj)); - DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&h_fun->obj)); + DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&h_fun->obj)); DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&h_fun->obj)); DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&h_fun->obj)); DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&h_fun->obj)); DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun->obj)); /* Create function 'data' buffer but don't attach it yet. */ - fun_data = (duk_uint8_t *) duk_push_fixed_buffer(ctx, data_size); + fun_data = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, data_size); DUK_ASSERT(fun_data != NULL); /* Load bytecode instructions. */ @@ -12150,7 +12950,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t duk_double_t val; DUK__ASSERT_LEFT(8); val = DUK_RAW_READ_DOUBLE_BE(p); - DUK_TVAL_SET_NUMBER_CHKFAST(&tv_tmp, val); + DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(&tv_tmp, val); duk_push_tval(ctx, &tv_tmp); break; } @@ -12177,10 +12977,9 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t * them afterwards. */ - h_data = (duk_hbuffer *) duk_get_hbuffer(ctx, idx_base + 1); - DUK_ASSERT(h_data != NULL); + h_data = (duk_hbuffer *) duk_known_hbuffer(ctx, idx_base + 1); DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data)); - DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, h_fun, h_data); + DUK_HCOMPFUNC_SET_DATA(thr->heap, h_fun, h_data); DUK_HBUFFER_INCREF(thr, h_data); tv1 = duk_get_tval(ctx, idx_base + 2); /* may be NULL if no constants or inner funcs */ @@ -12197,7 +12996,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t tv1 += count_const; } - DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q); + DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q); for (n = count_funcs; n > 0; n--) { duk_hobject *h_obj; @@ -12211,7 +13010,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t q += sizeof(duk_hobject *); } - DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q); + DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q); /* The function object is now reachable and refcounts are fine, * so we can pop off all the temporaries. @@ -12222,42 +13021,64 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t /* Setup function properties. */ tmp32 = DUK_RAW_READ_U32_BE(p); duk_push_u32(ctx, tmp32); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); - p = duk__load_string_raw(ctx, p); +#if defined(DUK_USE_FUNC_NAME_PROPERTY) + p = duk__load_string_raw(ctx, p); /* -> [ func funcname ] */ + func_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; + DUK_ASSERT(func_env != NULL); + need_pop = 0; if (DUK_HOBJECT_HAS_NAMEBINDING((duk_hobject *) h_fun)) { /* Original function instance/template had NAMEBINDING. * Must create a lexical environment on loading to allow * recursive functions like 'function foo() { foo(); }'. */ - duk_hobject *proto; + duk_hobject *new_env; - proto = thr->builtins[DUK_BIDX_GLOBAL_ENV]; - (void) duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - proto); - duk_dup(ctx, -2); /* -> [ func funcname env funcname ] */ + new_env = duk_push_object_helper_proto(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), + func_env); + DUK_ASSERT(new_env != NULL); + func_env = new_env; + + duk_dup_m2(ctx); /* -> [ func funcname env funcname ] */ duk_dup(ctx, idx_base); /* -> [ func funcname env funcname func ] */ duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */ - duk_xdef_prop_stridx(ctx, idx_base, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC); - /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it - * will be ignored anyway - */ + + need_pop = 1; /* Need to pop env, but -after- updating h_fun and increfs. */ } - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); + DUK_ASSERT(func_env != NULL); + DUK_HCOMPFUNC_SET_LEXENV(thr->heap, h_fun, func_env); + DUK_HCOMPFUNC_SET_VARENV(thr->heap, h_fun, func_env); + DUK_HOBJECT_INCREF(thr, func_env); + DUK_HOBJECT_INCREF(thr, func_env); + if (need_pop) { + duk_pop(ctx); + } + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); +#endif /* DUK_USE_FUNC_NAME_PROPERTY */ +#if defined(DUK_USE_FUNC_FILENAME_PROPERTY) p = duk__load_string_raw(ctx, p); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C); +#endif /* DUK_USE_FUNC_FILENAME_PROPERTY */ - duk_push_object(ctx); - duk_dup(ctx, -2); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */ - duk_compact(ctx, -1); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); + if (DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_fun)) { + /* Restore empty external .prototype only for constructable + * functions. + */ + duk_push_object(ctx); + duk_dup_m2(ctx); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */ + duk_compact_m1(ctx); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); + } +#if defined(DUK_USE_PC2LINE) p = duk__load_buffer_raw(ctx, p); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC); +#endif /* DUK_USE_PC2LINE */ duk_push_object(ctx); /* _Varmap */ for (;;) { @@ -12271,9 +13092,14 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t duk_push_u32(ctx, tmp32); duk_put_prop(ctx, -3); } - duk_compact(ctx, -1); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE); + duk_compact_m1(ctx); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE); + /* If _Formals wasn't present in the original function, the list + * here will be empty. Same happens if _Formals was present but + * had zero length. We can omit _Formals from the result if its + * length is zero and matches nargs. + */ duk_push_array(ctx); /* _Formals */ for (arr_idx = 0; ; arr_idx++) { /* XXX: awkward */ @@ -12284,8 +13110,12 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t } duk_put_prop_index(ctx, -2, arr_idx); } - duk_compact(ctx, -1); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE); + if (arr_idx == 0 && h_fun->nargs == 0) { + duk_pop(ctx); + } else { + duk_compact_m1(ctx); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE); + } /* Return with final function pushed on stack top. */ DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(ctx, -1))); @@ -12298,7 +13128,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t DUK_EXTERNAL void duk_dump_function(duk_context *ctx) { duk_hthread *thr; - duk_hcompiledfunction *func; + duk_hcompfunc *func; duk_bufwriter_ctx bw_ctx_alloc; duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc; duk_uint8_t *p; @@ -12310,9 +13140,9 @@ DUK_EXTERNAL void duk_dump_function(duk_context *ctx) { * lookup the non-bound target function or reject bound functions. * For now, bound functions are rejected. */ - func = duk_require_hcompiledfunction(ctx, -1); + func = duk_require_hcompfunc(ctx, -1); DUK_ASSERT(func != NULL); - DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&func->obj)); + DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&func->obj)); /* Estimating the result size beforehand would be costly, so * start with a reasonable size and extend as needed. @@ -12327,7 +13157,7 @@ DUK_EXTERNAL void duk_dump_function(duk_context *ctx) { DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(ctx, -1))); - duk_remove(ctx, -2); /* [ ... func buf ] -> [ ... buf ] */ + duk_remove_m2(ctx); /* [ ... func buf ] -> [ ... buf ] */ } DUK_EXTERNAL void duk_load_function(duk_context *ctx) { @@ -12363,53 +13193,54 @@ DUK_EXTERNAL void duk_load_function(duk_context *ctx) { goto format_error; } - duk_remove(ctx, -2); /* [ ... buf func ] -> [ ... func ] */ + duk_remove_m2(ctx); /* [ ... buf func ] -> [ ... func ] */ return; format_error: DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED); } -#undef DUK__SER_MARKER -#undef DUK__SER_VERSION -#undef DUK__SER_STRING -#undef DUK__SER_NUMBER -#undef DUK__BYTECODE_INITIAL_ALLOC - #else /* DUK_USE_BYTECODE_DUMP_SUPPORT */ DUK_EXTERNAL void duk_dump_function(duk_context *ctx) { - DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx); + DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx); } DUK_EXTERNAL void duk_load_function(duk_context *ctx) { - DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx); + DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx); } #endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */ -#line 1 "duk_api_call.c" + +/* automatic undefs */ +#undef DUK__ASSERT_LEFT +#undef DUK__BYTECODE_INITIAL_ALLOC +#undef DUK__SER_MARKER +#undef DUK__SER_NUMBER +#undef DUK__SER_STRING +#undef DUK__SER_VERSION /* * Calls. * * Protected variants should avoid ever throwing an error. */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ /* Prepare value stack for a method call through an object property. * May currently throw an error e.g. when getting the property. */ -DUK_LOCAL void duk__call_prop_prep_stack(duk_context *ctx, duk_idx_t normalized_obj_index, duk_idx_t nargs) { +DUK_LOCAL void duk__call_prop_prep_stack(duk_context *ctx, duk_idx_t normalized_obj_idx, duk_idx_t nargs) { DUK_ASSERT_CTX_VALID(ctx); - DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_index=%ld, nargs=%ld, stacktop=%ld", - (long) normalized_obj_index, (long) nargs, (long) duk_get_top(ctx))); + DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_idx=%ld, nargs=%ld, stacktop=%ld", + (long) normalized_obj_idx, (long) nargs, (long) duk_get_top(ctx))); /* [... key arg1 ... argN] */ /* duplicate key */ duk_dup(ctx, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */ - duk_get_prop(ctx, normalized_obj_index); + duk_get_prop(ctx, normalized_obj_idx); DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(ctx, -1))); @@ -12419,7 +13250,7 @@ DUK_LOCAL void duk__call_prop_prep_stack(duk_context *ctx, duk_idx_t normalized_ /* [... func arg1 ... argN] */ - duk_dup(ctx, normalized_obj_index); + duk_dup(ctx, normalized_obj_idx); duk_insert(ctx, -nargs - 1); /* [... func this arg1 ... argN] */ @@ -12436,7 +13267,7 @@ DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) { idx_func = duk_get_top(ctx) - nargs - 1; if (idx_func < 0 || nargs < 0) { /* note that we can't reliably pop anything here */ - DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_TYPE_INVALID_ARGS(thr); } /* XXX: awkward; we assume there is space for this, overwrite @@ -12463,7 +13294,7 @@ DUK_EXTERNAL void duk_call_method(duk_context *ctx, duk_idx_t nargs) { idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */ if (idx_func < 0 || nargs < 0) { /* note that we can't reliably pop anything here */ - DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_TYPE_INVALID_ARGS(thr); } call_flags = 0; /* not protected, respect reclimit, not constructor */ @@ -12473,7 +13304,7 @@ DUK_EXTERNAL void duk_call_method(duk_context *ctx, duk_idx_t nargs) { call_flags); /* call_flags */ } -DUK_EXTERNAL void duk_call_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) { +DUK_EXTERNAL void duk_call_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs) { /* * XXX: if duk_handle_call() took values through indices, this could be * made much more sensible. However, duk_handle_call() needs to fudge @@ -12483,9 +13314,9 @@ DUK_EXTERNAL void duk_call_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t DUK_ASSERT_CTX_VALID(ctx); - obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */ + obj_idx = duk_require_normalize_index(ctx, obj_idx); /* make absolute */ - duk__call_prop_prep_stack(ctx, obj_index, nargs); + duk__call_prop_prep_stack(ctx, obj_idx, nargs); duk_call_method(ctx, nargs); } @@ -12511,7 +13342,7 @@ DUK_EXTERNAL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs) { * might STILL throw an out-of-memory error or some other internal * fatal error. */ - DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_TYPE_INVALID_ARGS(thr); return DUK_EXEC_ERROR; /* unreachable */ } @@ -12540,7 +13371,7 @@ DUK_EXTERNAL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs) { idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */ if (idx_func < 0 || nargs < 0) { /* See comments in duk_pcall(). */ - DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_TYPE_INVALID_ARGS(thr); return DUK_EXEC_ERROR; /* unreachable */ } @@ -12553,27 +13384,33 @@ DUK_EXTERNAL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs) { return rc; } -DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_context *ctx) { - duk_idx_t obj_index; +struct duk__pcall_prop_args { + duk_idx_t obj_idx; duk_idx_t nargs; +}; +typedef struct duk__pcall_prop_args duk__pcall_prop_args; - /* Get the original arguments. Note that obj_index may be a relative - * index so the stack must have the same top when we use it. - */ +DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_context *ctx, void *udata) { + duk_idx_t obj_idx; + duk_idx_t nargs; + duk__pcall_prop_args *args; DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(udata != NULL); - obj_index = (duk_idx_t) duk_get_int(ctx, -2); - nargs = (duk_idx_t) duk_get_int(ctx, -1); - duk_pop_2(ctx); + args = (duk__pcall_prop_args *) udata; + obj_idx = args->obj_idx; + nargs = args->nargs; - obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */ - duk__call_prop_prep_stack(ctx, obj_index, nargs); + obj_idx = duk_require_normalize_index(ctx, obj_idx); /* make absolute */ + duk__call_prop_prep_stack(ctx, obj_idx, nargs); duk_call_method(ctx, nargs); return 1; } -DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) { +DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs) { + duk__pcall_prop_args args; + /* * Must be careful to catch errors related to value stack manipulation * and property lookup, not just the call itself. @@ -12581,17 +13418,17 @@ DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_index, duk DUK_ASSERT_CTX_VALID(ctx); - duk_push_idx(ctx, obj_index); - duk_push_idx(ctx, nargs); + args.obj_idx = obj_idx; + args.nargs = nargs; - /* Inputs: explicit arguments (nargs), +1 for key, +2 for obj_index/nargs passing. - * If the value stack does not contain enough args, an error is thrown; this matches + /* Inputs: explicit arguments (nargs), +1 for key. If the value stack + * does not contain enough args, an error is thrown; this matches * behavior of the other protected call API functions. */ - return duk_safe_call(ctx, duk__pcall_prop_raw, nargs + 1 + 2 /*nargs*/, 1 /*nrets*/); + return duk_safe_call(ctx, duk__pcall_prop_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/); } -DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, duk_idx_t nargs, duk_idx_t nrets) { +DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, void *udata, duk_idx_t nargs, duk_idx_t nrets) { duk_hthread *thr = (duk_hthread *) ctx; duk_int_t rc; @@ -12600,12 +13437,13 @@ DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function fu if (duk_get_top(ctx) < nargs || nrets < 0) { /* See comments in duk_pcall(). */ - DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_TYPE_INVALID_ARGS(thr); return DUK_EXEC_ERROR; /* unreachable */ } rc = duk_handle_safe_call(thr, /* thread */ func, /* func */ + udata, /* udata */ nargs, /* num_stack_args */ nrets); /* num_stack_res */ @@ -12695,7 +13533,7 @@ DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) { */ goto not_constructable; } - if (!DUK_HOBJECT_HAS_BOUND(cons)) { + if (!DUK_HOBJECT_HAS_BOUNDFUNC(cons)) { break; } } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { @@ -12705,12 +13543,12 @@ DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) { /* Anything else is not constructable. */ goto not_constructable; } - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [... cons target] */ - duk_remove(ctx, -2); /* -> [... target] */ + duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [... cons target] */ + duk_remove_m2(ctx); /* -> [... target] */ } DUK_ASSERT(duk_is_callable(ctx, -1)); DUK_ASSERT(duk_is_lightfunc(ctx, -1) || - (duk_get_hobject(ctx, -1) != NULL && !DUK_HOBJECT_HAS_BOUND(duk_get_hobject(ctx, -1)))); + (duk_get_hobject(ctx, -1) != NULL && !DUK_HOBJECT_HAS_BOUNDFUNC(duk_get_hobject(ctx, -1)))); /* [... constructor arg1 ... argN final_cons] */ @@ -12725,7 +13563,7 @@ DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) { /* [... constructor arg1 ... argN final_cons fallback] */ - duk_get_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE); + duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_PROTOTYPE); proto = duk_get_hobject(ctx, -1); if (!proto) { DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object " @@ -12785,8 +13623,10 @@ DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) { * object instance or not. */ - if (duk_is_object(ctx, -1)) { - duk_remove(ctx, -2); + if (duk_check_type_mask(ctx, -1, DUK_TYPE_MASK_OBJECT | + DUK_TYPE_MASK_BUFFER | + DUK_TYPE_MASK_LIGHTFUNC)) { + duk_remove_m2(ctx); } else { duk_pop(ctx); } @@ -12797,7 +13637,7 @@ DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) { * stack reflects the caller which is correct. */ -#ifdef DUK_USE_AUGMENT_ERROR_CREATE +#if defined(DUK_USE_AUGMENT_ERROR_CREATE) duk_hthread_sync_currpc(thr); duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/); #endif @@ -12807,14 +13647,22 @@ DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) { return; not_constructable: - DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE); +#if defined(DUK_USE_VERBOSE_ERRORS) +#if defined(DUK_USE_PARANOID_ERRORS) + DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_get_type_name(ctx, -1)); +#else + DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_push_string_readable(ctx, -1)); +#endif +#else + DUK_ERROR_TYPE(thr, "not constructable"); +#endif } -DUK_LOCAL duk_ret_t duk__pnew_helper(duk_context *ctx) { - duk_uint_t nargs; +DUK_LOCAL duk_ret_t duk__pnew_helper(duk_context *ctx, void *udata) { + duk_idx_t nargs; - nargs = duk_to_uint(ctx, -1); - duk_pop(ctx); + DUK_ASSERT(udata != NULL); + nargs = *((duk_idx_t *) udata); duk_new(ctx, nargs); return 1; @@ -12833,8 +13681,7 @@ DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) { * wrapper. */ - duk_push_uint(ctx, nargs); - rc = duk_safe_call(ctx, duk__pnew_helper, nargs + 2 /*nargs*/, 1 /*nrets*/); + rc = duk_safe_call(ctx, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/); return rc; } @@ -12847,8 +13694,19 @@ DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_context *ctx) { DUK_ASSERT_DISABLE(thr->callstack_top >= 0); act = duk_hthread_get_current_activation(thr); - DUK_ASSERT(act != NULL); /* because callstack_top > 0 */ - return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); + if (act != NULL) { + return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); + } + return 0; +} + +/* XXX: Make this obsolete by adding a function flag for rejecting a + * non-constructor call automatically? + */ +DUK_INTERNAL void duk_require_constructor_call(duk_context *ctx) { + if (!duk_is_constructor_call(ctx)) { + DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CONSTRUCT_ONLY); + } } DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_context *ctx) { @@ -12900,29 +13758,29 @@ DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_context *ctx) { } DUK_ASSERT(func != NULL); - if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) { - duk_hnativefunction *nf = (duk_hnativefunction *) func; + if (DUK_HOBJECT_IS_NATFUNC(func)) { + duk_hnatfunc *nf = (duk_hnatfunc *) func; return (duk_int_t) nf->magic; } } return 0; } -DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; duk_hobject *h; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_require_tval(ctx, index); + tv = duk_require_tval(ctx, idx); if (DUK_TVAL_IS_OBJECT(tv)) { h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); - if (!DUK_HOBJECT_HAS_NATIVEFUNCTION(h)) { + if (!DUK_HOBJECT_HAS_NATFUNC(h)) { goto type_error; } - return (duk_int_t) ((duk_hnativefunction *) h)->magic; + return (duk_int_t) ((duk_hnatfunc *) h)->magic; } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); @@ -12934,16 +13792,45 @@ DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index) { return 0; } -DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t magic) { - duk_hnativefunction *nf; +DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t idx, duk_int_t magic) { + duk_hnatfunc *nf; DUK_ASSERT_CTX_VALID(ctx); - nf = duk_require_hnativefunction(ctx, index); + nf = duk_require_hnatfunc(ctx, idx); DUK_ASSERT(nf != NULL); nf->magic = (duk_int16_t) magic; } -#line 1 "duk_api_codec.c" + +/* + * Misc helpers + */ + +DUK_INTERNAL void duk_resolve_nonbound_function(duk_context *ctx) { + duk_uint_t sanity; + duk_tval *tv; + + sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY; + do { + tv = DUK_GET_TVAL_NEGIDX(ctx, -1); + if (DUK_TVAL_IS_LIGHTFUNC(tv)) { + /* Lightweight function: never bound, so terminate. */ + break; + } else if (DUK_TVAL_IS_OBJECT(tv)) { + duk_hobject *func; + + func = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(func != NULL); + if (!DUK_HOBJECT_IS_CALLABLE(func) || !DUK_HOBJECT_HAS_BOUNDFUNC(func)) { + break; + } + duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_TARGET); + duk_replace(ctx, -2); + } else { + break; + } + } while (--sanity > 0); +} /* * Encoding and decoding basic formats: hex, base64. * @@ -12952,19 +13839,24 @@ DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t mag * Base-64: https://tools.ietf.org/html/rfc4648#section-4 */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ /* 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); +DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { + void *ptr; + duk_bool_t isbuffer; + + DUK_ASSERT(duk_is_valid_index(ctx, idx)); /* checked by caller */ + + ptr = duk_get_buffer_data_raw(ctx, idx, out_len, 0 /*throw_flag*/, &isbuffer); + if (isbuffer) { + DUK_ASSERT(*out_len == 0 || ptr != NULL); + return (const duk_uint8_t *) ptr; } + return (const duk_uint8_t *) duk_to_lstring(ctx, idx, out_len); } #if defined(DUK_USE_BASE64_FASTPATH) @@ -13313,7 +14205,7 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_ } #endif /* DUK_USE_BASE64_FASTPATH */ -DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; const duk_uint8_t *src; duk_size_t srclen; @@ -13327,8 +14219,8 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) { * which makes a copy of the input. */ - index = duk_require_normalize_index(ctx, index); - src = duk__prep_codec_arg(ctx, index, &srclen); + idx = duk_require_normalize_index(ctx, idx); + src = duk__prep_codec_arg(ctx, idx, &srclen); /* Note: for srclen=0, src may be NULL */ /* Computation must not wrap; this limit works for 32-bit size_t: @@ -13340,12 +14232,12 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) { goto type_error; } dstlen = (srclen + 2) / 3 * 4; - dst = (duk_uint8_t *) duk_push_fixed_buffer(ctx, dstlen); + dst = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, dstlen); duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst); - ret = duk_to_string(ctx, -1); - duk_replace(ctx, index); + ret = duk_buffer_to_string(ctx, -1); /* Safe, result is ASCII. */ + duk_replace(ctx, idx); return ret; type_error: @@ -13353,7 +14245,7 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) { return NULL; /* never here */ } -DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; const duk_uint8_t *src; duk_size_t srclen; @@ -13368,8 +14260,8 @@ DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) { * which causes an unnecessary interning. */ - index = duk_require_normalize_index(ctx, index); - src = duk__prep_codec_arg(ctx, index, &srclen); + idx = duk_require_normalize_index(ctx, idx); + src = duk__prep_codec_arg(ctx, idx, &srclen); /* Computation must not wrap, only srclen + 3 is at risk of * wrapping because after that the number gets smaller. @@ -13390,14 +14282,14 @@ DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) { /* XXX: convert to fixed buffer? */ (void) duk_resize_buffer(ctx, -1, (duk_size_t) (dst_final - dst)); - duk_replace(ctx, index); + duk_replace(ctx, idx); return; type_error: DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED); } -DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t idx) { const duk_uint8_t *inp; duk_size_t len; duk_size_t i; @@ -13410,12 +14302,12 @@ DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) { DUK_ASSERT_CTX_VALID(ctx); - index = duk_require_normalize_index(ctx, index); - inp = duk__prep_codec_arg(ctx, index, &len); + idx = duk_require_normalize_index(ctx, idx); + inp = duk__prep_codec_arg(ctx, idx, &len); DUK_ASSERT(inp != NULL || len == 0); /* Fixed buffer, no zeroing because we'll fill all the data. */ - buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len * 2, DUK_BUF_FLAG_NOZERO /*flags*/); + buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, len * 2); DUK_ASSERT(buf != NULL); #if defined(DUK_USE_HEX_FASTPATH) @@ -13448,12 +14340,12 @@ DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) { * caller coerce to string if necessary? */ - ret = duk_to_string(ctx, -1); - duk_replace(ctx, index); + ret = duk_buffer_to_string(ctx, -1); /* Safe, result is ASCII. */ + duk_replace(ctx, idx); return ret; } -DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; const duk_uint8_t *inp; duk_size_t len; @@ -13468,8 +14360,8 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) { DUK_ASSERT_CTX_VALID(ctx); - index = duk_require_normalize_index(ctx, index); - inp = duk__prep_codec_arg(ctx, index, &len); + idx = duk_require_normalize_index(ctx, idx); + inp = duk__prep_codec_arg(ctx, idx, &len); DUK_ASSERT(inp != NULL || len == 0); if (len & 0x01) { @@ -13477,7 +14369,7 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) { } /* Fixed buffer, no zeroing because we'll fill all the data. */ - buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len / 2, DUK_BUF_FLAG_NOZERO /*flags*/); + buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, len / 2); DUK_ASSERT(buf != NULL); #if defined(DUK_USE_HEX_FASTPATH) @@ -13530,64 +14422,75 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) { } #endif /* DUK_USE_HEX_FASTPATH */ - duk_replace(ctx, index); + duk_replace(ctx, idx); return; type_error: DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED); } -DUK_EXTERNAL const char *duk_json_encode(duk_context *ctx, duk_idx_t index) { -#ifdef DUK_USE_ASSERTIONS +#if defined(DUK_USE_JSON_SUPPORT) +DUK_EXTERNAL const char *duk_json_encode(duk_context *ctx, duk_idx_t idx) { +#if defined(DUK_USE_ASSERTIONS) duk_idx_t top_at_entry; #endif const char *ret; DUK_ASSERT_CTX_VALID(ctx); -#ifdef DUK_USE_ASSERTIONS +#if defined(DUK_USE_ASSERTIONS) top_at_entry = duk_get_top(ctx); #endif - index = duk_require_normalize_index(ctx, index); + idx = duk_require_normalize_index(ctx, idx); duk_bi_json_stringify_helper(ctx, - index /*idx_value*/, + idx /*idx_value*/, DUK_INVALID_INDEX /*idx_replacer*/, DUK_INVALID_INDEX /*idx_space*/, 0 /*flags*/); DUK_ASSERT(duk_is_string(ctx, -1)); - duk_replace(ctx, index); - ret = duk_get_string(ctx, index); + duk_replace(ctx, idx); + ret = duk_get_string(ctx, idx); DUK_ASSERT(duk_get_top(ctx) == top_at_entry); return ret; } -DUK_EXTERNAL void duk_json_decode(duk_context *ctx, duk_idx_t index) { -#ifdef DUK_USE_ASSERTIONS +DUK_EXTERNAL void duk_json_decode(duk_context *ctx, duk_idx_t idx) { +#if defined(DUK_USE_ASSERTIONS) duk_idx_t top_at_entry; #endif DUK_ASSERT_CTX_VALID(ctx); -#ifdef DUK_USE_ASSERTIONS +#if defined(DUK_USE_ASSERTIONS) top_at_entry = duk_get_top(ctx); #endif - index = duk_require_normalize_index(ctx, index); + idx = duk_require_normalize_index(ctx, idx); duk_bi_json_parse_helper(ctx, - index /*idx_value*/, + idx /*idx_value*/, DUK_INVALID_INDEX /*idx_reviver*/, 0 /*flags*/); - duk_replace(ctx, index); + duk_replace(ctx, idx); DUK_ASSERT(duk_get_top(ctx) == top_at_entry); } -#line 1 "duk_api_compile.c" +#else /* DUK_USE_JSON_SUPPORT */ +DUK_EXTERNAL const char *duk_json_encode(duk_context *ctx, duk_idx_t idx) { + DUK_UNREF(idx); + DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx); +} + +DUK_EXTERNAL void duk_json_decode(duk_context *ctx, duk_idx_t idx) { + DUK_UNREF(idx); + DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx); +} +#endif /* DUK_USE_JSON_SUPPORT */ /* * Compilation and evaluation */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ typedef struct duk__compile_raw_args duk__compile_raw_args; struct duk__compile_raw_args { @@ -13643,14 +14546,15 @@ DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, du } /* Helper which can be called both directly and with duk_safe_call(). */ -DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) { +DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx, void *udata) { duk_hthread *thr = (duk_hthread *) ctx; duk__compile_raw_args *comp_args; duk_uint_t flags; duk_small_uint_t comp_flags; - duk_hcompiledfunction *h_templ; + duk_hcompfunc *h_templ; DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(udata != NULL); /* Note: strictness is not inherited from the current Duktape/C * context. Otherwise it would not be possible to compile @@ -13659,13 +14563,10 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) { * for discussion. */ - /* [ ... source? filename? &comp_args ] (depends on flags) */ + /* [ ... source? filename? ] (depends on flags) */ - comp_args = (duk__compile_raw_args *) duk_require_pointer(ctx, -1); + comp_args = (duk__compile_raw_args *) udata; flags = comp_args->flags; - duk_pop(ctx); - - /* [ ... source? filename? ] */ if (flags & DUK_COMPILE_NOFILENAME) { /* Automatic filename: 'eval' or 'input'. */ @@ -13680,11 +14581,7 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) { h_sourcecode = duk_get_hstring(ctx, -2); if ((flags & DUK_COMPILE_NOSOURCE) || /* args incorrect */ (h_sourcecode == NULL)) { /* e.g. duk_push_string_file_raw() pushed undefined */ - /* XXX: when this error is caused by a nonexistent - * file given to duk_peval_file() or similar, the - * error message is not the best possible. - */ - DUK_ERROR_API(thr, DUK_STR_NO_SOURCECODE); + DUK_ERROR_TYPE(thr, DUK_STR_NO_SOURCECODE); } DUK_ASSERT(h_sourcecode != NULL); comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode); @@ -13714,19 +14611,18 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) { if (flags & DUK_COMPILE_NOSOURCE) { ; } else { - duk_remove(ctx, -2); + duk_remove_m2(ctx); } /* [ ... func_template ] */ - h_templ = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1); - DUK_ASSERT(h_templ != NULL); + h_templ = (duk_hcompfunc *) duk_known_hobject(ctx, -1); duk_js_push_closure(thr, h_templ, thr->builtins[DUK_BIDX_GLOBAL_ENV], thr->builtins[DUK_BIDX_GLOBAL_ENV], 1 /*add_auto_proto*/); - duk_remove(ctx, -2); /* -> [ ... closure ] */ + duk_remove_m2(ctx); /* -> [ ... closure ] */ /* [ ... closure ] */ @@ -13749,9 +14645,8 @@ DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, comp_args->src_buffer = (const duk_uint8_t *) src_buffer; comp_args->src_length = src_length; comp_args->flags = flags; - duk_push_pointer(ctx, (void *) comp_args); - /* [ ... source? filename? &comp_args ] (depends on flags) */ + /* [ ... source? filename? ] (depends on flags) */ if (flags & DUK_COMPILE_SAFE) { duk_int_t rc; @@ -13763,27 +14658,26 @@ DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, * directly into flags. */ nargs = flags & 0x07; - DUK_ASSERT(nargs == (1 + - ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) + - ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1))); - rc = duk_safe_call(ctx, duk__do_compile, nargs, nrets); + DUK_ASSERT(nargs == ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) + + ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1)); + rc = duk_safe_call(ctx, duk__do_compile, (void *) comp_args, nargs, nrets); /* [ ... closure ] */ return rc; } - (void) duk__do_compile(ctx); + (void) duk__do_compile(ctx, (void *) comp_args); /* [ ... closure ] */ return DUK_EXEC_SUCCESS; } -#line 1 "duk_api_debug.c" /* * Debugging related API calls */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ +#if defined(DUK_USE_JSON_SUPPORT) DUK_EXTERNAL void duk_push_context_dump(duk_context *ctx) { duk_idx_t idx; duk_idx_t top; @@ -13817,18 +14711,23 @@ DUK_EXTERNAL void duk_push_context_dump(duk_context *ctx) { duk_pop(ctx); DUK_ASSERT(duk_is_string(ctx, -1)); } +#else /* DUK_USE_JSON_SUPPORT */ +DUK_EXTERNAL void duk_push_context_dump(duk_context *ctx) { + DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx); +} +#endif /* DUK_USE_JSON_SUPPORT */ #if defined(DUK_USE_DEBUGGER_SUPPORT) -DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx, - duk_debug_read_function read_cb, - duk_debug_write_function write_cb, - duk_debug_peek_function peek_cb, - duk_debug_read_flush_function read_flush_cb, - duk_debug_write_flush_function write_flush_cb, - duk_debug_request_function request_cb, - duk_debug_detached_function detached_cb, - void *udata) { +DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx, + duk_debug_read_function read_cb, + duk_debug_write_function write_cb, + duk_debug_peek_function peek_cb, + duk_debug_read_flush_function read_flush_cb, + duk_debug_write_flush_function write_flush_cb, + duk_debug_request_function request_cb, + duk_debug_detached_function detached_cb, + void *udata) { duk_hthread *thr = (duk_hthread *) ctx; duk_heap *heap; const char *str; @@ -13858,7 +14757,7 @@ DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx, /* Start in paused state. */ heap->dbg_processing = 0; - heap->dbg_paused = 1; + DUK_HEAP_SET_DEBUGGER_PAUSED(heap); heap->dbg_state_dirty = 1; heap->dbg_force_restart = 0; heap->dbg_step_type = 0; @@ -13937,7 +14836,7 @@ DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) top = duk_get_top(ctx); if (top < nvalues) { - DUK_ERROR_API(thr, "not enough stack values for notify"); + DUK_ERROR_RANGE(thr, "not enough stack values for notify"); return ret; /* unreachable */ } if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { @@ -13986,15 +14885,15 @@ DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) { #else /* DUK_USE_DEBUGGER_SUPPORT */ -DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx, - duk_debug_read_function read_cb, - duk_debug_write_function write_cb, - duk_debug_peek_function peek_cb, - duk_debug_read_flush_function read_flush_cb, - duk_debug_write_flush_function write_flush_cb, - duk_debug_request_function request_cb, - duk_debug_detached_function detached_cb, - void *udata) { +DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx, + duk_debug_read_function read_cb, + duk_debug_write_function write_cb, + duk_debug_peek_function peek_cb, + duk_debug_read_flush_function read_flush_cb, + duk_debug_write_flush_function write_flush_cb, + duk_debug_request_function request_cb, + duk_debug_detached_function detached_cb, + void *udata) { DUK_ASSERT_CTX_VALID(ctx); DUK_UNREF(read_cb); DUK_UNREF(write_cb); @@ -14004,12 +14903,12 @@ DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx, DUK_UNREF(request_cb); DUK_UNREF(detached_cb); DUK_UNREF(udata); - DUK_ERROR_API((duk_hthread *) ctx, "no debugger support"); + DUK_ERROR_TYPE((duk_hthread *) ctx, "no debugger support"); } DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) { DUK_ASSERT_CTX_VALID(ctx); - DUK_ERROR_API((duk_hthread *) ctx, "no debugger support"); + DUK_ERROR_TYPE((duk_hthread *) ctx, "no debugger support"); } DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) { @@ -14025,7 +14924,7 @@ DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) top = duk_get_top(ctx); if (top < nvalues) { - DUK_ERROR_API((duk_hthread *) ctx, "not enough stack values for notify"); + DUK_ERROR_RANGE_INVALID_COUNT((duk_hthread *) ctx); return 0; /* unreachable */ } @@ -14041,12 +14940,11 @@ DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) { } #endif /* DUK_USE_DEBUGGER_SUPPORT */ -#line 1 "duk_api_heap.c" /* * Heap creation and destruction */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ typedef struct duk_internal_thread_state duk_internal_thread_state; @@ -14205,24 +15103,19 @@ DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) { * same (initial) built-ins. */ - (void) duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), - -1); /* no prototype, updated below */ - - duk_dup(ctx, -2); - duk_dup(ctx, -3); - - /* [ ... new_glob new_env new_glob new_glob ] */ + h_env = duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), + -1); /* no prototype, updated below */ + DUK_ASSERT(h_env != NULL); - duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); - duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); + duk_dup_m2(ctx); + duk_dup_m3(ctx); + duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); + duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* [ ... new_glob new_env ] */ - h_env = duk_get_hobject(ctx, -1); - DUK_ASSERT(h_env != NULL); - h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_env; DUK_HOBJECT_INCREF(thr, h_env); @@ -14236,65 +15129,257 @@ DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) { /* [ ... ] */ } -#line 1 "duk_api_logging.c" /* - * Logging - * - * Current logging primitive is a sprintf-style log which is convenient - * for most C code. Another useful primitive would be to log N arguments - * from value stack (like the Ecmascript binding does). + * Inspection */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ -DUK_EXTERNAL void duk_log_va(duk_context *ctx, duk_int_t level, const char *fmt, va_list ap) { - /* stridx_logfunc[] must be static to allow initializer with old compilers like BCC */ - static const duk_uint16_t stridx_logfunc[6] = { - DUK_STRIDX_LC_TRACE, DUK_STRIDX_LC_DEBUG, DUK_STRIDX_LC_INFO, - DUK_STRIDX_LC_WARN, DUK_STRIDX_LC_ERROR, DUK_STRIDX_LC_FATAL - }; +/* For footprint efficient multiple value setting: arrays are much better than + * varargs, format string with parsing is often better than string pointer arrays. + */ +DUK_LOCAL void duk__inspect_multiple_uint(duk_context *ctx, const char *fmt, duk_int_t *vals) { + duk_int_t val; + const char *p; + const char *p_curr; + duk_size_t len; - DUK_ASSERT_CTX_VALID(ctx); + for (p = fmt;;) { + len = DUK_STRLEN(p); + p_curr = p; + p += len + 1; + if (len == 0) { + /* Double NUL (= empty key) terminates. */ + break; + } + val = *vals++; + if (val >= 0) { + /* Negative values are markers to skip key. */ + duk_push_string(ctx, p_curr); + duk_push_uint(ctx, val); + duk_put_prop(ctx, -3); + } + } +} - if (level < 0) { - level = 0; - } else if (level > (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1) { - level = (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1; +/* Raw helper to extract internal information / statistics about a value. + * The return value is an object with properties that are version specific. + * The properties must not expose anything that would lead to security + * issues (e.g. exposing compiled function 'data' buffer might be an issue). + * Currently only counts and sizes and such are given so there shouldn't + * be security implications. + */ + +#define DUK__IDX_TYPE 0 +#define DUK__IDX_ITAG 1 +#define DUK__IDX_REFC 2 +#define DUK__IDX_HBYTES 3 +#define DUK__IDX_CLASS 4 +#define DUK__IDX_PBYTES 5 +#define DUK__IDX_ESIZE 6 +#define DUK__IDX_ENEXT 7 +#define DUK__IDX_ASIZE 8 +#define DUK__IDX_HSIZE 9 +#define DUK__IDX_BCBYTES 10 +#define DUK__IDX_DBYTES 11 +#define DUK__IDX_TSTATE 12 +#define DUK__IDX_VARIANT 13 + +DUK_EXTERNAL void duk_inspect_value(duk_context *ctx, duk_idx_t idx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + duk_heaphdr *h; + /* The temporary values should be in an array rather than individual + * variables which (in practice) ensures that the compiler won't map + * them to registers and emit a lot of unnecessary shuffling code. + */ + duk_int_t vals[14]; + + DUK_UNREF(thr); + + tv = duk_get_tval_or_unused(ctx, idx); + h = (DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv) : NULL); + + /* Assume two's complement and set everything to -1. */ + DUK_MEMSET((void *) &vals, (int) 0xff, sizeof(vals)); + DUK_ASSERT(vals[DUK__IDX_TYPE] == -1); /* spot check one */ + + duk_push_bare_object(ctx); + + vals[DUK__IDX_TYPE] = duk_get_type_tval(tv); + vals[DUK__IDX_ITAG] = (duk_uint_t) DUK_TVAL_GET_TAG(tv); + + if (h == NULL) { + goto finish; } + duk_push_pointer(ctx, (void *) h); + duk_put_prop_string(ctx, -2, "hptr"); - duk_push_hobject_bidx(ctx, DUK_BIDX_LOGGER_CONSTRUCTOR); - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_CLOG); - duk_get_prop_stridx(ctx, -1, stridx_logfunc[level]); - duk_dup(ctx, -2); +#if 0 + /* Covers a lot of information, e.g. buffer and string variants. */ + duk_push_uint(ctx, (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h)); + duk_put_prop_string(ctx, -2, "hflags"); +#endif + +#if defined(DUK_USE_REFERENCE_COUNTING) + vals[DUK__IDX_REFC] = (duk_int_t) DUK_HEAPHDR_GET_REFCOUNT(h); +#endif + vals[DUK__IDX_VARIANT] = 0; + + /* Heaphdr size and additional allocation size, followed by + * type specific stuff (with varying value count). + */ + switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) { + case DUK_HTYPE_STRING: { + duk_hstring *h_str = (duk_hstring *) h; + vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1); +#if defined(DUK_USE_HSTRING_EXTDATA) + if (DUK_HSTRING_HAS_EXTDATA(h_str)) { + vals[DUK__IDX_VARIANT] = 1; + } +#endif + break; + } + case DUK_HTYPE_OBJECT: { + duk_hobject *h_obj = (duk_hobject *) h; - /* [ ... Logger clog logfunc clog ] */ + /* XXX: variants here are maybe pointless; class is enough? */ + if (DUK_HOBJECT_IS_ARRAY(h_obj)) { + vals[DUK__IDX_HBYTES] = sizeof(duk_harray); + } else if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) { + vals[DUK__IDX_HBYTES] = sizeof(duk_hcompfunc); + } else if (DUK_HOBJECT_IS_NATFUNC(h_obj)) { + vals[DUK__IDX_HBYTES] = sizeof(duk_hnatfunc); + } else if (DUK_HOBJECT_IS_THREAD(h_obj)) { + vals[DUK__IDX_HBYTES] = sizeof(duk_hthread); + vals[DUK__IDX_TSTATE] = ((duk_hthread *) h_obj)->state; +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) + } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { + vals[DUK__IDX_HBYTES] = sizeof(duk_hbufobj); + /* XXX: some size information */ +#endif + } else { + vals[DUK__IDX_HBYTES] = (duk_small_uint_t) sizeof(duk_hobject); + } - duk_push_vsprintf(ctx, fmt, ap); + vals[DUK__IDX_CLASS] = (duk_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h_obj); + vals[DUK__IDX_PBYTES] = (duk_int_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj), + vals[DUK__IDX_ESIZE] = (duk_int_t) DUK_HOBJECT_GET_ESIZE(h_obj); + vals[DUK__IDX_ENEXT] = (duk_int_t) DUK_HOBJECT_GET_ENEXT(h_obj); + vals[DUK__IDX_ASIZE] = (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj); + vals[DUK__IDX_HSIZE] = (duk_int_t) DUK_HOBJECT_GET_HSIZE(h_obj); - /* [ ... Logger clog logfunc clog(=this) msg ] */ + /* Note: e_next indicates the number of gc-reachable entries + * in the entry part, and also indicates the index where the + * next new property would be inserted. It does *not* indicate + * the number of non-NULL keys present in the object. That + * value could be counted separately but requires a pass through + * the key list. + */ - duk_call_method(ctx, 1 /*nargs*/); + if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) { + duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, (duk_hcompfunc *) h_obj); + vals[DUK__IDX_BCBYTES] = (duk_int_t) (h_data ? DUK_HBUFFER_GET_SIZE(h_data) : 0); + } + break; + } + case DUK_HTYPE_BUFFER: { + duk_hbuffer *h_buf = (duk_hbuffer *) h; - /* [ ... Logger clog res ] */ + if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) { + if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) { + vals[DUK__IDX_VARIANT] = 2; /* buffer variant 2: external */ + vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_external)); + } else { + /* When alloc_size == 0 the second allocation may not + * actually exist. + */ + vals[DUK__IDX_VARIANT] = 1; /* buffer variant 1: dynamic */ + vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_dynamic)); + } + vals[DUK__IDX_DBYTES] = (duk_uint_t) (DUK_HBUFFER_GET_SIZE(h_buf)); + } else { + DUK_ASSERT(vals[DUK__IDX_VARIANT] == 0); /* buffer variant 0: fixed */ + vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf)); + } + break; + } + } - duk_pop_3(ctx); + finish: + duk__inspect_multiple_uint(ctx, + "type" "\x00" "itag" "\x00" "refc" "\x00" "hbytes" "\x00" "class" "\x00" + "pbytes" "\x00" "esize" "\x00" "enext" "\x00" "asize" "\x00" "hsize" "\x00" + "bcbytes" "\x00" "dbytes" "\x00" "tstate" "\x00" "variant" "\x00" "\x00", + (duk_int_t *) &vals); } -DUK_EXTERNAL void duk_log(duk_context *ctx, duk_int_t level, const char *fmt, ...) { - va_list ap; +DUK_EXTERNAL void duk_inspect_callstack_entry(duk_context *ctx, duk_int_t level) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_activation *act; + duk_uint_fast32_t pc; + duk_uint_fast32_t line; DUK_ASSERT_CTX_VALID(ctx); - va_start(ap, fmt); - duk_log_va(ctx, level, fmt, ap); - va_end(ap); + /* -1 = top callstack entry, callstack[callstack_top - 1] + * -callstack_top = bottom callstack entry, callstack[0] + */ + if (level >= 0 || -level > (duk_int_t) thr->callstack_top) { + duk_push_undefined(ctx); + return; + } + duk_push_bare_object(ctx); + DUK_ASSERT(level >= -((duk_int_t) thr->callstack_top) && level <= -1); + + act = thr->callstack + thr->callstack_top + level; + /* Relevant PC is just before current one because PC is + * post-incremented. This should match what error augment + * code does. + */ + pc = duk_hthread_get_act_prev_pc(thr, act); + + duk_push_tval(ctx, &act->tv_func); + + duk_push_uint(ctx, (duk_uint_t) pc); + duk_put_prop_stridx_short(ctx, -3, DUK_STRIDX_PC); + +#if defined(DUK_USE_PC2LINE) + line = duk_hobject_pc2line_query(ctx, -1, pc); +#else + line = 0; +#endif + duk_push_uint(ctx, (duk_uint_t) line); + duk_put_prop_stridx_short(ctx, -3, DUK_STRIDX_LINE_NUMBER); + + duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_LC_FUNCTION); + /* Providing access to e.g. act->lex_env would be dangerous: these + * internal structures must never be accessible to the application. + * Duktape relies on them having consistent data, and this consistency + * is only asserted for, not checked for. + */ } -#line 1 "duk_api_memory.c" + +/* automatic undefs */ +#undef DUK__IDX_ASIZE +#undef DUK__IDX_BCBYTES +#undef DUK__IDX_CLASS +#undef DUK__IDX_DBYTES +#undef DUK__IDX_ENEXT +#undef DUK__IDX_ESIZE +#undef DUK__IDX_HBYTES +#undef DUK__IDX_HSIZE +#undef DUK__IDX_ITAG +#undef DUK__IDX_PBYTES +#undef DUK__IDX_REFC +#undef DUK__IDX_TSTATE +#undef DUK__IDX_TYPE +#undef DUK__IDX_VARIANT /* * Memory calls. */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ DUK_EXTERNAL void *duk_alloc_raw(duk_context *ctx, duk_size_t size) { duk_hthread *thr = (duk_hthread *) ctx; @@ -14371,34 +15456,24 @@ DUK_EXTERNAL void duk_get_memory_functions(duk_context *ctx, duk_memory_function } DUK_EXTERNAL void duk_gc(duk_context *ctx, duk_uint_t flags) { -#ifdef DUK_USE_MARK_AND_SWEEP duk_hthread *thr = (duk_hthread *) ctx; duk_heap *heap; + duk_small_uint_t ms_flags; - DUK_UNREF(flags); - - /* NULL accepted */ - if (!ctx) { - return; - } DUK_ASSERT_CTX_VALID(ctx); heap = thr->heap; DUK_ASSERT(heap != NULL); DUK_D(DUK_DPRINT("mark-and-sweep requested by application")); - duk_heap_mark_and_sweep(heap, 0); -#else - DUK_D(DUK_DPRINT("mark-and-sweep requested by application but mark-and-sweep not enabled, ignoring")); - DUK_UNREF(ctx); - DUK_UNREF(flags); -#endif + DUK_ASSERT(DUK_GC_COMPACT == DUK_MS_FLAG_EMERGENCY); /* Compact flag is 1:1 with emergency flag which forces compaction. */ + ms_flags = (duk_small_uint_t) flags; + duk_heap_mark_and_sweep(heap, ms_flags); } -#line 1 "duk_api_object.c" /* * Object handling: property access and other support functions. */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ /* * Property handling @@ -14408,7 +15483,7 @@ DUK_EXTERNAL void duk_gc(duk_context *ctx, duk_uint_t flags) { * defineProperty, getOwnPropertyDescriptor). */ -DUK_EXTERNAL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_index) { +DUK_EXTERNAL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv_obj; duk_tval *tv_key; @@ -14420,55 +15495,67 @@ DUK_EXTERNAL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_index) { * resize is not necessary for a property get right now. */ - tv_obj = duk_require_tval(ctx, obj_index); + tv_obj = duk_require_tval(ctx, obj_idx); tv_key = duk_require_tval(ctx, -1); rc = duk_hobject_getprop(thr, tv_obj, tv_key); DUK_ASSERT(rc == 0 || rc == 1); /* a value is left on stack regardless of rc */ - duk_remove(ctx, -2); /* remove key */ + duk_remove_m2(ctx); /* remove key */ return rc; /* 1 if property found, 0 otherwise */ } -DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) { +DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) { DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(key != NULL); - obj_index = duk_require_normalize_index(ctx, obj_index); + obj_idx = duk_require_normalize_index(ctx, obj_idx); duk_push_string(ctx, key); - return duk_get_prop(ctx, obj_index); + return duk_get_prop(ctx, obj_idx); } -DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) { +DUK_EXTERNAL duk_bool_t duk_get_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(key != NULL); - obj_index = duk_require_normalize_index(ctx, obj_index); - duk_push_uarridx(ctx, arr_index); - return duk_get_prop(ctx, obj_index); + obj_idx = duk_require_normalize_index(ctx, obj_idx); + duk_push_lstring(ctx, key, key_len); + return duk_get_prop(ctx, obj_idx); } -DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) { +DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { + DUK_ASSERT_CTX_VALID(ctx); + + obj_idx = duk_require_normalize_index(ctx, obj_idx); + duk_push_uarridx(ctx, arr_idx); + return duk_get_prop(ctx, obj_idx); +} + +DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx) { duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT_CTX_VALID(ctx); - DUK_ASSERT_DISABLE(stridx >= 0); - DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + DUK_ASSERT_STRIDX_VALID(stridx); DUK_UNREF(thr); - obj_index = duk_require_normalize_index(ctx, obj_index); + obj_idx = duk_require_normalize_index(ctx, obj_idx); duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx)); - return duk_get_prop(ctx, obj_index); + return duk_get_prop(ctx, obj_idx); +} + +DUK_INTERNAL duk_bool_t duk_get_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args) { + return duk_get_prop_stridx(ctx, (duk_idx_t) (duk_int16_t) (packed_args >> 16), + (duk_small_uint_t) (packed_args & 0xffffUL)); } -DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_bool_t *out_has_prop) { +DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop) { duk_bool_t rc; DUK_ASSERT_CTX_VALID(ctx); - DUK_ASSERT_DISABLE(stridx >= 0); - DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + DUK_ASSERT_STRIDX_VALID(stridx); - rc = duk_get_prop_stridx(ctx, obj_index, stridx); + rc = duk_get_prop_stridx(ctx, obj_idx, stridx); if (out_has_prop) { *out_has_prop = rc; } @@ -14496,6 +15583,7 @@ DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_context *ctx, duk_idx_t obj_idx, d */ DUK_ASSERT((idx_key == -2 && (idx_key ^ 1) == -1) || (idx_key == -1 && (idx_key ^ 1) == -2)); + /* XXX: Direct access; faster validation. */ tv_obj = duk_require_tval(ctx, obj_idx); tv_key = duk_require_tval(ctx, idx_key); tv_val = duk_require_tval(ctx, idx_key ^ 1); @@ -14526,6 +15614,15 @@ DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, return duk__put_prop_shared(ctx, obj_idx, -1); } +DUK_EXTERNAL duk_bool_t duk_put_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(key != NULL); + + obj_idx = duk_normalize_index(ctx, obj_idx); + (void) duk_push_lstring(ctx, key, key_len); + return duk__put_prop_shared(ctx, obj_idx, -1); +} + DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { DUK_ASSERT_CTX_VALID(ctx); @@ -14534,12 +15631,11 @@ DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, return duk__put_prop_shared(ctx, obj_idx, -1); } -DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_int_t stridx) { +DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx) { duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT_CTX_VALID(ctx); - DUK_ASSERT_DISABLE(stridx >= 0); - DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + DUK_ASSERT_STRIDX_VALID(stridx); DUK_UNREF(thr); obj_idx = duk_require_normalize_index(ctx, obj_idx); @@ -14547,7 +15643,12 @@ DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, return duk__put_prop_shared(ctx, obj_idx, -1); } -DUK_EXTERNAL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_index) { +DUK_INTERNAL duk_bool_t duk_put_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args) { + return duk_put_prop_stridx(ctx, (duk_idx_t) (duk_int16_t) (packed_args >> 16), + (duk_small_uint_t) (packed_args & 0xffffUL)); +} + +DUK_EXTERNAL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv_obj; duk_tval *tv_key; @@ -14560,7 +15661,7 @@ DUK_EXTERNAL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_index) { * resize is not necessary for a property delete right now. */ - tv_obj = duk_require_tval(ctx, obj_index); + tv_obj = duk_require_tval(ctx, obj_idx); tv_key = duk_require_tval(ctx, -1); throw_flag = duk_is_strict_call(ctx); @@ -14571,37 +15672,52 @@ DUK_EXTERNAL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_index) { return rc; } -DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) { +DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) { DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(key != NULL); - obj_index = duk_require_normalize_index(ctx, obj_index); + obj_idx = duk_require_normalize_index(ctx, obj_idx); duk_push_string(ctx, key); - return duk_del_prop(ctx, obj_index); + return duk_del_prop(ctx, obj_idx); +} + +DUK_EXTERNAL duk_bool_t duk_del_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(key != NULL); + + obj_idx = duk_require_normalize_index(ctx, obj_idx); + duk_push_lstring(ctx, key, key_len); + return duk_del_prop(ctx, obj_idx); } -DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) { +DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { DUK_ASSERT_CTX_VALID(ctx); - obj_index = duk_require_normalize_index(ctx, obj_index); - duk_push_uarridx(ctx, arr_index); - return duk_del_prop(ctx, obj_index); + obj_idx = duk_require_normalize_index(ctx, obj_idx); + duk_push_uarridx(ctx, arr_idx); + return duk_del_prop(ctx, obj_idx); } -DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) { +DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx) { duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT_CTX_VALID(ctx); - DUK_ASSERT_DISABLE(stridx >= 0); - DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + DUK_ASSERT_STRIDX_VALID(stridx); DUK_UNREF(thr); - obj_index = duk_require_normalize_index(ctx, obj_index); + obj_idx = duk_require_normalize_index(ctx, obj_idx); duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx)); - return duk_del_prop(ctx, obj_index); + return duk_del_prop(ctx, obj_idx); +} + +#if 0 +DUK_INTERNAL duk_bool_t duk_del_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args) { + return duk_del_prop_stridx(ctx, (duk_idx_t) (duk_int16_t) (packed_args >> 16), + (duk_small_uint_t) (packed_args & 0xffffUL)); } +#endif -DUK_EXTERNAL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_index) { +DUK_EXTERNAL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv_obj; duk_tval *tv_key; @@ -14613,7 +15729,7 @@ DUK_EXTERNAL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_index) { * resize is not necessary for a property existence check right now. */ - tv_obj = duk_require_tval(ctx, obj_index); + tv_obj = duk_require_tval(ctx, obj_idx); tv_key = duk_require_tval(ctx, -1); rc = duk_hobject_hasprop(thr, tv_obj, tv_key); @@ -14623,51 +15739,66 @@ DUK_EXTERNAL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_index) { return rc; /* 1 if property found, 0 otherwise */ } -DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) { +DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) { DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(key != NULL); - obj_index = duk_require_normalize_index(ctx, obj_index); + obj_idx = duk_require_normalize_index(ctx, obj_idx); duk_push_string(ctx, key); - return duk_has_prop(ctx, obj_index); + return duk_has_prop(ctx, obj_idx); +} + +DUK_EXTERNAL duk_bool_t duk_has_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(key != NULL); + + obj_idx = duk_require_normalize_index(ctx, obj_idx); + duk_push_lstring(ctx, key, key_len); + return duk_has_prop(ctx, obj_idx); } -DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) { +DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { DUK_ASSERT_CTX_VALID(ctx); - obj_index = duk_require_normalize_index(ctx, obj_index); - duk_push_uarridx(ctx, arr_index); - return duk_has_prop(ctx, obj_index); + obj_idx = duk_require_normalize_index(ctx, obj_idx); + duk_push_uarridx(ctx, arr_idx); + return duk_has_prop(ctx, obj_idx); } -DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) { +DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx) { duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT_CTX_VALID(ctx); - DUK_ASSERT_DISABLE(stridx >= 0); - DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + DUK_ASSERT_STRIDX_VALID(stridx); DUK_UNREF(thr); - obj_index = duk_require_normalize_index(ctx, obj_index); + obj_idx = duk_require_normalize_index(ctx, obj_idx); duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx)); - return duk_has_prop(ctx, obj_index); + return duk_has_prop(ctx, obj_idx); } -/* Define own property without inheritance looks and such. This differs from +#if 0 +DUK_INTERNAL duk_bool_t duk_has_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args) { + return duk_has_prop_stridx(ctx, (duk_idx_t) (duk_int16_t) (packed_args >> 16), + (duk_small_uint_t) (packed_args & 0xffffUL)); +} +#endif + +/* Define own property without inheritance lookups and such. This differs from * [[DefineOwnProperty]] because special behaviors (like Array 'length') are * not invoked by this method. The caller must be careful to invoke any such * behaviors if necessary. */ -DUK_INTERNAL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags) { +DUK_INTERNAL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t desc_flags) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *obj; duk_hstring *key; DUK_ASSERT_CTX_VALID(ctx); - obj = duk_require_hobject(ctx, obj_index); + obj = duk_require_hobject(ctx, obj_idx); DUK_ASSERT(obj != NULL); - key = duk_to_hstring(ctx, -2); + key = duk_to_property_key_hstring(ctx, -2); DUK_ASSERT(key != NULL); DUK_ASSERT(duk_require_tval(ctx, -1) != NULL); @@ -14676,29 +15807,28 @@ DUK_INTERNAL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small duk_pop(ctx); /* pop key */ } -DUK_INTERNAL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index, duk_small_uint_t desc_flags) { +DUK_INTERNAL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *obj; DUK_ASSERT_CTX_VALID(ctx); - obj = duk_require_hobject(ctx, obj_index); + obj = duk_require_hobject(ctx, obj_idx); DUK_ASSERT(obj != NULL); - duk_hobject_define_property_internal_arridx(thr, obj, arr_index, desc_flags); + duk_hobject_define_property_internal_arridx(thr, obj, arr_idx, desc_flags); /* value popped by call */ } -DUK_INTERNAL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags) { +DUK_INTERNAL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *obj; duk_hstring *key; DUK_ASSERT_CTX_VALID(ctx); - DUK_ASSERT_DISABLE(stridx >= 0); - DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + DUK_ASSERT_STRIDX_VALID(stridx); - obj = duk_require_hobject(ctx, obj_index); + obj = duk_require_hobject(ctx, obj_idx); DUK_ASSERT(obj != NULL); key = DUK_HTHREAD_GET_STRING(thr, stridx); DUK_ASSERT(key != NULL); @@ -14708,18 +15838,22 @@ DUK_INTERNAL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, du /* value popped by call */ } -DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags) { +DUK_INTERNAL void duk_xdef_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args) { + duk_xdef_prop_stridx(ctx, (duk_idx_t) (duk_int8_t) (packed_args >> 24), + (duk_small_uint_t) (packed_args >> 8) & 0xffffUL, + (duk_small_uint_t) (packed_args & 0xffL)); +} + +DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *obj; duk_hstring *key; DUK_ASSERT_CTX_VALID(ctx); - DUK_ASSERT_DISABLE(stridx >= 0); - DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); - DUK_ASSERT_DISABLE(builtin_idx >= 0); - DUK_ASSERT(builtin_idx < DUK_NUM_BUILTINS); + DUK_ASSERT_STRIDX_VALID(stridx); + DUK_ASSERT_BIDX_VALID(builtin_idx); - obj = duk_require_hobject(ctx, obj_index); + obj = duk_require_hobject(ctx, obj_idx); DUK_ASSERT(obj != NULL); key = DUK_HTHREAD_GET_STRING(thr, stridx); DUK_ASSERT(key != NULL); @@ -14734,15 +15868,23 @@ DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_i * object creation code, function instance creation code, and Function.prototype.bind(). */ -DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags) { - duk_hthread *thr = (duk_hthread *) ctx; - duk_hobject *obj = duk_require_hobject(ctx, obj_index); - duk_hobject *thrower = thr->builtins[DUK_BIDX_TYPE_ERROR_THROWER]; - duk_hobject_define_accessor_internal(thr, obj, DUK_HTHREAD_GET_STRING(thr, stridx), thrower, thrower, desc_flags); +DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx) { + obj_idx = duk_require_normalize_index(ctx, obj_idx); + duk_push_hstring_stridx(ctx, stridx); + duk_push_hobject_bidx(ctx, DUK_BIDX_TYPE_ERROR_THROWER); + duk_dup_top(ctx); + duk_def_prop(ctx, obj_idx, DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_FORCE); /* attributes always 0 */ +} + +/* Object.getOwnPropertyDescriptor() equivalent C binding. */ +DUK_EXTERNAL void duk_get_prop_desc(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags) { + DUK_UNREF(flags); /* no flags defined yet */ + + duk_hobject_object_get_own_property_descriptor(ctx, obj_idx); /* [ ... key ] -> [ ... desc ] */ } /* Object.defineProperty() equivalent C binding. */ -DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t flags) { +DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags) { duk_hthread *thr = (duk_hthread *) ctx; duk_idx_t idx_base; duk_hobject *obj; @@ -14755,7 +15897,7 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t DUK_ASSERT_CTX_VALID(ctx); - obj = duk_require_hobject(ctx, obj_index); + obj = duk_require_hobject(ctx, obj_idx); is_data_desc = flags & (DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE); is_acc_desc = flags & (DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); @@ -14772,7 +15914,7 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED | DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC); - set = duk_get_hobject_or_lfunc_coerce(ctx, idx_base); + set = duk_get_hobject_promote_lfunc(ctx, idx_base); if (set != NULL && !DUK_HOBJECT_IS_CALLABLE(set)) { goto fail_not_callable; } @@ -14784,7 +15926,7 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED | DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC); - get = duk_get_hobject_or_lfunc_coerce(ctx, idx_base); + get = duk_get_hobject_promote_lfunc(ctx, idx_base); if (get != NULL && !DUK_HOBJECT_IS_CALLABLE(get)) { goto fail_not_callable; } @@ -14798,7 +15940,8 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t } else { idx_value = (duk_idx_t) -1; } - key = duk_require_hstring(ctx, idx_base); + key = duk_to_property_key_hstring(ctx, idx_base); + DUK_ASSERT(key != NULL); duk_require_valid_index(ctx, idx_base); @@ -14808,7 +15951,8 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t key, idx_value, get, - set); + set, + 1 /*throw_flag*/); /* Clean up stack */ @@ -14834,26 +15978,30 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t * and are not exposed through the API. */ -DUK_EXTERNAL void duk_compact(duk_context *ctx, duk_idx_t obj_index) { +DUK_EXTERNAL void duk_compact(duk_context *ctx, duk_idx_t obj_idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *obj; DUK_ASSERT_CTX_VALID(ctx); - obj = duk_get_hobject(ctx, obj_index); + obj = duk_get_hobject(ctx, obj_idx); if (obj) { /* Note: this may fail, caller should protect the call if necessary */ duk_hobject_compact_props(thr, obj); } } +DUK_INTERNAL void duk_compact_m1(duk_context *ctx) { + duk_compact(ctx, -1); +} + /* XXX: the duk_hobject_enum.c stack APIs should be reworked */ -DUK_EXTERNAL void duk_enum(duk_context *ctx, duk_idx_t obj_index, duk_uint_t enum_flags) { +DUK_EXTERNAL void duk_enum(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t enum_flags) { DUK_ASSERT_CTX_VALID(ctx); - duk_dup(ctx, obj_index); - duk_require_hobject_or_lfunc_coerce(ctx, -1); + duk_dup(ctx, obj_idx); + duk_require_hobject_promote_mask(ctx, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); duk_hobject_enumerator_create(ctx, enum_flags); /* [target] -> [enum] */ } @@ -14869,31 +16017,34 @@ DUK_EXTERNAL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_index, duk_boo * Helpers for writing multiple properties */ -DUK_EXTERNAL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_index, const duk_function_list_entry *funcs) { +DUK_EXTERNAL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_idx, const duk_function_list_entry *funcs) { const duk_function_list_entry *ent = funcs; DUK_ASSERT_CTX_VALID(ctx); - obj_index = duk_require_normalize_index(ctx, obj_index); + obj_idx = duk_require_normalize_index(ctx, obj_idx); if (ent != NULL) { while (ent->key != NULL) { duk_push_c_function(ctx, ent->value, ent->nargs); - duk_put_prop_string(ctx, obj_index, ent->key); + duk_put_prop_string(ctx, obj_idx, ent->key); ent++; } } } -DUK_EXTERNAL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_index, const duk_number_list_entry *numbers) { +DUK_EXTERNAL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_idx, const duk_number_list_entry *numbers) { const duk_number_list_entry *ent = numbers; + duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); - obj_index = duk_require_normalize_index(ctx, obj_index); + obj_idx = duk_require_normalize_index(ctx, obj_idx); if (ent != NULL) { while (ent->key != NULL) { - duk_push_number(ctx, ent->value); - duk_put_prop_string(ctx, obj_index, ent->key); + tv = ((duk_hthread *) ctx)->valstack_top++; + DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); /* value stack init policy */ + DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv, ent->value); /* no need for decref/incref */ + duk_put_prop_string(ctx, obj_idx, ent->key); ent++; } } @@ -14914,7 +16065,22 @@ DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key) duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]); ret = duk_get_prop_string(ctx, -1, key); - duk_remove(ctx, -2); + duk_remove_m2(ctx); + return ret; +} + +DUK_EXTERNAL duk_bool_t duk_get_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_bool_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); + + /* XXX: direct implementation */ + + duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]); + ret = duk_get_prop_lstring(ctx, -1, key, key_len); + duk_remove_m2(ctx); return ret; } @@ -14934,11 +16100,27 @@ DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key) return ret; } +DUK_EXTERNAL duk_bool_t duk_put_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_bool_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); + + /* XXX: direct implementation */ + + duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]); + duk_insert(ctx, -2); + ret = duk_put_prop_lstring(ctx, -2, key, key_len); /* [ ... global val ] -> [ ... global ] */ + duk_pop(ctx); + return ret; +} + /* * Object prototype */ -DUK_EXTERNAL void duk_get_prototype(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void duk_get_prototype(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *obj; duk_hobject *proto; @@ -14946,7 +16128,7 @@ DUK_EXTERNAL void duk_get_prototype(duk_context *ctx, duk_idx_t index) { DUK_ASSERT_CTX_VALID(ctx); DUK_UNREF(thr); - obj = duk_require_hobject(ctx, index); + obj = duk_require_hobject(ctx, idx); DUK_ASSERT(obj != NULL); /* XXX: shared helper for duk_push_hobject_or_undefined()? */ @@ -14958,14 +16140,14 @@ DUK_EXTERNAL void duk_get_prototype(duk_context *ctx, duk_idx_t index) { } } -DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *obj; duk_hobject *proto; DUK_ASSERT_CTX_VALID(ctx); - obj = duk_require_hobject(ctx, index); + obj = duk_require_hobject(ctx, idx); DUK_ASSERT(obj != NULL); duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_UNDEFINED | DUK_TYPE_MASK_OBJECT); @@ -14988,23 +16170,36 @@ DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t index) { * Object finalizer */ +#if defined(DUK_USE_FINALIZER_SUPPORT) /* XXX: these could be implemented as macros calling an internal function * directly. * XXX: same issue as with Duktape.fin: there's no way to delete the property * now (just set it to undefined). */ -DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); - duk_get_prop_stridx(ctx, index, DUK_STRIDX_INT_FINALIZER); + duk_get_prop_stridx(ctx, idx, DUK_STRIDX_INT_FINALIZER); } -DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT_CTX_VALID(ctx); + + duk_put_prop_stridx(ctx, idx, DUK_STRIDX_INT_FINALIZER); +} +#else /* DUK_USE_FINALIZER_SUPPORT */ +DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(idx); + DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx); +} - duk_put_prop_stridx(ctx, index, DUK_STRIDX_INT_FINALIZER); +DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(idx); + DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx); } -#line 1 "duk_api_stack.c" +#endif /* DUK_USE_FINALIZER_SUPPORT */ /* * API calls related to general value stack manipulation: resizing the value * stack, pushing and popping values, type checking and reading values, @@ -15017,7 +16212,7 @@ DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t index) { /* XXX: repetition of stack pre-checks -> helper or macro or inline */ /* XXX: shared api error strings, and perhaps even throw code for rare cases? */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ /* * Forward declarations @@ -15029,7 +16224,7 @@ DUK_LOCAL_DECL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_functi * Global state for working around missing variadic macros */ -#ifndef DUK_USE_VARIADIC_MACROS +#if !defined(DUK_USE_VARIADIC_MACROS) DUK_EXTERNAL const char *duk_api_global_filename = NULL; DUK_EXTERNAL duk_int_t duk_api_global_line = 0; #endif @@ -15038,6 +16233,35 @@ DUK_EXTERNAL duk_int_t duk_api_global_line = 0; * Misc helpers */ +#if !defined(DUK_USE_PACKED_TVAL) +DUK_LOCAL const duk_uint_t duk__type_from_tag[] = { + DUK_TYPE_NUMBER, + DUK_TYPE_NUMBER, /* fastint */ + DUK_TYPE_UNDEFINED, + DUK_TYPE_NULL, + DUK_TYPE_BOOLEAN, + DUK_TYPE_POINTER, + DUK_TYPE_LIGHTFUNC, + DUK_TYPE_NONE, + DUK_TYPE_STRING, + DUK_TYPE_OBJECT, + DUK_TYPE_BUFFER, +}; +DUK_LOCAL const duk_uint_t duk__type_mask_from_tag[] = { + DUK_TYPE_MASK_NUMBER, + DUK_TYPE_MASK_NUMBER, /* fastint */ + DUK_TYPE_MASK_UNDEFINED, + DUK_TYPE_MASK_NULL, + DUK_TYPE_MASK_BOOLEAN, + DUK_TYPE_MASK_POINTER, + DUK_TYPE_MASK_LIGHTFUNC, + DUK_TYPE_MASK_NONE, + DUK_TYPE_MASK_STRING, + DUK_TYPE_MASK_OBJECT, + DUK_TYPE_MASK_BUFFER, +}; +#endif /* !DUK_USE_PACKED_TVAL */ + /* Check that there's room to push one value. */ #if defined(DUK_USE_VALSTACK_UNSAFE) /* Faster but value stack overruns are memory unsafe. */ @@ -15047,14 +16271,14 @@ DUK_EXTERNAL duk_int_t duk_api_global_line = 0; #else #define DUK__CHECK_SPACE() do { \ if (DUK_UNLIKELY(thr->valstack_top >= thr->valstack_end)) { \ - DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); \ + DUK_ERROR_RANGE_PUSH_BEYOND(thr); \ } \ } 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_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t idx, 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_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t idx, duk_bool_t require) { duk_hthread *thr; duk_tval *tv; duk_small_int_t c; @@ -15062,10 +16286,8 @@ DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t index, duk_b thr = (duk_hthread *) ctx; - tv = duk_get_tval(ctx, index); - if (tv == NULL) { - goto error_notnumber; - } + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); /* * Special cases like NaN and +/- Infinity are handled explicitly @@ -15112,16 +16334,14 @@ DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t index, duk_b } } - error_notnumber: - if (require) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); /* not reachable */ } return 0; } -DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk_bool_t require) { +DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t idx, duk_bool_t require) { duk_hthread *thr; duk_tval *tv; duk_small_int_t c; @@ -15131,10 +16351,8 @@ DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk thr = (duk_hthread *) ctx; - tv = duk_get_tval(ctx, index); - if (tv == NULL) { - goto error_notnumber; - } + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); #if defined(DUK_USE_FASTINT) if (DUK_TVAL_IS_FASTINT(tv)) { @@ -15169,10 +16387,8 @@ DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk } } - error_notnumber: - if (require) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); /* not reachable */ } return 0; @@ -15187,10 +16403,10 @@ DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk * There's some repetition because of this; keep the functions in sync. */ -DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_uidx_t vs_size; - duk_uidx_t uindex; + duk_uidx_t uidx; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(DUK_INVALID_INDEX < 0); @@ -15206,27 +16422,27 @@ DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t index) { vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ - if (index < 0) { - uindex = vs_size + (duk_uidx_t) index; + if (idx < 0) { + uidx = vs_size + (duk_uidx_t) idx; } else { /* since index non-negative */ - DUK_ASSERT(index != DUK_INVALID_INDEX); - uindex = (duk_uidx_t) index; + DUK_ASSERT(idx != DUK_INVALID_INDEX); + uidx = (duk_uidx_t) idx; } /* DUK_INVALID_INDEX won't be accepted as a valid index. */ DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); - if (DUK_LIKELY(uindex < vs_size)) { - return (duk_idx_t) uindex; + if (DUK_LIKELY(uidx < vs_size)) { + return (duk_idx_t) uidx; } return DUK_INVALID_INDEX; } -DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_uidx_t vs_size; - duk_uidx_t uindex; + duk_uidx_t uidx; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(DUK_INVALID_INDEX < 0); @@ -15235,27 +16451,27 @@ DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t i vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ - if (index < 0) { - uindex = vs_size + (duk_uidx_t) index; + if (idx < 0) { + uidx = vs_size + (duk_uidx_t) idx; } else { - DUK_ASSERT(index != DUK_INVALID_INDEX); - uindex = (duk_uidx_t) index; + DUK_ASSERT(idx != DUK_INVALID_INDEX); + uidx = (duk_uidx_t) idx; } /* DUK_INVALID_INDEX won't be accepted as a valid index. */ DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); - if (DUK_LIKELY(uindex < vs_size)) { - return (duk_idx_t) uindex; + if (DUK_LIKELY(uidx < vs_size)) { + return (duk_idx_t) uidx; } - DUK_ERROR_API_INDEX(thr, index); + DUK_ERROR_RANGE_INDEX(thr, idx); return 0; /* unreachable */ } -DUK_INTERNAL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index) { +DUK_INTERNAL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_uidx_t vs_size; - duk_uidx_t uindex; + duk_uidx_t uidx; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(DUK_INVALID_INDEX < 0); @@ -15264,26 +16480,43 @@ DUK_INTERNAL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index) { vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ - if (index < 0) { - uindex = vs_size + (duk_uidx_t) index; + if (idx < 0) { + uidx = vs_size + (duk_uidx_t) idx; } else { - DUK_ASSERT(index != DUK_INVALID_INDEX); - uindex = (duk_uidx_t) index; + DUK_ASSERT(idx != DUK_INVALID_INDEX); + uidx = (duk_uidx_t) idx; } /* DUK_INVALID_INDEX won't be accepted as a valid index. */ DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); - if (DUK_LIKELY(uindex < vs_size)) { - return thr->valstack_bottom + uindex; + if (DUK_LIKELY(uidx < vs_size)) { + return thr->valstack_bottom + uidx; } return NULL; } -DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index) { +/* Variant of duk_get_tval() which is guaranteed to return a valid duk_tval + * pointer. When duk_get_tval() would return NULL, this variant returns a + * pointer to a duk_tval with tag DUK_TAG_UNUSED. This allows the call site + * to avoid an unnecessary NULL check which sometimes leads to better code. + * The return duk_tval is read only (at least for the UNUSED value). + */ +DUK_LOCAL const duk_tval_unused duk__const_tval_unused = DUK_TVAL_UNUSED_INITIALIZER(); + +DUK_INTERNAL duk_tval *duk_get_tval_or_unused(duk_context *ctx, duk_idx_t idx) { + duk_tval *tv; + tv = duk_get_tval(ctx, idx); + if (tv != NULL) { + return tv; + } + return (duk_tval *) DUK_LOSE_CONST(&duk__const_tval_unused); +} + +DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_uidx_t vs_size; - duk_uidx_t uindex; + duk_uidx_t uidx; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(DUK_INVALID_INDEX < 0); @@ -15293,40 +16526,40 @@ DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index) { DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ /* Use unsigned arithmetic to optimize comparison. */ - if (index < 0) { - uindex = vs_size + (duk_uidx_t) index; + if (idx < 0) { + uidx = vs_size + (duk_uidx_t) idx; } else { - DUK_ASSERT(index != DUK_INVALID_INDEX); - uindex = (duk_uidx_t) index; + DUK_ASSERT(idx != DUK_INVALID_INDEX); + uidx = (duk_uidx_t) idx; } /* DUK_INVALID_INDEX won't be accepted as a valid index. */ DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); - if (DUK_LIKELY(uindex < vs_size)) { - return thr->valstack_bottom + uindex; + if (DUK_LIKELY(uidx < vs_size)) { + return thr->valstack_bottom + uidx; } - DUK_ERROR_API_INDEX(thr, index); + DUK_ERROR_RANGE_INDEX(thr, idx); return NULL; } /* Non-critical. */ -DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(DUK_INVALID_INDEX < 0); - return (duk_normalize_index(ctx, index) >= 0); + return (duk_normalize_index(ctx, idx) >= 0); } /* Non-critical. */ -DUK_EXTERNAL void duk_require_valid_index(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void duk_require_valid_index(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(DUK_INVALID_INDEX < 0); - if (duk_normalize_index(ctx, index) < 0) { - DUK_ERROR_API_INDEX(thr, index); + if (duk_normalize_index(ctx, idx) < 0) { + DUK_ERROR_RANGE_INDEX(thr, idx); return; /* unreachable */ } } @@ -15343,15 +16576,31 @@ DUK_EXTERNAL duk_idx_t duk_get_top(duk_context *ctx) { return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); } +/* Internal helper to get current top but to require a minimum top value + * (TypeError if not met). + */ +DUK_INTERNAL duk_idx_t duk_get_top_require_min(duk_context *ctx, duk_idx_t min_top) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_idx_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); + if (ret < min_top) { + DUK_ERROR_TYPE_INVALID_ARGS(thr); + } + return ret; +} + /* Set stack top within currently allocated range, but don't reallocate. * This is performance critical especially for call handling, so whenever * changing, profile and look at generated code. */ -DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_uidx_t vs_size; duk_uidx_t vs_limit; - duk_uidx_t uindex; + duk_uidx_t uidx; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); @@ -15362,16 +16611,16 @@ DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) { vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); vs_limit = (duk_uidx_t) (thr->valstack_end - thr->valstack_bottom); - if (index < 0) { + if (idx < 0) { /* Negative indices are always within allocated stack but * must not go below zero index. */ - uindex = vs_size + (duk_uidx_t) index; + uidx = vs_size + (duk_uidx_t) idx; } else { /* Positive index can be higher than valstack top but must * not go above allocated stack (equality is OK). */ - uindex = (duk_uidx_t) index; + uidx = (duk_uidx_t) idx; } /* DUK_INVALID_INDEX won't be accepted as a valid index. */ @@ -15379,15 +16628,15 @@ DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) { DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_limit); #if defined(DUK_USE_VALSTACK_UNSAFE) - DUK_ASSERT(uindex <= vs_limit); + DUK_ASSERT(uidx <= vs_limit); DUK_UNREF(vs_limit); #else - if (DUK_UNLIKELY(uindex > vs_limit)) { - DUK_ERROR_API_INDEX(thr, index); + if (DUK_UNLIKELY(uidx > vs_limit)) { + DUK_ERROR_RANGE_INDEX(thr, idx); return; /* unreachable */ } #endif - DUK_ASSERT(uindex <= vs_limit); + DUK_ASSERT(uidx <= vs_limit); /* Handle change in value stack top. Respect value stack * initialization policy: 'undefined' above top. Note that @@ -15395,37 +16644,42 @@ DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) { * so must relookup after DECREF. */ - if (uindex >= vs_size) { + if (uidx >= vs_size) { /* Stack size increases or stays the same. */ #if defined(DUK_USE_ASSERTIONS) duk_uidx_t count; - count = uindex - vs_size; + count = uidx - vs_size; while (count != 0) { count--; tv = thr->valstack_top + count; DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); } #endif - thr->valstack_top = thr->valstack_bottom + uindex; + thr->valstack_top = thr->valstack_bottom + uidx; } else { /* Stack size decreases. */ #if defined(DUK_USE_REFERENCE_COUNTING) duk_uidx_t count; + duk_tval *tv_end; - count = vs_size - uindex; + count = vs_size - uidx; DUK_ASSERT(count > 0); - while (count > 0) { - count--; - tv = --thr->valstack_top; /* tv -> value just before prev top value; must relookup */ + tv = thr->valstack_top; + tv_end = tv - count; + DUK_ASSERT(tv > tv_end); /* Because count > 0. */ + do { + tv--; DUK_ASSERT(tv >= thr->valstack_bottom); - DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ - } + DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv); + } while (tv != tv_end); + thr->valstack_top = tv_end; + DUK_REFZERO_CHECK_FAST(thr); #else /* DUK_USE_REFERENCE_COUNTING */ duk_uidx_t count; duk_tval *tv_end; - count = vs_size - uindex; + count = vs_size - uidx; tv = thr->valstack_top; tv_end = tv - count; DUK_ASSERT(tv > tv_end); @@ -15444,7 +16698,7 @@ DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_context *ctx) { DUK_ASSERT_CTX_VALID(ctx); - ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1; + ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1; if (DUK_UNLIKELY(ret < 0)) { /* Return invalid index; if caller uses this without checking * in another API call, the index won't map to a valid stack @@ -15455,15 +16709,28 @@ DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_context *ctx) { return ret; } +/* Internal variant: call assumes there is at least one element on the value + * stack frame; this is only asserted for. + */ +DUK_INTERNAL duk_idx_t duk_get_top_index_unsafe(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_idx_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1; + return ret; +} + DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_idx_t ret; DUK_ASSERT_CTX_VALID(ctx); - ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1; + ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1; if (DUK_UNLIKELY(ret < 0)) { - DUK_ERROR_API_INDEX(thr, -1); + DUK_ERROR_RANGE_INDEX(thr, -1); return 0; /* unreachable */ } return ret; @@ -15496,7 +16763,7 @@ DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size) duk_ptrdiff_t old_bottom_offset; duk_ptrdiff_t old_top_offset; duk_ptrdiff_t old_end_offset_post; -#ifdef DUK_USE_DEBUG +#if defined(DUK_USE_DEBUG) duk_ptrdiff_t old_end_offset_pre; duk_tval *old_valstack_pre; duk_tval *old_valstack_post; @@ -15517,7 +16784,7 @@ DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size) /* get pointer offsets for tweaking below */ old_bottom_offset = (((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack)); old_top_offset = (((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack)); -#ifdef DUK_USE_DEBUG +#if defined(DUK_USE_DEBUG) old_end_offset_pre = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* not very useful, used for debugging */ old_valstack_pre = thr->valstack; #endif @@ -15563,7 +16830,7 @@ DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size) /* success, fixup pointers */ old_end_offset_post = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* must be computed after realloc */ -#ifdef DUK_USE_DEBUG +#if defined(DUK_USE_DEBUG) old_valstack_post = thr->valstack; #endif thr->valstack = new_valstack; @@ -15579,7 +16846,7 @@ DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size) DUK_ASSERT(thr->valstack_end >= thr->valstack_top); /* useful for debugging */ -#ifdef DUK_USE_DEBUG +#if defined(DUK_USE_DEBUG) if (old_end_offset_pre != old_end_offset_post) { DUK_D(DUK_DPRINT("valstack was resized during valstack_resize(), probably by mark-and-sweep; " "end offset changed: %lu -> %lu", @@ -15711,7 +16978,7 @@ duk_bool_t duk_valstack_resize_raw(duk_context *ctx, DUK_DD(DUK_DDPRINT("valstack resize failed")); if (throw_flag) { - DUK_ERROR_ALLOC_DEFMSG(thr); + DUK_ERROR_ALLOC_FAILED(thr); } else { return 0; } @@ -15809,16 +17076,16 @@ DUK_EXTERNAL void duk_require_stack_top(duk_context *ctx, duk_idx_t top) { * Basic stack manipulation: swap, dup, insert, replace, etc */ -DUK_EXTERNAL void duk_swap(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) { +DUK_EXTERNAL void duk_swap(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) { duk_tval *tv1; duk_tval *tv2; duk_tval tv_tmp; DUK_ASSERT_CTX_VALID(ctx); - tv1 = duk_require_tval(ctx, index1); + tv1 = duk_require_tval(ctx, idx1); DUK_ASSERT(tv1 != NULL); - tv2 = duk_require_tval(ctx, index2); + tv2 = duk_require_tval(ctx, idx2); DUK_ASSERT(tv2 != NULL); /* If tv1==tv2 this is a NOP, no check is needed */ @@ -15827,13 +17094,13 @@ DUK_EXTERNAL void duk_swap(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) DUK_TVAL_SET_TVAL(tv2, &tv_tmp); } -DUK_EXTERNAL void duk_swap_top(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void duk_swap_top(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); - duk_swap(ctx, index, -1); + duk_swap(ctx, idx, -1); } -DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_index) { +DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_idx) { duk_hthread *thr; duk_tval *tv_from; duk_tval *tv_to; @@ -15842,7 +17109,7 @@ DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_index) { thr = (duk_hthread *) ctx; DUK__CHECK_SPACE(); - tv_from = duk_require_tval(ctx, from_index); + tv_from = duk_require_tval(ctx, from_idx); tv_to = thr->valstack_top++; DUK_ASSERT(tv_from != NULL); DUK_ASSERT(tv_to != NULL); @@ -15851,6 +17118,9 @@ DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_index) { } DUK_EXTERNAL void duk_dup_top(duk_context *ctx) { +#if defined(DUK_USE_PREFER_SIZE) + duk_dup(ctx, -1); +#else duk_hthread *thr; duk_tval *tv_from; duk_tval *tv_to; @@ -15860,7 +17130,7 @@ DUK_EXTERNAL void duk_dup_top(duk_context *ctx) { DUK__CHECK_SPACE(); if (thr->valstack_top - thr->valstack_bottom <= 0) { - DUK_ERROR_API_INDEX(thr, -1); + DUK_ERROR_RANGE_INDEX(thr, -1); return; /* unreachable */ } tv_from = thr->valstack_top - 1; @@ -15869,9 +17139,29 @@ DUK_EXTERNAL void duk_dup_top(duk_context *ctx) { DUK_ASSERT(tv_to != NULL); DUK_TVAL_SET_TVAL(tv_to, tv_from); DUK_TVAL_INCREF(thr, tv_to); /* no side effects */ +#endif +} + +DUK_INTERNAL void duk_dup_0(duk_context *ctx) { + duk_dup(ctx, 0); +} +DUK_INTERNAL void duk_dup_1(duk_context *ctx) { + duk_dup(ctx, 1); +} +DUK_INTERNAL void duk_dup_2(duk_context *ctx) { + duk_dup(ctx, 2); +} +DUK_INTERNAL void duk_dup_m2(duk_context *ctx) { + duk_dup(ctx, -2); +} +DUK_INTERNAL void duk_dup_m3(duk_context *ctx) { + duk_dup(ctx, -3); +} +DUK_INTERNAL void duk_dup_m4(duk_context *ctx) { + duk_dup(ctx, -4); } -DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) { +DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_idx) { duk_tval *p; duk_tval *q; duk_tval tv_tmp; @@ -15879,7 +17169,7 @@ DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) { DUK_ASSERT_CTX_VALID(ctx); - p = duk_require_tval(ctx, to_index); + p = duk_require_tval(ctx, to_idx); DUK_ASSERT(p != NULL); q = duk_require_tval(ctx, -1); DUK_ASSERT(q != NULL); @@ -15894,8 +17184,8 @@ DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) { nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */ - DUK_DDD(DUK_DDDPRINT("duk_insert: to_index=%ld, p=%p, q=%p, nbytes=%lu", - (long) to_index, (void *) p, (void *) q, (unsigned long) nbytes)); + DUK_DDD(DUK_DDDPRINT("duk_insert: to_idx=%ld, p=%p, q=%p, nbytes=%lu", + (long) to_idx, (void *) p, (void *) q, (unsigned long) nbytes)); /* No net refcount changes. */ @@ -15911,7 +17201,7 @@ DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) { } } -DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_index) { +DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv1; duk_tval *tv2; @@ -15921,7 +17211,7 @@ DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_index) { tv1 = duk_require_tval(ctx, -1); DUK_ASSERT(tv1 != NULL); - tv2 = duk_require_tval(ctx, to_index); + tv2 = duk_require_tval(ctx, to_idx); DUK_ASSERT(tv2 != NULL); /* For tv1 == tv2, both pointing to stack top, the end result @@ -15934,7 +17224,7 @@ DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_index) { DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */ } -DUK_EXTERNAL void duk_copy(duk_context *ctx, duk_idx_t from_index, duk_idx_t to_index) { +DUK_EXTERNAL void duk_copy(duk_context *ctx, duk_idx_t from_idx, duk_idx_t to_idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv1; duk_tval *tv2; @@ -15942,27 +17232,27 @@ DUK_EXTERNAL void duk_copy(duk_context *ctx, duk_idx_t from_index, duk_idx_t to_ DUK_ASSERT_CTX_VALID(ctx); DUK_UNREF(thr); /* w/o refcounting */ - tv1 = duk_require_tval(ctx, from_index); + tv1 = duk_require_tval(ctx, from_idx); DUK_ASSERT(tv1 != NULL); - tv2 = duk_require_tval(ctx, to_index); + tv2 = duk_require_tval(ctx, to_idx); DUK_ASSERT(tv2 != NULL); /* For tv1 == tv2, this is a no-op (no explicit check needed). */ DUK_TVAL_SET_TVAL_UPDREF(thr, tv2, tv1); /* side effects */ } -DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *p; duk_tval *q; -#ifdef DUK_USE_REFERENCE_COUNTING +#if defined(DUK_USE_REFERENCE_COUNTING) duk_tval tv_tmp; #endif duk_size_t nbytes; DUK_ASSERT_CTX_VALID(ctx); - p = duk_require_tval(ctx, index); + p = duk_require_tval(ctx, idx); DUK_ASSERT(p != NULL); q = duk_require_tval(ctx, -1); DUK_ASSERT(q != NULL); @@ -15975,7 +17265,7 @@ DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index) { * => [ ... | x | x | q ] [ ... ] */ -#ifdef DUK_USE_REFERENCE_COUNTING +#if defined(DUK_USE_REFERENCE_COUNTING) /* use a temp: decref only when valstack reachable values are correct */ DUK_TVAL_SET_TVAL(&tv_tmp, p); #endif @@ -15986,11 +17276,15 @@ DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index) { DUK_TVAL_SET_UNDEFINED(q); thr->valstack_top--; -#ifdef DUK_USE_REFERENCE_COUNTING +#if defined(DUK_USE_REFERENCE_COUNTING) DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */ #endif } +DUK_INTERNAL_DECL void duk_remove_m2(duk_context *ctx) { + duk_remove(ctx, -2); +} + /* * Stack slice primitives */ @@ -16011,13 +17305,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_API(to_thr, DUK_STR_INVALID_CONTEXT); + DUK_ERROR_TYPE(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_API(to_thr, DUK_STR_INVALID_COUNT); + DUK_ERROR_RANGE_INVALID_COUNT(to_thr); return; } @@ -16027,11 +17321,11 @@ 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_API(to_thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_RANGE_PUSH_BEYOND(to_thr); } src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes); if (src < (void *) from_thr->valstack_bottom) { - DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT); + DUK_ERROR_RANGE_INVALID_COUNT(to_thr); } /* copy values (no overlap even if to_ctx == from_ctx; that's not @@ -16068,42 +17362,41 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, * Get/require */ -DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_UNDEFINED(tv)) { - return; + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (!DUK_TVAL_IS_UNDEFINED(tv)) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "undefined", 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) { +DUK_EXTERNAL void duk_require_null(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_NULL(tv)) { - return; + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (!DUK_TVAL_IS_NULL(tv)) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "null", DUK_STR_NOT_NULL); } - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "null", DUK_STR_NOT_NULL); - return; /* not reachable */ } -DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx) { duk_bool_t ret = 0; /* default: false */ duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_BOOLEAN(tv)) { + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (DUK_TVAL_IS_BOOLEAN(tv)) { ret = DUK_TVAL_GET_BOOLEAN(tv); } @@ -16111,91 +17404,92 @@ DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t index) { return ret; } -DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; + duk_bool_t ret; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_BOOLEAN(tv)) { - duk_bool_t ret = DUK_TVAL_GET_BOOLEAN(tv); - DUK_ASSERT(ret == 0 || ret == 1); - return ret; + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (!DUK_TVAL_IS_BOOLEAN(tv)) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "boolean", DUK_STR_NOT_BOOLEAN); } - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "boolean", DUK_STR_NOT_BOOLEAN); - return 0; /* not reachable */ + ret = DUK_TVAL_GET_BOOLEAN(tv); + DUK_ASSERT(ret == 0 || ret == 1); + return ret; } -DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx) { duk_double_union ret; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); ret.d = DUK_DOUBLE_NAN; /* default: NaN */ - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_NUMBER(tv)) { + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (DUK_TVAL_IS_NUMBER(tv)) { ret.d = DUK_TVAL_GET_NUMBER(tv); } - /* - * Number should already be in NaN-normalized form, but let's - * normalize anyway. + /* When using packed duk_tval, number must be in NaN-normalized form + * for it to be a duk_tval, so no need to normalize. NOP for unpacked + * duk_tval. */ - - DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret); + DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); return ret.d; } -DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; + duk_double_union ret; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_NUMBER(tv)) { - duk_double_union ret; - ret.d = DUK_TVAL_GET_NUMBER(tv); + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (!DUK_TVAL_IS_NUMBER(tv)) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); + } - /* - * Number should already be in NaN-normalized form, - * but let's normalize anyway. - */ + ret.d = DUK_TVAL_GET_NUMBER(tv); - DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret); - return ret.d; - } - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER); - return DUK_DOUBLE_NAN; /* not reachable */ + /* When using packed duk_tval, number must be in NaN-normalized form + * for it to be a duk_tval, so no need to normalize. NOP for unpacked + * duk_tval. + */ + DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); + return ret.d; } -DUK_EXTERNAL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t idx) { /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_int_t) duk__api_coerce_d2i(ctx, index, 0 /*require*/); + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*require*/); } -DUK_EXTERNAL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t idx) { /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 0 /*require*/); + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*require*/); } -DUK_EXTERNAL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t idx) { /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_int_t) duk__api_coerce_d2i(ctx, index, 1 /*require*/); + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 1 /*require*/); } -DUK_EXTERNAL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t idx) { /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 1 /*require*/); + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 1 /*require*/); } -DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) { +DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { const char *ret; duk_tval *tv; @@ -16207,8 +17501,9 @@ DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t index, duk_ *out_len = 0; } - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_STRING(tv)) { + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (DUK_TVAL_IS_STRING(tv)) { /* Here we rely on duk_hstring instances always being zero * terminated even if the actual string is not. */ @@ -16223,87 +17518,125 @@ DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t index, duk_ return ret; } -DUK_EXTERNAL const char *duk_require_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) { - duk_hthread *thr = (duk_hthread *) ctx; - const char *ret; +DUK_EXTERNAL const char *duk_require_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { + duk_hstring *h; DUK_ASSERT_CTX_VALID(ctx); - /* Note: this check relies on the fact that even a zero-size string - * has a non-NULL pointer. - */ - ret = duk_get_lstring(ctx, index, out_len); - if (ret) { - return ret; + h = duk_require_hstring(ctx, idx); + DUK_ASSERT(h != NULL); + if (out_len) { + *out_len = DUK_HSTRING_GET_BYTELEN(h); + } + return (const char *) DUK_HSTRING_GET_DATA(h); +} + +DUK_INTERNAL const char *duk_require_lstring_notsymbol(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { + duk_hstring *h; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_require_hstring_notsymbol(ctx, idx); + DUK_ASSERT(h != NULL); + if (out_len) { + *out_len = DUK_HSTRING_GET_BYTELEN(h); + } + return (const char *) DUK_HSTRING_GET_DATA(h); +} + +DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk_get_lstring(ctx, idx, NULL); +} + +DUK_INTERNAL const char *duk_get_string_notsymbol(duk_context *ctx, duk_idx_t idx) { + duk_hstring *h; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hstring_notsymbol(ctx, idx); + if (h) { + return (const char *) DUK_HSTRING_GET_DATA(h); + } else { + return NULL; } - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "string", DUK_STR_NOT_STRING); - return NULL; /* not reachable */ } -DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL const char *duk_require_string(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); - return duk_get_lstring(ctx, index, NULL); + return duk_require_lstring(ctx, idx, NULL); } -DUK_EXTERNAL const char *duk_require_string(duk_context *ctx, duk_idx_t index) { +DUK_INTERNAL const char *duk_require_string_notsymbol(duk_context *ctx, duk_idx_t idx) { + duk_hstring *h; + DUK_ASSERT_CTX_VALID(ctx); - return duk_require_lstring(ctx, index, NULL); + h = duk_require_hstring_notsymbol(ctx, idx); + DUK_ASSERT(h != NULL); + return (const char *) DUK_HSTRING_GET_DATA(h); } -DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; + void *p; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_POINTER(tv)) { - void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ - return (void *) p; + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (!DUK_TVAL_IS_POINTER(tv)) { + return NULL; } - return NULL; + p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ + return p; } -DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; + void *p; DUK_ASSERT_CTX_VALID(ctx); /* Note: here we must be wary of the fact that a pointer may be * valid and be a NULL. */ - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_POINTER(tv)) { - void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ - return (void *) p; + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (!DUK_TVAL_IS_POINTER(tv)) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "pointer", DUK_STR_NOT_POINTER); } - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "pointer", DUK_STR_NOT_POINTER); - return NULL; /* not reachable */ + p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ + return p; } #if 0 /*unused*/ -DUK_INTERNAL void *duk_get_voidptr(duk_context *ctx, duk_idx_t index) { +DUK_INTERNAL void *duk_get_voidptr(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; + duk_heaphdr *h; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { - duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(h != NULL); - return (void *) h; + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { + return NULL; } - return NULL; + h = DUK_TVAL_GET_HEAPHDR(tv); + DUK_ASSERT(h != NULL); + return (void *) h; } #endif -DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_bool_t throw_flag) { +DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; + duk_hbuffer *h; DUK_ASSERT_CTX_VALID(ctx); DUK_UNREF(thr); @@ -16312,90 +17645,105 @@ DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t index, duk_si *out_size = 0; } - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_BUFFER(tv)) { - duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h != NULL); - if (out_size) { - *out_size = DUK_HBUFFER_GET_SIZE(h); + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (!DUK_TVAL_IS_BUFFER(tv)) { + if (throw_flag) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); } - return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */ + return NULL; } - if (throw_flag) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER); + h = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h != NULL); + if (out_size) { + *out_size = DUK_HBUFFER_GET_SIZE(h); } - return NULL; + return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */ } -DUK_EXTERNAL void *duk_get_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) { - return duk__get_buffer_helper(ctx, index, out_size, 0 /*throw_flag*/); +DUK_EXTERNAL void *duk_get_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { + return duk__get_buffer_helper(ctx, idx, out_size, 0 /*throw_flag*/); } -DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) { - return duk__get_buffer_helper(ctx, index, out_size, 1 /*throw_flag*/); +DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { + return duk__get_buffer_helper(ctx, idx, out_size, 1 /*throw_flag*/); } -DUK_LOCAL void *duk__get_buffer_data_helper(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_bool_t throw_flag) { +/* Get the active buffer data area for a plain buffer or a buffer object. + * Return NULL if the the value is not a buffer. Note that a buffer may + * have a NULL data pointer when its size is zero, the optional 'out_isbuffer' + * argument allows caller to detect this reliably. + */ +DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); DUK_UNREF(thr); + if (out_isbuffer != NULL) { + *out_isbuffer = 0; + } if (out_size != NULL) { *out_size = 0; } - tv = duk_get_tval(ctx, index); - if (tv == NULL) { - goto fail; - } + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); if (DUK_TVAL_IS_BUFFER(tv)) { duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); DUK_ASSERT(h != NULL); - if (out_size) { + if (out_size != NULL) { *out_size = DUK_HBUFFER_GET_SIZE(h); } + if (out_isbuffer != NULL) { + *out_isbuffer = 1; + } return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */ - } else if (DUK_TVAL_IS_OBJECT(tv)) { + } +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) + else if (DUK_TVAL_IS_OBJECT(tv)) { duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); - if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) { + if (DUK_HOBJECT_IS_BUFOBJ(h)) { /* XXX: this is probably a useful shared helper: for a - * duk_hbufferobject, get a validated buffer pointer/length. + * duk_hbufobj, get a validated buffer pointer/length. */ - duk_hbufferobject *h_bufobj = (duk_hbufferobject *) h; - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + duk_hbufobj *h_bufobj = (duk_hbufobj *) h; + DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); if (h_bufobj->buf != NULL && - DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) { + DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) { duk_uint8_t *p; p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf); if (out_size != NULL) { *out_size = (duk_size_t) h_bufobj->length; } + if (out_isbuffer != NULL) { + *out_isbuffer = 1; + } return (void *) (p + h_bufobj->offset); } /* if slice not fully valid, treat as error */ } } +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - fail: if (throw_flag) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); } return NULL; } -DUK_EXTERNAL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) { - return duk__get_buffer_data_helper(ctx, index, out_size, 0 /*throw_flag*/); +DUK_EXTERNAL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { + return duk_get_buffer_data_raw(ctx, idx, out_size, 0 /*throw_flag*/, NULL); } -DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) { - return duk__get_buffer_data_helper(ctx, index, out_size, 1 /*throw_flag*/); +DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { + return duk_get_buffer_data_raw(ctx, idx, out_size, 1 /*throw_flag*/, NULL); } /* Raw helper for getting a value from the stack, checking its tag. @@ -16403,290 +17751,301 @@ DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t index, du * tag in the packed representation. */ -DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag) { +DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t idx, duk_uint_t tag) { duk_tval *tv; + duk_heaphdr *ret; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (tv && (DUK_TVAL_GET_TAG(tv) == tag)) { - duk_heaphdr *ret; - ret = DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */ - return ret; + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (DUK_TVAL_GET_TAG(tv) != tag) { + return (duk_heaphdr *) NULL; } - return (duk_heaphdr *) NULL; + ret = DUK_TVAL_GET_HEAPHDR(tv); + DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */ + return ret; + } -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_INTERNAL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t idx) { + return (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); } -DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index) { - duk_heaphdr *h; - h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING); +DUK_INTERNAL duk_hstring *duk_get_hstring_notsymbol(duk_context *ctx, duk_idx_t idx) { + duk_hstring *res = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); + if (res && DUK_HSTRING_HAS_SYMBOL(res)) { + return NULL; + } + return res; +} + +DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t idx) { + duk_hstring *h; + h = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); if (h == NULL) { - DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "string", DUK_STR_NOT_STRING); + DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "string", DUK_STR_NOT_STRING); } - return (duk_hstring *) h; + return 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_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_context *ctx, duk_idx_t idx) { + duk_hstring *h; + h = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); + if (h == NULL || DUK_HSTRING_HAS_SYMBOL(h)) { + DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "string", DUK_STR_NOT_STRING); + } + return h; } -DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index) { - duk_heaphdr *h; - h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); +DUK_INTERNAL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t idx) { + return (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); +} + +DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t idx) { + duk_hobject *h; + h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); if (h == NULL) { - DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "object", DUK_STR_NOT_OBJECT); + DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "object", DUK_STR_NOT_OBJECT); } - return (duk_hobject *) h; + return 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_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t idx) { + return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_BUFFER); } -DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index) { - duk_heaphdr *h; - h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER); +DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t idx) { + duk_hbuffer *h; + h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_BUFFER); if (h == NULL) { - DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "buffer", DUK_STR_NOT_BUFFER); + DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "buffer", DUK_STR_NOT_BUFFER); } - return (duk_hbuffer *) h; + return 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_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t idx) { + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); if (h != NULL && !DUK_HOBJECT_IS_THREAD(h)) { h = NULL; } return (duk_hthread *) h; } -DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index) { +DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; - duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); if (!(h != NULL && DUK_HOBJECT_IS_THREAD(h))) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "thread", DUK_STR_NOT_THREAD); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "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); - if (h != NULL && !DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) { +DUK_INTERNAL duk_hcompfunc *duk_get_hcompfunc(duk_context *ctx, duk_idx_t idx) { + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); + if (h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h)) { h = NULL; } - return (duk_hcompiledfunction *) h; + return (duk_hcompfunc *) h; } -DUK_INTERNAL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index) { +DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; - 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); + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); + if (!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h))) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "compiledfunction", DUK_STR_NOT_COMPFUNC); } - return (duk_hcompiledfunction *) h; + return (duk_hcompfunc *) 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); - if (h != NULL && !DUK_HOBJECT_IS_NATIVEFUNCTION(h)) { +DUK_INTERNAL duk_hnatfunc *duk_get_hnatfunc(duk_context *ctx, duk_idx_t idx) { + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); + if (h != NULL && !DUK_HOBJECT_IS_NATFUNC(h)) { h = NULL; } - return (duk_hnativefunction *) h; + return (duk_hnatfunc *) h; } -DUK_INTERNAL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index) { +DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; - 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); + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); + if (!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h))) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC); } - return (duk_hnativefunction *) h; + return (duk_hnatfunc *) h; } -DUK_EXTERNAL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; duk_hobject *h; - duk_hnativefunction *f; + duk_hnatfunc *f; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (!tv) { - return NULL; - } + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); if (!DUK_TVAL_IS_OBJECT(tv)) { return NULL; } h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); - if (!DUK_HOBJECT_IS_NATIVEFUNCTION(h)) { + if (!DUK_HOBJECT_IS_NATFUNC(h)) { return NULL; } - DUK_ASSERT(DUK_HOBJECT_HAS_NATIVEFUNCTION(h)); - f = (duk_hnativefunction *) h; + DUK_ASSERT(DUK_HOBJECT_HAS_NATFUNC(h)); + f = (duk_hnatfunc *) h; return f->func; } -DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_c_function ret; DUK_ASSERT_CTX_VALID(ctx); - ret = duk_get_c_function(ctx, index); + ret = duk_get_c_function(ctx, idx); if (!ret) { - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC); } 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 void duk_require_function(duk_context *ctx, duk_idx_t idx) { + if (!duk_is_function(ctx, idx)) { + DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "function", DUK_STR_NOT_FUNCTION); + } +} + +DUK_INTERNAL_DECL void duk_require_constructable(duk_context *ctx, duk_idx_t idx) { + duk_hobject *h; + + h = duk_require_hobject_accept_mask(ctx, idx, DUK_TYPE_MASK_LIGHTFUNC); + if (h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) { + DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "constructable", DUK_STR_NOT_CONSTRUCTABLE); } + /* Lightfuncs (h == NULL) are constructable. */ } -DUK_EXTERNAL duk_context *duk_get_context(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_context *duk_get_context(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); - return (duk_context *) duk_get_hthread(ctx, index); + return (duk_context *) duk_get_hthread(ctx, idx); } -DUK_EXTERNAL duk_context *duk_require_context(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_context *duk_require_context(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); - return (duk_context *) duk_require_hthread(ctx, index); + return (duk_context *) duk_require_hthread(ctx, idx); } -DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; void *ret; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { - ret = (void *) DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(ret != NULL); - return ret; + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { + return (void *) NULL; } - return (void *) NULL; + ret = (void *) DUK_TVAL_GET_HEAPHDR(tv); + DUK_ASSERT(ret != NULL); + return ret; } -DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; void *ret; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_require_tval(ctx, index); + tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { - ret = (void *) DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(ret != NULL); - return ret; + if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "heapobject", DUK_STR_UNEXPECTED_TYPE); } - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "heapobject", DUK_STR_UNEXPECTED_TYPE); - return (void *) NULL; /* not reachable */ -} - -#if 0 -/* This would be pointless: we'd return NULL for both lightfuncs and - * unexpected types. - */ -DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) { + ret = (void *) DUK_TVAL_GET_HEAPHDR(tv); + DUK_ASSERT(ret != NULL); + return ret; } -#endif -/* Useful for internal call sites where we either expect an object (function) - * or a lightfunc. Accepts an object (returned as is) or a lightfunc (coerced - * to an object). Return value is NULL if value is neither an object nor a - * lightfunc. - */ -DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) { - duk_tval *tv; +/* Internal helper for getting/requiring a duk_hobject with possible promotion. */ +DUK_LOCAL duk_hobject *duk__get_hobject_promote_mask_raw(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask) { + duk_uint_t val_mask; + duk_hobject *res; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_require_tval(ctx, index); - DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_OBJECT(tv)) { - return DUK_TVAL_GET_OBJECT(tv); - } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { - duk_to_object(ctx, index); - return duk_require_hobject(ctx, index); + res = duk_get_hobject(ctx, idx); /* common case, not promoted */ + if (res != NULL) { + DUK_ASSERT(res != NULL); + return res; } + val_mask = duk_get_type_mask(ctx, idx); + if (val_mask & type_mask) { + if (type_mask & DUK_TYPE_MASK_PROMOTE) { + res = duk_to_hobject(ctx, idx); + DUK_ASSERT(res != NULL); + return res; + } else { + return NULL; /* accept without promoting */ + } + } + + if (type_mask & DUK_TYPE_MASK_THROW) { + DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "object", DUK_STR_NOT_OBJECT); + } return NULL; } -/* Useful for internal call sites where we either expect an object (function) - * or a lightfunc. Returns NULL for a lightfunc. +/* Get a duk_hobject * at 'idx'; if the value is not an object but matches the + * supplied 'type_mask', promote it to an object and return the duk_hobject *. + * This is useful for call sites which want an object but also accept a plain + * buffer and/or a lightfunc which gets automatically promoted to an object. + * Return value is NULL if value is neither an object nor a plain type allowed + * by the mask. */ -DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) { - duk_hthread *thr = (duk_hthread *) ctx; - duk_tval *tv; - - DUK_ASSERT_CTX_VALID(ctx); - - tv = duk_require_tval(ctx, index); - DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_OBJECT(tv)) { - return DUK_TVAL_GET_OBJECT(tv); - } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { - return NULL; - } - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT); - return NULL; /* not reachable */ +DUK_INTERNAL duk_hobject *duk_get_hobject_promote_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask) { + return duk__get_hobject_promote_mask_raw(ctx, idx, type_mask | DUK_TYPE_MASK_PROMOTE); } -/* Useful for internal call sites where we either expect an object (function) - * or a lightfunc. Accepts an object (returned as is) or a lightfunc (coerced - * to an object). Return value is never NULL. +/* Like duk_get_hobject_promote_mask() but throw a TypeError instead of + * returning a NULL. */ -DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) { - duk_hthread *thr = (duk_hthread *) ctx; - duk_tval *tv; - - DUK_ASSERT_CTX_VALID(ctx); +DUK_INTERNAL duk_hobject *duk_require_hobject_promote_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask) { + return duk__get_hobject_promote_mask_raw(ctx, idx, type_mask | DUK_TYPE_MASK_THROW | DUK_TYPE_MASK_PROMOTE); +} - tv = duk_require_tval(ctx, index); - if (DUK_TVAL_IS_OBJECT(tv)) { - return DUK_TVAL_GET_OBJECT(tv); - } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { - duk_to_object(ctx, index); - return duk_require_hobject(ctx, index); - } - DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT); - return NULL; /* not reachable */ +/* Require a duk_hobject * at 'idx'; if the value is not an object but matches the + * supplied 'type_mask', return a NULL instead. Otherwise throw a TypeError. + */ +DUK_INTERNAL duk_hobject *duk_require_hobject_accept_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask) { + return duk__get_hobject_promote_mask_raw(ctx, idx, type_mask | DUK_TYPE_MASK_THROW); } -DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) { +DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t idx, 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); + h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, 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_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t idx, duk_small_uint_t classnum) { duk_hthread *thr; duk_hobject *h; @@ -16695,26 +18054,24 @@ DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_i DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX); thr = (duk_hthread *) ctx; - h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, 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); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, (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_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (!tv) { - return 0; - } + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); switch (DUK_TVAL_GET_TAG(tv)) { case DUK_TAG_UNDEFINED: @@ -16722,16 +18079,29 @@ DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index) { case DUK_TAG_BOOLEAN: case DUK_TAG_POINTER: return 0; +#if defined(DUK_USE_PREFER_SIZE) + /* All of these types (besides object) have a virtual, non-configurable + * .length property which is within size_t range so we can just look it + * up without specific type checks. + */ + case DUK_TAG_STRING: + case DUK_TAG_BUFFER: + case DUK_TAG_LIGHTFUNC: { + duk_size_t ret; + duk_get_prop_stridx(ctx, idx, DUK_STRIDX_LENGTH); + ret = (duk_size_t) duk_to_number_m1(ctx); + duk_pop(ctx); + return ret; + } +#else /* DUK_USE_PREFER_SIZE */ case DUK_TAG_STRING: { duk_hstring *h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); + if (DUK_HSTRING_HAS_SYMBOL(h)) { + return 0; + } return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h); } - case DUK_TAG_OBJECT: { - duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - return (duk_size_t) duk_hobject_get_length((duk_hthread *) ctx, h); - } case DUK_TAG_BUFFER: { duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); DUK_ASSERT(h != NULL); @@ -16742,31 +18112,83 @@ DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index) { lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); return (duk_size_t) DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags); } +#endif /* DUK_USE_PREFER_SIZE */ + case DUK_TAG_OBJECT: { + duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + return (duk_size_t) duk_hobject_get_length((duk_hthread *) ctx, h); + } #if defined(DUK_USE_FASTINT) case DUK_TAG_FASTINT: #endif default: - /* number */ - DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + /* number or 'unused' */ + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv) || DUK_TVAL_IS_UNUSED(tv)); return 0; } DUK_UNREACHABLE(); } -DUK_INTERNAL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t length) { +/* + * duk_known_xxx() helpers + * + * Used internally when we're 100% sure that a certain index is valid and + * contains an object of a certain type. For example, if we duk_push_object() + * we can then safely duk_known_hobject(ctx, -1). These helpers just assert + * for the index and type, and if the assumptions are not valid, memory unsafe + * behavior happens. + */ + +DUK_LOCAL duk_heaphdr *duk__known_heaphdr(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; - duk_hobject *h; + duk_tval *tv; + duk_heaphdr *h; DUK_ASSERT_CTX_VALID(ctx); - - h = duk_get_hobject(ctx, index); - if (!h) { - return; + if (idx < 0) { + tv = thr->valstack_top + idx; + } else { + tv = thr->valstack_bottom + idx; } + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_ASSERT(tv < thr->valstack_top); + h = DUK_TVAL_GET_HEAPHDR(tv); + DUK_ASSERT(h != NULL); + return h; +} + +DUK_INTERNAL duk_hstring *duk_known_hstring(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT(duk_get_hstring(ctx, idx) != NULL); + return (duk_hstring *) duk__known_heaphdr(ctx, idx); +} + +DUK_INTERNAL duk_hobject *duk_known_hobject(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT(duk_get_hobject(ctx, idx) != NULL); + return (duk_hobject *) duk__known_heaphdr(ctx, idx); +} - duk_hobject_set_length(thr, h, (duk_uint32_t) length); /* XXX: typing */ +DUK_INTERNAL duk_hbuffer *duk_known_hbuffer(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT(duk_get_hbuffer(ctx, idx) != NULL); + return (duk_hbuffer *) duk__known_heaphdr(ctx, idx); +} + +DUK_INTERNAL duk_hcompfunc *duk_known_hcompfunc(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT(duk_get_hcompfunc(ctx, idx) != NULL); + return (duk_hcompfunc *) duk__known_heaphdr(ctx, idx); +} + +DUK_INTERNAL duk_hnatfunc *duk_known_hnatfunc(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT(duk_get_hnatfunc(ctx, idx) != NULL); + return (duk_hnatfunc *) duk__known_heaphdr(ctx, idx); +} + +DUK_EXTERNAL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len) { + DUK_ASSERT_CTX_VALID(ctx); + + idx = duk_normalize_index(ctx, idx); + duk_push_uint(ctx, (duk_uint_t) len); + duk_put_prop_stridx(ctx, idx, DUK_STRIDX_LENGTH); } /* @@ -16779,14 +18201,14 @@ DUK_INTERNAL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t l /* E5 Section 8.12.8 */ -DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_context *ctx, duk_idx_t index, duk_small_int_t func_stridx) { - if (duk_get_prop_stridx(ctx, index, func_stridx)) { +DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_context *ctx, duk_idx_t idx, duk_small_int_t func_stridx) { + if (duk_get_prop_stridx(ctx, idx, func_stridx)) { /* [ ... func ] */ if (duk_is_callable(ctx, -1)) { - duk_dup(ctx, index); /* -> [ ... func this ] */ + duk_dup(ctx, idx); /* -> [ ... func this ] */ duk_call_method(ctx, 0); /* -> [ ... retval ] */ if (duk_is_primitive(ctx, -1)) { - duk_replace(ctx, index); + duk_replace(ctx, idx); return 1; } /* [ ... retval ]; popped below */ @@ -16796,86 +18218,113 @@ DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_context *ctx, duk_idx_ return 0; } -DUK_EXTERNAL void duk_to_defaultvalue(duk_context *ctx, duk_idx_t index, duk_int_t hint) { - duk_hthread *thr = (duk_hthread *) ctx; - duk_hobject *obj; - /* inline initializer for coercers[] is not allowed by old compilers like BCC */ - duk_small_int_t coercers[2]; - - DUK_ASSERT_CTX_VALID(ctx); - DUK_ASSERT(thr != NULL); - - coercers[0] = DUK_STRIDX_VALUE_OF; - coercers[1] = DUK_STRIDX_TO_STRING; - - index = duk_require_normalize_index(ctx, index); - obj = duk_require_hobject_or_lfunc(ctx, index); - - if (hint == DUK_HINT_NONE) { - if (obj != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_DATE) { - hint = DUK_HINT_STRING; - } else { - hint = DUK_HINT_NUMBER; - } - } - - if (hint == DUK_HINT_STRING) { - coercers[0] = DUK_STRIDX_TO_STRING; - coercers[1] = DUK_STRIDX_VALUE_OF; - } - - if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[0])) { - return; - } - - if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[1])) { - return; - } - - DUK_ERROR_TYPE(thr, DUK_STR_DEFAULTVALUE_COERCE_FAILED); -} - -DUK_EXTERNAL void duk_to_undefined(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void duk_to_undefined(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); DUK_UNREF(thr); - tv = duk_require_tval(ctx, index); + tv = duk_require_tval(ctx, idx); DUK_ASSERT(tv != NULL); DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ } -DUK_EXTERNAL void duk_to_null(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void duk_to_null(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); DUK_UNREF(thr); - tv = duk_require_tval(ctx, index); + tv = duk_require_tval(ctx, idx); DUK_ASSERT(tv != NULL); DUK_TVAL_SET_NULL_UPDREF(thr, tv); /* side effects */ } /* E5 Section 9.1 */ -DUK_EXTERNAL void duk_to_primitive(duk_context *ctx, duk_idx_t index, duk_int_t hint) { +DUK_EXTERNAL void duk_to_primitive(duk_context *ctx, duk_idx_t idx, duk_int_t hint) { + duk_hthread *thr = (duk_hthread *) ctx; + /* inline initializer for coercers[] is not allowed by old compilers like BCC */ + duk_small_int_t coercers[2]; + duk_small_uint_t class_number; + DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING); - index = duk_require_normalize_index(ctx, index); + idx = duk_require_normalize_index(ctx, idx); + + if (!duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_OBJECT | + DUK_TYPE_MASK_LIGHTFUNC | + DUK_TYPE_MASK_BUFFER)) { + /* Any other values stay as is. */ + DUK_ASSERT(!duk_is_buffer(ctx, idx)); /* duk_to_string() relies on this behavior */ + return; + } + + class_number = duk_get_class_number(ctx, idx); + + /* XXX: Symbol objects normally coerce via the ES2015-revised ToPrimitive() + * algorithm which consults value[@@toPrimitive] and avoids calling + * .valueOf() and .toString(). Before that is implemented, special + * case Symbol objects to behave as if they had the default @@toPrimitive + * algorithm of E6 Section 19.4.3.4, i.e. return the plain symbol value + * with no further side effects. + */ + + if (class_number == DUK_HOBJECT_CLASS_SYMBOL) { + duk_hobject *h_obj; + duk_hstring *h_str; + + /* XXX: pretty awkward, index based API for internal value access? */ + h_obj = duk_known_hobject(ctx, idx); + h_str = duk_hobject_get_internal_value_string(thr->heap, h_obj); + if (h_str) { + duk_push_hstring(ctx, h_str); + duk_replace(ctx, idx); + return; + } + } + + + /* Objects are coerced based on E5 specification. + * Lightfuncs are coerced because they behave like + * objects even if they're internally a primitive + * type. Same applies to plain buffers, which behave + * like ArrayBuffer objects since Duktape 2.x. + */ + + coercers[0] = DUK_STRIDX_VALUE_OF; + coercers[1] = DUK_STRIDX_TO_STRING; + + if (hint == DUK_HINT_NONE) { + if (class_number == DUK_HOBJECT_CLASS_DATE) { + hint = DUK_HINT_STRING; + } else { + hint = DUK_HINT_NUMBER; + } + } + + if (hint == DUK_HINT_STRING) { + coercers[0] = DUK_STRIDX_TO_STRING; + coercers[1] = DUK_STRIDX_VALUE_OF; + } - if (!duk_check_type_mask(ctx, index, DUK_TYPE_MASK_OBJECT | - DUK_TYPE_MASK_LIGHTFUNC)) { - /* everything except object stay as is */ + if (duk__defaultvalue_coerce_attempt(ctx, idx, coercers[0])) { + DUK_ASSERT(!duk_is_buffer(ctx, idx)); /* duk_to_string() relies on this behavior */ return; } - duk_to_defaultvalue(ctx, index, hint); + + if (duk__defaultvalue_coerce_attempt(ctx, idx, coercers[1])) { + DUK_ASSERT(!duk_is_buffer(ctx, idx)); /* duk_to_string() relies on this behavior */ + return; + } + + DUK_ERROR_TYPE(thr, DUK_STR_TOPRIMITIVE_FAILED); } /* E5 Section 9.2 */ -DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; duk_bool_t val; @@ -16883,135 +18332,155 @@ DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t index) { DUK_ASSERT_CTX_VALID(ctx); DUK_UNREF(thr); - index = duk_require_normalize_index(ctx, index); - - tv = duk_require_tval(ctx, index); + idx = duk_require_normalize_index(ctx, idx); + tv = DUK_GET_TVAL_POSIDX(ctx, idx); DUK_ASSERT(tv != NULL); val = duk_js_toboolean(tv); DUK_ASSERT(val == 0 || val == 1); - /* Note: no need to re-lookup tv, conversion is side effect free */ + /* Note: no need to re-lookup tv, conversion is side effect free. */ DUK_ASSERT(tv != NULL); DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, val); /* side effects */ return val; } -DUK_EXTERNAL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; duk_double_t d; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_require_tval(ctx, index); + /* XXX: No need to normalize; the whole operation could be inlined here to + * avoid 'tv' re-lookup. + */ + idx = duk_require_normalize_index(ctx, idx); + tv = DUK_GET_TVAL_POSIDX(ctx, idx); DUK_ASSERT(tv != NULL); - /* XXX: fastint? */ - d = duk_js_tonumber(thr, tv); + d = duk_js_tonumber(thr, tv); /* XXX: fastint coercion? now result will always be a non-fastint */ - /* Note: need to re-lookup because ToNumber() may have side effects */ - tv = duk_require_tval(ctx, index); + /* ToNumber() may have side effects so must relookup 'tv'. */ + tv = DUK_GET_TVAL_POSIDX(ctx, idx); DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */ return d; } +DUK_INTERNAL duk_double_t duk_to_number_m1(duk_context *ctx) { + return duk_to_number(ctx, -1); +} +DUK_INTERNAL duk_double_t duk_to_number_m2(duk_context *ctx) { + return duk_to_number(ctx, -2); +} + +DUK_INTERNAL duk_double_t duk_to_number_tval(duk_context *ctx, duk_tval *tv) { + duk_double_t res; + + DUK_ASSERT_CTX_VALID(ctx); + + duk_push_tval(ctx, tv); + res = duk_to_number(ctx, -1); + duk_pop(ctx); + return res; +} + /* XXX: combine all the integer conversions: they share everything * but the helper function for coercion. */ typedef duk_double_t (*duk__toint_coercer)(duk_hthread *thr, duk_tval *tv); -DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_context *ctx, duk_idx_t index, duk__toint_coercer coerce_func) { +DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_context *ctx, duk_idx_t idx, duk__toint_coercer coerce_func) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; duk_double_t d; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_require_tval(ctx, index); + tv = duk_require_tval(ctx, idx); DUK_ASSERT(tv != NULL); d = coerce_func(thr, tv); /* XXX: fastint? */ /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ - tv = duk_require_tval(ctx, index); + tv = duk_require_tval(ctx, idx); DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */ return d; } -DUK_EXTERNAL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t idx) { /* Value coercion (in stack): ToInteger(), E5 Section 9.4 * API return value coercion: custom */ DUK_ASSERT_CTX_VALID(ctx); - (void) duk__to_int_uint_helper(ctx, index, duk_js_tointeger); - return (duk_int_t) duk__api_coerce_d2i(ctx, index, 0 /*require*/); + (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger); + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*require*/); } -DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t idx) { /* Value coercion (in stack): ToInteger(), E5 Section 9.4 * API return value coercion: custom */ DUK_ASSERT_CTX_VALID(ctx); - (void) duk__to_int_uint_helper(ctx, index, duk_js_tointeger); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 0 /*require*/); + (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger); + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*require*/); } -DUK_EXTERNAL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; duk_int32_t ret; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_require_tval(ctx, index); + tv = duk_require_tval(ctx, idx); DUK_ASSERT(tv != NULL); ret = duk_js_toint32(thr, tv); /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ - tv = duk_require_tval(ctx, index); - DUK_TVAL_SET_FASTINT_I32_UPDREF(thr, tv, ret); /* side effects */ + tv = duk_require_tval(ctx, idx); + DUK_TVAL_SET_I32_UPDREF(thr, tv, ret); /* side effects */ return ret; } -DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; duk_uint32_t ret; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_require_tval(ctx, index); + tv = duk_require_tval(ctx, idx); DUK_ASSERT(tv != NULL); ret = duk_js_touint32(thr, tv); /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ - tv = duk_require_tval(ctx, index); - DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv, ret); /* side effects */ + tv = duk_require_tval(ctx, idx); + DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */ return ret; } -DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; duk_uint16_t ret; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_require_tval(ctx, index); + tv = duk_require_tval(ctx, idx); DUK_ASSERT(tv != NULL); ret = duk_js_touint16(thr, tv); /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ - tv = duk_require_tval(ctx, index); - DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv, ret); /* side effects */ + tv = duk_require_tval(ctx, idx); + DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */ return ret; } #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) /* Special coercion for Uint8ClampedArray. */ -DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index) { +DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t idx) { duk_double_t d; duk_double_t t; duk_uint8_t ret; @@ -17021,7 +18490,7 @@ DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index) * directly. */ - d = duk_to_number(ctx, index); + d = duk_to_number(ctx, idx); if (d <= 0.0) { return 0; } else if (d >= 255) { @@ -17046,35 +18515,37 @@ DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index) } #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_EXTERNAL const char *duk_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) { +DUK_EXTERNAL const char *duk_to_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { DUK_ASSERT_CTX_VALID(ctx); - (void) duk_to_string(ctx, index); - return duk_require_lstring(ctx, index, out_len); + (void) duk_to_string(ctx, idx); + DUK_ASSERT(duk_is_string(ctx, idx)); + return duk_require_lstring(ctx, idx, out_len); } -DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_context *ctx) { +DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_context *ctx, void *udata) { DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(udata); duk_to_string(ctx, -1); return 1; } -DUK_EXTERNAL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) { +DUK_EXTERNAL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { DUK_ASSERT_CTX_VALID(ctx); - index = duk_require_normalize_index(ctx, index); + idx = duk_require_normalize_index(ctx, idx); /* We intentionally ignore the duk_safe_call() return value and only * check the output type. This way we don't also need to check that * the returned value is indeed a string in the success case. */ - duk_dup(ctx, index); - (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/); + duk_dup(ctx, idx); + (void) duk_safe_call(ctx, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/); if (!duk_is_string(ctx, -1)) { /* Error: try coercing error to string once. */ - (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/); + (void) duk_safe_call(ctx, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/); if (!duk_is_string(ctx, -1)) { /* Double error */ duk_pop(ctx); @@ -17083,72 +18554,129 @@ DUK_EXTERNAL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t index, ; } } else { + /* String; may be a symbol, accepted. */ ; } DUK_ASSERT(duk_is_string(ctx, -1)); - DUK_ASSERT(duk_get_string(ctx, -1) != NULL); - duk_replace(ctx, index); - return duk_get_lstring(ctx, index, out_len); + duk_replace(ctx, idx); + DUK_ASSERT(duk_get_string(ctx, idx) != NULL); + return duk_get_lstring(ctx, idx, out_len); } -#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */ -DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index) { - (void) duk_safe_to_string(ctx, index); - DUK_ASSERT(duk_is_string(ctx, index)); - DUK_ASSERT(duk_get_hstring(ctx, index) != NULL); - return duk_get_hstring(ctx, 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_INTERNAL duk_hstring *duk_to_property_key_hstring(duk_context *ctx, duk_idx_t idx) { + duk_hstring *h; DUK_ASSERT_CTX_VALID(ctx); - thr = (duk_hthread *) ctx; - DUK_UNREF(thr); - 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_to_primitive(ctx, idx, DUK_HINT_STRING); /* needed for e.g. Symbol objects */ + h = duk_get_hstring(ctx, idx); + if (h == NULL) { + /* The "is string?" check may seem unnecessary, but as things + * are duk_to_hstring() invokes ToString() which fails for + * symbols. But since symbols are already strings for Duktape + * C API, we check for that before doing the coercion. + */ + h = duk_to_hstring(ctx, idx); } - DUK_ASSERT(h_strclass != NULL); + DUK_ASSERT(h != NULL); + return h; +} - duk_pop(ctx); - duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass)); +#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */ +DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t idx) { + (void) duk_safe_to_string(ctx, idx); + DUK_ASSERT(duk_is_string(ctx, idx)); + DUK_ASSERT(duk_get_hstring(ctx, idx) != NULL); + return duk_known_hstring(ctx, idx); } +#endif -#if !defined(DUK_USE_PARANOID_ERRORS) -DUK_INTERNAL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h) { +/* Push Object.prototype.toString() output for 'tv'. */ +DUK_INTERNAL void duk_push_class_string_tval(duk_context *ctx, duk_tval *tv) { duk_hthread *thr; + duk_small_uint_t stridx; duk_hstring *h_strclass; DUK_ASSERT_CTX_VALID(ctx); - DUK_ASSERT(h != NULL); thr = (duk_hthread *) ctx; DUK_UNREF(thr); - h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h); + switch (DUK_TVAL_GET_TAG(tv)) { + case DUK_TAG_UNUSED: /* Treat like 'undefined', shouldn't happen. */ + case DUK_TAG_UNDEFINED: { + stridx = DUK_STRIDX_UC_UNDEFINED; + break; + } + case DUK_TAG_NULL: { + stridx = DUK_STRIDX_UC_NULL; + break; + } + case DUK_TAG_BOOLEAN: { + stridx = DUK_STRIDX_UC_BOOLEAN; + break; + } + case DUK_TAG_POINTER: { + stridx = DUK_STRIDX_UC_POINTER; + break; + } + case DUK_TAG_LIGHTFUNC: { + stridx = DUK_STRIDX_UC_FUNCTION; + break; + } + case DUK_TAG_STRING: { + duk_hstring *h; + h = DUK_TVAL_GET_STRING(tv); + DUK_ASSERT(h != NULL); + if (DUK_HSTRING_HAS_SYMBOL(h)) { + stridx = DUK_STRIDX_UC_SYMBOL; + } else { + stridx = DUK_STRIDX_UC_STRING; + } + break; + } + case DUK_TAG_OBJECT: { + duk_hobject *h; + duk_small_uint_t classnum; + + h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + classnum = DUK_HOBJECT_GET_CLASS_NUMBER(h); + stridx = DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum); + + /* XXX: This is not entirely correct anymore; in ES2015 the + * default lookup should use @@toStringTag to come up with + * e.g. [object Symbol], [object Uint8Array], etc. See + * ES2015 Section 19.1.3.6. The downside of implementing that + * directly is that the @@toStringTag lookup may have side + * effects, so all call sites must be checked for that. + * Some may need a side-effect free lookup, e.g. avoiding + * getters which are not typical. + */ + break; + } + case DUK_TAG_BUFFER: { + stridx = DUK_STRIDX_UINT8_ARRAY; + break; + } +#if defined(DUK_USE_FASTINT) + case DUK_TAG_FASTINT: + /* Fall through to generic number case. */ +#endif + default: { + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* number (maybe fastint) */ + stridx = DUK_STRIDX_UC_NUMBER; + break; + } + } + h_strclass = DUK_HTHREAD_GET_STRING(thr, stridx); 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_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; duk_tval tv_tmp; @@ -17158,7 +18686,7 @@ DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, DUK_ASSERT_CTX_VALID(ctx); - tv = duk_require_tval(ctx, index); + tv = duk_require_tval(ctx, idx); DUK_ASSERT(tv != NULL); d = duk_js_tointeger(thr, tv); /* E5 Section 9.4, ToInteger() */ @@ -17180,12 +18708,12 @@ DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, /* 'd' and 'res' agree here */ /* Relookup in case duk_js_tointeger() ends up e.g. coercing an object. */ - tv = duk_get_tval(ctx, index); + tv = duk_get_tval(ctx, idx); DUK_ASSERT(tv != NULL); /* not popped by side effect */ DUK_TVAL_SET_TVAL(&tv_tmp, tv); #if defined(DUK_USE_FASTINT) #if (DUK_INT_MAX <= 0x7fffffffL) - DUK_TVAL_SET_FASTINT_I32(tv, res); + DUK_TVAL_SET_I32(tv, res); #else /* Clamping needed if duk_int_t is 64 bits. */ if (res >= DUK_FASTINT_MIN && res <= DUK_FASTINT_MAX) { @@ -17211,25 +18739,24 @@ DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, return res; } -DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t index, duk_idx_t minval, duk_idx_t maxval) { +DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t idx, duk_idx_t minval, duk_idx_t maxval) { duk_bool_t dummy; - return duk_to_int_clamped_raw(ctx, index, minval, maxval, &dummy); + return duk_to_int_clamped_raw(ctx, idx, minval, maxval, &dummy); } -DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval) { - return duk_to_int_clamped_raw(ctx, index, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */ +DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t idx, duk_int_t minval, duk_int_t maxval) { + return duk_to_int_clamped_raw(ctx, idx, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */ } -DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); DUK_UNREF(thr); - index = duk_require_normalize_index(ctx, index); - - tv = duk_require_tval(ctx, index); + idx = duk_require_normalize_index(ctx, idx); + tv = DUK_GET_TVAL_POSIDX(ctx, idx); DUK_ASSERT(tv != NULL); switch (DUK_TVAL_GET_TAG(tv)) { @@ -17250,23 +18777,36 @@ DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t index) { break; } case DUK_TAG_STRING: { - /* nop */ + /* Nop for actual strings, TypeError for Symbols. + * Because various internals rely on ToString() coercion of + * internal strings, -allow- (NOP) string coercion for hidden + * symbols. + */ +#if 1 + duk_hstring *h; + h = DUK_TVAL_GET_STRING(tv); + DUK_ASSERT(h != NULL); + if (DUK_HSTRING_HAS_SYMBOL(h)) { + DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CANNOT_STRING_COERCE_SYMBOL); + } else { + goto skip_replace; + } +#else goto skip_replace; +#endif } + case DUK_TAG_BUFFER: /* Go through Uint8Array.prototype.toString() for coercion. */ case DUK_TAG_OBJECT: { - duk_to_primitive(ctx, index, DUK_HINT_STRING); - return duk_to_string(ctx, index); /* Note: recursive call */ - } - case DUK_TAG_BUFFER: { - duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); - - /* Note: this allows creation of internal strings. */ - - DUK_ASSERT(h != NULL); - duk_push_lstring(ctx, - (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h), - (duk_size_t) DUK_HBUFFER_GET_SIZE(h)); - break; + /* Plain buffers: go through ArrayBuffer.prototype.toString() + * for coercion. + * + * Symbol objects: duk_to_primitive() results in a plain symbol + * value, and duk_to_string() then causes a TypeError. + */ + duk_to_primitive(ctx, idx, DUK_HINT_STRING); + DUK_ASSERT(!duk_is_buffer(ctx, idx)); /* ToPrimitive() must guarantee */ + DUK_ASSERT(!duk_is_object(ctx, idx)); + return duk_to_string(ctx, idx); /* Note: recursive call */ } case DUK_TAG_POINTER: { void *ptr = DUK_TVAL_GET_POINTER(tv); @@ -17302,22 +18842,59 @@ DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t index) { } } - duk_replace(ctx, index); + duk_replace(ctx, idx); skip_replace: - return duk_require_string(ctx, index); + DUK_ASSERT(duk_is_string(ctx, idx)); + return duk_require_string(ctx, idx); } -DUK_INTERNAL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index) { +DUK_INTERNAL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t idx) { duk_hstring *ret; DUK_ASSERT_CTX_VALID(ctx); - duk_to_string(ctx, index); - ret = duk_get_hstring(ctx, index); + duk_to_string(ctx, idx); + ret = duk_get_hstring(ctx, idx); DUK_ASSERT(ret != NULL); return ret; } -DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_uint_t mode) { +DUK_INTERNAL duk_hstring *duk_to_hstring_m1(duk_context *ctx) { + return duk_to_hstring(ctx, -1); +} + +DUK_INTERNAL duk_hstring *duk_to_hstring_acceptsymbol(duk_context *ctx, duk_idx_t idx) { + duk_hstring *ret; + DUK_ASSERT_CTX_VALID(ctx); + ret = duk_get_hstring(ctx, idx); + if (ret && DUK_HSTRING_HAS_SYMBOL(ret)) { + return ret; + } + return duk_to_hstring(ctx, idx); +} + +/* Convert a plain buffer or any buffer object into a string, using the buffer + * bytes 1:1 in the internal string representation. For views the active byte + * slice (not element slice interpreted as an initializer) is used. This is + * necessary in Duktape 2.x because ToString(plainBuffer) no longer creates a + * string with the same bytes as in the buffer but rather (usually) + * '[object ArrayBuffer]'. + */ +DUK_EXTERNAL const char *duk_buffer_to_string(duk_context *ctx, duk_idx_t idx) { + void *ptr_src; + duk_size_t len; + const char *res; + + idx = duk_require_normalize_index(ctx, idx); + + ptr_src = duk_require_buffer_data(ctx, idx, &len); + DUK_ASSERT(ptr_src != NULL || len == 0); + + res = duk_push_lstring(ctx, (const char *) ptr_src, len); + duk_replace(ctx, idx); + return res; +} + +DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_uint_t mode) { duk_hthread *thr = (duk_hthread *) ctx; duk_hbuffer *h_buf; const duk_uint8_t *src_data; @@ -17327,9 +18904,9 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size DUK_ASSERT_CTX_VALID(ctx); DUK_UNREF(thr); - index = duk_require_normalize_index(ctx, index); + idx = duk_require_normalize_index(ctx, idx); - h_buf = duk_get_hbuffer(ctx, index); + h_buf = duk_get_hbuffer(ctx, idx); if (h_buf != NULL) { /* Buffer is kept as is, with the fixed/dynamic nature of the * buffer only changed if requested. An external buffer @@ -17355,10 +18932,10 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size } else { /* Non-buffer value is first ToString() coerced, then converted * to a buffer (fixed buffer is used unless a dynamic buffer is - * explicitly requested). + * explicitly requested). Symbols are rejected with a TypeError. + * XXX: C API could maybe allow symbol-to-buffer coercion? */ - - src_data = (const duk_uint8_t *) duk_to_lstring(ctx, index, &src_size); + src_data = (const duk_uint8_t *) duk_to_lstring(ctx, idx, &src_size); } dst_data = (duk_uint8_t *) duk_push_buffer(ctx, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/); @@ -17370,7 +18947,7 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size */ DUK_MEMCPY((void *) dst_data, (const void *) src_data, (size_t) src_size); } - duk_replace(ctx, index); + duk_replace(ctx, idx); skip_copy: if (out_size) { @@ -17379,15 +18956,14 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size return dst_data; } -DUK_EXTERNAL void *duk_to_pointer(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void *duk_to_pointer(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; void *res; DUK_ASSERT_CTX_VALID(ctx); - index = duk_require_normalize_index(ctx, index); - - tv = duk_require_tval(ctx, index); + idx = duk_require_normalize_index(ctx, idx); + tv = DUK_GET_TVAL_POSIDX(ctx, idx); DUK_ASSERT(tv != NULL); switch (DUK_TVAL_GET_TAG(tv)) { @@ -17426,11 +19002,51 @@ DUK_EXTERNAL void *duk_to_pointer(duk_context *ctx, duk_idx_t index) { } duk_push_pointer(ctx, res); - duk_replace(ctx, index); + duk_replace(ctx, idx); return res; } -DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) { +DUK_LOCAL void duk__push_func_from_lightfunc(duk_context *ctx, duk_c_function func, duk_small_uint_t lf_flags) { + duk_idx_t nargs; + duk_uint_t flags = 0; /* shared flags for a subset of types */ + duk_small_uint_t lf_len; + duk_hnatfunc *nf; + + nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags); + if (nargs == DUK_LFUNC_NARGS_VARARGS) { + nargs = (duk_idx_t) DUK_VARARGS; + } + + flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_NATFUNC | + DUK_HOBJECT_FLAG_NEWENV | + DUK_HOBJECT_FLAG_STRICT | + DUK_HOBJECT_FLAG_NOTAIL | + /* DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC: omitted here intentionally */ + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION); + (void) duk__push_c_function_raw(ctx, func, nargs, flags); + + lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags); + if ((duk_idx_t) lf_len != nargs) { + /* Explicit length is only needed if it differs from 'nargs'. */ + duk_push_int(ctx, (duk_int_t) lf_len); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); + } + +#if defined(DUK_USE_FUNC_NAME_PROPERTY) + duk_push_lightfunc_name_raw(ctx, func, lf_flags); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); +#endif + + nf = duk_known_hnatfunc(ctx, -1); + nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); + + /* Enable DUKFUNC exotic behavior once properties are set up. */ + DUK_HOBJECT_SET_EXOTIC_DUKFUNC((duk_hobject *) nf); +} + +DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; duk_uint_t flags = 0; /* shared flags for a subset of types */ @@ -17438,12 +19054,14 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) { DUK_ASSERT_CTX_VALID(ctx); - index = duk_require_normalize_index(ctx, index); - - tv = duk_require_tval(ctx, index); + idx = duk_require_normalize_index(ctx, idx); + tv = DUK_GET_TVAL_POSIDX(ctx, idx); DUK_ASSERT(tv != NULL); switch (DUK_TVAL_GET_TAG(tv)) { +#if !defined(DUK_USE_BUFFEROBJECT_SUPPORT) + case DUK_TAG_BUFFER: /* With no bufferobject support, don't object coerce. */ +#endif case DUK_TAG_UNDEFINED: case DUK_TAG_NULL: { DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE); @@ -17456,47 +19074,42 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) { goto create_object; } case DUK_TAG_STRING: { - flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING); - proto = DUK_BIDX_STRING_PROTOTYPE; + duk_hstring *h; + h = DUK_TVAL_GET_STRING(tv); + DUK_ASSERT(h != NULL); + if (DUK_HSTRING_HAS_SYMBOL(h)) { + flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_SYMBOL); + proto = DUK_BIDX_SYMBOL_PROTOTYPE; + } else { + flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING); + proto = DUK_BIDX_STRING_PROTOTYPE; + } goto create_object; } case DUK_TAG_OBJECT: { /* nop */ break; } +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) case DUK_TAG_BUFFER: { - /* A plain buffer coerces to a Duktape.Buffer because it's the - * object counterpart of the plain buffer value. But it might - * still make more sense to produce an ArrayBuffer here? + /* A plain buffer object coerces to a full ArrayBuffer which + * is not fully transparent behavior (ToObject() should be a + * nop for an object). This behavior matches lightfuncs which + * also coerce to an equivalent Function object. There are + * also downsides to defining ToObject(plainBuffer) as a no-op; + * for example duk_to_hobject() could result in a NULL pointer. */ + duk_hbuffer *h_buf; - duk_hbufferobject *h_bufobj; - duk_hbuffer *h_val; - - h_val = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h_val != NULL); - - h_bufobj = duk_push_bufferobject_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFFEROBJECT | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER), - DUK_BIDX_BUFFER_PROTOTYPE); - DUK_ASSERT(h_bufobj != NULL); - DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE((duk_hobject *) h_bufobj)); - DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_bufobj)); - - h_bufobj->buf = h_val; - DUK_HBUFFER_INCREF(thr, h_val); - DUK_ASSERT(h_bufobj->offset == 0); - h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val); - DUK_ASSERT(h_bufobj->shift == 0); - DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8); - - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + h_buf = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h_buf != NULL); + duk_hbufobj_push_uint8array_from_plain(thr, h_buf); goto replace_value; } +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ case DUK_TAG_POINTER: { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER); @@ -17506,50 +19119,18 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) { case DUK_TAG_LIGHTFUNC: { /* Lightfunc coerces to a Function instance with concrete * properties. Since 'length' is virtual for Duktape/C - * functions, don't need to define that. + * functions, don't need to define that. The result is made + * extensible to mimic what happens to strings in object + * coercion: * - * The result is made extensible to mimic what happens to - * strings: * > Object.isExtensible(Object('foo')) * true */ duk_small_uint_t lf_flags; - duk_idx_t nargs; - duk_small_uint_t lf_len; duk_c_function func; - duk_hnativefunction *nf; DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); - - nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags); - if (nargs == DUK_LFUNC_NARGS_VARARGS) { - nargs = (duk_idx_t) DUK_VARARGS; - } - flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_CONSTRUCTABLE | - DUK_HOBJECT_FLAG_NATIVEFUNCTION | - DUK_HOBJECT_FLAG_NEWENV | - DUK_HOBJECT_FLAG_STRICT | - DUK_HOBJECT_FLAG_NOTAIL | - /* DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC: omitted here intentionally */ - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION); - (void) duk__push_c_function_raw(ctx, func, nargs, flags); - - lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags); - if ((duk_idx_t) lf_len != nargs) { - /* Explicit length is only needed if it differs from 'nargs'. */ - duk_push_int(ctx, (duk_int_t) lf_len); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); - } - duk_push_lightfunc_name(ctx, tv); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); - - nf = duk_get_hnativefunction(ctx, -1); - DUK_ASSERT(nf != NULL); - nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); - - /* Enable DUKFUNC exotic behavior once properties are set up. */ - DUK_HOBJECT_SET_EXOTIC_DUKFUNC((duk_hobject *) nf); + duk__push_func_from_lightfunc(ctx, func, lf_flags); goto replace_value; } #if defined(DUK_USE_FASTINT) @@ -17564,6 +19145,7 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) { goto create_object; } } + DUK_ASSERT(duk_is_object(ctx, idx)); return; create_object: @@ -17576,49 +19158,53 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) { * String and buffer special behaviors are already enabled which is not * ideal, but a write to the internal value is not affected by them. */ - duk_dup(ctx, index); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); + duk_dup(ctx, idx); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); replace_value: - duk_replace(ctx, index); + duk_replace(ctx, idx); + DUK_ASSERT(duk_is_object(ctx, idx)); +} + +DUK_INTERNAL duk_hobject *duk_to_hobject(duk_context *ctx, duk_idx_t idx) { + duk_hobject *ret; + DUK_ASSERT_CTX_VALID(ctx); + duk_to_object(ctx, idx); + ret = duk_known_hobject(ctx, idx); + return ret; } /* * Type checking */ -DUK_LOCAL duk_bool_t duk__tag_check(duk_context *ctx, duk_idx_t index, duk_small_uint_t tag) { +DUK_LOCAL duk_bool_t duk__tag_check(duk_context *ctx, duk_idx_t idx, duk_small_uint_t tag) { duk_tval *tv; - tv = duk_get_tval(ctx, index); - if (!tv) { - return 0; - } + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); return (DUK_TVAL_GET_TAG(tv) == tag); } -DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_context *ctx, duk_idx_t index, duk_uint_t flag_mask) { +DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_context *ctx, duk_idx_t idx, duk_uint_t flag_mask) { duk_hobject *obj; DUK_ASSERT_CTX_VALID(ctx); - obj = duk_get_hobject(ctx, index); + obj = duk_get_hobject(ctx, idx); if (obj) { return (DUK_HEAPHDR_CHECK_FLAG_BITS((duk_heaphdr *) obj, flag_mask) ? 1 : 0); } return 0; } -DUK_EXTERNAL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index) { - duk_tval *tv; - - DUK_ASSERT_CTX_VALID(ctx); +DUK_INTERNAL duk_int_t duk_get_type_tval(duk_tval *tv) { + DUK_ASSERT(tv != NULL); - tv = duk_get_tval(ctx, index); - if (!tv) { - return DUK_TYPE_NONE; - } +#if defined(DUK_USE_PACKED_TVAL) switch (DUK_TVAL_GET_TAG(tv)) { + case DUK_TAG_UNUSED: + return DUK_TYPE_NONE; case DUK_TAG_UNDEFINED: return DUK_TYPE_UNDEFINED; case DUK_TAG_NULL: @@ -17644,7 +19230,22 @@ DUK_EXTERNAL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index) { DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); return DUK_TYPE_NUMBER; } - DUK_UNREACHABLE(); +#else /* DUK_USE_PACKED_TVAL */ + DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv)); + DUK_ASSERT(sizeof(duk__type_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1); + return (duk_int_t) duk__type_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN]; +#endif /* DUK_USE_PACKED_TVAL */ +} + +DUK_EXTERNAL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t idx) { + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + + return duk_get_type_tval(tv); } #if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS) @@ -17661,10 +19262,10 @@ DUK_LOCAL const char *duk__type_names[] = { "lightfunc" }; -DUK_INTERNAL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index) { +DUK_INTERNAL const char *duk_get_type_name(duk_context *ctx, duk_idx_t idx) { duk_int_t type_tag; - type_tag = duk_get_type(ctx, index); + type_tag = duk_get_type(ctx, idx); 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); @@ -17672,22 +19273,43 @@ DUK_INTERNAL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index) { } #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); +DUK_INTERNAL duk_small_uint_t duk_get_class_number(duk_context *ctx, duk_idx_t idx) { + duk_tval *tv; + duk_hobject *obj; - return (duk_get_type(ctx, index) == type) ? 1 : 0; -} + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); -DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t index) { - duk_tval *tv; + switch (DUK_TVAL_GET_TAG(tv)) { + case DUK_TAG_OBJECT: + obj = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(obj != NULL); + return DUK_HOBJECT_GET_CLASS_NUMBER(obj); + case DUK_TAG_BUFFER: + /* Buffers behave like Uint8Array objects. */ + return DUK_HOBJECT_CLASS_UINT8ARRAY; + case DUK_TAG_LIGHTFUNC: + /* Lightfuncs behave like Function objects. */ + return DUK_HOBJECT_CLASS_FUNCTION; + default: + /* Primitive or UNUSED, no class number. */ + return DUK_HOBJECT_CLASS_NONE; + } +} +DUK_EXTERNAL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t idx, duk_int_t type) { DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (!tv) { - return DUK_TYPE_MASK_NONE; - } + return (duk_get_type(ctx, idx) == type) ? 1 : 0; +} + +DUK_INTERNAL duk_uint_t duk_get_type_mask_tval(duk_tval *tv) { + DUK_ASSERT(tv != NULL); + +#if defined(DUK_USE_PACKED_TVAL) switch (DUK_TVAL_GET_TAG(tv)) { + case DUK_TAG_UNUSED: + return DUK_TYPE_MASK_NONE; case DUK_TAG_UNDEFINED: return DUK_TYPE_MASK_UNDEFINED; case DUK_TAG_NULL: @@ -17713,15 +19335,30 @@ DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t index) { DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); return DUK_TYPE_MASK_NUMBER; } - DUK_UNREACHABLE(); +#else /* DUK_USE_PACKED_TVAL */ + DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv)); + DUK_ASSERT(sizeof(duk__type_mask_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1); + return (duk_int_t) duk__type_mask_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN]; +#endif /* DUK_USE_PACKED_TVAL */ +} + +DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t idx) { + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + + return duk_get_type_mask_tval(tv); } -DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t index, duk_uint_t mask) { +DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t mask) { duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT_CTX_VALID(ctx); - if (duk_get_type_mask(ctx, index) & mask) { + if (duk_get_type_mask(ctx, idx) & mask) { return 1; } if (mask & DUK_TYPE_MASK_THROW) { @@ -17731,36 +19368,22 @@ DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t index, d return 0; } -DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); - return duk__tag_check(ctx, index, DUK_TAG_UNDEFINED); + return duk__tag_check(ctx, idx, DUK_TAG_UNDEFINED); } -DUK_EXTERNAL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); - return duk__tag_check(ctx, index, DUK_TAG_NULL); + return duk__tag_check(ctx, idx, DUK_TAG_NULL); } -DUK_EXTERNAL duk_bool_t duk_is_null_or_undefined(duk_context *ctx, duk_idx_t index) { - duk_tval *tv; - duk_small_uint_t tag; - +DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); - - tv = duk_get_tval(ctx, index); - if (!tv) { - return 0; - } - tag = DUK_TVAL_GET_TAG(tv); - return (tag == DUK_TAG_UNDEFINED) || (tag == DUK_TAG_NULL); + return duk__tag_check(ctx, idx, DUK_TAG_BOOLEAN); } -DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t index) { - DUK_ASSERT_CTX_VALID(ctx); - return duk__tag_check(ctx, index, DUK_TAG_BOOLEAN); -} - -DUK_EXTERNAL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); @@ -17770,16 +19393,14 @@ DUK_EXTERNAL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t index) { * tag in the 8-byte representation. */ - /* XXX: shorter version for 12-byte representation? */ + /* XXX: shorter version for unpacked representation? */ - tv = duk_get_tval(ctx, index); - if (!tv) { - return 0; - } + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); return DUK_TVAL_IS_NUMBER(tv); } -DUK_EXTERNAL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t idx) { /* XXX: This will now return false for non-numbers, even though they would * coerce to NaN (as a general rule). In particular, duk_get_number() * returns a NaN for non-numbers, so should this function also return @@ -17790,101 +19411,149 @@ DUK_EXTERNAL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t index) { DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (!tv || !DUK_TVAL_IS_NUMBER(tv)) { + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + + /* XXX: for packed duk_tval an explicit "is number" check is unnecessary */ + if (!DUK_TVAL_IS_NUMBER(tv)) { return 0; } return DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv)); } -DUK_EXTERNAL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__tag_check(ctx, idx, DUK_TAG_STRING); +} + +DUK_INTERNAL duk_bool_t duk_is_string_notsymbol(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); - return duk__tag_check(ctx, index, DUK_TAG_STRING); + return duk_get_hstring_notsymbol(ctx, idx) != NULL; } -DUK_EXTERNAL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__tag_check(ctx, idx, DUK_TAG_OBJECT); +} + +DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__tag_check(ctx, idx, DUK_TAG_BUFFER); +} + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx) { + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (DUK_TVAL_IS_BUFFER(tv)) { + return 1; + } else if (DUK_TVAL_IS_OBJECT(tv)) { + duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + if (DUK_HOBJECT_IS_BUFOBJ(h)) { + return 1; + } + } + return 0; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); - return duk__tag_check(ctx, index, DUK_TAG_OBJECT); + + return duk_is_buffer(ctx, idx); } -DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t index) { +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); - return duk__tag_check(ctx, index, DUK_TAG_BUFFER); + return duk__tag_check(ctx, idx, DUK_TAG_POINTER); } -DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); - return duk__tag_check(ctx, index, DUK_TAG_POINTER); + return duk__tag_check(ctx, idx, DUK_TAG_LIGHTFUNC); } -DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_symbol(duk_context *ctx, duk_idx_t idx) { + duk_hstring *h; + DUK_ASSERT_CTX_VALID(ctx); - return duk__tag_check(ctx, index, DUK_TAG_LIGHTFUNC); + h = duk_get_hstring(ctx, idx); + if (h != NULL && DUK_HSTRING_HAS_SYMBOL(h)) { + return 1; + } + return 0; } -DUK_EXTERNAL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t idx) { duk_hobject *obj; DUK_ASSERT_CTX_VALID(ctx); - obj = duk_get_hobject(ctx, index); + obj = duk_get_hobject(ctx, idx); if (obj) { return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_ARRAY ? 1 : 0); } return 0; } -DUK_EXTERNAL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_LIGHTFUNC(tv)) { + tv = duk_get_tval_or_unused(ctx, idx); + if (DUK_TVAL_IS_LIGHTFUNC(tv)) { return 1; } return duk__obj_flag_any_default_false(ctx, - index, - DUK_HOBJECT_FLAG_COMPILEDFUNCTION | - DUK_HOBJECT_FLAG_NATIVEFUNCTION | - DUK_HOBJECT_FLAG_BOUND); + idx, + DUK_HOBJECT_FLAG_COMPFUNC | + DUK_HOBJECT_FLAG_NATFUNC | + DUK_HOBJECT_FLAG_BOUNDFUNC); } -DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); return duk__obj_flag_any_default_false(ctx, - index, - DUK_HOBJECT_FLAG_NATIVEFUNCTION); + idx, + DUK_HOBJECT_FLAG_NATFUNC); } -DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); return duk__obj_flag_any_default_false(ctx, - index, - DUK_HOBJECT_FLAG_COMPILEDFUNCTION); + idx, + DUK_HOBJECT_FLAG_COMPFUNC); } -DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); return duk__obj_flag_any_default_false(ctx, - index, - DUK_HOBJECT_FLAG_BOUND); + idx, + DUK_HOBJECT_FLAG_BOUNDFUNC); } -DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); return duk__obj_flag_any_default_false(ctx, - index, + idx, DUK_HOBJECT_FLAG_THREAD); } -DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_BUFFER(tv)) { + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (DUK_TVAL_IS_BUFFER(tv)) { duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); DUK_ASSERT(h != NULL); return (DUK_HBUFFER_HAS_DYNAMIC(h) ? 0 : 1); @@ -17892,13 +19561,14 @@ DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index) { return 0; } -DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_BUFFER(tv)) { + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (DUK_TVAL_IS_BUFFER(tv)) { duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); DUK_ASSERT(h != NULL); return (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0); @@ -17906,13 +19576,14 @@ DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t index) return 0; } -DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); - tv = duk_get_tval(ctx, index); - if (tv && DUK_TVAL_IS_BUFFER(tv)) { + tv = duk_get_tval_or_unused(ctx, idx); + DUK_ASSERT(tv != NULL); + if (DUK_TVAL_IS_BUFFER(tv)) { duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); DUK_ASSERT(h != NULL); return (DUK_HBUFFER_HAS_DYNAMIC(h) && DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0); @@ -17920,14 +19591,14 @@ DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t index return 0; } -DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h; duk_uint_t sanity; DUK_ASSERT_CTX_VALID(ctx); - h = duk_get_hobject(ctx, index); + h = duk_get_hobject(ctx, idx); sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; do { @@ -18064,7 +19735,7 @@ DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val) { DUK__CHECK_SPACE(); tv_slot = thr->valstack_top++; #if DUK_INT_MAX <= 0x7fffffffL - DUK_TVAL_SET_FASTINT_I32(tv_slot, (duk_int32_t) val); + DUK_TVAL_SET_I32(tv_slot, (duk_int32_t) val); #else if (val >= DUK_FASTINT_MIN && val <= DUK_FASTINT_MAX) { DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val); @@ -18097,7 +19768,7 @@ DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val) { DUK__CHECK_SPACE(); tv_slot = thr->valstack_top++; #if DUK_UINT_MAX <= 0xffffffffUL - DUK_TVAL_SET_FASTINT_U32(tv_slot, (duk_uint32_t) val); + DUK_TVAL_SET_U32(tv_slot, (duk_uint32_t) val); #else if (val <= DUK_FASTINT_MAX) { /* val is unsigned so >= 0 */ /* XXX: take advantage of val being unsigned, no need to mask */ @@ -18144,7 +19815,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_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_RANGE_PUSH_BEYOND(thr); } /* NULL with zero length represents an empty string; NULL with higher @@ -18182,76 +19853,6 @@ DUK_EXTERNAL const char *duk_push_string(duk_context *ctx, const char *str) { } } -#ifdef DUK_USE_FILE_IO -/* This is a bit clunky because it is ANSI C portable. Should perhaps - * relocate to another file because this is potentially platform - * dependent. - */ -DUK_EXTERNAL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags) { - duk_hthread *thr = (duk_hthread *) ctx; - duk_file *f = NULL; - char *buf; - long sz; /* ANSI C typing */ - - DUK_ASSERT_CTX_VALID(ctx); - - if (!path) { - goto fail; - } - f = DUK_FOPEN(path, "rb"); - if (!f) { - goto fail; - } - if (DUK_FSEEK(f, 0, SEEK_END) < 0) { - goto fail; - } - sz = DUK_FTELL(f); - if (sz < 0) { - goto fail; - } - if (DUK_FSEEK(f, 0, SEEK_SET) < 0) { - goto fail; - } - buf = (char *) duk_push_fixed_buffer(ctx, (duk_size_t) sz); - DUK_ASSERT(buf != NULL); - if ((duk_size_t) DUK_FREAD(buf, 1, (size_t) sz, f) != (duk_size_t) sz) { - goto fail; - } - (void) DUK_FCLOSE(f); /* ignore fclose() error */ - f = NULL; - return duk_to_string(ctx, -1); - - fail: - if (f) { - DUK_FCLOSE(f); - } - - if (flags != 0) { - DUK_ASSERT(flags == DUK_STRING_PUSH_SAFE); /* only flag now */ - duk_push_undefined(ctx); - } else { - /* XXX: string not shared because it is conditional */ - DUK_ERROR_TYPE(thr, "read file error"); - } - return NULL; -} -#else -DUK_EXTERNAL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags) { - duk_hthread *thr = (duk_hthread *) ctx; - DUK_ASSERT_CTX_VALID(ctx); - DUK_UNREF(path); - - if (flags != 0) { - DUK_ASSERT(flags == DUK_STRING_PUSH_SAFE); /* only flag now */ - duk_push_undefined(ctx); - } else { - /* XXX: string not shared because it is conditional */ - DUK_ERROR_UNSUPPORTED(thr, "file I/O disabled"); - } - return NULL; -} -#endif /* DUK_USE_FILE_IO */ - DUK_EXTERNAL void duk_push_pointer(duk_context *ctx, void *val) { duk_hthread *thr; duk_tval *tv_slot; @@ -18263,6 +19864,16 @@ DUK_EXTERNAL void duk_push_pointer(duk_context *ctx, void *val) { DUK_TVAL_SET_POINTER(tv_slot, val); } +DUK_INTERNAL duk_hstring *duk_push_uint_to_hstring(duk_context *ctx, duk_uint_t i) { + duk_hstring *h_tmp; + + /* XXX: this could be a direct DUK_SPRINTF to a buffer followed by duk_push_string() */ + duk_push_uint(ctx, (duk_uint_t) i); + h_tmp = duk_to_hstring_m1(ctx); + DUK_ASSERT(h_tmp != NULL); + return h_tmp; +} + DUK_LOCAL void duk__push_this_helper(duk_context *ctx, duk_small_uint_t check_object_coercible) { duk_hthread *thr; duk_tval *tv_slot; @@ -18320,22 +19931,16 @@ DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx) { DUK_ASSERT_CTX_VALID(ctx); duk__push_this_helper(ctx, 1 /*check_object_coercible*/); - duk_to_object(ctx, -1); - h = duk_get_hobject(ctx, -1); + h = duk_to_hobject(ctx, -1); DUK_ASSERT(h != NULL); return h; } DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx) { - duk_hstring *h; - DUK_ASSERT_CTX_VALID(ctx); duk__push_this_helper(ctx, 1 /*check_object_coercible*/); - duk_to_string(ctx, -1); - h = duk_get_hstring(ctx, -1); - DUK_ASSERT(h != NULL); - return h; + return duk_to_hstring_m1(ctx); /* This will reject all Symbol values; accepts Symbol objects. */ } DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx) { @@ -18390,14 +19995,14 @@ DUK_EXTERNAL void duk_push_global_object(duk_context *ctx) { /* XXX: size optimize */ DUK_LOCAL void duk__push_stash(duk_context *ctx) { DUK_ASSERT_CTX_VALID(ctx); - if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE)) { + if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE)) { DUK_DDD(DUK_DDDPRINT("creating heap/global/thread stash on first use")); duk_pop(ctx); - duk_push_object_internal(ctx); + duk_push_bare_object(ctx); duk_dup_top(ctx); - duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */ + duk_xdef_prop_stridx_short(ctx, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */ } - duk_remove(ctx, -2); + duk_remove_m2(ctx); } DUK_EXTERNAL void duk_push_heap_stash(duk_context *ctx) { @@ -18420,7 +20025,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_API(thr, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_TYPE_INVALID_ARGS(thr); return; /* not reached */ } duk_push_hobject(ctx, (duk_hobject *) target_ctx); @@ -18459,8 +20064,8 @@ DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va /* special handling of fmt==NULL */ if (!fmt) { duk_hstring *h_str; - duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); - h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr); /* rely on interning, must be this string */ + duk_push_hstring_empty(ctx); + h_str = duk_known_hstring(ctx, -1); return (const char *) DUK_HSTRING_GET_DATA(h_str); } @@ -18497,16 +20102,16 @@ 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_API(thr, DUK_STR_SPRINTF_TOO_LONG); + DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG); } } - /* Cannot use duk_to_string() on the buffer because it is usually - * larger than 'len'. Also, 'buf' is usually a stack buffer. + /* Cannot use duk_buffer_to_string() on the buffer because it is + * usually larger than 'len'; 'buf' is also usually a stack buffer. */ res = duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len); /* [ buf? res ] */ if (pushed_buf) { - duk_remove(ctx, -2); + duk_remove_m2(ctx); } return res; } @@ -18525,11 +20130,10 @@ DUK_EXTERNAL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ... return ret; } -DUK_INTERNAL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) { +DUK_INTERNAL duk_hobject *duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv_slot; duk_hobject *h; - duk_idx_t ret; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(prototype_bidx == -1 || @@ -18537,12 +20141,12 @@ 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_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_RANGE_PUSH_BEYOND(thr); } h = duk_hobject_alloc(thr->heap, hobject_flags_and_class); if (!h) { - DUK_ERROR_ALLOC_DEFMSG(thr); + DUK_ERROR_ALLOC_FAILED(thr); } DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx", (unsigned long) h->hdr.h_flags)); @@ -18550,7 +20154,6 @@ DUK_INTERNAL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobje tv_slot = thr->valstack_top; DUK_TVAL_SET_OBJECT(tv_slot, h); DUK_HOBJECT_INCREF(thr, h); /* no side effects */ - ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); thr->valstack_top++; /* object is now reachable */ @@ -18562,71 +20165,95 @@ DUK_INTERNAL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobje DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL); } - return ret; + return h; } -DUK_INTERNAL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto) { +DUK_INTERNAL duk_hobject *duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto) { duk_hthread *thr = (duk_hthread *) ctx; - duk_idx_t ret; duk_hobject *h; DUK_ASSERT_CTX_VALID(ctx); - ret = duk_push_object_helper(ctx, hobject_flags_and_class, -1); - h = duk_get_hobject(ctx, -1); + h = duk_push_object_helper(ctx, hobject_flags_and_class, -1); DUK_ASSERT(h != NULL); DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL); DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, proto); - return ret; + return h; } DUK_EXTERNAL duk_idx_t duk_push_object(duk_context *ctx) { DUK_ASSERT_CTX_VALID(ctx); - return duk_push_object_helper(ctx, + (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), DUK_BIDX_OBJECT_PROTOTYPE); + return duk_get_top_index_unsafe(ctx); } DUK_EXTERNAL duk_idx_t duk_push_array(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; - duk_hobject *obj; + duk_uint_t flags; + duk_harray *obj; duk_idx_t ret; + duk_tval *tv_slot; DUK_ASSERT_CTX_VALID(ctx); - ret = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_ARRAY_PART | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY), - DUK_BIDX_ARRAY_PROTOTYPE); - - obj = duk_require_hobject(ctx, ret); + flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_ARRAY_PART | + DUK_HOBJECT_FLAG_EXOTIC_ARRAY | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY); - /* - * An array must have a 'length' property (E5 Section 15.4.5.2). - * The special array behavior flag must only be enabled once the - * length property has been added. - * - * The internal property must be a number (and preferably a - * fastint if fastint support is enabled). - */ + obj = duk_harray_alloc(thr->heap, flags); + if (!obj) { + DUK_ERROR_ALLOC_FAILED(thr); + } - duk_push_int(ctx, 0); -#if defined(DUK_USE_FASTINT) - DUK_ASSERT(DUK_TVAL_IS_FASTINT(duk_require_tval(ctx, -1))); -#endif + /* XXX: since prototype is NULL, could save a check */ + DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_ARRAY_PROTOTYPE]); - duk_hobject_define_property_internal(thr, - obj, - DUK_HTHREAD_STRING_LENGTH(thr), - DUK_PROPDESC_FLAGS_W); - DUK_HOBJECT_SET_EXOTIC_ARRAY(obj); + tv_slot = thr->valstack_top; + DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); + DUK_HOBJECT_INCREF(thr, obj); /* XXX: could preallocate with refcount = 1 */ + ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); + thr->valstack_top++; + DUK_ASSERT(obj->length == 0); /* Array .length starts at zero. */ return ret; } +DUK_INTERNAL duk_harray *duk_push_harray(duk_context *ctx) { + /* XXX: API call could do this directly, cast to void in API macro. */ + duk_hthread *thr; + duk_harray *a; + + thr = (duk_hthread *) ctx; + (void) duk_push_array(ctx); + DUK_ASSERT(DUK_TVAL_IS_OBJECT(thr->valstack_top - 1)); + a = (duk_harray *) DUK_TVAL_GET_OBJECT(thr->valstack_top - 1); + DUK_ASSERT(a != NULL); + return a; +} + +/* Push a duk_harray with preallocated size (.length also set to match size). + * Caller may then populate array part of the duk_harray directly. + */ +DUK_INTERNAL duk_harray *duk_push_harray_with_size(duk_context *ctx, duk_uint32_t size) { + duk_harray *a; + + a = duk_push_harray(ctx); + + duk_hobject_realloc_props((duk_hthread *) ctx, + (duk_hobject *) a, + 0, + size, + 0, + 0); + a->length = size; + return a; +} + DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) { duk_hthread *thr = (duk_hthread *) ctx; duk_hthread *obj; @@ -18637,7 +20264,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_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_RANGE_PUSH_BEYOND(thr); } obj = duk_hthread_alloc(thr->heap, @@ -18645,7 +20272,7 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) { DUK_HOBJECT_FLAG_THREAD | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); if (!obj) { - DUK_ERROR_ALLOC_DEFMSG(thr); + DUK_ERROR_ALLOC_FAILED(thr); } obj->state = DUK_HTHREAD_STATE_INACTIVE; #if defined(DUK_USE_ROM_STRINGS) @@ -18668,7 +20295,7 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) { /* important to do this *after* pushing, to make the thread reachable for gc */ if (!duk_hthread_init_stacks(thr->heap, obj)) { - DUK_ERROR_ALLOC_DEFMSG(thr); + DUK_ERROR_ALLOC_FAILED(thr); } /* initialize built-ins - either by copying or creating new ones */ @@ -18679,6 +20306,7 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) { } /* default prototype (Note: 'obj' must be reachable) */ + /* XXX: since prototype is NULL, could save a check */ DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]); /* Initial stack size satisfies the stack spare constraints so there @@ -18690,17 +20318,16 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) { return ret; } -DUK_INTERNAL duk_idx_t duk_push_compiledfunction(duk_context *ctx) { +DUK_INTERNAL duk_hcompfunc *duk_push_hcompfunc(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; - duk_hcompiledfunction *obj; - duk_idx_t ret; + duk_hcompfunc *obj; duk_tval *tv_slot; DUK_ASSERT_CTX_VALID(ctx); /* check stack first */ if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_RANGE_PUSH_BEYOND(thr); } /* Template functions are not strictly constructable (they don't @@ -18708,12 +20335,12 @@ DUK_INTERNAL duk_idx_t duk_push_compiledfunction(duk_context *ctx) { * DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here. */ - obj = duk_hcompiledfunction_alloc(thr->heap, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_COMPILEDFUNCTION | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION)); + obj = duk_hcompfunc_alloc(thr->heap, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_COMPFUNC | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION)); if (!obj) { - DUK_ERROR_ALLOC_DEFMSG(thr); + DUK_ERROR_ALLOC_FAILED(thr); } DUK_DDD(DUK_DDDPRINT("created compiled function object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags)); @@ -18721,18 +20348,16 @@ DUK_INTERNAL duk_idx_t duk_push_compiledfunction(duk_context *ctx) { tv_slot = thr->valstack_top; DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); DUK_HOBJECT_INCREF(thr, obj); - ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); thr->valstack_top++; - /* default prototype (Note: 'obj' must be reachable) */ DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); - return ret; + return obj; } DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_uint_t flags) { duk_hthread *thr = (duk_hthread *) ctx; - duk_hnativefunction *obj; + duk_hnatfunc *obj; duk_idx_t ret; duk_tval *tv_slot; duk_int16_t func_nargs; @@ -18741,22 +20366,22 @@ 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_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_RANGE_PUSH_BEYOND(thr); } if (func == NULL) { goto api_error; } - if (nargs >= 0 && nargs < DUK_HNATIVEFUNCTION_NARGS_MAX) { + if (nargs >= 0 && nargs < DUK_HNATFUNC_NARGS_MAX) { func_nargs = (duk_int16_t) nargs; } else if (nargs == DUK_VARARGS) { - func_nargs = DUK_HNATIVEFUNCTION_NARGS_VARARGS; + func_nargs = DUK_HNATFUNC_NARGS_VARARGS; } else { goto api_error; } - obj = duk_hnativefunction_alloc(thr->heap, flags); + obj = duk_hnatfunc_alloc(thr->heap, flags); if (!obj) { - DUK_ERROR_ALLOC_DEFMSG(thr); + DUK_ERROR_ALLOC_FAILED(thr); } obj->func = func; @@ -18777,7 +20402,7 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function fu return ret; api_error: - DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_TYPE_INVALID_ARGS(thr); return 0; /* not reached */ } @@ -18788,7 +20413,7 @@ DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func flags = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE | - DUK_HOBJECT_FLAG_NATIVEFUNCTION | + DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | DUK_HOBJECT_FLAG_NOTAIL | @@ -18805,7 +20430,7 @@ DUK_INTERNAL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function flags = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE | - DUK_HOBJECT_FLAG_NATIVEFUNCTION | + DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | DUK_HOBJECT_FLAG_NOTAIL | @@ -18820,7 +20445,7 @@ DUK_INTERNAL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk DUK_ASSERT_CTX_VALID(ctx); flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_NATIVEFUNCTION | + DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | DUK_HOBJECT_FLAG_NOTAIL | @@ -18838,7 +20463,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_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_RANGE_PUSH_BEYOND(thr); } if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) { @@ -18862,13 +20487,14 @@ 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_API(thr, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_TYPE_INVALID_ARGS(thr); return 0; /* not reached */ } -DUK_INTERNAL 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_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_hbufobj *duk_push_bufobj_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) { duk_hthread *thr = (duk_hthread *) ctx; - duk_hbufferobject *obj; + duk_hbufobj *obj; duk_tval *tv_slot; DUK_ASSERT(ctx != NULL); @@ -18876,16 +20502,16 @@ DUK_INTERNAL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_ /* check stack first */ if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_RANGE_PUSH_BEYOND(thr); } - obj = duk_hbufferobject_alloc(thr->heap, hobject_flags_and_class); + obj = duk_hbufobj_alloc(thr->heap, hobject_flags_and_class); if (!obj) { - DUK_ERROR_ALLOC_DEFMSG(thr); + DUK_ERROR_ALLOC_FAILED(thr); } DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]); - DUK_ASSERT_HBUFFEROBJECT_VALID(obj); + DUK_ASSERT_HBUFOBJ_VALID(obj); tv_slot = thr->valstack_top; DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); @@ -18894,40 +20520,36 @@ DUK_INTERNAL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_ return obj; } +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* XXX: There's quite a bit of overlap with buffer creation handling in * duk_bi_buffer.c. Look for overlap and refactor. */ -#define DUK__PACK_ARGS(classnum,protobidx,elemtype,elemshift,isview) \ - (((classnum) << 24) | ((protobidx) << 16) | ((elemtype) << 8) | ((elemshift) << 4) | (isview)) - #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +#define DUK__PACK_ARGS(classnum,protobidx,elemtype,elemshift,istypedarray) \ + (((classnum) << 24) | ((protobidx) << 16) | ((elemtype) << 8) | ((elemshift) << 4) | (istypedarray)) + static const duk_uint32_t duk__bufobj_flags_lookup[] = { - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_DUKTAPE_BUFFER */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_NODEJS_BUFFER */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_ARRAYBUFFER, DUK_BIDX_ARRAYBUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_ARRAYBUFFER */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_DATAVIEW, DUK_BIDX_DATAVIEW_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_DATAVIEW */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT8ARRAY, DUK_BIDX_INT8ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT8, 0, 1), /* DUK_BUFOBJ_INT8ARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_UINT8ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_UINT8ARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED, 0, 1), /* DUK_BUFOBJ_UINT8CLAMPEDARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT16ARRAY, DUK_BIDX_INT16ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT16, 1, 1), /* DUK_BUFOBJ_INT16ARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT16ARRAY, DUK_BIDX_UINT16ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT16, 1, 1), /* DUK_BUFOBJ_UINT16ARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT32ARRAY, DUK_BIDX_INT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT32, 2, 1), /* DUK_BUFOBJ_INT32ARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT32ARRAY, DUK_BIDX_UINT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT32, 2, 1), /* DUK_BUFOBJ_UINT32ARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT32ARRAY, DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_FLOAT32, 2, 1), /* DUK_BUFOBJ_FLOAT32ARRAY */ - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT64ARRAY, DUK_BIDX_FLOAT64ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_FLOAT64, 3, 1) /* DUK_BUFOBJ_FLOAT64ARRAY */ -}; -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -/* Only allow Duktape.Buffer when support disabled. */ -static const duk_uint32_t duk__bufobj_flags_lookup[] = { - DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0) /* DUK_BUFOBJ_DUKTAPE_BUFFER */ + /* Node.js Buffers are Uint8Array instances which inherit from Buffer.prototype. */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_ARRAYBUFFER, DUK_BIDX_ARRAYBUFFER_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_ARRAYBUFFER */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_NODEJS_BUFFER */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_DATAVIEW, DUK_BIDX_DATAVIEW_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_DATAVIEW */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT8ARRAY, DUK_BIDX_INT8ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT8, 0, 1), /* DUK_BUFOBJ_INT8ARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_UINT8ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_UINT8ARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8CLAMPED, 0, 1), /* DUK_BUFOBJ_UINT8CLAMPEDARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT16ARRAY, DUK_BIDX_INT16ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT16, 1, 1), /* DUK_BUFOBJ_INT16ARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT16ARRAY, DUK_BIDX_UINT16ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT16, 1, 1), /* DUK_BUFOBJ_UINT16ARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT32ARRAY, DUK_BIDX_INT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT32, 2, 1), /* DUK_BUFOBJ_INT32ARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT32ARRAY, DUK_BIDX_UINT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT32, 2, 1), /* DUK_BUFOBJ_UINT32ARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT32ARRAY, DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_FLOAT32, 2, 1), /* DUK_BUFOBJ_FLOAT32ARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT64ARRAY, DUK_BIDX_FLOAT64ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_FLOAT64, 3, 1) /* DUK_BUFOBJ_FLOAT64ARRAY */ }; #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -#undef DUK__PACK_ARGS +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) { duk_hthread *thr; - duk_hbufferobject *h_bufobj; + duk_hbufobj *h_bufobj; duk_hbuffer *h_val; duk_uint32_t tmp; duk_uint_t classnum; @@ -18939,9 +20561,9 @@ DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, thr = (duk_hthread *) ctx; DUK_UNREF(thr); - /* The underlying types for offset/length in duk_hbufferobject is - * duk_uint_t; make sure argument values fit and that offset + length - * does not wrap. + /* The underlying types for offset/length in duk_hbufobj is + * duk_uint_t; make sure argument values fit and that + * offset + length does not wrap. */ uint_offset = (duk_uint_t) byte_offset; uint_length = (duk_uint_t) byte_length; @@ -18968,11 +20590,11 @@ DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, h_val = duk_require_hbuffer(ctx, idx_buffer); DUK_ASSERT(h_val != NULL); - h_bufobj = duk_push_bufferobject_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFFEROBJECT | - DUK_HOBJECT_CLASS_AS_FLAGS(classnum), - protobidx); + h_bufobj = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(classnum), + protobidx); DUK_ASSERT(h_bufobj != NULL); h_bufobj->buf = h_val; @@ -18981,53 +20603,69 @@ DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, h_bufobj->length = uint_length; h_bufobj->shift = (tmp >> 4) & 0x0f; h_bufobj->elem_type = (tmp >> 8) & 0xff; - h_bufobj->is_view = tmp & 0x0f; - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + h_bufobj->is_typedarray = tmp & 0x0f; + DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) /* TypedArray views need an automatic ArrayBuffer which must be - * provided as .buffer property of the view. Just create a new - * ArrayBuffer sharing the same underlying buffer. + * provided as .buffer property of the view. The ArrayBuffer is + * referenced via duk_hbufobj->buf_prop and an inherited .buffer + * accessor returns it. + * + * The ArrayBuffer offset is always set to zero, so that if one + * accesses the ArrayBuffer at the view's .byteOffset, the value + * matches the view at index 0. */ if (flags & DUK_BUFOBJ_CREATE_ARRBUF) { - h_bufobj = duk_push_bufferobject_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFFEROBJECT | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); + duk_hbufobj *h_arrbuf; - DUK_ASSERT(h_bufobj != NULL); + h_arrbuf = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), + DUK_BIDX_ARRAYBUFFER_PROTOTYPE); + DUK_ASSERT(h_arrbuf != NULL); - h_bufobj->buf = h_val; + h_arrbuf->buf = h_val; DUK_HBUFFER_INCREF(thr, h_val); - h_bufobj->offset = uint_offset; - h_bufobj->length = uint_length; - DUK_ASSERT(h_bufobj->shift == 0); - h_bufobj->elem_type = DUK_HBUFFEROBJECT_ELEM_UINT8; - DUK_ASSERT(h_bufobj->is_view == 0); - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + h_arrbuf->offset = 0; + h_arrbuf->length = uint_offset + uint_length; /* Wrap checked above. */ + DUK_ASSERT(h_arrbuf->shift == 0); + h_arrbuf->elem_type = DUK_HBUFOBJ_ELEM_UINT8; + DUK_ASSERT(h_arrbuf->is_typedarray == 0); + DUK_ASSERT_HBUFOBJ_VALID(h_arrbuf); + DUK_ASSERT(h_arrbuf->buf_prop == NULL); + + DUK_ASSERT(h_bufobj->buf_prop == NULL); + h_bufobj->buf_prop = (duk_hobject *) h_arrbuf; + DUK_HBUFOBJ_INCREF(thr, h_arrbuf); /* Now reachable and accounted for. */ - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE); - duk_compact(ctx, -1); + duk_pop(ctx); } -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ return; range_error: - DUK_ERROR_RANGE(thr, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS); return; /* not reached */ arg_error: - DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_TYPE(thr, DUK_STR_INVALID_ARGS); return; /* not reached */ } +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) { + DUK_UNREF(idx_buffer); + DUK_UNREF(byte_offset); + DUK_UNREF(byte_length); + DUK_UNREF(flags); + DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx); +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) { duk_hthread *thr = (duk_hthread *) ctx; - duk_idx_t ret; duk_hobject *proto; -#ifdef DUK_USE_AUGMENT_ERROR_CREATE +#if defined(DUK_USE_AUGMENT_ERROR_CREATE) duk_bool_t noblame_fileline; #endif @@ -19037,22 +20675,22 @@ DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcod DUK_UNREF(line); /* Error code also packs a tracedata related flag. */ -#ifdef DUK_USE_AUGMENT_ERROR_CREATE +#if defined(DUK_USE_AUGMENT_ERROR_CREATE) noblame_fileline = err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE; #endif err_code = err_code & (~DUK_ERRCODE_FLAG_NOBLAME_FILELINE); /* error gets its 'name' from the prototype */ proto = duk_error_prototype_from_code(thr, err_code); - ret = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR), - proto); + (void) duk_push_object_helper_proto(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR), + proto); /* ... and its 'message' from an instance property */ if (fmt) { duk_push_vsprintf(ctx, fmt, ap); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); } else { /* If no explicit message given, put error code into message field * (as a number). This is not fully in keeping with the Ecmascript @@ -19061,18 +20699,18 @@ DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcod * probably more useful than having a separate 'code' property. */ duk_push_int(ctx, err_code); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); } /* XXX: .code = err_code disabled, not sure if useful */ /* Creation time error augmentation */ -#ifdef DUK_USE_AUGMENT_ERROR_CREATE +#if defined(DUK_USE_AUGMENT_ERROR_CREATE) /* filename may be NULL in which case file/line is not recorded */ duk_err_augment_error_create(thr, thr, filename, line, noblame_fileline); /* may throw an error */ #endif - return ret; + return duk_get_top_index_unsafe(ctx); } DUK_EXTERNAL duk_idx_t duk_push_error_object_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) { @@ -19115,7 +20753,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_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_RANGE_PUSH_BEYOND(thr); } /* Check for maximum buffer length. */ @@ -19125,7 +20763,7 @@ DUK_EXTERNAL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_sm h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data); if (!h) { - DUK_ERROR_ALLOC_DEFMSG(thr); + DUK_ERROR_ALLOC_FAILED(thr); } tv_slot = thr->valstack_top; @@ -19136,19 +20774,126 @@ DUK_EXTERNAL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_sm return (void *) buf_data; } +DUK_INTERNAL void *duk_push_fixed_buffer_nozero(duk_context *ctx, duk_size_t len) { + return duk_push_buffer_raw(ctx, len, DUK_BUF_FLAG_NOZERO); +} + +DUK_INTERNAL void *duk_push_fixed_buffer_zero(duk_context *ctx, duk_size_t len) { + void *ptr; + ptr = duk_push_buffer_raw(ctx, len, 0); +#if !defined(DUK_USE_ZERO_BUFFER_DATA) + /* ES2015 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA + * is not set. + */ + DUK_MEMZERO((void *) ptr, (size_t) len); +#endif + return ptr; +} + +#if defined(DUK_USE_ASSERTIONS) +DUK_LOCAL void duk__validate_push_heapptr(duk_context *ctx, void *ptr) { + duk_heaphdr *h; + duk_heaphdr *curr; + duk_hthread *thr; + duk_bool_t found = 0; + + thr = (duk_hthread *) ctx; + h = (duk_heaphdr *) ptr; + if (h == NULL) { + /* Allowed. */ + return; + } + DUK_ASSERT(h != NULL); + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); + + /* One particular problem case is where an object has been + * queued for finalization but the finalizer hasn't yet been + * executed. + * + * Corner case: we're running in a finalizer for object X, and + * user code calls duk_push_heapptr() for X itself. In this + * case X will be in finalize_list, and we can detect the case + * by seeing that X's FINALIZED flag is set (which is done before + * the finalizer starts executing). + */ + for (curr = thr->heap->finalize_list; + curr != NULL; + curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { + if (curr == h) { + if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) { + /* Object is currently being finalized. */ + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + } else { + DUK_ASSERT(0); + } + } + } + + /* Also check for the refzero_list; must not be there unless it is + * being finalized when duk_push_heapptr() is called. + * + * Corner case: similar to finalize_list. + */ +#if defined(DUK_USE_REFERENCE_COUNTING) + for (curr = thr->heap->refzero_list; + curr != NULL; + curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { + if (curr == h) { + if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) { + /* Object is currently being finalized. */ + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + } else { + DUK_ASSERT(0); + } + } + } +#endif + + /* If not present in finalize_list or refzero_list, the pointer + * must be either in heap_allocated or the string table. + */ + if (DUK_HEAPHDR_GET_TYPE(h) == DUK_HTYPE_STRING) { + /* Omitted from Duktape 2.0.x maintenance backport. */ + } else { + for (curr = thr->heap->heap_allocated; + curr != NULL; + curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { + if (curr == h) { + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + } + } + DUK_ASSERT(found != 0); + } +} +#endif /* DUK_USE_ASSERTIONS */ + DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) { duk_hthread *thr = (duk_hthread *) ctx; duk_idx_t ret; DUK_ASSERT_CTX_VALID(ctx); + /* Reviving an object using a heap pointer is a dangerous API + * operation: if the application doesn't guarantee that the + * pointer target is always reachable, difficult-to-diagnose + * problems may ensue. Try to validate the 'ptr' argument to + * the extent possible. + */ + +#if defined(DUK_USE_ASSERTIONS) + duk__validate_push_heapptr(ctx, ptr); +#endif + ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); if (ptr == NULL) { goto push_undefined; } - switch ((int) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) { + switch (DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) { case DUK_HTYPE_STRING: duk_push_hstring(ctx, (duk_hstring *) ptr); break; @@ -19168,11 +20913,13 @@ DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) { return ret; } -DUK_INTERNAL duk_idx_t duk_push_object_internal(duk_context *ctx) { - return duk_push_object_helper(ctx, +/* Push object with no prototype, i.e. a "bare" object. */ +DUK_EXTERNAL duk_idx_t duk_push_bare_object(duk_context *ctx) { + (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), -1); /* no prototype */ + return duk_get_top_index_unsafe(ctx); } DUK_INTERNAL void duk_push_hstring(duk_context *ctx, duk_hstring *h) { @@ -19183,13 +20930,19 @@ DUK_INTERNAL void duk_push_hstring(duk_context *ctx, duk_hstring *h) { duk_push_tval(ctx, &tv); } -DUK_INTERNAL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx) { +DUK_INTERNAL void duk_push_hstring_stridx(duk_context *ctx, duk_small_uint_t stridx) { duk_hthread *thr = (duk_hthread *) ctx; DUK_UNREF(thr); - DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS); + DUK_ASSERT_STRIDX_VALID(stridx); duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx)); } +DUK_INTERNAL void duk_push_hstring_empty(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, DUK_STRIDX_EMPTY_STRING)); +} + DUK_INTERNAL void duk_push_hobject(duk_context *ctx, duk_hobject *h) { duk_tval tv; DUK_ASSERT_CTX_VALID(ctx); @@ -19222,17 +20975,20 @@ DUK_INTERNAL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builti DUK_EXTERNAL void duk_pop_n(duk_context *ctx, duk_idx_t count) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; +#if defined(DUK_USE_REFERENCE_COUNTING) + duk_tval *tv_end; +#endif DUK_ASSERT_CTX_VALID(ctx); if (DUK_UNLIKELY(count < 0)) { - DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT); + DUK_ERROR_RANGE_INVALID_COUNT(thr); 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_API(thr, DUK_STR_POP_TOO_MANY); + DUK_ERROR_RANGE_INVALID_COUNT(thr); } /* @@ -19248,12 +21004,15 @@ DUK_EXTERNAL void duk_pop_n(duk_context *ctx, duk_idx_t count) { /* XXX: optimize loops */ #if defined(DUK_USE_REFERENCE_COUNTING) - while (count > 0) { - count--; - tv = --thr->valstack_top; /* tv points to element just below prev top */ + tv = thr->valstack_top; + tv_end = tv - count; + while (tv != tv_end) { + tv--; DUK_ASSERT(tv >= thr->valstack_bottom); - DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ + DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv); } + thr->valstack_top = tv; + DUK_REFZERO_CHECK_FAST(thr); #else tv = thr->valstack_top; while (count > 0) { @@ -19284,12 +21043,40 @@ 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_API(thr, DUK_STR_POP_TOO_MANY); + DUK_ERROR_RANGE_INVALID_COUNT(thr); } tv = --thr->valstack_top; /* tv points to element just below prev top */ DUK_ASSERT(tv >= thr->valstack_bottom); -#ifdef DUK_USE_REFERENCE_COUNTING +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ +#else + DUK_TVAL_SET_UNDEFINED(tv); +#endif + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); +} +#endif /* !DUK_USE_PREFER_SIZE */ + +/* Unsafe internal variant which assumes there are enough values on the value + * stack so that a top check can be skipped safely. + */ +#if defined(DUK_USE_PREFER_SIZE) +DUK_INTERNAL void duk_pop_unsafe(duk_context *ctx) { + DUK_ASSERT_CTX_VALID(ctx); + duk_pop_n(ctx, 1); +} +#else +DUK_INTERNAL void duk_pop_unsafe(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + DUK_ASSERT_CTX_VALID(ctx); + + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); + + tv = --thr->valstack_top; /* tv points to element just below prev top */ + DUK_ASSERT(tv >= thr->valstack_bottom); +#if defined(DUK_USE_REFERENCE_COUNTING) DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ #else DUK_TVAL_SET_UNDEFINED(tv); @@ -19308,11 +21095,86 @@ DUK_EXTERNAL void duk_pop_3(duk_context *ctx) { duk_pop_n(ctx, 3); } +/* + * Pack and unpack (pack value stack entries into an array and vice versa) + */ + +/* XXX: pack index range? array index offset? */ +DUK_INTERNAL void duk_pack(duk_context *ctx, duk_idx_t count) { + duk_hthread *thr; + duk_harray *a; + duk_tval *tv_src; + duk_tval *tv_dst; + duk_tval *tv_curr; + duk_tval *tv_limit; + duk_idx_t top; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + + top = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); + if (count < 0 || count > top) { + DUK_ERROR_RANGE_INVALID_COUNT(thr); + return; + } + + /* Wrapping is controlled by the check above: value stack top can be + * at most thr->valstack_max which is low enough so that multiplying + * with sizeof(duk_tval) won't wrap. + */ + DUK_ASSERT(count >= 0 && count <= (duk_idx_t) thr->valstack_max); + DUK_ASSERT((duk_size_t) count <= DUK_SIZE_MAX / sizeof(duk_tval)); /* no wrapping */ + + a = duk_push_harray_with_size(ctx, (duk_uint32_t) count); /* XXX: uninitialized would be OK */ + DUK_ASSERT(a != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_ASIZE((duk_hobject *) a) == (duk_uint32_t) count); + DUK_ASSERT(count == 0 || DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a) != NULL); + DUK_ASSERT((duk_idx_t) a->length == count); + + /* Copy value stack values directly to the array part without + * any refcount updates: net refcount changes are zero. + */ + + tv_src = thr->valstack_top - count - 1; + tv_dst = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a); + DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, (size_t) count * sizeof(duk_tval)); + + /* Overwrite result array to final value stack location and wipe + * the rest; no refcount operations needed. + */ + + tv_dst = tv_src; /* when count == 0, same as tv_src (OK) */ + tv_src = thr->valstack_top - 1; + DUK_TVAL_SET_TVAL(tv_dst, tv_src); + + /* XXX: internal helper to wipe a value stack segment? */ + tv_curr = tv_dst + 1; + tv_limit = thr->valstack_top; + while (tv_curr != tv_limit) { + /* Wipe policy: keep as 'undefined'. */ + DUK_TVAL_SET_UNDEFINED(tv_curr); + tv_curr++; + } + thr->valstack_top = tv_dst + 1; +} + +#if 0 +/* XXX: unpack to position? */ +DUK_INTERNAL void duk_unpack(duk_context *ctx) { + /* - dense with length <= a_part + * - dense with length > a_part + * - sparse + * - array-like but not actually an array? + * - how to deal with 'unused' values (gaps); inherit or ignore? + */ +} +#endif + /* * Error throwing */ -DUK_EXTERNAL void duk_throw(duk_context *ctx) { +DUK_EXTERNAL void duk_throw_raw(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT(thr->valstack_bottom >= thr->valstack); @@ -19320,7 +21182,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_API(thr, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_TYPE_INVALID_ARGS(thr); } /* Errors are augmented when they are created, not when they are @@ -19343,15 +21205,15 @@ DUK_EXTERNAL void duk_throw(duk_context *ctx) { duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW); /* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't - * need to check that here. If the value is NULL, a panic occurs because - * we can't return. + * need to check that here. If the value is NULL, a fatal error occurs + * because we can't return. */ duk_err_longjmp(thr); DUK_UNREACHABLE(); } -DUK_EXTERNAL void duk_fatal(duk_context *ctx, duk_errcode_t err_code, const char *err_msg) { +DUK_EXTERNAL void duk_fatal_raw(duk_context *ctx, const char *err_msg) { duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT_CTX_VALID(ctx); @@ -19359,23 +21221,29 @@ DUK_EXTERNAL void duk_fatal(duk_context *ctx, duk_errcode_t err_code, const char DUK_ASSERT(thr->heap != NULL); DUK_ASSERT(thr->heap->fatal_func != NULL); - DUK_D(DUK_DPRINT("fatal error occurred, code %ld, message %s", - (long) err_code, (const char *) err_msg)); + DUK_D(DUK_DPRINT("fatal error occurred: %s", err_msg ? err_msg : "NULL")); /* fatal_func should be noreturn, but noreturn declarations on function * pointers has a very spotty support apparently so it's not currently * done. */ - thr->heap->fatal_func(ctx, err_code, err_msg); + thr->heap->fatal_func(thr->heap->heap_udata, err_msg); - DUK_PANIC(DUK_ERR_API_ERROR, "fatal handler returned"); + /* If the fatal handler returns, all bets are off. It'd be nice to + * print something here but since we don't want to depend on stdio, + * there's no way to do so portably. + */ + DUK_D(DUK_DPRINT("fatal error handler returned, all bets are off!")); + for (;;) { + /* loop forever, don't return (function marked noreturn) */ + } } DUK_EXTERNAL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) { DUK_ASSERT_CTX_VALID(ctx); duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap); - duk_throw(ctx); + (void) duk_throw(ctx); } DUK_EXTERNAL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) { @@ -19386,14 +21254,15 @@ DUK_EXTERNAL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const va_start(ap, fmt); duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap); va_end(ap); - duk_throw(ctx); + (void) duk_throw(ctx); } #if !defined(DUK_USE_VARIADIC_MACROS) -DUK_EXTERNAL void duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) { +DUK_NORETURN(DUK_LOCAL_DECL void duk__throw_error_from_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, va_list ap)); + +DUK_LOCAL void duk__throw_error_from_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, va_list ap) { const char *filename; duk_int_t line; - va_list ap; DUK_ASSERT_CTX_VALID(ctx); @@ -19402,10 +21271,41 @@ DUK_EXTERNAL void duk_error_stash(duk_context *ctx, duk_errcode_t err_code, cons duk_api_global_filename = NULL; duk_api_global_line = 0; - va_start(ap, fmt); duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap); - va_end(ap); - duk_throw(ctx); + (void) duk_throw(ctx); +} + +#define DUK__ERROR_STASH_SHARED(code) do { \ + va_list ap; \ + va_start(ap, fmt); \ + duk__throw_error_from_stash(ctx, (code), fmt, ap); \ + va_end(ap); \ + /* Never reached; if return 0 here, gcc/clang will complain. */ \ + } while (0) + +DUK_EXTERNAL duk_ret_t duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) { + DUK__ERROR_STASH_SHARED(err_code); +} +DUK_EXTERNAL duk_ret_t duk_generic_error_stash(duk_context *ctx, const char *fmt, ...) { + DUK__ERROR_STASH_SHARED(DUK_ERR_ERROR); +} +DUK_EXTERNAL duk_ret_t duk_eval_error_stash(duk_context *ctx, const char *fmt, ...) { + DUK__ERROR_STASH_SHARED(DUK_ERR_EVAL_ERROR); +} +DUK_EXTERNAL duk_ret_t duk_range_error_stash(duk_context *ctx, const char *fmt, ...) { + DUK__ERROR_STASH_SHARED(DUK_ERR_RANGE_ERROR); +} +DUK_EXTERNAL duk_ret_t duk_reference_error_stash(duk_context *ctx, const char *fmt, ...) { + DUK__ERROR_STASH_SHARED(DUK_ERR_REFERENCE_ERROR); +} +DUK_EXTERNAL duk_ret_t duk_syntax_error_stash(duk_context *ctx, const char *fmt, ...) { + DUK__ERROR_STASH_SHARED(DUK_ERR_SYNTAX_ERROR); +} +DUK_EXTERNAL duk_ret_t duk_type_error_stash(duk_context *ctx, const char *fmt, ...) { + DUK__ERROR_STASH_SHARED(DUK_ERR_TYPE_ERROR); +} +DUK_EXTERNAL duk_ret_t duk_uri_error_stash(duk_context *ctx, const char *fmt, ...) { + DUK__ERROR_STASH_SHARED(DUK_ERR_URI_ERROR); } #endif /* DUK_USE_VARIADIC_MACROS */ @@ -19413,14 +21313,14 @@ DUK_EXTERNAL void duk_error_stash(duk_context *ctx, duk_errcode_t err_code, cons * Comparison */ -DUK_EXTERNAL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) { +DUK_EXTERNAL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv1, *tv2; DUK_ASSERT_CTX_VALID(ctx); - tv1 = duk_get_tval(ctx, index1); - tv2 = duk_get_tval(ctx, index2); + tv1 = duk_get_tval(ctx, idx1); + tv2 = duk_get_tval(ctx, idx2); if ((tv1 == NULL) || (tv2 == NULL)) { return 0; } @@ -19431,13 +21331,13 @@ DUK_EXTERNAL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t return duk_js_equals(thr, tv1, tv2); } -DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) { +DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) { duk_tval *tv1, *tv2; DUK_ASSERT_CTX_VALID(ctx); - tv1 = duk_get_tval(ctx, index1); - tv2 = duk_get_tval(ctx, index2); + tv1 = duk_get_tval(ctx, idx1); + tv2 = duk_get_tval(ctx, idx2); if ((tv1 == NULL) || (tv2 == NULL)) { return 0; } @@ -19446,11 +21346,26 @@ DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t index1, du return duk_js_strict_equals(tv1, tv2); } +DUK_EXTERNAL_DECL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) { + duk_tval *tv1, *tv2; + + DUK_ASSERT_CTX_VALID(ctx); + + tv1 = duk_get_tval(ctx, idx1); + tv2 = duk_get_tval(ctx, idx2); + if ((tv1 == NULL) || (tv2 == NULL)) { + return 0; + } + + /* No coercions or other side effects, so safe */ + return duk_js_samevalue(tv1, tv2); +} + /* * instanceof */ -DUK_EXTERNAL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) { +DUK_EXTERNAL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) { duk_tval *tv1, *tv2; DUK_ASSERT_CTX_VALID(ctx); @@ -19461,9 +21376,9 @@ DUK_EXTERNAL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t index1, duk_i * be somewhat inconsistent if rval would be allowed to be * non-existent without a TypeError. */ - tv1 = duk_require_tval(ctx, index1); + tv1 = duk_require_tval(ctx, idx1); DUK_ASSERT(tv1 != NULL); - tv2 = duk_require_tval(ctx, index2); + tv2 = duk_require_tval(ctx, idx2); DUK_ASSERT(tv2 != NULL); return duk_js_instanceof((duk_hthread *) ctx, tv1, tv2); @@ -19473,11 +21388,7 @@ DUK_EXTERNAL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t index1, duk_i * Lightfunc */ -DUK_INTERNAL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv) { - duk_c_function func; - - DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv)); - +DUK_INTERNAL void duk_push_lightfunc_name_raw(duk_context *ctx, duk_c_function func, duk_small_uint_t lf_flags) { /* Lightfunc name, includes Duktape/C native function pointer, which * can often be used to locate the function from a symbol table. * The name also includes the 16-bit duk_tval flags field because it @@ -19490,19 +21401,31 @@ DUK_INTERNAL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv) { * is accessed). */ - func = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv); duk_push_sprintf(ctx, "light_"); duk_push_string_funcptr(ctx, (duk_uint8_t *) &func, sizeof(func)); - duk_push_sprintf(ctx, "_%04x", (unsigned int) DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv)); + duk_push_sprintf(ctx, "_%04x", (unsigned int) lf_flags); duk_concat(ctx, 3); } +DUK_INTERNAL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv) { + duk_c_function func; + duk_small_uint_t lf_flags; + + DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv)); + DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); + duk_push_lightfunc_name_raw(ctx, func, lf_flags); +} + DUK_INTERNAL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv) { + duk_c_function func; + duk_small_uint_t lf_flags; + DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv)); + DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); /* read before 'tv' potentially invalidated */ duk_push_string(ctx, "function "); - duk_push_lightfunc_name(ctx, tv); - duk_push_string(ctx, "() {\"light\"}"); + duk_push_lightfunc_name_raw(ctx, func, lf_flags); + duk_push_string(ctx, "() { [lightfunc code] }"); duk_concat(ctx, 3); } @@ -19540,7 +21463,6 @@ 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). @@ -19607,28 +21529,55 @@ DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring 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_LOCAL const char *duk__push_string_tval_readable(duk_context *ctx, duk_tval *tv, duk_bool_t error_aware) { duk_hthread *thr; DUK_ASSERT_CTX_VALID(ctx); thr = (duk_hthread *) ctx; DUK_UNREF(thr); + /* 'tv' may be NULL */ if (tv == NULL) { duk_push_string(ctx, "none"); } else { switch (DUK_TVAL_GET_TAG(tv)) { case DUK_TAG_STRING: { + /* XXX: symbol support (maybe in summary rework branch) */ 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); + + if (error_aware && + duk_hobject_prototype_chain_contains(thr, h, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) { + /* Get error message in a side effect free way if + * possible; if not, summarize as a generic object. + * Error message currently gets quoted. + */ + /* XXX: better internal getprop call; get without side effects + * but traverse inheritance chain. + */ + duk_tval *tv_msg; + tv_msg = duk_hobject_find_existing_entry_tval_ptr(thr->heap, h, DUK_HTHREAD_STRING_MESSAGE(thr)); + if (tv_msg) { + /* It's important this summarization is + * not error aware to avoid unlimited + * recursion when the .message property + * is e.g. another error. + */ + return duk_push_string_tval_readable(ctx, tv_msg); + } + } + duk_push_class_string_tval(ctx, tv); break; } case DUK_TAG_BUFFER: { + /* While plain buffers mimic Uint8Arrays, they summarize differently. + * This is useful so that the summarized string accurately reflects the + * internal type which may matter for figuring out bugs etc. + */ /* XXX: Hex encoded, length limited buffer summary here? */ duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); DUK_ASSERT(h != NULL); @@ -19641,7 +21590,7 @@ DUK_INTERNAL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tva */ duk_push_tval(ctx, tv); duk_push_sprintf(ctx, "(%s)", duk_to_string(ctx, -1)); - duk_remove(ctx, -2); + duk_remove_m2(ctx); break; } default: { @@ -19653,22 +21602,57 @@ DUK_INTERNAL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tva return duk_to_string(ctx, -1); } +DUK_INTERNAL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__push_string_tval_readable(ctx, tv, 0 /*error_aware*/); +} -DUK_INTERNAL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index) { +DUK_INTERNAL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT_CTX_VALID(ctx); - return duk_push_string_tval_readable(ctx, duk_get_tval(ctx, index)); + return duk_push_string_tval_readable(ctx, duk_get_tval(ctx, idx)); } -#endif /* !DUK_USE_PARANOID_ERRORS */ +DUK_INTERNAL const char *duk_push_string_tval_readable_error(duk_context *ctx, duk_tval *tv) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__push_string_tval_readable(ctx, tv, 1 /*error_aware*/); +} + +DUK_INTERNAL void duk_push_symbol_descriptive_string(duk_context *ctx, duk_hstring *h) { + const duk_uint8_t *p; + const duk_uint8_t *p_end; + const duk_uint8_t *q; + + /* .toString() */ + duk_push_string(ctx, "Symbol("); + p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); + p_end = p + DUK_HSTRING_GET_BYTELEN(h); + DUK_ASSERT(p[0] == 0xff || (p[0] & 0xc0) == 0x80); + p++; + for (q = p; q < p_end; q++) { + if (*q == 0xffU) { + /* Terminate either at end-of-string (but NUL MUST + * be accepted without terminating description) or + * 0xFF, which is used to mark start of unique trailer + * (and cannot occur in CESU-8 / extended UTF-8). + */ + break; + } + } + duk_push_lstring(ctx, (const char *) p, (duk_size_t) (q - p)); + duk_push_string(ctx, ")"); + duk_concat(ctx, 3); +} + +/* automatic undefs */ #undef DUK__CHECK_SPACE +#undef DUK__ERROR_STASH_SHARED #undef DUK__PACK_ARGS #undef DUK__READABLE_STRING_MAXCHARS -#line 1 "duk_api_string.c" /* * String manipulation */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in, duk_bool_t is_join) { duk_hthread *thr = (duk_hthread *) ctx; @@ -19683,11 +21667,11 @@ 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_API(thr, DUK_STR_INVALID_COUNT); + DUK_ERROR_RANGE_INVALID_COUNT(thr); return; } DUK_ASSERT(count_in == 0); - duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); + duk_push_hstring_empty(ctx); return; } count = (duk_uint_t) count_in; @@ -19702,7 +21686,7 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in, t2 = (duk_size_t) (count - 1); limit = (duk_size_t) DUK_HSTRING_MAX_BYTELEN; if (DUK_UNLIKELY(t2 != 0 && t1 > limit / t2)) { - /* Combined size of separators already overflows */ + /* Combined size of separators already overflows. */ goto error_overflow; } len = (duk_size_t) (t1 * t2); @@ -19712,8 +21696,7 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in, for (i = count; i >= 1; i--) { duk_size_t new_len; - duk_to_string(ctx, -((duk_idx_t) i)); - h = duk_require_hstring(ctx, -((duk_idx_t) i)); + h = duk_to_hstring(ctx, -((duk_idx_t) i)); new_len = len + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h); /* Impose a string maximum length, need to handle overflow @@ -19729,11 +21712,13 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in, DUK_DDD(DUK_DDDPRINT("join/concat %lu strings, total length %lu bytes", (unsigned long) count, (unsigned long) len)); - /* use stack allocated buffer to ensure reachability in errors (e.g. intern error) */ - buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, len); + /* Use stack allocated buffer to ensure reachability in errors + * (e.g. intern error). + */ + buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, len); DUK_ASSERT(buf != NULL); - /* [... (sep) str1 str2 ... strN buf] */ + /* [ ... (sep) str1 str2 ... strN buf ] */ idx = 0; for (i = count; i >= 1; i--) { @@ -19749,9 +21734,9 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in, DUK_ASSERT(idx == len); - /* [... (sep) str1 str2 ... strN buf] */ + /* [ ... (sep) str1 str2 ... strN buf ] */ - /* get rid of the strings early to minimize memory use before intern */ + /* Get rid of the strings early to minimize memory use before intern. */ if (is_join) { duk_replace(ctx, -((duk_idx_t) count) - 2); /* overwrite sep */ @@ -19761,15 +21746,15 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in, duk_pop_n(ctx, count-1); } - /* [... buf] */ + /* [ ... buf ] */ - (void) duk_to_string(ctx, -1); + (void) duk_buffer_to_string(ctx, -1); /* Safe if inputs are safe. */ - /* [... res] */ + /* [ ... res ] */ return; error_overflow: - DUK_ERROR_RANGE(thr, DUK_STR_CONCAT_RESULT_TOO_LONG); + DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG); } DUK_EXTERNAL void duk_concat(duk_context *ctx, duk_idx_t count) { @@ -19788,7 +21773,7 @@ DUK_EXTERNAL void duk_join(duk_context *ctx, duk_idx_t count) { * Case conversion needs also the character surroundings though. */ -DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decode_char_function callback, void *udata) { +DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t idx, duk_decode_char_function callback, void *udata) { duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h_input; const duk_uint8_t *p, *p_start, *p_end; @@ -19796,7 +21781,7 @@ DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decod DUK_ASSERT_CTX_VALID(ctx); - h_input = duk_require_hstring(ctx, index); + h_input = duk_require_hstring(ctx, idx); /* Accept symbols. */ DUK_ASSERT(h_input != NULL); p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); @@ -19807,12 +21792,12 @@ DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decod if (p >= p_end) { break; } - cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); + cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); callback(udata, cp); } } -DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char_function callback, void *udata) { +DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t idx, duk_map_char_function callback, void *udata) { duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h_input; duk_bufwriter_ctx bw_alloc; @@ -19822,13 +21807,13 @@ DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char DUK_ASSERT_CTX_VALID(ctx); - index = duk_normalize_index(ctx, index); + idx = duk_normalize_index(ctx, idx); - h_input = duk_require_hstring(ctx, index); + h_input = duk_require_hstring(ctx, idx); /* Accept symbols. */ DUK_ASSERT(h_input != NULL); bw = &bw_alloc; - DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* reasonable output estimate */ + DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* Reasonable output estimate. */ p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); @@ -19842,18 +21827,18 @@ DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char if (p >= p_end) { break; } - cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); + cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); cp = callback(udata, cp); DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp); } DUK_BW_COMPACT(thr, bw); - duk_to_string(ctx, -1); - duk_replace(ctx, index); + (void) duk_buffer_to_string(ctx, -1); /* Safe, extended UTF-8 encoded. */ + duk_replace(ctx, idx); } -DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t start_offset, duk_size_t end_offset) { +DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t idx, duk_size_t start_offset, duk_size_t end_offset) { duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h; duk_hstring *res; @@ -19862,8 +21847,8 @@ DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t st DUK_ASSERT_CTX_VALID(ctx); - index = duk_require_normalize_index(ctx, index); - h = duk_require_hstring(ctx, index); + idx = duk_require_normalize_index(ctx, idx); /* Accept symbols. */ + h = duk_require_hstring(ctx, idx); DUK_ASSERT(h != NULL); if (end_offset >= DUK_HSTRING_GET_CHARLEN(h)) { @@ -19878,7 +21863,7 @@ DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t st DUK_ASSERT_DISABLE(end_offset >= 0); DUK_ASSERT(end_offset >= start_offset && end_offset <= DUK_HSTRING_GET_CHARLEN(h)); - /* guaranteed by string limits */ + /* Guaranteed by string limits. */ DUK_ASSERT(start_offset <= DUK_UINT32_MAX); DUK_ASSERT(end_offset <= DUK_UINT32_MAX); @@ -19886,21 +21871,21 @@ DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t st end_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) end_offset); DUK_ASSERT(end_byte_offset >= start_byte_offset); - DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* guaranteed by string limits */ + DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* Guaranteed by string limits. */ - /* no size check is necessary */ + /* No size check is necessary. */ res = duk_heap_string_intern_checked(thr, DUK_HSTRING_GET_DATA(h) + start_byte_offset, (duk_uint32_t) (end_byte_offset - start_byte_offset)); duk_push_hstring(ctx, res); - duk_replace(ctx, index); + duk_replace(ctx, idx); } /* XXX: this is quite clunky. Add Unicode helpers to scan backwards and * forwards with a callback to process codepoints? */ -DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) { +DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h; const duk_uint8_t *p, *p_start, *p_end, *p_tmp1, *p_tmp2; /* pointers for scanning */ @@ -19909,8 +21894,8 @@ DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) { DUK_ASSERT_CTX_VALID(ctx); - index = duk_require_normalize_index(ctx, index); - h = duk_require_hstring(ctx, index); + idx = duk_require_normalize_index(ctx, idx); /* Accept symbols. */ + h = duk_require_hstring(ctx, idx); DUK_ASSERT(h != NULL); p_start = DUK_HSTRING_GET_DATA(h); @@ -19927,7 +21912,7 @@ DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) { } q_start = p; if (p == p_end) { - /* entire string is whitespace */ + /* Entire string is whitespace. */ q_end = p; goto scan_done; } @@ -19973,123 +21958,112 @@ DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) { } duk_push_lstring(ctx, (const char *) q_start, (duk_size_t) (q_end - q_start)); - duk_replace(ctx, index); + duk_replace(ctx, idx); } -DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t index, duk_size_t char_offset) { +DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t idx, duk_size_t char_offset) { duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h; duk_ucodepoint_t cp; DUK_ASSERT_CTX_VALID(ctx); - h = duk_require_hstring(ctx, index); + /* XXX: Share code with String.prototype.charCodeAt? Main difference + * is handling of clamped offsets. + */ + + h = duk_require_hstring(ctx, idx); /* Accept symbols. */ DUK_ASSERT(h != NULL); - DUK_ASSERT_DISABLE(char_offset >= 0); /* always true, arg is unsigned */ + DUK_ASSERT_DISABLE(char_offset >= 0); /* Always true, arg is unsigned. */ if (char_offset >= DUK_HSTRING_GET_CHARLEN(h)) { return 0; } - DUK_ASSERT(char_offset <= DUK_UINT_MAX); /* guaranteed by string limits */ - cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset); + DUK_ASSERT(char_offset <= DUK_UINT_MAX); /* Guaranteed by string limits. */ + cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset, 0 /*surrogate_aware*/); return (duk_codepoint_t) cp; } -#line 1 "duk_api_var.c" /* - * Variable access + * Date/time. */ -/* include removed: duk_internal.h */ - -DUK_EXTERNAL void duk_get_var(duk_context *ctx) { - duk_hthread *thr = (duk_hthread *) ctx; - duk_activation *act; - duk_hstring *h_varname; - duk_small_int_t throw_flag = 1; /* always throw ReferenceError for unresolvable */ - - DUK_ASSERT_CTX_VALID(ctx); - - h_varname = duk_require_hstring(ctx, -1); /* XXX: tostring? */ - DUK_ASSERT(h_varname != NULL); - - act = duk_hthread_get_current_activation(thr); - if (act) { - (void) duk_js_getvar_activation(thr, act, h_varname, throw_flag); /* -> [ ... varname val this ] */ - } else { - /* Outside any activation -> look up from global. */ - DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL); - (void) duk_js_getvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, throw_flag); - } +/* #include duk_internal.h -> already included */ - /* [ ... varname val this ] (because throw_flag == 1, always resolved) */ - - duk_pop(ctx); - duk_remove(ctx, -2); - - /* [ ... val ] */ - - /* Return value would be pointless: because throw_flag==1, we always - * throw if the identifier doesn't resolve. - */ - return; +DUK_EXTERNAL duk_double_t duk_get_now(duk_context *ctx) { + return ((duk_double_t) DUK_USE_DATE_GET_NOW((ctx))); } -DUK_EXTERNAL void duk_put_var(duk_context *ctx) { - duk_hthread *thr = (duk_hthread *) ctx; - duk_activation *act; - duk_hstring *h_varname; - duk_tval *tv_val; - duk_small_int_t throw_flag; - - DUK_ASSERT_CTX_VALID(ctx); - - h_varname = duk_require_hstring(ctx, -2); /* XXX: tostring? */ - DUK_ASSERT(h_varname != NULL); +DUK_EXTERNAL void duk_time_to_components(duk_context *ctx, duk_double_t timeval, duk_time_components *comp) { + duk_int_t parts[DUK_DATE_IDX_NUM_PARTS]; + duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; + duk_uint_t flags; - tv_val = duk_require_tval(ctx, -1); + DUK_ASSERT(ctx != NULL); + DUK_ASSERT(comp != NULL); /* XXX: or check? */ + DUK_UNREF(ctx); - throw_flag = duk_is_strict_call(ctx); + /* Convert as one-based, but change month to zero-based to match the + * Ecmascript Date built-in behavior 1:1. + */ + flags = DUK_DATE_FLAG_ONEBASED | DUK_DATE_FLAG_NAN_TO_ZERO; - act = duk_hthread_get_current_activation(thr); - if (act) { - duk_js_putvar_activation(thr, act, h_varname, tv_val, throw_flag); /* -> [ ... varname val this ] */ - } else { - /* Outside any activation -> put to global. */ - DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL); - duk_js_putvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, tv_val, throw_flag); - } + duk_bi_date_timeval_to_parts(timeval, parts, dparts, flags); - /* [ ... varname val ] */ + DUK_ASSERT(dparts[DUK_DATE_IDX_MONTH] >= 1.0 && dparts[DUK_DATE_IDX_MONTH] <= 12.0); + comp->year = dparts[DUK_DATE_IDX_YEAR]; + comp->month = dparts[DUK_DATE_IDX_MONTH] - 1.0; + comp->day = dparts[DUK_DATE_IDX_DAY]; + comp->hours = dparts[DUK_DATE_IDX_HOUR]; + comp->minutes = dparts[DUK_DATE_IDX_MINUTE]; + comp->seconds = dparts[DUK_DATE_IDX_SECOND]; + comp->milliseconds = dparts[DUK_DATE_IDX_MILLISECOND]; + comp->weekday = dparts[DUK_DATE_IDX_WEEKDAY]; +} - duk_pop_2(ctx); +DUK_EXTERNAL duk_double_t duk_components_to_time(duk_context *ctx, duk_time_components *comp) { + duk_double_t d; + duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; + duk_uint_t flags; - /* [ ... ] */ + DUK_ASSERT(ctx != NULL); + DUK_ASSERT(comp != NULL); /* XXX: or check? */ + DUK_UNREF(ctx); - return; -} + /* Match Date constructor behavior (with UTC time). Month is given + * as zero-based. Day-of-month is given as one-based so normalize + * it to zero-based as the internal conversion helpers expects all + * components to be zero-based. + */ + flags = 0; -DUK_EXTERNAL duk_bool_t duk_del_var(duk_context *ctx) { - DUK_ASSERT_CTX_VALID(ctx); + /* XXX: expensive conversion; use array format in API instead, or unify + * time provider and time API to use same struct? + */ - DUK_ERROR_UNIMPLEMENTED_DEFMSG((duk_hthread *) ctx); - return 0; -} + dparts[DUK_DATE_IDX_YEAR] = comp->year; + dparts[DUK_DATE_IDX_MONTH] = comp->month; + dparts[DUK_DATE_IDX_DAY] = comp->day - 1.0; + dparts[DUK_DATE_IDX_HOUR] = comp->hours; + dparts[DUK_DATE_IDX_MINUTE] = comp->minutes; + dparts[DUK_DATE_IDX_SECOND] = comp->seconds; + dparts[DUK_DATE_IDX_MILLISECOND] = comp->milliseconds; + dparts[DUK_DATE_IDX_WEEKDAY] = 0; /* ignored */ -DUK_EXTERNAL duk_bool_t duk_has_var(duk_context *ctx) { - DUK_ASSERT_CTX_VALID(ctx); + d = duk_bi_date_get_timeval_from_dparts(dparts, flags); - DUK_ERROR_UNIMPLEMENTED_DEFMSG((duk_hthread *) ctx); - return 0; + return d; } -#line 1 "duk_bi_array.c" /* * Array built-ins * - * Note that most Array built-ins are intentionally generic and work even - * when the 'this' binding is not an Array instance. To ensure this, - * Array algorithms do not assume "magical" Array behavior for the "length" - * property, for instance. + * Most Array built-ins are intentionally generic in Ecmascript, and are + * intended to work even when the 'this' binding is not an Array instance. + * This Ecmascript feature is also used by much real world code. For this + * reason the implementations here don't assume exotic Array behavior or + * e.g. presence of a .length property. However, some algorithms have a + * fast path for duk_harray backed actual Array instances, enabled when + * footprint is not a concern. * * XXX: the "Throw" flag should be set for (almost?) all [[Put]] and * [[Delete]] operations, but it's currently false throughout. Go through @@ -20102,7 +22076,6 @@ DUK_EXTERNAL duk_bool_t duk_has_var(duk_context *ctx) { * the unsigned 32-bit range (E5.1 Section 15.4.5.1 throws a RangeError if so) * some intermediate values may be above 0xffffffff and this may not be always * correctly handled now (duk_uint32_t is not enough for all algorithms). - * * For instance, push() can legitimately write entries beyond length 0xffffffff * and cause a RangeError only at the end. To do this properly, the current * push() implementation tracks the array index using a 'double' instead of a @@ -20119,28 +22092,33 @@ DUK_EXTERNAL duk_bool_t duk_has_var(duk_context *ctx) { * Both "put" and "define" are used in the E5.1 specification; as a rule, * "put" is used when modifying an existing array (or a non-array 'this' * binding) and "define" for setting values into a fresh result array. - * - * Also note that Array instance 'length' should be writable, but not - * enumerable and definitely not configurable: even Duktape code internally - * assumes that an Array instance will always have a 'length' property. - * Preventing deletion of the property is critical. */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ /* Perform an intermediate join when this many elements have been pushed * on the value stack. */ #define DUK__ARRAY_MID_JOIN_LIMIT 4096 -/* Shared entry code for many Array built-ins. Note that length is left - * on stack (it could be popped, but that's not necessary). +#if defined(DUK_USE_ARRAY_BUILTIN) + +/* + * Shared helpers. + */ + +/* Shared entry code for many Array built-ins: the 'this' binding is pushed + * on the value stack and object coerced, and the current .length is returned. + * Note that length is left on stack (it could be popped, but that's not + * usually necessary because call handling will clean it up automatically). */ DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_context *ctx) { duk_uint32_t len; + /* XXX: push more directly? */ (void) duk_push_this_coercible_to_object(ctx); - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH); + DUK_ASSERT_HOBJECT_VALID(duk_get_hobject(ctx, -1)); + duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_LENGTH); len = duk_to_uint32(ctx, -1); /* -> [ ... ToObject(this) ToUint32(length) ] */ @@ -20154,51 +22132,101 @@ DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_context *ctx) { */ duk_uint32_t ret = duk__push_this_obj_len_u32(ctx); if (DUK_UNLIKELY(ret >= 0x80000000UL)) { - DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_ARRAY_LENGTH_OVER_2G); + DUK_ERROR_RANGE_INVALID_LENGTH((duk_hthread *) ctx); } return ret; } +#if defined(DUK_USE_ARRAY_FASTPATH) +/* Check if 'this' binding is an Array instance (duk_harray) which satisfies + * a few other guarantees for fast path operation. The fast path doesn't + * need to handle all operations, even for duk_harrays, but must handle a + * significant fraction to improve performance. Return a non-NULL duk_harray + * pointer when all fast path criteria are met, NULL otherwise. + */ +DUK_LOCAL duk_harray *duk__arraypart_fastpath_this(duk_context *ctx) { + duk_hthread *thr; + duk_tval *tv; + duk_hobject *h; + duk_uint_t flags_mask, flags_bits, flags_value; + + thr = (duk_hthread *) ctx; + DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* because call in progress */ + tv = DUK_GET_THIS_TVAL_PTR(thr); + + /* Fast path requires that 'this' is a duk_harray. Read only arrays + * (ROM backed) are also rejected for simplicity. + */ + if (!DUK_TVAL_IS_OBJECT(tv)) { + DUK_DD(DUK_DDPRINT("reject array fast path: not an object")); + return NULL; + } + h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + flags_mask = DUK_HOBJECT_FLAG_ARRAY_PART | \ + DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \ + DUK_HEAPHDR_FLAG_READONLY; + flags_bits = DUK_HOBJECT_FLAG_ARRAY_PART | \ + DUK_HOBJECT_FLAG_EXOTIC_ARRAY; + flags_value = DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) h); + if ((flags_value & flags_mask) != flags_bits) { + DUK_DD(DUK_DDPRINT("reject array fast path: object flag check failed")); + return NULL; + } + + /* In some cases a duk_harray's 'length' may be larger than the + * current array part allocation. Avoid the fast path in these + * cases, so that all fast path code can safely assume that all + * items in the range [0,length[ are backed by the current array + * part allocation. + */ + if (((duk_harray *) h)->length > DUK_HOBJECT_GET_ASIZE(h)) { + DUK_DD(DUK_DDPRINT("reject array fast path: length > array part size")); + return NULL; + } + + /* Guarantees for fast path. */ + DUK_ASSERT(h != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0 || DUK_HOBJECT_A_GET_BASE(thr->heap, h) != NULL); + DUK_ASSERT(((duk_harray *) h)->length <= DUK_HOBJECT_GET_ASIZE(h)); + + DUK_DD(DUK_DDPRINT("array fast path allowed for: %!O", (duk_heaphdr *) h)); + return (duk_harray *) h; +} +#endif /* DUK_USE_ARRAY_FASTPATH */ + /* * Constructor */ DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_context *ctx) { duk_idx_t nargs; + duk_harray *a; duk_double_t d; duk_uint32_t len; - duk_idx_t i; + duk_uint32_t len_prealloc; nargs = duk_get_top(ctx); - duk_push_array(ctx); if (nargs == 1 && duk_is_number(ctx, 0)) { /* XXX: expensive check (also shared elsewhere - so add a shared internal API call?) */ d = duk_get_number(ctx, 0); len = duk_to_uint32(ctx, 0); if (((duk_double_t) len) != d) { - return DUK_RET_RANGE_ERROR; + DUK_DCERROR_RANGE_INVALID_LENGTH((duk_hthread *) ctx); } - /* XXX: if 'len' is low, may want to ensure array part is kept: - * the caller is likely to want a dense array. + /* For small lengths create a dense preallocated array. + * For large arrays preallocate an initial part. */ - duk_push_u32(ctx, len); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); /* [ ToUint32(len) array ToUint32(len) ] -> [ ToUint32(len) array ] */ + len_prealloc = len < 64 ? len : 64; + a = duk_push_harray_with_size(ctx, len_prealloc); + DUK_ASSERT(a != NULL); + a->length = len; return 1; } - /* XXX: optimize by creating array into correct size directly, and - * operating on the array part directly; values can be memcpy()'d from - * value stack directly as long as refcounts are increased. - */ - for (i = 0; i < nargs; i++) { - duk_dup(ctx, i); - duk_xdef_prop_index_wec(ctx, -2, (duk_uarridx_t) i); - } - - duk_push_u32(ctx, (duk_uint32_t) nargs); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); + duk_pack(ctx, nargs); return 1; } @@ -20220,7 +22248,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx) { DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) { (void) duk_push_this_coercible_to_object(ctx); - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_JOIN); + duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_JOIN); /* [ ... this func ] */ if (!duk_is_callable(ctx, -1)) { @@ -20330,7 +22358,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) { * is known to be an array, this should be equivalent. */ duk_push_uarridx(ctx, idx_last); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); DUK_ASSERT_TOP(ctx, n + 1); return 1; @@ -20381,20 +22409,21 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) { DUK__ARRAY_MID_JOIN_LIMIT : len) + 4; duk_require_stack(ctx, valstack_required); - duk_dup(ctx, 0); + duk_dup_0(ctx); /* [ sep ToObject(this) len sep ] */ count = 0; idx = 0; for (;;) { + DUK_DDD(DUK_DDDPRINT("join idx=%ld", (long) idx)); if (count >= DUK__ARRAY_MID_JOIN_LIMIT || /* intermediate join to avoid valstack overflow */ idx >= len) { /* end of loop (careful with len==0) */ /* [ sep ToObject(this) len sep str0 ... str(count-1) ] */ DUK_DDD(DUK_DDDPRINT("mid/final join, count=%ld, idx=%ld, len=%ld", (long) count, (long) idx, (long) len)); duk_join(ctx, (duk_idx_t) count); /* -> [ sep ToObject(this) len str ] */ - duk_dup(ctx, 0); /* -> [ sep ToObject(this) len str sep ] */ + duk_dup_0(ctx); /* -> [ sep ToObject(this) len str sep ] */ duk_insert(ctx, -2); /* -> [ sep ToObject(this) len sep str ] */ count = 1; } @@ -20406,17 +22435,15 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) { duk_get_prop_index(ctx, 1, (duk_uarridx_t) idx); if (duk_is_null_or_undefined(ctx, -1)) { duk_pop(ctx); - duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); + duk_push_hstring_empty(ctx); } else { if (to_locale_string) { duk_to_object(ctx, -1); - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_LOCALE_STRING); + duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_TO_LOCALE_STRING); duk_insert(ctx, -2); /* -> [ ... toLocaleString ToObject(val) ] */ duk_call_method(ctx, 0); - duk_to_string(ctx, -1); - } else { - duk_to_string(ctx, -1); } + duk_to_string(ctx, -1); } count++; @@ -20432,15 +22459,72 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) { * pop(), push() */ +#if defined(DUK_USE_ARRAY_FASTPATH) +DUK_LOCAL duk_ret_t duk__array_pop_fastpath(duk_context *ctx, duk_harray *h_arr) { + duk_hthread *thr; + duk_tval *tv_arraypart; + duk_tval *tv_val; + duk_uint32_t len; + + thr = (duk_hthread *) ctx; + + tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr); + len = h_arr->length; + if (len <= 0) { + /* nop, return undefined */ + return 0; + } + + len--; + h_arr->length = len; + + /* Fast path doesn't check for an index property inherited from + * Array.prototype. This is quite often acceptable; if not, + * disable fast path. + */ + DUK_ASSERT_VS_SPACE(thr); + tv_val = tv_arraypart + len; + if (DUK_TVAL_IS_UNUSED(tv_val)) { + /* No net refcount change. Value stack already has + * 'undefined' based on value stack init policy. + */ + DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); + DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv_val)); + } else { + /* No net refcount change. */ + DUK_TVAL_SET_TVAL(thr->valstack_top, tv_val); + DUK_TVAL_SET_UNUSED(tv_val); + } + thr->valstack_top++; + + /* XXX: there's no shrink check in the fast path now */ + + return 1; +} +#endif /* DUK_USE_ARRAY_FASTPATH */ + DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx) { duk_uint32_t len; duk_uint32_t idx; +#if defined(DUK_USE_ARRAY_FASTPATH) + duk_harray *h_arr; +#endif DUK_ASSERT_TOP(ctx, 0); + +#if defined(DUK_USE_ARRAY_FASTPATH) + h_arr = duk__arraypart_fastpath_this(ctx); + if (h_arr) { + return duk__array_pop_fastpath(ctx, h_arr); + } +#endif + + /* XXX: Merge fastpath check into a related call (push this, coerce length, etc)? */ + len = duk__push_this_obj_len_u32(ctx); if (len == 0) { duk_push_int(ctx, 0); - duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); + duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LENGTH); return 0; } idx = len - 1; @@ -20448,10 +22532,59 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx) { duk_get_prop_index(ctx, 0, (duk_uarridx_t) idx); duk_del_prop_index(ctx, 0, (duk_uarridx_t) idx); duk_push_u32(ctx, idx); - duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); + duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LENGTH); return 1; } +#if defined(DUK_USE_ARRAY_FASTPATH) +DUK_LOCAL duk_ret_t duk__array_push_fastpath(duk_context *ctx, duk_harray *h_arr) { + duk_hthread *thr; + duk_tval *tv_arraypart; + duk_tval *tv_src; + duk_tval *tv_dst; + duk_uint32_t len; + duk_idx_t i, n; + + thr = (duk_hthread *) ctx; + + len = h_arr->length; + tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr); + + n = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); + if (DUK_UNLIKELY(len + n < len)) { + DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw")); + DUK_DCERROR_RANGE_INVALID_LENGTH(thr); /* != 0 return value returned as is by caller */ + } + if (len + n > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr)) { + /* Array part would need to be extended. Rely on slow path + * for now. + * + * XXX: Rework hobject code a bit and add extend support. + */ + return 0; + } + + tv_src = thr->valstack_bottom; + tv_dst = tv_arraypart + len; + for (i = 0; i < n; i++) { + /* No net refcount change; reset value stack values to + * undefined to satisfy value stack init policy. + */ + DUK_TVAL_SET_TVAL(tv_dst, tv_src); + DUK_TVAL_SET_UNDEFINED(tv_src); + tv_src++; + tv_dst++; + } + thr->valstack_top = thr->valstack_bottom; + len += n; + h_arr->length = len; + + DUK_ASSERT((duk_uint_t) len == len); + duk_push_uint(ctx, (duk_uint_t) len); + return 1; +} +#endif /* DUK_USE_ARRAY_FASTPATH */ + DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) { /* Note: 'this' is not necessarily an Array object. The push() * algorithm is supposed to work for other kinds of objects too, @@ -20461,6 +22594,21 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) { duk_uint32_t len; duk_idx_t i, n; +#if defined(DUK_USE_ARRAY_FASTPATH) + duk_harray *h_arr; +#endif + +#if defined(DUK_USE_ARRAY_FASTPATH) + h_arr = duk__arraypart_fastpath_this(ctx); + if (h_arr) { + duk_ret_t rc; + rc = duk__array_push_fastpath(ctx, h_arr); + if (rc != 0) { + return rc; + } + DUK_DD(DUK_DDPRINT("array push() fast path exited, resize case")); + } +#endif n = duk_get_top(ctx); len = duk__push_this_obj_len_u32(ctx); @@ -20479,7 +22627,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) { if (len + (duk_uint32_t) n < len) { DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw")); - return DUK_RET_RANGE_ERROR; + DUK_DCERROR_RANGE_INVALID_LENGTH((duk_hthread *) ctx); } for (i = 0; i < n; i++) { @@ -20490,7 +22638,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) { duk_push_u32(ctx, len); duk_dup_top(ctx); - duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH); + duk_put_prop_stridx_short(ctx, -4, DUK_STRIDX_LENGTH); /* [ arg1 ... argN obj length new_length ] */ return 1; @@ -20581,25 +22729,25 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id if (!duk_is_undefined(ctx, idx_fn)) { duk_double_t d; - /* no need to check callable; duk_call() will do that */ + /* No need to check callable; duk_call() will do that. */ duk_dup(ctx, idx_fn); /* -> [ ... x y fn ] */ duk_insert(ctx, -3); /* -> [ ... fn x y ] */ duk_call(ctx, 2); /* -> [ ... res ] */ - /* The specification is a bit vague what to do if the return - * value is not a number. Other implementations seem to - * tolerate non-numbers but e.g. V8 won't apparently do a - * ToNumber(). + /* ES5 is a bit vague about what to do if the return value is + * not a number. ES2015 provides a concrete description: + * http://www.ecma-international.org/ecma-262/6.0/#sec-sortcompare. */ - /* XXX: best behavior for real world compatibility? */ - - d = duk_to_number(ctx, -1); + d = duk_to_number_m1(ctx); if (d < 0.0) { ret = -1; } else if (d > 0.0) { ret = 1; } else { + /* Because NaN compares to false, NaN is handled here + * without an explicit check above. + */ ret = 0; } @@ -20610,8 +22758,9 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id /* string compare is the default (a bit oddly) */ + /* XXX: any special handling for plain array; causes repeated coercion now? */ h1 = duk_to_hstring(ctx, -2); - h2 = duk_to_hstring(ctx, -1); + h2 = duk_to_hstring_m1(ctx); DUK_ASSERT(h1 != NULL); DUK_ASSERT(h2 != NULL); @@ -20652,7 +22801,7 @@ DUK_LOCAL void duk__array_sort_swap(duk_context *ctx, duk_int_t l, duk_int_t r) } } -#if defined(DUK_USE_DDDPRINT) +#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) /* Debug print which visualizes the qsort partitioning process. */ DUK_LOCAL void duk__debuglog_qsort_state(duk_context *ctx, duk_int_t lo, duk_int_t hi, duk_int_t pivot) { char buf[4096]; @@ -20685,7 +22834,6 @@ DUK_LOCAL void duk__debuglog_qsort_state(duk_context *ctx, duk_int_t lo, duk_int #endif DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) { - duk_hthread *thr = (duk_hthread *) ctx; duk_int_t p, l, r; /* The lo/hi indices may be crossed and hi < 0 is possible at entry. */ @@ -20709,10 +22857,9 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) { DUK_ASSERT(hi - lo + 1 >= 2); /* randomized pivot selection */ - p = lo + (duk_util_tinyrandom_get_bits(thr, 30) % (hi - lo + 1)); /* rnd in [lo,hi] */ + p = lo + (duk_int_t) (DUK_UTIL_GET_RANDOM_DOUBLE((duk_hthread *) ctx) * (duk_double_t) (hi - lo + 1)); DUK_ASSERT(p >= lo && p <= hi); - DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld", - (long) lo, (long) hi, (long) p)); + DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld", (long) lo, (long) hi, (long) p)); /* move pivot out of the way */ duk__array_sort_swap(ctx, p, lo); @@ -20773,7 +22920,7 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) { DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(ctx, 1))); duk__array_sort_swap(ctx, lo, r); -#if defined(DUK_USE_DDDPRINT) +#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) duk__debuglog_qsort_state(ctx, lo, hi, r); #endif @@ -20849,11 +22996,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) { } DUK_ASSERT(act_start >= 0 && act_start <= (duk_int_t) len); -#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT +#if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT) if (have_delcount) { #endif del_count = duk_to_int_clamped(ctx, 1, 0, len - act_start); -#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT +#if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT) } else { /* E5.1 standard behavior when deleteCount is not given would be * to treat it just like if 'undefined' was given, which coerces @@ -20873,7 +23020,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) { /* For now, restrict result array into 32-bit length range. */ if (((duk_double_t) len) - ((duk_double_t) del_count) + ((duk_double_t) item_count) > (duk_double_t) DUK_UINT32_MAX) { DUK_D(DUK_DPRINT("Array.prototype.splice() would go beyond 32-bit length, throw")); - return DUK_RET_RANGE_ERROR; + DUK_DCERROR_RANGE_INVALID_LENGTH((duk_hthread *) ctx); } duk_push_array(ctx); @@ -20898,7 +23045,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) { } } duk_push_u32(ctx, (duk_uint32_t) del_count); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); /* Steps 12 and 13: reorganize elements to make room for itemCount elements */ @@ -20971,7 +23118,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) { */ duk_push_u32(ctx, len - del_count + item_count); - duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH); + duk_put_prop_stridx_short(ctx, -4, DUK_STRIDX_LENGTH); /* result array is already at the top of stack */ DUK_ASSERT_TOP(ctx, nargs + 3); @@ -21085,7 +23232,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) { } duk_push_u32(ctx, res_length); - duk_xdef_prop_stridx(ctx, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); + duk_xdef_prop_stridx_short(ctx, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); DUK_ASSERT_TOP(ctx, 5); return 1; @@ -21102,7 +23249,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) { len = duk__push_this_obj_len_u32(ctx); if (len == 0) { duk_push_int(ctx, 0); - duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); + duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LENGTH); return 0; } @@ -21127,7 +23274,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) { duk_del_prop_index(ctx, 0, (duk_uarridx_t) (len - 1)); duk_push_u32(ctx, (duk_uint32_t) (len - 1)); - duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); + duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LENGTH); DUK_ASSERT_TOP(ctx, 3); return 1; @@ -21159,7 +23306,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) { if (len + (duk_uint32_t) nargs < len) { DUK_D(DUK_DPRINT("Array.prototype.unshift() would go beyond 32-bit length, throw")); - return DUK_RET_RANGE_ERROR; + DUK_DCERROR_RANGE_INVALID_LENGTH((duk_hthread *) ctx); } i = len; @@ -21191,7 +23338,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) { DUK_ASSERT_TOP(ctx, nargs + 2); duk_push_u32(ctx, len + nargs); duk_dup_top(ctx); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */ - duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH); + duk_put_prop_stridx_short(ctx, -4, DUK_STRIDX_LENGTH); return 1; } @@ -21202,7 +23349,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) { DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) { duk_idx_t nargs; duk_int_t i, len; - duk_int_t from_index; + duk_int_t from_idx; duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for indexOf, -1 for lastIndexOf */ /* lastIndexOf() needs to be a vararg function because we must distinguish @@ -21241,22 +23388,22 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) { * lastIndexOf: clamp fromIndex to [-len - 1, len - 1] * (if clamped to -len-1 -> fromIndex becomes -1, terminates for-loop directly) */ - from_index = duk_to_int_clamped(ctx, - 1, - (idx_step > 0 ? -len : -len - 1), - (idx_step > 0 ? len : len - 1)); - if (from_index < 0) { + from_idx = duk_to_int_clamped(ctx, + 1, + (idx_step > 0 ? -len : -len - 1), + (idx_step > 0 ? len : len - 1)); + if (from_idx < 0) { /* for lastIndexOf, result may be -1 (mark immediate termination) */ - from_index = len + from_index; + from_idx = len + from_idx; } } else { /* for indexOf, ToInteger(undefined) would be 0, i.e. correct, but * handle both indexOf and lastIndexOf specially here. */ if (idx_step > 0) { - from_index = 0; + from_idx = 0; } else { - from_index = len - 1; + from_idx = len - 1; } } @@ -21266,7 +23413,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) { * stack[3] = length (not needed, but not popped above) */ - for (i = from_index; i >= 0 && i < len; i += idx_step) { + for (i = from_idx; i >= 0 && i < len; i += idx_step) { DUK_ASSERT_TOP(ctx, 4); if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) { @@ -21356,11 +23503,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) { * effects. */ - duk_dup(ctx, 0); - duk_dup(ctx, 1); - duk_dup(ctx, -3); + duk_dup_0(ctx); + duk_dup_1(ctx); + duk_dup_m3(ctx); duk_push_u32(ctx, i); - duk_dup(ctx, 2); /* [ ... val callback thisArg val i obj ] */ + duk_dup_2(ctx); /* [ ... val callback thisArg val i obj ] */ duk_call_method(ctx, 3); /* -> [ ... val retval ] */ switch (iter_type) { @@ -21382,14 +23529,14 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) { /* nop */ break; case DUK__ITER_MAP: - duk_dup(ctx, -1); + duk_dup_top(ctx); duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) i); /* retval to result[i] */ res_length = i + 1; break; case DUK__ITER_FILTER: bval = duk_to_boolean(ctx, -1); if (bval) { - duk_dup(ctx, -2); /* orig value */ + duk_dup_m2(ctx); /* orig value */ duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) k); k++; res_length = k; @@ -21419,7 +23566,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) { DUK_ASSERT_TOP(ctx, 5); DUK_ASSERT(duk_is_array(ctx, -1)); /* topmost element is the result array already */ duk_push_u32(ctx, res_length); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); break; default: DUK_UNREACHABLE(); @@ -21447,9 +23594,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) { duk_set_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); /* stack[0] = callback fn * stack[1] = initialValue @@ -21460,7 +23605,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) { have_acc = 0; if (nargs >= 2) { - duk_dup(ctx, 1); + duk_dup_1(ctx); have_acc = 1; } DUK_DDD(DUK_DDDPRINT("have_acc=%ld, acc=%!T", @@ -21494,11 +23639,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) { DUK_ASSERT_TOP(ctx, 5); } else { DUK_ASSERT_TOP(ctx, 5); - duk_dup(ctx, 0); + duk_dup_0(ctx); duk_dup(ctx, 4); duk_get_prop_index(ctx, 2, (duk_uarridx_t) i); duk_push_u32(ctx, i); - duk_dup(ctx, 2); + duk_dup_2(ctx); DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T", (duk_tval *) duk_get_tval(ctx, -5), (duk_tval *) duk_get_tval(ctx, -4), (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2), @@ -21511,29 +23656,29 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) { } if (!have_acc) { - goto type_error; + DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); } DUK_ASSERT_TOP(ctx, 5); return 1; - - type_error: - return DUK_RET_TYPE_ERROR; } -#undef DUK__ARRAY_MID_JOIN_LIMIT +#endif /* DUK_USE_ARRAY_BUILTIN */ +/* automatic undefs */ +#undef DUK__ARRAY_MID_JOIN_LIMIT #undef DUK__ITER_EVERY -#undef DUK__ITER_SOME +#undef DUK__ITER_FILTER #undef DUK__ITER_FOREACH #undef DUK__ITER_MAP -#undef DUK__ITER_FILTER -#line 1 "duk_bi_boolean.c" +#undef DUK__ITER_SOME /* * Boolean built-ins */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ + +#if defined(DUK_USE_BOOLEAN_BUILTIN) /* Shared helper to provide toString() and valueOf(). Checks 'this', gets * the primitive value to stack top, and optionally coerces with ToString(). @@ -21559,13 +23704,14 @@ DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx DUK_ASSERT(h != NULL); if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) { - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE); + duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE); DUK_ASSERT(duk_is_boolean(ctx, -1)); goto type_ok; } } - return DUK_RET_TYPE_ERROR; + DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); + /* never here */ type_ok: if (coerce_tostring) { @@ -21585,32 +23731,49 @@ DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx) { if (duk_is_constructor_call(ctx)) { /* XXX: helper; rely on Boolean.prototype as being non-writable, non-configurable */ duk_push_this(ctx); - h_this = duk_get_hobject(ctx, -1); - DUK_ASSERT(h_this != NULL); + h_this = duk_known_hobject(ctx, -1); DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]); DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN); - duk_dup(ctx, 0); /* -> [ val obj val ] */ - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */ + duk_dup_0(ctx); /* -> [ val obj val ] */ + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */ } /* unbalanced stack */ return 1; } -#line 1 "duk_bi_buffer.c" + +#endif /* DUK_USE_BOOLEAN_BUILTIN */ /* - * Duktape.Buffer, Node.js Buffer, and Khronos/ES6 TypedArray built-ins + * ES2015 TypedArray and Node.js Buffer built-ins */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ /* - * Misc helpers + * Helpers for buffer handling, enabled with DUK_USE_BUFFEROBJECT_SUPPORT. */ #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -/* Map DUK_HBUFFEROBJECT_ELEM_xxx to duk_hobject class number. - * Sync with duk_hbufferobject.h and duk_hobject.h. +/* Map class number (minus DUK_HOBJECT_CLASS_BUFOBJ_MIN) to a bidx for the + * default internal prototype. + */ +static const duk_uint8_t duk__buffer_proto_from_classnum[] = { + DUK_BIDX_ARRAYBUFFER_PROTOTYPE, + DUK_BIDX_DATAVIEW_PROTOTYPE, + DUK_BIDX_INT8ARRAY_PROTOTYPE, + DUK_BIDX_UINT8ARRAY_PROTOTYPE, + DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, + DUK_BIDX_INT16ARRAY_PROTOTYPE, + DUK_BIDX_UINT16ARRAY_PROTOTYPE, + DUK_BIDX_INT32ARRAY_PROTOTYPE, + DUK_BIDX_UINT32ARRAY_PROTOTYPE, + DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, + DUK_BIDX_FLOAT64ARRAY_PROTOTYPE +}; + +/* Map DUK_HBUFOBJ_ELEM_xxx to duk_hobject class number. + * Sync with duk_hbufobj.h and duk_hobject.h. */ static const duk_uint8_t duk__buffer_class_from_elemtype[9] = { DUK_HOBJECT_CLASS_UINT8ARRAY, @@ -21623,11 +23786,9 @@ static const duk_uint8_t duk__buffer_class_from_elemtype[9] = { DUK_HOBJECT_CLASS_FLOAT32ARRAY, DUK_HOBJECT_CLASS_FLOAT64ARRAY }; -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -/* Map DUK_HBUFFEROBJECT_ELEM_xxx to prototype object built-in index. - * Sync with duk_hbufferobject.h. +/* Map DUK_HBUFOBJ_ELEM_xxx to prototype object built-in index. + * Sync with duk_hbufobj.h. */ static const duk_uint8_t duk__buffer_proto_from_elemtype[9] = { DUK_BIDX_UINT8ARRAY_PROTOTYPE, @@ -21640,11 +23801,8 @@ static const duk_uint8_t duk__buffer_proto_from_elemtype[9] = { DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, DUK_BIDX_FLOAT64ARRAY_PROTOTYPE }; -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -/* Map DUK__FLX_xxx to byte size. - */ +/* Map DUK__FLD_xxx to byte size. */ static const duk_uint8_t duk__buffer_nbytes_from_fldtype[6] = { 1, /* DUK__FLD_8BIT */ 2, /* DUK__FLD_16BIT */ @@ -21653,129 +23811,168 @@ static const duk_uint8_t duk__buffer_nbytes_from_fldtype[6] = { 8, /* DUK__FLD_DOUBLE */ 0 /* DUK__FLD_VARINT; not relevant here */ }; -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -/* Bitfield for each DUK_HBUFFEROBJECT_ELEM_xxx indicating which element types +/* Bitfield for each DUK_HBUFOBJ_ELEM_xxx indicating which element types * are compatible with a blind byte copy for the TypedArray set() method (also * used for TypedArray constructor). Array index is target buffer elem type, * bitfield indicates compatible source types. The types must have same byte * size and they must be coercion compatible. */ +#if !defined(DUK_USE_PREFER_SIZE) static duk_uint16_t duk__buffer_elemtype_copy_compatible[9] = { - /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT8 */ - (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) | - (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) | - (1U << DUK_HBUFFEROBJECT_ELEM_INT8), + /* xxx -> DUK_HBUFOBJ_ELEM_UINT8 */ + (1U << DUK_HBUFOBJ_ELEM_UINT8) | + (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) | + (1U << DUK_HBUFOBJ_ELEM_INT8), - /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED + /* xxx -> DUK_HBUFOBJ_ELEM_UINT8CLAMPED * Note: INT8 is -not- copy compatible, e.g. -1 would coerce to 0x00. */ - (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) | - (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED), + (1U << DUK_HBUFOBJ_ELEM_UINT8) | + (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED), - /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT8 */ - (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) | - (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) | - (1U << DUK_HBUFFEROBJECT_ELEM_INT8), + /* xxx -> DUK_HBUFOBJ_ELEM_INT8 */ + (1U << DUK_HBUFOBJ_ELEM_UINT8) | + (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) | + (1U << DUK_HBUFOBJ_ELEM_INT8), - /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT16 */ - (1U << DUK_HBUFFEROBJECT_ELEM_UINT16) | - (1U << DUK_HBUFFEROBJECT_ELEM_INT16), + /* xxx -> DUK_HBUFOBJ_ELEM_UINT16 */ + (1U << DUK_HBUFOBJ_ELEM_UINT16) | + (1U << DUK_HBUFOBJ_ELEM_INT16), - /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT16 */ - (1U << DUK_HBUFFEROBJECT_ELEM_UINT16) | - (1U << DUK_HBUFFEROBJECT_ELEM_INT16), + /* xxx -> DUK_HBUFOBJ_ELEM_INT16 */ + (1U << DUK_HBUFOBJ_ELEM_UINT16) | + (1U << DUK_HBUFOBJ_ELEM_INT16), - /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT32 */ - (1U << DUK_HBUFFEROBJECT_ELEM_UINT32) | - (1U << DUK_HBUFFEROBJECT_ELEM_INT32), + /* xxx -> DUK_HBUFOBJ_ELEM_UINT32 */ + (1U << DUK_HBUFOBJ_ELEM_UINT32) | + (1U << DUK_HBUFOBJ_ELEM_INT32), - /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT32 */ - (1U << DUK_HBUFFEROBJECT_ELEM_UINT32) | - (1U << DUK_HBUFFEROBJECT_ELEM_INT32), + /* xxx -> DUK_HBUFOBJ_ELEM_INT32 */ + (1U << DUK_HBUFOBJ_ELEM_UINT32) | + (1U << DUK_HBUFOBJ_ELEM_INT32), - /* xxx -> DUK_HBUFFEROBJECT_ELEM_FLOAT32 */ - (1U << DUK_HBUFFEROBJECT_ELEM_FLOAT32), + /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT32 */ + (1U << DUK_HBUFOBJ_ELEM_FLOAT32), - /* xxx -> DUK_HBUFFEROBJECT_ELEM_FLOAT64 */ - (1U << DUK_HBUFFEROBJECT_ELEM_FLOAT64) + /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT64 */ + (1U << DUK_HBUFOBJ_ELEM_FLOAT64) }; -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ +#endif /* !DUK_USE_PREFER_SIZE */ -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -/* Shared helper. */ -DUK_LOCAL duk_hbufferobject *duk__getrequire_bufobj_this(duk_context *ctx, duk_bool_t throw_flag) { +DUK_LOCAL duk_hbufobj *duk__hbufobj_promote_this(duk_context *ctx) { + duk_hthread *thr; + duk_tval *tv_dst; + duk_hbufobj *res; + + thr = (duk_hthread *) ctx; + duk_push_this(ctx); + DUK_ASSERT(duk_is_buffer(ctx, -1)); + res = (duk_hbufobj *) duk_to_hobject(ctx, -1); + DUK_ASSERT_HBUFOBJ_VALID(res); + DUK_DD(DUK_DDPRINT("promoted 'this' automatically to an ArrayBuffer: %!iT", duk_get_tval(ctx, -1))); + + tv_dst = duk_get_borrowed_this_tval(ctx); + DUK_TVAL_SET_OBJECT_UPDREF(thr, tv_dst, (duk_hobject *) res); + duk_pop(ctx); + + return res; +} + +#define DUK__BUFOBJ_FLAG_THROW (1 << 0) +#define DUK__BUFOBJ_FLAG_PROMOTE (1 << 1) + +/* Shared helper. When DUK__BUFOBJ_FLAG_PROMOTE is given, the return value is + * always a duk_hbufobj *. Without the flag the return value can also be a + * plain buffer, and the caller must check for it using DUK_HEAPHDR_IS_BUFFER(). + */ +DUK_LOCAL duk_heaphdr *duk__getrequire_bufobj_this(duk_context *ctx, duk_small_uint_t flags) { duk_hthread *thr; duk_tval *tv; - duk_hbufferobject *h_this; + duk_hbufobj *h_this; DUK_ASSERT(ctx != NULL); thr = (duk_hthread *) ctx; tv = duk_get_borrowed_this_tval(ctx); DUK_ASSERT(tv != NULL); + if (DUK_TVAL_IS_OBJECT(tv)) { - h_this = (duk_hbufferobject *) DUK_TVAL_GET_OBJECT(tv); + h_this = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h_this != NULL); - if (DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_this)) { - DUK_ASSERT_HBUFFEROBJECT_VALID(h_this); - return h_this; + if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_this)) { + DUK_ASSERT_HBUFOBJ_VALID(h_this); + return (duk_heaphdr *) h_this; + } + } else if (DUK_TVAL_IS_BUFFER(tv)) { + if (flags & DUK__BUFOBJ_FLAG_PROMOTE) { + /* Promote a plain buffer to a Uint8Array. This is very + * inefficient but allows plain buffer to be used wherever an + * Uint8Array is used with very small cost; hot path functions + * like index read/write calls should provide direct buffer + * support to avoid promotion. + */ + /* XXX: make this conditional to a flag if call sites need it? */ + h_this = duk__hbufobj_promote_this(ctx); + DUK_ASSERT(h_this != NULL); + DUK_ASSERT_HBUFOBJ_VALID(h_this); + return (duk_heaphdr *) h_this; + } else { + /* XXX: ugly, share return pointer for duk_hbuffer. */ + return (duk_heaphdr *) DUK_TVAL_GET_BUFFER(tv); } } - if (throw_flag) { + if (flags & DUK__BUFOBJ_FLAG_THROW) { DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER); } return NULL; } -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -/* Check that 'this' is a duk_hbufferobject and return a pointer to it. */ -DUK_LOCAL duk_hbufferobject *duk__get_bufobj_this(duk_context *ctx) { - return duk__getrequire_bufobj_this(ctx, 0); +/* Check that 'this' is a duk_hbufobj and return a pointer to it. */ +DUK_LOCAL duk_hbufobj *duk__get_bufobj_this(duk_context *ctx) { + return (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_PROMOTE); } -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -/* Check that 'this' is a duk_hbufferobject and return a pointer to it +/* Check that 'this' is a duk_hbufobj and return a pointer to it * (NULL if not). */ -DUK_LOCAL duk_hbufferobject *duk__require_bufobj_this(duk_context *ctx) { - return duk__getrequire_bufobj_this(ctx, 1); +DUK_LOCAL duk_hbufobj *duk__require_bufobj_this(duk_context *ctx) { + return (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW | DUK__BUFOBJ_FLAG_PROMOTE); } -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -/* Check that value is a duk_hbufferobject and return a pointer to it. */ -DUK_LOCAL duk_hbufferobject *duk__require_bufobj_value(duk_context *ctx, duk_idx_t index) { +/* Check that value is a duk_hbufobj and return a pointer to it. */ +DUK_LOCAL duk_hbufobj *duk__require_bufobj_value(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr; duk_tval *tv; - duk_hbufferobject *h_obj; + duk_hbufobj *h_obj; thr = (duk_hthread *) ctx; /* Don't accept relative indices now. */ - DUK_ASSERT(index >= 0); + DUK_ASSERT(idx >= 0); - tv = duk_require_tval(ctx, index); + tv = duk_require_tval(ctx, idx); DUK_ASSERT(tv != NULL); if (DUK_TVAL_IS_OBJECT(tv)) { - h_obj = (duk_hbufferobject *) DUK_TVAL_GET_OBJECT(tv); + h_obj = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h_obj != NULL); - if (DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_obj)) { - DUK_ASSERT_HBUFFEROBJECT_VALID(h_obj); + if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_obj)) { + DUK_ASSERT_HBUFOBJ_VALID(h_obj); return h_obj; } + } else if (DUK_TVAL_IS_BUFFER(tv)) { + h_obj = (duk_hbufobj *) duk_to_hobject(ctx, idx); + DUK_ASSERT(h_obj != NULL); + DUK_ASSERT_HBUFOBJ_VALID(h_obj); + return h_obj; } DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER); return NULL; /* not reachable */ } -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_LOCAL void duk__set_bufobj_buffer(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_hbuffer *h_val) { +DUK_LOCAL void duk__set_bufobj_buffer(duk_context *ctx, duk_hbufobj *h_bufobj, duk_hbuffer *h_val) { duk_hthread *thr; thr = (duk_hthread *) ctx; @@ -21785,44 +23982,41 @@ DUK_LOCAL void duk__set_bufobj_buffer(duk_context *ctx, duk_hbufferobject *h_buf DUK_ASSERT(h_bufobj != NULL); DUK_ASSERT(h_bufobj->buf == NULL); /* no need to decref */ DUK_ASSERT(h_val != NULL); - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); h_bufobj->buf = h_val; DUK_HBUFFER_INCREF(thr, h_val); h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val); DUK_ASSERT(h_bufobj->shift == 0); - DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8); + DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8); + DUK_ASSERT(h_bufobj->is_typedarray == 0); - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); } -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_LOCAL duk_hbufferobject *duk__push_arraybuffer_with_length(duk_context *ctx, duk_uint_t len) { +DUK_LOCAL duk_hbufobj *duk__push_arraybuffer_with_length(duk_context *ctx, duk_uint_t len) { duk_hbuffer *h_val; - duk_hbufferobject *h_bufobj; + duk_hbufobj *h_bufobj; - (void) duk_push_fixed_buffer(ctx, (duk_size_t) len); - h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1); - DUK_ASSERT(h_val != NULL); + (void) duk_push_fixed_buffer_zero(ctx, (duk_size_t) len); + h_val = (duk_hbuffer *) duk_known_hbuffer(ctx, -1); - h_bufobj = duk_push_bufferobject_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFFEROBJECT | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); + h_bufobj = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), + DUK_BIDX_ARRAYBUFFER_PROTOTYPE); DUK_ASSERT(h_bufobj != NULL); duk__set_bufobj_buffer(ctx, h_bufobj, h_val); - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); return h_bufobj; } -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) /* Shared offset/length coercion helper. */ DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx, - duk_hbufferobject *h_bufarg, + duk_hbufobj *h_bufarg, duk_idx_t idx_offset, duk_idx_t idx_length, duk_uint_t *out_offset, @@ -21877,29 +24071,24 @@ DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx, return; fail_range: - DUK_ERROR_RANGE(thr, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS); } -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) /* Shared lenient buffer length clamping helper. No negative indices, no * element/byte shifting. */ DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx, - duk_hbufferobject *h_bufobj, + duk_int_t buffer_length, duk_idx_t idx_start, duk_idx_t idx_end, duk_int_t *out_start_offset, duk_int_t *out_end_offset) { - duk_int_t buffer_length; duk_int_t start_offset; duk_int_t end_offset; DUK_ASSERT(out_start_offset != NULL); DUK_ASSERT(out_end_offset != NULL); - buffer_length = (duk_int_t) h_bufobj->length; - /* undefined coerces to zero which is correct */ start_offset = duk_to_int_clamped(ctx, idx_start, 0, buffer_length); if (duk_is_undefined(ctx, idx_end)) { @@ -21917,9 +24106,7 @@ DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx, *out_start_offset = start_offset; *out_end_offset = end_offset; } -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) /* Shared lenient buffer length clamping helper. Indices are treated as * element indices (though output values are byte offsets) which only * really matters for TypedArray views as other buffer object have a zero @@ -21928,20 +24115,19 @@ DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx, * against input slice. Used for e.g. ArrayBuffer slice(). */ DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx, - duk_hbufferobject *h_bufobj, + duk_int_t buffer_length, + duk_uint8_t buffer_shift, duk_idx_t idx_start, duk_idx_t idx_end, duk_int_t *out_start_offset, duk_int_t *out_end_offset) { - duk_int_t buffer_length; duk_int_t start_offset; duk_int_t end_offset; DUK_ASSERT(out_start_offset != NULL); DUK_ASSERT(out_end_offset != NULL); - buffer_length = (duk_int_t) h_bufobj->length; - buffer_length >>= h_bufobj->shift; /* as elements */ + buffer_length >>= buffer_shift; /* as (full) elements */ /* Resolve start/end offset as element indices first; arguments * at idx_start/idx_end are element offsets. Working with element @@ -21979,60 +24165,102 @@ DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx, DUK_ASSERT(start_offset <= end_offset); /* Convert indices to byte offsets. */ - start_offset <<= h_bufobj->shift; - end_offset <<= h_bufobj->shift; + start_offset <<= buffer_shift; + end_offset <<= buffer_shift; *out_start_offset = start_offset; *out_end_offset = end_offset; } -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -/* - * Indexed read/write helpers (also used from outside this file) - */ +DUK_INTERNAL void duk_hbufobj_promote_plain(duk_context *ctx, duk_idx_t idx) { + if (duk_is_buffer(ctx, idx)) { + duk_to_object(ctx, idx); + } +} + +DUK_INTERNAL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf) { + duk_context *ctx; + + ctx = (duk_context *) thr; + + /* Push Uint8Array which will share the same underlying buffer as + * the plain buffer argument. Also create an ArrayBuffer with the + * same backing for the result .buffer property. + */ + + duk_push_hbuffer(ctx, h_buf); + duk_push_buffer_object(ctx, -1, 0, (duk_size_t) DUK_HBUFFER_GET_SIZE(h_buf), DUK_BUFOBJ_UINT8ARRAY); + duk_remove_m2(ctx); + +#if 0 + /* More verbose equivalent; maybe useful if e.g. .buffer is omitted. */ + h_bufobj = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY), + DUK_BIDX_UINT8ARRAY_PROTOTYPE); + DUK_ASSERT(h_bufobj != NULL); + duk__set_bufobj_buffer(ctx, h_bufobj, h_buf); + h_bufobj->is_typedarray = 1; + DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); + + h_arrbuf = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), + DUK_BIDX_ARRAYBUFFER_PROTOTYPE); + DUK_ASSERT(h_arrbuf != NULL); + duk__set_bufobj_buffer(ctx, h_arrbuf, h_buf); + DUK_ASSERT(h_arrbuf->is_typedarray == 0); + DUK_ASSERT_HBUFOBJ_VALID(h_arrbuf); + + DUK_ASSERT(h_bufobj->buf_prop == NULL); + h_bufobj->buf_prop = (duk_hobject *) h_arrbuf; + DUK_ASSERT(h_arrbuf != NULL); + DUK_HBUFOBJ_INCREF(thr, h_arrbuf); + duk_pop(ctx); +#endif +} -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) { +/* Indexed read helper for buffer objects, also called from outside this file. */ +DUK_INTERNAL void duk_hbufobj_push_validated_read(duk_context *ctx, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) { duk_double_union du; DUK_MEMCPY((void *) du.uc, (const void *) p, (size_t) elem_size); switch (h_bufobj->elem_type) { - case DUK_HBUFFEROBJECT_ELEM_UINT8: -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - case DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED: -#endif + case DUK_HBUFOBJ_ELEM_UINT8: + case DUK_HBUFOBJ_ELEM_UINT8CLAMPED: duk_push_uint(ctx, (duk_uint_t) du.uc[0]); break; -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - /* These are not needed when only Duktape.Buffer is supported. */ - case DUK_HBUFFEROBJECT_ELEM_INT8: + case DUK_HBUFOBJ_ELEM_INT8: duk_push_int(ctx, (duk_int_t) (duk_int8_t) du.uc[0]); break; - case DUK_HBUFFEROBJECT_ELEM_UINT16: + case DUK_HBUFOBJ_ELEM_UINT16: duk_push_uint(ctx, (duk_uint_t) du.us[0]); break; - case DUK_HBUFFEROBJECT_ELEM_INT16: + case DUK_HBUFOBJ_ELEM_INT16: duk_push_int(ctx, (duk_int_t) (duk_int16_t) du.us[0]); break; - case DUK_HBUFFEROBJECT_ELEM_UINT32: + case DUK_HBUFOBJ_ELEM_UINT32: duk_push_uint(ctx, (duk_uint_t) du.ui[0]); break; - case DUK_HBUFFEROBJECT_ELEM_INT32: + case DUK_HBUFOBJ_ELEM_INT32: duk_push_int(ctx, (duk_int_t) (duk_int32_t) du.ui[0]); break; - case DUK_HBUFFEROBJECT_ELEM_FLOAT32: + case DUK_HBUFOBJ_ELEM_FLOAT32: duk_push_number(ctx, (duk_double_t) du.f[0]); break; - case DUK_HBUFFEROBJECT_ELEM_FLOAT64: + case DUK_HBUFOBJ_ELEM_FLOAT64: duk_push_number(ctx, (duk_double_t) du.d); break; -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ default: DUK_UNREACHABLE(); } } -DUK_INTERNAL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) { +/* Indexed write helper for buffer objects, also called from outside this file. */ +DUK_INTERNAL void duk_hbufobj_validated_write(duk_context *ctx, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) { duk_double_union du; /* NOTE! Caller must ensure that any side effects from the @@ -22044,36 +24272,33 @@ DUK_INTERNAL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbuffe */ switch (h_bufobj->elem_type) { - case DUK_HBUFFEROBJECT_ELEM_UINT8: + case DUK_HBUFOBJ_ELEM_UINT8: du.uc[0] = (duk_uint8_t) duk_to_uint32(ctx, -1); break; -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - /* These are not needed when only Duktape.Buffer is supported. */ - case DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED: + case DUK_HBUFOBJ_ELEM_UINT8CLAMPED: du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(ctx, -1); break; - case DUK_HBUFFEROBJECT_ELEM_INT8: + case DUK_HBUFOBJ_ELEM_INT8: du.uc[0] = (duk_uint8_t) duk_to_int32(ctx, -1); break; - case DUK_HBUFFEROBJECT_ELEM_UINT16: + case DUK_HBUFOBJ_ELEM_UINT16: du.us[0] = (duk_uint16_t) duk_to_uint32(ctx, -1); break; - case DUK_HBUFFEROBJECT_ELEM_INT16: + case DUK_HBUFOBJ_ELEM_INT16: du.us[0] = (duk_uint16_t) duk_to_int32(ctx, -1); break; - case DUK_HBUFFEROBJECT_ELEM_UINT32: + case DUK_HBUFOBJ_ELEM_UINT32: du.ui[0] = (duk_uint32_t) duk_to_uint32(ctx, -1); break; - case DUK_HBUFFEROBJECT_ELEM_INT32: + case DUK_HBUFOBJ_ELEM_INT32: du.ui[0] = (duk_uint32_t) duk_to_int32(ctx, -1); break; - case DUK_HBUFFEROBJECT_ELEM_FLOAT32: - du.f[0] = (duk_float_t) duk_to_number(ctx, -1); + case DUK_HBUFOBJ_ELEM_FLOAT32: + du.f[0] = (duk_float_t) duk_to_number_m1(ctx); break; - case DUK_HBUFFEROBJECT_ELEM_FLOAT64: - du.d = (duk_double_t) duk_to_number(ctx, -1); + case DUK_HBUFOBJ_ELEM_FLOAT64: + du.d = (duk_double_t) duk_to_number_m1(ctx); break; -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ default: DUK_UNREACHABLE(); } @@ -22081,187 +24306,110 @@ DUK_INTERNAL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbuffe DUK_MEMCPY((void *) p, (const void *) du.uc, (size_t) elem_size); } -/* - * Duktape.Buffer: constructor +/* Helper to create a fixed buffer from argument value at index 0. + * Node.js and allocPlain() compatible. */ - -DUK_INTERNAL duk_ret_t duk_bi_buffer_constructor(duk_context *ctx) { - duk_hthread *thr; +DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_context *ctx) { + duk_int_t len; + duk_int_t i; duk_size_t buf_size; - duk_small_int_t buf_dynamic; - duk_uint8_t *buf_data; - const duk_uint8_t *src_data; - - thr = (duk_hthread *) ctx; - DUK_UNREF(thr); - - /* - * Constructor arguments are currently somewhat compatible with - * (keep it that way if possible): - * - * http://nodejs.org/api/buffer.html - * - * Note that the ToBuffer() coercion (duk_to_buffer()) does NOT match - * the constructor behavior. - */ - - buf_dynamic = duk_get_boolean(ctx, 1); /* default to false */ + duk_uint8_t *buf; switch (duk_get_type(ctx, 0)) { case DUK_TYPE_NUMBER: { - /* new buffer of specified size */ - buf_size = (duk_size_t) duk_to_int(ctx, 0); - (void) duk_push_buffer(ctx, buf_size, buf_dynamic); - break; - } - case DUK_TYPE_BUFFER: { - /* return input buffer, converted to a Duktape.Buffer object - * if called as a constructor (no change if called as a - * function). - */ - duk_set_top(ctx, 1); + len = duk_to_int_clamped(ctx, 0, 0, DUK_INT_MAX); + (void) duk_push_fixed_buffer_zero(ctx, (duk_size_t) len); break; } - case DUK_TYPE_STRING: { - /* new buffer with string contents */ - src_data = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &buf_size); - DUK_ASSERT(src_data != NULL); /* even for zero-length string */ - buf_data = (duk_uint8_t *) duk_push_buffer(ctx, buf_size, buf_dynamic); - DUK_MEMCPY((void *) buf_data, (const void *) src_data, (size_t) buf_size); - break; + case DUK_TYPE_BUFFER: { /* Treat like Uint8Array. */ + goto slow_copy; } case DUK_TYPE_OBJECT: { - /* For all duk_hbufferobjects, get the plain buffer inside - * without making a copy. This is compatible with Duktape 1.2 - * but means that a slice/view information is ignored and the - * full underlying buffer is returned. - * - * If called as a constructor, a new Duktape.Buffer object - * pointing to the same plain buffer is created below. + duk_hobject *h; + duk_hbufobj *h_bufobj; + + /* For Node.js Buffers "Passing an ArrayBuffer returns a Buffer + * that shares allocated memory with the given ArrayBuffer." + * https://nodejs.org/api/buffer.html#buffer_buffer_from_buffer_alloc_and_buffer_allocunsafe */ - duk_hbufferobject *h_bufobj; - h_bufobj = (duk_hbufferobject *) duk_get_hobject(ctx, 0); - DUK_ASSERT(h_bufobj != NULL); - if (!DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_bufobj)) { - return DUK_RET_TYPE_ERROR; - } - if (h_bufobj->buf == NULL) { - return DUK_RET_TYPE_ERROR; + + h = duk_known_hobject(ctx, 0); + if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAYBUFFER) { + DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(h)); + h_bufobj = (duk_hbufobj *) h; + if (DUK_UNLIKELY(h_bufobj->buf == NULL)) { + DUK_ERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); + } + if (DUK_UNLIKELY(h_bufobj->offset != 0 || h_bufobj->length != DUK_HBUFFER_GET_SIZE(h_bufobj->buf))) { + /* No support for ArrayBuffers with slice + * offset/length. + */ + DUK_ERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); + } + duk_push_hbuffer(ctx, h_bufobj->buf); + return h_bufobj->buf; } - duk_push_hbuffer(ctx, h_bufobj->buf); - break; + goto slow_copy; } - case DUK_TYPE_NONE: - default: { - return DUK_RET_TYPE_ERROR; + case DUK_TYPE_STRING: { + /* ignore encoding for now */ + duk_require_hstring_notsymbol(ctx, 0); + duk_dup_0(ctx); + (void) duk_to_buffer(ctx, -1, &buf_size); + break; } + default: + DUK_ERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); } - DUK_ASSERT(duk_is_buffer(ctx, -1)); - - /* stack is unbalanced, but: [ buf ] */ - - if (duk_is_constructor_call(ctx)) { - duk_hbufferobject *h_bufobj; - duk_hbuffer *h_val; - - h_val = duk_get_hbuffer(ctx, -1); - DUK_ASSERT(h_val != NULL); - h_bufobj = duk_push_bufferobject_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFFEROBJECT | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER), - DUK_BIDX_BUFFER_PROTOTYPE); - DUK_ASSERT(h_bufobj != NULL); + done: + DUK_ASSERT(duk_is_buffer(ctx, -1)); + return duk_known_hbuffer(ctx, -1); - duk__set_bufobj_buffer(ctx, h_bufobj, h_val); + slow_copy: + /* XXX: fast path for typed arrays and other buffer objects? */ - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + (void) duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_LENGTH); + len = duk_to_int_clamped(ctx, -1, 0, DUK_INT_MAX); + duk_pop(ctx); + buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, (duk_size_t) len); /* no zeroing, all indices get initialized */ + for (i = 0; i < len; i++) { + /* XXX: fast path for array or buffer arguments? */ + duk_get_prop_index(ctx, 0, (duk_uarridx_t) i); + buf[i] = (duk_uint8_t) (duk_to_uint32(ctx, -1) & 0xffU); + duk_pop(ctx); } - /* Note: unbalanced stack on purpose */ - - return 1; + goto done; } +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* - * Node.js Buffer: constructor + * Node.js Buffer constructor + * + * Node.js Buffers are just Uint8Arrays with internal prototype set to + * Buffer.prototype so they're handled otherwise the same as Uint8Array. + * However, the constructor arguments are very different so a separate + * constructor entry point is used. */ - #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) { - /* Internal class is Object: Object.prototype.toString.call(new Buffer(0)) - * prints "[object Object]". - */ - duk_int_t len; - duk_int_t i; duk_hbuffer *h_buf; - duk_hbufferobject *h_bufobj; - duk_size_t buf_size; - - switch (duk_get_type(ctx, 0)) { - case DUK_TYPE_BUFFER: { - /* Custom behavior: plain buffer is used as internal buffer - * without making a copy (matches Duktape.Buffer). - */ - duk_set_top(ctx, 1); /* -> [ buffer ] */ - break; - } - case DUK_TYPE_NUMBER: { - len = duk_to_int_clamped(ctx, 0, 0, DUK_INT_MAX); - (void) duk_push_fixed_buffer(ctx, (duk_size_t) len); - break; - } - case DUK_TYPE_OBJECT: { - duk_uint8_t *buf; - - (void) duk_get_prop_string(ctx, 0, "length"); - len = duk_to_int_clamped(ctx, -1, 0, DUK_INT_MAX); - duk_pop(ctx); - buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len); - for (i = 0; i < len; i++) { - /* XXX: fast path for array arguments? */ - duk_get_prop_index(ctx, 0, (duk_uarridx_t) i); - buf[i] = (duk_uint8_t) (duk_to_uint32(ctx, -1) & 0xffU); - duk_pop(ctx); - } - break; - } - case DUK_TYPE_STRING: { - /* ignore encoding for now */ - duk_dup(ctx, 0); - (void) duk_to_buffer(ctx, -1, &buf_size); - break; - } - default: - return DUK_RET_TYPE_ERROR; - } - DUK_ASSERT(duk_is_buffer(ctx, -1)); - h_buf = duk_get_hbuffer(ctx, -1); + h_buf = duk__hbufobj_fixed_from_argvalue(ctx); DUK_ASSERT(h_buf != NULL); - h_bufobj = duk_push_bufferobject_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFFEROBJECT | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER), - DUK_BIDX_NODEJS_BUFFER_PROTOTYPE); - DUK_ASSERT(h_bufobj != NULL); + duk_push_buffer_object(ctx, + -1, + 0, + DUK_HBUFFER_FIXED_GET_SIZE((duk_hbuffer_fixed *) h_buf), + DUK_BUFOBJ_UINT8ARRAY); + duk_push_hobject_bidx(ctx, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE); + duk_set_prototype(ctx, -2); - h_bufobj->buf = h_buf; - DUK_HBUFFER_INCREF(thr, h_buf); - DUK_ASSERT(h_bufobj->offset == 0); - h_bufobj->length = (duk_int_t) DUK_HBUFFER_GET_SIZE(h_buf); - DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8); - - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + /* XXX: a more direct implementation */ return 1; } -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* @@ -22271,72 +24419,46 @@ 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_hbufobj *h_bufobj; duk_hbuffer *h_val; + duk_int_t len; 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; - } - - if (duk_is_buffer(ctx, 0)) { - /* Custom behavior: plain buffer is used as internal buffer - * without making a copy (matches Duktape.Buffer). - */ - - h_val = duk_get_hbuffer(ctx, 0); - DUK_ASSERT(h_val != NULL); - - /* XXX: accept any duk_hbufferobject type as an input also? */ - } else { - duk_int_t len; - len = duk_to_int(ctx, 0); - if (len < 0) { - goto fail_length; - } - (void) duk_push_fixed_buffer(ctx, (duk_size_t) len); - h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1); - DUK_ASSERT(h_val != NULL); + duk_require_constructor_call(ctx); -#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 + len = duk_to_int(ctx, 0); + if (len < 0) { + goto fail_length; } + (void) duk_push_fixed_buffer_zero(ctx, (duk_size_t) len); + h_val = (duk_hbuffer *) duk_known_hbuffer(ctx, -1); - h_bufobj = duk_push_bufferobject_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFFEROBJECT | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); + h_bufobj = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), + DUK_BIDX_ARRAYBUFFER_PROTOTYPE); DUK_ASSERT(h_bufobj != NULL); duk__set_bufobj_buffer(ctx, h_bufobj, h_val); - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); return 1; fail_length: - return DUK_RET_RANGE_ERROR; -} -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; + DUK_DCERROR_RANGE_INVALID_LENGTH(thr); } #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* Format of magic, bits: * 0...1: elem size shift (0-3) - * 2...5: elem type (DUK_HBUFFEROBJECT_ELEM_xxx) + * 2...5: elem type (DUK_HBUFOBJ_ELEM_xxx) + * + * XXX: add prototype bidx explicitly to magic instead of using a mapping? */ #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) @@ -22344,9 +24466,9 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { duk_hthread *thr; duk_tval *tv; duk_hobject *h_obj; - duk_hbufferobject *h_bufobj = NULL; - duk_hbufferobject *h_bufarr = NULL; - duk_hbufferobject *h_bufarg = NULL; + duk_hbufobj *h_bufobj = NULL; + duk_hbufobj *h_bufarr = NULL; + duk_hbufobj *h_bufarg = NULL; duk_hbuffer *h_val; duk_small_uint_t magic; duk_small_uint_t shift; @@ -22363,10 +24485,11 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *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; - } + /* XXX: The same copy helpers could be shared with at least some + * buffer functions. + */ + + duk_require_constructor_call(ctx); /* We could fit built-in index into magic but that'd make the magic * number dependent on built-in numbering (genbuiltins.py doesn't @@ -22394,6 +24517,12 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { * created. */ + /* XXX: initial iteration to treat a plain buffer like an ArrayBuffer: + * coerce to an ArrayBuffer object and use that as .buffer. The underlying + * buffer will be the same but result .buffer !== inputPlainBuffer. + */ + duk_hbufobj_promote_plain(ctx, 0); + tv = duk_get_tval(ctx, 0); DUK_ASSERT(tv != NULL); /* arg count */ if (DUK_TVAL_IS_OBJECT(tv)) { @@ -22408,7 +24537,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { duk_int_t byte_offset_signed; duk_uint_t byte_offset; - h_bufarg = (duk_hbufferobject *) h_obj; + h_bufarg = (duk_hbufobj *) h_obj; byte_offset_signed = duk_to_int(ctx, 1); if (byte_offset_signed < 0) { @@ -22455,14 +24584,14 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { DUK_ASSERT(byte_offset + byte_length <= h_bufarg->length); DUK_ASSERT((elem_length << shift) == byte_length); - h_bufobj = duk_push_bufferobject_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFFEROBJECT | - DUK_HOBJECT_CLASS_AS_FLAGS(class_num), - proto_bidx); + h_bufobj = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(class_num), + proto_bidx); h_val = h_bufarg->buf; if (h_val == NULL) { - return DUK_RET_TYPE_ERROR; + DUK_DCERROR_TYPE_INVALID_ARGS(thr); } h_bufobj->buf = h_val; DUK_HBUFFER_INCREF(thr, h_val); @@ -22470,25 +24599,26 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { h_bufobj->length = byte_length; h_bufobj->shift = (duk_uint8_t) shift; h_bufobj->elem_type = (duk_uint8_t) elem_type; - h_bufobj->is_view = 1; - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + h_bufobj->is_typedarray = 1; + DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); /* Set .buffer to the argument ArrayBuffer. */ - duk_dup(ctx, 0); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE); - duk_compact(ctx, -1); + DUK_ASSERT(h_bufobj->buf_prop == NULL); + h_bufobj->buf_prop = (duk_hobject *) h_bufarg; + DUK_ASSERT(h_bufarg != NULL); + DUK_HBUFOBJ_INCREF(thr, h_bufarg); return 1; - } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) { - /* TypedArray (or other non-ArrayBuffer duk_hbufferobject). + } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { + /* TypedArray (or other non-ArrayBuffer duk_hbufobj). * Conceptually same behavior as for an Array-like argument, * with a few fast paths. */ - h_bufarg = (duk_hbufferobject *) h_obj; - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufarg); + h_bufarg = (duk_hbufobj *) h_obj; + DUK_ASSERT_HBUFOBJ_VALID(h_bufarg); elem_length_signed = (duk_int_t) (h_bufarg->length >> h_bufarg->shift); if (h_bufarg->buf == NULL) { - return DUK_RET_TYPE_ERROR; + DUK_DCERROR_TYPE_INVALID_ARGS(thr); } /* Select copy mode. Must take into account element @@ -22505,8 +24635,12 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { (long) (elem_length_signed << shift))); copy_mode = 2; /* default is explicit index read/write copy */ +#if !defined(DUK_USE_PREFER_SIZE) + /* With a size optimized build copy_mode 2 is enough. + * Modes 0 and 1 are faster but conceptually the same. + */ DUK_ASSERT(elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t)); - if (DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)) { + if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) { if ((duk__buffer_elemtype_copy_compatible[elem_type] & (1 << h_bufarg->elem_type)) != 0) { DUK_DDD(DUK_DDDPRINT("source/target are copy compatible, memcpy")); DUK_ASSERT(shift == h_bufarg->shift); /* byte sizes will match */ @@ -22516,19 +24650,12 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { copy_mode = 1; } } +#endif /* !DUK_USE_PREFER_SIZE */ } else { /* Array or Array-like */ 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 @@ -22562,11 +24689,11 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { DUK_ASSERT(h_val != NULL); /* Push the resulting view object and attach the ArrayBuffer. */ - h_bufobj = duk_push_bufferobject_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFFEROBJECT | - DUK_HOBJECT_CLASS_AS_FLAGS(class_num), - proto_bidx); + h_bufobj = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(class_num), + proto_bidx); h_bufobj->buf = h_val; DUK_HBUFFER_INCREF(thr, h_val); @@ -22574,13 +24701,14 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { h_bufobj->length = byte_length; h_bufobj->shift = (duk_uint8_t) shift; h_bufobj->elem_type = (duk_uint8_t) elem_type; - h_bufobj->is_view = 1; - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + h_bufobj->is_typedarray = 1; + DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); /* Set .buffer */ - duk_dup(ctx, -2); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE); - duk_compact(ctx, -1); + DUK_ASSERT(h_bufobj->buf_prop == NULL); + h_bufobj->buf_prop = (duk_hobject *) h_bufarr; + DUK_ASSERT(h_bufarr != NULL); + DUK_HBUFOBJ_INCREF(thr, h_bufarr); /* Copy values, the copy method depends on the arguments. * @@ -22590,6 +24718,10 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { */ DUK_DDD(DUK_DDDPRINT("copy mode: %d", (int) copy_mode)); switch (copy_mode) { + /* Copy modes 0 and 1 can be omitted in size optimized build, + * copy mode 2 handles them (but more slowly). + */ +#if !defined(DUK_USE_PREFER_SIZE) case 0: { /* Use byte copy. */ @@ -22598,13 +24730,13 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { DUK_ASSERT(h_bufobj != NULL); DUK_ASSERT(h_bufobj->buf != NULL); - DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)); + DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj)); DUK_ASSERT(h_bufarg != NULL); DUK_ASSERT(h_bufarg->buf != NULL); - DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)); + DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg)); - p_dst = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj); - p_src = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg); + p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj); + p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg); DUK_DDD(DUK_DDDPRINT("using memcpy: p_src=%p, p_dst=%p, byte_length=%ld", (void *) p_src, (void *) p_dst, (long) byte_length)); @@ -22623,16 +24755,16 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { DUK_ASSERT(h_bufobj != NULL); DUK_ASSERT(h_bufobj->buf != NULL); - DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)); + DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj)); DUK_ASSERT(h_bufarg != NULL); DUK_ASSERT(h_bufarg->buf != NULL); - DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)); + DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg)); src_elem_size = 1 << h_bufarg->shift; dst_elem_size = elem_size; - p_src = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg); - p_dst = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj); + p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg); + p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj); p_src_end = p_src + h_bufarg->length; DUK_DDD(DUK_DDDPRINT("using fast copy: p_src=%p, p_src_end=%p, p_dst=%p, " @@ -22647,14 +24779,15 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { /* A validated read() is always a number, so it's write coercion * is always side effect free an won't invalidate pointers etc. */ - duk_hbufferobject_push_validated_read(ctx, h_bufarg, p_src, src_elem_size); - duk_hbufferobject_validated_write(ctx, h_bufobj, p_dst, dst_elem_size); + duk_hbufobj_push_validated_read(ctx, h_bufarg, p_src, src_elem_size); + duk_hbufobj_validated_write(ctx, h_bufobj, p_dst, dst_elem_size); duk_pop(ctx); p_src += src_elem_size; p_dst += dst_elem_size; } break; } +#endif /* !DUK_USE_PREFER_SIZE */ case 2: { /* Copy values by index reads and writes. Let virtual * property handling take care of coercion. @@ -22675,13 +24808,6 @@ 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; @@ -22691,76 +24817,84 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { return 1; fail_arguments: - return DUK_RET_RANGE_ERROR; + DUK_DCERROR_RANGE_INVALID_ARGS(thr); } #else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +/* When bufferobject support is disabled, new Uint8Array() could still be + * supported to create a plain fixed buffer. Disabled for now. + */ +#if 0 DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; + duk_int_t elem_length_signed; + duk_uint_t byte_length; + + /* XXX: The same copy helpers could be shared with at least some + * buffer functions. + */ + + duk_require_constructor_call(ctx); + + elem_length_signed = duk_require_int(ctx, 0); + if (elem_length_signed < 0) { + goto fail_arguments; + } + byte_length = (duk_uint_t) elem_length_signed; + + (void) duk_push_fixed_buffer_zero(ctx, (duk_size_t) byte_length); + return 1; + + fail_arguments: + DUK_DCERROR_RANGE_INVALID_ARGS((duk_hthread *) ctx); } +#endif /* 0 */ #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) { - duk_hbufferobject *h_bufarg; - duk_hbufferobject *h_bufobj; + duk_hbufobj *h_bufarg; + duk_hbufobj *h_bufobj; duk_hbuffer *h_val; duk_uint_t offset; duk_uint_t length; - /* XXX: function flag to make this automatic? */ - if (!duk_is_constructor_call(ctx)) { - return DUK_RET_TYPE_ERROR; - } + duk_require_constructor_call(ctx); h_bufarg = duk__require_bufobj_value(ctx, 0); DUK_ASSERT(h_bufarg != NULL); + if (DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufarg) != DUK_HOBJECT_CLASS_ARRAYBUFFER) { + DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); + } duk__resolve_offset_opt_length(ctx, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/); DUK_ASSERT(offset <= h_bufarg->length); DUK_ASSERT(offset + length <= h_bufarg->length); - h_bufobj = duk_push_bufferobject_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFFEROBJECT | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW), - DUK_BIDX_DATAVIEW_PROTOTYPE); + h_bufobj = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW), + DUK_BIDX_DATAVIEW_PROTOTYPE); h_val = h_bufarg->buf; if (h_val == NULL) { - return DUK_RET_TYPE_ERROR; + DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); } h_bufobj->buf = h_val; DUK_HBUFFER_INCREF(thr, h_val); h_bufobj->offset = h_bufarg->offset + offset; h_bufobj->length = length; DUK_ASSERT(h_bufobj->shift == 0); - DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8); - h_bufobj->is_view = 1; - - /* The DataView .buffer property is ordinarily set to the argument - * which is an ArrayBuffer. We accept any duk_hbufferobject as - * an argument and .buffer will be set to the argument regardless - * of what it is. This may be a bit confusing if the argument - * is e.g. a DataView or another TypedArray view. - * - * XXX: Copy .buffer property from a DataView/TypedArray argument? - * Create a fresh ArrayBuffer for Duktape.Buffer and Node.js Buffer - * arguments? See: test-bug-dataview-buffer-prop.js. - */ + DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8); + DUK_ASSERT(h_bufobj->is_typedarray == 0); - duk_dup(ctx, 0); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE); - duk_compact(ctx, -1); + DUK_ASSERT(h_bufobj->buf_prop == NULL); + h_bufobj->buf_prop = (duk_hobject *) h_bufarg; + DUK_ASSERT(h_bufarg != NULL); + DUK_HBUFOBJ_INCREF((duk_hthread *) ctx, h_bufarg); - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); return 1; } -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* @@ -22772,17 +24906,60 @@ DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) { duk_hobject *h_obj; duk_bool_t ret = 0; - h_obj = duk_get_hobject(ctx, 0); - if (h_obj != NULL && DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) { - ret = ((duk_hbufferobject *) h_obj)->is_view; + if (duk_is_buffer(ctx, 0)) { + ret = 1; + } else { + h_obj = duk_get_hobject(ctx, 0); + if (h_obj != NULL && DUK_HOBJECT_IS_BUFOBJ(h_obj)) { + /* DataView needs special casing: ArrayBuffer.isView() is + * true, but ->is_typedarray is 0. + */ + ret = ((duk_hbufobj *) h_obj)->is_typedarray || + (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_DATAVIEW); + } } duk_push_boolean(ctx, ret); return 1; } -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Uint8Array.allocPlain() + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_uint8array_allocplain(duk_context *ctx) { + duk__hbufobj_fixed_from_argvalue(ctx); + return 1; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Uint8Array.plainOf() + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_uint8array_plainof(duk_context *ctx) { + duk_hbufobj *h_bufobj; + +#if !defined(DUK_USE_PREFER_SIZE) + /* Avoid churn if argument is already a plain buffer. */ + if (duk_is_buffer(ctx, 0)) { + return 1; + } +#endif + + /* Promotes plain buffers to ArrayBuffers, so for a plain buffer + * argument we'll create a pointless temporary (but still work + * correctly). + */ + h_bufobj = duk__require_bufobj_value(ctx, 0); + if (h_bufobj->buf == NULL) { + duk_push_undefined(ctx); + } else { + duk_push_hbuffer(ctx, h_bufobj->buf); + } + return 1; } #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ @@ -22793,7 +24970,7 @@ DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) { #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) { duk_hthread *thr; - duk_hbufferobject *h_this; + duk_hbufobj *h_this; duk_int_t start_offset, end_offset; duk_uint8_t *buf_slice; duk_size_t slice_length; @@ -22807,100 +24984,45 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) { duk_push_string(ctx, "[object Object]"); return 1; } - DUK_ASSERT_HBUFFEROBJECT_VALID(h_this); + DUK_ASSERT_HBUFOBJ_VALID(h_this); - /* ignore encoding for now */ + /* Ignore encoding for now. */ - duk__clamp_startend_nonegidx_noshift(ctx, h_this, 1 /*idx_start*/, 2 /*idx_end*/, &start_offset, &end_offset); + duk__clamp_startend_nonegidx_noshift(ctx, + (duk_int_t) h_this->length, + 1 /*idx_start*/, + 2 /*idx_end*/, + &start_offset, + &end_offset); slice_length = (duk_size_t) (end_offset - start_offset); - buf_slice = (duk_uint8_t *) duk_push_fixed_buffer(ctx, slice_length); + buf_slice = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, slice_length); /* all bytes initialized below */ DUK_ASSERT(buf_slice != NULL); - if (h_this->buf == NULL) { - goto type_error; + /* Neutered or uncovered, TypeError. */ + if (h_this->buf == NULL || + !DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, start_offset + slice_length)) { + DUK_DCERROR_TYPE_INVALID_ARGS(thr); } - 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), - (size_t) slice_length); - } else { - /* not covered, return all zeroes */ - ; - } - - duk_to_string(ctx, -1); - return 1; - - type_error: - return DUK_RET_TYPE_ERROR; -} -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} -#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ - -/* - * Duktape.Buffer: toString(), valueOf() - */ - -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) { - duk_hthread *thr; - duk_tval *tv; - duk_small_int_t to_string = duk_get_current_magic(ctx); - - thr = (duk_hthread *) ctx; - DUK_UNREF(thr); - - tv = duk_get_borrowed_this_tval(ctx); - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_IS_BUFFER(tv)) { - duk_hbuffer *h_buf; - h_buf = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h_buf != NULL); - duk_push_hbuffer(ctx, h_buf); - } else if (DUK_TVAL_IS_OBJECT(tv)) { - duk_hobject *h; - duk_hbufferobject *h_bufobj; - - /* Accept any duk_hbufferobject, though we're only normally - * called for Duktape.Buffer values. - */ - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - if (!DUK_HOBJECT_IS_BUFFEROBJECT(h)) { - DUK_DD(DUK_DDPRINT("toString/valueOf() called for a non-bufferobject object")); - goto type_error; - } - h_bufobj = (duk_hbufferobject *) h; - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); - - if (h_bufobj->buf == NULL) { - DUK_DD(DUK_DDPRINT("toString/valueOf() called for a bufferobject with NULL buf")); - goto type_error; - } - duk_push_hbuffer(ctx, h_bufobj->buf); - } else { - goto type_error; - } + /* XXX: ideally we wouldn't make a copy but a view into the buffer for the + * decoding process. Or the decoding helper could be changed to accept + * the slice info (a buffer pointer is NOT a good approach because guaranteeing + * its stability is difficult). + */ - if (to_string) { - duk_to_string(ctx, -1); - } - return 1; + DUK_ASSERT(DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, start_offset + slice_length)); + DUK_MEMCPY((void *) buf_slice, + (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset), + (size_t) slice_length); - type_error: - return DUK_RET_TYPE_ERROR; -} -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; + /* Use the equivalent of: new TextEncoder().encode(this) to convert the + * string. Result will be valid UTF-8; non-CESU-8 inputs are currently + * interpreted loosely. Value stack convention is a bit odd for now. + */ + duk_replace(ctx, 0); + duk_set_top(ctx, 1); + return duk_textdecoder_decode_utf8_nodejs(ctx); } #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ @@ -22911,16 +25033,19 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) { duk_hthread *thr; - duk_hbufferobject *h_this; + duk_hbufobj *h_this; + duk_harray *h_arr; duk_uint8_t *buf; - duk_uint_t i; + duk_uint_t i, n; + duk_tval *tv; thr = (duk_hthread *) ctx; DUK_UNREF(thr); + h_this = duk__require_bufobj_this(ctx); DUK_ASSERT(h_this != NULL); - if (h_this->buf == NULL || !DUK_HBUFFEROBJECT_VALID_SLICE(h_this)) { + if (h_this->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_this)) { /* Serialize uncovered backing buffer as a null; doesn't * really matter as long we're memory safe. */ @@ -22930,27 +25055,23 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) { duk_push_object(ctx); duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_BUFFER); - duk_put_prop_stridx(ctx, -2, DUK_STRIDX_TYPE); + duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_TYPE); - duk_push_array(ctx); - for (i = 0; i < h_this->length; i++) { - /* XXX: regetting the pointer may be overkill - we're writing - * to a side-effect free array here. - */ - DUK_ASSERT(h_this->buf != NULL); - buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this); - duk_push_uint(ctx, (duk_uint_t) buf[i]); - duk_put_prop_index(ctx, -2, (duk_idx_t) i); + DUK_ASSERT_DISABLE((duk_size_t) h_this->length <= (duk_size_t) DUK_UINT32_MAX); + h_arr = duk_push_harray_with_size(ctx, (duk_uint32_t) h_this->length); /* XXX: needs revision with >4G buffers */ + DUK_ASSERT(h_arr != NULL); + DUK_ASSERT(h_arr->length == h_this->length); + tv = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr); + + DUK_ASSERT(h_this->buf != NULL); + buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this); + for (i = 0, n = h_this->length; i < n; i++) { + DUK_TVAL_SET_U32(tv + i, (duk_uint32_t) buf[i]); /* no need for decref or incref */ } - duk_put_prop_stridx(ctx, -2, DUK_STRIDX_DATA); + duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_DATA); return 1; } -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* @@ -22963,13 +25084,15 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) { DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) { duk_hthread *thr; duk_small_uint_t magic; - duk_hbufferobject *h_bufarg1; - duk_hbufferobject *h_bufarg2; + duk_hbufobj *h_bufarg1; + duk_hbufobj *h_bufarg2; duk_small_int_t comp_res; thr = (duk_hthread *) ctx; DUK_UNREF(thr); + /* XXX: keep support for plain buffers and non-Node.js buffers? */ + magic = duk_get_current_magic(ctx); if (magic & 0x02) { /* Static call style. */ @@ -22988,8 +25111,8 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) { * matters is to be memory safe. */ - if (DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg1) && - DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg2)) { + if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg1) && + DUK_HBUFOBJ_VALID_SLICE(h_bufarg2)) { comp_res = duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg1->buf) + h_bufarg1->offset, (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg2->buf) + h_bufarg2->offset, (duk_size_t) h_bufarg1->length, @@ -23008,11 +25131,6 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) { return 1; } -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* @@ -23022,7 +25140,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) { #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) { duk_hthread *thr; - duk_hbufferobject *h_this; + duk_hbufobj *h_this; const duk_uint8_t *fill_str_ptr; duk_size_t fill_str_len; duk_uint8_t fill_value; @@ -23037,15 +25155,16 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) { h_this = duk__require_bufobj_this(ctx); DUK_ASSERT(h_this != NULL); if (h_this->buf == NULL) { - return DUK_RET_TYPE_ERROR; + DUK_DCERROR_TYPE_INVALID_ARGS(thr); } /* [ value offset end ] */ - if (duk_is_string(ctx, 0)) { + if (duk_is_string_notsymbol(ctx, 0)) { fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &fill_str_len); DUK_ASSERT(fill_str_ptr != NULL); } else { + /* Symbols get ToNumber() coerced and cause TypeError. */ fill_value = (duk_uint8_t) duk_to_uint32(ctx, 0); fill_str_ptr = (const duk_uint8_t *) &fill_value; fill_str_len = 1; @@ -23053,7 +25172,12 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) { /* Fill offset handling is more lenient than in Node.js. */ - duk__clamp_startend_nonegidx_noshift(ctx, h_this, 1 /*idx_start*/, 2 /*idx_end*/, &fill_offset, &fill_end); + duk__clamp_startend_nonegidx_noshift(ctx, + (duk_int_t) h_this->length, + 1 /*idx_start*/, + 2 /*idx_end*/, + &fill_offset, + &fill_end); DUK_DDD(DUK_DDDPRINT("fill: fill_value=%02x, fill_offset=%ld, fill_end=%ld, view length=%ld", (unsigned int) fill_value, (long) fill_offset, (long) fill_end, (long) h_this->length)); @@ -23061,7 +25185,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) { DUK_ASSERT(fill_end - fill_offset >= 0); DUK_ASSERT(h_this->buf != NULL); - p = (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + fill_offset); + p = (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + fill_offset); fill_length = (duk_size_t) (fill_end - fill_offset); if (fill_str_len == 1) { /* Handle single character fills as memset() even when @@ -23085,11 +25209,6 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) { duk_push_this(ctx); return 1; } -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* @@ -23099,7 +25218,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) { #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) { duk_hthread *thr; - duk_hbufferobject *h_this; + duk_hbufobj *h_this; duk_uint_t offset; duk_uint_t length; const duk_uint8_t *str_data; @@ -23108,11 +25227,12 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) { thr = (duk_hthread *) ctx; DUK_UNREF(thr); + /* XXX: very inefficient support for plain buffers */ h_this = duk__require_bufobj_this(ctx); DUK_ASSERT(h_this != NULL); /* Argument must be a string, e.g. a buffer is not allowed. */ - str_data = (const duk_uint8_t *) duk_require_lstring(ctx, 0, &str_len); + str_data = (const duk_uint8_t *) duk_require_lstring_notsymbol(ctx, 0, &str_len); duk__resolve_offset_opt_length(ctx, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/); DUK_ASSERT(offset <= h_this->length); @@ -23124,9 +25244,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) { length = (duk_uint_t) str_len; } - if (DUK_HBUFFEROBJECT_VALID_SLICE(h_this)) { + if (DUK_HBUFOBJ_VALID_SLICE(h_this)) { /* Cannot overlap. */ - DUK_MEMCPY((void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + offset), + DUK_MEMCPY((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset), (const void *) str_data, (size_t) length); } else { @@ -23136,11 +25256,6 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) { duk_push_uint(ctx, length); return 1; } -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* @@ -23150,8 +25265,8 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) { #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) { duk_hthread *thr; - duk_hbufferobject *h_this; - duk_hbufferobject *h_bufarg; + duk_hbufobj *h_this; + duk_hbufobj *h_bufarg; duk_int_t source_length; duk_int_t target_length; duk_int_t target_start, source_start, source_end; @@ -23228,13 +25343,13 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) { /* Ensure copy is covered by underlying buffers. */ DUK_ASSERT(h_bufarg->buf != NULL); /* length check */ DUK_ASSERT(h_this->buf != NULL); /* length check */ - if (DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufarg, target_ustart + copy_size) && - DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, source_ustart + copy_size)) { + if (DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufarg, target_ustart + copy_size) && + DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, source_ustart + copy_size)) { /* Must use memmove() because copy area may overlap (source and target * buffer may be the same, or from different slices. */ - DUK_MEMMOVE((void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart), - (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + source_ustart), + DUK_MEMMOVE((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart), + (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + source_ustart), (size_t) copy_size); } else { DUK_DDD(DUK_DDDPRINT("buffer copy not covered by underlying buffer(s), ignoring")); @@ -23249,12 +25364,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) { return 1; fail_bounds: - return DUK_RET_RANGE_ERROR; -} -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; + DUK_DCERROR_RANGE_INVALID_ARGS(thr); } #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ @@ -23297,7 +25407,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) { #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { duk_hthread *thr; - duk_hbufferobject *h_this; + duk_hbufobj *h_this; duk_hobject *h_obj; duk_uarridx_t i, n; duk_int_t offset_signed; @@ -23309,15 +25419,15 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { h_this = duk__require_bufobj_this(ctx); DUK_ASSERT(h_this != NULL); - DUK_ASSERT_HBUFFEROBJECT_VALID(h_this); + DUK_ASSERT_HBUFOBJ_VALID(h_this); if (h_this->buf == NULL) { DUK_DDD(DUK_DDDPRINT("source neutered, skip copy")); return 0; } + duk_hbufobj_promote_plain(ctx, 0); h_obj = duk_require_hobject(ctx, 0); - DUK_ASSERT(h_obj != NULL); /* XXX: V8 throws a TypeError for negative values. Would it * be more useful to interpret negative offsets here from the @@ -23325,29 +25435,32 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { */ offset_signed = duk_to_int(ctx, 1); if (offset_signed < 0) { - return DUK_RET_TYPE_ERROR; + /* For some reason this is a TypeError (at least in V8). */ + DUK_DCERROR_TYPE_INVALID_ARGS(thr); } offset_elems = (duk_uint_t) offset_signed; offset_bytes = offset_elems << h_this->shift; if ((offset_bytes >> h_this->shift) != offset_elems) { /* Byte length would overflow. */ /* XXX: easier check with less code? */ - return DUK_RET_RANGE_ERROR; + goto fail_args; } if (offset_bytes > h_this->length) { /* Equality may be OK but >length not. Checking * this explicitly avoids some overflow cases * below. */ - return DUK_RET_RANGE_ERROR; + goto fail_args; } DUK_ASSERT(offset_bytes <= h_this->length); - /* Fast path: source is a TypedArray (or any bufferobject). */ + /* Fast path: source is a TypedArray (or any bufobj). */ - if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) { - duk_hbufferobject *h_bufarg; + if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { + duk_hbufobj *h_bufarg; +#if !defined(DUK_USE_PREFER_SIZE) duk_uint16_t comp_mask; +#endif duk_small_int_t no_overlap = 0; duk_uint_t src_length; duk_uint_t dst_length; @@ -23360,8 +25473,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { duk_small_uint_t src_elem_size; duk_small_uint_t dst_elem_size; - h_bufarg = (duk_hbufferobject *) h_obj; - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufarg); + h_bufarg = (duk_hbufobj *) h_obj; + DUK_ASSERT_HBUFOBJ_VALID(h_bufarg); if (h_bufarg->buf == NULL) { DUK_DDD(DUK_DDDPRINT("target neutered, skip copy")); @@ -23375,7 +25488,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { if ((dst_length >> h_this->shift) != dst_length_elems) { /* Byte length would overflow. */ /* XXX: easier check with less code? */ - return DUK_RET_RANGE_ERROR; + goto fail_args; } DUK_DDD(DUK_DDDPRINT("nominal size check: src_length=%ld, dst_length=%ld", (long) src_length, (long) dst_length)); @@ -23385,22 +25498,22 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { * side and guaranteed to be >= 0. */ DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length")); - return DUK_RET_RANGE_ERROR; + goto fail_args; } - if (!DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, offset_bytes + dst_length)) { + if (!DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, offset_bytes + dst_length)) { DUK_DDD(DUK_DDDPRINT("copy not covered by underlying target buffer, ignore")); return 0; } - p_src_base = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg); - p_dst_base = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + offset_bytes; + p_src_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg); + p_dst_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset_bytes; /* Check actual underlying buffers for validity and that they * cover the copy. No side effects are allowed after the check * so that the validity status doesn't change. */ - if (!DUK_HBUFFEROBJECT_VALID_SLICE(h_this) || - !DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)) { + if (!DUK_HBUFOBJ_VALID_SLICE(h_this) || + !DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) { /* The condition could be more narrow and check for the * copy area only, but there's no need for fine grained * behavior when the underlying buffer is misconfigured. @@ -23420,6 +25533,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { * and destination element sizes are necessarily equal. */ +#if !defined(DUK_USE_PREFER_SIZE) DUK_ASSERT(h_this->elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t)); comp_mask = duk__buffer_elemtype_copy_compatible[h_this->elem_type]; if (comp_mask & (1 << h_bufarg->elem_type)) { @@ -23430,6 +25544,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { return 0; } DUK_DDD(DUK_DDDPRINT("fast path: views are not compatible with a byte copy, copy by item")); +#endif /* !DUK_USE_PREFER_SIZE */ /* We want to avoid making a copy to process set() but that's * not always possible: the source and the target may overlap @@ -23466,7 +25581,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { duk_uint8_t *p_src_copy; DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source")); - p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_length); + p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, src_length); DUK_ASSERT(p_src_copy != NULL); DUK_MEMCPY((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length); @@ -23501,8 +25616,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { /* A validated read() is always a number, so it's write coercion * is always side effect free an won't invalidate pointers etc. */ - duk_hbufferobject_push_validated_read(ctx, h_bufarg, p_src, src_elem_size); - duk_hbufferobject_validated_write(ctx, h_this, p_dst, dst_elem_size); + duk_hbufobj_push_validated_read(ctx, h_bufarg, p_src, src_elem_size); + duk_hbufobj_validated_write(ctx, h_this, p_dst, dst_elem_size); duk_pop(ctx); p_src += src_elem_size; p_dst += dst_elem_size; @@ -23514,7 +25629,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { * to write coerce target values. We don't need to worry about overlap * here because the source is not a TypedArray. * - * We could use the bufferobject write coercion helper but since the + * We could use the bufobj write coercion helper but since the * property read may have arbitrary side effects, full validity checks * would be needed for every element anyway. */ @@ -23526,7 +25641,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { * side and guaranteed to be >= 0. */ DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length")); - return DUK_RET_RANGE_ERROR; + goto fail_args; } /* There's no need to check for buffer validity status for the @@ -23546,18 +25661,16 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { } return 0; -} -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; + + fail_args: + DUK_DCERROR_RANGE_INVALID_ARGS(thr); } #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* * Node.js Buffer.prototype.slice([start], [end]) * ArrayBuffer.prototype.slice(begin, [end]) - * TypedArray.prototype.slice(begin, [end]) + * TypedArray.prototype.subarray(begin, [end]) * * The API calls are almost identical; negative indices are counted from end * of buffer, and final indices are clamped (allowing crossed indices). Main @@ -23570,19 +25683,58 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { * call (or 'this' argument) * * - TypedArray .subarray() arguments are element indices, not byte offsets + * + * - Plain buffer argument creates a plain buffer slice */ #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_LOCAL void duk__arraybuffer_plain_slice(duk_context *ctx, duk_hbuffer *h_val) { + duk_hthread *thr; + duk_int_t start_offset, end_offset; + duk_uint_t slice_length; + duk_uint8_t *p_copy; + duk_size_t copy_length; + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + duk__clamp_startend_negidx_shifted(ctx, + (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val), + 0 /*buffer_shift*/, + 0 /*idx_start*/, + 1 /*idx_end*/, + &start_offset, + &end_offset); + DUK_ASSERT(end_offset <= (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val)); + DUK_ASSERT(start_offset >= 0); + DUK_ASSERT(end_offset >= start_offset); + slice_length = (duk_uint_t) (end_offset - start_offset); + + p_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, (duk_size_t) slice_length); + DUK_ASSERT(p_copy != NULL); + copy_length = slice_length; + + DUK_MEMCPY((void *) p_copy, + (const void *) ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_val) + start_offset), + copy_length); +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +/* Shared helper for slice/subarray operation. + * Magic: 0x01=isView, 0x02=copy, 0x04=Node.js Buffer special handling. + */ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) { duk_hthread *thr; duk_small_int_t magic; duk_small_uint_t res_class_num; - duk_hobject *res_proto; - duk_hbufferobject *h_this; - duk_hbufferobject *h_bufobj; + duk_small_int_t res_proto_bidx; + duk_hbufobj *h_this; + duk_hbufobj *h_bufobj; duk_hbuffer *h_val; duk_int_t start_offset, end_offset; duk_uint_t slice_length; + duk_tval *tv; thr = (duk_hthread *) ctx; DUK_UNREF(thr); @@ -23590,6 +25742,34 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) { /* [ start end ] */ magic = duk_get_current_magic(ctx); + + tv = duk_get_borrowed_this_tval(ctx); + DUK_ASSERT(tv != NULL); + + if (DUK_TVAL_IS_BUFFER(tv)) { + /* For plain buffers return a plain buffer slice. */ + h_val = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h_val != NULL); + + if (magic & 0x02) { + /* Make copy: ArrayBuffer.prototype.slice() uses this. */ + duk__arraybuffer_plain_slice(ctx, h_val); + return 1; + } else { + /* View into existing buffer: cannot be done if the + * result is a plain buffer because there's no slice + * info. So return an ArrayBuffer instance; coerce + * the 'this' binding into an object and behave as if + * the original call was for an Object-coerced plain + * buffer (handled automatically by duk__require_bufobj_this()). + */ + + DUK_DDD(DUK_DDDPRINT("slice() doesn't handle view into plain buffer, coerce 'this' to ArrayBuffer object")); + /* fall through */ + } + } + tv = NULL; /* No longer valid nor needed. */ + h_this = duk__require_bufobj_this(ctx); /* Slice offsets are element (not byte) offsets, which only matters @@ -23601,40 +25781,51 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) { * against the underlying buffer here. */ - duk__clamp_startend_negidx_shifted(ctx, h_this, 0 /*idx_start*/, 1 /*idx_end*/, &start_offset, &end_offset); + duk__clamp_startend_negidx_shifted(ctx, + (duk_int_t) h_this->length, + (duk_uint8_t) h_this->shift, + 0 /*idx_start*/, + 1 /*idx_end*/, + &start_offset, + &end_offset); DUK_ASSERT(end_offset >= start_offset); slice_length = (duk_uint_t) (end_offset - start_offset); /* The resulting buffer object gets the same class and prototype as - * the buffer in 'this', e.g. if the input is a Node.js Buffer the - * result is a Node.js Buffer; if the input is a Float32Array, the - * result is a Float32Array. + * the buffer in 'this', e.g. if the input is a Uint8Array the + * result is a Uint8Array; if the input is a Float32Array, the + * result is a Float32Array. The result internal prototype should + * be the default prototype for the class (e.g. initial value of + * Uint8Array.prototype), not copied from the argument (Duktape 1.x + * did that). * - * For the class number this seems correct. The internal prototype - * is not so clear: if 'this' is a bufferobject with a non-standard - * prototype object, that value gets copied over into the result - * (instead of using the standard prototype for that object type). + * Node.js Buffers have special handling: they're Uint8Arrays as far + * as the internal class is concerned, so the new Buffer should also + * be an Uint8Array but inherit from Buffer.prototype. */ - res_class_num = DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_this); - h_bufobj = duk_push_bufferobject_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFFEROBJECT | - DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num), - DUK_BIDX_OBJECT_PROTOTYPE); /* replaced */ + DUK_ASSERT(res_class_num >= DUK_HOBJECT_CLASS_BUFOBJ_MIN); /* type check guarantees */ + DUK_ASSERT(res_class_num <= DUK_HOBJECT_CLASS_BUFOBJ_MAX); + res_proto_bidx = duk__buffer_proto_from_classnum[res_class_num - DUK_HOBJECT_CLASS_BUFOBJ_MIN]; + if (magic & 0x04) { + res_proto_bidx = DUK_BIDX_NODEJS_BUFFER_PROTOTYPE; + } + h_bufobj = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num), + res_proto_bidx); DUK_ASSERT(h_bufobj != NULL); - res_proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_this); /* may be NULL */ - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) h_bufobj, res_proto); h_bufobj->length = slice_length; h_bufobj->shift = h_this->shift; /* inherit */ h_bufobj->elem_type = h_this->elem_type; /* inherit */ - h_bufobj->is_view = magic & 0x01; - DUK_ASSERT(h_bufobj->is_view == 0 || h_bufobj->is_view == 1); + h_bufobj->is_typedarray = magic & 0x01; + DUK_ASSERT(h_bufobj->is_typedarray == 0 || h_bufobj->is_typedarray == 1); h_val = h_this->buf; if (h_val == NULL) { - return DUK_RET_TYPE_ERROR; + DUK_DCERROR_TYPE_INVALID_ARGS(thr); } if (magic & 0x02) { @@ -23642,19 +25833,18 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) { duk_uint8_t *p_copy; duk_size_t copy_length; - p_copy = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) slice_length); + p_copy = (duk_uint8_t *) duk_push_fixed_buffer_zero(ctx, (duk_size_t) slice_length); /* must be zeroed, not all bytes always copied */ DUK_ASSERT(p_copy != NULL); /* Copy slice, respecting underlying buffer limits; remainder * is left as zero. */ - copy_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, slice_length); + copy_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, slice_length); DUK_MEMCPY((void *) p_copy, - (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + start_offset), + (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset), copy_length); - h_val = duk_get_hbuffer(ctx, -1); - DUK_ASSERT(h_val != NULL); + h_val = duk_known_hbuffer(ctx, -1); h_bufobj->buf = h_val; DUK_HBUFFER_INCREF(thr, h_val); @@ -23671,24 +25861,15 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) { * XXX: limit copy only for TypedArray classes specifically? */ - duk_push_this(ctx); - if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_BUFFER)) { - duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE); - duk_pop(ctx); - } else { - duk_pop_2(ctx); - } + DUK_ASSERT(h_bufobj->buf_prop == NULL); + h_bufobj->buf_prop = h_this->buf_prop; /* may be NULL */ + DUK_HOBJECT_INCREF_ALLOWNULL(thr, (duk_hobject *) h_bufobj->buf_prop); } /* unbalanced stack on purpose */ - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); return 1; } -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* @@ -23706,11 +25887,6 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) { duk_push_boolean(ctx, DUK_STRCMP(encoding, "utf8") == 0); return 1; } -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* @@ -23720,7 +25896,6 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) { #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) { duk_hthread *thr; - duk_tval *tv; duk_hobject *h; duk_hobject *h_proto; duk_bool_t ret = 0; @@ -23728,18 +25903,13 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) { thr = (duk_hthread *) ctx; DUK_ASSERT(duk_get_top(ctx) >= 1); /* nargs */ - tv = duk_get_tval(ctx, 0); - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_IS_OBJECT(tv)) { - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - + h = duk_get_hobject(ctx, 0); + if (h != NULL) { h_proto = thr->builtins[DUK_BIDX_NODEJS_BUFFER_PROTOTYPE]; DUK_ASSERT(h_proto != NULL); h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); - if (h) { + if (h != NULL) { ret = duk_hobject_prototype_chain_contains(thr, h, h_proto, 0 /*ignore_loop*/); } } @@ -23747,11 +25917,6 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) { duk_push_boolean(ctx, ret); return 1; } -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* @@ -23768,16 +25933,21 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) { * unconditionally. */ + /* XXX: to be revised; Old Node.js behavior just coerces any buffer + * values to string: + * $ node + * > Buffer.byteLength(new Uint32Array(10)) + * 20 + * > Buffer.byteLength(new Uint32Array(100)) + * 20 + * (The 20 comes from '[object Uint32Array]'.length + */ + str = duk_to_lstring(ctx, 0, &len); DUK_UNREF(str); duk_push_size_t(ctx, len); return 1; } -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* @@ -23789,8 +25959,8 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) { duk_hthread *thr; duk_hobject *h_arg; duk_int_t total_length = 0; - duk_hbufferobject *h_bufobj; - duk_hbufferobject *h_bufres; + duk_hbufobj *h_bufobj; + duk_hbufobj *h_bufres; duk_hbuffer *h_val; duk_uint_t i, n; duk_uint8_t *p; @@ -23803,7 +25973,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) { /* Node.js accepts only actual Arrays. */ h_arg = duk_require_hobject(ctx, 0); if (DUK_HOBJECT_GET_CLASS_NUMBER(h_arg) != DUK_HOBJECT_CLASS_ARRAY) { - return DUK_RET_TYPE_ERROR; + DUK_DCERROR_TYPE_INVALID_ARGS(thr); } /* Compute result length and validate argument buffers. */ @@ -23819,15 +25989,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) { total_length += h_bufobj->length; duk_pop(ctx); } - if (n == 1) { - /* For the case n==1 Node.js doesn't seem to type check - * the sole member but we do it before returning it. - * For this case only the original buffer object is - * returned (not a copy). - */ - duk_get_prop_index(ctx, 0, 0); - return 1; - } + /* In Node.js v0.12.1 a 1-element array is special and won't create a + * copy, this was fixed later so an explicit check no longer needed. + */ /* User totalLength overrides a computed length, but we'll check * every copy in the copy loop. Note that duk_to_uint() can @@ -23841,17 +26005,17 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) { total_length = duk_to_int(ctx, 1); } if (total_length < 0) { - return DUK_RET_RANGE_ERROR; + DUK_DCERROR_RANGE_INVALID_ARGS(thr); } - h_bufres = duk_push_bufferobject_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFFEROBJECT | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER), - DUK_BIDX_NODEJS_BUFFER_PROTOTYPE); + h_bufres = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY), + DUK_BIDX_NODEJS_BUFFER_PROTOTYPE); DUK_ASSERT(h_bufres != NULL); - p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, total_length); + p = (duk_uint8_t *) duk_push_fixed_buffer_zero(ctx, total_length); /* must be zeroed, all bytes not necessarily written over */ DUK_ASSERT(p != NULL); space_left = total_length; @@ -23868,9 +26032,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) { } if (h_bufobj->buf != NULL && - DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) { + DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) { DUK_MEMCPY((void *) p, - (const void *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj), + (const void *) DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj), copy_size); } else { /* Just skip, leaving zeroes in the result. */ @@ -23882,21 +26046,16 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) { duk_pop(ctx); } - h_val = duk_get_hbuffer(ctx, -1); - DUK_ASSERT(h_val != NULL); + h_val = duk_known_hbuffer(ctx, -1); duk__set_bufobj_buffer(ctx, h_bufres, h_val); - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufres); + h_bufres->is_typedarray = 1; + DUK_ASSERT_HBUFOBJ_VALID(h_bufres); duk_pop(ctx); /* pop plain buffer, now reachable through h_bufres */ return 1; /* return h_bufres */ } -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* @@ -23932,7 +26091,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) { duk_small_int_t magic_signed; duk_small_int_t magic_typedarray; duk_small_int_t endswap; - duk_hbufferobject *h_this; + duk_hbufobj *h_this; duk_bool_t no_assert; duk_int_t offset_signed; duk_uint_t offset; @@ -23949,7 +26108,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) { magic_signed = magic & 0x0010; magic_typedarray = magic & 0x0020; - h_this = duk__require_bufobj_this(ctx); + h_this = duk__require_bufobj_this(ctx); /* XXX: very inefficient for plain buffers */ DUK_ASSERT(h_this != NULL); buffer_length = h_this->length; @@ -23995,12 +26154,12 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) { * takes into account the underlying buffer. This value will be * potentially invalidated by any side effect. */ - check_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, buffer_length); + check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length); DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld", (long) buffer_length, (long) check_length)); if (h_this->buf) { - buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this); + buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this); } else { /* Neutered. We could go into the switch-case safely with * buf == NULL because check_length == 0. To avoid scanbuild @@ -24178,13 +26337,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) { duk_push_nan(ctx); return 1; } - - return DUK_RET_RANGE_ERROR; -} -#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; + DUK_DCERROR_RANGE_INVALID_ARGS(thr); } #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ @@ -24198,7 +26351,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) { duk_small_int_t magic_signed; duk_small_int_t magic_typedarray; duk_small_int_t endswap; - duk_hbufferobject *h_this; + duk_hbufobj *h_this; duk_bool_t no_assert; duk_int_t offset_signed; duk_uint_t offset; @@ -24217,7 +26370,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) { magic_typedarray = magic & 0x0020; DUK_UNREF(magic_signed); - h_this = duk__require_bufobj_this(ctx); + h_this = duk__require_bufobj_this(ctx); /* XXX: very inefficient for plain buffers */ DUK_ASSERT(h_this != NULL); buffer_length = h_this->length; @@ -24286,12 +26439,12 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) { * takes into account the underlying buffer. This value will be * potentially invalidated by any side effect. */ - check_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, buffer_length); + check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length); DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld", (long) buffer_length, (long) check_length)); if (h_this->buf) { - buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this); + buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this); } else { /* Neutered. We could go into the switch-case safely with * buf == NULL because check_length == 0. To avoid scanbuild @@ -24439,7 +26592,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) { */ if (magic_typedarray) { /* For TypedArrays 'undefined' return value is specified - * by ES6 (matches V8). + * by ES2015 (matches V8). */ return 0; } @@ -24462,25 +26615,118 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) { duk_push_uint(ctx, offset + nbytes); return 1; } - return DUK_RET_RANGE_ERROR; + DUK_DCERROR_RANGE_INVALID_ARGS(thr); +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Accessors for .buffer, .byteLength, .byteOffset + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx) { + duk_hbufobj *h_bufobj; + + h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW /*flags*/); + DUK_ASSERT(h_bufobj != NULL); + if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) { + duk_hbufobj *h_res; + duk_hbuffer *h_buf; + + h_buf = (duk_hbuffer *) h_bufobj; + h_res = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), + DUK_BIDX_ARRAYBUFFER_PROTOTYPE); + DUK_ASSERT(h_res != NULL); + DUK_UNREF(h_res); + + duk__set_bufobj_buffer(ctx, h_res, h_buf); + DUK_ASSERT_HBUFOBJ_VALID(h_res); + + DUK_DD(DUK_DDPRINT("autospawned .buffer ArrayBuffer: %!iT", duk_get_tval(ctx, -1))); + return 1; + } else { + if (h_bufobj->buf_prop) { + duk_push_hobject(ctx, h_bufobj->buf_prop); + return 1; + } + } + return 0; +} + +DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_context *ctx) { + duk_hbufobj *h_bufobj; + + h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW /*flags*/); + DUK_ASSERT(h_bufobj != NULL); + if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) { + duk_push_uint(ctx, 0); + } else { + /* If neutered must return 0; offset is zeroed during + * neutering. + */ + duk_push_uint(ctx, h_bufobj->offset); + } + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx) { + duk_hbufobj *h_bufobj; + + h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW /*flags*/); + DUK_ASSERT(h_bufobj != NULL); + if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) { + duk_hbuffer *h_buf; + + h_buf = (duk_hbuffer *) h_bufobj; + DUK_ASSERT(DUK_HBUFFER_GET_SIZE(h_buf) <= DUK_UINT_MAX); /* Buffer limits. */ + duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf)); + } else { + /* If neutered must return 0; length is zeroed during + * neutering. + */ + duk_push_uint(ctx, h_bufobj->length); + } + return 1; } #else /* DUK_USE_BUFFEROBJECT_SUPPORT */ -DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; +/* No .buffer getter without ArrayBuffer support. */ +#if 0 +DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx) { + return 0; +} +#endif + +DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_context *ctx) { + duk_push_uint(ctx, 0); + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx) { + duk_hbuffer *h_buf; + + /* XXX: helper? */ + duk_push_this(ctx); + h_buf = duk_require_hbuffer(ctx, -1); + duk_push_uint(ctx, DUK_HBUFFER_GET_SIZE(h_buf)); + return 1; } #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -#undef DUK__FLD_8BIT -#undef DUK__FLD_16BIT -#undef DUK__FLD_32BIT -#undef DUK__FLD_FLOAT -#undef DUK__FLD_DOUBLE -#undef DUK__FLD_VARINT -#undef DUK__FLD_BIGENDIAN -#undef DUK__FLD_SIGNED -#undef DUK__FLD_TYPEDARRAY -#line 1 "duk_bi_date.c" +/* automatic undefs */ +#undef DUK__BUFOBJ_FLAG_PROMOTE +#undef DUK__BUFOBJ_FLAG_THROW +#undef DUK__FLD_16BIT +#undef DUK__FLD_32BIT +#undef DUK__FLD_8BIT +#undef DUK__FLD_BIGENDIAN +#undef DUK__FLD_DOUBLE +#undef DUK__FLD_FLOAT +#undef DUK__FLD_SIGNED +#undef DUK__FLD_TYPEDARRAY +#undef DUK__FLD_VARINT /* * Date built-ins * @@ -24494,7 +26740,9 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) { * */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ + +/* XXX: currently defines unnecessary symbols when DUK_USE_DATE_BUILTIN is disabled. */ /* * Forward declarations @@ -24544,7 +26792,7 @@ DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk #define DUK__YEAR(x) ((duk_uint8_t) ((x) - 1970)) DUK_LOCAL duk_uint8_t duk__date_equivyear[14] = { #if 1 - /* This is based on V8 EquivalentYear() algorithm (see src/genequivyear.py): + /* This is based on V8 EquivalentYear() algorithm (see util/genequivyear.py): * http://code.google.com/p/v8/source/browse/trunk/src/date.h#146 */ @@ -24571,7 +26819,6 @@ DUK_LOCAL duk_uint8_t duk__date_equivyear[14] = { DUK__YEAR(1976), DUK__YEAR(1988), DUK__YEAR(1972) #endif }; -#undef DUK__YEAR /* * ISO 8601 subset parser. @@ -24708,7 +26955,7 @@ DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const ch DUK_DDD(DUK_DDDPRINT("too many digits -> reject")); goto reject; } - if (part_idx == DUK__PI_MILLISECOND /*msec*/ && ndigits >= 3) { + if (part_idx == DUK__PI_MILLISECOND && ndigits >= 3) { /* ignore millisecond fractions after 3 */ } else { accum = accum * 10 + ((duk_int_t) ch) - ((duk_int_t) DUK_ASC_0) + 0x00; @@ -25381,8 +27628,8 @@ DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk DUK_ERROR_TYPE(thr, "expected Date"); } - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE); - d = duk_to_number(ctx, -1); + duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE); + d = duk_to_number_m1(ctx); duk_pop(ctx); if (DUK_ISNAN(d)) { @@ -25427,7 +27674,7 @@ DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk_doub d = duk_bi_date_get_timeval_from_dparts(dparts, flags); duk_push_number(ctx, d); /* -> [ ... this timeval_new ] */ duk_dup_top(ctx); /* -> [ ... this timeval_new timeval_new ] */ - duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE); + duk_put_prop_stridx_short(ctx, -3, DUK_STRIDX_INT_VALUE); /* stack top: new time value, return 1 to allow tail calls */ return 1; @@ -25749,27 +27996,6 @@ DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts, (double) dparts[6], (double) dparts[7])); } -/* - * Helper to format a time value into caller buffer, used by logging. - * 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long. - */ - -DUK_INTERNAL void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t *out_buf) { - duk_int_t parts[DUK_DATE_IDX_NUM_PARTS]; - - duk_bi_date_timeval_to_parts(timeval, - parts, - NULL, - DUK_DATE_FLAG_ONEBASED); - - duk__format_parts_iso8601(parts, - 0 /*tzoffset*/, - DUK_DATE_FLAG_TOSTRING_DATE | - DUK_DATE_FLAG_TOSTRING_TIME | - DUK_DATE_FLAG_SEP_T /*flags*/, - out_buf); -} - /* * Indirect magic value lookup for Date methods. * @@ -25909,6 +28135,7 @@ DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_context *ctx) { return (duk_small_uint_t) duk__date_magics[magicidx]; } +#if defined(DUK_USE_DATE_BUILTIN) /* * Constructor calls */ @@ -25921,10 +28148,10 @@ DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_context *ctx) { DUK_DDD(DUK_DDDPRINT("Date constructor, nargs=%ld, is_cons=%ld", (long) nargs, (long) is_cons)); - duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE), - DUK_BIDX_DATE_PROTOTYPE); + (void) duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE), + DUK_BIDX_DATE_PROTOTYPE); /* Unlike most built-ins, the internal [[PrimitiveValue]] of a Date * is mutable. @@ -25933,21 +28160,23 @@ DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_context *ctx) { if (nargs == 0 || !is_cons) { d = duk__timeclip(DUK_USE_DATE_GET_NOW(ctx)); duk_push_number(ctx, d); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W); if (!is_cons) { /* called as a normal function: return new Date().toString() */ duk_to_string(ctx, -1); } return 1; } else if (nargs == 1) { + const char *str; duk_to_primitive(ctx, 0, DUK_HINT_NONE); - if (duk_is_string(ctx, 0)) { - duk__parse_string(ctx, duk_to_string(ctx, 0)); + str = duk_get_string_notsymbol(ctx, 0); + if (str) { + duk__parse_string(ctx, str); duk_replace(ctx, 0); /* may be NaN */ } - d = duk__timeclip(duk_to_number(ctx, 0)); + d = duk__timeclip(duk_to_number(ctx, 0)); /* symbols fail here */ duk_push_number(ctx, d); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W); return 1; } @@ -26061,8 +28290,8 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx) { } duk_pop(ctx); - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_ISO_STRING); - duk_dup(ctx, -2); /* -> [ O toIsoString O ] */ + duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_TO_ISO_STRING); + duk_dup_m2(ctx); /* -> [ O toIsoString O ] */ duk_call_method(ctx, 0); return 1; } @@ -26205,18 +28434,68 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx) { d = duk__timeclip(duk_to_number(ctx, 0)); duk_push_number(ctx, d); duk_dup_top(ctx); - duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval this timeval ] */ + duk_put_prop_stridx_short(ctx, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval this timeval ] */ return 1; } -#line 1 "duk_bi_date_unix.c" + +#endif /* DUK_USE_DATE_BUILTIN */ + +/* automatic undefs */ +#undef DUK__CF_ACCEPT +#undef DUK__CF_ACCEPT_NUL +#undef DUK__CF_NEG +#undef DUK__DPRINT_DPARTS +#undef DUK__DPRINT_PARTS +#undef DUK__DPRINT_PARTS_AND_DPARTS +#undef DUK__LOCAL_TZOFFSET_MAXITER +#undef DUK__NUM_ISO8601_PARSER_PARTS +#undef DUK__PACK_RULE +#undef DUK__PI_DAY +#undef DUK__PI_HOUR +#undef DUK__PI_MILLISECOND +#undef DUK__PI_MINUTE +#undef DUK__PI_MONTH +#undef DUK__PI_SECOND +#undef DUK__PI_TZHOUR +#undef DUK__PI_TZMINUTE +#undef DUK__PI_YEAR +#undef DUK__PM_DAY +#undef DUK__PM_HOUR +#undef DUK__PM_MILLISECOND +#undef DUK__PM_MINUTE +#undef DUK__PM_MONTH +#undef DUK__PM_SECOND +#undef DUK__PM_TZHOUR +#undef DUK__PM_TZMINUTE +#undef DUK__PM_YEAR +#undef DUK__RULE_MASK_PART_SEP +#undef DUK__SI_COLON +#undef DUK__SI_MINUS +#undef DUK__SI_NUL +#undef DUK__SI_PERIOD +#undef DUK__SI_PLUS +#undef DUK__SI_SPACE +#undef DUK__SI_T +#undef DUK__SI_Z +#undef DUK__SM_COLON +#undef DUK__SM_MINUS +#undef DUK__SM_NUL +#undef DUK__SM_PERIOD +#undef DUK__SM_PLUS +#undef DUK__SM_SPACE +#undef DUK__SM_T +#undef DUK__SM_Z +#undef DUK__UNPACK_RULE +#undef DUK__WEEKDAY_MOD_ADDER +#undef DUK__YEAR /* * Unix-like Date providers * * Generally useful Unix / POSIX / ANSI Date providers. */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ /* The necessary #includes are in place in duk_config.h. */ @@ -26234,7 +28513,7 @@ DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx) { duk_double_t d; if (gettimeofday(&tv, NULL) != 0) { - DUK_ERROR_INTERNAL_DEFMSG(thr); + DUK_ERROR_INTERNAL(thr); } d = ((duk_double_t) tv.tv_sec) * 1000.0 + @@ -26256,14 +28535,14 @@ DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(duk_context *ctx) { } #endif /* DUK_USE_DATE_NOW_TIME */ -#if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R) +#if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) /* Get local time offset (in seconds) for a certain (UTC) instant 'd'. */ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) { time_t t, t1, t2; duk_int_t parts[DUK_DATE_IDX_NUM_PARTS]; duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; struct tm tms[2]; -#ifdef DUK_USE_DATE_TZO_GMTIME +#if defined(DUK_USE_DATE_TZO_GMTIME) struct tm *tm_ptr; #endif @@ -26346,6 +28625,9 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) { #if defined(DUK_USE_DATE_TZO_GMTIME_R) (void) gmtime_r(&t, &tms[0]); (void) localtime_r(&t, &tms[1]); +#elif defined(DUK_USE_DATE_TZO_GMTIME_S) + (void) gmtime_s(&t, &tms[0]); + (void) localtime_s(&t, &tms[1]); #elif defined(DUK_USE_DATE_TZO_GMTIME) tm_ptr = gmtime(&t); DUK_MEMCPY((void *) &tms[0], tm_ptr, sizeof(struct tm)); @@ -26485,7 +28767,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_ * supporting a large time range (the full Ecmascript range). */ if (sizeof(time_t) < 8 && - (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) { + (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) { /* be paranoid for 32-bit time values (even avoiding negative ones) */ return 0; } @@ -26517,9 +28799,9 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_ } #endif /* DUK_USE_DATE_FMT_STRFTIME */ -#undef DUK__STRPTIME_BUF_SIZE +/* automatic undefs */ #undef DUK__STRFTIME_BUF_SIZE -#line 1 "duk_bi_date_windows.c" +#undef DUK__STRPTIME_BUF_SIZE /* * Windows Date providers * @@ -26528,7 +28810,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_ * - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ /* The necessary #includes are in place in duk_config.h. */ @@ -26557,7 +28839,7 @@ DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) { } #endif /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */ -#ifdef DUK_USE_DATE_NOW_WINDOWS +#if defined(DUK_USE_DATE_NOW_WINDOWS) DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx) { /* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970: * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx @@ -26618,7 +28900,6 @@ DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000000LL); /* seconds */ } #endif /* DUK_USE_DATE_TZO_WINDOWS */ -#line 1 "duk_bi_duktape.c" /* * Duktape built-ins * @@ -26630,180 +28911,24 @@ DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t * anyway. */ -/* include removed: duk_internal.h */ - -/* Raw helper to extract internal information / statistics about a value. - * The return values are version specific and must not expose anything - * that would lead to security issues (e.g. exposing compiled function - * 'data' buffer might be an issue). Currently only counts and sizes and - * such are given so there should not be a security impact. - */ -DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx) { - duk_hthread *thr = (duk_hthread *) ctx; - duk_tval *tv; - duk_heaphdr *h; - duk_int_t i, n; - - DUK_UNREF(thr); - - /* result array */ - duk_push_array(ctx); /* -> [ val arr ] */ - - /* type tag (public) */ - duk_push_int(ctx, duk_get_type(ctx, 0)); - - /* address */ - tv = duk_get_tval(ctx, 0); - DUK_ASSERT(tv != NULL); /* because arg count is 1 */ - if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { - h = DUK_TVAL_GET_HEAPHDR(tv); - duk_push_pointer(ctx, (void *) h); - } else { - /* internal type tag */ - duk_push_int(ctx, (duk_int_t) DUK_TVAL_GET_TAG(tv)); - goto done; - } - DUK_ASSERT(h != NULL); - - /* refcount */ -#ifdef DUK_USE_REFERENCE_COUNTING - duk_push_size_t(ctx, DUK_HEAPHDR_GET_REFCOUNT(h)); -#else - duk_push_undefined(ctx); -#endif - - /* heaphdr size and additional allocation size, followed by - * type specific stuff (with varying value count) - */ - switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) { - case DUK_HTYPE_STRING: { - duk_hstring *h_str = (duk_hstring *) h; - duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1)); - break; - } - case DUK_HTYPE_OBJECT: { - duk_hobject *h_obj = (duk_hobject *) h; - duk_small_uint_t hdr_size; - if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) { - hdr_size = (duk_small_uint_t) sizeof(duk_hcompiledfunction); - } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj)) { - hdr_size = (duk_small_uint_t) sizeof(duk_hnativefunction); - } else if (DUK_HOBJECT_IS_THREAD(h_obj)) { - hdr_size = (duk_small_uint_t) sizeof(duk_hthread); -#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) - } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) { - hdr_size = (duk_small_uint_t) sizeof(duk_hbufferobject); -#endif - } else { - hdr_size = (duk_small_uint_t) sizeof(duk_hobject); - } - duk_push_uint(ctx, (duk_uint_t) hdr_size); - duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj)); - duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj)); - /* Note: e_next indicates the number of gc-reachable entries - * in the entry part, and also indicates the index where the - * next new property would be inserted. It does *not* indicate - * the number of non-NULL keys present in the object. That - * value could be counted separately but requires a pass through - * the key list. - */ - duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj)); - duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj)); - duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj)); - if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) { - duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, (duk_hcompiledfunction *) h_obj); - if (h_data) { - duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_data)); - } else { - duk_push_uint(ctx, 0); - } - } - break; - } - case DUK_HTYPE_BUFFER: { - duk_hbuffer *h_buf = (duk_hbuffer *) h; - if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) { - if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) { - duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_external))); - } else { - /* When alloc_size == 0 the second allocation may not - * actually exist. - */ - duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_dynamic))); - } - duk_push_uint(ctx, (duk_uint_t) (DUK_HBUFFER_GET_SIZE(h_buf))); - } else { - duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf) + 1)); - } - break; +/* #include duk_internal.h -> already included */ - } - } +#if defined(DUK_USE_DUKTAPE_BUILTIN) - done: - /* set values into ret array */ - /* XXX: primitive to make array from valstack slice */ - n = duk_get_top(ctx); - for (i = 2; i < n; i++) { - duk_dup(ctx, i); - duk_put_prop_index(ctx, 1, i - 2); - } - duk_dup(ctx, 1); +DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx) { + duk_inspect_value(ctx, -1); return 1; } DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx) { - duk_hthread *thr = (duk_hthread *) ctx; - duk_activation *act; - duk_uint_fast32_t pc; - duk_uint_fast32_t line; duk_int_t level; - /* -1 = top callstack entry, callstack[callstack_top - 1] - * -callstack_top = bottom callstack entry, callstack[0] - */ level = duk_to_int(ctx, 0); - if (level >= 0 || -level > (duk_int_t) thr->callstack_top) { - return 0; - } - DUK_ASSERT(level >= -((duk_int_t) thr->callstack_top) && level <= -1); - act = thr->callstack + thr->callstack_top + level; - - duk_push_object(ctx); - - duk_push_tval(ctx, &act->tv_func); - - /* Relevant PC is just before current one because PC is - * post-incremented. This should match what error augment - * code does. - */ - pc = duk_hthread_get_act_prev_pc(thr, act); - duk_push_uint(ctx, (duk_uint_t) pc); - -#if defined(DUK_USE_PC2LINE) - line = duk_hobject_pc2line_query(ctx, -2, pc); -#else - line = 0; -#endif - duk_push_uint(ctx, (duk_uint_t) line); - - /* Providing access to e.g. act->lex_env would be dangerous: these - * internal structures must never be accessible to the application. - * Duktape relies on them having consistent data, and this consistency - * is only asserted for, not checked for. - */ - - /* [ level obj func pc line ] */ - - /* XXX: version specific array format instead? */ - duk_xdef_prop_stridx_wec(ctx, -4, DUK_STRIDX_LINE_NUMBER); - duk_xdef_prop_stridx_wec(ctx, -3, DUK_STRIDX_PC); - duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_LC_FUNCTION); + duk_inspect_callstack_entry(ctx, level); return 1; } DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) { -#ifdef DUK_USE_MARK_AND_SWEEP duk_hthread *thr = (duk_hthread *) ctx; duk_small_uint_t flags; duk_bool_t rc; @@ -26816,12 +28941,9 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) { */ duk_push_boolean(ctx, !rc); return 1; -#else - DUK_UNREF(ctx); - return 0; -#endif } +#if defined(DUK_USE_FINALIZER_SUPPORT) DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) { (void) duk_require_hobject(ctx, 0); if (duk_get_top(ctx) >= 2) { @@ -26832,15 +28954,16 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) { * be deleted. */ duk_set_top(ctx, 2); - (void) duk_put_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER); + (void) duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_FINALIZER); return 0; } else { /* Get. */ DUK_ASSERT(duk_get_top(ctx) == 1); - duk_get_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER); + duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_FINALIZER); return 1; } } +#endif /* DUK_USE_FINALIZER_SUPPORT */ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; @@ -26853,7 +28976,7 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) { * non-existent optional parameters. */ - h_str = duk_require_hstring(ctx, 0); + h_str = duk_require_hstring(ctx, 0); /* Could reject symbols, but no point: won't match comparisons. */ duk_require_valid_index(ctx, 1); if (h_str == DUK_HTHREAD_STRING_HEX(thr)) { @@ -26864,7 +28987,7 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) { duk_set_top(ctx, 2); duk_base64_encode(ctx, 1); DUK_ASSERT_TOP(ctx, 2); -#ifdef DUK_USE_JX +#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX) } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) { duk_bi_json_stringify_helper(ctx, 1 /*idx_value*/, @@ -26874,7 +28997,7 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) { DUK_JSON_FLAG_ASCII_ONLY | DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/); #endif -#ifdef DUK_USE_JC +#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC) } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) { duk_bi_json_stringify_helper(ctx, 1 /*idx_value*/, @@ -26884,7 +29007,7 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) { DUK_JSON_FLAG_ASCII_ONLY /*flags*/); #endif } else { - return DUK_RET_TYPE_ERROR; + DUK_DCERROR_TYPE_INVALID_ARGS(thr); } return 1; } @@ -26900,7 +29023,7 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) { * non-existent optional parameters. */ - h_str = duk_require_hstring(ctx, 0); + h_str = duk_require_hstring(ctx, 0); /* Could reject symbols, but no point: won't match comparisons */ duk_require_valid_index(ctx, 1); if (h_str == DUK_HTHREAD_STRING_HEX(thr)) { @@ -26911,14 +29034,14 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) { duk_set_top(ctx, 2); duk_base64_decode(ctx, 1); DUK_ASSERT_TOP(ctx, 2); -#ifdef DUK_USE_JX +#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX) } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) { duk_bi_json_parse_helper(ctx, 1 /*idx_value*/, 2 /*idx_replacer*/, DUK_JSON_FLAG_EXT_CUSTOM /*flags*/); #endif -#ifdef DUK_USE_JC +#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC) } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) { duk_bi_json_parse_helper(ctx, 1 /*idx_value*/, @@ -26926,7 +29049,7 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) { DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/); #endif } else { - return DUK_RET_TYPE_ERROR; + DUK_DCERROR_TYPE_INVALID_ARGS(thr); } return 1; } @@ -26940,12 +29063,547 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx) { duk_compact(ctx, 0); return 1; /* return the argument object */ } -#line 1 "duk_bi_error.c" + +#endif /* DUK_USE_DUKTAPE_BUILTIN */ +/* + * WHATWG Encoding API built-ins + * + * API specification: https://encoding.spec.whatwg.org/#api + * Web IDL: https://www.w3.org/TR/WebIDL/ + */ + +/* #include duk_internal.h -> already included */ + +/* + * Data structures for encoding/decoding + */ + +typedef struct { + duk_uint8_t *out; /* where to write next byte(s) */ + duk_codepoint_t lead; /* lead surrogate */ +} duk__encode_context; + +typedef struct { + /* UTF-8 decoding state */ + duk_codepoint_t codepoint; /* built up incrementally */ + duk_uint8_t upper; /* max value of next byte (decode error otherwise) */ + duk_uint8_t lower; /* min value of next byte (ditto) */ + duk_uint8_t needed; /* how many more bytes we need */ + duk_uint8_t bom_handled; /* BOM seen or no longer expected */ + + /* Decoder configuration */ + duk_uint8_t fatal; + duk_uint8_t ignore_bom; +} duk__decode_context; + +/* The signed duk_codepoint_t type is used to signal a decoded codepoint + * (>= 0) or various other states using negative values. + */ +#define DUK__CP_CONTINUE (-1) /* continue to next byte, no completed codepoint */ +#define DUK__CP_ERROR (-2) /* decoding error */ +#define DUK__CP_RETRY (-3) /* decoding error; retry last byte */ + +/* + * Raw helpers for encoding/decoding + */ + +/* Emit UTF-8 (= CESU-8) encoded U+FFFD (replacement char), i.e. ef bf bd. */ +DUK_LOCAL duk_uint8_t *duk__utf8_emit_repl(duk_uint8_t *ptr) { + *ptr++ = 0xef; + *ptr++ = 0xbf; + *ptr++ = 0xbd; + return ptr; +} + +DUK_LOCAL void duk__utf8_decode_init(duk__decode_context *dec_ctx) { + /* (Re)init the decoding state of 'dec_ctx' but leave decoder + * configuration fields untouched. + */ + dec_ctx->codepoint = 0x0000L; + dec_ctx->upper = 0xbf; + dec_ctx->lower = 0x80; + dec_ctx->needed = 0; + dec_ctx->bom_handled = 0; +} + +DUK_LOCAL duk_codepoint_t duk__utf8_decode_next(duk__decode_context *dec_ctx, duk_uint8_t x) { + /* + * UTF-8 algorithm based on the Encoding specification: + * https://encoding.spec.whatwg.org/#utf-8-decoder + * + * Two main states: decoding initial byte vs. decoding continuation + * bytes. Shortest length encoding is validated by restricting the + * allowed range of first continuation byte using 'lower' and 'upper'. + */ + + if (dec_ctx->needed == 0) { + /* process initial byte */ + if (x <= 0x7f) { + /* U+0000-U+007F, 1 byte (ASCII) */ + return (duk_codepoint_t) x; + } else if (x >= 0xc2 && x <= 0xdf) { + /* U+0080-U+07FF, 2 bytes */ + dec_ctx->needed = 1; + dec_ctx->codepoint = x & 0x1f; + DUK_ASSERT(dec_ctx->lower == 0x80); + DUK_ASSERT(dec_ctx->upper == 0xbf); + return DUK__CP_CONTINUE; + } else if (x >= 0xe0 && x <= 0xef) { + /* U+0800-U+FFFF, 3 bytes */ + if (x == 0xe0) { + dec_ctx->lower = 0xa0; + DUK_ASSERT(dec_ctx->upper == 0xbf); + } else if (x == 0xed) { + DUK_ASSERT(dec_ctx->lower == 0x80); + dec_ctx->upper = 0x9f; + } + dec_ctx->needed = 2; + dec_ctx->codepoint = x & 0x0f; + return DUK__CP_CONTINUE; + } else if (x >= 0xf0 && x <= 0xf4) { + /* U+010000-U+10FFFF, 4 bytes */ + if (x == 0xf0) { + dec_ctx->lower = 0x90; + DUK_ASSERT(dec_ctx->upper == 0xbf); + } else if (x == 0xf4) { + DUK_ASSERT(dec_ctx->lower == 0x80); + dec_ctx->upper = 0x8f; + } + dec_ctx->needed = 3; + dec_ctx->codepoint = x & 0x07; + return DUK__CP_CONTINUE; + } else { + /* not a legal initial byte */ + return DUK__CP_ERROR; + } + } else { + /* process continuation byte */ + if (x >= dec_ctx->lower && x <= dec_ctx->upper) { + dec_ctx->lower = 0x80; + dec_ctx->upper = 0xbf; + dec_ctx->codepoint = (dec_ctx->codepoint << 6) | (x & 0x3f); + if (--dec_ctx->needed > 0) { + /* need more bytes */ + return DUK__CP_CONTINUE; + } else { + /* got a codepoint */ + duk_codepoint_t ret; + DUK_ASSERT(dec_ctx->codepoint <= 0x10ffffL); /* Decoding rules guarantee. */ + ret = dec_ctx->codepoint; + dec_ctx->codepoint = 0x0000L; + dec_ctx->needed = 0; + return ret; + } + } else { + /* We just encountered an illegal UTF-8 continuation byte. This might + * be the initial byte of the next character; if we return a plain + * error status and the decoder is in replacement mode, the character + * will be masked. We still need to alert the caller to the error + * though. + */ + dec_ctx->codepoint = 0x0000L; + dec_ctx->needed = 0; + dec_ctx->lower = 0x80; + dec_ctx->upper = 0xbf; + return DUK__CP_RETRY; + } + } +} + +DUK_LOCAL void duk__utf8_encode_char(void *udata, duk_codepoint_t codepoint) { + duk__encode_context *enc_ctx; + + DUK_ASSERT(codepoint >= 0); + enc_ctx = (duk__encode_context *) udata; + DUK_ASSERT(enc_ctx != NULL); + +#if !defined(DUK_USE_PREFER_SIZE) + if (codepoint <= 0x7f && enc_ctx->lead == 0x0000L) { + /* Fast path for ASCII. */ + *enc_ctx->out++ = (duk_uint8_t) codepoint; + return; + } +#endif + + if (DUK_UNLIKELY(codepoint > 0x10ffffL)) { + /* cannot legally encode in UTF-8 */ + codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; + } else if (codepoint >= 0xd800L && codepoint <= 0xdfffL) { + if (codepoint <= 0xdbffL) { + /* high surrogate */ + duk_codepoint_t prev_lead = enc_ctx->lead; + enc_ctx->lead = codepoint; + if (prev_lead == 0x0000L) { + /* high surrogate, no output */ + return; + } else { + /* consecutive high surrogates, consider first one unpaired */ + codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; + } + } else { + /* low surrogate */ + if (enc_ctx->lead != 0x0000L) { + codepoint = 0x010000L + ((enc_ctx->lead - 0xd800L) << 10) + (codepoint - 0xdc00L); + enc_ctx->lead = 0x0000L; + } else { + /* unpaired low surrogate */ + DUK_ASSERT(enc_ctx->lead == 0x0000L); + codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; + } + } + } else { + if (enc_ctx->lead != 0x0000L) { + /* unpaired high surrogate: emit replacement character and the input codepoint */ + enc_ctx->lead = 0x0000L; + enc_ctx->out = duk__utf8_emit_repl(enc_ctx->out); + } + } + + /* Codepoint may be original input, a decoded surrogate pair, or may + * have been replaced with U+FFFD. + */ + enc_ctx->out += duk_unicode_encode_xutf8(codepoint, enc_ctx->out); +} + +/* Shared helper for buffer-to-string using a TextDecoder() compatible UTF-8 + * decoder. + */ +DUK_LOCAL duk_ret_t duk__decode_helper(duk_context *ctx, duk__decode_context *dec_ctx) { + const duk_uint8_t *input; + duk_size_t len = 0; + duk_size_t len_tmp; + duk_bool_t stream = 0; + duk_codepoint_t codepoint; + duk_uint8_t *output; + const duk_uint8_t *in; + duk_uint8_t *out; + + DUK_ASSERT(dec_ctx != NULL); + + /* Careful with input buffer pointer: any side effects involving + * code execution (e.g. getters, coercion calls, and finalizers) + * may cause a resize and invalidate a pointer we've read. This + * is why the pointer is actually looked up at the last minute. + * Argument validation must still happen first to match WHATWG + * required side effect order. + */ + + if (duk_is_undefined(ctx, 0)) { + duk_push_fixed_buffer_nozero(ctx, 0); + duk_replace(ctx, 0); + } + (void) duk_require_buffer_data(ctx, 0, &len); /* Need 'len', avoid pointer. */ + + if (duk_check_type_mask(ctx, 1, DUK_TYPE_MASK_UNDEFINED | + DUK_TYPE_MASK_NULL | + DUK_TYPE_MASK_NONE)) { + /* Use defaults, treat missing value like undefined. */ + } else { + duk_require_type_mask(ctx, 1, DUK_TYPE_MASK_UNDEFINED | + DUK_TYPE_MASK_NULL | + DUK_TYPE_MASK_LIGHTFUNC | + DUK_TYPE_MASK_BUFFER | + DUK_TYPE_MASK_OBJECT); + if (duk_get_prop_string(ctx, 1, "stream")) { + stream = duk_to_boolean(ctx, -1); + } + } + + /* Allowance is 3*len in the general case because all bytes may potentially + * become U+FFFD. If the first byte completes a non-BMP codepoint it will + * decode to a CESU-8 surrogate pair (6 bytes) so we allow 3 extra bytes to + * compensate: (1*3)+3 = 6. Non-BMP codepoints are safe otherwise because + * the 4->6 expansion is well under the 3x allowance. + * + * XXX: As with TextEncoder, need a better buffer allocation strategy here. + */ + if (len >= (DUK_HBUFFER_MAX_BYTELEN / 3) - 3) { + DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_RESULT_TOO_LONG); + } + output = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, 3 + (3 * len)); /* used parts will be always manually written over */ + + input = (const duk_uint8_t *) duk_get_buffer_data(ctx, 0, &len_tmp); + DUK_ASSERT(input != NULL || len == 0); + if (DUK_UNLIKELY(len != len_tmp)) { + /* Very unlikely but possible: source buffer was resized by + * a side effect when fixed buffer was pushed. Output buffer + * may not be large enough to hold output, so just fail if + * length has changed. + */ + DUK_D(DUK_DPRINT("input buffer resized by side effect, fail")); + goto fail_type; + } + + /* From this point onwards it's critical that no side effect occur + * which may disturb 'input': finalizer execution, property accesses, + * active coercions, etc. Even an allocation related mark-and-sweep + * may affect the pointer because it may trigger a pending finalizer. + */ + + in = input; + out = output; + while (in < input + len) { + codepoint = duk__utf8_decode_next(dec_ctx, *in++); + if (codepoint < 0) { + if (codepoint == DUK__CP_CONTINUE) { + continue; + } + + /* Decoding error with or without retry. */ + DUK_ASSERT(codepoint == DUK__CP_ERROR || codepoint == DUK__CP_RETRY); + if (codepoint == DUK__CP_RETRY) { + --in; /* retry last byte */ + } + /* replacement mode: replace with U+FFFD */ + codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; + if (dec_ctx->fatal) { + /* fatal mode: throw a TypeError */ + goto fail_type; + } + /* Continue with 'codepoint', Unicode replacement. */ + } + DUK_ASSERT(codepoint >= 0x0000L && codepoint <= 0x10ffffL); + + if (!dec_ctx->bom_handled) { + dec_ctx->bom_handled = 1; + if (codepoint == 0xfeffL && !dec_ctx->ignore_bom) { + continue; + } + } + + out += duk_unicode_encode_cesu8(codepoint, out); + DUK_ASSERT(out <= output + (3 + (3 * len))); + } + + if (!stream) { + if (dec_ctx->needed != 0) { + /* truncated sequence at end of buffer */ + if (dec_ctx->fatal) { + goto fail_type; + } else { + out += duk_unicode_encode_cesu8(DUK_UNICODE_CP_REPLACEMENT_CHARACTER, out); + DUK_ASSERT(out <= output + (3 + (3 * len))); + } + } + duk__utf8_decode_init(dec_ctx); /* Initialize decoding state for potential reuse. */ + } + + /* Output buffer is fixed and thus stable even if there had been + * side effects (which there shouldn't be). + */ + duk_push_lstring(ctx, (const char *) output, (duk_size_t) (out - output)); + return 1; + + fail_type: + DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_DECODE_FAILED); + DUK_UNREACHABLE(); +} + +/* + * Built-in bindings + */ + +#if defined(DUK_USE_ENCODING_BUILTINS) +DUK_INTERNAL duk_ret_t duk_bi_textencoder_constructor(duk_context *ctx) { + /* TextEncoder currently requires no persistent state, so the constructor + * does nothing on purpose. + */ + + duk_require_constructor_call(ctx); + return 0; +} + +DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_context *ctx) { + duk_push_string(ctx, "utf-8"); + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx) { + duk__encode_context enc_ctx; + duk_size_t len; + duk_size_t final_len; + duk_uint8_t *output; + + DUK_ASSERT_TOP(ctx, 1); + if (duk_is_undefined(ctx, 0)) { + len = 0; + } else { + duk_hstring *h_input; + + h_input = duk_to_hstring(ctx, 0); + DUK_ASSERT(h_input != NULL); + + len = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_input); + if (len >= DUK_HBUFFER_MAX_BYTELEN / 3) { + DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_RESULT_TOO_LONG); + } + } + + /* Allowance is 3*len because all bytes can potentially be replaced with + * U+FFFD -- which rather inconveniently encodes to 3 bytes in UTF-8. + * Rely on dynamic buffer data pointer stability: no other code has + * access to the data pointer. + * + * XXX: The buffer allocation strategy used here is rather inefficient. + * Maybe switch to a chunk-based strategy, or preprocess the string to + * figure out the space needed ahead of time? + */ + DUK_ASSERT(3 * len >= len); + output = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, 3 * len); + + if (len > 0) { + DUK_ASSERT(duk_is_string(ctx, 0)); /* True if len > 0. */ + + /* XXX: duk_decode_string() is used to process the input + * string. For standard Ecmascript strings, represented + * internally as CESU-8, this is fine. However, behavior + * beyond CESU-8 is not very strict: codepoints using an + * extended form of UTF-8 are also accepted, and invalid + * codepoint sequences (which are allowed in Duktape strings) + * are not handled as well as they could (e.g. invalid + * continuation bytes may mask following codepoints). + * This is how Ecmascript code would also see such strings. + * Maybe replace duk_decode_string() with an explicit strict + * CESU-8 decoder here? + */ + enc_ctx.lead = 0x0000L; + enc_ctx.out = output; + duk_decode_string(ctx, 0, duk__utf8_encode_char, (void *) &enc_ctx); + if (enc_ctx.lead != 0x0000L) { + /* unpaired high surrogate at end of string */ + enc_ctx.out = duk__utf8_emit_repl(enc_ctx.out); + DUK_ASSERT(enc_ctx.out <= output + (3 * len)); + } + + /* The output buffer is usually very much oversized, so shrink it to + * actually needed size. Pointer stability assumed up to this point. + */ + DUK_ASSERT_TOP(ctx, 2); + DUK_ASSERT(output == (duk_uint8_t *) duk_get_buffer_data(ctx, -1, NULL)); + + final_len = (duk_size_t) (enc_ctx.out - output); + duk_resize_buffer(ctx, -1, final_len); + /* 'output' and 'enc_ctx.out' are potentially invalidated by the resize. */ + } else { + final_len = 0; + } + + /* Standard WHATWG output is a Uint8Array. Here the Uint8Array will + * be backed by a dynamic buffer which differs from e.g. Uint8Arrays + * created as 'new Uint8Array(N)'. Ecmascript code won't see the + * difference but C code will. When bufferobjects are not supported, + * returns a plain dynamic buffer. + */ +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) + duk_push_buffer_object(ctx, -1, 0, final_len, DUK_BUFOBJ_UINT8ARRAY); +#endif + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_context *ctx) { + duk__decode_context *dec_ctx; + duk_bool_t fatal = 0; + duk_bool_t ignore_bom = 0; + + DUK_ASSERT_TOP(ctx, 2); + duk_require_constructor_call(ctx); + if (!duk_is_undefined(ctx, 0)) { + /* XXX: For now ignore 'label' (encoding identifier). */ + duk_to_string(ctx, 0); + } + if (!duk_is_null_or_undefined(ctx, 1)) { + if (duk_get_prop_string(ctx, 1, "fatal")) { + fatal = duk_to_boolean(ctx, -1); + } + if (duk_get_prop_string(ctx, 1, "ignoreBOM")) { + ignore_bom = duk_to_boolean(ctx, -1); + } + } + + duk_push_this(ctx); + + /* The decode context is not assumed to be zeroed; all fields are + * initialized explicitly. + */ + dec_ctx = (duk__decode_context *) duk_push_fixed_buffer(ctx, sizeof(duk__decode_context)); + dec_ctx->fatal = fatal; + dec_ctx->ignore_bom = ignore_bom; + duk__utf8_decode_init(dec_ctx); /* Initializes remaining fields. */ + + duk_put_prop_string(ctx, -2, "\xff" "Context"); + return 0; +} + +/* Get TextDecoder context from 'this'; leaves garbage on stack. */ +DUK_LOCAL duk__decode_context *duk__get_textdecoder_context(duk_context *ctx) { + duk__decode_context *dec_ctx; + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, "\xff" "Context"); + dec_ctx = (duk__decode_context *) duk_require_buffer(ctx, -1, NULL); + DUK_ASSERT(dec_ctx != NULL); + return dec_ctx; +} + +DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_context *ctx) { + duk__decode_context *dec_ctx; + duk_int_t magic; + + dec_ctx = duk__get_textdecoder_context(ctx); + magic = duk_get_current_magic(ctx); + switch (magic) { + case 0: + /* Encoding is now fixed, so _Context lookup is only needed to + * validate the 'this' binding (TypeError if not TextDecoder-like). + */ + duk_push_string(ctx, "utf-8"); + break; + case 1: + duk_push_boolean(ctx, dec_ctx->fatal); + break; + default: + duk_push_boolean(ctx, dec_ctx->ignore_bom); + break; + } + + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx) { + duk__decode_context *dec_ctx; + + dec_ctx = duk__get_textdecoder_context(ctx); + return duk__decode_helper(ctx, dec_ctx); +} +#endif /* DUK_USE_ENCODING_BUILTINS */ + +/* + * Internal helper for Node.js Buffer + */ + +/* Internal helper used for Node.js Buffer .toString(). Value stack convention + * is currently odd: it mimics TextDecoder .decode() so that argument must be at + * index 0, and decode options (not present for Buffer) at index 1. Return value + * is a Duktape/C function return value. + */ +DUK_INTERNAL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_context *ctx) { + duk__decode_context dec_ctx; + + dec_ctx.fatal = 0; /* use replacement chars */ + dec_ctx.ignore_bom = 1; /* ignore BOMs (matches Node.js Buffer .toString()) */ + duk__utf8_decode_init(&dec_ctx); + + return duk__decode_helper(ctx, &dec_ctx); +} + +/* automatic undefs */ +#undef DUK__CP_CONTINUE +#undef DUK__CP_ERROR +#undef DUK__CP_RETRY /* * Error built-ins */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx) { /* Behavior for constructor and non-constructor call is @@ -26964,22 +29622,22 @@ DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx) { DUK_UNREF(thr); - duk_push_object_helper(ctx, flags_and_class, bidx_prototype); + (void) duk_push_object_helper(ctx, flags_and_class, bidx_prototype); /* If message is undefined, the own property 'message' is not set at * all to save property space. An empty message is inherited anyway. */ if (!duk_is_undefined(ctx, 0)) { duk_to_string(ctx, 0); - duk_dup(ctx, 0); /* [ message error message ] */ - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); + duk_dup_0(ctx); /* [ message error message ] */ + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); } /* Augment the error if called as a normal function. __FILE__ and __LINE__ * are not desirable in this case. */ -#ifdef DUK_USE_AUGMENT_ERROR_CREATE +#if defined(DUK_USE_AUGMENT_ERROR_CREATE) if (!duk_is_constructor_call(ctx)) { duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/); } @@ -26992,11 +29650,11 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) { /* XXX: optimize with more direct internal access */ duk_push_this(ctx); - (void) duk_require_hobject_or_lfunc_coerce(ctx, -1); + (void) duk_require_hobject_promote_mask(ctx, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); /* [ ... this ] */ - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME); + duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_NAME); if (duk_is_undefined(ctx, -1)) { duk_pop(ctx); duk_push_string(ctx, "Error"); @@ -27010,10 +29668,10 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) { * accident or are they actually needed? The first ToString() * could conceivably return 'undefined'. */ - duk_get_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE); + duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_MESSAGE); if (duk_is_undefined(ctx, -1)) { duk_pop(ctx); - duk_push_string(ctx, ""); + duk_push_hstring_empty(ctx); } else { duk_to_string(ctx, -1); } @@ -27074,7 +29732,7 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o DUK_UNREF(thr); duk_push_this(ctx); - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TRACEDATA); + duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_TRACEDATA); idx_td = duk_get_top_index(ctx); duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_4SPACE); @@ -27099,7 +29757,7 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o duk_require_stack(ctx, 5); duk_get_prop_index(ctx, idx_td, i); duk_get_prop_index(ctx, idx_td, i + 1); - d = duk_to_number(ctx, -1); + d = duk_to_number_m1(ctx); pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32); flags = (duk_int_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32); t = (duk_small_int_t) duk_get_type(ctx, -2); @@ -27115,8 +29773,12 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o h_func = duk_get_hobject(ctx, -2); /* NULL for lightfunc */ - duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME); - duk_get_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME); + /* These may be systematically omitted by Duktape + * with certain config options, but allow user to + * set them on a case-by-case basis. + */ + duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME); + duk_get_prop_stridx_short(ctx, -3, DUK_STRIDX_FILE_NAME); #if defined(DUK_USE_PC2LINE) line = duk_hobject_pc2line_query(ctx, -4, (duk_uint_fast32_t) pc); @@ -27129,7 +29791,7 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o /* When looking for .fileName/.lineNumber, blame first * function which has a .fileName. */ - if (duk_is_string(ctx, -1)) { + if (duk_is_string_notsymbol(ctx, -1)) { if (output_type == DUK__OUTPUT_TYPE_FILENAME) { return 1; } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { @@ -27140,10 +29802,10 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o /* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */ /* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */ - h_name = duk_get_hstring(ctx, -2); /* may be NULL */ + h_name = duk_get_hstring_notsymbol(ctx, -2); /* may be NULL */ funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ? "[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name); - filename = duk_get_string(ctx, -1); + filename = duk_get_string_notsymbol(ctx, -1); filename = filename ? filename : ""; DUK_ASSERT(funcname != NULL); DUK_ASSERT(filename != NULL); @@ -27156,7 +29818,7 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); - } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h_func)) { + } else if (DUK_HOBJECT_HAS_NATFUNC(h_func)) { duk_push_sprintf(ctx, "at %s (%s) native%s%s%s%s%s", (const char *) funcname, (const char *) filename, @@ -27177,8 +29839,10 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); } duk_replace(ctx, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */ - duk_pop_n(ctx, 3); /* -> [ ... str ] */ + duk_pop_3(ctx); /* -> [ ... str ] */ } else if (t == DUK_TYPE_STRING) { + const char *str_file; + /* * __FILE__ / __LINE__ entry, here 'pc' is line number directly. * Sometimes __FILE__ / __LINE__ is reported as the source for @@ -27200,8 +29864,14 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o } } + /* Tracedata is trusted but avoid any risk of using a NULL + * for %s format because it has undefined behavior. Symbols + * don't need to be explicitly rejected as they pose no memory + * safety issues. + */ + str_file = (const char *) duk_get_string(ctx, -2); duk_push_sprintf(ctx, "at [anon] (%s:%ld) internal", - (const char *) duk_get_string(ctx, -2), (long) pc); + (const char *) (str_file ? str_file : "null"), (long) pc); duk_replace(ctx, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */ duk_pop(ctx); /* -> [ ... str ] */ } else { @@ -27250,10 +29920,6 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER); } -#undef DUK__OUTPUT_TYPE_TRACEBACK -#undef DUK__OUTPUT_TYPE_FILENAME -#undef DUK__OUTPUT_TYPE_LINENUMBER - #else /* DUK_USE_TRACEBACKS */ /* @@ -27299,7 +29965,7 @@ DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t duk_push_this(ctx); duk_push_hstring_stridx(ctx, (duk_small_int_t) stridx_key); - duk_dup(ctx, 0); + duk_dup_0(ctx); /* [ ... obj key value ] */ @@ -27324,20 +29990,32 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx) 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" + +/* automatic undefs */ +#undef DUK__OUTPUT_TYPE_FILENAME +#undef DUK__OUTPUT_TYPE_LINENUMBER +#undef DUK__OUTPUT_TYPE_TRACEBACK /* * Function built-ins */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ + +/* Needed even when Function built-in is disabled. */ +DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_context *ctx) { + /* ignore arguments, return undefined (E5 Section 15.3.4) */ + DUK_UNREF(ctx); + return 0; +} +#if defined(DUK_USE_FUNCTION_BUILTIN) DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h_sourcecode; duk_idx_t nargs; duk_idx_t i; duk_small_uint_t comp_flags; - duk_hcompiledfunction *func; + duk_hcompfunc *func; duk_hobject *outer_lex_env; duk_hobject *outer_var_env; @@ -27345,15 +30023,15 @@ DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) { nargs = duk_get_top(ctx); for (i = 0; i < nargs; i++) { - duk_to_string(ctx, i); + duk_to_string(ctx, i); /* Rejects Symbols during coercion. */ } if (nargs == 0) { - duk_push_string(ctx, ""); - duk_push_string(ctx, ""); + duk_push_hstring_empty(ctx); + duk_push_hstring_empty(ctx); } else if (nargs == 1) { /* XXX: cover this with the generic >1 case? */ - duk_push_string(ctx, ""); + duk_push_hstring_empty(ctx); } else { duk_insert(ctx, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */ duk_push_string(ctx, ","); @@ -27369,9 +30047,9 @@ DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) { * It will fail in corner cases; see test-dev-func-cons-args.js. */ duk_push_string(ctx, "function("); - duk_dup(ctx, 1); + duk_dup_1(ctx); duk_push_string(ctx, "){"); - duk_dup(ctx, 0); + duk_dup_0(ctx); duk_push_string(ctx, "}"); duk_concat(ctx, 5); @@ -27383,14 +30061,19 @@ DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) { comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR; duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */ - h_sourcecode = duk_require_hstring(ctx, -2); + h_sourcecode = duk_require_hstring(ctx, -2); /* no symbol check needed; -2 is concat'd code */ duk_js_compile(thr, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode), (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode), comp_flags); - func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1); - DUK_ASSERT(func != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func)); + + /* Force .name to 'anonymous' (ES2015). */ + duk_push_string(ctx, "anonymous"); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); + + func = (duk_hcompfunc *) duk_known_hobject(ctx, -1); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func)); + DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) func)); /* [ body formals source template ] */ @@ -27407,36 +30090,34 @@ DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) { return 1; } +#endif /* DUK_USE_FUNCTION_BUILTIN */ -DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_context *ctx) { - /* ignore arguments, return undefined (E5 Section 15.3.4) */ - DUK_UNREF(ctx); - return 0; -} - +#if defined(DUK_USE_FUNCTION_BUILTIN) DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) { duk_tval *tv; /* * E5 Section 15.3.4.2 places few requirements on the output of - * this function: + * this function: the result is implementation dependent, must + * follow FunctionDeclaration syntax (in particular, must have a + * name even for anonymous functions or functions with empty name). + * The output does NOT need to compile into anything useful. * - * - The result is an implementation dependent representation - * of the function; in particular + * E6 Section 19.2.3.5 changes the requirements completely: the + * result must either eval() to a functionally equivalent object + * OR eval() to a SyntaxError. * - * - The result must follow the syntax of a FunctionDeclaration. - * In particular, the function must have a name (even in the - * case of an anonymous function or a function with an empty - * name). + * We opt for the SyntaxError approach for now, with a syntax that + * mimics V8's native function syntax: * - * - Note in particular that the output does NOT need to compile - * into anything useful. + * 'function cos() { [native code] }' + * + * but extended with [ecmascript code], [bound code], and + * [lightfunc code]. */ - - /* XXX: faster internal way to get this */ duk_push_this(ctx); - tv = duk_get_tval(ctx, -1); + tv = DUK_GET_TVAL_NEGIDX(ctx, -1); DUK_ASSERT(tv != NULL); if (DUK_TVAL_IS_OBJECT(tv)) { @@ -27444,12 +30125,13 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) { const char *func_name; /* Function name: missing/undefined is mapped to empty string, - * otherwise coerce to string. + * otherwise coerce to string. No handling for invalid identifier + * characters or e.g. '{' in the function name. This doesn't + * really matter as long as a SyntaxError results. Technically + * if the name contained a suitable prefix followed by '//' it + * might cause the result to parse without error. */ - /* XXX: currently no handling for non-allowed identifier characters, - * e.g. a '{' in the function name. - */ - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME); + duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_NAME); if (duk_is_undefined(ctx, -1)) { func_name = ""; } else { @@ -27457,15 +30139,12 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) { DUK_ASSERT(func_name != NULL); } - /* Indicate function type in the function body using a dummy - * directive. - */ - if (DUK_HOBJECT_HAS_COMPILEDFUNCTION(obj)) { - duk_push_sprintf(ctx, "function %s() {\"ecmascript\"}", (const char *) func_name); - } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(obj)) { - duk_push_sprintf(ctx, "function %s() {\"native\"}", (const char *) func_name); - } else if (DUK_HOBJECT_HAS_BOUND(obj)) { - duk_push_sprintf(ctx, "function %s() {\"bound\"}", (const char *) func_name); + if (DUK_HOBJECT_IS_COMPFUNC(obj)) { + duk_push_sprintf(ctx, "function %s() { [ecmascript code] }", (const char *) func_name); + } else if (DUK_HOBJECT_IS_NATFUNC(obj)) { + duk_push_sprintf(ctx, "function %s() { [native code] }", (const char *) func_name); + } else if (DUK_HOBJECT_IS_BOUNDFUNC(obj)) { + duk_push_sprintf(ctx, "function %s() { [bound code] }", (const char *) func_name); } else { goto type_error; } @@ -27478,40 +30157,76 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) { return 1; type_error: - return DUK_RET_TYPE_ERROR; + DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); } +#endif +#if defined(DUK_USE_FUNCTION_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN) DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx) { + /* + * magic = 0: Function.prototype.apply() + * magic = 1: Reflect.apply() + * magic = 2: Reflect.construct() + */ + + duk_idx_t idx_args; duk_idx_t len; duk_idx_t i; + duk_int_t magic; + duk_idx_t nargs; + duk_uint_t mask; - DUK_ASSERT_TOP(ctx, 2); /* not a vararg function */ - - duk_push_this(ctx); - if (!duk_is_callable(ctx, -1)) { - DUK_DDD(DUK_DDDPRINT("func is not callable")); - goto type_error; + magic = duk_get_current_magic(ctx); + switch (magic) { + case 0: /* Function.prototype.apply() */ + DUK_ASSERT_TOP(ctx, 2); /* not a vararg function */ + duk_push_this(ctx); + duk_insert(ctx, 0); + /* Fall through intentionally for shared handling. */ + case 1: /* Reflect.apply(); Function.prototype.apply() after 'this' fixup. */ + DUK_ASSERT_TOP(ctx, 3); /* not a vararg function */ + idx_args = 2; + duk_require_callable(ctx, 0); + break; + default: /* Reflect.construct() */ + DUK_ASSERT(magic == 2); + duk_require_constructable(ctx, 0); + nargs = duk_get_top(ctx); + if (nargs < 2) { + DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); + } + if (nargs >= 3 && !duk_strict_equals(ctx, 0, 2)) { + /* XXX: [[Construct]] newTarget currently unsupported */ + DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx); + } + idx_args = 1; + break; } - duk_insert(ctx, 0); - DUK_ASSERT_TOP(ctx, 3); - DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT", - (duk_tval *) duk_get_tval(ctx, 0), - (duk_tval *) duk_get_tval(ctx, 1), - (duk_tval *) duk_get_tval(ctx, 2))); + if (magic != 2) { + DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT", + (duk_tval *) duk_get_tval(ctx, 0), + (duk_tval *) duk_get_tval(ctx, 1), + (duk_tval *) duk_get_tval(ctx, 2))); + } else { + /* thisArg is not applicable for Reflect.construct(). */ + DUK_DDD(DUK_DDDPRINT("func=%!iT, argArray=%!iT", + (duk_tval *) duk_get_tval(ctx, 0), + (duk_tval *) duk_get_tval(ctx, 1))); + } - /* [ func thisArg argArray ] */ + /* [ func thisArg? argArray ] */ - if (duk_is_null_or_undefined(ctx, 2)) { + mask = duk_get_type_mask(ctx, idx_args); + if (mask & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED)) { DUK_DDD(DUK_DDDPRINT("argArray is null/undefined, no args")); len = 0; - } else if (!duk_is_object(ctx, 2)) { - goto type_error; - } else { + } else if (mask & DUK_TYPE_MASK_OBJECT) { DUK_DDD(DUK_DDDPRINT("argArray is an object")); /* XXX: make this an internal helper */ - duk_get_prop_stridx(ctx, 2, DUK_STRIDX_LENGTH); + DUK_ASSERT(idx_args >= 0 && idx_args <= 0x7fffL); /* short variants would work, but avoid shifting */ + duk_get_prop_stridx(ctx, idx_args, DUK_STRIDX_LENGTH); len = (duk_idx_t) duk_to_uint32(ctx, -1); /* ToUint32() coercion required */ duk_pop(ctx); @@ -27519,25 +30234,38 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx) { DUK_DDD(DUK_DDDPRINT("argArray length is %ld", (long) len)); for (i = 0; i < len; i++) { - duk_get_prop_index(ctx, 2, i); + duk_get_prop_index(ctx, idx_args, i); } + } else { + goto type_error; } - duk_remove(ctx, 2); - DUK_ASSERT_TOP(ctx, 2 + len); + duk_remove(ctx, idx_args); + DUK_ASSERT_TOP(ctx, idx_args + len); - /* [ func thisArg arg1 ... argN ] */ + /* [ func thisArg? arg1 ... argN ] */ - DUK_DDD(DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%ld", - (duk_tval *) duk_get_tval(ctx, 0), - (duk_tval *) duk_get_tval(ctx, 1), - (long) len)); - duk_call_method(ctx, len); + if (magic != 2) { + /* Function.prototype.apply() or Reflect.apply() */ + DUK_DDD(DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%ld", + (duk_tval *) duk_get_tval(ctx, 0), + (duk_tval *) duk_get_tval(ctx, 1), + (long) len)); + duk_call_method(ctx, len); + } else { + /* Reflect.construct() */ + DUK_DDD(DUK_DDDPRINT("construct, func=%!iT, len=%ld", + (duk_tval *) duk_get_tval(ctx, 0), + (long) len)); + duk_new(ctx, len); + } return 1; type_error: - return DUK_RET_TYPE_ERROR; + DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); } +#endif +#if defined(DUK_USE_FUNCTION_BUILTIN) DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx) { duk_idx_t nargs; @@ -27568,7 +30296,9 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx) { duk_call_method(ctx, nargs - 1); return 1; } +#endif /* DUK_USE_FUNCTION_BUILTIN */ +#if defined(DUK_USE_FUNCTION_BUILTIN) /* XXX: the implementation now assumes "chained" bound functions, * whereas "collapsed" bound functions (where there is ever only * one bound function which directly points to a non-bound, final @@ -27576,6 +30306,7 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx) { * merges argument lists etc here. */ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h_bound; duk_hobject *h_target; duk_idx_t nargs; @@ -27590,30 +30321,26 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) { DUK_ASSERT(nargs >= 1); duk_push_this(ctx); - if (!duk_is_callable(ctx, -1)) { - DUK_DDD(DUK_DDDPRINT("func is not callable")); - goto type_error; - } + duk_require_callable(ctx, -1); /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs total) */ DUK_ASSERT_TOP(ctx, nargs + 1); /* create bound function object */ - duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BOUND | - DUK_HOBJECT_FLAG_CONSTRUCTABLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION), - DUK_BIDX_FUNCTION_PROTOTYPE); - h_bound = duk_get_hobject(ctx, -1); + h_bound = duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BOUNDFUNC | + DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION), + DUK_BIDX_FUNCTION_PROTOTYPE); DUK_ASSERT(h_bound != NULL); /* [ thisArg arg1 ... argN func boundFunc ] */ - duk_dup(ctx, -2); /* func */ - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); + duk_dup_m2(ctx); /* func */ + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); - duk_dup(ctx, 0); /* thisArg */ - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); + duk_dup_0(ctx); /* thisArg */ + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); duk_push_array(ctx); @@ -27623,35 +30350,55 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) { duk_dup(ctx, 1 + i); duk_put_prop_index(ctx, -2, i); } - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE); /* [ thisArg arg1 ... argN func boundFunc ] */ - /* bound function 'length' property is interesting */ h_target = duk_get_hobject(ctx, -2); + + /* internal prototype must be copied from the target */ + if (h_target != NULL) { + /* For lightfuncs Function.prototype is used and is already in place. */ + DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_bound, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_target)); + } + + /* bound function 'length' property is interesting */ if (h_target == NULL || /* lightfunc */ DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) { /* For lightfuncs, simply read the virtual property. */ duk_int_t tmp; - duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH); + duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH); tmp = duk_to_int(ctx, -1) - (nargs - 1); /* step 15.a */ duk_pop(ctx); duk_push_int(ctx, (tmp < 0 ? 0 : tmp)); } else { duk_push_int(ctx, 0); } - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); /* attrs in E5 Section 15.3.5.1 */ + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); /* attrs in E6 Section 9.2.4 */ /* caller and arguments must use the same thrower, [[ThrowTypeError]] */ - duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE); - duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE); + duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER); + duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS); - /* these non-standard properties are copied for convenience */ /* XXX: 'copy properties' API call? */ - duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_WC); - duk_get_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC); +#if defined(DUK_USE_FUNC_NAME_PROPERTY) + duk_push_string(ctx, "bound "); /* ES2015 19.2.3.2. */ + duk_get_prop_stridx_short(ctx, -3, DUK_STRIDX_NAME); + if (!duk_is_string_notsymbol(ctx, -1)) { + /* ES2015 has requirement to check that .name of target is a string + * (also must check for Symbol); if not, targetName should be the + * empty string. ES2015 19.2.3.2. + */ + duk_pop(ctx); + duk_push_hstring_empty(ctx); + } + duk_concat(ctx, 2); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); +#endif +#if defined(DUK_USE_FUNC_FILENAME_PROPERTY) + duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_FILE_NAME); + duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C); +#endif /* The 'strict' flag is copied to get the special [[Get]] of E5.1 * Section 15.3.5.4 to apply when a 'caller' value is a strict bound @@ -27667,16 +30414,13 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) { DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(ctx, -1))); return 1; - - type_error: - return DUK_RET_TYPE_ERROR; } -#line 1 "duk_bi_global.c" +#endif /* DUK_USE_FUNCTION_BUILTIN */ /* * Global object built-ins */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ /* * Encoding/decoding helpers @@ -27744,7 +30488,7 @@ DUK_LOCAL const duk_uint8_t duk__decode_uri_component_reserved_table[16] = { DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */ }; -#ifdef DUK_USE_SECTION_B +#if defined(DUK_USE_SECTION_B) /* E5.1 Section B.2.2, step 7. */ DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = { DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ @@ -27758,8 +30502,6 @@ DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = { }; #endif /* DUK_USE_SECTION_B */ -#undef DUK__MKBITS - typedef struct { duk_hthread *thr; duk_hstring *h_str; @@ -27813,7 +30555,7 @@ DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback ca DUK_BW_COMPACT(thr, &tfm_ctx->bw); - duk_to_string(ctx, -1); + (void) duk_buffer_to_string(ctx, -1); /* Safe if transform is safe. */ return 1; } @@ -27865,7 +30607,7 @@ DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ct len = duk_unicode_encode_xutf8((duk_ucodepoint_t) cp, xutf8_buf); for (i = 0; i < len; i++) { - t = (int) xutf8_buf[i]; + t = (duk_small_int_t) xutf8_buf[i]; DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr, &tfm_ctx->bw, DUK_ASC_PERCENT, @@ -27876,7 +30618,7 @@ DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ct return; uri_error: - DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input"); + DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT); } DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { @@ -28014,10 +30756,10 @@ DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ct return; uri_error: - DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input"); + DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT); } -#ifdef DUK_USE_SECTION_B +#if defined(DUK_USE_SECTION_B) DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { DUK_UNREF(udata); @@ -28054,7 +30796,7 @@ DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, c return; esc_error: - DUK_ERROR_TYPE(tfm_ctx->thr, "invalid input"); + DUK_ERROR_TYPE(tfm_ctx->thr, DUK_STR_INVALID_INPUT); } DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { @@ -28098,7 +30840,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) { duk_activation *act_caller; duk_activation *act_eval; duk_activation *act; - duk_hcompiledfunction *func; + duk_hcompfunc *func; duk_hobject *outer_lex_env; duk_hobject *outer_var_env; duk_bool_t this_to_global = 1; @@ -28118,8 +30860,9 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) { * activation doesn't exist, call must be indirect. */ - h = duk_get_hstring(ctx, 0); + h = duk_get_hstring_notsymbol(ctx, 0); if (!h) { + /* Symbol must be returned as is, like any non-string values. */ return 1; /* return arg as-is */ } @@ -28161,9 +30904,8 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) { (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), (duk_size_t) DUK_HSTRING_GET_BYTELEN(h), comp_flags); - func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1); - DUK_ASSERT(func != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func)); + func = (duk_hcompfunc *) duk_known_hobject(ctx, -1); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func)); /* [ source template ] */ @@ -28194,18 +30936,15 @@ 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 + level; /* caller */ act_lex_env = act->lex_env; act = NULL; /* invalidated */ - (void) duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - act_lex_env); - new_env = duk_require_hobject(ctx, -1); + new_env = duk_push_object_helper_proto(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), + act_lex_env); DUK_ASSERT(new_env != NULL); - DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", - (duk_heaphdr *) new_env)); + DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env)); outer_lex_env = new_env; outer_var_env = new_env; @@ -28270,15 +31009,19 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) { * Parsing of ints and floats */ +#if defined(DUK_USE_GLOBAL_BUILTIN) DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) { duk_int32_t radix; duk_small_uint_t s2n_flags; DUK_ASSERT_TOP(ctx, 2); - duk_to_string(ctx, 0); + duk_to_string(ctx, 0); /* Reject symbols. */ radix = duk_to_int32(ctx, 1); + /* While parseInt() recognizes 0xdeadbeef, it doesn't recognize + * ES2015 0o123 or 0b10001. + */ s2n_flags = DUK_S2N_FLAG_TRIM_WHITE | DUK_S2N_FLAG_ALLOW_GARBAGE | DUK_S2N_FLAG_ALLOW_PLUS | @@ -28304,7 +31047,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) { radix = 10; } - duk_dup(ctx, 0); + duk_dup_0(ctx); duk_numconv_parse(ctx, radix, s2n_flags); return 1; @@ -28312,13 +31055,15 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) { duk_push_nan(ctx); return 1; } +#endif /* DUK_USE_GLOBAL_BUILTIN */ +#if defined(DUK_USE_GLOBAL_BUILTIN) DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx) { duk_small_uint_t s2n_flags; duk_int32_t radix; DUK_ASSERT_TOP(ctx, 1); - duk_to_string(ctx, 0); + duk_to_string(ctx, 0); /* Reject symbols. */ radix = 10; @@ -28337,27 +31082,33 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx) { duk_numconv_parse(ctx, radix, s2n_flags); return 1; } +#endif /* DUK_USE_GLOBAL_BUILTIN */ /* * Number checkers */ +#if defined(DUK_USE_GLOBAL_BUILTIN) DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx) { duk_double_t d = duk_to_number(ctx, 0); duk_push_boolean(ctx, DUK_ISNAN(d)); return 1; } +#endif /* DUK_USE_GLOBAL_BUILTIN */ +#if defined(DUK_USE_GLOBAL_BUILTIN) DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx) { duk_double_t d = duk_to_number(ctx, 0); duk_push_boolean(ctx, DUK_ISFINITE(d)); return 1; } +#endif /* DUK_USE_GLOBAL_BUILTIN */ /* * URI handling */ +#if defined(DUK_USE_GLOBAL_BUILTIN) DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx) { return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table); } @@ -28374,7 +31125,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ct return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table); } -#ifdef DUK_USE_SECTION_B +#if defined(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, (const void *) NULL); } @@ -28382,585 +31133,12 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) { DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) { 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) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} - -DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} #endif /* DUK_USE_SECTION_B */ +#endif /* DUK_USE_GLOBAL_BUILTIN */ -#if defined(DUK_USE_BROWSER_LIKE) && (defined(DUK_USE_FILE_IO) || defined(DUK_USE_DEBUGGER_SUPPORT)) -DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) { - duk_hthread *thr = (duk_hthread *) ctx; - duk_int_t magic; - duk_idx_t nargs; - const duk_uint8_t *buf; - duk_size_t sz_buf; - const char nl = (const char) DUK_ASC_LF; -#ifndef DUK_USE_PREFER_SIZE - duk_uint8_t buf_stack[256]; -#endif -#ifdef DUK_USE_FILE_IO - duk_file *f_out; -#endif - - DUK_UNREF(thr); - - magic = duk_get_current_magic(ctx); - DUK_UNREF(magic); - - nargs = duk_get_top(ctx); - - /* If argument count is 1 and first argument is a buffer, write the buffer - * as raw data into the file without a newline; this allows exact control - * over stdout/stderr without an additional entrypoint (useful for now). - * - * Otherwise current print/alert semantics are to ToString() coerce - * arguments, join them with a single space, and append a newline. - */ - - if (nargs == 1 && duk_is_buffer(ctx, 0)) { - buf = (const duk_uint8_t *) duk_get_buffer(ctx, 0, &sz_buf); - DUK_ASSERT(buf != NULL); - } else if (nargs > 0) { -#ifdef DUK_USE_PREFER_SIZE - /* Compact but lots of churn. */ - duk_push_hstring_stridx(thr, DUK_STRIDX_SPACE); - duk_insert(ctx, 0); - duk_join(ctx, nargs); - duk_push_string(thr, "\n"); - duk_concat(ctx, 2); - buf = (const duk_uint8_t *) duk_get_lstring(ctx, -1, &sz_buf); - DUK_ASSERT(buf != NULL); -#else /* DUK_USE_PREFER_SIZE */ - /* Higher footprint, less churn. */ - duk_idx_t i; - duk_size_t sz_str; - const duk_uint8_t *p_str; - duk_uint8_t *p; - - sz_buf = (duk_size_t) nargs; /* spaces (nargs - 1) + newline */ - for (i = 0; i < nargs; i++) { - (void) duk_to_lstring(ctx, i, &sz_str); - sz_buf += sz_str; - } - - if (sz_buf <= sizeof(buf_stack)) { - p = (duk_uint8_t *) buf_stack; - } else { - p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, sz_buf); - DUK_ASSERT(p != NULL); - } - - 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); - DUK_MEMCPY((void *) p, (const void *) p_str, sz_str); - p += sz_str; - *p++ = (duk_uint8_t) (i == nargs - 1 ? DUK_ASC_LF : DUK_ASC_SPACE); - } - DUK_ASSERT((const duk_uint8_t *) p == buf + sz_buf); -#endif /* DUK_USE_PREFER_SIZE */ - } else { - buf = (const duk_uint8_t *) &nl; - sz_buf = 1; - } - - /* 'buf' contains the string to write, 'sz_buf' contains the length - * (which may be zero). - */ - DUK_ASSERT(buf != NULL); - - if (sz_buf == 0) { - return 0; - } - -#ifdef DUK_USE_FILE_IO - f_out = (magic ? DUK_STDERR : DUK_STDOUT); - DUK_FWRITE((const void *) buf, 1, (size_t) sz_buf, f_out); - DUK_FFLUSH(f_out); -#endif - -#if defined(DUK_USE_DEBUGGER_SUPPORT) && defined(DUK_USE_DEBUGGER_FWD_PRINTALERT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { - duk_debug_write_notify(thr, magic ? DUK_DBG_CMD_ALERT : DUK_DBG_CMD_PRINT); - duk_debug_write_string(thr, (const char *) buf, sz_buf); - duk_debug_write_eom(thr); - } -#endif - return 0; -} -#elif defined(DUK_USE_BROWSER_LIKE) /* print provider */ -DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) { - DUK_UNREF(ctx); - return 0; -} -#else /* print provider */ -DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} -#endif /* print provider */ - -/* - * CommonJS require() and modules support - */ - -#if defined(DUK_USE_COMMONJS_MODULES) -DUK_LOCAL void duk__bi_global_resolve_module_id(duk_context *ctx, const char *req_id, const char *mod_id) { - duk_hthread *thr = (duk_hthread *) ctx; - duk_uint8_t buf[DUK_BI_COMMONJS_MODULE_ID_LIMIT]; - duk_uint8_t *p; - duk_uint8_t *q; - duk_uint8_t *q_last; /* last component */ - duk_int_t int_rc; - - DUK_ASSERT(req_id != NULL); - /* mod_id may be NULL */ - - /* - * A few notes on the algorithm: - * - * - Terms are not allowed to begin with a period unless the term - * is either '.' or '..'. This simplifies implementation (and - * is within CommonJS modules specification). - * - * - There are few output bound checks here. This is on purpose: - * the resolution input is length checked and the output is never - * longer than the input. The resolved output is written directly - * over the input because it's never longer than the input at any - * point in the algorithm. - * - * - Non-ASCII characters are processed as individual bytes and - * need no special treatment. However, U+0000 terminates the - * algorithm; this is not an issue because U+0000 is not a - * desirable term character anyway. - */ - - /* - * Set up the resolution input which is the requested ID directly - * (if absolute or no current module path) or with current module - * ID prepended (if relative and current module path exists). - * - * Suppose current module is 'foo/bar' and relative path is './quux'. - * The 'bar' component must be replaced so the initial input here is - * 'foo/bar/.././quux'. - */ - - if (mod_id != NULL && req_id[0] == '.') { - int_rc = DUK_SNPRINTF((char *) buf, sizeof(buf), "%s/../%s", mod_id, req_id); - } else { - int_rc = DUK_SNPRINTF((char *) buf, sizeof(buf), "%s", req_id); - } - if (int_rc >= (duk_int_t) sizeof(buf) || int_rc < 0) { - /* Potentially truncated, NUL not guaranteed in any case. - * The (int_rc < 0) case should not occur in practice. - */ - DUK_DD(DUK_DDPRINT("resolve error: temporary working module ID doesn't fit into resolve buffer")); - goto resolve_error; - } - DUK_ASSERT(DUK_STRLEN((const char *) buf) < sizeof(buf)); /* at most sizeof(buf) - 1 */ - - DUK_DDD(DUK_DDDPRINT("input module id: '%s'", (const char *) buf)); - - /* - * Resolution loop. At the top of the loop we're expecting a valid - * term: '.', '..', or a non-empty identifier not starting with a period. - */ - - p = buf; - q = buf; - for (;;) { - duk_uint_fast8_t c; - - /* Here 'p' always points to the start of a term. - * - * We can also unconditionally reset q_last here: if this is - * the last (non-empty) term q_last will have the right value - * on loop exit. - */ - - DUK_ASSERT(p >= q); /* output is never longer than input during resolution */ - - DUK_DDD(DUK_DDDPRINT("resolve loop top: p -> '%s', q=%p, buf=%p", - (const char *) p, (void *) q, (void *) buf)); - - q_last = q; - - c = *p++; - if (DUK_UNLIKELY(c == 0)) { - DUK_DD(DUK_DDPRINT("resolve error: requested ID must end with a non-empty term")); - goto resolve_error; - } else if (DUK_UNLIKELY(c == '.')) { - c = *p++; - if (c == '/') { - /* Term was '.' and is eaten entirely (including dup slashes). */ - goto eat_dup_slashes; - } - if (c == '.' && *p == '/') { - /* Term was '..', backtrack resolved name by one component. - * q[-1] = previous slash (or beyond start of buffer) - * q[-2] = last char of previous component (or beyond start of buffer) - */ - p++; /* eat (first) input slash */ - DUK_ASSERT(q >= buf); - if (q == buf) { - DUK_DD(DUK_DDPRINT("resolve error: term was '..' but nothing to backtrack")); - goto resolve_error; - } - DUK_ASSERT(*(q - 1) == '/'); - q--; /* backtrack to last output slash (dups already eliminated) */ - for (;;) { - /* Backtrack to previous slash or start of buffer. */ - DUK_ASSERT(q >= buf); - if (q == buf) { - break; - } - if (*(q - 1) == '/') { - break; - } - q--; - } - goto eat_dup_slashes; - } - DUK_DD(DUK_DDPRINT("resolve error: term begins with '.' but is not '.' or '..' (not allowed now)")); - goto resolve_error; - } else if (DUK_UNLIKELY(c == '/')) { - /* e.g. require('/foo'), empty terms not allowed */ - DUK_DD(DUK_DDPRINT("resolve error: empty term (not allowed now)")); - goto resolve_error; - } else { - for (;;) { - /* Copy term name until end or '/'. */ - *q++ = c; - c = *p++; - if (DUK_UNLIKELY(c == 0)) { - /* This was the last term, and q_last was - * updated to match this term at loop top. - */ - goto loop_done; - } else if (DUK_UNLIKELY(c == '/')) { - *q++ = '/'; - break; - } else { - /* write on next loop */ - } - } - } - - eat_dup_slashes: - for (;;) { - /* eat dup slashes */ - c = *p; - if (DUK_LIKELY(c != '/')) { - break; - } - p++; - } - } - loop_done: - /* Output #1: resolved absolute name */ - DUK_ASSERT(q >= buf); - duk_push_lstring(ctx, (const char *) buf, (size_t) (q - buf)); - - /* Output #2: last component name */ - DUK_ASSERT(q >= q_last); - DUK_ASSERT(q_last >= buf); - duk_push_lstring(ctx, (const char *) q_last, (size_t) (q - q_last)); - - DUK_DD(DUK_DDPRINT("after resolving module name: buf=%p, q_last=%p, q=%p", - (void *) buf, (void *) q_last, (void *) q)); - return; - - resolve_error: - DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "cannot resolve module id: %s", (const char *) req_id); -} -#endif /* DUK_USE_COMMONJS_MODULES */ - -#if defined(DUK_USE_COMMONJS_MODULES) -/* Stack indices for better readability */ -#define DUK__IDX_REQUESTED_ID 0 /* Module id requested */ -#define DUK__IDX_REQUIRE 1 /* Current require() function */ -#define DUK__IDX_REQUIRE_ID 2 /* The base ID of the current require() function, resolution base */ -#define DUK__IDX_RESOLVED_ID 3 /* Resolved, normalized absolute module ID */ -#define DUK__IDX_LASTCOMP 4 /* Last component name in resolved path */ -#define DUK__IDX_DUKTAPE 5 /* Duktape object */ -#define DUK__IDX_MODLOADED 6 /* Duktape.modLoaded[] module cache */ -#define DUK__IDX_UNDEFINED 7 /* 'undefined', artifact of lookup */ -#define DUK__IDX_FRESH_REQUIRE 8 /* New require() function for module, updated resolution base */ -#define DUK__IDX_EXPORTS 9 /* Default exports table */ -#define DUK__IDX_MODULE 10 /* Module object containing module.exports, etc */ - -DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) { - const char *str_req_id; /* requested identifier */ - const char *str_mod_id; /* require.id of current module */ - duk_int_t pcall_rc; - - /* NOTE: we try to minimize code size by avoiding unnecessary pops, - * so the stack looks a bit cluttered in this function. DUK_ASSERT_TOP() - * assertions are used to ensure stack configuration is correct at each - * step. - */ - - /* - * Resolve module identifier into canonical absolute form. - */ - - str_req_id = duk_require_string(ctx, DUK__IDX_REQUESTED_ID); - duk_push_current_function(ctx); - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_ID); - str_mod_id = duk_get_string(ctx, DUK__IDX_REQUIRE_ID); /* ignore non-strings */ - DUK_DDD(DUK_DDDPRINT("resolve module id: requested=%!T, currentmodule=%!T", - duk_get_tval(ctx, DUK__IDX_REQUESTED_ID), - duk_get_tval(ctx, DUK__IDX_REQUIRE_ID))); - duk__bi_global_resolve_module_id(ctx, str_req_id, str_mod_id); - str_req_id = NULL; - str_mod_id = NULL; - DUK_DDD(DUK_DDDPRINT("resolved module id: requested=%!T, currentmodule=%!T, result=%!T, lastcomp=%!T", - duk_get_tval(ctx, DUK__IDX_REQUESTED_ID), - duk_get_tval(ctx, DUK__IDX_REQUIRE_ID), - duk_get_tval(ctx, DUK__IDX_RESOLVED_ID), - duk_get_tval(ctx, DUK__IDX_LASTCOMP))); - - /* [ requested_id require require.id resolved_id last_comp ] */ - DUK_ASSERT_TOP(ctx, DUK__IDX_LASTCOMP + 1); - - /* - * Cached module check. - * - * If module has been loaded or its loading has already begun without - * finishing, return the same cached value ('exports'). The value is - * registered when module load starts so that circular references can - * be supported to some extent. - */ - - duk_push_hobject_bidx(ctx, DUK_BIDX_DUKTAPE); - duk_get_prop_stridx(ctx, DUK__IDX_DUKTAPE, DUK_STRIDX_MOD_LOADED); /* Duktape.modLoaded */ - (void) duk_require_hobject(ctx, DUK__IDX_MODLOADED); - DUK_ASSERT_TOP(ctx, DUK__IDX_MODLOADED + 1); - - duk_dup(ctx, DUK__IDX_RESOLVED_ID); - if (duk_get_prop(ctx, DUK__IDX_MODLOADED)) { - /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded Duktape.modLoaded[id] ] */ - DUK_DD(DUK_DDPRINT("module already loaded: %!T", - duk_get_tval(ctx, DUK__IDX_RESOLVED_ID))); - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_EXPORTS); /* return module.exports */ - return 1; - } - DUK_ASSERT_TOP(ctx, DUK__IDX_UNDEFINED + 1); - - /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined ] */ - - /* - * Module not loaded (and loading not started previously). - * - * Create a new require() function with 'id' set to resolved ID - * of module being loaded. Also create 'exports' and 'module' - * tables but don't register exports to the loaded table yet. - * We don't want to do that unless the user module search callbacks - * succeeds in finding the module. - */ - - DUK_D(DUK_DPRINT("loading module %!T, resolution base %!T, requested ID %!T -> resolved ID %!T, last component %!T", - duk_get_tval(ctx, DUK__IDX_RESOLVED_ID), - duk_get_tval(ctx, DUK__IDX_REQUIRE_ID), - duk_get_tval(ctx, DUK__IDX_REQUESTED_ID), - duk_get_tval(ctx, DUK__IDX_RESOLVED_ID), - duk_get_tval(ctx, DUK__IDX_LASTCOMP))); - - /* Fresh require: require.id is left configurable (but not writable) - * so that is not easy to accidentally tweak it, but it can still be - * done with Object.defineProperty(). - * - * XXX: require.id could also be just made non-configurable, as there - * is no practical reason to touch it. - */ - duk_push_c_function(ctx, duk_bi_global_object_require, 1 /*nargs*/); - duk_push_hstring_stridx(ctx, DUK_STRIDX_REQUIRE); - duk_xdef_prop_stridx(ctx, DUK__IDX_FRESH_REQUIRE, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); - duk_dup(ctx, DUK__IDX_RESOLVED_ID); - duk_xdef_prop_stridx(ctx, DUK__IDX_FRESH_REQUIRE, DUK_STRIDX_ID, DUK_PROPDESC_FLAGS_C); /* a fresh require() with require.id = resolved target module id */ - - /* Module table: - * - module.exports: initial exports table (may be replaced by user) - * - module.id is non-writable and non-configurable, as the CommonJS - * spec suggests this if possible - * - module.filename: not set, defaults to resolved ID if not explicitly - * set by modSearch() (note capitalization, not .fileName, matches Node.js) - * - module.name: not set, defaults to last component of resolved ID if - * not explicitly set by modSearch() - */ - duk_push_object(ctx); /* exports */ - duk_push_object(ctx); /* module */ - duk_dup(ctx, DUK__IDX_EXPORTS); - duk_xdef_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS, DUK_PROPDESC_FLAGS_WC); /* module.exports = exports */ - duk_dup(ctx, DUK__IDX_RESOLVED_ID); /* resolved id: require(id) must return this same module */ - duk_xdef_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_ID, DUK_PROPDESC_FLAGS_NONE); /* module.id = resolved_id */ - duk_compact(ctx, DUK__IDX_MODULE); /* module table remains registered to modLoaded, minimize its size */ - DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 1); - - DUK_DD(DUK_DDPRINT("module table created: %!T", duk_get_tval(ctx, DUK__IDX_MODULE))); - - /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module ] */ - - /* Register the module table early to modLoaded[] so that we can - * support circular references even in modSearch(). If an error - * is thrown, we'll delete the reference. - */ - duk_dup(ctx, DUK__IDX_RESOLVED_ID); - duk_dup(ctx, DUK__IDX_MODULE); - duk_put_prop(ctx, DUK__IDX_MODLOADED); /* Duktape.modLoaded[resolved_id] = module */ - - /* - * Call user provided module search function and build the wrapped - * module source code (if necessary). The module search function - * can be used to implement pure Ecmacsript, pure C, and mixed - * Ecmascript/C modules. - * - * The module search function can operate on the exports table directly - * (e.g. DLL code can register values to it). It can also return a - * string which is interpreted as module source code (if a non-string - * is returned the module is assumed to be a pure C one). If a module - * cannot be found, an error must be thrown by the user callback. - * - * Because Duktape.modLoaded[] already contains the module being - * loaded, circular references for C modules should also work - * (although expected to be quite rare). - */ - - duk_push_string(ctx, "(function(require,exports,module){"); - - /* Duktape.modSearch(resolved_id, fresh_require, exports, module). */ - duk_get_prop_stridx(ctx, DUK__IDX_DUKTAPE, DUK_STRIDX_MOD_SEARCH); /* Duktape.modSearch */ - duk_dup(ctx, DUK__IDX_RESOLVED_ID); - duk_dup(ctx, DUK__IDX_FRESH_REQUIRE); - duk_dup(ctx, DUK__IDX_EXPORTS); - duk_dup(ctx, DUK__IDX_MODULE); /* [ ... Duktape.modSearch resolved_id last_comp fresh_require exports module ] */ - pcall_rc = duk_pcall(ctx, 4 /*nargs*/); /* -> [ ... source ] */ - DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 3); - - if (pcall_rc != DUK_EXEC_SUCCESS) { - /* Delete entry in Duktape.modLoaded[] and rethrow. */ - goto delete_rethrow; - } - - /* If user callback did not return source code, module loading - * is finished (user callback initialized exports table directly). - */ - if (!duk_is_string(ctx, -1)) { - /* User callback did not return source code, so module loading - * is finished: just update modLoaded with final module.exports - * and we're done. - */ - goto return_exports; - } - - /* Finish the wrapped module source. Force module.filename as the - * function .fileName so it gets set for functions defined within a - * module. This also ensures loggers created within the module get - * the module ID (or overridden filename) as their default logger name. - * (Note capitalization: .filename matches Node.js while .fileName is - * used elsewhere in Duktape.) - */ - duk_push_string(ctx, "})"); - duk_concat(ctx, 3); - if (!duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_FILENAME)) { - /* module.filename for .fileName, default to resolved ID if - * not present. - */ - duk_pop(ctx); - duk_dup(ctx, DUK__IDX_RESOLVED_ID); - } - duk_eval_raw(ctx, NULL, 0, DUK_COMPILE_EVAL); - - /* Module has now evaluated to a wrapped module function. Force its - * .name to match module.name (defaults to last component of resolved - * ID) so that it is shown in stack traces too. Note that we must not - * introduce an actual name binding into the function scope (which is - * usually the case with a named function) because it would affect the - * scope seen by the module and shadow accesses to globals of the same name. - * This is now done by compiling the function as anonymous and then forcing - * its .name without setting a "has name binding" flag. - */ - - duk_push_hstring_stridx(ctx, DUK_STRIDX_NAME); - if (!duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_NAME)) { - /* module.name for .name, default to last component if - * not present. - */ - duk_pop(ctx); - duk_dup(ctx, DUK__IDX_LASTCOMP); - } - duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE); - - /* - * Call the wrapped module function. - * - * Use a protected call so that we can update Duktape.modLoaded[resolved_id] - * even if the module throws an error. - */ - - /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func ] */ - DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 2); - - duk_dup(ctx, DUK__IDX_EXPORTS); /* exports (this binding) */ - duk_dup(ctx, DUK__IDX_FRESH_REQUIRE); /* fresh require (argument) */ - duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS); /* relookup exports from module.exports in case it was changed by modSearch */ - duk_dup(ctx, DUK__IDX_MODULE); /* module (argument) */ - DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 6); - - /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func exports fresh_require exports module ] */ - - pcall_rc = duk_pcall_method(ctx, 3 /*nargs*/); - if (pcall_rc != DUK_EXEC_SUCCESS) { - /* Module loading failed. Node.js will forget the module - * registration so that another require() will try to load - * the module again. Mimic that behavior. - */ - goto delete_rethrow; - } - - /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module result(ignored) ] */ - DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 2); - - /* fall through */ - - return_exports: - duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS); - duk_compact(ctx, -1); /* compact the exports table */ - return 1; /* return module.exports */ - - delete_rethrow: - duk_dup(ctx, DUK__IDX_RESOLVED_ID); - duk_del_prop(ctx, DUK__IDX_MODLOADED); /* delete Duktape.modLoaded[resolved_id] */ - duk_throw(ctx); /* rethrow original error */ - return 0; /* not reachable */ -} - -#undef DUK__IDX_REQUESTED_ID -#undef DUK__IDX_REQUIRE -#undef DUK__IDX_REQUIRE_ID -#undef DUK__IDX_RESOLVED_ID -#undef DUK__IDX_LASTCOMP -#undef DUK__IDX_DUKTAPE -#undef DUK__IDX_MODLOADED -#undef DUK__IDX_UNDEFINED -#undef DUK__IDX_FRESH_REQUIRE -#undef DUK__IDX_EXPORTS -#undef DUK__IDX_MODULE -#else -DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) { - DUK_UNREF(ctx); - return DUK_RET_UNSUPPORTED_ERROR; -} -#endif /* DUK_USE_COMMONJS_MODULES */ -#line 1 "duk_bi_json.c" +/* automatic undefs */ +#undef DUK__CHECK_BITMASK +#undef DUK__MKBITS /* * JSON built-ins. * @@ -28977,7 +31155,9 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) { * indeed correct! */ -/* include removed: duk_internal.h */ +/* #include duk_internal.h -> already included */ + +#if defined(DUK_USE_JSON_SUPPORT) /* * Local defines and forward declarations. @@ -28991,13 +31171,15 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) { DUK_LOCAL_DECL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx); DUK_LOCAL_DECL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx); +#if defined(DUK_USE_JX) DUK_LOCAL_DECL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx); +#endif DUK_LOCAL_DECL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx); DUK_LOCAL_DECL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx); DUK_LOCAL_DECL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n); DUK_LOCAL_DECL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx); DUK_LOCAL_DECL void duk__dec_string(duk_json_dec_ctx *js_ctx); -#ifdef DUK_USE_JX +#if defined(DUK_USE_JX) DUK_LOCAL_DECL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx); DUK_LOCAL_DECL void duk__dec_pointer(duk_json_dec_ctx *js_ctx); DUK_LOCAL_DECL void duk__dec_buffer(duk_json_dec_ctx *js_ctx); @@ -29034,7 +31216,9 @@ DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv #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); -DUK_LOCAL_DECL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj); +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_LOCAL_DECL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj); +#endif #endif DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth); @@ -29200,10 +31384,12 @@ DUK_LOCAL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx) { js_ctx->p = p; } +#if defined(DUK_USE_JX) DUK_LOCAL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx) { DUK_ASSERT(js_ctx->p <= js_ctx->p_end); return *js_ctx->p; } +#endif DUK_LOCAL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx) { DUK_ASSERT(js_ctx->p <= js_ctx->p_end); @@ -29259,8 +31445,7 @@ DUK_LOCAL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t st * have internal NULs. */ - DUK_ASSERT_DISABLE(stridx >= 0); /* unsigned */ - DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + DUK_ASSERT_STRIDX_VALID(stridx); h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx); DUK_ASSERT(h != NULL); @@ -29295,7 +31480,7 @@ DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_u * will match the default case (syntax error). */ cp = (duk_uint_fast32_t) duk__dec_get(js_ctx); - switch ((int) cp) { + switch (cp) { case DUK_ASC_BACKSLASH: break; case DUK_ASC_DOUBLEQUOTE: break; case DUK_ASC_SLASH: break; @@ -29308,7 +31493,7 @@ DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_u cp = duk__dec_decode_hex_escape(js_ctx, 4); break; } -#ifdef DUK_USE_JX +#if defined(DUK_USE_JX) case DUK_ASC_UC_U: { if (js_ctx->flag_ext_custom) { cp = duk__dec_decode_hex_escape(js_ctx, 8); @@ -29431,7 +31616,7 @@ DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) { #endif /* DUK_USE_JSON_DECSTRING_FASTPATH */ DUK_BW_SETPTR_AND_COMPACT(js_ctx->thr, bw, q); - duk_to_string(ctx, -1); + (void) duk_buffer_to_string(ctx, -1); /* Safe if input string is safe. */ /* [ ... str ] */ @@ -29442,7 +31627,7 @@ DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) { DUK_UNREACHABLE(); } -#ifdef DUK_USE_JX +#if defined(DUK_USE_JX) /* Decode a plain string consisting entirely of identifier characters. * Used to parse plain keys (e.g. "foo: 123"). */ @@ -29488,7 +31673,7 @@ DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) { } #endif /* DUK_USE_JX */ -#ifdef DUK_USE_JX +#if defined(DUK_USE_JX) DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) { duk_hthread *thr = js_ctx->thr; duk_context *ctx = (duk_context *) thr; @@ -29542,7 +31727,7 @@ DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) { } #endif /* DUK_USE_JX */ -#ifdef DUK_USE_JX +#if defined(DUK_USE_JX) DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) { duk_hthread *thr = js_ctx->thr; duk_context *ctx = (duk_context *) thr; @@ -29582,8 +31767,9 @@ DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) { p++; } + /* XXX: this is not very nice; unnecessary copy is made. */ src_len = (duk_size_t) (p - js_ctx->p); - buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_len); + buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, src_len); DUK_ASSERT(buf != NULL); DUK_MEMCPY((void *) buf, (const void *) js_ctx->p, src_len); duk_hex_decode(ctx, -1); @@ -29731,7 +31917,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) { if (x == DUK_ASC_DOUBLEQUOTE) { duk__dec_string(js_ctx); -#ifdef DUK_USE_JX +#if defined(DUK_USE_JX) } else if (js_ctx->flag_ext_custom && duk_unicode_is_identifier_start((duk_codepoint_t) x)) { duk__dec_plain_string(js_ctx); @@ -29852,7 +32038,7 @@ DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) { if (x == DUK_ASC_DOUBLEQUOTE) { duk__dec_string(js_ctx); } else if ((x >= DUK_ASC_0 && x <= DUK_ASC_9) || (x == DUK_ASC_MINUS)) { -#ifdef DUK_USE_JX +#if defined(DUK_USE_JX) if (js_ctx->flag_ext_custom && x == DUK_ASC_MINUS && duk__dec_peek(js_ctx) == DUK_ASC_UC_I) { duk__dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY); /* "-Infinity", '-' has been eaten */ duk_push_number(ctx, -DUK_DOUBLE_INFINITY); @@ -29873,7 +32059,7 @@ DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) { } else if (x == DUK_ASC_LC_N) { duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_NULL); duk_push_null(ctx); -#ifdef DUK_USE_JX +#if defined(DUK_USE_JX) } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LC_U) { duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_UNDEFINED); duk_push_undefined(ctx); @@ -29936,10 +32122,8 @@ DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) { (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1))); - /* XXX: push_uint_string / push_u32_string */ duk_dup_top(ctx); - duk_push_uint(ctx, (duk_uint_t) i); - duk_to_string(ctx, -1); /* -> [ ... holder name val val ToString(i) ] */ + (void) duk_push_uint_to_hstring(ctx, (duk_uint_t) i); /* -> [ ... holder name val val ToString(i) ] */ duk__dec_reviver_walk(js_ctx); /* -> [ ... holder name val new_elem ] */ if (duk_is_undefined(ctx, -1)) { @@ -29963,8 +32147,8 @@ DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) { (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1))); /* [ ... holder name val enum obj_key ] */ - duk_dup(ctx, -3); - duk_dup(ctx, -2); + duk_dup_m3(ctx); + duk_dup_m2(ctx); /* [ ... holder name val enum obj_key val obj_key ] */ duk__dec_reviver_walk(js_ctx); @@ -30034,8 +32218,7 @@ DUK_LOCAL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *str) { DUK_LOCAL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx) { duk_hstring *h; - DUK_ASSERT_DISABLE(stridx >= 0); /* unsigned */ - DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + DUK_ASSERT_STRIDX_VALID(stridx); h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx); DUK_ASSERT(h != NULL); @@ -30066,7 +32249,7 @@ DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uin * (nybble_count << 16) | (escape_char1) | (escape_char2) */ -#ifdef DUK_USE_JX +#if defined(DUK_USE_JX) if (DUK_LIKELY(cp < 0x100UL)) { if (DUK_UNLIKELY(js_ctx->flag_ext_custom)) { tmp = DUK__MKESC(2, DUK_ASC_BACKSLASH, DUK_ASC_LC_X); @@ -30078,7 +32261,7 @@ DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uin if (DUK_LIKELY(cp < 0x10000UL)) { tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U); } else { -#ifdef DUK_USE_JX +#if defined(DUK_USE_JX) if (DUK_LIKELY(js_ctx->flag_ext_custom)) { tmp = DUK__MKESC(8, DUK_ASC_BACKSLASH, DUK_ASC_UC_U); } else @@ -30272,7 +32455,7 @@ DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_st p = p_tmp + 1; } -#ifdef DUK_USE_NONSTD_JSON_ESC_U2028_U2029 +#if defined(DUK_USE_NONSTD_JSON_ESC_U2028_U2029) if (js_ctx->flag_ascii_only || cp == 0x2028 || cp == 0x2029) { #else if (js_ctx->flag_ascii_only) { @@ -30336,8 +32519,7 @@ DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) { /* [ ... number ] -> [ ... string ] */ duk_numconv_stringify(ctx, 10 /*radix*/, 0 /*digits*/, n2s_flags); } - h_str = duk_to_hstring(ctx, -1); - DUK_ASSERT(h_str != NULL); + h_str = duk_known_hstring(ctx, -1); DUK__EMIT_HSTR(js_ctx, h_str); return; } @@ -30479,8 +32661,8 @@ DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_d * 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. + /* The #if defined() 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. */ @@ -30534,8 +32716,8 @@ DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) { DUK_MEMZERO(buf, sizeof(buf)); - /* The #ifdef clutter here needs to handle the three cases: - * (1) JX+JC, (2) JX only, (3) JC only. + /* The #if defined() 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) @@ -30561,20 +32743,22 @@ DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) { } #endif /* DUK_USE_JX || DUK_USE_JC */ +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) #if defined(DUK_USE_JX) || defined(DUK_USE_JC) -DUK_LOCAL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj) { - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); +DUK_LOCAL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj) { + DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - if (h_bufobj->buf == NULL || !DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) { + if (h_bufobj->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) { DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); } else { /* Handle both full and partial slice (as long as covered). */ duk__enc_buffer_data(js_ctx, - (duk_uint8_t *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj), + (duk_uint8_t *) DUK_HBUFOBJ_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj), (duk_size_t) h_bufobj->length); } } #endif /* DUK_USE_JX || DUK_USE_JC */ +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* Indent helper. Calling code relies on js_ctx->recursion_depth also being * directly related to indent depth. @@ -30656,8 +32840,7 @@ DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_ * with overflow in a loop check object. */ - h_target = duk_get_hobject(ctx, -1); /* object or array */ - DUK_ASSERT(h_target != NULL); + h_target = duk_known_hobject(ctx, -1); /* object or array */ n = js_ctx->recursion_depth; if (DUK_UNLIKELY(n > DUK_JSON_ENC_LOOPARRAY)) { @@ -30707,8 +32890,7 @@ DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_t /* Loop check. */ - h_target = duk_get_hobject(ctx, *entry_top - 1); /* original target at entry_top - 1 */ - DUK_ASSERT(h_target != NULL); + h_target = duk_known_hobject(ctx, *entry_top - 1); /* original target at entry_top - 1 */ if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) { /* Previous entry was inside visited[], nothing to do. */ @@ -30776,8 +32958,9 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) { (duk_tval *) duk_get_tval(ctx, idx_obj), (duk_tval *) duk_get_tval(ctx, -1))); - h_key = duk_get_hstring(ctx, -1); + h_key = duk_known_hstring(ctx, -1); DUK_ASSERT(h_key != NULL); + DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(h_key)); /* proplist filtering; enum options */ prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw); if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { @@ -30853,9 +33036,7 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) { duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); } - /* XXX: duk_push_uint_string() */ - duk_push_uint(ctx, (duk_uint_t) i); - duk_to_string(ctx, -1); /* -> [ ... key ] */ + (void) duk_push_uint_to_hstring(ctx, (duk_uint_t) i); /* -> [ ... key ] */ /* [ ... key ] */ @@ -30894,7 +33075,6 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) { DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder) { duk_context *ctx = (duk_context *) js_ctx->thr; duk_hthread *thr = (duk_hthread *) ctx; - duk_hobject *h_tmp; duk_tval *tv; duk_tval *tv_holder; duk_tval *tv_key; @@ -30910,24 +33090,29 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_holder)); tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1); DUK_ASSERT(DUK_TVAL_IS_STRING(tv_key)); + DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING(tv_key))); /* Caller responsible. */ (void) duk_hobject_getprop(thr, tv_holder, tv_key); /* -> [ ... key val ] */ DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1))); - h_tmp = duk_get_hobject_or_lfunc_coerce(ctx, -1); - if (h_tmp != NULL) { - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_JSON); - h_tmp = duk_get_hobject_or_lfunc_coerce(ctx, -1); /* toJSON() can also be a lightfunc */ - - if (h_tmp != NULL && DUK_HOBJECT_IS_CALLABLE(h_tmp)) { + /* Standard JSON checks for .toJSON() only for actual objects; for + * example, setting Number.prototype.toJSON and then serializing a + * number won't invoke the .toJSON() method. However, lightfuncs and + * plain buffers mimic objects so we check for their .toJSON() method. + */ + if (duk_check_type_mask(ctx, -1, DUK_TYPE_MASK_OBJECT | + DUK_TYPE_MASK_LIGHTFUNC | + DUK_TYPE_MASK_BUFFER)) { + duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_TO_JSON); + if (duk_is_callable(ctx, -1)) { /* toJSON() can also be a lightfunc */ DUK_DDD(DUK_DDDPRINT("value is object, has callable toJSON() -> call it")); /* XXX: duk_dup_unvalidated(ctx, -2) etc. */ - duk_dup(ctx, -2); /* -> [ ... key val toJSON val ] */ - duk_dup(ctx, -4); /* -> [ ... key val toJSON val key ] */ + duk_dup_m2(ctx); /* -> [ ... key val toJSON val ] */ + duk_dup_m4(ctx); /* -> [ ... key val toJSON val key ] */ duk_call_method(ctx, 1); /* -> [ ... key val val' ] */ - duk_remove(ctx, -2); /* -> [ ... key val' ] */ + duk_remove_m2(ctx); /* -> [ ... key val' ] */ } else { duk_pop(ctx); /* -> [ ... key val ] */ } @@ -30942,10 +33127,10 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold DUK_DDD(DUK_DDDPRINT("replacer is set, call replacer")); duk_push_hobject(ctx, js_ctx->h_replacer); /* -> [ ... key val replacer ] */ duk_dup(ctx, idx_holder); /* -> [ ... key val replacer holder ] */ - duk_dup(ctx, -4); /* -> [ ... key val replacer holder key ] */ - duk_dup(ctx, -4); /* -> [ ... key val replacer holder key val ] */ + duk_dup_m4(ctx); /* -> [ ... key val replacer holder key ] */ + duk_dup_m4(ctx); /* -> [ ... key val replacer holder key val ] */ duk_call_method(ctx, 2); /* -> [ ... key val val' ] */ - duk_remove(ctx, -2); /* -> [ ... key val' ] */ + duk_remove_m2(ctx); /* -> [ ... key val' ] */ } /* [ ... key val ] */ @@ -30959,86 +33144,77 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); - if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) { +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) #if defined(DUK_USE_JX) || defined(DUK_USE_JC) - duk_hbufferobject *h_bufobj; - h_bufobj = (duk_hbufferobject *) h; - DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); - - /* Conceptually we'd extract the plain underlying buffer - * or its slice and then do a type mask check below to - * see if we should reject it. Do the mask check here - * instead to avoid making a copy of the buffer slice. - */ - - if (js_ctx->mask_for_undefined & DUK_TYPE_MASK_BUFFER) { - DUK_DDD(DUK_DDDPRINT("-> bufferobject (-> plain buffer) will result in undefined (type mask check)")); - goto pop2_undef; - } - DUK_DDD(DUK_DDDPRINT("-> bufferobject won't result in undefined, encode directly")); - duk__enc_bufferobject(js_ctx, h_bufobj); + if (DUK_HOBJECT_IS_BUFOBJ(h) && + js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE)) { + /* With JX/JC a bufferobject gets serialized specially. */ + duk_hbufobj *h_bufobj; + h_bufobj = (duk_hbufobj *) h; + DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); + duk__enc_bufobj(js_ctx, h_bufobj); goto pop2_emitted; -#else - DUK_DDD(DUK_DDDPRINT("no JX/JC support, bufferobject/buffer will always result in undefined")); - goto pop2_undef; -#endif - } else { - c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h); - switch ((int) c) { - case DUK_HOBJECT_CLASS_NUMBER: { - DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()")); - duk_to_number(ctx, -1); - /* The coercion potentially invokes user .valueOf() and .toString() - * but can't result in a function value because [[DefaultValue]] would - * reject such a result: test-dev-json-stringify-coercion-1.js. - */ - DUK_ASSERT(!duk_is_callable(ctx, -1)); - break; - } - case DUK_HOBJECT_CLASS_STRING: { - DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()")); - duk_to_string(ctx, -1); - /* Same coercion behavior as for Number. */ - DUK_ASSERT(!duk_is_callable(ctx, -1)); - break; - } + } + /* Otherwise bufferobjects get serialized as normal objects. */ +#endif /* JX || JC */ +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h); + switch (c) { + case DUK_HOBJECT_CLASS_NUMBER: { + DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()")); + duk_to_number_m1(ctx); + /* The coercion potentially invokes user .valueOf() and .toString() + * but can't result in a function value because ToPrimitive() would + * reject such a result: test-dev-json-stringify-coercion-1.js. + */ + DUK_ASSERT(!duk_is_callable(ctx, -1)); + break; + } + case DUK_HOBJECT_CLASS_STRING: { + DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()")); + duk_to_string(ctx, -1); + /* Same coercion behavior as for Number. */ + DUK_ASSERT(!duk_is_callable(ctx, -1)); + break; + } #if defined(DUK_USE_JX) || defined(DUK_USE_JC) - case DUK_HOBJECT_CLASS_POINTER: + case DUK_HOBJECT_CLASS_POINTER: #endif - case DUK_HOBJECT_CLASS_BOOLEAN: { - DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value")); - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE); - duk_remove(ctx, -2); - break; - } - default: { - /* Normal object which doesn't get automatically coerced to a - * primitive value. Functions are checked for specially. The - * primitive value coercions for Number, String, Pointer, and - * Boolean can't result in functions so suffices to check here. - */ - DUK_ASSERT(h != NULL); - if (DUK_HOBJECT_IS_CALLABLE(h)) { + case DUK_HOBJECT_CLASS_BOOLEAN: { + DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value")); + duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE); + duk_remove_m2(ctx); + break; + } + default: { + /* Normal object which doesn't get automatically coerced to a + * primitive value. Functions are checked for specially. The + * primitive value coercions for Number, String, Pointer, and + * Boolean can't result in functions so suffices to check here. + * Symbol objects are handled like plain objects (their primitive + * value is NOT looked up like for e.g. String objects). + */ + DUK_ASSERT(h != NULL); + if (DUK_HOBJECT_IS_CALLABLE(h)) { #if defined(DUK_USE_JX) || defined(DUK_USE_JC) - if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | - DUK_JSON_FLAG_EXT_COMPATIBLE)) { - /* We only get here when doing non-standard JSON encoding */ - DUK_DDD(DUK_DDDPRINT("-> function allowed, serialize to custom format")); - DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); - DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function); - goto pop2_emitted; - } else { - DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)")); - goto pop2_undef; - } -#else /* DUK_USE_JX || DUK_USE_JC */ + if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | + DUK_JSON_FLAG_EXT_COMPATIBLE)) { + /* We only get here when doing non-standard JSON encoding */ + DUK_DDD(DUK_DDDPRINT("-> function allowed, serialize to custom format")); + DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); + DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function); + goto pop2_emitted; + } else { DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)")); goto pop2_undef; -#endif /* DUK_USE_JX || DUK_USE_JC */ } +#else /* DUK_USE_JX || DUK_USE_JC */ + DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)")); + goto pop2_undef; +#endif /* DUK_USE_JX || DUK_USE_JC */ } - } /* end switch */ } + } /* end switch */ } /* [ ... key val ] */ @@ -31079,7 +33255,9 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold case DUK_TAG_STRING: { duk_hstring *h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - + if (DUK_HSTRING_HAS_SYMBOL(h)) { + goto pop2_undef; + } duk__enc_quote_string(js_ctx, h); break; } @@ -31099,13 +33277,26 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold } break; } -#if defined(DUK_USE_JX) || defined(DUK_USE_JC) - /* When JX/JC not in use, the type mask above will avoid this case if needed. */ + /* Because plain buffers mimics Uint8Array, they have enumerable + * index properties [0,byteLength[. Because JSON only serializes + * enumerable own properties, no properties can be serialized for + * plain buffers (all virtual properties are non-enumerable). However, + * there may be a .toJSON() method which was already handled above. + */ case DUK_TAG_BUFFER: { - duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv)); +#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; + } +#endif + /* Could implement a fast path, but object coerce and + * serialize the result for now. + */ + duk_to_object(ctx, -1); + duk__enc_object(js_ctx); break; } -#endif /* DUK_USE_JX || DUK_USE_JC */ case DUK_TAG_LIGHTFUNC: { #if defined(DUK_USE_JX) || defined(DUK_USE_JC) /* We only get here when doing non-standard JSON encoding */ @@ -31137,7 +33328,9 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold } } +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) pop2_emitted: +#endif duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */ return 1; /* emitted */ @@ -31148,13 +33341,24 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold /* E5 Section 15.12.3, main algorithm, step 4.b.ii steps 1-4. */ DUK_LOCAL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv) { - duk_hobject *h; duk_small_int_t c; + /* XXX: some kind of external internal type checker? + * - type mask; symbol flag; class mask + */ DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_STRING(tv) || DUK_TVAL_IS_NUMBER(tv)) { + if (DUK_TVAL_IS_STRING(tv)) { + duk_hstring *h; + h = DUK_TVAL_GET_STRING(tv); + DUK_ASSERT(h != NULL); + if (DUK_HSTRING_HAS_SYMBOL(h)) { + return 0; + } + return 1; + } else if (DUK_TVAL_IS_NUMBER(tv)) { return 1; } else if (DUK_TVAL_IS_OBJECT(tv)) { + duk_hobject *h; h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h); @@ -31214,9 +33418,11 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du } case DUK_TAG_STRING: { duk_hstring *h; - h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); + if (DUK_HSTRING_HAS_SYMBOL(h)) { + goto emit_undefined; + } duk__enc_quote_string(js_ctx, h); break; } @@ -31225,7 +33431,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du duk_tval *tv_val; duk_bool_t emitted = 0; duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef, - c_func, c_bufobj, c_object; + c_func, c_bufobj, c_object, c_abort; /* For objects JSON.stringify() only looks for own, enumerable * properties which is nice for the fast path here. @@ -31311,11 +33517,12 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du c_unbox = DUK_HOBJECT_CMASK_NUMBER | DUK_HOBJECT_CMASK_STRING | DUK_HOBJECT_CMASK_BOOLEAN | - DUK_HOBJECT_CMASK_POINTER; + DUK_HOBJECT_CMASK_POINTER; /* Symbols are not unboxed. */ c_func = DUK_HOBJECT_CMASK_FUNCTION; - c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS; + c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFOBJS; c_undef = 0; - c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef); + c_abort = 0; + c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort); } else #endif @@ -31324,13 +33531,17 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du c_array = DUK_HOBJECT_CMASK_ARRAY; c_unbox = DUK_HOBJECT_CMASK_NUMBER | DUK_HOBJECT_CMASK_STRING | - DUK_HOBJECT_CMASK_BOOLEAN; + DUK_HOBJECT_CMASK_BOOLEAN; /* Symbols are not unboxed. */ 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); + DUK_HOBJECT_CMASK_POINTER; + /* As the fast path doesn't currently properly support + * duk_hbufobj virtual properties, abort fast path if + * we encounter them in plain JSON mode. + */ + c_abort = DUK_HOBJECT_CMASK_ALL_BUFOBJS; + c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort); } c_bit = DUK_HOBJECT_GET_CLASS_MASK(obj); @@ -31355,6 +33566,15 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du if (!k) { continue; } + if (DUK_HSTRING_HAS_ARRIDX(k)) { + /* If an object has array index keys we would need + * to sort them into the ES2015 enumeration order to + * be consistent with the slow path. Abort the fast + * path and handle in the slow path for now. + */ + DUK_DD(DUK_DDPRINT("property key is an array index, abort fast path")); + goto abort_fastpath; + } if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(js_ctx->thr->heap, obj, i)) { continue; } @@ -31365,7 +33585,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path")); goto abort_fastpath; } - if (DUK_HSTRING_HAS_INTERNAL(k)) { + if (DUK_HSTRING_HAS_SYMBOL(k)) { continue; } @@ -31391,8 +33611,8 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du } /* If any non-Array value had enumerable virtual own - * properties, they should be serialized here. Standard - * types don't. + * properties, they should be serialized here (actually, + * before the explicit properties). Standard types don't. */ if (emitted) { @@ -31416,62 +33636,58 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du goto abort_fastpath; } - arr_len = (duk_uint_fast32_t) duk_hobject_get_length(js_ctx->thr, obj); + arr_len = (duk_uint_fast32_t) ((duk_harray *) obj)->length; asize = (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj); - if (arr_len > asize) { - /* Array length is larger than 'asize'. This shouldn't - * happen in practice. Bail out just in case. - */ - DUK_DD(DUK_DDPRINT("arr_len > asize, abort fast path")); - goto abort_fastpath; - } /* Array part may be larger than 'length'; if so, iterate - * only up to array 'length'. + * only up to array 'length'. Array part may also be smaller + * than 'length' in some cases. */ for (i = 0; i < arr_len; i++) { - DUK_ASSERT(i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj)); - - tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i); + duk_tval *tv_arrval; + duk_hstring *h_tmp; + duk_bool_t has_inherited; 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 - * to support gappy arrays for all practical code. - */ - duk_hstring *h_tmp; - duk_bool_t has_inherited; - - /* XXX: refactor into an internal helper, pretty awkward */ - duk_push_uint((duk_context *) js_ctx->thr, (duk_uint_t) i); - h_tmp = duk_to_hstring((duk_context *) js_ctx->thr, -1); - DUK_ASSERT(h_tmp != NULL); - has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp); - duk_pop((duk_context *) js_ctx->thr); - - if (has_inherited) { - DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path")); - goto abort_fastpath; + if (DUK_LIKELY(i < asize)) { + tv_arrval = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i); + if (DUK_LIKELY(!DUK_TVAL_IS_UNUSED(tv_arrval))) { + /* Expected case: element is present. */ + if (duk__json_stringify_fast_value(js_ctx, tv_arrval) == 0) { + DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); + } + goto elem_done; } + } - /* Ordinary gap, undefined encodes to 'null' in - * standard JSON (and no JX/JC support here now). - */ - DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path")); + /* Gap in array; check for inherited property, + * bail out if one exists. This should be enough + * to support gappy arrays for all practical code. + */ + + h_tmp = duk_push_uint_to_hstring((duk_context *) js_ctx->thr, (duk_uint_t) i); + has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp); + duk_pop((duk_context *) js_ctx->thr); + if (has_inherited) { + DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path")); + goto abort_fastpath; + } + + /* Ordinary gap, undefined encodes to 'null' in + * standard JSON, but JX/JC use their form for + * undefined to better preserve the typing. + */ + DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path")); #if defined(DUK_USE_JX) - DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined); + DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined); #else - DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); + DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); #endif - } else { - if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) { - DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); - } - } + /* fall through */ + elem_done: DUK__EMIT_1(js_ctx, DUK_ASC_COMMA); emitted = 1; } @@ -31490,6 +33706,8 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du * automatic unboxing. Rely on internal value being * sane (to avoid infinite recursion). */ + DUK_ASSERT((c_bit & DUK_HOBJECT_CMASK_SYMBOL) == 0); /* Symbols are not unboxed. */ + #if 1 /* The code below is incorrect if .toString() or .valueOf() have * have been overridden. The correct approach would be to look up @@ -31519,9 +33737,14 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du #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); +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) } else if (c_bit & c_bufobj) { - duk__enc_bufferobject(js_ctx, (duk_hbufferobject *) obj); + duk__enc_bufobj(js_ctx, (duk_hbufobj *) obj); +#endif #endif + } else if (c_bit & c_abort) { + DUK_DD(DUK_DDPRINT("abort fast path for unsupported type")); + goto abort_fastpath; } else { DUK_ASSERT((c_bit & c_undef) != 0); @@ -31538,16 +33761,31 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du break; } case DUK_TAG_BUFFER: { + /* Plain buffers are treated like Uint8Arrays: they have + * enumerable indices. Other virtual properties are not + * enumerable, and inherited properties are not serialized. + * However, there can be a replacer (not relevant here) or + * a .toJSON() method (which we need to check for explicitly). + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) + if (duk_hobject_hasprop_raw(js_ctx->thr, + js_ctx->thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE], + DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr))) { + DUK_DD(DUK_DDPRINT("value is a plain buffer and there's an inherited .toJSON, abort fast path")); + goto abort_fastpath; + } +#endif + #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 + /* Could implement a fast path, but abort fast path for now. */ + DUK_DD(DUK_DDPRINT("value is a plain buffer and serializing as plain JSON, abort fast path")); + goto abort_fastpath; } case DUK_TAG_POINTER: { #if defined(DUK_USE_JX) || defined(DUK_USE_JC) @@ -31613,24 +33851,24 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du abort_fastpath: /* Error message doesn't matter: the error is ignored anyway. */ DUK_DD(DUK_DDPRINT("aborting fast path")); - DUK_ERROR_INTERNAL_DEFMSG(js_ctx->thr); + DUK_ERROR_INTERNAL(js_ctx->thr); return 0; /* unreachable */ } -DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_context *ctx) { +DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_context *ctx, void *udata) { duk_json_enc_ctx *js_ctx; duk_tval *tv; DUK_ASSERT(ctx != NULL); - tv = DUK_GET_TVAL_NEGIDX(ctx, -2); - DUK_ASSERT(DUK_TVAL_IS_POINTER(tv)); - js_ctx = (duk_json_enc_ctx *) DUK_TVAL_GET_POINTER(tv); + DUK_ASSERT(udata != NULL); + + js_ctx = (duk_json_enc_ctx *) udata; DUK_ASSERT(js_ctx != NULL); tv = DUK_GET_TVAL_NEGIDX(ctx, -1); if (duk__json_stringify_fast_value(js_ctx, tv) == 0) { DUK_DD(DUK_DDPRINT("top level value not supported, fail fast path")); - return DUK_RET_ERROR; /* error message doesn't matter, ignored anyway */ + DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); /* Error message is ignored, so doesn't matter. */ } return 0; @@ -31650,7 +33888,7 @@ void duk_bi_json_parse_helper(duk_context *ctx, duk_json_dec_ctx js_ctx_alloc; duk_json_dec_ctx *js_ctx = &js_ctx_alloc; duk_hstring *h_text; -#ifdef DUK_USE_ASSERTIONS +#if defined(DUK_USE_ASSERTIONS) duk_idx_t entry_top = duk_get_top(ctx); #endif @@ -31666,7 +33904,7 @@ void duk_bi_json_parse_helper(duk_context *ctx, DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc)); js_ctx->thr = thr; -#ifdef DUK_USE_EXPLICIT_NULL_INIT +#if defined(DUK_USE_EXPLICIT_NULL_INIT) /* nothing now */ #endif js_ctx->recursion_limit = DUK_USE_JSON_DEC_RECLIMIT; @@ -31687,7 +33925,7 @@ void duk_bi_json_parse_helper(duk_context *ctx, 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 */ + h_text = duk_to_hstring(ctx, idx_value); /* coerce in-place; rejects Symbols */ DUK_ASSERT(h_text != NULL); /* JSON parsing code is allowed to read [p_start,p_end]: p_end is @@ -31717,8 +33955,8 @@ void duk_bi_json_parse_helper(duk_context *ctx, js_ctx->idx_reviver = idx_reviver; duk_push_object(ctx); - duk_dup(ctx, -2); /* -> [ ... val root val ] */ - duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */ + duk_dup_m2(ctx); /* -> [ ... val root val ] */ + duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */ duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */ DUK_DDD(DUK_DDDPRINT("start reviver walk, root=%!T, name=%!T", @@ -31726,7 +33964,7 @@ void duk_bi_json_parse_helper(duk_context *ctx, (duk_tval *) duk_get_tval(ctx, -1))); duk__dec_reviver_walk(js_ctx); /* [ ... val root "" ] -> [ ... val val' ] */ - duk_remove(ctx, -2); /* -> [ ... val' ] */ + duk_remove_m2(ctx); /* -> [ ... val' ] */ } else { DUK_DDD(DUK_DDDPRINT("reviver does not exist or is not callable: %!T", (duk_tval *) duk_get_tval(ctx, idx_reviver))); @@ -31777,7 +34015,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx, DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc)); js_ctx->thr = thr; -#ifdef DUK_USE_EXPLICIT_NULL_INIT +#if defined(DUK_USE_EXPLICIT_NULL_INIT) js_ctx->h_replacer = NULL; js_ctx->h_gap = NULL; #endif @@ -31790,17 +34028,17 @@ void duk_bi_json_stringify_helper(duk_context *ctx, js_ctx->flags = flags; js_ctx->flag_ascii_only = flags & DUK_JSON_FLAG_ASCII_ONLY; js_ctx->flag_avoid_key_quotes = flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES; -#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 - /* The #ifdef clutter here handles the JX/JC enable/disable + /* The #if defined() clutter here handles the JX/JC enable/disable * combinations properly. */ #if defined(DUK_USE_JX) || defined(DUK_USE_JC) @@ -31839,15 +34077,19 @@ void duk_bi_json_stringify_helper(duk_context *ctx, else #endif /* DUK_USE_JX || DUK_USE_JC */ { + /* Plain buffer is treated like ArrayBuffer and serialized. + * Lightfuncs are treated like objects, but JSON explicitly + * skips serializing Function objects so we can just reject + * lightfuncs here. + */ js_ctx->mask_for_undefined = DUK_TYPE_MASK_UNDEFINED | DUK_TYPE_MASK_POINTER | - DUK_TYPE_MASK_BUFFER | DUK_TYPE_MASK_LIGHTFUNC; } DUK_BW_INIT_PUSHBUF(thr, &js_ctx->bw, DUK__JSON_STRINGIFY_BUFSIZE); - js_ctx->idx_loop = duk_push_object_internal(ctx); + js_ctx->idx_loop = duk_push_bare_object(ctx); DUK_ASSERT(js_ctx->idx_loop >= 0); /* [ ... buf loop ] */ @@ -31929,14 +34171,12 @@ void duk_bi_json_stringify_helper(duk_context *ctx, DUK_ASSERT(nspace >= 0 && nspace <= 10); duk_push_lstring(ctx, spaces, (duk_size_t) nspace); - js_ctx->h_gap = duk_get_hstring(ctx, -1); + js_ctx->h_gap = duk_known_hstring(ctx, -1); DUK_ASSERT(js_ctx->h_gap != NULL); - } else if (duk_is_string(ctx, idx_space)) { - /* XXX: substring in-place at idx_place? */ + } else if (duk_is_string_notsymbol(ctx, idx_space)) { duk_dup(ctx, idx_space); duk_substring(ctx, -1, 0, 10); /* clamp to 10 chars */ - js_ctx->h_gap = duk_get_hstring(ctx, -1); - DUK_ASSERT(js_ctx->h_gap != NULL); + js_ctx->h_gap = duk_known_hstring(ctx, -1); } else { /* nop */ } @@ -31959,9 +34199,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx, 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; -#endif DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path")); @@ -31980,22 +34218,18 @@ void duk_bi_json_stringify_helper(duk_context *ctx, * limited loop detection). */ - duk_push_pointer(ctx, (void *) js_ctx); duk_dup(ctx, idx_value); -#if defined(DUK_USE_MARK_AND_SWEEP) /* Must prevent finalizers which may have arbitrary side effects. */ prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags; thr->heap->mark_and_sweep_base_flags |= DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */ DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact any objects */ -#endif - pcall_rc = duk_safe_call(ctx, duk__json_stringify_fast, 2 /*nargs*/, 0 /*nret*/); + pcall_rc = duk_safe_call(ctx, duk__json_stringify_fast, (void *) js_ctx /*udata*/, 1 /*nargs*/, 0 /*nret*/); -#if defined(DUK_USE_MARK_AND_SWEEP) thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; -#endif + if (pcall_rc == DUK_EXEC_SUCCESS) { DUK_DD(DUK_DDPRINT("fast path successful")); DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw); @@ -32019,7 +34253,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx, idx_holder = duk_push_object(ctx); duk_dup(ctx, idx_value); - duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING); + duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_EMPTY_STRING); DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, " "proplist=%!T, gap=%!O, holder=%!T", @@ -32032,7 +34266,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx, /* serialize the wrapper with empty string key */ - duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); + duk_push_hstring_empty(ctx); /* [ ... buf loop (proplist) (gap) holder "" ] */ @@ -32078,6 +34312,8 @@ void duk_bi_json_stringify_helper(duk_context *ctx, DUK_ASSERT(duk_get_top(ctx) == entry_top + 1); } +#if defined(DUK_USE_JSON_BUILTIN) + /* * Entry points */ @@ -32099,318 +34335,28 @@ DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx) { return 1; } +#endif /* DUK_USE_JSON_BUILTIN */ + +#endif /* DUK_USE_JSON_SUPPORT */ + +/* automatic undefs */ +#undef DUK__EMIT_1 +#undef DUK__EMIT_2 +#undef DUK__EMIT_CSTR +#undef DUK__EMIT_HSTR +#undef DUK__EMIT_STRIDX #undef DUK__JSON_DECSTR_BUFSIZE #undef DUK__JSON_DECSTR_CHUNKSIZE #undef DUK__JSON_ENCSTR_CHUNKSIZE -#undef DUK__JSON_STRINGIFY_BUFSIZE #undef DUK__JSON_MAX_ESC_LEN -#line 1 "duk_bi_logger.c" -/* - * Logging support - */ - -/* include removed: duk_internal.h */ - -/* 3-letter log level strings */ -DUK_LOCAL const duk_uint8_t duk__log_level_strings[] = { - (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_C, - (duk_uint8_t) DUK_ASC_UC_D, (duk_uint8_t) DUK_ASC_UC_B, (duk_uint8_t) DUK_ASC_UC_G, - (duk_uint8_t) DUK_ASC_UC_I, (duk_uint8_t) DUK_ASC_UC_N, (duk_uint8_t) DUK_ASC_UC_F, - (duk_uint8_t) DUK_ASC_UC_W, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_N, - (duk_uint8_t) DUK_ASC_UC_E, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_R, - (duk_uint8_t) DUK_ASC_UC_F, (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_L -}; - -/* Constructor */ -DUK_INTERNAL duk_ret_t duk_bi_logger_constructor(duk_context *ctx) { - duk_hthread *thr = (duk_hthread *) ctx; - duk_idx_t nargs; - - /* Calling as a non-constructor is not meaningful. */ - if (!duk_is_constructor_call(ctx)) { - return DUK_RET_TYPE_ERROR; - } - - nargs = duk_get_top(ctx); - duk_set_top(ctx, 1); - - duk_push_this(ctx); - - /* [ name this ] */ - - if (nargs == 0) { - /* Automatic defaulting of logger name from caller. This would - * work poorly with tail calls, but constructor calls are currently - * never tail calls, so tail calls are not an issue now. - */ - - if (thr->callstack_top >= 2) { - duk_activation *act_caller = thr->callstack + thr->callstack_top - 2; - duk_hobject *func_caller; - - func_caller = DUK_ACT_GET_FUNC(act_caller); - if (func_caller) { - /* Stripping the filename might be a good idea - * ("/foo/bar/quux.js" -> logger name "quux"), - * but now used verbatim. - */ - duk_push_hobject(ctx, func_caller); - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME); - duk_replace(ctx, 0); - } - } - } - /* the stack is unbalanced here on purpose; we only rely on the - * initial two values: [ name this ]. - */ - - if (duk_is_string(ctx, 0)) { - duk_dup(ctx, 0); - duk_put_prop_stridx(ctx, 1, DUK_STRIDX_LC_N); - } else { - /* don't set 'n' at all, inherited value is used as name */ - } - - duk_compact(ctx, 1); - - return 0; /* keep default instance */ -} - -/* Default function to format objects. Tries to use toLogString() but falls - * back to toString(). Any errors are propagated out without catching. - */ -DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx) { - if (duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_LOG_STRING)) { - /* [ arg toLogString ] */ - - duk_dup(ctx, 0); - duk_call_method(ctx, 0); - - /* [ arg result ] */ - return 1; - } - - /* [ arg undefined ] */ - duk_pop(ctx); - duk_to_string(ctx, 0); - return 1; -} - -/* Default function to write a formatted log line. Writes to stderr, - * appending a newline to the log line. - * - * The argument is a buffer whose visible size contains the log message. - * This function should avoid coercing the buffer to a string to avoid - * string table traffic. - */ -DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx) { - const char *data; - duk_size_t data_len; - - DUK_UNREF(ctx); - DUK_UNREF(data); - DUK_UNREF(data_len); - -#ifdef DUK_USE_FILE_IO - data = (const char *) duk_require_buffer(ctx, 0, &data_len); - DUK_FWRITE((const void *) data, 1, data_len, DUK_STDERR); - DUK_FPUTC((int) '\n', DUK_STDERR); - DUK_FFLUSH(DUK_STDERR); -#else - /* nop */ -#endif - return 0; -} - -/* Log frontend shared helper, magic value indicates log level. Provides - * frontend functions: trace(), debug(), info(), warn(), error(), fatal(). - * This needs to have small footprint, reasonable performance, minimal - * memory churn, etc. - */ -DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx) { - duk_hthread *thr = (duk_hthread *) ctx; - duk_double_t now; - duk_small_int_t entry_lev = duk_get_current_magic(ctx); - duk_small_int_t logger_lev; - duk_int_t nargs; - duk_int_t i; - duk_size_t tot_len; - const duk_uint8_t *arg_str; - duk_size_t arg_len; - duk_uint8_t *buf, *p; - const duk_uint8_t *q; - duk_uint8_t date_buf[DUK_BI_DATE_ISO8601_BUFSIZE]; - duk_size_t date_len; - duk_small_int_t rc; - - DUK_ASSERT(entry_lev >= 0 && entry_lev <= 5); - DUK_UNREF(thr); - - /* XXX: sanitize to printable (and maybe ASCII) */ - /* XXX: better multiline */ - - /* - * Logger arguments are: - * - * magic: log level (0-5) - * this: logger - * stack: plain log args - * - * We want to minimize memory churn so a two-pass approach - * is used: first pass formats arguments and computes final - * string length, second pass copies strings either into a - * pre-allocated and reused buffer (short messages) or into a - * newly allocated fixed buffer. If the backend function plays - * nice, it won't coerce the buffer to a string (and thus - * intern it). - */ - - nargs = duk_get_top(ctx); - - /* [ arg1 ... argN this ] */ - - /* - * Log level check - */ - - duk_push_this(ctx); - - duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_L); - logger_lev = (duk_small_int_t) duk_get_int(ctx, -1); - if (entry_lev < logger_lev) { - return 0; - } - /* log level could be popped but that's not necessary */ - - now = DUK_USE_DATE_GET_NOW(ctx); - duk_bi_date_format_timeval(now, date_buf); - date_len = DUK_STRLEN((const char *) date_buf); - - duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LC_N); - duk_to_string(ctx, -1); - DUK_ASSERT(duk_is_string(ctx, -1)); - - /* [ arg1 ... argN this loggerLevel loggerName ] */ - - /* - * Pass 1 - */ - - /* Line format: